Your AI sous chef. Spec it, let it cook.
A CLI tool for autonomous AI coding workflows powered by Amp and the Amp SDK. Write specs, let AI plan and execute the work task by task.
Inspired by Ralph Wiggum by Geoff Huntley, but with a different philosophy: heavy upfront planning and task-scoped execution to keep the agent in its smart zone.
Ralph Wiggum pipes a prompt to an AI agent and lets it figure out what to work on from a task list. The agent reads prd.json, picks a task, implements it, decides when it's done, and signals completion. Simple and effective.
I used Ralph via bash scripts happily until two things happened:
-
The task file grew. As
prd.jsonaccumulated tasks, the agent spent more and more tokens just parsing and deciding what to work on next. Implementation time shrank; orchestration overhead grew. -
PROGRESS.md exploded. Every iteration appended learnings. Eventually the agent was consuming thousands of tokens of historical context before writing a single line of code.
AI agents are perfectly capable of reading task lists, resolving dependencies, and deciding what to work on. But every token spent on orchestration is a token not spent on implementation.
letmecook separates concerns:
prep— AI does all the planning: task breakdown, dependency ordering, change location discoverygo— AI does pure implementation: no thinking about what's next, just build what's in front of it
The orchestration logic moves outside the agent's context:
flowchart LR
subgraph Ralph["Ralph"]
A1[Agent reads prd.json] --> A2[Agent picks task]
A2 --> A3[Agent implements]
A3 --> A4[Agent updates state]
A4 --> A5[Agent decides: done?]
end
subgraph LMC["letmecook"]
B1[CLI parses implementation.json] --> B2[CLI resolves dependencies]
B2 --> B3[CLI injects single task]
B3 --> B4[Agent implements]
B4 --> B5[CLI updates state]
end
The CLI programmatically:
- Parses
implementation.jsonand resolves task dependencies - Selects the next eligible task
- Injects only that task into the agent's context (description, change locations, acceptance criteria, verification steps)
- Updates task status when the agent completes
The agent never sees the full task list. It gets exactly what it needs for one task — nothing more.
| What | Ralph | letmecook |
|---|---|---|
| Task list in context | Full prd.json every iteration |
Never — CLI handles externally |
| Dependency resolution | Agent figures it out | CLI resolves before injection |
| Task selection | Agent reads and picks | CLI picks, agent just executes |
| State updates | Agent writes to files | CLI updates implementation.json |
| Context per task | Task list + selection logic + state | Single task with pre-resolved context |
| Progress history | Grows unbounded | reduce compacts to learnings + issues |
The reduce command solves the PROGRESS.md bloat problem. When the file grows too large, it uses AI to distill the history into consolidated learnings and outstanding issues. Future prep and go runs get the same institutional knowledge at a fraction of the token cost.
- External context control — CLI decides what the agent sees
- One task per turn — Agent focuses on implementation, not orchestration
- Programmatic state — Task status lives in TypeScript, not agent memory
- Pre-resolved dependencies — Agent never wastes tokens on dependency graphs
- Explicit verification — Each task includes how to prove it's done
letmecook is built exclusively on Amp for a few reasons:
- Single SDK, multiple models — Amp's SDK abstracts model selection. The Amp team decides the best models for different use cases, so we don't have to.
- Sub-agent support — The planner and builder can spawn sub-agents for parallel exploration and implementation.
- Web thread view — Every task execution creates a thread visible at ampcode.com. You can review what the agent did, share threads, and debug failures.
- Live streaming from CLI — Run
amp threads continue <id>to watch a task execute in real-time. Unlike other coding agents, you see exactly what's happening as it happens.
bun install
bun link# Initialize in your project
cd your-project
letmecook init
# Generate a spec from an idea
letmecook recipe "add dark mode with system preference detection"
# Or write specs manually in .letmecook/specs/
# Generate implementation plan
letmecook prep
# Trust the chef 🔥
letmecook go| Command | What it does | Flags |
|---|---|---|
init |
Sets up .letmecook/ in your project |
-f, --force to overwrite |
recipe |
AI generates a spec from your idea | <description> required |
prep |
AI analyzes specs → generates tasks | — |
go |
Executes tasks one by one until done | -y, --auto-confirm skip prompts |
reduce |
Compacts PROGRESS.md via AI summary | — |
flowchart LR
subgraph You
idea[💡 Feature Idea]
end
subgraph recipe["recipe"]
generate[📝 Generate Spec]
end
subgraph prep["prep"]
explore[🔍 Oracle Exploration]
plan[📋 Task Generation]
end
subgraph go["go"]
execute[🔧 Execute Task]
verify[✅ Verify & Log]
end
idea --> generate
generate --> explore
explore --> plan
plan --> execute
execute --> verify
verify -->|next task| execute
Use letmecook recipe "your feature idea" to generate a spec, or drop markdown files manually in .letmecook/specs/. Each spec describes a feature:
# Add Dark Mode
## Problem
As a user, I want a dark theme, so I can reduce eye strain at night.
## Intended users
All authenticated users.
## User journey
User opens settings → clicks theme toggle → UI switches to dark mode.
## Solution overview
A theme toggle in the settings page that persists preference to localStorage.
## Acceptance criteria
- [ ] Given I'm on any page, when I click the theme toggle, then the UI switches between light/dark
- [ ] Given I set dark mode, when I refresh the page, then dark mode persists
## Verification approach
- **Browser:** settings page, test toggle in both states
- **Automated:** unit test for theme context, e2e for persistence
## Notes
### Non-goals
- System preference detection (future spec)
### Edge cases
- No localStorage access (fallback to light)The Planner runs an autonomous exploration phase using Oracle to deeply analyze your codebase before generating tasks.
flowchart TD
A[Read Spec] --> B[Parse Requirements & ACs]
B --> C[Identify Exploration Targets]
C --> D[Oracle: Deep Codebase Analysis]
D --> E{Find patterns, usages,<br/>tests, dependencies}
E --> F[Synthesize Into Tasks]
F --> G[Validate Plan]
G --> H[Write implementation.json]
What Oracle discovers:
- File paths with line numbers for each change
- Existing patterns to follow
- Tests that need updating
- Dependencies and risks
Output: implementation.json — a prioritized task queue with:
- Task descriptions with concrete change locations (
file:line) - Story points (1, 2, 3, or 5—never 8, split instead)
- Dependencies between tasks
- Verification approach for each task
- Task-level acceptance criteria
The Builder picks up tasks one by one with a structured execution workflow:
flowchart TD
A[Load Next Pending Task] --> B[Pre-Flight: Read GUARDRAILS.md]
B --> C[Implement Changes]
C --> D[Post-Flight: Verify Guardrails]
D --> E{UI Changes?}
E -->|Yes| F[Browser Verification]
E -->|No| G{Backend Changes?}
F --> G
G -->|Yes| H[Run Test Suites]
G -->|No| I[Log to PROGRESS.md]
H --> I
I --> J[Commit & Push]
J --> K{More Tasks?}
K -->|Yes| A
K -->|No| L[Done]
Task execution includes:
- Pre-flight check — reads
GUARDRAILS.mdfor project rules - Implementation — uses sub-agents for parallel changes when possible
- Post-flight check — verifies all guardrails pass
- Frontend verification — loads
agent-browserskill to test UI changes - Backend verification — runs unit, integration, and e2e tests
- Progress logging — appends structured log to
PROGRESS.md - Commit — commits with spec name
Hit Ctrl+C anytime—the current task reverts to pending status for clean resumption.
After letmecook init:
your-project/
└── .letmecook/
├── config.json # Project settings, notifications
├── GUARDRAILS.md # Rules the AI must follow
├── PROGRESS.md # Audit log of completed work
├── implementation.json # The master task list
└── specs/ # Your feature specs go here
└── example.md # Template to get you started
{
"version": 2,
"updatedAt": "2026-01-24T10:30:00Z",
"specs": [
{
"id": "001-add-dark-mode",
"file": ".letmecook/specs/001-add-dark-mode.md",
"name": "Add Dark Mode",
"priority": 100,
"status": "pending",
"dependsOn": [],
"tasks": [
{
"id": "001-add-dark-mode-1",
"description": "Add theme context and provider",
"potentialChangeLocations": [
"src/context/theme.tsx:1 - create new file",
"src/app.tsx:12 - wrap with ThemeProvider"
],
"verificationApproach": [
"bun run typecheck",
"Visual check in browser at /settings"
],
"acceptanceCriteria": [
"ThemeContext provides theme and toggle function",
"App wrapped in ThemeProvider"
],
"points": 2,
"status": "pending"
}
]
}
]
}Get pinged when builds start, tasks complete, or something goes wrong. Configure during init.
Every completed task gets logged to PROGRESS.md with a structured format:
## [2026-01-24 14:30] - Add Dark Mode
**Guardrails:**
- Pre-flight: ✓
- Post-flight: ✓
**Verification:**
- `bun run typecheck` → PASS
- `bun run test` → PASS
**What was done:**
Added ThemeContext with light/dark toggle, wrapped App in provider.
**Learnings:**
- Use CSS variables for theme colors, not inline styles
- Toggle persists to localStorage
---Auto-compacts when it gets too long (via the compactor plugin).
Define rules in GUARDRAILS.md that the AI checks before and after each task. The build prompt enforces:
- Pre-flight: Read and understand guardrails before making changes
- Post-flight: Verify all guardrails pass after changes
Tasks can depend on other tasks. The planner figures out the order; the builder respects it. Specs can also depend on other specs.
When you run prep, older implementation.json versions are automatically migrated to the latest schema.
letmecook uses an event-driven architecture with a plugin system for extensibility.
flowchart TB
subgraph Commands
recipe[recipe command]
prep[prep command]
go[go command]
reduce[reduce command]
end
subgraph Services
specWriter[SpecWriter]
planner[Planner]
builder[Builder]
compactorSvc[Compactor]
executor[AmpExecutor]
end
subgraph Core["Event Bus"]
events[TypedEventEmitter]
end
subgraph Plugins
telegram[Telegram]
compactorPlugin[Compactor Plugin]
renderer[StreamRenderer]
end
recipe --> specWriter
prep --> planner
go --> builder
reduce --> compactorSvc
specWriter --> executor
planner --> executor
builder --> executor
compactorSvc --> executor
specWriter -.->|emit| events
planner -.->|emit| events
builder -.->|emit| events
executor -.->|emit| events
events -.->|subscribe| telegram
events -.->|subscribe| compactor
events -.->|subscribe| renderer
A typed TypedEventEmitter broadcasts events throughout the build lifecycle. Services emit events, plugins react to them.
Event categories:
| Category | Events | Purpose |
|---|---|---|
recipe:* |
started, completed |
Spec generation lifecycle |
plan:* |
started, completed |
Planning lifecycle |
build:* |
started, completed |
Build lifecycle |
spec:* |
started, completed, failed |
Per-spec progress |
task:* |
started, completed, failed |
Per-task progress |
amp:* |
started, message, completed |
Low-level Amp SDK stream |
Plugins live in src/plugins/impl/ and are auto-discovered at startup. Each plugin receives a PluginContext with access to events and config.
const myPlugin: BuilderPlugin = {
name: "my-plugin",
register(ctx: PluginContext) {
ctx.events.on("task:completed", async ({ taskDescription }) => {
// React to task completion
});
},
};Built-in plugins:
| Plugin | Purpose |
|---|---|
telegram |
Sends notifications on build/task events |
compactor |
Auto-compacts PROGRESS.md when it gets too long |
stream-renderer |
Renders Amp execution output to terminal |
An AppContext is created at startup and injected into services/plugins:
config— Parsed project configurationevents— The typed event emitterprojectRoot— Working directoryprojectName— From config or default
bun install
bun run typecheck
bun test- Geoff Huntley for the Ralph Wiggum methodology that this project implements
- Amp for the SDK that makes autonomous coding actually work
MIT
Now step back. The chef's got this. 🍳
