AI-orchestrated development CLI. Write a plain-text spec, and cestDone turns it into working code — planning, implementing, reviewing, and committing autonomously.
The bottleneck in AI-assisted development isn't the AI — it's the human sitting between the planner and the worker. You paste context, copy instructions, re-explain what was already decided, and babysit every step.
cestDone removes that bottleneck. A Director AI reads your spec, explores the codebase, creates a phased plan, and either implements it directly or delegates to a Worker AI. The human intervenes only when explicitly opted in.
There's a second, subtler problem: context window exhaustion. When you drive an AI agent manually through a large project, the conversation fills up — the model forgets earlier decisions, loses track of files, and quality degrades. cestDone sidesteps this by keeping the Director thin — it orchestrates via markdown files and never does deep code analysis itself. Workers get fresh sessions per task with only the relevant context. All handoffs happen through .plan.md and .cestdone/reports/ files, so nothing is lost and everything is traceable.
spec.md ──► DIRECTOR .plan.md
│ │
└─ Planning Worker ──────────────────────────────► │
(explores codebase, writes .plan.md) │
│
For each phase: │
┌──────────────────────────────────────────────┐ │
│ │ │
│ WORKER (fresh session per phase) │ │
│ ├─ Reads phase spec from plan │ │
│ ├─ Implements: edit files, run tests │ │
│ └─ Writes report to .cestdone/reports/ │ │
│ │ │ │
│ ▼ │ │
│ DIRECTOR (review) │ │
│ ├─ Reads report + code diff │ │
│ ├─ fix ──► retry Worker (max 3, then human) │ │
│ ├─ continue ──► Worker keeps going │ │
│ └─ done ──► commit, update plan ───────────►│ │
│ │ │
└──────────────────────────────────────────────┘ │
Planning (once per spec):
- Planning Worker — A Worker explores the codebase and writes a structured
.plan.mdwith numbered phases - Validation — The plan format is validated; if invalid, a revision Worker fixes it
- Approval — If
--with-human-validation, the plan is shown for approval before execution
Execution (per phase):
- Execute — Worker implements the phase (or the Director, in director-only mode)
- Review — Director reads the Worker's report and code diff to verify
- Complete — Director updates
.plan.md, commits verified work, moves to next phase
The Director and Workers communicate exclusively through markdown files in .cestdone/reports/:
.cestdone/reports/
phase-0-prompt.md ← Planning Worker's prompt (what the Director asked)
phase-1-prompt.md ← Phase 1 Worker's instructions
phase-1-report.md ← Phase 1 Worker's report (status, summary, files changed)
phase-2-prompt.md ← Phase 2 Worker's instructions
phase-2-report.md ← Phase 2 Worker's report
...
Additionally:
spec.plan.md— the plan file (written by Planning Worker, read by Director).cestdone/cestdone-diff.txt— git diff of changes (written by Worker, read by Director during review)
This gives full traceability of every Director↔Worker interaction. You can inspect these files to understand exactly what was asked and what was delivered.
- Two-agent mode (default): Director delegates planning and implementation to Workers. The Director is a thin orchestrator — it never reads code directly, only reviews through report files and diffs.
- Director-only mode (
--no-with-worker): The Director does everything. Simpler, but the Director's context carries more weight.
- Claude CLI (default): Spawns
claude -punder the hood. Uses your Claude Max or Pro subscription — no API key, no per-token billing. Authenticate withclaude auth login. - Agent SDK (
--backend agent-sdk): Uses@anthropic-ai/claude-agent-sdkwith per-token API billing. RequiresANTHROPIC_API_KEYin the environment.
You can mix backends per agent (e.g., Director on CLI, Worker on API) with --director-backend and --worker-backend.
# From the cestdone repo
npm install
npm run build
npm linkThis creates a global cestdone command you can call from anywhere. On Windows, it's case-insensitive (cestDone, CESTDONE, etc. all work).
After code changes, run npm run build to update the global command.
Write a spec file:
Add POST /api/auth/login with JWT tokens. Use bcrypt for passwords.
Include tests.
Run it from the target project directory:
cd ~/Code/my-app
cestdone run --spec ~/specs/auth.md
# Or specify the target explicitly
cestdone run --spec spec.md --target ./my-appWith Agent SDK backend (requires ANTHROPIC_API_KEY):
cestdone run --spec spec.md --target ./my-app --backend agent-sdkResume a partially completed plan:
cestdone resume --spec spec.md --target ./my-appUsage: cestdone [commands]
Commands:
run [options] Create a plan from a spec and execute all phases
resume [options] Resume execution from an existing .plan.md file
daemon [options] Start daemon with schedules and triggers from .cestdonerc.json
daemon status Show daemon status
daemon stop Stop running daemon
send-email Send an email (used by Worker agent via Bash)
--spec <path> Path to spec file (required)
--house-rules <path> Path to house rules file
--target <path> Target repository path (default: ".")
--director-model <model> Director model: haiku | sonnet | opus (default: "opus")
--worker-model <model> Worker model: haiku | sonnet | opus (default: "opus")
--with-worker Two-agent mode: Director plans, Worker implements (default: true)
--no-with-worker Disable two-agent mode (director-only)
--with-reviews Director reviews after Worker execution (default: true)
--no-with-reviews Disable Director reviews
--with-bash-reviews Allow Bash in reviews, implies --with-reviews (default: true)
--no-with-bash-reviews Disable Bash in reviews
--with-human-validation Require human approval of plan (default: false)
--non-interactive Run without TTY — auto-approves plans, skips clarifications (default: false)
--backend <type> Backend for both agents: agent-sdk | claude-cli (default: "claude-cli")
--director-backend <type> Override Director backend: agent-sdk | claude-cli
--worker-backend <type> Override Worker backend: agent-sdk | claude-cli
--claude-cli-path <path> Path to claude binary (default: "claude")
resume accepts all the same options except --house-rules.
# Default: two-agent mode, reviews enabled, Claude CLI backend
cestdone run --spec spec.md --target ./my-app
# Director-only mode (no Worker)
cestdone run --spec spec.md --target ./my-app --no-with-worker
# Require human approval of the plan before execution
cestdone run --spec spec.md --target ./my-app --with-human-validation
# Non-interactive (CI/CD, scripts, daemon — no TTY required)
cestdone run --spec spec.md --target ./my-app --non-interactive
# Use API backend with custom models
cestdone run --spec spec.md --target ./my-app \
--backend agent-sdk --director-model sonnet --worker-model haiku
# House rules for coding standards
cestdone run --spec spec.md --target ./my-app --house-rules house-rules.mdOptional .cestdonerc.json in the target repo. CLI flags take precedence.
{
"targetRepoPath": ".",
"maxTurns": 100,
"directorModel": "opus",
"workerModel": "opus",
"withWorker": true,
"withReviews": true,
"withBashReviews": true,
"withHumanValidation": false,
"nonInteractive": false,
"autoCommit": true,
"houseRules": "house-rules.md",
"directorBackend": "claude-cli",
"workerBackend": "claude-cli",
"claudeCliPath": "claude"
}Model aliases haiku, sonnet, and opus resolve to full model IDs. You can also pass a full ID directly (e.g., claude-sonnet-4-6).
The daemon is a long-running process that executes specs automatically based on schedules, webhooks, or polling triggers. It reuses the same handleRun execution engine — the daemon is just a "when to run" layer on top.
You maintain an open-source library. When someone opens a bug report on GitHub, you want cestDone to automatically analyze the issue, find the root cause, write a fix, add tests, and push a branch — all without you touching the keyboard.
Step 1 — Write a spec template (specs/fix-issue.md):
A user reported the following issue in our repository:
**Title**: {{payload.issue.title}}
**Description**: {{payload.issue.body}}
**Reporter**: {{payload.issue.user.login}}
Analyze the codebase, reproduce the bug, implement a fix, and add a regression test.
Create a new branch named fix/issue-{{payload.issue.number}} and commit the changes.
Do not modify unrelated code.Step 2 — Configure the daemon (.cestdonerc.json):
{
"targetRepoPath": "./my-library",
"daemon": {
"webhooks": [
{
"name": "github-issues",
"port": 9876,
"path": "/github/issues",
"spec": "specs/fix-issue.md",
"target": "./my-library",
"secret": "whsec_your_github_webhook_secret"
}
]
}
}Step 3 — Point GitHub at your daemon. In your repo's Settings > Webhooks, add:
- URL:
http://your-server:9876/github/issues - Content type:
application/json - Secret:
whsec_your_github_webhook_secret - Events: "Issues" (opened)
Step 4 — Start the daemon:
cestdone daemonNow, when someone opens an issue, GitHub POSTs the event to your daemon. The daemon injects the issue title, body, and number into the spec template, then runs the full Director + Worker flow — analyzing the codebase, writing a fix, running tests, and committing to a new branch. You wake up to a ready-to-review PR branch.
Other examples of what you can automate:
| Trigger | Use case |
|---|---|
Schedule 0 9 * * 1 |
Every Monday at 9am, scan for outdated dependencies and open upgrade PRs |
Schedule 0 2 * * * |
Nightly: scrape industry articles, generate a summary, commit to a knowledge repo |
| Webhook GitHub PR review | When a PR gets "changes requested", auto-address the review comments |
| Webhook Linear/Jira ticket | When a ticket is moved to "Ready for Dev", auto-implement it |
Poller npm audit --json |
Every 6 hours, check for new vulnerabilities — if any appear, patch them |
| Poller curl an API | Monitor an endpoint; when the response changes, update internal documentation |
.cestdonerc.json
│
├── schedules[] ──► cron fires ──────────────────────┐
├── webhooks[] ──► POST /path arrives ──────────────┤──► Job Queue (FIFO)
└── pollers[] ──► output changes ──────────────────┘ │
▼
handleRun()
(non-interactive)
│
Director + Worker
plan → execute
- You configure triggers in the
daemonsection of.cestdonerc.json - You start the daemon:
cestdone daemon— it runs in the foreground, listening for events - When a trigger fires, it creates a job in an in-memory FIFO queue
- The run loop processes jobs one at a time, calling
handleRunwith--non-interactive(auto-approves plans, skips clarifications) - Results are logged to
logs/daemon/— one daemon log + one log per job
The daemon stays running until you stop it (cestdone daemon stop or Ctrl+C). It is not a background service by itself — use systemd, pm2, or similar to daemonize it if needed.
Add a daemon section to .cestdonerc.json:
{
"targetRepoPath": "./my-app",
"daemon": {
"logDir": "logs/daemon",
"pidFile": "logs/daemon/daemon.pid",
"schedules": [
{
"name": "nightly-report",
"cron": "0 2 * * *",
"spec": "specs/generate-report.md",
"target": "./my-app"
}
],
"webhooks": [
{
"name": "github-issues",
"port": 9876,
"path": "/github/issues",
"spec": "specs/triage-issue.md",
"target": "./my-app",
"secret": "whsec_your_secret_here"
}
],
"pollers": [
{
"name": "check-deps",
"cron": "0 */6 * * *",
"command": "npm outdated --json",
"spec": "specs/update-deps.md",
"target": "./my-app"
}
]
}
}Run a spec on a cron schedule. Always triggers — every time the cron fires, a run is enqueued regardless of external state. Use for periodic tasks that should happen no matter what (reports, cleanups, recurring scans). Uses standard cron syntax (5-field).
| Field | Required | Description |
|---|---|---|
name |
yes | Unique name for this schedule |
cron |
yes | Cron expression (e.g. 0 2 * * * = daily at 2am) |
spec |
yes | Path to spec file |
target |
no | Target repository path |
houseRules |
no | Path to house rules file |
options |
no | Any run options to override |
Listen for HTTP POST requests and trigger a spec run with the payload injected via templates.
| Field | Required | Description |
|---|---|---|
name |
yes | Unique name for this webhook |
port |
yes | HTTP port to listen on |
path |
no | URL path to match (default: /) |
spec |
yes | Path to spec file (may contain {{variables}}) |
secret |
no | HMAC secret for X-Hub-Signature-256 validation |
target |
no | Target repository path |
options |
no | Any run options to override |
Multiple webhooks can share the same port if they have different paths.
Like a schedule, but with a "only if changed" gate. Periodically runs a command or fetches a URL, and only triggers a run when the output changes compared to the previous poll (first poll always triggers). Use when you want to react to changes rather than run blindly — e.g., "check npm audit every 6 hours, but only trigger a fix if new vulnerabilities appeared." If you used a schedule for this, cestDone would re-run every 6 hours even when nothing changed, wasting tokens and creating duplicate work.
| Field | Required | Description |
|---|---|---|
name |
yes | Unique name for this poller |
cron |
yes | How often to poll (cron expression) |
command |
one of | Shell command to run |
url |
one of | URL to fetch |
spec |
yes | Path to spec file (may contain {{variables}}) |
target |
no | Target repository path |
options |
no | Any run options to override |
Webhook payloads and poller outputs can be injected into spec files using {{variable}} syntax. The template context provides:
{{trigger.name}}— name of the trigger that fired{{trigger.type}}—webhookorpoller{{timestamp}}— ISO 8601 timestamp{{payload.*}}— webhook JSON body or{{payload.output}}for pollers
Example spec template for a GitHub issue webhook:
Triage and fix the following issue:
**Title**: {{payload.issue.title}}
**Body**: {{payload.issue.body}}
**Labels**: {{payload.issue.labels}}
Analyze the issue, find the root cause, implement a fix, and add tests.# Start the daemon (foreground — Ctrl+C to stop)
cestdone daemon
# Check if daemon is running
cestdone daemon status
# Stop a running daemon
cestdone daemon stopThe daemon runs in the foreground by default. To run it as a persistent background service:
With pm2:
pm2 start "cestdone daemon" --name cestdone-daemonWith systemd (Linux):
[Unit]
Description=cestDone Daemon
[Service]
WorkingDirectory=/path/to/project
ExecStart=cestdone daemon
Restart=on-failure
[Install]
WantedBy=multi-user.target| Scenario | Behavior |
|---|---|
| Spec run fails | Logged, marked as failed, queue continues |
| Invalid webhook JSON | Returns 400, not enqueued |
| HMAC validation fails | Returns 403, not enqueued |
| Poll command fails | Logged, skipped, keeps polling next interval |
| Escalation needed | NonInteractiveEscalationError caught, job marked failed |
| Daemon already running | Prints error with PID, exits |
cestDone can send emails via the send-email CLI command. This is designed for the Worker agent to invoke via Bash when a spec says "send an email when finished."
Set these environment variables (or add to .env):
| Variable | Required | Default | Description |
|---|---|---|---|
MAIL_PROVIDER |
No | smtp |
Mail provider (smtp) |
MAIL_FROM |
Yes | — | Sender email address |
SMTP_HOST |
Yes | — | SMTP server hostname |
SMTP_PORT |
No | 587 |
SMTP port (587 for STARTTLS, 465 for SSL) |
SMTP_USER |
Yes | — | SMTP username |
SMTP_PASS |
Yes | — | SMTP password or app password |
SMTP_SECURE |
No | auto | true for SSL (port 465), false for STARTTLS |
MAIL_FROM=you@yourdomain.com
SMTP_HOST=smtp.zoho.com
SMTP_PORT=587
SMTP_USER=you@yourdomain.com
SMTP_PASS=your-app-passwordcestdone send-email \
--to recipient@example.com \
--subject "Build complete" \
--body "All phases finished successfully."In a spec file, you can instruct the Worker to send an email:
When all tasks are complete, send a notification email:
cestdone send-email --to team@example.com --subject "Deploy done" --body "All phases completed."The provider abstraction supports adding new providers (SendGrid, SES, etc.) by implementing the MailProvider interface.
Just plain text. Describe what you want:
Build a dashboard that shows project metrics.
Scrape data from ITM Platform and render charts with Chart.js.
Add a refresh button and auto-update every 5 minutes.
The Director turns this into a structured .plan.md with phases, which becomes the source of truth for tracking progress. The original spec is never modified.
Optionally provide a --house-rules file with coding standards, conventions, or constraints that apply across all phases.
If you find cestDone useful, check out Olkano — a daily check-in app for people who live or spend time alone. One tap to say you're OK; your trusted contacts only hear from us if you don't. Because the best safety net is the one you never notice until you need it.
ISC