succinct-wizard
v0.1.0
Published
Agentic installer that sets up Succinct (gateway, observability, Downshift) in your codebase — the way an expert would.
Maintainers
Readme
succinct-wizard
An agentic CLI that installs and configures Succinct in your codebase — the way an expert would.
npx succinct-wizardThe wizard is an LLM agent (paid for by Succinct) that:
- Understands your codebase — finds every place you call an LLM (OpenAI/Anthropic SDKs, raw HTTP, LangChain, Vercel AI SDK …), which model you use in production, whether you stream, and how you load secrets.
- Connects your Succinct account — asks you to create a gateway API key in the dashboard and paste it. The key is validated instantly and written only to your local env file; it is never sent to the agent.
- Shows you the plan — exact files it will touch, env vars, risks and manual follow-ups. Nothing happens until you say yes.
- Instruments your code on a git branch (
succinct/install) — swaps your client's base URL/key/model to the Succinct gateway, adds anX-SLM-Taskheader, updates.env.example, installs anything needed, runs your typecheck. - Configures Downshift — creates a Downshift project bound to your key with your production model as baseline and a cheap-first candidate ladder, so Succinct starts comparing cheaper models on real traffic immediately.
- Verifies — sends one tiny request through the gateway and confirms it was logged and mirrored.
- Reports & commits — writes
succinct-setup-report.mdand commits everything on the branch for review.
While it works, the terminal UI explains how Succinct works — the gateway, Downshift's candidate ladder, anytime-valid readiness statistics, observability — with animated diagrams (inspired by the PostHog wizard).
Usage
# in the project you want to instrument
npx succinct-wizard
# non-interactive (CI / scripting)
npx succinct-wizard --yes --api-key sk-… --no-tui
# demo without any keys (scripted agent, conservative codemod)
npx succinct-wizard --simulate| Flag | Env | Meaning |
|---|---|---|
| --install-dir <path> | | Project directory (default: cwd) |
| --api-url <url> | SUCCINCT_API_URL | Succinct API base URL (default https://service.getsuccinct.com) |
| --dashboard-url <url> | SUCCINCT_DASHBOARD_URL | Dashboard URL for deep links (default https://app.getsuccinct.com) |
| --local | | Shortcut for a local Succinct (http://127.0.0.1:8000 / http://localhost:8080) |
| --api-key <key> | SUCCINCT_API_KEY | Skip the paste prompt |
| --llm succinct\|openrouter\|simulate | SUCCINCT_WIZARD_LLM | Agent backend. succinct (default): tokens paid by Succinct. openrouter is auto-selected when OPENROUTER_API_KEY is set (dev). |
| --model <id> | SUCCINCT_WIZARD_MODEL | Agent model (default anthropic/claude-sonnet-4.6) |
| -y, --yes | | Accept defaults, skip confirmations |
| --no-tui | | Plain logs (auto when stdout is not a TTY) |
| --no-verify / --no-downshift | | Skip the live probe / Downshift creation |
| --branch <name> | | Branch to create (default succinct/install) |
| --allow-dirty | | Run with uncommitted changes |
| --debug | SUCCINCT_WIZARD_DEBUG | Debug log in $TMPDIR/succinct-wizard.log |
TUI keys: ←/→ or 1/2/3 switch Status / Plan / Tail logs, q quits.
How "Succinct pays for the LLM" works
The wizard's own model calls go to POST <api-url>/v1/wizard/agent/chat/completions, an OpenAI-compatible endpoint on the Succinct backend. It is authenticated with the customer's gateway key (so only Succinct users can use it) but executed with Succinct's OpenRouter credential and never charged to the customer's key. It passes tool-calling through untouched, caps max_tokens, restricts models to an allowlist and rate-limits per key (400 calls/day). A full install uses ~10–20 calls (~$0.15–0.30 with Sonnet).
The CLI never needs a dashboard login: everything it does server-side goes through key-authenticated endpoints under /v1/wizard/*:
| Endpoint | Purpose |
|---|---|
| GET /v1/wizard/key | Validate the pasted key; org, spend, request count, bound Downshift project |
| GET /v1/wizard/baseline-models | Curated baseline catalog |
| GET/POST /v1/wizard/downshift | Get / create (idempotent) the Downshift project bound to this key |
| POST /v1/wizard/agent/chat/completions | The Succinct-paid agent LLM |
Architecture
src/
cli.tsx commander entry → plain UI or Ink TUI
config.ts flags/env → WizardOptions
events.ts WizardBus: typed events (task, log, plan, prompt, done) between engine and UI
engine/
runner.ts the 10 steps (preflight → auth → analyze → confirm → branch → env → apply → downshift → verify → report)
project.ts deterministic project detection (language, PM, frameworks, LLM SDK pre-scan)
git.ts / env.ts branch/commit helpers, dotenv upsert + .gitignore guard
report.ts succinct-setup-report.md
agent/
llm.ts minimal OpenAI-compatible chat client with tool calling (OpenRouter today, Succinct gateway tomorrow)
loop.ts tool loop + JSON extraction/repair
tools.ts list_files / read_file / grep / write_file / edit_file / run_command — sandboxed to the project root,
runtime .env files are write-protected, shell commands are allow-listed
prompts.ts system prompts + zod schemas for the analysis/plan and apply results
simulated.ts scripted agent for demos/tests (no key needed)
succinct/client.ts key-authenticated Succinct API client, dashboard deep links, model id mapping
ui/ Ink TUI: TitleBar, Learn deck (Sequencer + learn-content), Tasks panel, log tail, prompts, summaryThe engine never imports UI code; the UI only reacts to bus events. --no-tui and tests use the same engine.
Safety rails: the agent only sees your code, never your keys; it cannot write runtime .env* files; it can only run package installs / builds / typechecks / read-only git; every write is confined to the project root; all changes land on a branch you review.
Development
cd wizard
npm install
npm run dev -- --install-dir ../some-app --simulate # run from source
npm run build && node bin/succinct-wizard.js --help
npm test # unit tests (node:test)Backend tests for the wizard endpoints (needs Python ≥3.10 and a local Postgres DB whose name contains test): cd backend && DATABASE_URL=postgresql+asyncpg://localhost/smallest_pass_finder_wizard_test python -m pytest tests/test_wizard.py.
