ai-foreman
v2.0.2
Published
An orchestrator that keeps Codex CLI / Claude Code builders moving through their step list unattended. Part of Rafi.
Maintainers
Readme
ai-foreman
Loop Claude Code or Codex through tickets.
- No more typing
"next step"all day. - QA cycle included (disable with
--no-qa) - Uses its own smart local ticket tracking system (support for other systems possible later)
- Project plans still work when you do not want a tracker.
- One-off task files still work too.
Why
- Enforces TDD — the builder role is compiled from rule packs that require tests before implementation, red-green-refactor discipline, and test coverage gates on every ticket.
- Enterprise stability from day one — security, observability, robustness, and scalability rules are baked into every builder turn, not bolted on later.
- Rich ticket system — tickets carry acceptance criteria, required tests, dependencies, priority, size, and risk level. The agent reads the full context before starting each step.
- Future work tracking — when the builder discovers out-of-scope work during a run,
ai-foreman tickets discovercaptures it without derailing the current ticket. Discovered items live in a separate inbox until you promote them. - QA that actually gates — QA runs after every completed ticket and checks code quality, test passing, and regression protection. The ticket only closes after QA passes. QA turns do not count against
--steps. - Visible long-running work — semantic activity rows identify provider, phase, tools, retries, and quiet periods; safe record output coalesces spinner- and time-only changes.
Provider-managed retries are reported immediately as durable lines. A quiet-provider warning appears after 60 seconds without a signal, but Foreman does not add retries, abort the provider, or change provider retry limits. Non-TTY output emits the initial and meaningful status changes without ANSI redraws. Automatic TTY output also uses newline records and suppresses spinner-, elapsed-time-, and number-only repeats, making it safe for transcript hosts. Set RAFI_ACTIVITY_RENDER_MODE=cursor to explicitly enable animated in-place redraws in a known real terminal; records explicitly forces safe records, while auto selects the safe default.
Install
Global install:
npm install -g ai-foremanHelpful when:
- You want
ai-foremanavailable from any repo. - You use Foreman across multiple projects.
- You do not need each repo to pin its own Foreman version.
Per-project install:
npm install --save-dev ai-foreman
npx ai-foreman doctor .Helpful when:
- You prefer
npx ai-foremanover a global CLI. - You want Foreman tracked in
package.json. - You want teammates or CI to use the repo's installed version.
Requires:
- Node.js 24.
Claude runtime and enterprise authentication
Foreman first resolves and probes the system claude command, then passes that exact absolute executable path to the Claude Agent SDK. It does not use the SDK's bundled Claude executable. SDK sessions inherit the current environment and load Claude's user, project, and local settings; organization-managed policy remains applied by Claude Code. This preserves enterprise SSO such as /login-okta, managed settings, and proxy/certificate configuration.
The SDK package is an optional dependency of ai-foreman. Do not install @anthropic-ai/claude-agent-sdk into the application being built unless that application independently uses it.
Run ai-foreman doctor . to see the selected executable, SDK-wrapper status, settings sources, and relevant environment-variable names. Add --live-claude for a bounded, no-tools request through the real adapter path. That opt-in check uses account quota.
Use
- Check the target project.
- Initialize Foreman's local ticket tracker.
- Ask the ticket-maker role to convert existing tickets or populate them
- Run foreman for 5 tickets (and QA each one when done)
ai-foreman doctor ./my-project
ai-foreman tickets init --project ./my-project --app-name "My App"
ai-foreman tickets populate --project ./my-project --agent codex --model gpt-5.5 --effort xhigh
ai-foreman start ./my-project --agent codex --model gpt-5.5 --effort xhigh --steps 5
ai-foreman state export ./my-project --output rafi-state.rafi.gzWhat each part does:
./my-project: the repo Foreman will work on.tickets init: creates the local.tickets/tracker.tickets populate: generates tickets from an approved structured Rafi plan, with optional supporting context.- Converted output uses Foreman's schema.
start: drives Codex through the next tickets one step at a time.
In approved_plan mode, tickets populate requires a validated <docs.root>/rafi-plan.json. Supporting documents and URLs add detail but cannot replace its slices. external_import is a separate mode for importing configured Linear or Jira tickets.
Supporting context can include:
- plans
- TODOs
- roadmap docs
- ticket files
- folders or globs containing planning notes
Move Local State Between Machines
Use ai-foreman state export for a sequential handoff from one checkout to another:
ai-foreman state export ./my-project --output rafi-state.rafi.gz
ai-foreman state inspect rafi-state.rafi.gz
ai-foreman state import ./matching-checkout rafi-state.rafi.gzThe bundle includes the local tracker database, delivery state, workflow/recovery databases, compiled role bundles, source snapshots, interview recovery records, and diagnostic run/recovery files. It does not include source code, provider sessions, or live worktrees. Export/import refuse dirty Git checkouts, active workflow leases, incompatible branch/HEAD state, and divergent transfer lineage. Import asks before replacing existing local state unless --yes is supplied, keeps a backup under .rafi/state-transfer-backups/, and rolls back failed imports.
Provider sessions are historical after import. Resume with rafi build:resume <project> --fresh-with-handoff or the equivalent guided recovery path when exact session recovery is unavailable.
Primary Options
ai-foreman start
| Option | Common values | Default | Notes |
| --- | --- | --- | --- |
| <project> | ./my-project / ../repo | required | Target repo the agent works in. |
| -s, --steps <n> | 1 / 5 / 10 | required | Max tickets or implementation steps to drive. |
| -a, --agent <agent> | claude / codex | single rafi-config.yaml target, otherwise claude | Builder agent. Explicit --agent always wins. |
| -m, --model <model> | gpt-5.5 / any supported agent model | agent default | Overrides the builder model. |
| --effort <level> | Claude Code: low / medium / high / xhighCodex: low / medium / high / xhigh | agent default | Reasoning level. |
| --fast | flag | off | Use native fast mode when the selected model supports it. Otherwise continue at standard speed with the same model and reasoning settings. |
| -t, --tickets <path> | .md / .txt / .yaml | auto-detects standard tracker files | Sends a task file to the builder during preflight planning. |
| -y, --yes | flag | off | Skips preflight confirmation. |
| --no-qa | flag | QA on | Disables per-ticket QA review. |
| --continue | flag | off | Resumes the most recent logged session. |
| -r, --resume <sessionId> | session ID with a stored scoped binding | none | Resumes only after provider, canonical worktree, and workspace identity validation. |
| --branch-per-ticket | flag | off | Runs each selected structured ticket in its own git worktree and branch. Requires initialized .tickets/. |
| --create-pr | flag | off | Pushes each successful ticket branch and creates a GitHub PR. Implies --branch-per-ticket. |
| --pr-ready | flag | draft PRs | Creates ready-for-review PRs instead of draft PRs when used with --create-pr. |
| --keep-worktrees | flag | remove successful worktrees | Keeps successful ticket worktrees for inspection. Blocked worktrees are kept automatically. |
| --ticket <id> | T001 | none | Selects a branch-mode ticket to continue. Repeatable with --continue. |
| --base <ref> | main / origin/main / HEAD | current branch or HEAD | Base ref for root ticket branches. |
| --branch-prefix <prefix> | feature / rafi / another valid Git prefix | feature | Prefix for generated ticket branches. Explicit prefixes are preserved verbatim. |
| --max-branch-depth <n> | positive integer | 5 | Maximum selected branch/PR stack depth (root PR is depth 1). |
| --show-session-cost / --hide-session-cost | flags | saved role preferences | Show authoritative provider cost or trustworthy cumulative tokens for Builder and QA; does not change context occupancy display. |
| --auto-compact-threshold <percent> | integer 1–99 | saved Builder value, then 65 | Initial run threshold override. A newer persistent settings revision wins at the next safe boundary. |
Auto-detected tracker files:
- configured
paths.progress_docfrom.tickets/config.yaml docs/ticket-progress.mdticket-progress.md
Resume rule:
- Use either
--continueor--resume. - Exact resume requires the original canonical worktree and its recorded identity. A deleted, recreated, cross-worktree, ambiguous, or unverifiable session is rejected with fresh/handoff recovery guidance.
- Do not use both in the same command.
- In branch mode, use
--continue --ticket <id>to continue a ticket with its saved builder session. - For multiple branch tickets, repeat
--ticketwith--continue; do not reuse one explicit--resume <sessionId>across multiple tickets. - When a branch run ends blocked, Foreman prints paste-ready continue commands for resumable tickets.
Branch-mode examples:
ai-foreman start ./my-project --steps 3 --branch-per-ticket --agent codex
ai-foreman start ./my-project --steps 3 --create-pr --pr-ready --agent codex
ai-foreman start ./my-project --steps 3 --completion auto-merge --provider gitlab
ai-foreman start ./my-project --steps 3 --completion direct-merge
ai-foreman start ./my-project --steps 1 --branch-per-ticket --continue --ticket T001Saved tickets.build defaults in rafi-config.yaml can enable branch-per-ticket and completion behavior automatically. Use --completion pr|auto-merge|direct-merge|none, --no-branch-per-ticket, --no-create-pr, or --auto-merge-wait / --no-auto-merge-wait to override saved defaults for one run.
With the saved current strategy, Foreman works in the active branch while the user owns Git. It may edit, test, run QA, and update tracker/recovery state, but all branch/worktree, commit, push, merge, rebase, and review lifecycle commands are fenced. An unexpected active ref or worktree change pauses the run. Explicit isolated flags are reported as run overrides.
Build stall recovery uses current context occupancy, not lifetime token usage. The compact session strategy checks occupancy at ordinary boundaries and compacts only when the threshold requires it; fresh still creates an intentional new session. Compaction normally has a 120-second deadline, extending to at most 180 seconds only after correlated progress. Late completion is attributed to the original session; unresolved attempts remain quarantined across restart. Unknown completion pauses recovery rather than replaying implementation in a replacement session.
Unchanged, source-bound plan and ticket approvals are reused. Material ticket, plan, delivery, or workflow changes require a new decision, including with --yes. Legacy approval evidence that cannot prove unchanged scope requires review. --steps counts completed tickets or steps; it is neither a wall-clock limit nor a model-turn budget.
Questions are persisted before prompting. Redirected or detached runs return a recoverable needs-input outcome (exit 2). Use rafi build:attach . --run <id> to see decisions, rafi build:decide . --run <id> --decision <id> --choice <id> to answer, and rafi resume to select a build and continue. Custom answers additionally use --choice custom --answer "text". Independent eligible tickets continue around a ticket blocker; dependent and unsafe shared-delivery work stays deferred. Answered ticket questions are reconsidered at safe boundaries.
CLI starts run under a durable parent supervisor by default. --detach writes output under .rafi/logs/supervisor-<run>.log; --no-supervisor retains direct execution. A preparation-only worker crash may restart within frozen budgets after proving the worker and registered readiness children are stopped. A worker crash with unresolved provider work pauses for reconciliation: it does not silently repeat a possibly completed action. build:stop signals only a verified supervisor process incarnation.
Runtime deadlines can be overridden in autonomy.runtime_deadlines using positive integer milliseconds: preparation_ms (120000), rpc_ms (60000), compaction_ms (120000), shutdown_ms (10000), and turn_ms (3600000). They are frozen with the run policy. Transport-idle and hard active-turn deadlines have distinct meanings; neither grants permission to repeat uncertain side effects. Attached-process elapsed time includes waiting and is not provider compute time. Activity warns after five minutes without a completed tool or agent turn; intentional human waits are excluded, and the warning alone does not cancel work. Final paused output lists the durable question, its answer command, and the short rafi resume recovery command.
The current terminal status includes the role/provider, activity, truthful context state, successful compaction count, and handoff generation. At the Builder threshold, Foreman settles the in-flight action, verifies native compaction plus a fresh provider usage sample, and resumes the frozen action. The configured maximum defaults to ten successful compactions per location-scoped provider session; the next crossing uses a validated fresh handoff instead of exceeding it. Disposable QA snapshots never reuse a prior QA conversation in a new /tmp/rafi-qa-* worktree; they transfer cumulative state through an accepted handoff.
Failed QA reviews use the versioned RAFI_QA_FAILURE_REPORT_START / RAFI_QA_FAILURE_REPORT_END JSON contract. Foreman validates the report before Builder remediation, namespaces finding IDs by run, ticket, and review, and durably indexes the exact report, remediation response, and bounded fix summary by digest. A malformed failing report receives two correction-only turns in its original session, then a validated fresh successor performs one complete source-bound review followed by up to two correction-only turns. Any later operator-requested fresh successor performs one complete source-bound review followed by five usable correction-only turns.
A completed QA turn with missing/invalid continuity metadata or a malformed response can trigger one automatic complete fresh review per ticket. That allowance is durable across restarts and shared across protocol failures. The old session and snapshot close before the new review starts. Exhausted same-session report correction and malformed resumed report/acknowledgement responses use this route, rather than requiring an immediate manual resume. Earlier invalid responses cannot authorize Builder work or a QA pass. Provider execution failures, uncertain dispatch, invalid acceptance receipts, and modified recovery evidence still pause. Repeated failures exhaust the allowance and preserve recoverable state; independent eligible tickets can continue.
Owner-only recovery packets under .foreman/qa-report-recovery/ bind the review to a full frozen source digest: commit, porcelain status, staged and unstaged bytes, and untracked content. Every fresh attempt captures and compares that complete state. Drift appends the new state and forces a complete review; correction-only reconstruction is never applied to changed source. Packet revisions and the authoritative WorkflowDb recovery head advance together. A successor must have a location-scoped identity, accept a handoff containing the complete resource inventory (purpose, byte count, digest, and recovery requirement), and acknowledge the copied packet before reporting. Paused recovery is available through rafi resume or rafi build:resume in the project directory. The picker resolves the ticket, current QA revision, and validated QA handoff internally; explicit recovery flags still reject stale revisions.
ai-foreman manager
Manager provides project-wide diagnostic conversations and explicitly authorized, scoped controls over retained build runs. It starts with a verified live run when one exists, otherwise the most recently updated run; --run <id> changes only that initial focus. Each question refreshes the catalog, active state, deterministic aggregates, and relevant run details.
Permanent sanitized run summaries keep timing, counts, provider/model configuration, usage coverage, failure category, and terminal Git facts useful after detailed spans expire. Detailed spans retain the configured 30-day policy. Missing historical facts are reported as partial rather than reconstructed or treated as zero.
When the initial bounded packet omits evidence needed for a question, Manager can request catalog rows, aggregates, comparisons, or details through a host-validated read-only lookup. Each question is limited to two rounds, six operations per round, five detailed runs per operation, and fifty catalog rows per list operation. Questions, answers, and lookup envelopes are not stored as project evidence.
ai-foreman manager ./my-project
ai-foreman manager ./my-project --run <run-id> --ask "Compare this run with the last five successful runs"Full QA history is available without a provider through --ask '/qa-work <run>', /qa-attempts <run> <work>, /qa-report <run> <work> <attempt> [occurrence], and /qa-timeline <run> <work>. One-shot output expands all pinned pages and artifacts before exiting, independently of bounded model packets. /qa-export <run> <work> <attempt> [occurrence] exports exact protected report bytes with their identity and digest. Interactive /more <cursor> and /artifact <handle> continuations belong to that session; a later invocation retrieves fresh evidence. Reads do not migrate workflow state.
Explicit /guide-builder, /guide-qa, and /guide-both commands take a run, work ID, and exact advice. The owning process delivers one-use guidance at its next safe boundary. /pause <run> <work> [run] waits for the active turn to finish; withdraw the pause to allow continuation. /request-attempt <run> <work> <reason> grants one existing-ledger attempt authorization for the current failed review or waiting Builder guidance after an unfinalized pass. Guidance alone never grants attempts. Inspect truthful delivery and verification receipts with /qa-instruction <run> <work> <instruction>.
If QA passes while Builder guidance is waiting, explicit resume applies that guidance within the existing approved ticket scope and remaining attempt allowance, then performs a complete fresh QA review. This works on the current branch and in isolated ticket worktrees. The follow-up consumes the same durable allowance as QA remediation; neither a fresh review nor a restart resets it. When the allowance is exhausted, authorize one scoped follow-up with /request-attempt, then resume. Changed requirements need renewed approval, and uncertain submissions require reconciliation before another Builder turn. Saving guidance alone does not start work.
Ownership schema 4 requires admitted work before Builder/QA dispatch. Legacy QA records are retained in quarantine when authorization cannot be proved. Both resume aliases assess conflicts before selecting recovery mode. Use /qa-conflicts <run> and /qa-repair-plan <run> <work> to inspect the source mapping, then submit an explicit /qa-repair <JSON> decision with the displayed revision, source digest, approved scope, complete path mapping, and operator attestation. Stop the existing owner first. Repairs preserve source and historical packets and require fresh verification; uncertain provider dispatch needs separate reconciliation.
The upgrade stores a coherent database backup and recovery packet copy under .rafi/backups/work-admission-v4/<database digest>/ before committing its guards. Rollback means pausing execution and preserving newer evidence for forward repair. Older writers are rejected against upgraded databases; do not down-migrate or restore a backup without accounting for subsequent provider work.
GitHub PR Failure Recovery
When --create-pr cannot prepare GitHub, push a branch, or create a PR, Foreman records a structured failure and blocks the affected ticket cleanly. Blocked worktrees are retained automatically so you can repair the environment and retry without losing the ticket session.
ai-foreman status ./my-project shows the latest GitHub failure code, repair commands, last command output, and a retry command when a resumable ticket session exists.
Common failure codes:
| Code | Meaning |
| --- | --- |
| gh_missing | GitHub CLI is not installed or not on PATH. |
| gh_not_authenticated | gh is installed but not authenticated for the remote host. |
| repo_unreachable | gh repo view cannot access the target repository. |
| git_remote_unreachable | git ls-remote cannot access the configured remote. |
| network_or_timeout | A GitHub or git command timed out or hit a network error. |
| push_failed | The ticket branch could not be pushed. |
| pr_create_failed | The branch pushed, but PR creation or PR body writing failed. |
For GitHub Enterprise remotes, repair commands include the remote host:
gh auth login --hostname <host>
gh auth status --hostname <host>
gh repo view <host>/<owner>/<repo>ai-foreman tickets populate
| Option | Common values | Default | Notes |
| --- | --- | --- | --- |
| -p, --project <dir> | ./my-project / ../repo | current directory | Target repo with .tickets/. |
| -a, --agent <agent> | claude / codex | single rafi-config.yaml target, otherwise claude | Builder agent. Explicit --agent always wins. |
| -m, --model <model> | gpt-5.5 / any supported agent model | agent default | Overrides the builder model. |
| --effort <level> | Claude Code: low / medium / high / xhighCodex: low / medium / high / xhigh | agent default | Reasoning level. |
| --sources <paths...> | docs/tickets.md docs/plans/** | saved context, subject to source_handling | Supplemental files, folders, URLs, or globs. Passing an approved rafi-plan.json remains supported; ordinary documents cannot replace the approved plan. |
| --fast | flag | off | Lower latency. |
| -y, --yes | flag | off | Skips confirmation before builder edits ticket files. |
Use ai-foreman tickets setup:init or setup:update to manage supporting local/URL context and external Linear/Jira connections in the project-wide registry in rafi-config.yaml. Linear imports use LINEAR_API_KEY; Jira Cloud imports use JIRA_EMAIL and JIRA_API_TOKEN. Credentials are never persisted, and mirrored tickets retain source provenance.
Use ai-foreman tickets review to accept, defer, or dismiss pending split/combine/duplicate recommendations rendered in the progress doc.
What Foreman Does
During a run, Foreman:
- asks the builder for a short plan
- sends one ticket or implementation step at a time
- requires a final
STEP_STATUSmarker - runs QA after each completed step by default
- writes a JSONL log under
.foreman/
When .tickets/config.yaml exists, Foreman also:
- uses the local ticket tracker automatically
- marks the first eligible queue row
in_progress - marks the ticket
doneonly after QA passes
Without tickets, Foreman still works with:
- a one-off task file
- a plain project directory
Agents And Task Files
Claude Code:
- Default agent when no single runtime target is configured.
- Uses your existing Claude Code credentials.
- Runs through the Claude Agent SDK.
startandtickets populatecheck Claude auth before launching the builder and prompt you to repair it, switch to Codex for the current run, or cancel when interactive.
Codex:
- Use
--agent codex, or setharness.targets: ["codex"]inrafi-config.yamland omit--agent. - Shells out to
codex exec. - Requires the
codexCLI on yourPATH. startandtickets populate --agent codexcheck Codex auth before launching the builder and prompt you to repair it, switch to Claude for the current run, or cancel when interactive.
Runtime defaults and recovery:
- If
--agentis omitted, Foreman readsrafi-config.yaml. A singleharness.targetsvalue selects that runtime; missing config or both targets default to Claude. - Non-interactive and
--yesruns fail clearly instead of switching runtimes automatically. - Resume and continue flows do not offer runtime switching because session IDs are runtime-specific.
- If an interactive command switches providers, a provider-specific
--modeloverride is ignored for that run.--effortand--fastremain in effect. - Cancel stops the command and keeps project files, generated files, and installed packages in place.
Task file:
ai-foreman start ./my-project --steps 5 --tickets ./my-project/TICKETS.mdWith --tickets:
- Point at any file.
- Foreman sends that file to the builder during preflight planning.
Common formats include:
- Markdown
- text
- YAML
Ticket Setup
Tickets are optional.
Use them when you want the repo itself to contain:
- the canonical implementation order
- the generated agent-facing progress document
- the shared queue
- the shared status
1. Initialize Tickets
From anywhere:
ai-foreman tickets init --project ./my-project --app-name "My App"From inside the project:
ai-foreman tickets init --app-name "My App"Init options:
| Option | Common values | Default | Notes |
| --- | --- | --- | --- |
| -p, --project <dir> | ./my-project / ../repo | current directory | Project to initialize. |
| --app-name <name> | "My App" | none | Application name stored in tracker config. |
| --timezone <tz> | America/Chicago / UTC | UTC | IANA timezone. |
| --implementation-limit <n> | 250 / 500 / 1000 | 500 | Implementation queue window for generated docs and Foreman selection. |
| --view-limit <n> | 1000 / 20000 | 20000 | Default row limit for the display queue command. |
| --queue-limit <n> | 250 / 500 / 1000 | none | Deprecated alias for --implementation-limit. |
| --docs-root <dir> | docs / docs-rafi | rafi-config.yaml docs.root, then docs | Root for generated progress/archive docs. |
tickets init reads docs.root from rafi-config.yaml when present. --docs-root overrides that value. The selected root must be a safe repo-relative directory, and init refuses to overwrite an existing selected ticket-progress.md.
Init writes implementation_limit and view_limit to .tickets/config.yaml. Existing configs with queue_limit still load as an implementation limit, with the old default value 50 upgraded to 500.
This creates:
.tickets/
config.yaml
tickets.yaml
tracker-rules.md
ticket-state.sqlite
schema/
migrations/
backups/
docs/
ticket-progress.mdWith --docs-root docs-rafi, the generated tracker docs are written under docs-rafi/ instead.
2. Add Tickets
If the project already has planning material:
- Ask the ticket-maker role to convert it into Foreman's ticket format.
Supported source material can include:
- tickets
- plans
- TODOs
- roadmap docs
- Markdown trackers
- folders or globs containing planning notes
# Claude Code
ai-foreman tickets populate --project ./my-project
ai-foreman tickets populate --project ./my-project --sources docs/rafi-plan.md
ai-foreman tickets populate --project ./my-project --sources docs/tickets.md docs/plans/**
# Codex
ai-foreman tickets populate --project ./my-project --agent codex
ai-foreman tickets populate --project ./my-project --agent codex --model gpt-5.5 --effort xhighpopulate tells the builder to:
- read
.tickets/* - read the configured progress doc
- prefer the configured Rafi
<docs.root>/rafi-plan.md, then the ticket docs root, thendocs/rafi-plan.mdwhen no--sourcesare provided - read existing planning files
- fill
.tickets/tickets.yaml - render the progress doc
- validate the result
If the existing content does not map cleanly:
- The builder should ask you for guidance.
You can also edit .tickets/tickets.yaml manually.
Storage model:
- Ticket definitions live in YAML.
- Mutable status lives in SQLite.
- Status changes should use
ai-foreman ticketscommands.
Minimal valid example:
tickets:
- id: T001
order: 1000
title: Add health check command
area: CLI
priority: P1
size: S
risk: Low
depends_on: []
summary: Add a command that reports whether Foreman is configured correctly.
acceptance:
- The command exits 0 when required local checks pass.
- The command prints actionable warnings for optional missing tools.
required_tests:
- Unit test for success output
- Unit test for missing optional tools
likely_files:
- src/index.ts
- test/*.test.ts
rollback: null
notes: null
- id: T002
order: 2000
title: Document health check command
area: Docs
priority: P2
size: XS
risk: Low
depends_on:
- T001
summary: Add README examples for the health check command.
acceptance:
- README shows the command in the quick start.
required_tests:
- Documentation review
likely_files:
- README.md
rollback: Revert the README section.
notes: nullTicket fields Foreman expects:
| Field | Required | Notes |
| --- | --- | --- |
| id | yes | Stable ticket ID, unique within the file. |
| order | yes | Unique implementation order. Use gaps like 1000, 2000. |
| title | yes | Short human-readable title. |
| area | yes | Product or code area. |
| priority | yes | Allowed: P0 / P1 / P2 / P3. |
| size | yes | Allowed: XS / S / M / L / XL. |
| risk | yes | Allowed: Low / Medium / High. |
| depends_on | yes | Array of ticket IDs. Empty array is fine. |
| summary | yes | Short implementation summary. |
| acceptance | yes | Non-empty list of completion criteria. |
| required_tests | yes | Non-empty list of expected validation. |
| likely_files | yes | Expected files or globs. Empty only when unknown. |
| rollback | required for Medium/High risk | Rollback or mitigation notes. |
| notes | optional | Extra context. |
Do not put status fields in .tickets/tickets.yaml.
These belong in .tickets/ticket-state.sqlite:
status
last_worked_at
completed_at
attempt_count
last_error
evidence
current_step
blocked_by
validation_result3. Validate And Render
ai-foreman tickets validate --project ./my-project
ai-foreman tickets render --project ./my-project
ai-foreman tickets queue --project ./my-projectGenerated output:
- The configured progress doc is generated from
.tickets/tickets.yaml. - It also includes state from
.tickets/ticket-state.sqlite. - Builders should read it.
- You should not manually edit generated sections.
4. Run Foreman
Claude Code:
ai-foreman start ./my-project --steps 10Codex:
ai-foreman start ./my-project --agent codex --model gpt-5.5 --effort xhigh --steps 10Common Commands
# Check environment and config
ai-foreman doctor ./my-project
# Show the latest run summary
ai-foreman status ./my-project
# Disable per-step QA
ai-foreman start ./my-project --steps 5 --no-qa
# Resume the latest session / a specific session
ai-foreman start ./my-project --steps 5 --continue
ai-foreman start ./my-project --steps 5 --resume <session-id>
# Export, inspect, and import local Rafi state
ai-foreman state export ./my-project --output rafi-state.rafi.gz
ai-foreman state inspect rafi-state.rafi.gz
ai-foreman state import ./matching-checkout rafi-state.rafi.gzTicket Lifecycle Commands
After init, populate, validate, and render (covered in Ticket Setup above), these commands manage tickets day-to-day:
# Update a ticket's next action
ai-foreman tickets update T001 --project ./my-project --next-action "Add tests"
# Mark a ticket complete manually
ai-foreman tickets complete T001 --project ./my-project --evidence "pnpm test passed"
# Block / unblock
ai-foreman tickets block T001 --project ./my-project --blocked-by external-api --summary "Waiting on API key"
ai-foreman tickets unblock T001 --project ./my-project --summary "API key received"
# Capture future work discovered during a run
ai-foreman tickets discover --project ./my-project --summary "Add retry metrics" --rationale "Needed for operations"
# Promote discovered work into tickets.yaml
ai-foreman tickets accept-future-work 1 --project ./my-project --ticket-id T051 --order 51000
# Cancel / reorder / archive
ai-foreman tickets cancel T001 --project ./my-project --summary "Superseded by T002"
ai-foreman tickets reorder T051 --project ./my-project --after T050
ai-foreman tickets archive --project ./my-project --older-than-days 30
# Inspect immutable creation groups and reset an exact approved group
ai-foreman tickets groups list --project ./my-project
ai-foreman tickets reset --group TG-3 --project ./my-projectTicket creation groups use stable repository-local IDs (TG-1, TG-2, …); newest-first list position is separate and may change. Missing definitions remain immutable members with a validated recovery snapshot. Non-interactive group restoration requires an explicit deleted-ticket policy, and missing dependency definitions stop the reset atomically.
How The Loop Works
Before implementation starts:
- Foreman asks the builder to list the next
Nsteps. - You confirm or revise that list.
- Passing
--yesskips confirmation.
Every implementation turn must end with exactly one marker.
Builder and QA turns also publish a bounded cumulative continuity delta. Automatic fresh transitions stage a versioned JSON/Markdown handoff, require HANDOFF_ACCEPTED plus a valid successor checkpoint, and only then move the role lease. The all-in-one rafi CLI exposes durable handoff inspection and cache/history maintenance commands.
Marker rules:
- Put the marker on the final non-empty line.
- Use one of these forms:
STEP_STATUS: done | ticket="T001" summary="implemented health check" next="document command"
STEP_STATUS: blocked | ticket="T001" reason="missing DATABASE_URL"
STEP_STATUS: plan_complete | ticket="T001" summary="all requested work is complete"
STEP_STATUS: needs_input | question="Which storage backend?" choices="SQLite|Postgres"Provider-native AskUserQuestion prompts preserve their existing input/output behavior. Hosts may also observe a question only after the user successfully supplies a non-empty answer; cancelled, denied, malformed, and empty prompts do not emit answered-question telemetry. Rafi uses this boundary to recognize machine-shaped exhaustive-planning exchanges without treating generic questions as grill-me coverage.
When QA is enabled, Foreman creates an independent read-only review snapshot. A pass ends with:
STEP_STATUS: qa_pass | summary="tests pass and acceptance criteria are met"Failure uses a structured report immediately before the status marker (the short issues field is only a human synopsis and fallback input):
RAFI_QA_FAILURE_REPORT_START
{"version":1,"summary":"missing empty-config coverage","checks_run":[{"check":"tests","command":"pnpm test","outcome":"failed","evidence":"empty-config case is absent"}],"findings":[{"id":"F1","requirement":"empty config is handled","locations":["src/config.ts","test/config.test.ts"],"problem":"no regression case exists","evidence":"test search found no empty-config case","expected":"the suite covers empty config","fix_direction":"add the missing case and repair behavior if needed","verification":["pnpm test"]}],"observations":[]}
RAFI_QA_FAILURE_REPORT_END
STEP_STATUS: qa_fail | issues="missing test for empty config"If QA fails:
- Foreman sends the Builder the complete validated report, ticket requirements, current source digest, and prior report/remediation history.
- Foreman reruns QA.
- QA turns do not count against
--steps.
Permissions
Foreman's permission policy is deterministic.
- The policy does not use LLM judgment.
For Claude:
- The SDK surfaces tool requests to Foreman.
- Foreman classifies them with the project's
foreman.yaml. - Tools in
permissions.escalateToolsare denied. - File write tools are allowed only when their target stays inside the project.
- The inside-project check depends on the SDK surfacing the path to Foreman.
- Bash is denied if it contains an always-escalate substring.
- Bash is otherwise allowed only for configured prefixes.
- Every chained segment must start with an
allowBashprefix. - Supported project test forms include literal in-worktree
cd directory &&, constrainedPYTHONPATHor test environment assignments, existing project-local virtualenv Python/pytest executables, and2>&1.uv run --offline --no-syncmay wrap an already allowed test command. Every pipeline executable must be allowed. Configure additional test commands underpermissions.allowBashinforeman.yaml; PATH/loader overrides, substitutions, file redirection, and dependency acquisition remain separate decisions. - Unknown tools are denied.
- Unknown Bash commands are denied.
For Codex:
- Codex tool calls are not currently intercepted by Foreman.
- Runtime implementation and ticket population runs use
codex exec --sandbox workspace-write. - Read-only callers such as
rafi plancan requestcodex exec --sandbox read-only. - Codex safety depends on Codex's own sandboxing.
Default config:
- The default config lives in foreman.yaml.
- Copy it into a project when you need project-specific policy.
Development
From the monorepo root:
pnpm install
pnpm -r build
pnpm -r testFrom this package:
pnpm test
pnpm typecheck
pnpm build
pnpm dev -- start ../../examples/dummy-project --steps 2Package output:
- The package publishes an
ai-foremanbinary fromdist/index.js.
Current Limitations
- One builder at a time.
- No daemon or dashboard.
- Codex tool calls are not intercepted by Foreman's permission policy.
ai-foreman tickets importis currently a stub.- Escalated actions are denied and stop the batch.
- There is no approve/deny queue yet.
Part of Rafi
special-agents— library (rules + skills + agents + composition)ai-foreman— this runtime@rafi-ai/cli— CLI forrafi createandrafi compile
Recovery ownership upgrades
Stop existing workers before upgrading. The recovery database now records preparation admission, single-use launches, retry lineage, owned readiness processes and monotonic lease generations. Older binaries must not write an upgraded database; preserve these records when troubleshooting rather than deleting locks. Unknown process identity, incomplete child-launch evidence or an unresolved provider dispatch requires reconciliation. A stale heartbeat alone does not authorize another worker. Read-only resume inspection supports older storage without migrating it.
Ownership schema version 2 adds bounded child registration/acknowledgement, explicit child-workflow ownership, and separate readiness/cleanup outcomes. Build readiness requires the original admission and owning project even when the command executes in an external worktree. Both the current build and competing starts wait for verified probe cleanup. Runtime snapshot, dispatch, continuity and session writes retain original authority; releasing a lease does not make those records writable by an arbitrary caller. Completed, cancelled and superseded builds cannot be reactivated by saving a snapshot.
Ownership schema version 3 gates provider readiness behind registered helper authorization and records cleanup separately. Cleanup is reachable through both short resume commands even when its owning build is terminal or has no valid build snapshot. Restricted cleanup connections can update only their selected readiness records. Migration waits for local legacy execution to become safely quiescent; persistent compatibility guards then reject already-open older writers as well as new older opens. Uncertain remote provider records survive the upgrade unchanged so their owning recovery flow remains reachable. Ordinary starts remain blocked until those operations are reconciled. A lost acknowledgement cannot revoke an already-authorized helper.
Standalone readiness also rejects unverified cleanup. The current process retains its cleanup evidence and checks it before another probe starts; restoring process visibility permits a retry. Standalone commands do not create a build recovery database, so this evidence does not survive process exit.
On macOS/Linux, readiness cleanup checks the dedicated process group and inherited probe tags, including tagged descendants that escape the group. This is not a sandbox for descendants that deliberately remove their tag and detach. Unavailable inventory and ambiguous legacy evidence remain unresolved. The Windows readiness implementation targets Windows 10 / Server 2016 APIs, but those minimum versions have not been verified. Native Windows verification remains a release gate. Readiness providers start inside a non-breakaway Job Object with kill-on-close behavior, using built-in Windows PowerShell and Add-Type. Standard npm .cmd/.bat provider shims resolve to direct Node arguments; arbitrary shell shims are rejected. The Windows Job Object applies to readiness probes; it does not add containment for arbitrary Builder commands. Native regression tests are in .github/workflows/build-recovery.yml; the implementation plan records actual platform verification.
