agents
無料Agent rules for Forge client apps with a chat agent or in-app assistant. Use before any agent, chat, voice or in-app assistant work: its shape, turn, memory, tools, output, safety, cost and tests.
日本語の概要は準備中です。原文の説明を表示しています。
Run Forge, which takes a story from approval to a merged pull request. Use when the human asks what to do next, wants to plan a story, start a task or fix, build, close, save a spec or decision, add to the roadmap, check the setup, or see the board.
日本語の概要は準備中です。原文の説明を表示しています。
実行スコア 未検証
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Start with forge next. It says where things stand and gives the exact next command.
Mainline Deploy is available to install through the organization's plugin catalog. Do not assume that the plugin and MCP are installed or that the user is signed in. Use Mainline Deploy only when the user explicitly requests deployment. First check whether it is installed in the current host. If it is missing, use the organization's plugin catalog and the host's installation flow. Do not invent an installation command or marketplace address. Then follow the Mainline Deploy skill. Check OAuth sign-in and have the user complete it if needed. Wait for successful authentication before deployment. Installation alone does not mean the user is signed in. Deploy only the requested app to the requested environment. A build, fix, merge, ship/land request, successful test or review, demo preparation, or Forge next step does not by itself authorize deployment. Do not install Mainline or start OAuth sign-in for those requests. An explicit request such as "deploy this to staging" or "publish this on Mainline" needs no separate routine deployment approval.
Our deploy platform reads services.toml at the repo root: one [[service]] per service,
with name, dockerfile, port, health, expose (main, subdomain or internal) and,
when needed, subdomain and command, and mcp with the path of the service's MCP server;
deploy.md in Forge's conventions has the details.
Close refuses a list that names a Dockerfile the branch does not have or does not have
exactly one main service. When a client repo has a Dockerfile and no services.toml, write
it before the first deployment the owner asks for: one service per Dockerfile the app runs,
the port from its EXPOSE line and the health path from the code. Show it to the owner and
ask with options: confirm it, or change a service's exposure. Then merge it in a fix. The
owner picks the main subdomain on the platform, so the list does not hold it.
In a starter app, the API service has mcp = "/mcp".
The first deployment that the owner asks for in a client repo is its deploy setup, and that request is the explicit request above. Follow the installed Mainline Deploy skill in this order, and skip a step that is already done:
services.toml. When the repo has none, write it as the paragraph above says and get
the owner's confirmation..env.example names, with the values the owner gives, except the
ones that the platform provides, such as DATABASE_URL.After the setup, do not deploy. Mainline deploys dev at each merge to the default branch and a preview for each pull request. These deploys are Mainline's, not an agent's, and need no request. Production changes only when a person presses Promote in Mainline. Never deploy or promote production, also when the owner asks: tell them to press Promote in Mainline. When the owner asks for another deployment after the setup, tell them that Mainline deploys dev at the next merge.
| The human says | Run |
|---|---|
| "What now?" | forge next |
| "Show me progress" | forge board |
| "I have an idea", "Fix this" or "Plan this" | forge start "<their words>" |
| "Read the plan cold" | forge read <KEY>, or forge read <slug> for a spec or decision |
| "I've amended it" | forge read <KEY> again, for the next round |
| "Start this task" | forge task start <KEY>/<TASK> |
| "Give this story or part to a developer" | forge assign <KEY or KEY/TASK> <login> |
| "Name this fix" | forge fix start "<why>" --done "<done when>" --slug <name> |
| "Change this fix's Done-when" | forge fix amend <fix> --done "<done when>" --because "<why>" |
| "Add to this fix's Done-when" | forge fix amend <fix> --append "<text>" --because "<why>" |
| "This fix is too big" | forge story new <KEY> --from-fix <fix> |
| "Make it a story" (a fix) | Add the key to the fix's roadmap and commit it, then forge story new <KEY> --from-fix <fix> |
| "Make it a fix" or "Just fix it" (a plan in planning) | forge fix start "<its Problem>" --done "<its first Done-when>", then forge story drop <KEY> --because "Moved to the fix <fix>" |
| "Do it later" (a fix) | forge fix drop <fix> --because "The owner wants it later", then forge start "Do this later: <its why> (kept on fix <fix>)". fix drop --undo brings it back |
| "Do it now" (an idea-list entry) | forge start "<the owner's new words>: <the entry's idea without its deferral words>", for example forge start "Do it now: add dark mode". Then remove the entry from the main checkout's file while it is waiting, or else in the new item's branch |
| "Let this fix go over the limit" | forge fix allow-large "<reason>" |
| "Build it" | forge work <item> |
| "Tell the worker this round" | forge work <item> --note "<text>" |
| "Ask about this code" | Hand the question to the session's explorer subagent role |
| "Close it" or "Is it ready?" | forge close <item> |
| "Land it" | forge land <item>, run in the background and watched like forge work |
| "Land everything that's ready" | forge land --all, run in the background; never a hand-made merge lane |
| "Merge this ready item" | forge merge <item> when the default branch allows agent merges |
| "Let the agent merge" | The owner runs forge merge enable in a terminal outside Claude Code or Codex; never you |
| "What should we build?" or "Find the real problem" | Discovery, below |
| "Is it worth building?" | forge spec payback --build-days <days> --day-rate <rate> plus a value group |
| "Save this spec" | forge spec save <slug> |
| "The spec is confirmed" | forge spec confirm <slug> --by "<name>" |
| "Record the check-back result" | In a fix: forge spec measure <slug> --result "<result>" |
| "Record a decision" | forge decision new <slug> |
| "The decision is accepted" | forge decision accept <slug> --by "<name>" |
| "What does the client still need to decide?" | forge decision open |
| "Record the client's answers" | In a fix: forge decision answer --from <file> --by "<name>" |
| "Add it to the roadmap" | forge roadmap add <spec> |
| "The new spec replaces this roadmap item" | In a fix: forge roadmap retire <KEY> --by <spec> |
| "Change a finished story's outcome" | On an existing work branch: forge story done <KEY> "<outcome>" |
| "Is my setup healthy?" or "Fix my setup" | forge doctor, then forge doctor --fix for what it can repair. On the default branch, repairs to Forge's files need a clean checkout at origin/<default> and use a dated fix forge-files-<YYYYMMDD-HHMM>: forge close <name>, then merge it like any other. An existing fix/forge-files-* branch with no merged or closed pull request blocks another repair, record or not; follow doctor's finish-or-remove step. Finished-work cleanup skips only the open doctor fix. If a repair already used this minute's name, run forge doctor --fix in the next minute. A file it holds back as changed by hand: move that change out of the file, then forge doctor --fix again. In AGENTS.md, only hand edits inside the forge:begin and forge:end lines hold the file; your rules outside them stay as written when doctor refreshes Forge's block |
| "Set up a new repo" | Before forge init, answer "Does this repo run GitHub Actions?" from the repo's settings: gh api repos/{owner}/{repo}/actions/permissions gives enabled. Ask the human only if the settings do not answer it. Pass --actions yes or --actions no; yes uses CI checks, while no selects laptop tests with checks = []. Then use forge init --starter for a new React app, forge init --starter python for a new app whose owner asks for a Python backend, or forge init for another stack. Propose a fast_test as in step 9 of Adopt a live app, below |
| "Bring our live app into Forge" | Adopt a live app, below |
| "Change the test command" | Ask, then in a fix: edit forge.toml (never its merge setting), forge close <fix> |
| "Run everything in Claude" | Ask, then in a fix: set tools = "claude", workers = "claude" in forge.toml, then forge sync, forge close <fix> |
| "Run everything in Codex" | Ask, then in a fix: set tools = "codex", workers = "codex" in forge.toml, then forge sync, forge close <fix> |
| "Use both" | Ask, then in a fix: set tools = "both" in forge.toml, forge close <fix> |
| "Change who builds just for me" | Edit forge.local.toml beside forge.toml in the main checkout (not a worktree): only tools, workers and [models.<kind>] tables. Git ignores it, so no fix; every worktree of that clone uses it. forge next and forge doctor name what it sets |
| "Close takes too long running every test" | In a local-test repo, ask, then in a fix: set fast_test in forge.toml, a command close runs instead of test, with {base} replaced by the merge base with the default branch (for example npx vitest run --changed {base} plus lint). In a CI-test repo, its pull request check runs related tests; the nightly full run covers the rest. Then forge close <fix> |
| "Upgrade Forge" | Ask which release, then forge upgrade <release>; Upgrade Forge, below |
forge doctor lists started fixes with no work commits after more than seven days.
Each row gives forge fix drop <fix> --because "<reason>". Only drop a fix after
the owner agrees. forge doctor --fix does not drop these fixes. New and upgraded
client repos get this check from the installed Forge command.
Send every new idea through forge start "<their words>". Never ask the human whether it is a
story or a fix. When the answer is a fix, run its forge land <fix> in the background and watch it.
The human approves stories and chooses between options. In a client repo before the default
branch has an accepted sign-off, the agent runs forge merge <item> once forge close says Ready.
After sign-off, the default branch's forge.toml merge setting applies: the human merges by
default (merge = "human"), or the agent runs forge merge <item> for merge = "agent".
Forge's own repo follows its setting throughout. Never run gh pr merge; the agent merges only
through forge merge. Ask one question at a time: a decision gets options with your recommendation
first, a question of fact gets neutral choices.
Every client repo moves through seven steps. forge next names the current step in its first line.
docs/context/ and read them all before you ask anything. You can say: "Here are the client notes" or "I have an idea: <idea>".docs/product/BRIEF.md from the notes, and ask only about a point that changes a screen, a field or a flow. You can say: "The brief looks right" or "Change this in the brief: <change>".The cold read loop. A reader who did not write the plan reads it cold and lists its gaps. You fix the plan, and the reader reads it again. After two rounds that still have open notes, Forge stops and the owner chooses: accept, read again, or split. It exists because a gap found in the plan costs minutes, but the same gap found in the code costs a build round.
The build and review loop. A worker builds the part and its tests, then a separate review checks the change. A serious problem goes back to the worker for another round. A task gets two review rounds and a fix gets one. At the limit Forge stops and asks the owner, but a P0 problem keeps the loop going. It exists because a reviewer sees problems that the worker cannot see in its own work.
The CI checks. GitHub runs the repo's checks on the pull request. Close waits while they are queued or running, and a red check goes back to the worker. They exist because the checks run the tests on a clean machine, the same way for every change.
forge next adds one line under each running item that says what it waits on, why and for how long. Give that line to the person when they ask why something takes time.
After forge init in a new repo, tell the person the seven steps in one line each, then ask for the first input: the client notes or the idea.
When a person asks what they can do, or seems unsure, run forge next, name the current step from its first line, and show that step's "You can say" phrases. Name no commands.
When a Forge command refuses, tell the person in plain words what Forge stopped, why, and the fix that it names. Then do the fix, or ask the choice. When the refusal looks like a Forge fault (a wrong or confusing message, a refusal of a correct step, a crash, or a success that did nothing), say so and offer to file a Forge bug as Reporting a Forge bug, below, says. File it when the person agrees.
Before sign-off FORGE-SIGNOFF-1 adds Build now and Later; until then, record "build it later" with forge start "Do this later: <the first story's idea>".
Understand each human decision, direction and idea. Save each in the same turn; never leave it only in chat. Grill new directions one question at a time, with your recommendation first. Save the answer before moving to the next question.
forge close <item> --resolve <more|split|accept> --reason "<human's choice>".forge decision new <slug>. Batch decision
docs into the next fix; do not open one pull request per decision.
For a large decision, run forge read <decision-slug> before acceptance. Amend the decision
and answer findings between rounds, as for a spec. Notes stay beside the numbered decision
record. Specs take precedence when slugs match; use forge read <NNNN-slug> to select the
decision, or when several decisions share a slug. A cold read does not accept the decision.docs/specs/, state each rule once, on an R-<n>: line under ## Behaviour.
Validation (VAL), UAT and acceptance (AC) lines name the rule that they check by its ID, for
example VAL-11 checks R-13, and do not say the rule again. A decision that changes a rule
names its ID. forge decision accept then lists every spec line that names that ID: in the
same change, before close, update each line that no longer fits. On upgrade, the first
forge sync lists the old spec lines that seem to repeat a rule, with a fix to start. Show
the list to the owner and ask with options: rewrite those specs now in that fix, or later.forge start keeps plans/ideas.md, a short dated list, when the owner says later, and
carries waiting entries into the next fix or story. When you, a planner or a worker think of
something useful that nothing needs, add one line - <YYYY-MM-DD>: <the idea> to
plans/ideas.md in the branch in hand and build nothing for it.
Remove an entry when the owner says to do it now, as the command table explains.If the default branch moved after close, forge merge compares its new changed files with the item's changed files.
It merges the default branch locally to check the combined change.
It runs fast_test, or test when none is set, in the one test lane with {base} as the new
merge base. It merges the pull request only after the tests pass. A failure names the failed tests
and gives forge work <item> as the next step. This is always on, with no setting. With no
default-branch move, merge runs no extra tests. New repos get this rule at init; existing repos
get it on upgrade and sync.
If the file sets do not overlap, Forge restores the original head and merges without a push or another check wait.
If the file sets overlap, Forge keeps the local merge, reuses the existing review and commits its coverage of the combined change.
It pushes that commit, waits for its required checks, then merges.
The nightly full run on the default branch covers the rest. With no retest, the usual CI wait applies.
Before the retest, Forge refuses uncommitted changes and names their files. After tests and
checks, Forge fetches the default branch again. If it moved again, Forge refuses the merge
and gives forge merge <item> as the next step.
Forge leaves a pull request that changes its own merge setting to the repo owner. It compares the item's merge base with its head, so an older branch can merge after the owner enables agent merges. An already-merged pull request skips that check when tidying. Cleanup removes unchanged generated git hook shims and Husky's ignored rebuilt hooks; uncommitted work and later local commits keep the worktree in place. When another program holds the worktree open, the merge still finishes and keeps the local branch; close that program, then delete the folder the merge names.
When forge merge merges a story's last task, the same squash merge records the story as done.
Give forge merge <KEY>/<TASK> --outcome "<outcome>" to name what it achieved; without it Forge
uses the story's title. The board and forge next read that record from git, so no outcome fix,
extra pull request, review or CI run is needed. Stories already marked done keep their outcome.
Use forge story done only to correct an outcome later, on an existing work branch that carries
the correction through its own pull request; the command opens no branch or pull request.
When next says a remotely merged story needs its outcome, fetch origin before recording it.
Give each question one line of context and a header of 12 characters or less. Use 1-5 word options that say what happens, with the recommended one first for decisions. Use no IDs, paths or slugs in questions; write for the human's choice.
Write text that people read with the simplified-technical-english skill: a story's What changes
for you, Why and Done when, a fix's why and Done when, pull request summaries, questions to the
human, and board and forge next lines. Briefs, guides and code stay as they are.
The human never edits forge.toml; you keep it. When a setting must change, ask first with
options, then make the change yourself in a fix: forge fix start, the edit, then forge close.
A developer's own tools, workers and [models.<kind>] choices go in the git-ignored
forge.local.toml instead, which you edit directly when they ask; Forge refuses any other key there.
runner selects the GitHub Actions runner label for every job in the generated forge.yml;
it defaults to "ubuntu-latest". For self-hosted Linux runners, initialise with
forge init --runner self-hosted, or set runner = "self-hosted" (or a custom label) in an
existing repo's fix, then run forge sync. New repos get it at init; earlier adopted repos get
it after upgrading Forge and syncing. The jobs set up uv and Python, and install
Node for Node tests, respecting version files or engines with Node 22 as the fallback.
Close and land keep waiting while checks are queued. The wait line shows minutes observed
queued during this wait: shared runners may be busy or no runner may match the runner setting.
Only forge doctor reports a likely missing runner, when a current check has been queued at
least five minutes and no matching job started in its sample of this repo's runs created in
the last seven days. It reads at most 100 newest runs, skips successful runs, and reads one
page of latest jobs per remaining run, without earlier attempts or older runs. Make a
matching runner available or correct the setting; run forge sync only if you
change the runner setting. Keep the required checks enabled. New and upgraded repos get the
same waiting and doctor behaviour from the upgraded Forge commands.
The merge setting is the owner's, because it is a gate on your own work: never change it to
"agent" or run forge merge enable, even when the owner asks, and never merge a change to it.
When agent merges are off and the owner wants you to merge, tell them to run forge merge enable
in a terminal outside Claude Code or Codex; it opens the change for them to merge. If an interrupted switch's fix
contains only that setting and the default branch has moved, it rebuilds the same fix on the
current default branch, preserving its other settings. It leaves remote work outside that fix
alone and refuses to replace a remote branch that changes after its check. The owner still
merges the pull request. Close checks this generated fix mechanically instead of asking a model:
only forge.toml's top-level merge = "agent" may change, with all other parsed settings equal
to the fix's merge base. Extra changes are refused without review. Tests and CI still run;
every other item keeps its model review.
Give status updates in one shape: Ready to merge (n): ... · Needs you (n): ....
Who does what. The coordinator is the app the developer opens: Claude Code or Codex.
tools in forge.toml says which tools run Forge's work: "claude", "codex", or
"both" (the default when absent). One tool puts every item on it, including design work
with its own design model; workers is ignored. With both, workers keeps its usual meaning.
Forge's planning, approval, build, review, CI and merge process stays the same.
Doctor's SDK, project trust and UI skill checks follow the selected tool too.
When a round's tool is the coordinator's, its route is native: that session's own background subagent,
even with both tools. The other tool runs through its kit: the Codex app server or the Claude
Agent SDK. No coordinating session open in a one-tool repo means work waits for the session.
Reviews run externally through Autoreview on the named tool; with both, Codex when installed,
otherwise Claude. Normal, light and sign-off reviews use [models.review] or its per-tool entries.
Unset entries use Autoreview's default model and effort; unset effort uses its default effort.
Running a handed-out round. When Forge prints a subagent instruction, run that instruction
as a background subagent of the named role. Keep the item's chat while the session is open;
continue the named subagent when told to, or start fresh with the whole brief in a new session.
If that chat is unreachable in the same session, start fresh with the whole brief too.
Run forge handback with its last message and id and the printed --round when it finishes.
Send the nudge when asked; never edit the brief. Only the coordinator hands back or starts a round.
Native plan reads. With one tool, that tool reads every plan. With both, the first read
chooses the other installed tool, and later rounds keep their reader while it is available.
When that reader is your session's tool, forge read <target> prints a JSON instruction for
the reader role in the plan's checkout. Continue its named subagent with prompt, or start
one with fresh_prompt when no subagent is named. Run it in the background, read only, then
give its message and id to forge handback <target> --round <round> --subagent <id> --text "<message>".
The session holds the item's lock and machine place until handback or the session ends.
forge stop frees Forge's hold; stop the subagent in your session too. Stale rounds record nothing.
Forge checks for changed files, numbers and records findings. Init and upgrade deliver the reader role.
Native build rounds. forge work and forge land print the role (worker, fixer for a fix,
frontend for design work), the model to start it on (over the role's own), the checkout and the brief. Pipe its last message to
forge handback <item> --round <n> --subagent <id>; send any printed nudge, then hand back again.
Hand-back restores forge.toml and records a Question:. Then run forge land or forge close.
Upgrade first. Older Forge refuses the tools key. Follow Upgrade Forge before adding it.
New repos get the setting's default at init; existing repos get this guide when the upgraded
Forge syncs, keeping their settings as written.
When Forge itself misbehaves (a wrong or confusing message, a refusal that shouldn't happen, a crash, a command that reports success but did nothing, generated files that contradict each other), file a bug on Forge's GitHub. No client code, names, paths or secrets: describe what Forge did. Read the template text from GitHub and drop its front matter:
gh api repos/knacklabs/symphony-forge/contents/.github/ISSUE_TEMPLATE/forge-bug.md -H "Accept: application/vnd.github.raw"
Fill every section, then save the filled body with your own file-writing tool as UTF-8.
The template's sections, which the body file keeps exactly:
## Forge version: Output of forge --version and the pinned version in forge.toml.## Host and operating system: The host (Claude Code or Codex) and the operating system.## Command and output: The exact command and full output, with private names replaced.## Expected and actual: Expected vs what happened.## Steps to reproduce: Upgraded from which version, new or adopted repo, and the forge.toml settings without secrets.## forge next: The forge next output at the time.## Tried and workaround: What was tried, and any workaround.## How often: How often: always, sometimes or once.File it with no prompt:
gh issue create --repo knacklabs/symphony-forge --title "<short plain title>" --body-file <that file>
The repeatable laptop installers are published for Mac and Windows. They install the tools Forge needs; follow their prompts to sign in to GitHub and your agent.
After every clone, read the pinned version in forge.toml and install that release,
even if the laptop installer installed a different one:
uv tool install git+https://github.com/knacklabs/symphony-forge@<release>
(replace <release> with the pin, such as v1.2.4). Then run forge sync to install
the local git hooks and refresh the generated files, followed by forge doctor --fix.
In Husky repos, sync preserves the team's hooks and adds Forge's checks to the committed
.husky/pre-commit and .husky/pre-push, through .forge/hooks.sh. Commit those additions;
npm install can rebuild .husky/_ without removing Forge's checks.
The team's commands run first in a child shell; successful exit or exec cannot skip
Forge, both pre-push checks receive Git's input, and a team hook failure still blocks Git.
Resolve any remaining Doctor rows before starting work. An existing repo gets these
instructions and the updated CI workflow on its next forge sync after upgrading.
Read the migration playbook before running forge migrate --dry-run
or forge migrate. It ships beside this skill and covers the human's agreement,
preservation review, merge, cleanup and rollback. Follow it in order.
Forge gives agents half the available cores (at least one place), across all repos. Work rounds
share a line. Plan reads and close reviews take no place in that line. Every run, including
tests, reviews and plan reads, waits while the machine's
one-minute load per core is 1.5 or more, even when no other Forge run is active; where the OS reports no load
(Windows) the memory and core budgets still apply. Waiting items that other planned work waits on go
first, first-come within each group; each waiting run says its place and why. The test
lane makes all test runs share one process budget: the cores left after the agent share and busy
local CI jobs, with at least one process. Small selections count too. Each run takes its allocation
from the remaining budget. A worker's test runs use at most two processes. Nested pytest pickers
keep the parent run's allocation. Older-release entries without an allocation count as the old
default share, half the machine's cores. forge doctor names these older runs and shows both lane
budgets, free memory and its floor, test processes in use, and busy runners.
Every run waits when free memory is below 1.5 GB or ten percent of RAM, whichever is larger.
An unreadable memory source does not block work. Each busy local Runner.Worker reserves one core
from Forge's half-core budget, with at least one core left for Forge. Waiting runs check memory
and runner use again on each pass and start when capacity returns. On Mac and Linux, doctor warns when a GitHub Actions self-hosted runner
runs on this machine: its CPUs count against Forge's load limit.
forge board --json includes both machine-wide lanes, their sizes and entries in queue order,
alongside OS load and memory. Each entry has an id, kind, repo_root, repo_name, item,
model, effort, joined_at, started_at, process, output_path and progress.
Waiting entries have no start time. Test output and progress are null until the test runner sets
them. The process includes its pid and start identity; a reused pid cannot hold an old place, but
the run keeps it while its own Forge process runs.
Only a person runs forge stop <item> (optionally --repo <root>) to stop that item's entries in
both lanes, or forge stop --id <id> to stop one entry. The host asks for confirmation first.
Workers never run it. A waiting run leaves the line; a running run's verified process tree ends
before its place is freed. An unverifiable identity refuses without terminating anything.
Stopping an item also clears its abandoned item lock when no live run holds it, so the next
round can start even when the coordinating session stays open.
This applies to runs Forge launched. A handed-out native run has no process tree, so
forge stop frees its hold and the coordinator stops the subagent in its session.
In Claude Code's Forge pane, the Machine tab shows this release's agents and test lane across
repos, who waits next, local item gates, and machine load when the OS provides it. Desktop draws
an agent tree; narrow terminals use a list. Select a run, press o for its last 200 output lines
or s to ask the person whether to stop that exact run. A run that ends or is replaced during
confirmation is not stopped. Press l to show or hide recent events. The spinner names this
session's place in line. /forge includes the machine summary where panes cannot draw.
Lanes record each item's title when it joins, so other repos' stories and tasks keep their
plain names in rows, selectors and stop confirmation. Only this repo's board adds tool,
round, current step and gates.
forge lanes --json supplies the Machine tab; other releases still count towards admission but
are left out of its rows. New repos receive the mod on setup; existing repos receive it on
upgrade and forge sync. An unreadable output or a failed refresh is explained in the pane;
failed refreshes keep the last rows. The mod adds no background work or dependencies.
forge board opens the board as a live page on this computer: a server on 127.0.0.1 at a free
port, with a per-run token in the page address that every request must carry, so no other computer
and no old link can open it. The page refreshes by itself when the work changes, and the server
stops when the command ends (Ctrl-C). It rebuilds only the rows whose inputs changed and fetches
from GitHub at most once a minute. --out <path> writes every item's facts as JSON instead,
finished ones included.
forge board --json and forge next --json print JSON for the Claude Code mod and
other readers. The usual commands still print text. Both views
include version (the running Forge release) and repo_root (the resolved main
worktree path, shared by the repo's worktrees).
forge next --json uses the same 60-second GitHub cache as forge board --json, while text
forge next reads GitHub live.
Pull request creates, edits and draft changes keep this shared cache. They show within a minute.
Merges clear it at once. Each command fetches the default branch's settings at most once.
After close, a matching receipt still shows "ready to merge" while the cached list lacks the pull request's link.
Both views' items has one row per story and fix, with tasks in the story's children.
Finished stories, tasks and fixes older than seven days are left out of --json;
--out keeps them. The live page reads the same rows, so each state and time on it matches the
JSON. Each story shows its key small beside its title, the one ID on the board. Story rows carry
read_rounds: each cold-read round of the plan with its number, its findings' first lines and
their dispositions (cut, defer or keep with its reason), and read_at on the latest round
only. Each call reads current state without a history cache.
Assigned merged parts stay omitted rather than appearing as unstarted. Backticks around
task IDs in the plan are ignored by the board.
forge board --json supplies dependency_maps: one entry per roadmap story
with planned (false for a story with no plan yet, which has no parts), done (its finished
parts) and its full planned parts, plain titles, labelled states and waits_for item references,
including old merged dependencies omitted from active rows. Each unfinished part has column:
0 when it waits on nothing unfinished, else one more than the largest column it waits on, across
stories, so parts in one column can run at the same time; parts that wait on each other share a
column and say so in note. Finished parts have a null column. When fixes are open, an entry
with kind: "fixes" lists them in column 0 with running and started_on (the story part a
stacked fix was started on). Startability and scope
blockers come from the same rules as forge next, including approval and required rereads.
Both views add team: sentence, counts, needs_you, in_progress, blocked, pace,
go_live, trends and around_forge; a key not worked out yet is null. Every story, part and
fix row has one state, and team.counts counts each kind apart, finished ones included:
stories (done, building, approved but not started, waiting for approval, planning, no plan yet),
parts of approved stories and fixes (done, ready to merge, in progress, to do), and
finished_last_7_days. A story is building only once one of its parts has started. Rows also
carry merged_at, and approved_by is a name or null.
GitHub's pull request lists are read at most once a minute: the open ones and one search per
week for the last six full weeks and this one.
team.pace counts parts and fixes merged on the default branch per full week (Monday to Monday
UTC) for six weeks. team.go_live gives a date range for the parts of approved stories still to
merge, from the last three and six weeks' pace: range, about when the two agree, not enough history when the oldest merged part is under three weeks old or the last three weeks merged none,
or done; it counts the stories with no plan yet as the unknown, and team.sentence says the
same in a count, not names. team.in_progress lists the stories and fixes in
progress (id, title, kind, state). team.trends counts merged pull requests per week for the team and each person
(alphabetical, no totals or ranking), split into through Forge (a story/, task/ or fix/
branch) and around it; team.around_forge lists the ones merged around Forge in the last 7 days.
Both are null without GitHub, and a week capped at 1,000 results is null.
team.needs_you lists every item that waits on a person, oldest first, each with its reason,
since and waited_seconds: approval (a plan waiting for approval), review loop (a review
loop or stuck-worker choice), worker question, conflict (a merge conflict close stopped on),
merge (a ready pull request a human merges) and blocked plan, with the question or the
problem forge next reports in detail. Close and forge work publish
these waits to the pull request, so every machine lists the same ones; answer a worker question
with forge work <item> --note on any machine. team.blocked lists started parts and fixes
idle 24 hours or more (stalled) and the unfinished part the most unfinished parts wait on
(blocks the most), longest first, each
with detail and seconds. team.sentence counts both. Ask the human about each Needs you
item as forge next words it.
Active parts and fixes show recorded
Build, Tests, Review, CI and Merge times for their current round, with the current stage
marked. Missing times remain unknown. New clients get this at init; earlier adopted clients
get it after upgrading Forge and syncing. Cards and JSON use the same status and took
derivation; running stages include their elapsed time. Roadmap completion marks the story
and its parts finished. Finished items never stall; idle items past one day expose
stalled, idle_seconds, and waits_on. A story's idle clock includes its parts' activity;
a running part keeps the story active and a finished part resets its idle clock, including
a merge reported by GitHub before its commit is fetched. An older
worker round or a worker whose recorded lock is demonstrably dead is not a live run.
Live readers, workers and reviews take precedence
over a saved status, including in forge next. Approval history uses one display name per
Git email, honoring mailmap, and fix titles shorten at a word boundary.
Each row has id, kind, plain title, stage, worker (kind, model and
started_at, or null), pr (number, url and checks: pass, fail, running or unknown),
findings (count and titles), round, stages, total_seconds, occurrences,
approval, needs_person, and its own next. needs_person is true while the item waits on
a person, by the same decision as team.needs_you.
A story awaiting approval has approval.doc, the
absolute path to its document in its own worktree; other rows have null approval.
Task and fix rows add time_breakdown and rounds; story rows add outcome (null until done).
An empty board has an empty items list. Missing state shows unknown. No run start,
end, round or occurrence id is invented when its producer has not recorded one.
The last task's merged outcome marks its story done, even when the saved story
state still says approved. New clients get these views and this guide at init;
existing clients get them after upgrading Forge and running sync.
Tasks and fixes are ready only while close's clean review matches the pull request's head
(the local branch when it already holds that head) and the checks are not failing. The clean
review is this machine's receipt or the readiness close published in the pull request, so every
machine agrees. On a machine with no worktree for a ready item, its next step names the person
who started it to merge it from their machine (or, in a human-merge repo, the pull request to
merge); with the worktree here but no receipt, it is forge close <item>, which checks it again
and writes the receipt that forge merge needs. A failed
rerun shows checks failed with forge work as its next step, even after a successful
close. A running rerun or unavailable checks retain a matching receipt's readiness;
green checks alone cannot grant it. The item's next step uses the same evidence.
If the next step cannot be checked,
the row stays visible with no runnable command; check the connection and run forge next again.
Stages are Build, Tests, Review, CI and Merge, in that order. Each carries status,
started_at, ended_at and seconds for the current round from Forge's timing records;
unrecorded values are null. For tasks and fixes, total_seconds is elapsed time from the item's recorded start
(or first recorded activity) to now, including idle time; a finished item needs a recorded end.
Their snapshot already includes live time, so do not add a running stage's timer to it.
Worker-owned tests are separated from building in the breakdown, while close's tests and
forge test still appear in the Tests stage. A skipped test has status skipped. Run starts and ends
provide live worker and reader metadata; completed timing durations supply stage end
times. Values remain null where the producer has not recorded them.
time_breakdown separates building, own tests, reviewing, fixing findings, waiting for CI,
waiting in line, waiting for the owner and nothing running. Overlapping steps count once:
tests and recorded waits come out of the enclosing worker's time. rounds retains each round's
plain line, its finding titles, priorities and files, and its new and repeated finding counts.
Round lines number review attempts; the row's current round still identifies its worker turn.
Repeated means the same title and file appeared in an earlier recorded review. A missing
earlier review makes unseen findings' new-versus-repeat counts unknown. Repeats observed in the
retained history remain known even beside unseen findings whose classification is unknown.
CI lines distinguish passed, failed and gave up while queued or
running; losing contact with GitHub without a known result stays unknown.
An earlier release's failed CI timing without an explicit result also stays unknown.
Old records are not filled in with guessed findings, durations or zeroes. A known original start
can give an elapsed total even when some earlier activity is unknown; that unknown time is not
called idle and the known breakdown need not add up to the elapsed total. Gaps between legacy
timings stay unknown until complete activity recording begins. Earlier run and question events
do not establish completeness; historical questions without a recorded end stay unknown.
Quote the item's round lines when explaining a long run, then quote the relevant breakdown categories rather than adding overlapping stage timers. The board page shows these same details. The pull request's short How it went section comes from the same logs and keeps earlier findings after later reviews. Forge keeps the pull request body in an agent squash merge; when the human merges, keep this section in the squash commit body too. New repos get this guide and the recording behaviour at init; previously adopted repos get them on upgrade and sync. Their earlier unrecorded history remains unknown. If a fresh clone or missing local logs cannot reconstruct already published measurements, How it went retains them and shows the current checkout's observations separately. Quote each snapshot separately; do not add their totals, because their intervals may overlap.
Quote the item's round lines when explaining a long run, then quote the relevant breakdown
categories rather than adding overlapping stage timers. The board page shows these same
details. The pull request's How it went section carries intervals, review rounds (including
clean reviews), and waits with their ends. The shared record has a fixed size: while it is over, the oldest
detail of any kind (round lines, intervals, then raw events such as repeated CI waits) folds into
one "Rounds 1–N" line of totals and finding counts, oldest first; the newest round keeps its own numbered line,
and its folded retries add to it. Free text in each entry is cut to 300 characters, and a round
too big on its own, such as a huge review, folds whole into its line. Live progress stays local. So a
long item stays inside GitHub's body limit, and folding never changes its total time. Close and merge retain observations from other
checkouts and recompute repeated findings and overlapping time. The board reads this shared
record alongside local observations; source says which it had. A GitHub merge ends the last
wait at its merge time and names its merger. Story time counts each instant once: working when
any part or recorded plan read is working, waiting when none is working and any is waiting,
otherwise unknown. Inside a part's folded time range, the story's split between working and
waiting is approximate; the totals stay exact. Human times use rounded plain units; JSON keeps raw seconds. Rebuilt history
keeps its label and missing evidence remains unknown. New repos get this at init; existing
repos, including earlier adoptions, get it on upgrade and sync.
Worker questions and their answers refresh an existing pull request's record; a question before
its first pull request stays local. A first-close merge conflict opens the pull request so its
owner wait travels too, and resolving it records the wait's end.
Resuming work ends a published merge wait even when another checkout started it. History
refreshes retain the pull request's readiness; close publishes readiness for a newly checked head.
Board and next reads use the current pull request history and head; cached checks apply only
to the head they describe.
Questions on older pull requests without local publication evidence stay local.
Every pull request body stays within GitHub's size limit. Forge leaves tool-command prose out
of the shared time record, shortens duplicated and advisory detail before the contract, and
says plainly when it shortened anything. Exceptionally large time histories retain recent
evidence and current readiness; omitted time stays unknown. Full contracts and proof stay in git.
Items report working, waiting and unknown seconds alongside their detailed categories. An
unfinished story's runway continues through now, including unknown time after its last read
or recorded part activity; a read without a duration establishes a date, never guessed work.
Live rows add activity (status and a running action), idle_since and stalled
after 24 idle hours. A recorded worker adds tool, model, effort, round, start,
elapsed seconds and its latest tool step; close's live tests adds elapsed and
done/total where the runner reports progress. gates has plan_read, review and ci,
each with status; blocked reviews add count and running CI adds elapsed seconds.
PR failures list job and cause (timeout or failed); findings add items with title
and priority and a dismissed count. Both views' events list the last 20 run,
review and question records as time, item and one plain line, newest last.
Queue places stay absent until the shared lane entries ship.
The newest 25 open pull requests get checks in one GitHub request, cached for 60
seconds in the shared Git directory. Older pull requests and unreachable GitHub
show unknown checks. Required checks, including matrix variants, must succeed;
skipped or neutral required checks show fail, while optional ones count as passed.
A failed check occurrence keeps GitHub's own identity:
check-run:<databaseId>:<completedAt> or status:<id>. A rerun with a later
completion is a new occurrence. Each occurrence has id, kind and plain title;
run completions, undismissed review findings (including advisory findings) and unanswered
worker questions retain the ids in Forge's event records. Advisory occurrences do not
change the merge gate. Readiness uses the clean review's id plus the current head
commit. Runs that start and finish between board refreshes still appear as completions.
Both views' next contains command, line and step. Command is the first Next line
only when it is one runnable Forge command without a placeholder or alternative;
otherwise it is null. Line carries the plain current state from the text report. Step is
the first Next line's text even when it is not one runnable command, or null without one.
Release notices appear in the text output and never replace the machine view's state line.
Use each board row's next step for that item, never another
item's step. Machine views do not grant approval or permission to merge.
The shared mod contract fixture is tests/fixtures/board.json; command coverage
in tests/test_machine_views.py checks both views against it.
The Claude Code mod reads Forge's machine views, runs forge commands and draws;
it never edits repo files or replaces the commands' approval and merge rules.
All its consumers share one snapshot. On load, then every 10 seconds, one refresh
runs forge next --json and forge lanes --json together. The next output also
supplies the board rows, so the pane reads them once per refresh.
If that Forge has no lanes command, lane data is absent. A due refresh is skipped
while the previous one runs, rather than queued. There is no extra fetch on /forge.
Drawing ticks advance live timers every second without fetching state.
A failed or malformed refresh, or a command taking over 60 seconds, keeps the
last good rows and adds a dim Couldn't refresh: <first line of the error>.
It retries on the next tick. Only a non-zero command result containing
unrecognized arguments: --json shows
This repo's Forge is too old for the pane: upgrade Forge here.
Other failures use the normal refresh error. The board command owns the
60-second GitHub checks cache described above; a check changing without a local
edit appears on the next refresh after that cache expires. Unknown checks stay
unknown, including when GitHub is unreachable.
forge sync installs or updates the mod from Forge's latest release at user scope,
one per machine, independently of each repo's pinned Forge version. It needs
Claude Code v2.1.287 or newer on PATH. When the marketplace is missing, sync runs
claude plugin marketplace add knacklabs/symphony-forge, then always runs
claude plugin marketplace update forge. It runs
claude plugin install forge@forge --scope user for a new user install, or
claude plugin update forge@forge --scope user for an existing one.
Sync writes no repo files for the mod; Codex's setup and workflow are unchanged.
Without claude, sync skips the mod. A failed install or update (including no
network or old Claude Code) prints one warning line and sync still succeeds;
run forge sync to retry. forge doctor warns when Claude Code is missing or
older than v2.1.287 and keeps exit status 0. In a running session, use
/reload-plugins or restart to load the updated mod. Desktop's WSL sessions load
no plugins; use the forge command there.
The mod runs forge from PATH with argv and no shell, in the session's repo root.
It does not change the repo's pin. If the pane or strip says that repo's Forge is
too old, upgrade Forge in that repo; other refresh errors follow the core's retry
behaviour above. Sessions without the mod keep using the commands as today.
The pane has no Approve button: Claude Code's mod API cannot supply the story's exact text
to its native plan-approval prompt. Use Plan Mode and the story doc forge next
names, following Planning a story below. The existing approval hook and its trust
checks are unchanged. Plan Mode remains the approval path in Claude Code, Codex,
the VS Code chat panel and sessions without the mod; installing the mod changes
no approval rule.
Type /forge at any width, including 80 columns, to open and focus the pane.
The mod requests it at interactive session start too; Claude Code places it
automatically at 144 columns, or 110 after the person has opened it once.
The strip below that wide-screen threshold ends with /forge for the board.
The pane's Board tab, on the terminal and the Desktop app's Code tab alike, opens
with one summary line, such as 3 in progress · 1 needs you · 2 stuck · go-live Oct 20.
Each part shows only when the board's team fact behind it is known and not zero; when
none of them applies, the line counts the rows the tab shows in its own group words instead,
such as 1 moving · 2 ready to merge · 3 waiting; an empty board says only Nothing in progress.. An older Forge with no team shows no summary line. Below it come the board's
own sentence (team.sentence) and its labelled totals, one line per kind, such as
Fixes — Done: 0; Ready to merge: 0; In progress: 1; To do: 0, words built from
team.counts. Groups follow in this order, each only when it has items, and each in the board's own
order: NEEDS YOU (one row per team.needs_you entry, oldest first, with how long it has waited,
such as waiting 3h), STUCK (one row per team.blocked entry with its reason in words and its
age, such as 1 unfinished part waits on it · 2d, and the longest stall in days), MOVING (the board's In progress, team.in_progress, except what is ready to merge;
a running item shows its current stage and how long, such as Review running · 12 min),
READY TO MERGE (the rest of team.in_progress, each saying Ready to merge, with the checks in words when known, and its merge
step; an item merged from another machine shows forge next's line naming who merges it), then a
folded count of the work waiting or not started (planned stories and fixes not started), opened with a native button to the same rows. Each item shows its plain title, the story key small
beside it, one line of state in words and, where there is something to do, its next step
(next.step) after →. At most five rows show per group, then and N more · forge board for all.
An older Forge without the team lists draws the same groups from each row's needs_person,
stalled, running and ready flags, and shows no sentence or totals.
Outside those totals, the pane never shows zero counts, unknown times, raw timestamps, priority codes or
dismissed counts; findings read Review found 3 problems. Dates are short (Oct 5) or
relative (12 min, 8 days), and every time rounds as the board's do (2m, never 1m 30s). Stage chains, round lines and the time breakdown stay on
the board page. An empty board says Nothing in progress. /forge always returns the
same lines as text, as well as opening the pane. Where mods draw nothing (the VS Code
chat panel, claude -p and Remote Control from a phone or claude.ai), that text is the
status reply. It uses the last completed snapshot, including any refresh error. Until a
first refresh succeeds, the pane, the strip and /forge say Loading Forge…, or
Couldn't refresh: <first line of the error> once that refresh failed.
The strip above the prompt uses at most three lines. Its first line shows
Agents N/M (W waiting) · Tests N/M (K waiting) · <running item or idle> · 1: <next command>.
It also shows a recorded current worker step. The other lines show up to two active items
from this repo, each with Build → Tests → Review → CI → Merge, its round and total
time. A third active item replaces the last line with +N more · /forge for all.
Finished stages show ✓ and their duration, the current stage ● and a live timer,
and failed stages ✗ in red. Unreached stages have only their name; skipped tests
show Tests –. Symbols carry the meaning without colour. The total uses the elapsed-time
snapshot, which includes live and idle time without counting concurrent stages
twice. At widths under 80 columns it is one line: running and waiting counts, the first
active item's current stage and time, its total and the next step; without lane data,
the first line is only the next step; the narrow strip has no item or lane summary.
Press 1 on an empty prompt when Claude is idle to run the displayed next command
as the user. Before submitting, the mod re-reads forge next --json: if the command
changed it redraws and runs nothing. A failed re-read submits nothing and toasts
Couldn't check the next step: <reason>; a failed submit toasts
Couldn't run the next step: <reason>. A null command or busy Claude has no hotkey
and shows the plain next-step line instead. Typing into a nonempty prompt stays typing.
The mod starts a session turn for new review findings, failed checks, a pull request
ready to merge, worker questions and finished runs. Progress only updates the pane:
starting a run or running checks never asks the agent for a status turn.
Each event line names the plain item title, what happened and that item's own next command,
or forge next when there is no runnable command. When the turn arrives, act on it
straight away through Forge's commands: resolve findings with evidence or send a
worker round, follow a failed check's next step, close finished work, and merge ready
work only when allowed. Answer a worker question with
forge work <item> --note "<answer>"; a choice the human owns still goes to them.
Do not build another polling or watcher loop for an interactive mod session.
Forge's occurrence ids distinguish events, never their text: review results, run ends and questions get fresh ids; CI completions use the workflow id and head commit. Failed checks outside a workflow use GitHub's id and completion time, failed commit statuses use their own id, and readiness uses the review id and head commit. The same question in another round or a check failing again after a later completion therefore gets another turn, even if its wording is unchanged. A run that starts and finishes between refreshes still has its completion occurrence.
Seen ids are stored for the repo root and session id together, so two sessions
consume events independently. At session start or reload the current ids become
seen without starting a turn. Several changes, including those found while Claude
is busy, are combined in one turn after the current turn ends, one line per event.
At delivery, each line uses the item's current next command. Events for items that
have since merged are dropped. A CI completion names the workflow and its result,
once per workflow and commit.
A failed submission leaves them unseen for the next refresh to retry; a successful
one is not repeated. Only interactive sessions on terminal or Desktop receive
event turns, and only for their own repo. Forge-started workers, readers and
reviewers have FORGE_WORKER=1 and never act on events. Headless sessions receive
no event turns. Codex and sessions without the mod keep using forge next and the
existing command flow.
.git/forge/handoff.md in the main checkout, shared by every worktree, carries your state across
a compaction. Before each compaction Forge rewrites its current-state part from forge next and
keeps everything under ## Decisions and lessons. Add one line there at each milestone: a story
approved, a task merged, a decision the owner made, a lesson learned or a mistake you won't
repeat. After a compaction or in a new session, read it first. The file is local and never
committed.
The first time each of these happens for a person, add one plain sentence saying what just happened and what they can do next. Say it once, then never repeat it, and never name commands unless they ask. Note each one in the handoff so a new session doesn't repeat it.
Grill any request with more than one reasonable reading or no stated done-when before starting a fix or story. Ask one question at a time with your recommendation and why; look up facts in the repo instead of asking the human. A clear request with a stated done-when can go straight ahead.
When the human states a new direction, principle or value, grill how it applies before changing anything. Ask one question at a time with your recommended answer and why; look up facts in the repo instead of asking the human. Continue until the plan for applying it is agreed, then make the changes.
Every ask is a guess about a problem: find the problem before anything is planned. The worked example, question bank, customer call script and outlines for the pre-meeting brief and recap are in the reference page.
By size. On a fix or an everyday story, interview the engineer, and through them the
customer: one question per turn, about something that already happened. Offer no solutions while
discovering, and praise isn't evidence. A question of fact gets neutral choices; a decision gets
your recommendation first. Add a one-line Why I ask: to each question until the engineer says
they know why. Ask at most two questions for a fix and eight for a story, then write what is
still unanswered as unknown.
A new project. On a new app, the FDE puts every client note in docs/context/. Read all of them before you ask anything. Fill docs/product/BRIEF.md and the problem cards in docs/product/DISCOVERY.md from the notes, and list each contradiction and gap for the FDE. Ask the FDE one question at a time, and only about a point that changes a screen, a field or a flow. A new app has no fixed number of questions. Give every other open point a default, mark it (assumed) where you write it, and list these assumptions in one message for the FDE to change. Put each question the FDE cannot answer on the recap's Still to find out list, and build the prototype without waiting for the answer.
Before the first meeting, draft a one-page pre-meeting brief in
docs/context/ from the prospect's website: their likely jobs, two or three guessed problem cards
each marked (guess), their terms, and the first five questions to ask. During discovery, keep
the customer's own words in ## Words they use in docs/product/DISCOVERY.md, one
- <their word>: <what it means> line each. Ask for the spreadsheet or form they use today and
keep only its column headers, never its rows. The same day, draft a recap in docs/context/ for
the customer to confirm: their problem in their words, the cost in their numbers, the one task
the demo will cover, who signs off, the open "ask the client" questions and the demo date. When
they reply, record the Demo workflow and Sign-off person answers from it with client as the
source, as - Demo workflow: <task> (client, <YYYY-MM-DD>) and - Sign-off person: <name, role> (client, <YYYY-MM-DD>). The salesperson sends the recap; Forge sends nothing.
The card. Write each problem as a card under ## Problems in docs/product/DISCOVERY.md,
adding the section to an older file on first use: ### <short problem title>, then Job,
Workaround, Cost, Who feels it, How often and Evidence. Write customer notes in docs/context/
into cards and leave the notes where they are. Name the chosen card's heading in the brief's
Summary and the story's Why (or the spec's Why when using a spec). Costs use rounded rates,
never real salaries.
Options. For the chosen problem, offer two to four options, always with Don't build and
Smallest slice, plus Use what they have (a setting, report or process change in tools they
already run) whenever one could do the job. Give each option that builds something its own
forge spec payback line, and recommend the one with the fewest months among those answering
build or smallest slice first; a tie goes to the smaller build. If none does, recommend don't
build, or find out first when an option's value can't be estimated. The human chooses; write the
choice and one line of why into the story's Why, or the spec's Behaviour when using a spec.
New clients get these steps at init; existing clients get the same guide after upgrade and sync.
In a new client repo, follow the FDE route: start with discovery of the customer's job,
workaround, cost, people, frequency and evidence. Start with a canvas, as described below.
The canvas in Play mode is the default clickable prototype: the customer clicks through it,
and can sign off on it alone. Build a working prototype only when the FDE
requests one to prove something the canvas cannot, such as real data or speed. Record that
request with forge decision new prototype-build; the owner accepts it with
forge decision accept prototype-build --by "<name>". Then build the smallest working demo that proves
the request, demo it, review the whole prototype and answers, and obtain the customer's named sign-off;
then write the app's constitution; then create stories. Use prototype fixes before sign-off. The
salesperson can be the FDE at first;
the developer takes over with docs/product/DISCOVERY.md, docs/product/BRIEF.md and the customer
call script. Build the prototype on the starter app. Rename or remove the Project placeholder.
Push back when a requested feature does not serve the problem card: explain why and
offer to note it for after sign-off. Keep the same app as it grows into production.
For a requested working prototype, build the demo-data loader in the first version, so the customer sees their own kind of
work instead of empty screens (see demo-data.md). Use the customer's words
from ## Words they use in docs/product/DISCOVERY.md for screen labels. Tell the salesperson
they can point at the screen: click an element in the demo build, write what's wrong and paste the
output to the agent.
Open decisions. Write each question only the client can answer in this form, in the decision
record under ## To confirm, the spec, or the plan's Notes where it belongs:
- Open question: <question>
Touches: <screen or rule>
Why we ask: <what the answer changes>
Default: <choice>
Why this default: <reason>
If the default stands: <what happens>
Due: <YYYY-MM-DD>
Gain <1-5>, Work <1-5>, Harm <1-5>
Pick the default, due date and scores with the review bar before you ask. Copy a cold-read or
review note that needs the client into this form. forge decision open prints the ranked list;
go through the whole list with the client in one sitting, then record the answers with
forge decision answer. When forge next says a due date passed, record the defaults with
forge decision answer --defaults and tell the client each default and that a new decision can
change it. After an upgrade, rewrite each existing to-confirm list and open question in this form
once in a mechanical fix.
For each demo round, gather all requests from one conversation into one prototype fix. Build,
test, review and merge that round before starting another. Tell the salesperson what changed in
the demo: "the next version is ready to demo" or "the reviewer found a missing error message".
Say a version is live only after the requested deployment is verified. Do not
use Forge's words (fix, worktree, branch, pull request) in progress updates to the salesperson.
When forge next says to connect the repo to our deploy platform, explain what is needed;
that reminder does not authorize deployment. When the user explicitly requests deployment, use
Mainline Deploy as above. After the requested deployment is verified, record its address under
## Demo in docs/product/BRIEF.md as - Address: <url>. Copy that address into the sign-off
decision. A canvas-only prototype needs no demo address.
The demo. Every demo follows five steps, in order:
Send the demo link only after the guided demo, never before it. With each new version, draft a three-line "what changed" note for the salesperson to send: what they can do now, what changed since their last look, and what to try first, all in their words.
After each demo, ask the salesperson one question at a time: what the customer did themselves,
what they said word for word, and what they asked for. Write the answers under
## Prototype notes in docs/product/DISCOVERY.md as one ### <YYYY-MM-DD> block with - Did:,
- Said: "<their words>" and one - Asked: line per request, ending each request in
(serves the problem) or (after sign-off).
Ask one topic at a time when it first changes what you are building. Skip a topic the repo already
answers. In the options column, our default is first where there is one; questions of fact have
no default. Offer Ask the client on every question and add it to the customer call script in
docs/product/DISCOVERY.md. For a topic that may wait, also offer Decide later. Standards
already decide logging, security and error handling; take those defaults and include them in the
read-back without asking again. The first seven topics must have answers from the client,
salesperson or developer before sign-off; a default or agent-only answer does not settle them.
| Topic | Question | Options (default first) | Before sign-off |
|---|---|---|---|
| Sign-off person | Who at the customer approves the prototype? | name and role | must |
| Demo workflow | Which one task should the demo let them do from start to finish? | from the problem card | must |
| Users and roles | Who uses it, and what can each kind of user do? | admin and staff; other | must |
| Existing systems | Which systems must this work with? | none; CRM; accounting; email or SMS; payments; company sign-in | must |
| Sign-in | How will people sign in? | email and password; company sign-in (Google or Microsoft) | must |
| Personal data | Will it hold personal, health or payment data, or data that must stay in one country? | none; personal only; regulated | must |
| Production host | Where will the real app run? | our platform; the client's cloud; the client's servers | must |
| Data import | Does data need to come in from today's tools? | no; a spreadsheet; another system | may wait |
| Email or SMS | Which provider sends messages? | none yet; the client's provider | may wait |
| Domain | Which web address? | our subdomain; the client's domain | may wait |
| Backups and uptime | How much downtime or data loss is acceptable? | the platform's daily backups; stricter | may wait |
| Log retention | How long must logs be kept? | the platform's default; longer | may wait |
Keep one ## Answers section in docs/product/BRIEF.md, one line per topic. Record an answer as
- <Topic>: <answer> (<source>, <YYYY-MM-DD>), with the client, salesperson, developer, our
default or agent as its source. Record an open request as
- <Topic>: ask the client (<who asked>, <date>); replace it with the sourced answer when the
client replies. Only a may-wait topic can read - <Topic>: later, when <trigger>.
Canvas and app design. Make each app's design from the whole docs/product/BRIEF.md: its
purpose, users, records, fields, choice-list options and key flows. Use impeccable and
emil-design-eng. Run impeccable's init when PRODUCT.md is missing. Make the screens in a Claude
Design artifact with a shadcn design system and named shadcn components. On a Codex-only host
without an artifact tool, make HTML artboards in the repo. Keep the canvas available for the
customer and the sign-off review. New clients get this process at init; existing clients can use
their current brief and design after upgrade and sync. Client sign-off does not require a root
DESIGN.md, SCREENS.md or CHECKS.md, or a specific Things it keeps track of heading.
When the canvas has a SCREENS.md screen list, add Build: now or Build: later to each screen.
Put the whole product on the canvas, every screen, state and flow, later ones too, and mark
Build: now only what the first stories build.
Before sign-off, use impeccable's critique and polish and the emil-design-eng checklist. The owner
or FDE can approve the canvas with forge decision new prototype-design and
forge decision accept prototype-design --by "<name>".
For each story that adds a screen or changes a flow, use this design process before its cold read.
Save the folder under docs/design/<KEY>/. End ## What changes for you with
Design: docs/design/<KEY>/ (<tree id>), using git rev-parse HEAD:docs/design/<KEY>.
One plan approval covers that exact folder. A changed folder needs a new tree id and approval.
For small changes to existing screens that add no screen and change no flow, use
Design: none (<why>) instead. Backend-only stories need no canvas. Earlier approved stories keep working.
The build applies any existing app theme and follows the approved story design, including its
components and fields. Workers and reviewers receive that design context.
Sign-off. Before anyone asks for sign-off, hold one read-back call with the customer that
goes through every item from forge decision open and every answer on the answers page: our
defaults, the agent's guesses and the topics marked later. Settle every open must-answer topic
in that call: forge next lists those still
missing, malformed, or marked ask the client or later, and sign-off also refuses one answered by
our default or the agent, so record each as the client, salesperson or developer answered it. Then
write forge decision new client-signoff (customer, demo address for a working build, and the answers page copied word for word, leaving
approved via and approved on empty), and run forge decision accept client-signoff --by "<name>"
before any reply is recorded. Put each demo step and its test under ## Proof for a working build,
and settled choices under ## Decisions.
Sign-off checks that the copied Answers section matches docs/product/BRIEF.md and that the full
run on main is green. Its completeness review must pass after judging the screens against the whole
brief, including its purpose, users, records, fields, choices and key flows; it does not require a
separate screen list. Missing screens, fields, options or flows hold sign-off. When a precondition is
missing, the refusal lists every gap and the next action for each. Existing clients can complete
sign-off with the brief and design they have after upgrade and sync; they do not need to add
prototype design files for this gate.
The check uses Codex's gpt-6.1-sol at high effort, independent of [models.design].
Codex must be installed because only Codex can review the screen images.
On Windows, large image folders use separate batches to fit the native command line limit.
Fix gaps, then retry forge decision accept client-signoff.
If the review engine fails, fix the engine problem and run the accept command again.
A canvas-only sign-off needs no working build. A working build gets a full first product review.
Each later attempt reviews only product files changed since the previous review and its open findings.
Every reviewer gets earlier findings and answers. Settled findings stay settled.
After two rounds, P0 findings still block until fixed. Other open findings need the owner's choice.
Record that choice with forge decision accept client-signoff --by "<name>" --resolve accept|more|split --reason "<human's choice>".
Accept keeps the findings in the item's Known issues. Split creates a separate fix. More permits one more review.
These rules apply to new clients and earlier-adopted clients after upgrade.
Forge reuses passed results while what they checked stays unchanged.
The product review uses the green full run as test evidence. It needs no separate forge test run.
If the product or completeness review cannot finish, the refusal names its saved raw report when one exists.
Before the customer's reply, the command runs these checks and stops without accepting sign-off.
Autoreview uses the
repo's tool and [models.review] settings, with Autoreview's defaults for unset values. Fix what it finds and run it again. Once it passes, tell the salesperson to ask the
customer's named person for sign-off their own way. Draft no sign-off email; Forge sends nothing. When they bring the reply back, record
it in approved_via and approved_on, then run forge decision accept client-signoff --by "<name>" again to accept. The customer's reply is the approval evidence the sign-off decision
records. Set approved_via to email, call or chat and approved_on to the reply date.
The Answers check ignores trailing whitespace and line-ending differences. A refusal names the first different line in the Answers section, including its heading.
Every normal, light and sign-off review runs through the external Autoreview program:
Claude when tools = "claude", Codex when tools = "codex". With tools = "both",
it uses Codex when installed and Claude otherwise. Forge passes the selected tool's
[models.review] model and optional effort to Autoreview; without an entry, it uses
Autoreview's defaults. New and earlier-adopted repos get this behaviour on the current release.
A requested working prototype proves the demo steps and its security and data boundaries.
Its light review checks demo breakage, security and data loss, using [models.light_review].
A requested working prototype gets a light review that blocks only on P0 findings.
A Not done against the item's own approved Done-when still blocks at any priority.
Full proof is due at sign-off.
After sign-off, every new story carries forward the available canvas, Proof and Decisions into
## Proven by the prototype. Treat that evidence as settled. Plan and cold read only new work
or production risks. Start from the prototype canvas or a newer design approved with the plan.
Plan the first stories only from screens marked Build: now. A Build: later screen stays on
the signed canvas as the source for a later story.
When a later story needs a topic marked later, its cold read reports Decide first: <topic>.
Ask that one question, put the answer in the finding's disposition and the story's Notes as
Decided: <topic>: <answer> (<source>, <date>), and make the first task update the answers page.
Until the decision, use a fake provider for an external service.
Ask for the app's currency at setup (default INR) and write its code to DEFAULT_CURRENCY in libs/shared/util/src/format.ts and, in a Python app, apps/api/app/core/config.py.
During both halves of the interview, ask one question at a time in plain words for a person who may not be technical.
Before the prototype, take the product answers from the client notes: what the app is for, who uses it, the records and fields it needs, the options of each choice list, and the key flows. Write them in docs/product/BRIEF.md. Record the options for each choice list with the thing it belongs to. The prototype and sign-off review use the whole brief.
At the start, write docs/product/CONSTITUTION.md with every default from Constitution defaults filled in, and raise a default with the FDE only when the notes contradict it.
On a new app, check the client notes for five growth topics: the users and records in year one and year three, heavy background work, other systems that call in or that the app calls, rules on where the data stays, and parts that can become their own product. Ask about a topic only when the notes touch it and do not answer it, one question at a time. Write each answer under ## Growth notes in the constitution. A later story reads these notes before it plans modules, jobs or links.
In an app with libs/mcp or apps/api/app/mcp, check the client notes for tasks that people
will ask an agent to do again and again. When the notes describe such a task and do not list
them all, ask one question: "Which tasks will people ask an agent to do again and again?"
Write each task under ## Agent tasks in the constitution as
- <task>: <feature>; inputs: <the inputs it needs>. With no task, write - None.
Ask it again only when the person wants to change the list.
In an app whose tests run Nx's module-boundary lint, copy the fixed rules into the constitution's ## Fixed rules section, and ask nothing about them. In an app that has libs/organisations or apps/api/app/organisations, also copy the built-in lines into ## Fixed rules, and ask nothing about the defaults they answer.
In an app with libs/core/server/src/common/request-log.middleware.ts or set_log_level in apps/api/app/core/logging.py, also copy this line into ## Fixed rules: "- Built in: each API request writes one log line with its method, route, status, time taken and request id, never the query string; LOG_LEVEL picks the lowest level written; password, token, secret, key and authorization values are removed from log details; Mainline sends error alerts from the error lines, so the app has no error-tracking service."
In an app whose .env.example has APP_COMPANIES, ask once: "Is the app for one company, or for many customer companies?" Write the answer under ## Defaults, set APP_COMPANIES to one or many in .env.example and in the host's settings, and ask it again only when the person wants to change it. When the answer is one company, also copy this line into ## Fixed rules: "- Built in: APP_COMPANIES=one makes a one-company app: corepack pnpm run setup:company (uv run --no-sync python -m app.setup_company in the Python starter) makes the company and its first admin, and people join only from an admin's invite." In an app made from the Python starter, whose tests run import-linter, copy these fixed rules into ## Fixed rules instead, and ask nothing about them:
In any other app, record the stack, package manager and folder layout that the app already uses, and leave out ## Fixed rules.
After the customer's sign-off and before the first story, finish the app's constitution in
docs/product/CONSTITUTION.md. Use the defaults in
Constitution defaults, except where
## Answers in the brief already gives a settled answer. Skip a defaulted question that ## Answers
already answers. Check the brief's Personal data answer; ask whether any data is private or
regulated only when that answer is missing, then record the answer in ## Answers.
Use this outline, and do not copy product facts from the brief into the constitution:
# <App name> constitution
The product facts are in docs/product/BRIEF.md.
## Principles
- Is it needed at all? Deleting beats fixing.
- Add work only when F x H >= 2 x C. F, for the first 1,000 users: 1 rare, 2 weekly, 3 daily. H: 1 cosmetic or the person's own data, 2 wrong information or a broken step, 3 a P0. C: 1 for 20 lines or fewer with no model call or user step, 2 for up to about 150 lines or one model call or user step, 3 for more, or a new table, job, workflow or flag.
- Choose the simplest option.
- Rules are stated, not policed.
## Defaults
- <the question in plain words>: <the default or the person's answer>
## Fixed rules
- One app on pnpm and Prisma, split into modules.
- Each module owns its tables, in its own schema file.
- Built in: each module keeps its tables in its own Postgres schema, with core tables in core; links between business modules store an indexed id without a foreign key, and links to core keep their foreign key.
- A module uses another module only through its public service, never through its tables.
- The tests run Nx's module-boundary lint, so an import across modules fails them.
- Built in: each account belongs to one organisation, as an admin or a member, and every query is scoped to that organisation.
- Built in: admins invite people by email; members cannot invite people or change roles.
- Built in: dates and times are stored in UTC and shown in the person's time zone, and money is stored as an exact decimal with its currency code; the helpers in @app/shared-util format them.
- Built in: each table has a CSV export, admin actions write change history, and records are soft deleted.
- Built in: the API serves an MCP server at /mcp. An admin adds agent accounts on the Members screen, with a role and a key that shows once; agents use each feature's tools with that role's permissions, and delete and restore tools stay off until an admin turns them on for the feature.
- Built in: each feature also offers its items, its field guide and its allowed values as MCP resources; agents get a prompt only for a task under ## Agent tasks; the MCP server never uses elicitation or sampling.
- Built in: every action goes through its feature's service and permission, from the screens, the API and agents; each feature's create takes a retry key; an agent that a person signs in acts as that person, and the change history records both; reports are named, typed reads in their feature's report service.
- Built in: each UI or API crash writes one error report to the logs.
## Growth notes
- <the growth topic>: <the answer from the client notes or the person>
## Agent tasks
- <the task>: <feature>; inputs: <the inputs it needs>, or None
## Architecture choices
- <the choice>: <its reason, in one plain line> (docs/decisions/NNNN-<slug>.md)
Copy ## Principles into every app's constitution word for word, and ask nothing about it. Do not
add it to an approved constitution: the principles reach that app through its briefs, cold reads
and reviews.
Make each architecture choice yourself, from the answers and the code, and write it as one plain line with its reason and its decision record. Record the stack that the code already uses. For parts with no code, use the stack default: an Nx workspace with React (Vite and React Router), NestJS and Postgres. Use a FastAPI backend only when the person asks for it. A FastAPI backend starts from forge init --starter python. Each architecture choice names an accepted record in docs/decisions/NNNN-<slug>.md.
Follow the database skill (.codex/skills/database/SKILL.md) for new tables and extensions.
Follow the agents skill (.codex/skills/agents/SKILL.md) for any agent, chat, voice or in-app assistant work. When a part adds one, the plan names the skill's sections that apply and the model service it uses.
An extension outside its allowed list needs the owner's OK for this client. Ask the owner,
then write - Postgres extension <name>: the owner allows it on <date> (<why>) under
Architecture choices in docs/product/CONSTITUTION.md.
A live app answers both halves at adoption: ask only what the code cannot answer. Record the stack the code already uses.
Create and accept a decision record for each architecture choice with
forge decision new <slug> and forge decision accept <slug> --by "<name>". Create the
constitution approval record with forge decision new app-constitution. When the brief answers
what the app is for, who uses it, what it keeps track of and whether its data is private or
regulated, and the constitution has its defaults and accepted architecture records, run
forge decision accept app-constitution --by "<owner>". The owner approves the constitution once.
If it is not ready, fill in the missing answers, defaults or decisions, then run the accept command
again.
No new story starts until the owner approves the constitution. Existing stories, parts and fixes
continue, and prototype work is not held. When forge next has a worktree cleanup step, finish
cleanup first. The constitution reminder returns after cleanup. If the constitution is missing, start the constitution
fix Forge names with forge fix start "Write the app constitution" --done "The owner approved docs/product/CONSTITUTION.md", then complete it before starting a story. A review or cold read in an app with an
approved constitution checks work against its text; a conflict is a P1 finding or note. A change
to documents only keeps its light review, which holds only P0 findings.
An app already in production joins Forge through one fix and one pull request the human merges. Adopting changes no app code.
When initializing an existing repo, answer "Does this repo run GitHub Actions?" from the repo's
settings: gh api repos/{owner}/{repo}/actions/permissions gives enabled. Ask the human only
if the settings do not answer it. Pass
--actions yes or --actions no; omit --checks when the answer is no.
Follow App constitution for both interview halves together. Ask only what the code cannot answer, and record the stack the code already uses.
Write the codebase report in docs/context/codebase.md: the stack and how to run it; the tests
and the areas they don't cover; the CI workflows and the checks branch protection requires; what
a merge triggers; branch rules and reviewers; the hook tools already in use; secret files and
variables by name only, never their values; where personal data lives; the migration tool; and
the danger zones.
Mark as danger zones the most-changed, most-reverted and most-hotfixed files in git history. A story that touches one names it under Risks.
List the open pull requests and branches in the report, so a story's plan avoids colliding with a teammate's work.
Link or import the repo's existing decision records and design docs as Forge decisions:
forge decision new <slug>, the original linked or copied unchanged under the line
Imported from <path>. Don't rewrite them.
Read the review comments of about the last 100 merged pull requests. Each rule reviewers enforce repeatedly becomes a House rule citing the pull requests it came from.
Ask the human three questions, one at a time, with options: who approves stories, who merges, and what must never be touched.
Write the answers and the reviewers' rules under ## House rules in AGENTS.md, outside Forge's
block. The repo's own rules win where they differ from Forge's default-stack conventions.
A rule every review must follow, such as which tests a kind of change needs, goes under
## Review rules in AGENTS.md, outside Forge's block: every review reads that section from the
default branch and follows it.
A repo keeps its rules in AGENTS.md only: forge sync moves a CLAUDE.md's own lines into
AGENTS.md, outside Forge's block, and deletes CLAUDE.md, since Claude Code reads AGENTS.md itself.
Propose a fast_test for the repo: its own test command, keeping its configuration and setup,
with the test tool's built-in changed-only option and {base} (for example
vitest --changed {base} or jest --changedSince {base}). Once the human agrees, set it in
forge.toml through a fix. For pytest repos, propose
forge test --pytest {base}: Forge runs this picker outside the project, keeping the repo's
full test command and narrows pytest to changed and module-related test files. Use the
repo's Python runner for test; keep Forge outside the project, and keep lint and other
checks in test.
Forge writes no fast_test by itself.
When fast_test is missing, forge doctor and forge upgrade print one suggested
fast_test line: Python gets forge test --pytest {base}; vitest and jest keep the
repo's own install and runner, adding --changed {base} or --changedSince {base}
and --passWithNoTests. Mixed repos get one part per kind. The Python picker skips
the JavaScript test runners, checks and installation steps, including when shared Python
inputs require all Python tests; the suggested Node part installs first and runs its checks
once. Forge's generated optional-package wrapper is kept around the Node suggestion.
npm exec keeps its own options before -- and its runner after it so npm forwards
the changed-file flags. Go, Rust, Java, .NET
and Ruby get no suggestion. Check the suggestion against the repo's setup before
agreeing to it; other shell flows need the agent to adapt the command.
When the repo has a Dockerfile, write services.toml as the deploy paragraph at the top
of this guide says, get the human's confirmation, and add it to the adoption fix.
On a live app, every story and fix also follows these:
-- Contract: ... line in Prisma SQL or a # Contract: ... line in Alembic Python. The line explains why the live release no longer reads the table or column; close allows it when the line is present, and review reads the explanation.On the default branch, forge doctor --fix commits its dated Forge-files fix with a proof list
of its Done-when and the files refreshed by the pinned release's sync. Run forge close <name>
as doctor suggests; close starts tests alongside the first review and reports both results. New repos get this
at setup, and existing repos get it when they move to this release.
When forge next says a newer Forge release is out, offer the upgrade to the owner.
Never upgrade without the owner's agreement. The check runs at most once per UTC day,
shares its cache across worktrees, and stays silent when GitHub cannot be reached.
An upgrade is one fix. Its pull request carries the new version and every file Forge keeps in the repo, rewritten by that version. One command does all of it.
Before starting another upgrade, it removes an earlier upgrade's leftover worktree and local branch when its pull request has merged and the checkout has no unpushed or uncommitted work. An open upgrade or local work still refuses and stays in place. Ignored configuration and data also stay in place; only recognized cache directories may be discarded.
forge upgrade names the items in the machine's lanes and asks you to wait if any remain.forge upgrade <release> in the main checkout, on the default branch. It installs the
release, has that release refresh Forge's files in the fix, commits them and closes the fix.
Its commit includes the upgrade's proof list; close reports tests and review results together.
It changes only the version in forge.toml.Next: line. Running it again picks up where it stopped.forge merge <fix> when the repo allows it.Close runs the time-story backfill as part of the upgrade, with nothing extra to type. It rebuilds open items and items merged in the last six weeks from git and GitHub, marks them "rebuilt from history", and leaves spans without evidence unknown. If GitHub cannot be reached, the next close on this machine retries the backfill. The agent then opens the board and reports what is still missing.
A repo pinned to a release without forge upgrade runs it once through uv:
uvx --from git+https://github.com/knacklabs/symphony-forge@<release> forge upgrade <release>.
Until the upgrade merges, the default branch keeps working with the new release installed.
After it merges, older branches keep their pinned release and its rules. When Forge says the
default branch already pins the installed release, merge origin/<default> into your branch to
use that release and its rules.
When the default branch's lockfiles and Dockerfiles are over a week old by git log, forge next
lists a refresh fix with its forge fix start command; start it like any ready item. In the
fix's folder:
npm update, pnpm update,
yarn upgrade (Yarn 1), yarn up -R '*' '@*/*' (Yarn 3+), bun update, uv lock --upgrade, poetry update, cargo update,
go get -u=patch ./... && go mod tidy); never raise a range.
For Yarn 2, remove only yarn.lock, then run yarn install --no-immutable;
keep every package.json unchanged. This re-resolves the whole dependency tree within its
declared ranges; recursive yarn up -R starts in Yarn 3.test_place: in local mode, run the related tests through
forge test; in CI mode, do not run them here. Commit, then forge close <fix>.Follow the agents skill (.codex/skills/agents/SKILL.md) for any agent, chat, voice or in-app assistant work. When a part adds one, the plan names the skill's sections that apply and the model service it uses.
A cold read passes when no note is at the bar (blocking): the plan is wrong, contradicts itself,
or a builder could not act on it. Readers prefix numbered findings with Blocking: or
Advisory:. Advisory and below-bar notes need no disposition from you or another round; unmarked
findings block in round one. A cold read stops after round two when notes below P0 are still
open, or when P0 notes are open in two rounds in a row.
New repos get this rule on init; existing repos get it on upgrade plus sync.
Start with forge start "<their words>". A spec is optional: when Forge chooses a plan, its branch adds
its missing roadmap entry, so no separate roadmap fix, spec read or spec confirmation is needed.
The entry travels with its tasks to the default branch, including tasks waiting on another story.
Write the problem, today's workaround and its cost in the plan's Why; the title seeds that
section. Run the story's one cold-read loop, then get its one approval. A story already linked
to a confirmed spec keeps that link and follows the same story read and approval as before.
Promotion keeps the fix's existing roadmap entry: before using --from-fix, put that entry
on the fix's branch and commit it. Promotion adds no entry or separate roadmap copy.
Forge refuses promotion while the fix's roadmap has uncommitted changes.
New repos get this guide at init; existing repos get it after upgrading Forge and running sync.
End each item of a plan's What changes for you with its source in plain words, such as
(Source: the client's note on late orders, 12 Oct), or with the sourced item that needs it,
such as (Needed by: the Customers screen). A source is a client note in
docs/product/DISCOVERY.md, an answer in docs/product/BRIEF.md, a decision in
docs/decisions/, a screen marked Build now at sign-off, a fixed rule in
docs/product/CONSTITUTION.md, or the human's own request with its date. An item that has a
source needs what it cannot work without: its validation, an error or empty state, an index for a
filter that a list shows, or accessibility basics. Name each screen, field, endpoint, tool and
setting that the plan adds in one of these items. Plan nothing that a source asks for but the
work does not need: Is it needed at all? Deleting beats fixing. The canvas can show
later screens; plan only the screens marked Build now. The starter's fixed rules are the base:
plan nothing beyond them just in case.
Readers should return plain No findings. alone when a read finds nothing. forge read also
accepts replies with at least one no-findings line when every numbered or bulleted item says
there are no findings, ignoring other note lines. A numbered or bulleted blocking finding in round one still
needs a disposition and another round.
Handle cold-read rounds yourself: amend the plan and write dispositions. Once a read is clean, before Plan Mode approval, list the choices you made alone answering notes in all rounds: each amendment that picked a behaviour, a limit, a refusal or a scope cut. Grill the human one question at a time, with your recommendation first. Record each answer in the plan, then ask for approval. Plain factual corrections need no question.
Use one framing line before showing a story in Plan Mode:
Approving: <title>, <n> parts, <risks>.
The owner approves only the top of the story doc. Show it from its title down to
## For the builders, unchanged, in Plan Mode and exit Plan Mode with that part as the plan; in
Codex, show the same part, then ask the approval question forge next gives. A doc with no
## For the builders heading is shown whole. The approval binds "What changes for you" and
"Done when", so tightening anything below ## For the builders needs no new approval, while
changing a result or "What changes for you" does. Once a round of cold read has passed, an edit only
below ## For the builders needs no new round either, and forge read refuses to run one; an
edit above it does. From round two, for stories, specs and decisions alike, the reader checks
whether each earlier finding is closed and raises anything new only for a P0 that happens in
normal use. A round-one fix that breaks the main path counts as a P0.
Blank question replies count as unanswered. The approval hook's pin notice appears only after
recording succeeds; if the repo pins a newer release, install that pinned release.
forge read refuses larger plans in one
line asking you to split them into smaller stories; already approved larger stories stay as they are.### Done-when details, the first section under ## For the builders. Workers and reviewers
get the entries of the items their task covers. An item with nothing to add has no entry.## For the builders heading, so the owner's
sections come first and everything for the agents sits below.forge fix allow-large "<reason>"
in the part's folder, the same way fixes work. Stories approved before this limit keep working.forge task feature <plural> --one <singular> --field '<field>:<kind>'.
Quote every --field value with single quotes, including simple fields. For example:forge task feature clients --one client --field 'name:text'
forge task feature jobs --one job --field 'name:text' --field 'description?:long-text' --field 'status:status(planned|active|done)' --field 'client?:link(clients)' --field 'hoursBudget?:number' --field 'budget?:money' --field 'dueDate?:date' --field 'contactEmail?:email' --field 'billable:yes-no'
A feature needs a text field for its name. The nine kinds are text, long-text, number, money,
date, yes-no, email, status and link; ? makes a field optional. Add other kinds by hand.
The worker runs the command; the human makes no technical choices and never types it.
Keep the generated organisation checks, change history and five permissions. If the plan
changes the role permissions, name that change for the worker to make in the feature's
permission mapping. A non-starter or older starter missing the required parts gets a refusal
naming what is missing; build that feature by hand in its existing layout.
libs/<plural>/server/src/<plural>.tools.ts, Python apps/api/app/<plural>/tools.py),
and the feature command writes it. When a story adds a route that agents need, the part
names the hand-made tool, its name in the form <feature>_<verb>, its permission and its
annotations. When the owner wants a default tool hidden, the part says so.
Every generated or hand-made tool follows these rules:
<singular>_id for an id. Strict input and output
schemas come from the feature's own schemas.query, the feature's filters, limit (20 by default,
up to 100) and cursor. Return next_cursor, how many match in all (more than 10,000
when capped), and how to narrow the search.response_format set to concise by default
and detailed on request, structuredContent with an outputSchema, and a short summary.isError, a plain message with the fix and an example
where useful, kind, retryable and retry_after_seconds. Never return HTTP statuses or
traces for tool failures; protocol errors are only for an unknown tool or malformed request.
A missing or revoked agent key is an HTTP 401 before any tool call.idempotency_key; update, delete and restore are safe to run again.readOnlyHint, destructiveHint, idempotentHint and
openWorldHint, to describe what the tool does.unavailable error. Limit each key
to 120 calls a minute per running API copy. Both errors say how many seconds to wait.
Work can still finish after the time limit, so a create's retry uses the same key.every tool has a description, annotations, schemas and the error shape passing for every tool, including tools added by hand.
Only starter apps get the MCP server. Upgrade and sync deliver this guidance without app
files or a services.toml change. In an older starter without MCP support, the feature
command builds the feature without tools and says so.viaAgent text.defineFeatureTools and need no code.
When a story builds or changes a feature that a task under ## Agent tasks names, the part
names its prompt: the name in the form <feature>_<verb>, its inputs and its permission.
Write no other prompt. Add no elicitation and never use sampling.forge next and forge task start hold the task until that task's pull request merges.New moving parts: line (see Build simple).The roadmap. Order stories by value, not by layer. The first story is the smallest slice, end to end and usable by the client; it brings only the setup, sign-in and data it needs. No setup-only, platform or "foundation" stories. Cut a story that answers no problem in its Why; when linked to a spec, it must also serve that spec's behaviour.
Start every task and fix forge next lists as ready at once, and close each as its worker
finishes. One machine runs agents on half its available cores (at least one; work rounds, plan reads and close
reviews), across all its repos; the rest wait in line. Every run also waits while load per
core is 1.5 or more, including when external jobs cause the load, or free memory is below its floor.
Busy local CI jobs reduce the available budget until they finish. Items that other planned work waits on go
first, first-come within each group; runs print their place and why when they start waiting and
each time it changes. Running agents keep their places. A run that dies frees its place once its agent ends. A waiting
run is working as meant: keep watching it. When a fix changed a story's plan on the default branch, forge next and forge task start say
so with the command that merges it into the story branch; run it, then carry on. Forge compares
content history, never commit dates: an older copy on the default branch does not block a start.
When only the story doc differs, forge task start merges the default branch into the clean
story branch itself and says so; conflicting edits still need the printed merge command.
When a story pins an older Forge release than the fetched default branch, forge task start
first merges that default branch into the clean story branch so the task uses the upgraded
release and rules. Resolve any merge conflicts in the named story folder, commit the merge,
then retry task start. Matching release pins need no upgrade merge.
This also works from an older story checkout or a stale default checkout: task start handles
the upgrade before Forge can forward the command to the checkout's older release.
forge next names the unmerged item a part waits on for overlapping files, including another
story's work, using the same overlap rule as forge task start.
Settled findings stay settled. Readers and reviewers receive all earlier rounds' notes,
answers and fixed or dismissed findings, including the coordinator's recorded work notes.
Forge ignores repeats of disposed cold-read text or a fixed review title and file; they cannot
block or start another round. A dismissed finding stays dismissed while the line its file:line
cites is unchanged, even when it moves; once that line changes, a repeat of it blocks again and
needs a fix or a new dismissal. A new defect needs distinct text and new evidence.
Human acceptance still expires when the accepted version changes. New repos get this on init;
existing repos, including earlier adopted ones, get it on upgrade and sync.
Unproven: item <n>: <case> or Trap: <trap>: item <n>: add the case to that Done-when item
and its test to the Tests cell of the task that owns it. Never resolve one only in Notes.Not needed: <what> on a large addition: name the item's source or the sourced item that
needs it, or cut the addition and add one line for it to plans/ideas.md. On a small addition it is advice: act on it only when
that is cheap.keep only a finding outside the boundary or factually wrong, and give
the reason as the Leave out line it falls under, the Raise line it lacks, the cited fact that
disproves it, or the human's Decided: line.Disputed keep <n>: <why>: the reader still disagrees with a finding you kept. Put it to the
human as one question with options, record the answer in the doc's Notes as
Decided: <finding>: <answer> (owner, <date>), and give both the kept finding and the disputed
one the disposition keep citing that line.Learn the traps. Before closing the story's last task, look back at the story's
review rounds. For each kind of finding the plan missed that cost two or more fix rounds or hit
two or more tasks, add one trap line to the ## Known traps section of the repo's AGENTS.md,
outside Forge's block, in the last task's worktree; create the section when it is missing.
Commit it before closing the task. Every cold read checks plans against that section.
Count the story's items' entries per file in the spotted records on the default branch, open or
done; each file with three or more, or one a task was stopped on (its state's stop), gets one
trap line naming the file and the kind of problem that kept coming back.
Before forge work can start a worker, resolve any unfinished merge in the item's checkout
and commit the merge, then rerun forge work <item>. Work refuses before changing its start
record or the index, so both conflicted and resolved but uncommitted merges stay intact.
New repos get this guidance at init; existing repos get it after upgrading and running sync.
When forge work says Claude ended without running a turn, no worker ran: Claude is often
waiting on a prompt, such as a review of changed hooks. Run claude once in the item's
checkout, answer its prompt, then run forge work <item> again.
Every Codex worker, plan reader and review runs with low model verbosity, no reasoning
summaries, and a developer instruction to write no progress commentary, only the final handoff
and any question. Forge sets these for each thread, including resumed threads; neither
forge.toml nor user or project Codex settings can turn them up. New and upgraded repos get
this automatically, with no setting to change.
When one sentence would help a worker finish its next round, give it with
forge work <item> --note "<text>". The note appears under "From the coordinator" in that
round's brief and is recorded with the turn. Give it again if a later round needs it; a note
does not change the item's Scope. Read a close finding and the code it cites before deciding
whether the worker needs a note or the finding should be dismissed with evidence.
If a worker ends with a Question: paragraph, answer with
forge work <item> --note "<answer>". The worker waits for that answer: another work round
without a note and forge close <item> both refuse until the answering round completes, and
forge next shows the question with that answer step. The
answer returns to the same conversation when it can resume; a fresh brief carries both the
question and answer. Workers change files outside Scope that the change needs and name them in
the handoff, so answer a Scope question only when the change isn't needed. If the answer needs a
choice the item does not settle, get that choice made before sending the note.
When a round ends with changes left uncommitted, forge work continues the same conversation
once, telling the worker to commit first. In a local-test repo, the worker runs related tests
through forge test once at the end of the turn, reruns only failures and commits any fixes. In a
CI-test repo, the worker commits first and leaves the change's related tests, lint and type checks
to pull request CI; it runs forge test only for a test it is writing, to watch it fail. Only
if changes are still uncommitted after that does it warn, naming them: forge close reviews only
what is committed, so look at them before closing.
Continued worker rounds repeat the selected test-place instruction and the commit-first order,
replacing any earlier full-suite instruction. Follow the repo's test_place choice when applying
the test-audit skill. The nightly full run covers the rest.
Forge trusts its own Codex hooks for each turn it starts, so the guard runs even after a hook
changes. Codex runs no project hook in a project it doesn't trust, so Codex workers and readers
all refuse there until the human trusts it. Forge needs an exact trusted [projects] entry in
Codex's config for the project folder or its main checkout; a parent folder's entry does not
count, and the refusal and forge doctor name the entry to set. A project hook that isn't Forge's and that Codex doesn't trust stops every Codex turn;
ask the human to review it in Codex's /hooks, then run the command again.
For a quick read-only question about this checkout, hand it to the session's explorer
subagent role. It uses the explore entry in forge.toml; no separate Forge command is needed.
Each kind in forge.toml's [models] table may have a codex and a claude entry, such as
[models.build.codex] and [models.build.claude]; a single entry counts only for its own model's
tool (a gpt model is Codex's, any other Claude's). Workers use their selected tool's entry,
and explorers use their host's entry. Workers and Claude plan readers with no entry use Forge's defaults.
Codex build, fix and lite default to gpt-6.1-sol at medium effort; design uses its design default.
Claude workers use model and effort
and ignore the Codex-only subagents and subagent_effort keys.
After forge sync, Codex sessions opened in the repo can use every shipped role, including
fixer. Sync keeps the team's other registered roles. The default subagent model and effort
come from build's Codex subagents and subagent_effort, falling back to lite's pair when
build has none. With neither pair, sync leaves the defaults unset. Hands-on Codex roles use
that same pair when set, so their worker model does not override the subagent budget.
Claude implementation (build, fix, lite and design, including frontend) defaults to
claude-sonnet-5-5 at xhigh effort. Claude plan reads (grill) default to
claude-opus-5-5 at high effort, including when Claude is the only installed tool.
forge init writes these Claude entries explicitly; omitted entries use the same built-in
defaults. Claude planner and architect roles use the plan-read entry; debugger, security
and performance roles use Opus 5.5 at high effort. Autoreview owns every review's model
and effort, including prototype sign-off.
Existing model entries stay unchanged on upgrade. To opt in, set each of
[models.build.claude], [models.fix.claude], [models.lite.claude],
[models.design.claude] to Sonnet at xhigh. Set [models.grill.claude] to Opus at high.
For a missing implementation entry,
add a top-level line before the first table, replacing build with each kind:
models.build.claude = { model = "claude-sonnet-5-5", effort = "xhigh" }.
For plan reads, use this line:
models.grill.claude = { model = "claude-opus-5-5", effort = "high" }.
If build, fix or lite has a single entry, move it to its family's table before adding the
Claude entry. Then run forge sync to refresh subagent roles. Legacy review entries stay
in existing settings but no longer override Autoreview's defaults.
With tools = "both", forge.toml's workers says who builds each task and fix.
forge work prints the worker,
model and effort it starts with, and why; forge next names the worker beside each ready task:
codex: everything on Codex; user-facing work uses [models.design.codex].claude: everything on Claude; user-facing work uses [models.design.claude].split (what forge init writes): user-facing story tasks on Claude, everything else on Codex.Split routing also applies in Forge's source repo: a task row's User-facing: yes selects
Claude and its design entry. New repos get this at init; existing repos get it on upgrade.
When the worker changes between rounds of one item, the next forge work starts a fresh session
on the new worker with the whole brief and the latest review findings.
Each task and fix keeps the same worker chat for each tool until merge. Later rounds resume it
after model or effort changes, restarts, missing local records or a fresh worktree. Plan reads
keep their reader chat across rounds too. Forge starts a new chat only when the tool reports
the old chat gone or archived, another program keeps it held after one retry, or the item changes
tools, and says why in one line. A work round starts the new chat with the whole brief, as a cold
read does. Other resume errors stop the round and keep its chat.
Upgrade's sync commits earlier-release chat bindings in their owning work branches, without
accepting reader findings. It also recovers turn logs when local JSON is missing, moved spec
worktrees and workers on forge/ branches. A landed spec's binding travels in the upgrade fix's existing notes.
Sync never waits for other items' runs: it leaves the chat of an item whose forge work or
forge read is running to that run, says so in one line, and refreshes everything else.
Sync writes every generated file first, then keeps chats. When it can't keep one (a run on an
earlier release holds it, its record has uncommitted edits, several worktrees hold a moved spec,
or Codex has no starting commit for a log-only spec read), it prints a warning that names the item,
the reason and the next step. It leaves that chat on this machine only, so run forge read <slug>
or forge work <item> on its own branch before you remove .git/forge.
Keep .git/forge until the upgrade finishes.
Codex app-server turns use the selected model's Fast tier for every fix, from the second worker
round onward, or when other planned work waits on the item (the board's waits_for dependencies).
Other turns run at normal speed; models without Fast also run normally. Fast uses more of your Codex allowance.
The optional codex_fast setting in forge.toml defaults to "needed"; choose "off" to disable
Fast or "always" to request it on every Codex turn. forge doctor shows the policy and whether the last Codex turn ran
with Fast. When Fast is wanted but the model does not offer it, the run's first line says so.
Every turn, including capacity retries, records the
requested tier and the tier Codex reports; an unreported tier stays unknown. New repos
get the default at init; existing repos get it on upgrade without adding a setting, and sync
refreshes both host guides. The upgrade's sync announces the default in one line.
For a side job inside your own session, hand it to one of Forge's subagent roles, which
forge sync writes for both hosts from forge.toml's models: explorer to read and trace code;
planner and architect for planning and design choices; debugger, security and
performance to diagnose; worker, coder, frontend, tester and refactorer to build.
The diagnosing and planning roles change no files. Building an item still goes through
forge work. To change a building or planning role's model or effort, change forge.toml
and run forge sync; Claude diagnostic roles keep Opus at high effort.
Codex roles use their host's entry when the kind has per-tool entries. With a single entry, a model
from the other tool is omitted so the Codex role uses the session's model. Claude building
roles use their implementation entry or Sonnet xhigh; Claude planning uses grill or Opus high,
and Claude diagnosing always uses Opus high.
The explorer role uses the read-only explore kind; lite keeps a fix's first
build round. New repos get [models.explore.claude] with claude-haiku-5-5 at high effort and
[models.explore.codex] with the same settings as the initial lite Codex entry. Existing repos
without explore keep using lite for read-only work after upgrading and syncing. To choose
separate read-only settings there, add the explore entries in a fix and run forge sync.
Git merges the roadmap and spotted list with forge hook merge-roadmap from PATH.
Edits to different fields of an item merge; competing edits to the same field need a manual resolution.
New repos get this rule at init; existing repos get it with forge sync or
forge doctor --fix. The shared rule keeps working after a worktree is removed.
Doctor repairs both paths in Git's shared local attributes, including when an older
repo's tracked attributes only name the roadmap, without enabling excluded git hooks.
Read standards.md beside this skill for Forge's principles, the client's app rules and the build-simple ladder. Apply its rules in every phase.
Finding forms. Simpler: <cut> → <replacement> is P2, or P1 when a new moving part isn't
named in the story. Untraced work: Cut or defer: <item>. An unmet Done-when item:
Not done: <item> (P1). A missing rule-11 basic is its own P1, never Simpler:.
A Not done finding blocks only when it names a Done-when item the change misses as
written. A case the Done-when does not name, such as another language, platform, shell,
tool or folder layout, is a P2 Follow-up: <the case> finding that Forge records and the merge
doesn't wait for, even when the case is realistic; a functional, security or data-loss defect
on the changed code still blocks under its own Raise line.
Only the human decides to drop a fix. Ask first and run forge fix drop <fix> --because "<reason>" only on a clear yes. Forge pushes the fix branch, records the reason, who and when
on that branch, and closes its pull request with the reason. The fix leaves the board,
forge next and the merge queue. Its name stays reserved and its remote branch keeps the work.
Forge removes the clean worktree and local branch unless ignored files outside rebuildable folders keep it. It lists those paths and keeps their data. Commit uncommitted changes first; wait for local Forge runs to finish and drop or finish any open fixes stacked on this fix. A merged fix cannot be dropped.
Run forge fix drop <fix> --undo to bring it back. Forge restores the worktree or reuses the
kept one after a fast-forward, records the restore and reopens a pull request the drop closed.
A fix that was ready needs forge close again for its new commit. Teammates see a drop or
restore after they fetch.
A fix gets one review round; a story part gets two. At the round limit, open findings below P0 stop the item and ask the owner: one more round, split or accept. Accept makes the open findings follow-ups in Known issues with the owner's reason. An open P0 never stops for the owner; the worker keeps fixing it. When the same P0 stays open two worker rounds in a row, Forge stops with the stuck question.
From the second review round, close checks the previous round's findings and new P0s that
happen in normal use. The reviewer says fixed or not fixed for each previous finding.
A round-one fix that breaks the main path counts as a P0 (Harm 4 or more). Open findings below
P0 need the owner's choice at the limit, whether their lines changed or not.
A Case: rare finding does not block unless it names a kind the owner requires.
A security hole or data loss that any user can reach is normal use. Reviewers and readers do not
raise questions that Review rules or recorded owner
decisions (docs/decisions/, Decided: or Ruling:) already settle.
A worker can decline a finding in a commit body with
Declined: <title> (<file>): not worth the code - <reason>, using its exact title and file.
An empty commit is fine. Close applies it even to a reused review and keeps it as a follow-up.
A P0 stays open. Later rounds receive the decline as settled. Only the human dismisses findings.
Not done blocks only against a numbered owner-approved Done-when item (a fix uses its Done-when
line). Builder details, Notes and implementation guidance never block as Not done.
New repos get this guide on init; existing repos, including earlier adopted repos, get it on
upgrade and sync. Close applies the same boundary in every repo.
The owner can set added_work_min_gain to 3, 4 or 5 and always_block to a list of kinds in
forge.toml. Record the owner's settings in a fix. They apply after it merges, from the default
branch. Adds work: <what> marks a finding that asks for another check, retry, guard or flag.
An unfloored fix-now finding below the minimum becomes a Known issue with its scores and reason.
Harm 4 or more, Gain 5 and every score floor still block. Must: <kind>: <gap> holds a listed
kind at any score, even for a rare case or in a light review. The worker cannot decline it.
Only the owner can accept it. Without these settings, new and existing repos keep today's bar.
An upgrade adds no setting. Plan reads and prototype sign-off keep today's bar.
Before building a fix, check its brief for the five-code-file limit, interface globs and any
recorded allowance; test files and files whose content is exactly what forge sync writes don't
count, so an upgrade fix needs no allowance. You may run forge fix allow-large "<reason>"
yourself, without asking the human, when the fix corrects one kind of problem in every place it
appears and changes no interface. Name that problem in the reason and record the allowance
before editing beyond the limit. Anything else needs the human's allowance or a story.
For a follow-up to an unmerged item's findings, run forge fix start in that item's checkout.
The fix starts there, and its size and interface checks count only its own changes, including
after the underlying item lands. Close first tries a plain merge of the current default branch
without changing the checkout. If it is clean, close keeps the branch's commits and merges when
the pull request needs it. A clean merge needs no force-push. If the merge conflicts after the
underlying item lands, close replays only the follow-up's own commits from its recorded start
onto the current default branch and publishes with a lease. It preserves earlier merge edits,
leaves unknown remote commits alone, and stops with a replay command if the fix's own changes
conflict. Follow the printed replay and leased publication commands before closing again.
Otherwise it starts from the default branch and close keeps merging default updates.
Follow-up replay and merging default-branch updates before the underlying item lands need Git
2.38 or newer.
Mark generated files such as migration snapshots linguist-generated in .gitattributes, so
reviews show them only as counts of changed lines.
Read the worker's final handoff and resolve its stated blockers before forge close.
Before close, the worker puts a Proof list: paragraph in its last commit message: each Done-when
item you cover and every detail next to the test or check that proves it, or marked missing.
Name each test by its pytest node ID or file and write no test results: close checks each named
test against its own run and writes the list with only the tests it ran and their results, and marks every line it cannot match to its run's per-test results not checked. Name any other
check with its result. Forge copies the list into the pull request and the review prompt. The first review checks the whole list, not a sample: Check every
entry against the code and its named proof, including every Done-when detail. Compare it with the
covered items so omitted entries cannot hide gaps; report every missing case in that one round,
even when a finding already blocks. Keep the whole list current; later reviews check repairs and
newly changed lines under the boundary above.
When a Done-when item's named proof is a pull request check that has not finished yet, do not
report it as Not done if the check is configured to run on the pull request. Close's checks
gate holds the merge until that check passes. A failed check or a proof with no check behind
it is still P1 Not done. New repos get these instructions at init; existing repos get them
after upgrading Forge and running sync.
Test fixtures are plain text files, never archives or other binary files. Build an old repo for
an upgrade test in the test from a text fixture folder. Close refuses added binary files under
tests/ before the review, naming the file to replace.
When every file a change touches is forge.toml, under docs/ or plans/, a Markdown file or under
.factory/, close skips forge.toml's test command and says so; the review and every named check
still run.
When a worker round or close's merge changes the item's Forge pin, land and close say so in one
line and continue through uv under that release before reading its new settings.
Generated-conflict sync and the merge commit check use the new pin too, so the merge finishes
before the original land or close command continues.
The board and next use failed pull request checks only when they belong to that pull request's
current head, including branches that exist only on the remote or are ahead of the local branch.
Close and forge next warn when this item and another open branch add the same migration
number under a migrations folder. The warning names both items and the number. It does not
stop work or need a setting. Forge refreshes origin once and reads its branch snapshot without
a checkout. Completed items do not cause warnings, even when their branches remain on origin.
Close brings in the current default branch before it tests or reviews. If only files forge sync writes
conflict, close takes the default branch's copies, runs sync and commits the merge. A conflict in
any other file stops close for the worker to resolve. While waiting for checks, close stops at once
if GitHub reports a conflicting pull request: GitHub runs no checks on it. Rerun close to bring
in the default branch. Land retries close once itself, including a conflict during its merge check
wait; if the merge needs a person, it stops with close's existing conflict next step.
If GitHub refuses a pull request body update, close stops after one attempt, including during a
history retry. Wait for a rate limit to reset, or fix the reported problem, then retry the command.
Close reruns failed pytest files once after a local test failure. If they pass, close names
them as flaky and continues. A second failure still stops close. A failure without named
test files still stops close.
In local mode, close's tests and review run at the same time. In CI mode, close runs its review
while the pull request's checks run, then waits for both. A red test or a P0/P1 finding still
stops the round. When the
local test command fails, its test report ends with all failed pytest files and test names,
including setup, teardown and collection errors, and the full test log path.
Close keeps the output for the worker: run
forge work <item>, whose brief carries it; forge land runs that fix round itself.
In CI mode, close leaves test execution to the pull request's tests check. In local mode, close
runs fast_test when set. Otherwise it uses the shipped pytest picker for changed tests
and tests importing changed Python modules, Vitest's --changed <base>, or Jest's
--changedSince <base> (including __tests__ files). The pull request's CI runs the related
tests; the nightly full run covers the rest.
Docs and brand-asset changes get the light review, which blocks only on P0 findings.
Close and the generated forge.yml skip the test command when every changed path is Markdown
(case-insensitive), or under docs/, plans/, .factory/ or .forge/. They compare against the
base with the same rule as the part-size check. No setting is needed. The required tests check
passes and says docs only: tests skipped. Images and fonts also count as assets, wherever they
live. Files marked linguist-generated and docs or assets referenced by tests keep the full
review and tests. Forge resolves literal paths from the repository or test file's folder on
both sides of the change, including literal path joins, __tests__/ files and shared
conftest.py fixtures.
CI checks this once before the tests job and skips that job for a docs-only change.
One code file runs tests as usual. New repos get
this rule at init, and existing repos get it after upgrade and sync. Bare forge test still runs.
For other changes, the generated forge.yml runs one tests job with forge test --change.
Set groups = 4 in forge.toml to run four parallel jobs with any test runner. Each job runs the
tests related to the pull request. Put {group} and {groups} in the test or fast_test
command where the runner expects its shard number and total, for example
vitest run --shard={group}/{groups}. Forge fills these values for each job and uses 1 for both
outside CI. Without a shard flag, each job repeats the same related tests; this is correct but
slower. For a direct pytest command with pytest-split, Forge adds the split options automatically.
When groups exceeds 1 and test has no {group} placeholder or automatic pytest split,
forge doctor and the generated workflow each show one warning. They do not refuse or change
the chosen groups. Set groups to 1 or add the runner's shard options to test.
Init writes groups = 1 for new and adopted repos. An upgrade adds no groups setting, so an
existing repo with a direct pytest command and pytest-split keeps its six groups. Each group then
runs its share of the related tests through forge test --change. The required tests check passes
only when every job passes; branch protection keeps the same tests check.
In CI mode, forge.yml also runs forge test --full once a day on the default branch and supports
workflow_dispatch. To start a full run now, run gh workflow run forge.yml --ref <default>.
Local mode has no scheduled job; when forge next says the daily run is due, run forge test --full
in the main checkout when the machine is quiet. A green full run on the latest default-branch
commit is required before pushing a release tag or accepting client-signoff. Everyday merges do
not wait for it.
A failed scheduled or manual full run appears in forge next with its failed test names.
The required forge-pr-check fails a pull request from a branch Forge did not start.
Before the first committed review, this check stays pending. A stale or blocked review still
fails. New repos get this rule at init. Existing repos get it after upgrade and sync.
Redo the change with forge fix start "<why>" --done "<done when>" and copy the commits there.
Forge's generated forge/* branches and doctor's dated fix/forge-files-* branches still use
the normal check for a Forge record and a current review. New repos get this check at init;
existing repos get it after upgrading Forge. Sync refreshes these instructions for both.
Each change runs its related tests, lint and type checks once. Close runs the full related-test
selection, even when it covers more than a third of the Python test files. Shared test inputs
select every test.
Bare forge test keeps worker runs bounded: when the pytest selection would cover more than
a third of the Python test files, it runs only the part's Tests column or the fix's touched test
files, plus always_test, and says "The nightly full run covers the rest." With no named tests
it runs only always_test. An explicit forge test --pytest <base> keeps the full selection.
New repos get this bound at init; existing repos get it after upgrade and sync.
Setup steps such as uv sync and npm ci keep their arguments; no filenames are appended.
Forge's initial optional-package Node command uses the same selection once an app adds
package.json; with no package it still runs nothing.
Go and other runners run the full test command. Compound npm scripts also keep their full
command because arguments cannot select each runner inside them. Set fast_test for a different
selection. Supported runners with no related tests run none locally. A red CI still sends
the item back to the worker.
To include fast checks or a wider selection, set fast_test in forge.toml (in a fix), with
{base} standing for the merge base with the default branch.
Tests that check the whole repo, such as rules over every test file, name no changed file, so
the pytest picker never picks them by default. List them in always_test in
forge.toml (in a fix), as test files or pytest node IDs such as
tests/test_rules.py::test_1_rules; it is empty by default. With the pytest picker, close runs
them on every change that includes code or settings, beside the tests it picks. Docs-only changes
skip these tests too.
Forge passes each entry to pytest, so it runs even outside the paths test names. In a grouped
run, pytest-split assigns each entry to one group; the other groups do not fail because they did
not run it. A missing file or node still fails. In a grouped run, a mark or -k filter that
removes an entry is not reported as missing. In a one-group run, an entry that runs no test, for
example because -k deselects it, still fails the run.
For pytest repos, set fast_test to forge test --pytest {base}. Forge's own repo uses this
shipped picker too. It selects only changed test files and tests importing or naming a changed
Python module by its dotted name or file path, such as shop.prices or src/shop/prices.py,
including package-relative imports. Filenames and references to changed non-Python inputs
do not select tests. After the run it names each changed Python file that no test names. Tests
that run the program from outside miss it locally; the nightly full run covers it. It supports
root packages and the src/ layout, and pytest's
test_*.py and *_test.py filenames. It excludes unrelated tests even when the full command names them explicitly. It keeps
the full test command's setup and options, caps pytest-xdist at half the machine's cores even
when pytest configuration supplies the worker count, and runs the
full command when conftest.py, requirements or lock files change, except for bare forge test's
worker bound above.
For pyproject.toml, every change triggers the full command unless all changed lines are
known-harmless: project.version and project.description, or Hatch's packaged-file
include, exclude and force-include settings under tool.hatch.build and its wheel
or sdist targets. Multiline values are supported. Unknown sections, unsupported layouts,
comments outside safe values and mixed safe/unsafe edits run the full command.
Forge's commands and generated tests job set UV_FROZEN=1, so uv consumes the recorded
lockfile without rewriting it, including in older worktrees. If you wrap a Forge command in
uv run, use uv run --frozen: the outer uv starts before Forge can set its environment.
Update dependency locks deliberately before testing changed dependencies.
For uv.lock, poetry.lock, Pipfile.lock and package-lock.json, a change only to
the repo's own package version selects related tests instead. Forge identifies the
root package from the adjacent manifest and its local source; dependency versions,
hashes and other lock data still trigger the full run. Missing or unrecognized lock
data also triggers the full run.
New pytest repos get this proposal at setup; existing repos get the picker and guidance after
upgrade. Upgrade never rewrites their test or fast_test settings. Doctor reports an old
python -m forge.fasttest setting with its one-line replacement. Forge needs no installation
in the project: it loads a temporary pytest hook to exclude unrelated files, including on pytest
before 8.2. Test launchers must preserve PYTHONPATH, forward pytest arguments and expose xdist
options in the command or pytest configuration.
Workers run tests only through bare forge test. It runs fast_test, or test when none is
set (using pytest selection when supported), with {base} as the merge base with
origin/<default branch>, in the same fair machine-wide test lane as close.
It prints the report close keeps and always runs, including docs-only and
uncommitted changes. If the remote default branch is missing it says to fetch it; if forge.toml
names no test command it says so and exits successfully. Forge sets PYTEST_XDIST_AUTO_NUM_WORKERS
and FORGE_TEST_CPUS to the run's allocation from the shared process budget. A worker's session
requests at most two processes, so its own pytest -n auto also stays at two. A fixed -n in
its test command is capped with --maxprocesses, also outside a worker session.
Direct Vitest and Jest commands use the same budget through --maxWorkers.
This includes npx (with optional --no-install) and npm exec, pnpm exec or yarn exec.
Forge caps explicit --maxWorkers values to the run's allocation, including percentage values.
Lower caps and Jest's serial options --runInBand and -i stay as written.
Forge does not change npm, pnpm or yarn scripts to set their worker budget.
It keeps existing NODE_OPTIONS and adds a Node preload that caps the actual runner's arguments,
so package scripts keep their lifecycle hooks and share the same process budget.
Those scripts can read FORGE_TEST_CPUS. If the test command runs Vitest through a script
with Vitest projects, pass --maxWorkers=${FORGE_TEST_CPUS:-2} on the command line,
for example npm test -- --maxWorkers=${FORGE_TEST_CPUS:-2}, instead of setting the cap
in the Vitest config. A config cap can leave projects with different maxWorkers but the
same sequence.groupOrder, which Vitest refuses. Other runners stay as written.
Direct forge test --pytest <base> runs join the test lane and obey its memory floor and budget.
A picker inside close or bare forge test shares that run's single lane entry.
pytest -n auto honours
the first; other runners may read the second. The lane stays taken until the test command ends,
even if Forge is killed. forge stop <item> ends a running test or removes a waiting one.
When forge close stops on a finding, open the line it cites, and the code that line calls,
before anything else. The review's "What counts" list is the boundary, and the bar decides
inside it: every finding at the bar (Proposed "fix now" or "fix this round") gets a fix round with
forge work <item>, whatever its priority, unless close waits for the owner's choice or a decline
makes it a follow-up. A finding below the bar holds only when it names a required Must: kind
or this item's own Done-when. Close lists other findings in the pull request as follow-ups or
lived with. Harm 4 or 5, or Gain 5 stops the work.
Otherwise, Gain 4, or Gain 3 with Harm 3, holds the work only with Work 1 or 2. Every other
Gain 3 or 4 finding becomes a follow-up fix, even at Work 1 or 2 when Gain is 3 and Harm is 1 or 2.
Gain 1 or 2 is lived with. Never re-score a finding to change its
outcome. Dismiss only a finding outside the boundary or factually wrong, with
forge close <item> --dismiss <n> --because "<file:line> <why>", where the why names the Leave
out line it falls under or the Raise line it lacks, or the file:line is the code that disproves it.
Close fetches the default branch but merges it in only for a trial-merge clash, or when GitHub
reports the pull request conflicting or behind under its up-to-date rule. Unrelated main changes
add no merge. Close checks GitHub's clash state at every look, even with green checks; a clash
stops a hand-run close and says to run close again. An UNKNOWN answer keeps it waiting.
When close merges the latest default branch, an unchanged branch diff keeps the last review and
its dismissals, including --dismiss given in that close command. A changed diff needs a new review.
Before reusing serious findings, close also checks the reviewed files and contract against the
current head. A repair brought in from the default branch needs a new review, even if the branch
diff stayed the same. Land uses the same check through close.
Close pushes and opens the pull request before a new review, so CI runs alongside it, then
updates the pull request's review block when the review finishes. Ready still needs a clean
review and green checks on the final pushed head. After forge fix amend, close also updates
the pull request's Done when line. Use --append "<text>" to add text with a space between
the old and new text. --done "<done when>" replaces the whole Done-when. Both options show
the old and new text before writing, and need --because "<why>".
Upgrade close leaves the repo's local git hooks alone,
including when it regenerates conflicted Forge files with the newly pinned release.
If conflicted-merge handling fails, close aborts the merge and reports the error before retrying.
After upgrading, run forge sync to receive
the tests workflow's quick pass: it reuses a successful parent tests workflow only when the
commit changes Forge's review or test-state record and its accompanying state under .factory/. Any other
change or missing passing parent result runs the suite on the pull request merged into its
current base. Reuse also requires the parent to include that base; a parent pull request run
must have tested that same base. A changed base or missing proof runs the suite again.
Other workflows can use the same rule. Init and forge sync ship .forge/records-only.
After checkout, add this one step: - {id: forge-records, uses: ./.forge/records-only}.
Give the job contents: read and actions: read permissions, and fetch the full history.
The runner needs Python, Bash and the GitHub CLI, as GitHub-hosted runners provide.
Add the condition below to each later step that can skip the records commit:
permissions:
contents: read
actions: read
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- {id: forge-records, uses: ./.forge/records-only}
- if: steps.forge-records.outputs.records_only != 'true'
run: your-build-command
The output is records_only=true only for a push or pull request whose parent passed this
same workflow. The step uses Forge's existing close-record rule. Code changes, documentation
changes, a failed parent run or missing proof produce false, so the workflow runs normally.
For pull requests, the parent must also include the current base and its run must cover that base.
Each job that uses the step skips only its guarded steps.
When forge land stops after its one fix round or on a check it cannot fix, judge
them the same way: dismiss with evidence, or forge work <item>, then forge land <item> again.
A failed CI job whose log names none of the change's files is re-run once per pushed head
instead of costing a fix round. Forge's review check follows review recovery, never this retry.
When GitHub has not started that
re-run in time, land stops; run forge land <item> again, which closes again and runs a fix
round if the check is still red.
Use forge land <item> for build, close, fix rounds and merge where agent merges are allowed;
otherwise it hands the ready pull request to the human. It replaces private landing and CI-wait
loops, with bounded check waiting and fix rounds. Land waits for the pushed head's checks while
GitHub shows progress or checks remain queued, retrying unreadable or failed answers. It stops
waiting on green or failed checks, or after 30 minutes without a check starting, finishing or
being replaced while none are queued, and says which checks are still running, missing, or
unreadable. Close on its own still waits at most ten minutes while none are queued. When it
stops, follow its refusal and the
Closing section above, then run it again. Run it in the background and keep watching it.
GitHub reads also retry unreadable answers and server errors three times, pausing for one,
two and four seconds. If GitHub still does not answer, rerun the command. Not-found and
permission refusals stop immediately; writes are never replayed by these read retries.
If the branch already has commits after the item's start, land goes straight to close unless
you give --note "<text>" to start a worker round with that guidance. The note applies only to
the first round this run starts, not later fix rounds. Close
still stops for a pending question and gives open findings or failing tests a worker fix round.
Use forge land --all in place of a hand-made merge lane. It takes every task and fix whose
status is reviewing, fixing, waiting for checks or ready, and leaves out, by name, one still with
its builder, one already merged and one another command works on. It starts them oldest first,
several at a time up to this machine's agent places, and merges each one when it passes.
A child that waits only for GitHub checks releases its place so another close can start.
It takes a place again before it continues. Queued checks keep their place to limit new CI work.
A stacked
fix follows its base even when its start date is earlier. Where Forge merges, it waits for its
base to merge, including a base whose builder or another command still works on it. If the base
stops, the stacked fix stops with it. A base outside the run must merge before the stacked fix
can enter close. Among changes whose bases are ready, the oldest starts first. A change
not yet ready that changes a file an older change in the run also changes waits until that one
merges or stops; Forge's own plans/spotted.json and .factory/ files never count. Only one run
works in a repo at a time. When two closes in the run collide on git's ref lock while fetching,
the run starts that change again once and says so. It runs no fix rounds: a change that needs a worker or the owner stops
alone and the others go on. The run ends with Merged (n): ... · Ready to merge (n): ... · Needs you (n): ..., then each stopped change with its reason and next step: forge land <item> for
its fix rounds, or, for a stopped change, close's own question and next step, which only the owner
answers. Close waits for the owner's recorded choice. A failed
CI job whose log names none of the change's files runs again once; a second failure stops that
change. Forge's review check follows review recovery instead. Where a human merges, the run closes
every change, holds none and merges none, and lists the ready ones oldest first, with stacked fixes after their bases,
with their pull request links: merge them
in that order.
Start a part with forge task start <KEY>/<TASK>, or a named fix with
forge fix start "<why>" --done "<done when>" --slug <name>, then forge land <item>.
To guide a round and continue through close and merge, use forge land <item> --note "<text>".
To queue several items, run forge land <item> for each in the background, with --note when
needed. Forge admits each worker round by machine capacity. Do not write shell queues or private
slot loops. --note takes one item and cannot be used with --all.
forge work queues work rounds across the machine, while reads and close reviews skip
that line. All runs wait for high load to fall and memory to recover. Busy local CI jobs reserve
cores from the budget until they finish. Close and worker tests share the separate test lane, except picker runs of five or fewer
test files, with one place per four available cores
(at least one), so no private slot loop is needed.
If close refuses a conflicted merge, it has aborted the merge. In the item's worktree:
forge.toml first.
Keep the team's notes outside Forge's blocks in shared files such as AGENTS.md; never take
one side of a whole shared file blindly. Resolve the structure of shared Markdown, JSON and
TOML files so sync can read them.forge sync to regenerate Forge's own files and blocks.
For merge-driver setup or drift, use forge sync or forge doctor --fix.git add <paths>,
and commit once every conflict is resolved. Then rerun forge close <item> or
forge land <item>.Starting is the claim: forge story new, forge task start and forge fix start push the
new branch to GitHub after committing its start. The author of that start commit is the person
who started the work; the board page and forge board --json show them next to the plan's
approver, refreshing GitHub's branches so existing checkouts see new claims. Git is the one
record. Git keeps a start tag pointing at the original commit, so its author survives squash
merges and work-branch cleanup. A retained fix start tag reserves its name even after its
branch is abandoned; another start says the name is taken and uses the next numbered name.
Close also publishes retained start commits when an earlier
start push failed. A second checkout's
task start names the person who already started that part on GitHub. A failed push says so
and leaves the work local: teammates cannot see that claim until its branch is pushed.
New repos get this at init; existing repos get it when upgraded and synced, including repos
adopted on an earlier release.
Use forge assign <KEY> <login> to give a story to a developer by GitHub username.
Use forge assign <KEY/TASK> <login> to give one part to a developer.
The command writes the story's Owner: line or the part's Developer cell.
It commits the plan on the story branch and pushes that branch.
If the story has no plan, the command refuses and says to plan it first.
After git fetch origin, forge next reads assignments from the remote story branch.
For that developer, it offers assigned ready parts first, then unassigned parts.
A part's Developer cell overrides the story's Owner.
Someone else can start an assigned part. Task start names its assigned developer in a warning.
The board JSON carries owner for each story and part, including parts not started yet.
The lead can change assignments below For the builders without another approval.
After fetching, teammates can discover the published story before its first part merges.
If publishing its approval failed, the approved plan on the default branch after its first
part merges takes precedence over the story's initial published draft.
Next, start and both boards reconcile published assignments with local builder edits;
a locally changed assignment takes precedence, and conflicting other edits need reconciliation.
The plan's Owner line and Developer cells are the assignment records. There is no separate roster.
Serialize start commands. When task start refuses for overlapping work or an unmet dependency,
keep other ready work moving while that work finishes. Run forge next after each merge to
start what was unblocked. Retry a start only after its dependency or overlap clears; follow
other refusals' next actions instead of repeatedly retrying them.
A worker or review notes problems outside its change as spotted items, which Forge keeps in
spotted records and nobody edits by hand. A spotted item never widens the change in hand,
except a bug that blocks it. When forge next names a file that keeps breaking, start its fix
command at once, like any ready item, without asking the owner.
When forge next says the latest scheduled run of the default branch failed, it names the
failed jobs and tests; start its fix command the same way, or follow the step it gives for the
fix already started.
Close stops at review round two for a story part or round one for a fix when findings below P0
remain open. It asks the owner: "One more round, split or accept?" Close, land and work show
the same question until the owner records a choice. An open P0 returns to the worker.
An older release's unanswered stop also waits for the owner.
Land prints the owner's question, open findings and failing checks, then exits with status 3
(needs a choice). It does not wait or send the worker back while the stop is unanswered.
Record the choice with
forge close <item> --resolve <more|split|accept> --reason "<human's choice>".
Then run forge land <item> again. Land also prints open findings and failing checks when it
stops for another reason or hands a round to a session subagent.
More gives the worker one more round. After that review, close asks again if findings below P0
remain open and no P0 is open.
Split creates one follow-up fix with
every open finding's title and file:line in its why and Done-when. Close records the fix on the
item, prints its name, and lets this item continue without those findings.
Accept puts every remaining finding of the latest review in Known issues as a follow-up with
the owner's reason. Close carries on without checking whether code or the default branch changed
since that review. Close still requires green checks; later work needs another review.
A stop that asks the owner needs a recorded choice with forge close --resolve.
A merge of the default branch or a clean review does not clear it. Close repeats the question.
Land runs at most one fix round, including across session handbacks. If findings, tests or checks
still need a worker, land stops.
For a user-facing change, before review round two, run the real flow once, without tests or stubs.
Add Live run: <what you ran> - <what you saw> to the commit's Functional check: paragraph.
Close copies that paragraph into the pull request and review. This request adds no check or refusal.
The stop rule: the coordinator lists each round's findings and asks the owner, whatever the scores.
The coordinator asks. The owner decides. The coordinator records the choice.
When a cold read or review loop stops and you must ask, ask the human the question it printed, in
its words, one item per question. It names the item and what it delivers, shows the open notes as one table ranked
by score (number, the problem and who it hits, Gain, Work, Harm, and what is proposed), and says
what each choice does; forge next prints it again for a stopped item. When a note
has no scores, as one saved before scores, the question lists the notes as plain lines instead.
Every update to the owner that lists notes or findings uses the same table, in the same order. The coordinator follows the bar's outcome and never re-scores a note: a fix round for a note at the bar, a disposition with the scores in its reason for one below it, and the stop rule above at a stop. Approval and merge steps stay the owner's.
When two rounds in a row leave close's tests failing or the same P0 open, forge work
stops the item. Close also stops a story part that grows past its line limit. Either prints a
ready-to-ask question: what the item delivers, what is stuck, what the worker tried, and the
choices. Ask the owner exactly that question. Record the choice with
forge close <item> --resolve <switch|same|narrow|split> --reason "<human's choice>", then
forge work <item>. Switch runs this item's next rounds on the other tool, as forge next shows;
every choice buys one more round before Forge asks again.
A cold read stops after round two when notes below P0 are still open, or when P0 notes are open
in two rounds in a row. This applies to stories, specs and decisions alike.
Ask the owner: "One more round, split or accept?" Do not read again
until the choice is recorded with
forge read <KEY or spec or decision> --resolve <accept|more|split> --reason "<human's choice>".
More permits one more read round. The same stop rule applies to that round.
Accept keeps the notes with the owner's reason and permits approval or confirmation. Split
the plan as agreed before reading again. Forge never starts a third round by itself.
For a review loop stopped by forge land, record the choice with the same forge close --resolve
command as a close stop.
When GitHub reports a clash during the check wait or refuses a merge because the branch is
behind or conflicting, forge merge retries close and merge once. A mergeable pull request
keeps its current head when the default branch has not moved. When GitHub refuses a branch
that fell behind during the merge, forge merge and forge land say so in one line,
run close again to merge the default branch and run the tests,
review and checks as close decides, then retry the merge. If that merge selects a different
Forge release, close finishes under that release before the original command continues.
A real conflict stops with close's existing resolution steps. Other GitHub refusals keep their
next action.
Once every story from a spec is done and its check date has passed, forge next lists the check.
Measure it, record it in a fix with forge spec measure <slug> --result "<result>", then ask the
human one question. Target met: "Stop here" (recommended) or "Next problem card". Target
missed: "Change the slice", "Remove it" or "Find out why". Adding features is never the default.
Ask which parts the client doesn't use; each becomes a removal story on the roadmap.
まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
Agent rules for Forge client apps with a chat agent or in-app assistant. Use before any agent, chat, voice or in-app assistant work: its shape, turn, memory, tools, output, safety, cost and tests.
日本語の概要は準備中です。原文の説明を表示しています。
The baseline every Forge client app gets without anyone asking. Use for any frontend or UI work in a Forge client repo, including screens, layout, navigation, forms, tables and prototype demos, before building or changing it.
日本語の概要は準備中です。原文の説明を表示しています。
Database rules for Forge client apps on Postgres. Use before adding or changing a table, column, index, constraint, migration, extension, list query, report or job table, in Prisma or SQLAlchemy.
日本語の概要は準備中です。原文の説明を表示しています。
Start a named Remote Control Claude Code session in a chosen checkout for an action the human must take from the Claude mobile app. Stories in every Forge repo can be approved from the one main chat; use this when another action needs its own session.
日本語の概要は準備中です。原文の説明を表示しています。
Writes and rewrites text in Simplified Technical English (ASD-STE100), a controlled language for clear technical documentation. Use when the user asks for STE, Simplified Technical English, controlled language, or plain technical writing, and when the user asks to write, rewrite, review, or check technical documentation, procedures, manuals, instructions, warnings, or reports.
日本語の概要は準備中です。原文の説明を表示しています。
Use whenever writing, changing, reviewing, or auditing tests. Gates new and changed tests and guides focused audits of low-value, implementation-coupled, or duplicative coverage and the test-only production seams it demands.
日本語の概要は準備中です。原文の説明を表示しています。