agentleFS
ShipTodayShipToday/forge-plugin-cursor/skills/forge-autopilot/SKILL.md

forge-autopilot

Skill0 starsChanged 5 days agoMITView on GitHub

Routes a request to Forge by ShipToday — ONLY when the user asks for Forge by name. Invoke this skill when the user's current message contains "@forge", "forge", "@shiptoday" or "shiptoday" (any case) and asks Forge to do something: plan, define, implement, fix, review, estimate, ship, check status, or map architecture. Also invoke when a Forge hook directive (FORGE ROUTING, FORGE OBSERVATION, FORGE CHECKPOINT) explicitly tells you to. Do NOT invoke for any message that does not name Forge — however much it looks like product or engineering work, and even when it contains a tracked work item key such as "PROJ-123": handle it normally. If the mention is ambiguous (for example "we deploy with Laravel Forge"), ask whether the user meant Forge before invoking.

2 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 2

    1. tonmoy007/forge-plugins★ 2same name
    2. tusharpandey13/forge★ 1same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository2 other files it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

53 rules. About 0 are common, 21 are distinctive, and 32 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈21

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 32

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Before calling any Forge tool, build the connected_tools array by checking which MCP tools are available in the current session:

    line 31
  2. Very specific:

    Only include connectors you can verify.

    line 48
  3. Distinctive:

    When in doubt, include it — over-declaring a relevant skill is harmless.

    line 64
  4. Very specific:

    Do NOT include skills unrelated to product/SDLC work (e.g.

    line 66
  5. Very specific:

    If no relevant local skills are found, omit the local_skills parameter entirely.

    line 76
  6. Very specific:

    When a current checkout is available, read git remote get-url origin (or reuse the remote already observed for this request) and send it as …

    line 80
  7. Distinctive:

    If there is no checkout, no origin, or the read is unavailable, omit the field.

    line 86
  8. Very specific:

    If the user explicitly says to run directly or not delegate, their instruction wins: include delegation_preference: { choice: "direct", …

    line 107
  9. Distinctive:

    Prefer a compatible blocking control.

    line 131
  10. Distinctive:

    Whether the user asked is your call: No hook reads their words to route, approve or block a start.

    line 180
  11. Very specific:

    Do NOT pass an explicit workflow parameter on the initial call and do NOT try to route to a server-side skill.

    line 187
  12. Distinctive:

    If the request names no outcome and no lifecycle verb (for example "help me with the roadmap"), do not match yet: ask one question about …

    line 191
  13. Distinctive:

    If multiple catalog workflows genuinely fit, present only those, always with a final "None of these fit" option — a user handed the wrong …

    line 203
  14. Very specific:

    Never invent a workflow, expose a server-side skill id as an option, or set classification_complete: true without an explicit workflow — …

    line 215
  15. Very specific:

    Pages: When the line says page 1 of N, the reply lists that page only.

    line 230
  16. Very specific:

    A reply that did not arrive whole: If you see fewer workflows than the Catalog line states, no end line, or any part of the reply was cut …

    line 242
  17. Very specific:

    If they align, re-call forge__start_workflow with the same arguments plus the returned admission_token and start_confirmed: true.

    line 260
  18. Very specific:

    If they do not align, do not confirm and do not call forge__abandon_workflow — no workflow has started.

    line 262
  19. Very specific:

    Never set start_confirmed: true without the server-issued admission_token from the immediately preceding proposal.

    line 267
  20. Distinctive:

    When the proposal is an approach Forge worked out for the request ("How Forge will approach this"), show it to the person exactly as …

    line 269
  21. Very specific:

    Follow the returned instructions to present a tracking nudge to the user.

    line 308
  22. Very specific:

    Do NOT classify this as a build/bug/architecture request — it's a passive check.

    line 309
  23. Very specific:

    When a workflow returns Workflow complete., look at the final state_updates payload you sent.

    line 313
  24. Very specific:

    If follow_up is null or absent, do not chain.

    line 336
  25. Very specific:

    Do NOT start a workflow, do NOT classify this as a build/bug/architecture request, and do NOT surface anything to the user — it is a …

    line 356
  26. Very specific:

    After calling start_workflow, Forge returns step-by-step instructions.

    line 364
  27. Very specific:

    After completing each step, call forge__update_state with the results AND the step_token from the most recent response (see below)

    line 370
  28. Very specific:

    If Forge returns needsDisambiguation or needsIntentClassification, present options or pick a workflow per the returned instructions and …

    line 372
  29. Very specific:

    Layer 1 — CHECKPOINT enforcement: When the orchestrator returns a CHECKPOINT response from forge__update_state (a relayed-question skill is …

    line 381
  30. Very specific:

    Every step transition publishes a Tool Permissions: cat1, cat2, … line listing the categories the active step is meant to use.

    line 411
  31. Distinctive:

    If you receive a deny decision for a tool you genuinely need, the right move is to get the user's answer or the write plan's approval first …

    line 462
  32. Very specific:

    Every start_workflow and update_state response also includes a line:

    line 468
  33. Very specific:

    When you call forge__update_state, include the most recent token via state_updates.step_token: "<token>".

    line 474
  34. Distinctive:

    NOT rotate — re-use the same token until the workflow actually advances to a new step.

    line 482
  35. Very specific:

    If you delegate a step to a sub-agent, pass the current step's token into the sub-agent prompt verbatim — the sub-agent threads it through …

    line 495
  36. Distinctive:

    MUST return that response to you (the parent) VERBATIM.

    line 501
  37. Very specific:

    If both sentinels are present AND the opening sentinel declares bytes=N, compute the UTF-8 byte length of the body between them and compare …

    line 512
  38. Very specific:

    If both sentinels are present but bytes=N is absent (a common smaller-model paraphrase mode — the agent keeps the sentinel shape but drops …

    line 516
  39. Very specific:

    When the current FORGE_DISPLAY_VERBATIM event was already shown, make the recovery call with include_display: false.

    line 530
  40. Distinctive:

    Diagnostic phrasing: when this happens, describe it as a fetch ("the envelope isn't in the sub-agent's return — fetching canonical state") …

    line 539
  41. Very specific:

    If the workflow no longer applies — the user redirected to unrelated work, the classifier picked the wrong workflow, or scope changed …

    line 558
  42. Very specific:

    After abandoning, you may start a fresh workflow with forge__start_workflow or proceed without one.

    line 582
  43. Distinctive:

    Follow the instructions in the Model Routing block returned by Forge:

    line 607
  44. Very specific:

    Do not display workflow-state JSON, catalogs, routes, tokens, tool examples, question schemas, or FORGE_NEXT_STEP instructions merely …

    line 625
  45. Distinctive:

    balanced: - default reasoning model tier

    line 642
  46. Distinctive:

    If you already match the recommended tier, execute the instructions directly — no delegation needed.

    line 645
  47. Distinctive:

    When it comes out yes, three things matter:

    line 672
  48. Distinctive:

    Reuse the reviewer, never the author: Do not resume an agent that helped build the thing.

    line 686
  49. Distinctive:

    When you cannot spawn one, run it inline and label it: *"Reviewed on my own context — this is a self-review."* A self-review is a fine …

    line 695
  50. Distinctive:

    Follow the per-step Worth-it check.

    line 727
  51. Distinctive:

    When a read-only / planning mode is active AND a Forge workflow is requested,

    line 778
  52. Distinctive:

    Do NOT execute those writes while the read-only mode is active.

    line 790
  53. Distinctive:

    Anti-pattern to avoid: do NOT abandon the Forge workflow mid-step because a read-only mode is active.

    line 802

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Forge Autopilot

You are routing requests to Forge via the forge MCP server. Forge runs only when the user asks for it by name — see the Trigger rule in Step 2. A request that does not name Forge gets a normal response, however SDLC-shaped it is.

Forge's workflow catalog lives on the server side and is fully data-driven. You don't need to know which workflows exist — forge__start_workflow will return a classifier prompt listing all available workflows (Forge defaults plus any org-specific workflows configured for the current user) when it needs the client AI to choose. Just call it and follow the instructions.

Step 1: Detect connected tools

Before calling any Forge tool, build the connected_tools array by checking which MCP tools are available in the current session:

ConnectorLook for these tool names
jirasearchJiraIssuesUsingJql, createJiraIssue, updateJiraIssue
linearsave_issue, save_comment, list_issue_statuses
githubGitHub MCP tools: search_issues, add_issue_comment, search_code, get_file_contents, list_pull_requests — or the gh CLI installed and authenticated
slackslack_send_message, slack_search_users, slack_search_channels
confluencesearchConfluenceUsingCql, getConfluencePage
notionnotion-search, notion-fetch, notion-create-pages
google_drivenative integration — include only if connected
gmailnative integration — include only if connected
granolasearch_meetings, get_meeting_transcript
figmaget_design_context, get_screenshot, get_metadata
local_codefilesystem/shell access (always include in coding environments)

Only include connectors you can verify. Always include local_code when you have filesystem access. The forge__start_workflow tool description carries the server's full list of signals per connector; this table is a subset of it.

Step 1b: Detect local skills

Build the local_skills array by checking your available skills, rules, or slash commands. Include every skill relevant to product development or the software development lifecycle — anything a Forge workflow step could draw on, such as brainstorming, planning, requirements, estimation, architecture analysis, code review, debugging, testing, or documentation. Relevance — not whether the skill is project-specific — is the test: a general-purpose skill still counts if it supports SDLC work.

A Forge workflow step can declare one of these as a required local skill, so under-declaring a relevant skill will block the step that depends on it. When in doubt, include it — over-declaring a relevant skill is harmless.

Do NOT include skills unrelated to product/SDLC work (e.g. presentation, document, or spreadsheet builders, image or media generators) or built-in platform commands (/help, /clear, etc.) — Forge workflows never use these.

SourceWhere to look
CursorSkills from installed plugins and rules loaded from .cursor/rules/ shown in your system context
CodexSkills listed in the current session or loaded from the project

For each skill found, include { "name": "<skill-name>", "description": "<brief description>" }. If no relevant local skills are found, omit the local_skills parameter entirely.

Current repository

When a current checkout is available, read git remote get-url origin (or reuse the remote already observed for this request) and send it as repo_remote on every forge__start_workflow call. This applies to built-in workflows and worked-out approaches, including routing, team selection, admission confirmation and follow-up calls. Preserve it on every re-call so the first practice read and the opening brief use the current repository. If there is no checkout, no origin, or the read is unavailable, omit the field; never guess it from a repository mentioned in a ticket or example.

Automatic admission

On every forge__start_workflow call, include:

client_capabilities: ["auto_admission"]

It tells Forge this client starts an approach Forge worked out as soon as the person has seen it, without a Start question first. Like the field below, it applies to every call form shown, which omit it for readability.

Codex delegation authorization

Invoking this applicable Forge skill authorizes Codex to use model-tier delegation for eligible workflow steps. On every forge__start_workflow call in Codex, include:

delegation_preference: { choice: "delegate", source: "skill" }

If the user explicitly says to run directly or not delegate, their instruction wins: include delegation_preference: { choice: "direct", source: "user" } instead and preserve it on every re-call. Applicable project instructions may be reported with source: "project". This is client-reported routing metadata; Forge does not treat it as server-side tool permission. Do not ask a separate model-delegation permission question. This field is a Codex authorization signal; it does not change Claude Code's existing direct Agent(...) model-routing behavior. This applies to every call form shown below, including catalog re-calls, admission confirmation, recommendations, passive observation, and follow_up chaining; those examples omit conditional host-only fields for readability.

Step 2: Route the request

Codex question lifetime

For fixed choices, prefer supported, permitted native UI. Forge may use a negotiated MCP form; after an answered RE-ENTRY, never ask the question again. Otherwise use request_user_input or request_user_input_async only when callable and permitted for this question's purpose in the current mode. Assess MCP forms and each host tool independently. In Default mode, a Plan-only blocking tool does not prohibit the async tool: check its own permissions before numbered text. An unexplained MCP rejection is not a policy-wide denial. Explicit policy prohibiting the question across routes still applies. Prefer a compatible blocking control. A permitted async picker may be used once; its string options carry exact labels, so show descriptions and full approval material in prose before opening it. Respect each tool's actual schema: blocking input accepts 2–3 options; that limit does not apply to every native control. Do not remove choices to make them fit.

An acknowledgment such as accepted:true records submitted delivery only, with no answer. Retain the pending question ID, step token and option keys; wait for the actual user selection or explicit typed reply before dependent work. The async picker can close at turn end or timeout: show the same numbered recovery choices before ending the turn unless the user has already answered. Never re-open it automatically, force Plan mode, probe forbidden tools, or keep it alive with sleeps or polling. A resolved UI event can be cleanup, not an answer. Do not bypass host policy rejection through another tool. When native input is unavailable or prohibited, use persistent numbered choices. Other hosts keep their permitted native controls and existing wait protocol.

Trigger rule — check before calling Forge

Forge starts only when the user's current message asks for it by name: it contains @forge, forge, @shiptoday or shiptoday (any case) with a clear request for Forge. Nothing else starts a workflow. Without the keyword, handle the request normally, even when it is SDLC-shaped (plan, review, fix, ship, estimate) and even when it names a tracked work item key such as PROJ-123. That includes when the user is:

  • implementing specific changes already requested or reviewed in this session;
  • resolving a merge conflict or applying known review comments;
  • editing known files, adding already-specified tests, or fixing an already- diagnosed local defect; or
  • committing, pushing, creating, or updating a pull request for work already in progress.

A keyword in an earlier message does not carry over to a new request: judge each message on its own. If the mention is ambiguous — "we deploy with Laravel Forge", "forge ahead with the plan" — ask the user whether they meant Forge before calling anything, as a yes/no choice in the host's question UI when one is available, and start nothing on the mention alone. Once the user has said they did not mean Forge by ShipToday, do not ask again about the same kind of mention in this conversation. A message that tells you not to use Forge ("don't use Forge for this") is not a request for it.

Three things are not new requests, so they need no keyword: an answer to a question Forge asked, which continues the run already in progress; a follow_up the user chose when a workflow completed; and the hook-driven entries below (the session observer and its checkpoints), which start on a Forge hook directive, not on the user's words.

Whether the user asked is your call. No hook reads their words to route, approve or block a start.

For a request that names Forge, your default action is:

→ forge__start_workflow(feature_request, connected_tools, local_skills: <detected_skills>)

Do NOT pass an explicit workflow parameter on the initial call and do NOT try to route to a server-side skill. When intent selection is needed, Forge returns the enabled workflow catalog for this user and organization.

  • If the request names no outcome and no lifecycle verb (for example "help me with the roadmap"), do not match yet: ask one question about what should exist when the work is done, with options phrased as outcomes the catalog can deliver (never workflow ids), plus a final "None of these fit". Forge's returned instructions say, per caller, whether to add "Build a custom workflow" before it. Then classify the answer, and report the ask on the classified call as routing_ask: { asked: true, scope: "outcome", offered: [<the ids behind the outcomes you offered>] }.
  • A workflow fits only when it would deliver the named outcome, not feed into it — a near miss is a no-match, not a candidate. If one workflow clearly fits, re-call forge__start_workflow with that explicit catalog workflow id and classification_complete: true.
  • If multiple catalog workflows genuinely fit, present only those, always with a final "None of these fit" option — a user handed the wrong options must never be cornered into one. When Forge's instructions say the caller can author, add "Build a custom workflow" immediately before it and show at most two candidates (the widget holds four options). After they choose a candidate, re-call with that explicit workflow id, classification_complete: true, and routing_ask: { asked: true, scope: "catalog", offered: [<the ids you offered>] } — add authoring_offered: true when the build option was shown. If they pick "None of these fit" — or skip the question — treat the request as having no match and follow the instructions Forge returns; do not re-ask. If they pick "Build a custom workflow", take the authoring offer in Forge's instructions directly, carrying their words forward.
  • Never invent a workflow, expose a server-side skill id as an option, or set classification_complete: true without an explicit workflow — except when sending an approach Forge asked you to work out; that call never names a workflow.

The server-provided workflow catalog is the source of truth; the client AI owns the contextual choice among those available workflows.

When the catalog is paged, shortened or incomplete

Forge keeps a routing reply small enough for the host to show it whole, so a large catalog can arrive in pieces. Every catalog opens with a **Catalog** line — how many workflows it holds, whether all of them are listed or which page this is, and a version — and closes with an end line.

  • Pages. When the line says page 1 of N, the reply lists that page only. Route to a workflow on it when it clearly delivers what was asked. Before deciding that nothing fits, or choosing between candidates, read the rest: re-call forge__start_workflow with the same arguments plus catalog_page: 2, then each page after it. If a page reports a different version, the catalog changed while you were reading: start again at page 1.
  • Shortened entries. An entry ending in "…" was trimmed to fit. Before choosing between workflows that look close, or ruling one out on a trimmed entry, re-call with the same arguments plus catalog_details: [<ids>] (up to 8) for their full routing hints. Hints come back whole; when they are too long for one reply the answer says which page it is, and you read on with the same catalog_details plus catalog_page.
  • A reply that did not arrive whole. If you see fewer workflows than the **Catalog** line states, no end line, or any part of the reply was cut off or replaced by a notice (a truncation marker, a "saved to a file" pointer), the catalog you hold is incomplete. Do not tell the user no workflow exists, do not work out an approach and do not offer to build a workflow from it: re-call with the same arguments plus catalog_page: 1 and read every page first.

Neither argument starts anything. Both list only workflows this user can route to, so a workflow missing from every page is not available here.

Admission proposal — validate before activation

A post-classification call returns a server-resolved workflow proposal before it creates an active conversation. Compare its entry step, missing inputs, configured path, and potential side effects with the user's full conversation and current phase:

  • If they align, re-call forge__start_workflow with the same arguments plus the returned admission_token and start_confirmed: true.
  • If they do not align, do not confirm and do not call forge__abandon_workflow — no workflow has started. Choose another workflow only when it is an exact catalog match. If none matches, continue normally when this is coding continuation, otherwise explain that no available Forge workflow fits.
  • Never set start_confirmed: true without the server-issued admission_token from the immediately preceding proposal.
  • When the proposal is an approach Forge worked out for the request ("How Forge will approach this"), show it to the person exactly as written and follow the confirmation it returns. This client reports automatic admission, so Forge tells you to start it in the same turn, with no Start question; the person can stop it, or change its steps, at any time. If the confirmation asks you to put Start to the person instead, do that and never confirm it yourself.

Exception 1 — Help / recommendation request

"forge, what should I do with PROJ-123?", "@forge help with PROJ-123", "forge, where do I start?"

→ forge__start_workflow(feature_request, connected_tools, recommendation: true, local_skills: <detected_skills>)

Exception 2 — Session observer (passive tracking)

Triggered by the stop-observer.cjs stop hook — the auto-submitted follow-up turn's input contains "observe session" or "observe_session workflow". A hook directive, not the user's words, starts it, so it needs no Forge keyword. The user can also ask for it: a message that asks Forge to track, or resume tracking, this session ("@forge resume tracking this session") takes this route too — not the catalog route in Step 2, which cannot reach the observer.

→ forge__start_workflow(feature_request: "Passive session observation", connected_tools, workflow: "observe_session", local_skills: <detected_skills>)

The observe_session workflow is a single-step workflow that wraps the session observer. It is marked auto_classify: false server-side so it is invisible to the intent classifier — the only valid entry point is this explicit workflow: "observe_session" argument.

Client authority stops at eligibility. The hook and client AI may decide only whether the conversation contains project-related SDLC work. If it does, start observe_session; if it does not, skip it. Do not choose, infer, or encode a tracking outcome on the user's behalf, and do not replace an eligible observation with a client-only defer/sleep disposition. Link, create, ad-hoc logging, snooze, dismissal, and workflow follow-up are user choices made through the observer's relayed needs_input questions.

Follow the returned instructions to present a tracking nudge to the user. Do NOT classify this as a build/bug/architecture request — it's a passive check.

After any workflow completes — read follow_up

When a workflow returns Workflow complete., look at the final state_updates payload you sent. If it includes a non-null follow_up object, you MUST chain to that workflow before resuming the user's original request. Status reports and session-observer outcomes both use this structured handoff contract.

forge__start_workflow(
  feature_request: <follow_up.feature_request>,
  connected_tools: <same array as before>,
  epic_key: <follow_up.epic_key>,
  workflow: <follow_up.workflow>,
  classification_complete: <follow_up.classification_complete ?? true>,
  pre_forge_context: <follow_up.pre_forge_context>,
  local_skills: <detected_skills>
)

The four-field structured shape keeps the bound work item key clean: epic_key is passed as a structured parameter so any PROJ-NNN-shaped strings inside pre_forge_context cannot hijack the binding via the embedded-key regex.

If follow_up is null or absent, do not chain. Continue the conversation normally.

Common failure mode to avoid: treating "Workflow complete" as "the workflow is done — go back to the user's original ask". A selected follow-up is an explicit user route; silently ignoring it leaves that choice unhonored. Always read follow_up before resuming.

Exception 3 — Session checkpoint (passive time tracking)

Triggered by the stop-observer.cjs stop hook for an already-tracked (logged / linked) session — input contains "session checkpoint" and spells out a complete forge__update_state call (conversation_id, completed_step, state_updates).

→ Call forge__update_state exactly as the directive specifies — pass the conversation_id and state_updates verbatim. The conversation_id is the original observe_session conversation; the server records the elapsed time as a silent audit event.

Do NOT start a workflow, do NOT classify this as a build/bug/architecture request, and do NOT surface anything to the user — it is a passive, silent check. After the call, continue normally.

Step 3: Follow the workflow

Pass the user's request as feature_request (strip pleasantries, keep substance).

After calling start_workflow, Forge returns step-by-step instructions. Follow them:

  1. Execute each step as instructed
  2. Follow the returned question-delivery instructions. Forge may deliver a native MCP form and return the answered step directly; do not ask the same question again after RE-ENTRY. Otherwise, on Cursor, ask in your reply and end your turn: render bounded choices as a numbered list (1., 2., 3....) and tell the user to enter one number; for multi-select, ask for comma-separated numbers. Do not use AskQuestion for a Forge decision — Forge accepts an answer only after the user's next message, so an answer gathered through AskQuestion is refused. Keep genuinely open-ended prompts as free text.
  3. A tool submission acknowledgment means submitted, not displayed or answered. Wait for the actual user answer before dependent work. Preserve the question ID, step token, option order and labels. Post the actual answer through the returned user_answer path. Never convert dismissal, failure, empty input, an invalid/out-of-range number, or a preselected default into TBD or approval. Keep the decision identifiable to the user. Read-only recovery does not re-present; use question_resume: true with the returned identity on an explicit resume.
  4. After completing each step, call forge__update_state with the results AND the step_token from the most recent response (see below)
  5. If Forge returns needsDisambiguation or needsIntentClassification, present options or pick a workflow per the returned instructions and re-call

Workflow guard — what is enforced

Forge installs a preToolUse hook (workflow-guard.cjs) that denies tool calls in two situations: while a question is waiting for the user, and while a write is waiting for the user's approval. Two layers:

Layer 1 — CHECKPOINT enforcement. When the orchestrator returns a **CHECKPOINT** response from forge__update_state (a relayed-question skill is awaiting user input), the hook holds write tools — the same ones the write lock holds (tracker, docs and messaging writes, code-host connector writes, file writes and deletions) — until the user has answered. Everything else passes:

  • a direct question in your reply — relay the pending question (numbered choices), then wait for the user's next message; on Cursor that message is how Forge knows the user answered
  • forge__update_state — advance with the user's answer
  • forge__abandon_workflow — exit when the workflow no longer applies (see below; it is not a way to end a run early)
  • Reads, such as filesystem reads and search, web fetch and search, and read-only MCP tools
  • The host's own task-list, progress and coordination tools, such as ToolSearch, Skill, waiting tools and the host task tools. They do not authorize connector writes or workflow advancement.

The hook does not check shell commands, here or anywhere (see below). While a question is pending, the instructions still apply: wait for the user's answer, and use any tool or the shell only to ask, inspect or coordinate, never to act on the decision being asked.

Layer 2 — the write lock. A step set to Always asks that writes carries a **Write Lock**: on line until its write plan is approved. Until then the hook holds write tools (tracker, docs and messaging writes, code-host connector writes, file writes and deletions). Post the write plan, get it approved, then write.

Per-step tool_permissions — follow them; the hook does not enforce them. Every step transition publishes a **Tool Permissions**: cat1, cat2, … line listing the categories the active step is meant to use. Staying inside them is your job, the same as for shell. Categories are coarse:

CategoryTools
read_codefilesystem reads and search (always allowed regardless)
ask_userdirect user question or structured user-input tool
webweb fetch and web search tools
tracker_readlist_issues, get_issue, list_comments, search_threads, …
tracker_writesave_issue, create_issue, save_comment, update_issue, …
docs_readRead connected documents; this category grants no writes
docs_writeCreate or update connected documents. When the active step explicitly routes an approved document into the repository, use Write, Edit, or apply_patch to create or update that ONE canonical routed document only
messagingSlack send
calendar / design / meetingsPer-connector groups
conversation_artifacttask-owned .html/.svg backing file for an inline renderer; never a repository file
code_editcode-editing tools such as Write, Edit, or apply_patch, for application code and other repository edits beyond the narrow docs_write document scope
shellCommands that change or publish things (builds, tests, commits, pushes, PRs), plus the code-host connector writes (create_pull_request, merge_pull_request, push_files, …)

Concretely: a readiness check does not include code_edit or shell, so do not edit during it. A code-execution step includes both. A triage step that only reads the ticket includes tracker_read but not tracker_write — read the ticket's comments, but do not post to or rewrite the ticket.

A docs_write step without code_edit can save only the document the step explicitly routed and approved, at its resolved canonical location. Read nearby documents to follow the existing layout, then create or update that document; do not edit application source or configuration. This permission adds no shell or git rights: do not stage, commit, push, or change a pull request to deliver the document. A tracker pointer also requires tracker_write and its own declared write scope. Content approval and any required repository-destination choice still come before writing; a detected layout alone grants nothing.

Shell is not checked by the hook. Shell and WriteShellStdin always pass — a pending question and the write lock never look at a command. Following the step's permissions is your job here too: a step without shell may run read-only commands (git and gh reads, file listings, package audits) and nothing that changes or publishes anything; a gh issue write counts as tracker_write; under the write lock, run no command that publishes until the write plan is approved. Command examples in step instructions are illustrative — any equivalent read-only command is fine.

Anything denied gets an actionable reason that points at the three legitimate next moves: relay the user question, advance (forge__update_state), or abandon (forge__abandon_workflow — only when the workflow itself no longer applies). On Claude Code the guard uses the host's PreToolUse denial format. Other hosts may expose different hook contracts, and wrappers or unknown tools can limit enforcement. This is not a security boundary: forge__abandon_workflow is always allowed, and a host that wraps MCP calls may not expose every call to the hook.

If you receive a deny decision for a tool you genuinely need, the right move is to get the user's answer or the write plan's approval first — that is what the hook is waiting for.

Step token — pass it back on every update_state

Every start_workflow and update_state response also includes a line:

**Step Token**: `step_<uuid>` — include this in your next `forge__update_state` call

When you call forge__update_state, include the most recent token via state_updates.step_token: "<token>". The orchestrator validates it matches the conversation's current step — a mismatch means the conversation has already advanced (typically a sub-agent advanced it without your knowledge), and the call is rejected with an actionable error pointing you at forge__get_workflow_state for recovery.

For relayed-question CHECKPOINT and RE-ENTRY responses the token does NOT rotate — re-use the same token until the workflow actually advances to a new step. The token rotates on every real step advance.

Sub-agent relay — verify the envelope, fetch canonical state when absent

An agent in a separate client session does not inherit the parent's local question or write guard. Before that agent's first forge__update_state for the run, it must call forge__get_workflow_state with the conversation id and follow the returned question, token, and write lock. Reuse that agent's session for later steps when possible; recovery is needed once per new session, not after each step in the same session. If the child cannot recover the run, keep the workflow update in the parent's session.

If you delegate a step to a sub-agent, pass the current step's token into the sub-agent prompt verbatim — the sub-agent threads it through its own update_state call, using the current token from recovery if it differs. The orchestrator's response to that call (carrying the new step_token and the next step's instructions) is delivered to whoever made the MCP call: the sub-agent. The sub-agent MUST return that response to you (the parent) VERBATIM.

To detect a missing envelope mechanically rather than heuristically, the orchestrator wraps the next-step instructions in a <<<FORGE_NEXT_STEP token="…" bytes=N>>> … <<<END FORGE_NEXT_STEP>>> envelope. The parser accepts the envelope on sentinels + token; bytes=N is an optional integrity annotation. After every sub-agent return:

  1. Scan the return for the envelope. If either sentinel is missing — or the opening sentinel is restructured so token="…" no longer sits on it — the sub-agent didn't include a parseable envelope.
  2. If both sentinels are present AND the opening sentinel declares bytes=N, compute the UTF-8 byte length of the body between them and compare against N. Mismatch = the sub-agent paraphrased inside otherwise-correct sentinels.
  3. If both sentinels are present but bytes=N is absent (a common smaller-model paraphrase mode — the agent keeps the sentinel shape but drops the byte count as "boring metadata"), trust the envelope on sentinel + token alone. No fetch needed — the next-step body is good as-is.
  4. On a step-1 fail (missing/restructured sentinels) OR step-2 mismatch (declared bytes don't match), call forge__get_workflow_state(conversation_id: "<id>") to fetch the canonical step body and current step_token. This is the designed recovery channel — read-only, idempotent, and owner-checked. Findings the sub-agent put in display_text are preserved as a ## Findings block in the fetched response, so no analytical output is dropped — only the verbatim relay shortcut was skipped.

When the current FORGE_DISPLAY_VERBATIM event was already shown, make the recovery call with include_display: false; recovery must not re-announce an unchanged step. The response publishes Instruction Bytes before the body. If the host truncates the full response, do not repeat the same unbounded fetch: restart with instruction_chunk_bytes: 20000, instruction_offset_bytes: 0, and include_display: false; then follow each returned next_offset_bytes until complete=true. Read the chunks in order and execute the step only after the full instruction body has been recovered.

Diagnostic phrasing: when this happens, describe it as a fetch ("the envelope isn't in the sub-agent's return — fetching canonical state") rather than as a failure ("the relay was lost"). The findings layer is the system's designed answer to envelope-not-present, so the information path stayed intact even though the shortcut path didn't. This wording matters for the user reading your message — "lost" reads as a regression, "fetching" reads as a normal recovery.

A summarized or paraphrased return without the envelope leaves the parent with a stale token if it doesn't fall through to the state fetch — the new token lives ONLY in the orchestrator's response body, and your parent CANNOT see the sub-agent's tool results. The STEP BOUNDARY directive injected into delegated prompts repeats this requirement and names the envelope explicitly. This applies uniformly across Claude Code (Agent tool), Codex (spawn_agent), Cursor, and any other environment with sub-agent delegation.

Escape hatch — forge__abandon_workflow

If the workflow no longer applies — the user redirected to unrelated work, the classifier picked the wrong workflow, or scope changed mid-stream — call forge__abandon_workflow(conversation_id, reason) to cleanly close the conversation. This is the only correct way to exit a workflow without completing it.

  • Not for ending a run early. Workflows run straight through — there is no pause between steps. When the user asks to stop, call forge__update_state for the current step with state_updates: { stop_run: true, step_token: "<the current token>" }, even while a question is waiting for them. Forge ends the run with a recap of everything produced and the steps that did not run, and does not mark it abandoned. Deciding on your own that the remaining steps are unnecessary is not a reason to stop or abandon — that is the user's call.
  • Do NOT silently bypass the workflow by skipping forge__update_state calls and proceeding directly with implementation. Silent bypass leaves the audit trail blind to why the workflow stopped applying — the team loses signal about which workflows misroute and why.
  • The reason is required, must be at least 8 characters, and is recorded in the audit trail. Make it meaningful (e.g., "user redirected to fix-bug workflow", "scope changed — going direct on a 1-line change", "wrong workflow classified, restarting"). Don't write filler like "abandoning" or "no longer needed".
  • Idempotent: re-abandoning returns the original record. Safe to retry.
  • After abandoning, you may start a fresh workflow with forge__start_workflow or proceed without one. Subsequent forge__update_state calls against the abandoned conversation will be rejected.

Step 4: Respect model delegation rules

Forge responses include a **Model Routing** metadata line with the recommended model tier. You MUST check this line and delegate when your current model does not match the recommended tier.

How to read the routing signal

The response metadata contains a line like:

**Model Routing**: tier=balanced | model=gpt-6.1-terra | environment=codex | guidance=codex_model_map | complexity=medium | task=planning

The tier value tells you which capability tier to use. The optional model value is only exact when the guidance variant names a maintained model map for your current environment. If no model is present, use the tier language only: pick your fastest, balanced, or most capable available model.

How to delegate

Follow the instructions in the Model Routing block returned by Forge:

Routing signalWhat to do
guidance=claude_code_model_mapUse the concrete model parameter Forge provides.
guidance=codex_model_mapUse the provided Codex model hint when your Agent or model switch supports it; otherwise choose the same tier in Codex.
guidance=model_agnostic_tierDo not invent a model name. Choose your tool's available model that matches the tier.

A delegated sub-agent inherits your MCP tools and can call external connectors directly.

CRITICAL: Sub-agents execute ONE step only. The ---DELEGATE BELOW--- content already includes a step boundary directive. After the sub-agent returns, YOU (the parent) surface the user-facing findings before the next step or confirmation. Render designated display_text and FORGE_DISPLAY_VERBATIM bodies in full, without the sentinels. Also preserve complete user-facing deliverables explicitly required by the step, even when a legacy step has no display_text. Summarize other findings as useful prose. Do not display workflow-state JSON, catalogs, routes, tokens, tool examples, question schemas, or FORGE_NEXT_STEP instructions merely because they occur in a sub-agent return. Those are internal control data for you to consume. This is not a ban on JSON or code: preserve either when the user requested it or it is substantive review/approval material. Then interpret the next step yourself; do not expect a sub-agent to chain steps.

Common loophole to avoid: when a sub-agent's return bundles both its substantive findings AND state-advancement metadata (e.g. "advanced to step 3, here's the next-step instructions"), it is tempting to read the whole return as workflow plumbing and skip straight to the next sub-agent. Don't. The findings are user-facing; the state metadata is internal. Surface the findings first, every time.

Self-check: which tier are you?

  • fast - lightweight/low-cost model tier
  • balanced - default reasoning model tier
  • capable - strongest available reasoning model tier

If you already match the recommended tier, execute the instructions directly — no delegation needed. If you do NOT match, delegate or switch using the environment-specific guidance Forge returned — unless the step's Worth-it check flags the remaining work as a pre-computed replay (content already in workflow state, no new generation), in which case run it inline regardless of tier.

Independence: a different question from tier

Tier asks "is this model strong enough?". It does not ask "should the reviewer be someone who has already seen this work?" — and for a step whose job is to judge an artifact, that second question is often the one that decides quality. A reviewer who produced the work reads what they meant to write; a reviewer with no prior exposure reads what is actually there.

Each step's advisory carries an Independence check above its delegation rules. Settle it first, because the rules would answer it wrongly: "I'm already on the right tier" and "I already hold the context" both point at running inline, and on a review step holding the author's context is the disqualification, not the qualification.

The check is a test you apply to the step in front of you — Forge does not pre-label which steps are reviews, because your org's own workflows and skills count too. It also covers judging your own conclusions, not just your own code: confirming a root cause you hypothesised earlier in the run is the same failure mode, and a more expensive one, since the whole fix gets built on it.

When it comes out yes, three things matter:

  • Give away the judgment, keep the step. Hand the fault-finding to the fresh agent; keep the mechanical checks, the rendering, and — when the step ends in a relayed question — the question and the forge__update_state hand-off. Delegating such a step whole forces the sub-agent to relay the entire envelope back to you, which is the most fragile part of the contract. A split prompt is not the standard payload — see rule 4 below.
  • Check that "fresh" is actually fresh. On some hosts a spawned sub-agent inherits the parent conversation by default, so calling it fresh does not make it so — an agent holding your reasoning will confirm you, and it costs more than an isolated one. If your sub-agent tool has a context/history parameter, set it to inherit nothing. Forge's per-step advisory names the exact parameter where it knows it.
  • Reuse the reviewer, never the author. Do not resume an agent that helped build the thing. Do resume the independent reviewer you already spawned this run — it is still independent, and it saves re-reading the same diff on every review step. A run with three judgments over one diff should pay one cold read, not three.
  • Brief it with the artifact and the standard, never your conclusions, and surface what it found before you reconcile it. Knowing what you meant to write is not evidence that the code does it.

When you cannot spawn one, run it inline and label it: "Reviewed on my own context — this is a self-review." A self-review is a fine outcome; a self-review that reads as an independent one is not.

Rules

  1. Always check — if **Model Routing** is present, evaluate it before executing the step instructions
  2. Delegate both up and down — if the tier says "capable", use your strongest available model; if it says "fast", use your lightweight model
  3. Announce delegation — briefly tell the user before delegating (e.g., "Delegating to a balanced model for this step...")
  4. Pass the full prompt — when the WHOLE step goes over — everything below ---DELEGATE BELOW--- is the delegated prompt; include all of it. If you are splitting the step instead (handing over a judgment per the independence check, or a bounded read per the step's rule 5), do NOT forward the STEP BOUNDARY directive: that is what makes a sub-agent call forge__update_state and advance, which rotates the step_token out from under your own call for the same step. Send the artifact, the standard and the analysis portion only, and tell it to return findings as text and call no forge__ tool
  5. Everything ABOVE the delimiter stays with you — it is addressed to the parent, not the sub-agent. In particular, a <<<FORGE_DISPLAY_VERBATIM …>>> block above the delimiter is content for the user (the "Step N of M" progress marker): render it verbatim BEFORE you delegate, and never fold it into the delegated prompt. See "Must-display blocks" below
  6. Delegate when it pays for itself, not reflexively — for real work that's off your tier, delegating up buys better reasoning and down saves real cost. But each step's advisory carries a Worth-it check: when the remaining work is only replaying content already in workflow state (a pre-computed pending_* post, no new generation), run it inline on your current model — spawning a sub-agent for that just burns a round-trip. Follow the per-step Worth-it check; don't skip delegation merely because direct execution is easier

Must-display blocks

Forge marks content that is meant for the user — not for you — by wrapping it in a relay envelope:

> **Relay to the user** — render the block between the sentinels below ...

<<<FORGE_DISPLAY_VERBATIM id="position:step_<uuid>">>>
### Step 2 of 8: Discover AI SDLC
next: ... · then: ...

---
<<<END FORGE_DISPLAY_VERBATIM>>>

Rules:

  • Render what is between the sentinels, verbatim — never the sentinels themselves, and never a summary. It is the user's only view of where the run has got to.
  • Render it before anything else in that turn — before analysis, before delegating, before your next tool call.
  • It is always the parent's job. These blocks sit OUTSIDE the <<<FORGE_NEXT_STEP>>> envelope and above ---DELEGATE BELOW---, so a sub-agent never receives one as part of its prompt. If you ARE a sub-agent and one appears in a tool result you got, relay it to your parent unrendered along with the envelope — your parent is the one talking to the user.
  • Display ids are event identities. preflight identifies the once-per-run brief. position:step_<uuid> identifies one workflow step and remains stable across retries, read-only recovery, and question re-entry. Render an id the first time you see it. If the exact same id appears later and you already rendered its body in one of your own user-facing messages, consume it as a replay and do not render it again. A new id is always a new event.

On Cursor this is the only mechanism. Other Forge clients back this up with a hook that surfaces the block automatically; Cursor's postToolUse has no user-visible output channel, so if you do not render it, the user never sees where the run has got to.

Step 5: Coexist with planning / read-only modes

Some environments enter a planning or read-only mode for non-trivial work (for example, Cursor's Ask mode answers without editing, and some setups gate writes behind plan approval). In such a mode, non-readonly tool calls are restricted and you are expected to present a plan for the user to approve before any writes happen.

When a read-only / planning mode is active AND a Forge workflow is requested, both protocols apply — they are not in conflict:

  1. Routing still applies — call forge__start_workflow to fetch the right workflow. This is a read-only call to Forge; it has no side effects on the user's systems.
  2. Execute only the read-only operations from the workflow's instructions — typically the early "fetch context" steps that read from the project tracker, codebase, or documentation tools.
  3. Defer writes — surface every write the workflow would normally perform (status updates via save_issue, ticket comments, code edits, forge__update_state calls) as part of the plan you present to the user. Do NOT execute those writes while the read-only mode is active.
  4. After the mode exits (the user approves the plan), resume the workflow from where you paused — call forge__update_state to advance through the deferred steps in order until the workflow completes.

Why both protocols are compatible: a read-only mode constrains which tools you may call, not which workflows you may consider. Forge's routing (which workflow to use, what its steps look like) is informational at this stage. Writes are deferred, not skipped — the workflow completes normally once the mode releases you to act.

Anti-pattern to avoid: do NOT abandon the Forge workflow mid-step because a read-only mode is active. If you've called forge__start_workflow and read the step instructions, complete the read-only portions and present the deferred writes in your plan — do not pivot to a parallel investigation that ignores the workflow. Abandoning closes the run for good: the steps that had not run are recorded as not run, the audit trail records the abandonment, and nothing resumes it — the user has to start over.

What NOT to route

The line is the Trigger rule in Step 2, nothing else: route only a current message that asks Forge for something by name. Without that, handle the request normally — whatever it is about:

  • "Write a function that..." / "refactor this component" / "add a test for..."
  • "Read this file" / "explain this code" / "what does this error mean?"
  • "Commit my changes" / "push to main"
  • "Plan the release", "review this PR against the requirements", "break PROJ-123 into stories" — product-development work too, but not a request for Forge until the user names it
  • "Review this PR directly, without using Forge" — the user has said no

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.