Small feature
Implement a scoped new feature in a sandboxed worktree, refactor what you touched, write tests for the new public surface, gate on lint / typecheck / scenario / test, and land a commit.
What it does
feat-small is a five-stage pipeline tuned for net-new code: an implementation step, a refactor pass scoped to the files the implementation touched, a test-writer pass that adds minimal coverage for any new public surface, the deterministic gate with a fixer subagent, and a summary writer that produces the commit message and changelog entry. The full run is real claude (or codex) end-to-end.
When to reach for it
- You're adding new behavior — a new function, flag, endpoint, component →
feat-small. - The behavior already exists and is wrong → use
bug-fix.feat-smalldoesn't have a "find the bug" phase. - You want to clean up working code → use
refactor.feat-smallhas scope creep guardrails but its job is to expand the surface, not contract it. - The work is large enough to need design conversation → don't use any of these. Land a plan first; come back when the plan is concrete.
Quickstart
scratch/cli-quiet-flag.md:
Run:
The user-message file
Like every default agent, --user-message accepts either a markdown file path or an inline string. The feat-small pipeline is the most common case for the inline form, because briefs for tiny additions are often one paragraph long:
A markdown brief is still recommended once the feature has any structure:
The feat-small agent has a built-in test-writer step (see Pipeline below). You don't need to dictate the test plan — just describe the new public surface clearly enough that the test-writer can identify what to cover.
Pipeline
feat-small registers four steps plus a summary writer. Every step has the shared agents/_shared/prompts/agent-guidelines.md prepended to its system prompt.
The deterministic gate runs these five commands in order, all in the worktree:
Failures loop up to 3 iterations: the deterministic-fixer subagent reads the failing output, edits the worktree, then the gate re-runs. After 3 failed iterations the run is preserved as a FAIL.
Flags
Backends
Every run shells out to one CLI. The selector resolves in this order, flag winning on conflict:
--cli <claude|codex>on the subcommand.MUNCHKINS_CLI=<claude|codex>environment variable.claude(default).
codex requires the codex CLI on PATH and a prior codex login. The framework does not pre-validate this; failures surface as a non-zero exit from the spawn.
Cost reporting caveat. Codex's JSONL stream does not emit per-call cost. Runs that include any Codex-backed call render the cost field as — in the PASS line, the summary.json, and the changelog entry. Token in/out are still reported in full.
Integration modes
Strategy resolves: --integrate flag → author declaration on the builder → run-layer default (integrateMerge).
merge (default). Rebase the worktree branch onto your base branch, resolving any conflicts via the merge-fixer subagent (up to 3 iterations), then fast-forward your base branch to the rebased tip. Result: your branch points at the agent's commits. The summary writer's commit message becomes the head commit's title.
pr. Same rebase, then git push -u origin <branch> and open a PR/MR. Provider is auto-detected from the remote URL: GitLab if the URL contains gitlab, GitHub otherwise. The CLI used to open the PR is gh for GitHub and glab for GitLab — both must be on PATH and authenticated. The PR's title is the summary writer's commit message; its body is the markdown changelog entry. The PR URL is returned and printed in the PASS line.
What you get back
On success:
- A new commit on your base branch with the summary writer's message as the title (and a
docs(changelog): <title>commit beneath it for the changelog entry). - A prepended entry in your
CHANGELOG.md(path overridable viaMUNCHKINS_CHANGELOG_PATH) with the date, agent name, duration, cost, and a markdown body. summary.jsonwithtokensIn,tokensOut,costUsd,durationMs,agentSteps,deterministicCommands,fixerInvocations, the commit message, and the markdown body.events.jsonl— one event per Claude call, deterministic iteration, or fixer invocation.- Per-step
step-NN-agent.{system.md,user.md,response.txt}andstep-NN-det-iter-MM.log— exact prompts and outputs for each phase. The test-writer step also lands as astep-NN-agent.*triple.
When --integrate=pr succeeds, the PR URL is also printed in the PASS line.
Resuming an interrupted run
If you Ctrl-C, lose power, or the spawn crashes mid-run, the run state lives at .munchkins/runs/<slug>-<id>/state.json and the worktree stays intact.
<run-id> matches either the directory's run id or the slug (slug must be unambiguous). Replay semantics:
- Steps already marked
completedare skipped. - For an in-flight agent step, if the CLI captured a session id (Claude or Codex), the run resumes that session and the model picks up where it left off.
- If the session can't be restored (expired, CLI restarted, etc.) the step restarts with a worktree-state preamble appended to the system prompt:
git status --shortandgit diff --stat HEAD— so the model sees its partial work. - Resume restores the original
--user-message,--cli,--verbose, and--thinkingchoices via the env snapshot stored instate.json.
Scheduling
Cron a feat-small run by attaching .cron(spec, { userMessage, verbosity }) to the builder in your own bundle and starting the daemon:
The daemon parses each cron spec, prints the next firing time, and arms a timer per agent. The user-message is fixed per cron config — if you want a different brief on each tick, regenerate the markdown file from a wrapper script before the cron fires. Verbosity options: default, thinking, verbose.
Delegating from Claude Code
The launch-munchkin Claude Code skill hands a task off to a feat-small agent and exits. From within Claude Code:
"Launch a feat-small agent for the --quiet flag we discussed."
The skill picks the right subcommand, drafts a scratch/<slug>.md spec from the conversation, shows it to you for one confirmation, then fires bun run munchkins feat-small --user-message=<path> in the background. It does not poll or report back — the agent integrates its own commits when it's done.
Spec-only mode. Say "just write the spec" or "give me the command, don't run it" and the skill writes the markdown file, prints the exact CLI invocation, and stops without spawning anything.
Install the skills bundle into a host repo with bun run munchkins skills install.
Pass / fail behavior
Pass. Worktree branch is rebased and fast-forwarded into your base branch. The worktree directory is removed. The agent's branch is deleted. The PASS line prints the duration, tokens, cost, commit message, and (for --integrate=pr) the PR URL.
Fail. Worktree and branch are preserved at the printed path. Inspect the diff with cd <path> && git diff main, look at the prompts and responses under .munchkins/runs/<slug>-<id>/, and clean up by hand:
That removes the directory and the branch. (failureReason in summary.json and state.json tells you which phase exploded.)
Worked example — inline user-message
Sometimes the brief is short enough that a file is overkill. feat-small accepts the user-message inline:
Excerpt of what gets printed:
Resulting commit message:
Resulting CHANGELOG.md entry (prepended; default path is CHANGELOG.md):