@guidobuilds/forge-ai 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +19 -13
- package/artifacts/forge/forge.md +16 -4
- package/artifacts/forge-adversary/forge-adversary.md +2 -0
- package/artifacts/forge-grill/forge-grill.md +7 -1
- package/artifacts/forge-worker/forge-worker.md +63 -10
- package/artifacts/forge-worker-leaf/forge-worker-leaf.md +93 -0
- package/artifacts/using-forge/using-forge.md +56 -5
- package/dist/src/adapters/claude-known.js +1 -0
- package/dist/src/adapters/claude.js +10 -2
- package/dist/src/processor.js +12 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,31 @@ Versions prior to 0.3.0 are not reconstructed here; see git history for earlier
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.6.0] - 2026-07-05
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`forge-worker-leaf` agent** — terminal worker for bounded subgoal shards at `DISPATCH_DEPTH: 2`. No spawn tools (`task: deny` on OpenCode; no `Agent`/`task` on Claude/Grok). Installed alongside `forge-worker` on all platforms.
|
|
17
|
+
- **Worker sub-delegation** — `forge-worker` is now a coordinator that spawns `forge-worker-leaf` when context triggers fire (≥ 8 file reads, ≥ 6 searches, ≥ 20 tool calls, ≥ 5 files to build, or `DELEGATION: required`). Extended worker contract: `DISPATCH_DEPTH`, `WORKER_ROLE`, `SUB_RESULTS`, `DELEGATION_REQUESTS`, `NEXT_RECOMMENDED: sub-delegate`.
|
|
18
|
+
- **Pre-build approval gate** — for non-trivial work, the orchestrator presents an approval brief (conclusions, path/tasks, why) after inspect/design/plan (and `forge-grill` if it ran) and waits for the user's explicit approval before the first build dispatch. Trivial, explicit, low-risk requests remain self-approving — no artificial gate is created.
|
|
19
|
+
- **Per-feature `tasks[]` ledger** — each feature in `feature-list.json` can carry a `tasks[]` array (`id`, `title`, `workType`, `files`, `expectedOutcome`, `validation`, `state`) so any agent can resume mid-build knowing what a task was, what it touches, what "done" looks like, and how to validate it. `forge-worker` owns the schema.
|
|
20
|
+
- **Claude Code skill frontmatter** — canonical artifacts can now set `claude.when_to_use`, `claude.model`, and `claude.user-invocable` (Claude Code now supports `model` on skills, not just agents). Applied to the three artifacts that render as Claude Code skills: `forge` and `forge-grill` runs on `opus`, `forge` is the only one left user-invocable; `using-forge` run on `sonnet` and are set (along with `forge-grill`) `user-invocable: false` (Claude still loads them automatically; they no longer appear in the `/` menu or run as standalone commands).
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **`forge-worker` frontmatter** — Claude adds `Agent`; Grok adds `task`, `get_task_output`, `kill_task`; OpenCode adds `task: allow`.
|
|
25
|
+
- **README** — corrects outdated claim that Claude subagents cannot spawn subagents. Nested sub-agents are supported since Claude Code v2.1.172 (platform max 5 levels); Forge caps at depth 2 by cross-harness policy.
|
|
26
|
+
- **`using-forge`**, **`forge`**, **`forge-grill`**, **`forge-adversary`** — document two-tier worker model and Codex `DELEGATION_REQUESTS` fan-out fallback.
|
|
27
|
+
- **Route announcement** — for non-trivial work, the announcement is now followed by the pre-build approval brief; re-announcing mid-flight also re-triggers approval.
|
|
28
|
+
- **`forge-worker` plan/build modes** — plan populates `tasks[]`; build flips task `state` (`not_started -> active -> done`) as it works. Task `done` is distinct from feature `state`, which only a verify dispatch can move to `passing`.
|
|
29
|
+
- **`forge-adversary`** — cross-checks that each task's `validation` was actually satisfied, not just the feature's top-level `verification` command.
|
|
30
|
+
- **`progress.md` / `session-handoff.md` templates** — now reference the active `<feature-id>/<task-id>` so a resuming agent finds its place immediately.
|
|
31
|
+
- **`renderClaudeSkill`** — no longer drops the `model` field for Claude Code skills; it now validates it against known Claude models the same way `renderClaudeAgent` does.
|
|
32
|
+
|
|
33
|
+
### Migration from 0.5.0
|
|
34
|
+
|
|
35
|
+
- Run `npx @guidobuilds/forge-ai update` to install `forge-worker-leaf` and refresh coordinator artifacts. Requires Claude Code **v2.1.172+** for structural sub-delegation on Claude.
|
|
36
|
+
|
|
12
37
|
## [0.5.0] - 2026-06-20
|
|
13
38
|
|
|
14
39
|
### Added
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Forge is a personal project for working with code agents more reliably.
|
|
4
4
|
|
|
5
|
-
It started as a way to get better results from OpenCode, and now also supports Codex and
|
|
5
|
+
It started as a way to get better results from OpenCode, and now also supports Claude Code, Codex and Grok Build. The idea is to give agents a lightweight operating model for turning vague software requests into smaller, safer, verifiable changes without adding a heavy process around them.
|
|
6
6
|
|
|
7
7
|
Forge is experimental. It is shaped by hands-on use, and the workflow may change as I learn what works and what does not.
|
|
8
8
|
|
|
@@ -49,7 +49,7 @@ build -> verify
|
|
|
49
49
|
|
|
50
50
|
There is no mandatory lifecycle. Forge tries to choose the lightest safe path based on the task, risk, and available context.
|
|
51
51
|
|
|
52
|
-
Before delegating, the orchestrator states the chosen route to the user — the work types it plans to run, whether `forge-grill` runs before build, and why it is the lightest safe path for that request.
|
|
52
|
+
Before delegating, the orchestrator states the chosen route to the user — the work types it plans to run, whether `forge-grill` runs before build, and why it is the lightest safe path for that request. For non-trivial work, it then presents an approval brief — conclusions, planned tasks, why — and waits for an explicit go-ahead before the first build dispatch.
|
|
53
53
|
|
|
54
54
|
## Durable Context
|
|
55
55
|
|
|
@@ -68,10 +68,12 @@ Small, obvious changes do not need ceremony. The goal is to use durable artifact
|
|
|
68
68
|
|
|
69
69
|
For non-trivial or multi-session work, Forge keeps a small state model under `.forge/<feature-slug>/`, sized to the task:
|
|
70
70
|
|
|
71
|
-
- `feature-list.json` — the unit-of-work ledger. Each feature carries the triple `behavior` + `verification` (a runnable command) + `state` (`not_started | active | blocked | passing`).
|
|
71
|
+
- `feature-list.json` — the unit-of-work ledger. Each feature carries the triple `behavior` + `verification` (a runnable command) + `state` (`not_started | active | blocked | passing`), plus a `tasks[]` execution ledger (title, files, expected outcome, validation, state) so any agent can resume mid-build.
|
|
72
72
|
- `verification.md` — recorded verification evidence: the command, its output, and a pass/fail verdict.
|
|
73
73
|
- `progress.md` / `session-handoff.md` — session continuity and handoff, written when work spans sessions or blocks.
|
|
74
74
|
|
|
75
|
+
Before build starts on non-trivial work, Forge presents an approval brief — conclusions, the planned tasks, and why — and waits for an explicit go-ahead; a finished plan does not authorize build by itself.
|
|
76
|
+
|
|
75
77
|
Two rules make "done" mean done:
|
|
76
78
|
|
|
77
79
|
- **Definition of Done.** A feature only reaches `passing` once its verification command was actually run and the evidence is recorded in `verification.md`. No feature is marked done on assertion alone.
|
|
@@ -130,10 +132,11 @@ Forge installs the **same operating model** on every agent, but **how you invoke
|
|
|
130
132
|
|
|
131
133
|
### The pieces
|
|
132
134
|
|
|
133
|
-
Forge is one orchestrator, a
|
|
135
|
+
Forge is one orchestrator, a two-tier worker model, and a dedicated adversary, with two supporting skills:
|
|
134
136
|
|
|
135
137
|
- **`forge`** — the orchestrator. It talks to you, decides how much process a task needs, and delegates the real work. It does not edit code itself.
|
|
136
|
-
- **`forge-worker`** — the worker. It
|
|
138
|
+
- **`forge-worker`** — the coordinator worker. It executes bounded subgoals and spawns `forge-worker-leaf` when context would grow too large (~100k-token peak).
|
|
139
|
+
- **`forge-worker-leaf`** — the terminal worker. It runs one bounded shard with no sub-delegation.
|
|
137
140
|
- **`forge-adversary`** — the breaker. After a build, the orchestrator dispatches it to *try to break* the work — logically and technically (logic/requirements, runtime, security, performance). It gates the Definition of Done: a confirmed, reproducible break keeps the feature out of `passing`. It complements `forge-grill`, which grills plans *before* building.
|
|
138
141
|
- **`using-forge`** — the shared operating-model skill the orchestrator follows.
|
|
139
142
|
- **`forge-grill`** — an orchestrator mode for stress-testing a plan or design before building. The orchestrator invokes it proactively before non-trivial or risk-bearing builds; also available as `/forge-grill` for manual use.
|
|
@@ -144,22 +147,24 @@ What changes per platform is the **kind** each piece is installed as, and theref
|
|
|
144
147
|
|
|
145
148
|
| Piece | Installed as | How you invoke it |
|
|
146
149
|
|---|---|---|
|
|
147
|
-
| `forge` | skill | type `/forge` in the prompt |
|
|
148
|
-
| `forge-grill` | skill |
|
|
149
|
-
| `using-forge` | skill
|
|
150
|
-
| `forge-worker` | subagent |
|
|
150
|
+
| `forge` | skill (`model: opus`) | type `/forge` in the prompt — the only Forge skill you invoke directly |
|
|
151
|
+
| `forge-grill` | skill (`model: sonnet`, not user-invocable) | loaded automatically by `forge` before non-trivial or risk-bearing builds |
|
|
152
|
+
| `using-forge` | skill (`model: sonnet`, not user-invocable) | loaded automatically by `forge` before routing work |
|
|
153
|
+
| `forge-worker` | subagent | coordinator; main thread delegates via `Agent` (or legacy `Task`) |
|
|
154
|
+
| `forge-worker-leaf` | subagent | terminal shard; spawned by `forge-worker` (or orchestrator on Codex) |
|
|
151
155
|
| `forge-adversary` | subagent | the orchestrator delegates to it after build to gate risk-bearing work |
|
|
152
156
|
|
|
153
|
-
Start a session by typing **`/forge`**. That loads the orchestrator role into your main Claude Code thread, which
|
|
157
|
+
Start a session by typing **`/forge`**. That loads the orchestrator role into your main Claude Code thread, which delegates each bounded task to `forge-worker`, which may spawn `forge-worker-leaf` for heavy inspect/build shards. Requires **Claude Code v2.1.172+** for nested sub-agents. `forge-grill` and `using-forge` are marked `user-invocable: false`: Claude still loads and runs them as part of `forge`'s routing, but they no longer appear in the `/` menu or run as standalone commands — `forge` is the single entry point.
|
|
154
158
|
|
|
155
|
-
> Why a skill and not an agent on Claude?
|
|
159
|
+
> Why a skill and not an agent on Claude? The main thread retains `Agent`/`Task` and can delegate. A skill injects orchestrator behavior without replacing the main agent. The trade-off: "delegate, never do worker work inline" is followed by instruction at the orchestrator layer, not by tool restrictions — but `forge-worker` **can** structurally spawn leaves when given `Agent` in its tool list.
|
|
156
160
|
|
|
157
161
|
### OpenCode
|
|
158
162
|
|
|
159
163
|
| Piece | Installed as | How you invoke it |
|
|
160
164
|
|---|---|---|
|
|
161
165
|
| `forge` | primary agent | switch your active agent to `forge` |
|
|
162
|
-
| `forge-worker` | subagent |
|
|
166
|
+
| `forge-worker` | subagent | coordinator; `forge` delegates with `task: allow` |
|
|
167
|
+
| `forge-worker-leaf` | subagent | terminal shard; spawned by coordinator (`task: deny`) |
|
|
163
168
|
| `forge-adversary` | subagent | the `forge` agent delegates to it to gate risk-bearing work after build |
|
|
164
169
|
| `using-forge`, `forge-grill` | skills | loaded by the agent as needed |
|
|
165
170
|
|
|
@@ -183,7 +188,8 @@ Codex support is the most partial of the three: Forge writes the agent `.toml` f
|
|
|
183
188
|
| `forge` | skill | type `/forge` in the prompt |
|
|
184
189
|
| `forge-grill` | skill | type `/forge-grill` |
|
|
185
190
|
| `using-forge` | skill | `/using-forge` (usually pulled in by `/forge`) |
|
|
186
|
-
| `forge-worker` | subagent |
|
|
191
|
+
| `forge-worker` | subagent | coordinator; main thread delegates via `task` |
|
|
192
|
+
| `forge-worker-leaf` | subagent | terminal shard; spawned by coordinator |
|
|
187
193
|
| `forge-adversary` | subagent | the orchestrator delegates to it after build to gate risk-bearing work |
|
|
188
194
|
|
|
189
195
|
Start a session by typing **`/forge`**. Like Claude Code, the orchestrator runs as a skill in the main Grok session, which then delegates bounded work to the `forge-worker` subagent. Grok uses its own tool IDs (`run_terminal_cmd`, `grep_search`, `search_replace`, etc.) — the installer translates the worker's toolset automatically.
|
package/artifacts/forge/forge.md
CHANGED
|
@@ -4,6 +4,8 @@ description: Forge orchestrator with dynamic runtime routing and a single worker
|
|
|
4
4
|
kind: agent
|
|
5
5
|
claude:
|
|
6
6
|
kind: skill
|
|
7
|
+
model: opus
|
|
8
|
+
when_to_use: Use for any development or operational task in this repo — build a feature, fix a bug, investigate code, plan work, or verify a change. This is the default entry point; invoke explicitly with /forge or let Claude select it automatically for repo work.
|
|
7
9
|
grok:
|
|
8
10
|
kind: skill
|
|
9
11
|
opencode:
|
|
@@ -41,20 +43,24 @@ The `using-forge` skill owns runtime routing, operating principles, approval heu
|
|
|
41
43
|
- Choose the lightest safe routing permitted by the skill.
|
|
42
44
|
- Before the first dispatch, state the chosen route to the user (see `using-forge`: Route announcement).
|
|
43
45
|
- Run `forge-grill` proactively before building non-trivial or risk-bearing work; do not wait for the user to ask (see `using-forge`: Routing rules).
|
|
46
|
+
- For non-trivial work, present the pre-build approval brief (conclusions, path/tasks, why) and wait for the user's explicit approval before the first build dispatch; a finished plan does not by itself authorize build (see `using-forge`: Approval heuristics).
|
|
44
47
|
- Enforce the Forge worker contract strictly.
|
|
45
48
|
- Assign an effort level per dispatch and delegate by size (see `using-forge`: Effort routing, Routing rules).
|
|
46
49
|
|
|
47
50
|
## Worker model
|
|
48
|
-
- `forge-worker` is the
|
|
49
|
-
- `forge-
|
|
51
|
+
- `forge-worker` is the coordinator worker; route all build and operational work to it at `DISPATCH_DEPTH: 1`.
|
|
52
|
+
- `forge-worker-leaf` is the terminal worker for bounded shards at `DISPATCH_DEPTH: 2`; coordinators spawn it — or you fan out leaves when a coordinator returns `DELEGATION_REQUESTS` (Codex).
|
|
53
|
+
- `forge-adversary` is a dedicated adversarial verification agent: dispatch it as the Definition-of-Done gate for risk-bearing work to break the build before it can reach `passing`. Never sub-delegate verify or adversary work.
|
|
50
54
|
- You may launch one worker instance for a bounded task.
|
|
51
55
|
- You may launch multiple `forge-worker` instances in sequence when one result should shape the next delegation.
|
|
52
56
|
- You may launch multiple `forge-worker` instances in parallel when subgoals are sufficiently independent.
|
|
53
57
|
- Keep each worker invocation narrowly scoped so multiple instances do not collide on the same ownership or files unless deliberate.
|
|
58
|
+
- Tag heavy dispatches with `DELEGATION: allowed|required|forbidden`. Default trivial work to `forbidden`.
|
|
54
59
|
|
|
55
60
|
## State model
|
|
56
61
|
- Size the state model to the work. Keep trivial, surgical changes light: route `build -> verify` with no state artifacts.
|
|
57
62
|
- For non-trivial or multi-session work, route through the `.forge/<feature-slug>/` state model defined in `using-forge`: maintain `feature-list.json` (behavior + verification + state) and persist `progress.md` / `session-handoff.md` when work spans sessions or blocks.
|
|
63
|
+
- Non-trivial features carry a `tasks[]` ledger (title, files, expected outcome, validation, state) inside `feature-list.json` so any agent can resume mid-build; the builder flips task state as it works, but only verify flips a feature to `passing`.
|
|
58
64
|
- A feature reaches `passing` only via recorded verification evidence (the Definition of Done in `using-forge`).
|
|
59
65
|
- For non-trivial work, dispatch a separate verify run; never accept a builder's self-certified `passing`. Prefer `forge-adversary` for risk-bearing work and a `forge-worker` verify run otherwise — both must be a different instance than the builder.
|
|
60
66
|
- Read `.forge/repo-facts.md` and `.forge/lessons.md` when present, and have the verify dispatch flush lessons and update `.forge/index.md` at closure (see `using-forge`).
|
|
@@ -66,18 +72,24 @@ Each worker response must include:
|
|
|
66
72
|
STATUS: success|partial|blocked
|
|
67
73
|
WORK_TYPE: inspect|design|plan|build|operate|verify|mixed
|
|
68
74
|
FEATURE_SLUG: <kebab-case>
|
|
75
|
+
DISPATCH_DEPTH: 0|1|2
|
|
76
|
+
WORKER_ROLE: coordinator|leaf
|
|
69
77
|
ARTIFACTS:
|
|
70
78
|
- <path or None>
|
|
71
79
|
SUMMARY:
|
|
72
80
|
- <point>
|
|
73
|
-
|
|
81
|
+
SUB_RESULTS:
|
|
82
|
+
- task_id: <id> | status: success|partial|blocked | work_type: <type> | summary: <one line>
|
|
83
|
+
DELEGATION_REQUESTS:
|
|
84
|
+
- task_id: <id> | work_type: <type> | role: leaf | parallel: true|false | subgoal: <bounded> | files_hint: <paths or None>
|
|
85
|
+
NEXT_RECOMMENDED: inspect|design|plan|build|operate|verify|sub-delegate|ask-user|none
|
|
74
86
|
RISKS:
|
|
75
87
|
- <risk or None>
|
|
76
88
|
QUESTIONS:
|
|
77
89
|
1) <question>
|
|
78
90
|
```
|
|
79
91
|
|
|
80
|
-
`QUESTIONS` appears only when `STATUS: blocked`.
|
|
92
|
+
`QUESTIONS` appears only when `STATUS: blocked`. On `DELEGATION_REQUESTS`, fan out `forge-worker-leaf` dispatches (Codex fallback). Trust coordinator `SUB_RESULTS` unless `partial` or `blocked`.
|
|
81
93
|
|
|
82
94
|
If output is malformed:
|
|
83
95
|
1) request one reformat retry with same task_id
|
|
@@ -49,6 +49,7 @@ When state-model files exist, read them before acting and treat `feature-list.js
|
|
|
49
49
|
## Core rules
|
|
50
50
|
|
|
51
51
|
- **Independence**: you are a different instance than the builder. Never accept a self-certified `passing`.
|
|
52
|
+
- **No sub-delegation**: run in a single skeptical context; never spawn sub-agents.
|
|
52
53
|
- **Attack, do not repair**: you may write reproductions (failing tests, fuzz scripts, payloads) and state files, but you must NOT edit the implementation under test. Surface the breakage and leave the fix to a build dispatch.
|
|
53
54
|
- **Evidence over assertion**: every claimed break must be reproducible — a command plus the observed failure — and recorded in `verification.md`. No break is real on assertion alone.
|
|
54
55
|
- **Strict judging**: a break counts only if it violates a stated requirement or an invariant a reasonable user expects. Separate real defects from style nits and speculation.
|
|
@@ -85,6 +86,7 @@ In scope only when the work has a load or scale dimension. Probe algorithmic com
|
|
|
85
86
|
You are the Definition-of-Done gate for the targeted feature(s), per the rules in `using-forge`.
|
|
86
87
|
|
|
87
88
|
- For each targeted feature in `feature-list.json`, run its `verification` command AND your adversarial attacks.
|
|
89
|
+
- Cross-check that each task's `validation` for the targeted feature was actually satisfied, not just the top-level `verification` command — a task marked `done` with unmet `validation` is a break; record it and flip the feature to `blocked`.
|
|
88
90
|
- A confirmed, reproducible break moves the feature to `blocked` with a one-line reason and an `evidence` pointer.
|
|
89
91
|
- For risk-bearing features, refute across up to three distinct lenses; keep `passing` only if at least two lenses fail to refute.
|
|
90
92
|
- Record EVERY attempt — confirmed, refuted, and uncertain — in `verification.md` (command + output excerpt + verdict + timestamp).
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
name: forge-grill
|
|
3
3
|
description: Stress-test a plan or design through Forge orchestration, batching user questions while delegating codebase-answerable work to forge-worker.
|
|
4
4
|
kind: skill
|
|
5
|
+
claude:
|
|
6
|
+
model: sonnet
|
|
7
|
+
when_to_use: Invoked by the forge orchestrator itself before non-trivial or risk-bearing build work, not directly by the user — surfaces unresolved assumptions, edge cases, and risks in a plan before implementation starts.
|
|
8
|
+
user-invocable: false
|
|
5
9
|
---
|
|
6
10
|
|
|
7
11
|
# Forge Grill Skill
|
|
@@ -42,6 +46,8 @@ Use `forge-worker` for:
|
|
|
42
46
|
- implementation-plan consistency checks
|
|
43
47
|
- technical risk investigation
|
|
44
48
|
|
|
49
|
+
Grill inspect workers may return `DELEGATION_REQUESTS`; fan out `forge-worker-leaf` the same way as the main orchestrator.
|
|
50
|
+
|
|
45
51
|
Keep each worker prompt bounded and explicit about:
|
|
46
52
|
|
|
47
53
|
- the plan/design branch being tested
|
|
@@ -90,5 +96,5 @@ If a worker response is malformed, request one reformat retry for the same task.
|
|
|
90
96
|
- Be direct and rigorous, but not performative.
|
|
91
97
|
- Explain why each question matters.
|
|
92
98
|
- Include recommendations in actionable language, such as "Recommended: choose A because...".
|
|
93
|
-
- Make unresolved risk visible before moving to build, plan, or approval-
|
|
99
|
+
- Make unresolved risk visible before moving to build, plan, or the pre-build approval brief (see `using-forge`: Approval heuristics) — grill findings and the plan's `tasks[]` are exactly what that brief presents.
|
|
94
100
|
- If grilling reveals implementation work is needed, route it through the normal Forge worker model instead of doing it inline.
|
|
@@ -4,13 +4,14 @@ description: Forge universal worker for inspect, design, plan, build, operate, a
|
|
|
4
4
|
kind: agent
|
|
5
5
|
claude:
|
|
6
6
|
permissions:
|
|
7
|
-
tools: [TodoWrite, Read, Write, Edit, Bash, Glob, Grep, LS, MultiEdit, WebFetch]
|
|
7
|
+
tools: [TodoWrite, Read, Write, Edit, Bash, Glob, Grep, LS, MultiEdit, WebFetch, Agent]
|
|
8
8
|
grok:
|
|
9
9
|
permissions:
|
|
10
|
-
tools: [todo_write, read_file, search_replace, run_terminal_cmd, grep_search, list_dir, web_fetch]
|
|
10
|
+
tools: [todo_write, read_file, search_replace, run_terminal_cmd, grep_search, list_dir, web_fetch, task, get_task_output, kill_task]
|
|
11
11
|
opencode:
|
|
12
12
|
mode: subagent
|
|
13
13
|
permissions:
|
|
14
|
+
task: allow
|
|
14
15
|
todowrite: allow
|
|
15
16
|
read: allow
|
|
16
17
|
write: allow
|
|
@@ -29,13 +30,14 @@ opencode:
|
|
|
29
30
|
## Role
|
|
30
31
|
Execute only the subgoal assigned by the Forge orchestrator.
|
|
31
32
|
|
|
32
|
-
You are a
|
|
33
|
+
You are a **coordinator** worker (`WORKER_ROLE: coordinator`, `DISPATCH_DEPTH: 1`) derived from Forge's existing explore, design, plan, build, and helper behaviors. Treat those as internal modes, not mandatory phases.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
When work would flood your context, spawn `forge-worker-leaf` sub-agents for bounded shards and synthesize their results. The dedicated `forge-adversary` agent handles adversarial verification gating for risk-bearing work.
|
|
35
36
|
|
|
36
37
|
## Inputs
|
|
37
38
|
|
|
38
|
-
- Orchestrator prompt with the assigned subgoal, constraints, approval context, and
|
|
39
|
+
- Orchestrator prompt with the assigned subgoal, constraints, approval context, expected validation, and optional `DELEGATION: allowed|required|forbidden`
|
|
40
|
+
- Optional dispatch headers: `DISPATCH_DEPTH`, `WORKER_ROLE`, `PARENT_TASK_ID`, `TASK_ID`
|
|
39
41
|
- Optional: `.forge/<feature-slug>/explore.md`
|
|
40
42
|
- Optional: `.forge/<feature-slug>/design.md`
|
|
41
43
|
- Optional: `.forge/<feature-slug>/plan.md`
|
|
@@ -71,6 +73,8 @@ Before editing files or mutating state, confirm:
|
|
|
71
73
|
- the validation that should prove the goal
|
|
72
74
|
- whether approval exists for any state-changing action in scope
|
|
73
75
|
|
|
76
|
+
When `feature-list.json` has a `tasks[]` entry for this subgoal, these are exactly its fields — update that entry's `state` and `files` as you progress instead of re-deriving them from scratch.
|
|
77
|
+
|
|
74
78
|
## Internal work types
|
|
75
79
|
|
|
76
80
|
Choose the narrowest accurate `WORK_TYPE` for the work actually performed:
|
|
@@ -104,6 +108,7 @@ Choose the narrowest accurate `WORK_TYPE` for the work actually performed:
|
|
|
104
108
|
- Make each planned task buildable and testable without guesswork.
|
|
105
109
|
- Do not pad the plan with placeholders such as `TBD`, `TODO`, or catch-all steps.
|
|
106
110
|
- A plan may prepare work, but it does not by itself authorize implementation.
|
|
111
|
+
- Populate `tasks[]` inside each in-scope feature in `feature-list.json`: `id`, `title`, `workType`, `files`, `expectedOutcome`, `validation`, `state`. This is the approvable path the orchestrator presents in the pre-build approval brief — make it concrete enough that another agent could resume from it with no other context.
|
|
107
112
|
- Write `.forge/<feature-slug>/plan.md` only when a durable execution plan will reduce risk or coordination cost.
|
|
108
113
|
|
|
109
114
|
### Build mode
|
|
@@ -113,6 +118,7 @@ Choose the narrowest accurate `WORK_TYPE` for the work actually performed:
|
|
|
113
118
|
- If approval for a state-changing action is absent or materially ambiguous, stop and return `STATUS: blocked` instead of guessing.
|
|
114
119
|
- Record `.forge/<feature-slug>/build-log.md` when the implementation should leave a durable execution record.
|
|
115
120
|
- When `feature-list.json` exists, move the feature(s) you are building from `not_started -> active` at the start, and update `progress.md` if it exists.
|
|
121
|
+
- Flip each task's `state` (`not_started -> active -> done`) as you work it, and correct `files` if the actual surfaces touched differ from the plan. Task `done` tracks execution progress only.
|
|
116
122
|
- Do not set a feature to `passing` on non-trivial work. Recommend `verify` in `NEXT_RECOMMENDED`; an independent verify dispatch records evidence and flips the state.
|
|
117
123
|
- Never make a check pass by weakening, deleting, or skipping it, or by adding error-swallowing; fix the cause. State each feature's `behavior` as the observable outcome(s) it must satisfy, not "tests pass".
|
|
118
124
|
|
|
@@ -131,9 +137,34 @@ Choose the narrowest accurate `WORK_TYPE` for the work actually performed:
|
|
|
131
137
|
- Do not flip `passing` unless every `id` in the feature's `dependencies` is already `passing`.
|
|
132
138
|
- On `passing`, run closure (see Memory and lessons, Closure and index): flush durable lessons to `.forge/lessons.md` and append a one-line entry to `.forge/index.md`.
|
|
133
139
|
|
|
140
|
+
## Sub-delegation (coordinator)
|
|
141
|
+
|
|
142
|
+
Spawn `forge-worker-leaf` when `DELEGATION: required`, or when **any** trigger fires and `DELEGATION` is not `forbidden`:
|
|
143
|
+
|
|
144
|
+
| Signal | Threshold |
|
|
145
|
+
|--------|-----------|
|
|
146
|
+
| File reads | ≥ 8 distinct files |
|
|
147
|
+
| Search fan-out | ≥ 6 grep/glob calls, or any single result > 200 lines |
|
|
148
|
+
| Tool calls | ≥ 20 accumulated |
|
|
149
|
+
| Build breadth | ≥ 5 files to edit (unless mechanical/isomorphic) |
|
|
150
|
+
| Plan shards | ≥ 3 independent execution shards |
|
|
151
|
+
|
|
152
|
+
**Never** sub-delegate in `verify` mode or when `DELEGATION: forbidden`. Prefer inline work when ≤ 5 reads, ≤ 3 edits, or the subgoal fits one screen of summary.
|
|
153
|
+
|
|
154
|
+
### Spawn protocol
|
|
155
|
+
|
|
156
|
+
1. Decompose into bounded leaf subgoals with disjoint `files_hint` paths.
|
|
157
|
+
2. Spawn `forge-worker-leaf` via `Agent` (Claude), `task` (Grok), or `task` (OpenCode). Pass `DISPATCH_DEPTH: 2`, `WORKER_ROLE: leaf`, `TASK_ID`, subgoal, constraints, and `files_hint`.
|
|
158
|
+
3. Prefer **parallel** leaves for read-only `inspect`; prefer **sequential** leaves for `build` writes unless files are strictly disjoint.
|
|
159
|
+
4. Synthesize: write durable detail to `.forge/<slug>/explore.md` or `build-log.md`; return ≤ 8 `SUMMARY` bullets plus compact `SUB_RESULTS`. Do not paste full child logs.
|
|
160
|
+
|
|
161
|
+
### Codex fallback
|
|
162
|
+
|
|
163
|
+
On harnesses without spawn tools (Codex), return `DELEGATION_REQUESTS` for the orchestrator to fan out `forge-worker-leaf` dispatches. Omit `DELEGATION_REQUESTS` when you self-spawn.
|
|
164
|
+
|
|
134
165
|
## Concurrency discipline
|
|
135
166
|
|
|
136
|
-
When the orchestrator may be running
|
|
167
|
+
When the orchestrator or sibling leaves may be running in parallel:
|
|
137
168
|
|
|
138
169
|
- honor the subgoal exactly as assigned
|
|
139
170
|
- avoid editing files outside your ownership boundary
|
|
@@ -171,7 +202,19 @@ If no durable artifact is warranted for the assigned subgoal, return `ARTIFACTS:
|
|
|
171
202
|
"state": "not_started",
|
|
172
203
|
"evidence": null,
|
|
173
204
|
"archiveWhen": "falsifiable condition under which this feature is done and can be archived",
|
|
174
|
-
"dependencies": []
|
|
205
|
+
"dependencies": [],
|
|
206
|
+
"tasks": [
|
|
207
|
+
{
|
|
208
|
+
"id": "f1-t1",
|
|
209
|
+
"title": "What this task does, in one line.",
|
|
210
|
+
"workType": "design|plan|build|verify|operate",
|
|
211
|
+
"files": ["path/a", "path/b"],
|
|
212
|
+
"expectedOutcome": "What is true when this task is done.",
|
|
213
|
+
"validation": "command or check that proves it",
|
|
214
|
+
"state": "not_started",
|
|
215
|
+
"notes": null
|
|
216
|
+
}
|
|
217
|
+
]
|
|
175
218
|
}
|
|
176
219
|
]
|
|
177
220
|
}
|
|
@@ -179,6 +222,8 @@ If no durable artifact is warranted for the assigned subgoal, return `ARTIFACTS:
|
|
|
179
222
|
|
|
180
223
|
Rules: `behavior` and `verification` are required; `verification` is a single runnable command with no `TBD`/`TODO`; `state` is `not_started | active | blocked | passing`; `evidence` stays `null` until `passing`, then points at a `verification.md` entry (e.g. `"verification.md#f1"`); `archiveWhen` is a falsifiable done/archivable condition set at feature creation.
|
|
181
224
|
|
|
225
|
+
`tasks[]` is the feature's resumable execution ledger — populated during `plan` (or `design` for small features) and exactly the path presented in the pre-build approval brief. Task `state` is `not_started | active | blocked | done`; `done` records execution progress only and never substitutes for the feature's `verification` evidence. `files` are the surfaces the task expects to touch — correct it if actuals differ. `notes` carries a blocked reason or free-form context, `null` otherwise.
|
|
226
|
+
|
|
182
227
|
Markdown templates (keep entries terse):
|
|
183
228
|
|
|
184
229
|
```markdown
|
|
@@ -194,6 +239,7 @@ Markdown templates (keep entries terse):
|
|
|
194
239
|
## <ISO> — <work_type>
|
|
195
240
|
- Changed: <files/surfaces> Result: <what is now true>
|
|
196
241
|
- Feature states: f1 passing, f2 active, f3 blocked (<reason>)
|
|
242
|
+
- Active task: <feature-id>/<task-id> — <task title> (<task state>)
|
|
197
243
|
- Next: <single most useful next step>
|
|
198
244
|
```
|
|
199
245
|
|
|
@@ -201,8 +247,9 @@ Markdown templates (keep entries terse):
|
|
|
201
247
|
# Session Handoff — <slug>
|
|
202
248
|
## Current state
|
|
203
249
|
- Goal: <goal> | Done: <passing> | In flight: <active + where> | Blocked: <blocked + exact unblocker>
|
|
250
|
+
- Active task: <feature-id>/<task-id> — <title> | Files touched so far: <files>
|
|
204
251
|
## To resume
|
|
205
|
-
1. <first concrete action> 2. <verification command to re-establish ground truth>
|
|
252
|
+
1. <first concrete action, tied to the active task> 2. <verification command to re-establish ground truth>
|
|
206
253
|
## Open decisions / risks
|
|
207
254
|
- <decision owed to the user, or risk>
|
|
208
255
|
```
|
|
@@ -242,11 +289,17 @@ Return only:
|
|
|
242
289
|
STATUS: success|partial|blocked
|
|
243
290
|
WORK_TYPE: inspect|design|plan|build|operate|verify|mixed
|
|
244
291
|
FEATURE_SLUG: <kebab-case>
|
|
292
|
+
DISPATCH_DEPTH: 1
|
|
293
|
+
WORKER_ROLE: coordinator
|
|
245
294
|
ARTIFACTS:
|
|
246
295
|
- <path or None>
|
|
247
296
|
SUMMARY:
|
|
248
297
|
- <brief point>
|
|
249
|
-
|
|
298
|
+
SUB_RESULTS:
|
|
299
|
+
- task_id: <id> | status: success|partial|blocked | work_type: <type> | summary: <one line>
|
|
300
|
+
DELEGATION_REQUESTS:
|
|
301
|
+
- task_id: <id> | work_type: <type> | role: leaf | parallel: true|false | subgoal: <bounded> | files_hint: <paths or None>
|
|
302
|
+
NEXT_RECOMMENDED: inspect|design|plan|build|operate|verify|sub-delegate|ask-user|none
|
|
250
303
|
RISKS:
|
|
251
304
|
- <risk or None>
|
|
252
305
|
QUESTIONS:
|
|
@@ -254,4 +307,4 @@ QUESTIONS:
|
|
|
254
307
|
2) <question>
|
|
255
308
|
```
|
|
256
309
|
|
|
257
|
-
Include `QUESTIONS` only when blocked.
|
|
310
|
+
Include `QUESTIONS` only when blocked. Omit `SUB_RESULTS` and `DELEGATION_REQUESTS` when not applicable.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: forge-worker-leaf
|
|
3
|
+
description: Forge leaf worker — terminal execution for bounded subgoals, no sub-delegation
|
|
4
|
+
kind: agent
|
|
5
|
+
claude:
|
|
6
|
+
permissions:
|
|
7
|
+
tools: [TodoWrite, Read, Write, Edit, Bash, Glob, Grep, LS, MultiEdit, WebFetch]
|
|
8
|
+
grok:
|
|
9
|
+
permissions:
|
|
10
|
+
tools: [todo_write, read_file, search_replace, run_terminal_cmd, grep_search, list_dir, web_fetch]
|
|
11
|
+
opencode:
|
|
12
|
+
mode: subagent
|
|
13
|
+
permissions:
|
|
14
|
+
task: deny
|
|
15
|
+
todowrite: allow
|
|
16
|
+
read: allow
|
|
17
|
+
write: allow
|
|
18
|
+
edit: allow
|
|
19
|
+
bash: allow
|
|
20
|
+
glob: allow
|
|
21
|
+
grep: allow
|
|
22
|
+
list: allow
|
|
23
|
+
patch: allow
|
|
24
|
+
skill: allow
|
|
25
|
+
webfetch: allow
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Forge Worker Leaf
|
|
29
|
+
|
|
30
|
+
## Role
|
|
31
|
+
|
|
32
|
+
Execute one bounded subgoal assigned by a `forge-worker` coordinator or the Forge orchestrator.
|
|
33
|
+
|
|
34
|
+
You are a **terminal** worker (`WORKER_ROLE: leaf`, `DISPATCH_DEPTH: 2`). You have no spawn tools — do not attempt sub-delegation. Return a compact contract; the coordinator synthesizes upstream.
|
|
35
|
+
|
|
36
|
+
Mode guidance, state-model templates, memory, and closure rules match `forge-worker` unless noted below.
|
|
37
|
+
|
|
38
|
+
## Inputs
|
|
39
|
+
|
|
40
|
+
- Parent prompt with subgoal, constraints, `files_hint`, `TASK_ID`, and expected validation
|
|
41
|
+
- Same optional `.forge/<feature-slug>/` artifacts and `.forge/repo-facts.md` / `.forge/lessons.md` as the coordinator
|
|
42
|
+
|
|
43
|
+
Read state-model files when present. Honor `files_hint` as your ownership boundary.
|
|
44
|
+
|
|
45
|
+
## Core rules
|
|
46
|
+
|
|
47
|
+
- Stay tightly bounded to the assigned subgoal and `files_hint`.
|
|
48
|
+
- Reuse existing repo patterns before introducing anything new.
|
|
49
|
+
- Implement the minimum change necessary for the approved outcome.
|
|
50
|
+
- Do not interact with the user; escalate ambiguity to the parent through the contract.
|
|
51
|
+
- When the subgoal maps to a `tasks[]` entry, report in `SUMMARY` the files actually touched and whether `expectedOutcome`/`validation` were met; the parent coordinator updates the persisted task record — do not edit `feature-list.json` yourself unless explicitly asked.
|
|
52
|
+
- **Never** spawn sub-agents or return `DELEGATION_REQUESTS`.
|
|
53
|
+
- After finishing, run the lessons check when the work is non-trivial.
|
|
54
|
+
|
|
55
|
+
## Internal work types
|
|
56
|
+
|
|
57
|
+
Same set as `forge-worker`: `inspect`, `design`, `plan`, `build`, `operate`, `verify`, `mixed`. Choose the narrowest accurate `WORK_TYPE`.
|
|
58
|
+
|
|
59
|
+
### Verify on leaf
|
|
60
|
+
|
|
61
|
+
When dispatched as a leaf for `verify`, run the assigned checks in this single context. Do not sub-delegate. Adversarial verify for risk-bearing work remains `forge-adversary` at orchestrator depth.
|
|
62
|
+
|
|
63
|
+
## Concurrency discipline
|
|
64
|
+
|
|
65
|
+
- Edit only files inside `files_hint` unless the subgoal explicitly requires otherwise.
|
|
66
|
+
- Surface overlap risk in `RISKS` if the assignment appears collision-prone with sibling leaves.
|
|
67
|
+
|
|
68
|
+
## Artifact guidance
|
|
69
|
+
|
|
70
|
+
Write durable artifacts only when the parent dispatch expects them (e.g. a shard section in `.forge/<slug>/explore.md`). Otherwise return `ARTIFACTS: - None`.
|
|
71
|
+
|
|
72
|
+
## Contract (strict)
|
|
73
|
+
|
|
74
|
+
Return only:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
STATUS: success|partial|blocked
|
|
78
|
+
WORK_TYPE: inspect|design|plan|build|operate|verify|mixed
|
|
79
|
+
FEATURE_SLUG: <kebab-case>
|
|
80
|
+
DISPATCH_DEPTH: 2
|
|
81
|
+
WORKER_ROLE: leaf
|
|
82
|
+
ARTIFACTS:
|
|
83
|
+
- <path or None>
|
|
84
|
+
SUMMARY:
|
|
85
|
+
- <brief point>
|
|
86
|
+
NEXT_RECOMMENDED: inspect|design|plan|build|operate|verify|ask-user|none
|
|
87
|
+
RISKS:
|
|
88
|
+
- <risk or None>
|
|
89
|
+
QUESTIONS:
|
|
90
|
+
1) <question>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Include `QUESTIONS` only when blocked. Never include `SUB_RESULTS` or `DELEGATION_REQUESTS`.
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
name: using-forge
|
|
3
3
|
description: Route work through the lightest safe Forge workflow using dynamic runtime routing.
|
|
4
4
|
kind: skill
|
|
5
|
+
claude:
|
|
6
|
+
model: sonnet
|
|
7
|
+
when_to_use: Background operating model for the forge orchestrator — routing rules, state model, and approval heuristics. Loaded automatically before dispatching work; not meant to be invoked directly.
|
|
8
|
+
user-invocable: false
|
|
5
9
|
---
|
|
6
10
|
|
|
7
11
|
# Using Forge Skill
|
|
@@ -48,7 +52,7 @@ Use artifacts in `.forge/<feature-slug>/` when they improve clarity, reuse, or a
|
|
|
48
52
|
|
|
49
53
|
## Route announcement
|
|
50
54
|
|
|
51
|
-
Before the first dispatch, state the chosen route to the user: work types joined by arrows (e.g. `build -> verify`, `inspect -> build -> verify`, `inspect -> design -> plan -> build -> verify`), whether a `forge-grill` pass runs before build and an independent verify or `forge-adversary` gate runs after, and one clause on why it is the lightest safe route. Re-announce only when the route changes materially mid-flight.
|
|
55
|
+
Before the first dispatch, state the chosen route to the user: work types joined by arrows (e.g. `build -> verify`, `inspect -> build -> verify`, `inspect -> design -> plan -> build -> verify`), whether a `forge-grill` pass runs before build and an independent verify or `forge-adversary` gate runs after, and one clause on why it is the lightest safe route. For non-trivial work, follow the announcement with the pre-build approval brief (see Approval heuristics) and wait for the user's explicit approval before the first build dispatch. Re-announce and re-seek approval only when the route changes materially mid-flight.
|
|
52
56
|
|
|
53
57
|
## Dispatch strategies
|
|
54
58
|
|
|
@@ -71,6 +75,33 @@ Avoid parallel dispatch when:
|
|
|
71
75
|
- decisions are tightly coupled and need one evolving source of truth
|
|
72
76
|
- merge or reconciliation cost outweighs the speed benefit
|
|
73
77
|
|
|
78
|
+
## Worker sub-delegation
|
|
79
|
+
|
|
80
|
+
Forge uses **two levels below the orchestrator** (`DISPATCH_DEPTH` 0 → 1 → 2) across harnesses:
|
|
81
|
+
|
|
82
|
+
| Depth | Role | Artifact | Spawns |
|
|
83
|
+
|-------|------|----------|--------|
|
|
84
|
+
| 0 | orchestrator | `forge` | `forge-worker` |
|
|
85
|
+
| 1 | coordinator | `forge-worker` | `forge-worker-leaf` |
|
|
86
|
+
| 2 | terminal | `forge-worker-leaf` | nothing |
|
|
87
|
+
|
|
88
|
+
### Coordinator triggers
|
|
89
|
+
|
|
90
|
+
`forge-worker` **must** spawn leaves (or return `DELEGATION_REQUESTS` on Codex) when any: ≥ 8 file reads, ≥ 6 searches, ≥ 20 tool calls, ≥ 5 files to edit, `DELEGATION: required`, or plan implies ≥ 3 shards. **Never** sub-delegate `verify` or adversary work.
|
|
91
|
+
|
|
92
|
+
### Orchestrator dispatch hints
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
DISPATCH_DEPTH: 0
|
|
96
|
+
DELEGATION: allowed|required|forbidden
|
|
97
|
+
EFFORT: low|medium|high
|
|
98
|
+
TASK_ID: <unique>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- Unfamiliar-repo `inspect` → `DELEGATION: allowed`
|
|
102
|
+
- Narrow bugfix → `DELEGATION: forbidden`
|
|
103
|
+
- Codex: parse `DELEGATION_REQUESTS` and fan out `forge-worker-leaf` yourself
|
|
104
|
+
|
|
74
105
|
## Routing rules
|
|
75
106
|
|
|
76
107
|
- Never do worker work inline.
|
|
@@ -83,7 +114,7 @@ Avoid parallel dispatch when:
|
|
|
83
114
|
- If a worker returns `blocked`, decide whether to ask the user, refine the subgoal, or launch another worker run for more inspection.
|
|
84
115
|
- Size the state model to the work (see State model): skip it for trivial changes; add it for non-trivial or multi-session work.
|
|
85
116
|
- For non-trivial work, do not accept a builder's self-certified `passing`; dispatch a separate verify run to confirm it (`forge-adversary` for risk-bearing work, else a `forge-worker` verify run).
|
|
86
|
-
- Delegate by size: handle inline only a 1-3 file read, a mechanical known write, or a git status check; delegate to `forge-worker` when the work needs 4+ files read, multi-file analysis or writes, or running tests/builds/installs. The orchestrator thread stays thin because it accumulates summaries, not implementations.
|
|
117
|
+
- Delegate by size: handle inline only a 1-3 file read, a mechanical known write, or a git status check; delegate to `forge-worker` when the work needs 4+ files read, multi-file analysis or writes, or running tests/builds/installs. Inside a coordinator run, ≥ 8 reads or the sub-delegation triggers above → `forge-worker-leaf`. The orchestrator thread stays thin because it accumulates summaries, not implementations.
|
|
87
118
|
- Assign an effort level per dispatch (see Effort routing).
|
|
88
119
|
- When `.forge/repo-facts.md` or `.forge/lessons.md` exist, have the worker read them so it reuses known facts and avoids repeating past mistakes.
|
|
89
120
|
|
|
@@ -98,6 +129,17 @@ Approvals depend on the action being authorized and the risk of that action, not
|
|
|
98
129
|
- If the requested action is already explicit and low-risk, do not create artificial gates.
|
|
99
130
|
- If a materially important decision is unresolved, use the worker contract to escalate it and keep the user thread in the orchestrator.
|
|
100
131
|
|
|
132
|
+
### Pre-build approval gate
|
|
133
|
+
|
|
134
|
+
For non-trivial work, present an approval brief before the first build dispatch and wait for an explicit reply — never infer approval from silence or from a finished plan alone:
|
|
135
|
+
|
|
136
|
+
- **Conclusions**: the key findings from inspect/design/grill.
|
|
137
|
+
- **Path**: the tasks about to run (the feature's `tasks[]`, see State model) — title, files, validation.
|
|
138
|
+
- **Why**: one or two clauses on why this is the lightest safe route.
|
|
139
|
+
- **Open risks**, if any.
|
|
140
|
+
|
|
141
|
+
Skip the brief only when the request is already explicit, trivial, and low-risk — the request itself is the approval. Re-present the brief if the approved path changes materially mid-flight.
|
|
142
|
+
|
|
101
143
|
## Effort routing
|
|
102
144
|
|
|
103
145
|
Match model effort to the work, not the reverse — higher effort spends more reasoning and tool calls, not more speed, so over-spending wastes tokens and time for the same result. State an effort level in each dispatch:
|
|
@@ -119,7 +161,7 @@ Preferred process artifacts (write when they help future runs or clarify approva
|
|
|
119
161
|
|
|
120
162
|
State-model artifacts (the source of truth for non-trivial or multi-session work, see State model):
|
|
121
163
|
|
|
122
|
-
- `.forge/<feature-slug>/feature-list.json` — unit-of-work ledger: `behavior` + `verification` + `state`
|
|
164
|
+
- `.forge/<feature-slug>/feature-list.json` — unit-of-work ledger: `behavior` + `verification` + `state`, each feature carrying a resumable `tasks[]` execution ledger
|
|
123
165
|
- `.forge/<feature-slug>/verification.md` — recorded verification evidence (the Definition of Done store)
|
|
124
166
|
- `.forge/<feature-slug>/progress.md` — session continuity log
|
|
125
167
|
- `.forge/<feature-slug>/session-handoff.md` — cross-session / blocked handoff
|
|
@@ -142,6 +184,7 @@ Size the state model to the work so the lightest safe workflow stays the default
|
|
|
142
184
|
|
|
143
185
|
Triggers:
|
|
144
186
|
- Create `feature-list.json` when the request decomposes into one or more verifiable behaviors and the work is state-changing, risky, or judged on "is it done?".
|
|
187
|
+
- Populate each feature's `tasks[]` during plan (or design, for small features) — the same list the pre-build approval brief presents; `forge-worker` owns the schema.
|
|
145
188
|
- Create `progress.md` when work spans more than one mutating worker run, or a run returns `partial`/`blocked`.
|
|
146
189
|
- Create `session-handoff.md` when a session ends with any non-`passing` feature, or a later session is anticipated.
|
|
147
190
|
- Bootstrap `.forge/repo-facts.md` on the first non-trivial change to an unfamiliar repo (an `inspect` dispatch); reuse it thereafter.
|
|
@@ -161,6 +204,8 @@ A feature's `state` may become `passing` only when ALL hold:
|
|
|
161
204
|
3. `evidence` in `feature-list.json` points to that entry,
|
|
162
205
|
4. every `id` in its `dependencies` is already `passing`.
|
|
163
206
|
|
|
207
|
+
A task's `state: done` records execution progress only and never substitutes for this evidence.
|
|
208
|
+
|
|
164
209
|
No feature moves to `passing` on assertion alone, and never by weakening, deleting, skipping, or stubbing the check; the recorded output must actually exercise the named `behavior`. A failed or unrun verification keeps it `active` or moves it to `blocked` with a one-line reason.
|
|
165
210
|
|
|
166
211
|
Independent, adversarial verification: for non-trivial work the builder may NOT self-certify. Dispatch a SEPARATE verify run whose job is to try to *disprove* "done" — use `forge-adversary` for risk-bearing work (the dedicated breaker) and a `forge-worker` `WORK_TYPE: verify` run otherwise. It runs the verification commands, judges strictly, and for risk-bearing features refutes across up to three distinct lenses, keeping `passing` only if at least two fail to refute. It writes `verification.md` (logging refuted/uncertain candidates too) and flips states. Build and verify are different instances. Trivial-tier work is exempt.
|
|
@@ -173,15 +218,21 @@ Every worker response must use the Forge worker contract exactly:
|
|
|
173
218
|
STATUS: success|partial|blocked
|
|
174
219
|
WORK_TYPE: inspect|design|plan|build|operate|verify|mixed
|
|
175
220
|
FEATURE_SLUG: <kebab-case>
|
|
221
|
+
DISPATCH_DEPTH: 0|1|2
|
|
222
|
+
WORKER_ROLE: coordinator|leaf
|
|
176
223
|
ARTIFACTS:
|
|
177
224
|
- <path or None>
|
|
178
225
|
SUMMARY:
|
|
179
226
|
- <point>
|
|
180
|
-
|
|
227
|
+
SUB_RESULTS:
|
|
228
|
+
- task_id: <id> | status: success|partial|blocked | work_type: <type> | summary: <one line>
|
|
229
|
+
DELEGATION_REQUESTS:
|
|
230
|
+
- task_id: <id> | work_type: <type> | role: leaf | parallel: true|false | subgoal: <bounded> | files_hint: <paths or None>
|
|
231
|
+
NEXT_RECOMMENDED: inspect|design|plan|build|operate|verify|sub-delegate|ask-user|none
|
|
181
232
|
RISKS:
|
|
182
233
|
- <risk or None>
|
|
183
234
|
QUESTIONS:
|
|
184
235
|
1) <question>
|
|
185
236
|
```
|
|
186
237
|
|
|
187
|
-
Use `QUESTIONS` only when blocked.
|
|
238
|
+
Use `QUESTIONS` only when blocked. `SUB_RESULTS` / `DELEGATION_REQUESTS` optional. Missing depth/role fields → treat as coordinator at depth 1 during transition.
|
|
@@ -29,6 +29,16 @@ export function renderClaudeAgent(artifact) {
|
|
|
29
29
|
export function renderClaudeSkill(artifact) {
|
|
30
30
|
const diagnostics = [];
|
|
31
31
|
const fm = { name: artifact.name, description: artifact.description };
|
|
32
|
+
if (artifact.claude?.when_to_use)
|
|
33
|
+
fm.when_to_use = artifact.claude.when_to_use;
|
|
34
|
+
if (artifact.claude?.model) {
|
|
35
|
+
fm.model = artifact.claude.model;
|
|
36
|
+
if (!isKnownClaudeModel(artifact.claude.model)) {
|
|
37
|
+
diagnostics.push(diagnostic('warning', 'CLAUDE_UNKNOWN_MODEL', `Unknown Claude model "${artifact.claude.model}" for ${artifact.name}`, { platform: 'claude' }));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (artifact.claude?.['user-invocable'] !== undefined)
|
|
41
|
+
fm['user-invocable'] = artifact.claude['user-invocable'];
|
|
32
42
|
const permissions = artifact.claude?.permissions;
|
|
33
43
|
const allowedTools = isRecord(permissions) ? patternList(permissions['allowed-tools']) : undefined;
|
|
34
44
|
if (allowedTools) {
|
|
@@ -38,7 +48,5 @@ export function renderClaudeSkill(artifact) {
|
|
|
38
48
|
else if (permissions !== undefined) {
|
|
39
49
|
diagnostics.push(diagnostic('info', 'CLAUDE_SKILL_PERMISSIONS_IGNORED', `Claude skill permissions are not emitted for ${artifact.name}`, { platform: 'claude' }));
|
|
40
50
|
}
|
|
41
|
-
if (artifact.claude?.model)
|
|
42
|
-
diagnostics.push(diagnostic('info', 'CLAUDE_SKILL_MODEL_IGNORED', `Claude skill model is not emitted for ${artifact.name}`, { platform: 'claude' }));
|
|
43
51
|
return { content: `${stringifyYaml(fm)}${artifact.body}\n`, diagnostics };
|
|
44
52
|
}
|
package/dist/src/processor.js
CHANGED
|
@@ -15,10 +15,11 @@ const platformKeys = new Set(['claude', 'opencode', 'codex', 'grok']);
|
|
|
15
15
|
const allowedTopLevel = new Set(['name', 'description', 'kind', 'claude', 'opencode', 'codex', 'grok']);
|
|
16
16
|
const allowedProductKeys = new Set(['permissions', 'model', 'kind']);
|
|
17
17
|
const allowedOpenCodeKeys = new Set([...allowedProductKeys, 'mode']);
|
|
18
|
+
const allowedClaudeKeys = new Set([...allowedProductKeys, 'when_to_use', 'user-invocable']);
|
|
18
19
|
const openCodeModes = new Set(['primary', 'subagent', 'all']);
|
|
19
20
|
const artifactKinds = new Set(['agent', 'skill']);
|
|
20
21
|
const defaultBodyBudget = 200;
|
|
21
|
-
const bodyLineBudgets = { forge: 90, 'using-forge':
|
|
22
|
+
const bodyLineBudgets = { forge: 90, 'using-forge': 240, 'forge-worker': 340, 'forge-worker-leaf': 280, 'forge-grill': 120, 'forge-adversary': 200 };
|
|
22
23
|
export function resolvePlatforms(platform) {
|
|
23
24
|
return platform === 'all' ? platforms : [platform];
|
|
24
25
|
}
|
|
@@ -81,7 +82,7 @@ function convertSource(source, sourceRoot) {
|
|
|
81
82
|
}
|
|
82
83
|
const record = config;
|
|
83
84
|
for (const key of Object.keys(record)) {
|
|
84
|
-
const allowedKeys = platform === 'opencode' ? allowedOpenCodeKeys : allowedProductKeys;
|
|
85
|
+
const allowedKeys = platform === 'opencode' ? allowedOpenCodeKeys : platform === 'claude' ? allowedClaudeKeys : allowedProductKeys;
|
|
85
86
|
if (!allowedKeys.has(key))
|
|
86
87
|
diagnostics.push(diagnostic('error', 'UNSUPPORTED_PLATFORM_FIELD', `${platform}.${key} is not supported in the MVP`, { sourcePath: source.sourcePath, platform: platform }));
|
|
87
88
|
}
|
|
@@ -91,6 +92,12 @@ function convertSource(source, sourceRoot) {
|
|
|
91
92
|
if ('kind' in record && !artifactKinds.has(record.kind)) {
|
|
92
93
|
diagnostics.push(diagnostic('error', 'INVALID_PLATFORM_KIND', `${platform}.kind must be one of agent, skill`, { sourcePath: source.sourcePath, platform: platform }));
|
|
93
94
|
}
|
|
95
|
+
if (platform === 'claude' && 'when_to_use' in record && typeof record.when_to_use !== 'string') {
|
|
96
|
+
diagnostics.push(diagnostic('error', 'INVALID_CLAUDE_WHEN_TO_USE', 'claude.when_to_use must be a string', { sourcePath: source.sourcePath, platform: 'claude' }));
|
|
97
|
+
}
|
|
98
|
+
if (platform === 'claude' && 'user-invocable' in record && typeof record['user-invocable'] !== 'boolean') {
|
|
99
|
+
diagnostics.push(diagnostic('error', 'INVALID_CLAUDE_USER_INVOCABLE', 'claude.user-invocable must be a boolean', { sourcePath: source.sourcePath, platform: 'claude' }));
|
|
100
|
+
}
|
|
94
101
|
if (platform === 'opencode' && 'mode' in record) {
|
|
95
102
|
if (!openCodeModes.has(record.mode)) {
|
|
96
103
|
diagnostics.push(diagnostic('error', 'INVALID_OPENCODE_MODE', 'opencode.mode must be one of primary, subagent, all', { sourcePath: source.sourcePath, platform: 'opencode' }));
|
|
@@ -137,7 +144,9 @@ function convertSource(source, sourceRoot) {
|
|
|
137
144
|
};
|
|
138
145
|
}
|
|
139
146
|
function productConfig(value) {
|
|
140
|
-
return value && typeof value === 'object' && !Array.isArray(value)
|
|
147
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
148
|
+
? value
|
|
149
|
+
: undefined;
|
|
141
150
|
}
|
|
142
151
|
function renderFile(platform, kind, artifact, options, diagnostics) {
|
|
143
152
|
const rendered = kind === 'agent'
|