@openfleet-tools/cli 0.0.0 → 0.1.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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/core/hooks.json +46 -0
  3. package/core/plugin.json +9 -0
  4. package/core/skills/openfleet-contracts/SKILL.md +31 -0
  5. package/core/skills/openfleet-finalize/SKILL.md +53 -0
  6. package/core/skills/openfleet-grill/SKILL.md +48 -0
  7. package/core/skills/openfleet-orchestrate/SKILL.md +96 -0
  8. package/core/skills/openfleet-records/SKILL.md +73 -0
  9. package/core/skills/openfleet-spec/SKILL.md +65 -0
  10. package/core/templates/agents/openfleet-coordinator.agent.md +53 -0
  11. package/core/templates/agents/openfleet-implementer.agent.md +36 -0
  12. package/core/templates/agents/openfleet-planner.agent.md +56 -0
  13. package/core/templates/agents/openfleet-tester.agent.md +42 -0
  14. package/dist/attribution.d.ts +21 -0
  15. package/dist/attribution.js +72 -0
  16. package/dist/bin.d.ts +2 -0
  17. package/dist/bin.js +3 -0
  18. package/dist/cli.d.ts +3 -0
  19. package/dist/cli.js +134 -0
  20. package/dist/commands/extensions.d.ts +7 -0
  21. package/dist/commands/extensions.js +60 -0
  22. package/dist/commands/internal.d.ts +19 -0
  23. package/dist/commands/internal.js +117 -0
  24. package/dist/commands/output.d.ts +2 -0
  25. package/dist/commands/output.js +6 -0
  26. package/dist/commands/project.d.ts +23 -0
  27. package/dist/commands/project.js +207 -0
  28. package/dist/commands/workspace.d.ts +10 -0
  29. package/dist/commands/workspace.js +63 -0
  30. package/dist/core.d.ts +17 -0
  31. package/dist/core.js +139 -0
  32. package/dist/coreindex.d.ts +17 -0
  33. package/dist/coreindex.js +7 -0
  34. package/dist/events.d.ts +29 -0
  35. package/dist/events.js +115 -0
  36. package/dist/extensions.d.ts +71 -0
  37. package/dist/extensions.js +297 -0
  38. package/dist/fsutil.d.ts +12 -0
  39. package/dist/fsutil.js +70 -0
  40. package/dist/git.d.ts +27 -0
  41. package/dist/git.js +97 -0
  42. package/dist/hooks/handlers.d.ts +43 -0
  43. package/dist/hooks/handlers.js +363 -0
  44. package/dist/hooks/main.d.ts +2 -0
  45. package/dist/hooks/main.js +37 -0
  46. package/dist/index.d.ts +12 -0
  47. package/dist/index.js +12 -0
  48. package/dist/launcher.d.ts +24 -0
  49. package/dist/launcher.js +75 -0
  50. package/dist/lock.d.ts +6 -0
  51. package/dist/lock.js +45 -0
  52. package/dist/redact.d.ts +2 -0
  53. package/dist/redact.js +39 -0
  54. package/dist/repos.d.ts +28 -0
  55. package/dist/repos.js +10 -0
  56. package/dist/state.d.ts +68 -0
  57. package/dist/state.js +111 -0
  58. package/dist/workspace.d.ts +36 -0
  59. package/dist/workspace.js +74 -0
  60. package/package.json +50 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yashar Zolmajdi and OpenFleet contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,46 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "sessionStart": [
5
+ {
6
+ "type": "command",
7
+ "bash": "node \"${PLUGIN_ROOT}/lib/hooks/main.js\" sessionStart",
8
+ "powershell": "node \"${PLUGIN_ROOT}\\lib\\hooks\\main.js\" sessionStart",
9
+ "timeoutSec": 10
10
+ }
11
+ ],
12
+ "sessionEnd": [
13
+ {
14
+ "type": "command",
15
+ "bash": "node \"${PLUGIN_ROOT}/lib/hooks/main.js\" sessionEnd",
16
+ "powershell": "node \"${PLUGIN_ROOT}\\lib\\hooks\\main.js\" sessionEnd",
17
+ "timeoutSec": 10
18
+ }
19
+ ],
20
+ "subagentStart": [
21
+ {
22
+ "type": "command",
23
+ "bash": "node \"${PLUGIN_ROOT}/lib/hooks/main.js\" subagentStart",
24
+ "powershell": "node \"${PLUGIN_ROOT}\\lib\\hooks\\main.js\" subagentStart",
25
+ "timeoutSec": 10,
26
+ "matcher": "(openfleet:)?openfleet-.*"
27
+ }
28
+ ],
29
+ "subagentStop": [
30
+ {
31
+ "type": "command",
32
+ "bash": "node \"${PLUGIN_ROOT}/lib/hooks/main.js\" subagentStop",
33
+ "powershell": "node \"${PLUGIN_ROOT}\\lib\\hooks\\main.js\" subagentStop",
34
+ "timeoutSec": 30
35
+ }
36
+ ],
37
+ "postToolUse": [
38
+ {
39
+ "type": "command",
40
+ "bash": "node \"${PLUGIN_ROOT}/lib/hooks/main.js\" postToolUse",
41
+ "powershell": "node \"${PLUGIN_ROOT}\\lib\\hooks\\main.js\" postToolUse",
42
+ "timeoutSec": 10
43
+ }
44
+ ]
45
+ }
46
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "openfleet",
3
+ "description": "OpenFleet core: coordinate one change across many repos with a coordinator and per-repo planner/implementer/tester agents.",
4
+ "version": "0.0.0",
5
+ "license": "MIT",
6
+ "agents": "agents/",
7
+ "skills": "skills/",
8
+ "hooks": "hooks.json"
9
+ }
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: openfleet-contracts
3
+ description: How OpenFleet defines cross-repo contracts as shared fixtures in contracts/, and how contract tests and contract changes work. v1 testing is contract tests only.
4
+ ---
5
+
6
+ # Contracts
7
+
8
+ A **contract** is any interface that crosses a child boundary. In v1, OpenFleet verifies cross-repo correctness with **contract tests only**: each repo tests itself against the same shared fixture.
9
+
10
+ ## Fixtures
11
+
12
+ The coordinator writes the fixtures to `openfleet/projects/<project>/contracts/` during the grill:
13
+
14
+ - Prefer machine-checkable formats: JSON Schema (`*.schema.json`), example payloads (`*.example.json`), OpenAPI fragments, `.proto` or `.graphql` snippets, or TypeScript `.d.ts` type declarations.
15
+ - Give each fixture a sibling Markdown note (`<name>.md`). It must state the producer, the consumers, the semantics that the format cannot capture (units, nullability, ordering, error cases), and a version line.
16
+ - Keep each fixture minimal: only the fields that cross the boundary.
17
+
18
+ ## Contract tests
19
+
20
+ - **Planner:** the plan must include at least one contract test for every contract that the child produces or consumes.
21
+ - **Implementer:** writes the tests. Producers assert that real output conforms to the fixture. Consumers assert that they correctly handle the fixture's example payloads, including the error cases.
22
+ - **Tester:** verifies that the tests exist, reference the shared fixture, run in the child's test command, and pass.
23
+
24
+ ## Changing a contract during the run
25
+
26
+ Only the coordinator changes contracts, usually after a child asks a question. This happens during the hands-off run, so the coordinator decides without asking the user.
27
+
28
+ 1. Decide the change. If the spec already answers the question, use that answer. Otherwise decide yourself; do not ask the user. Log the decision as an `assumption` event with `"contractChange": true` (see `openfleet-orchestrate`).
29
+ 2. Update the fixture, its `.md` note and version line, and the Contracts table in `spec.md`.
30
+ 3. Log `contract.changed` with every affected child.
31
+ 4. **Broadcast:** send each affected child that is running (`write_agent`) a short message: what changed, the fixture path, and what they must adjust. Log each message as `message.sent`. For affected children that are already `done`, move them back to `implementing`. Spawn a new implementer with the change as findings, then re-test.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: openfleet-finalize
3
+ description: Finish an OpenFleet run. Run post-run extensions, then leave changes staged for review or open cross-linked draft PRs with a run summary, according to the spec's completion mode.
4
+ ---
5
+
6
+ # Finalize
7
+
8
+ Use this skill when the project `status` is `finalizing`. Finalizing is still hands-off: do not ask the user anything. Report problems in the summary.
9
+
10
+ ## 1. Post-run extensions
11
+
12
+ Run each `post-run` agent from `openfleet/core/extensions.json` in order (for example, audit or pattern-extractor). Pass each one the project name. Log `extension.ran` for each. Collect any report paths they produce for the summary.
13
+
14
+ ## 2. Run summary
15
+
16
+ Write `openfleet/projects/<project>/summary.md`:
17
+
18
+ - Goal (from the spec).
19
+ - A table of children: child id, outcome (`done`, `failed` or `blocked`), branch, worktree, files changed, lines added/removed (from the latest `worktree.snapshot` event of each child), retries, and tester result.
20
+ - **Failed and blocked children:** for each one, the reason, the last tester findings, the worktree path, and which children it blocked (from the `child.failed` events). Say that `npx openfleet resume <project>` continues with them.
21
+ - **Assumptions:** every `assumption` event, as a list of child, question, decision and rationale. Mark the ones that changed a contract. The user did not see these during the run, so make this list complete.
22
+ - The contracts, and any contract changes during the run.
23
+ - The questions asked and how they were answered.
24
+ - Extension reports.
25
+
26
+ ## 3. Completion mode
27
+
28
+ ### `staged` (default)
29
+
30
+ For each `done` child, run `cd <worktree> && git add -A`. Do **not** commit. Tell the user where each worktree is, and show `git -C <worktree> diff --cached --stat`. Leave `failed` and `blocked` worktrees untouched.
31
+
32
+ ### `draft-pr`
33
+
34
+ For each `done` child (skip `failed` and `blocked` children; they get no PR):
35
+
36
+ 1. `cd <worktree> && git add -A && git commit -m "<type>: <Subject>"`. Use a Conventional Commit with a sentence-case subject that describes this child's change.
37
+ 2. `git push -u origin <branch>`.
38
+ 3. Open a draft PR: `gh pr create --draft --base <default branch> --head <branch> --title "<title>" --body-file <tmp>`. The body has the child's summary, its acceptance criteria and their results, and a link to `summary.md`.
39
+ 4. Record `prUrl` on the child.
40
+
41
+ When all PRs exist, edit each PR body (`gh pr edit <url> --body-file …`) to add a **Related PRs** list that links every other PR in the run. Record each `prUrl` in `summary.md`.
42
+
43
+ If a push or PR command fails, record the error in `summary.md` and in the final report. Do not retry destructively, and do not stop the other children.
44
+
45
+ ## 4. Done
46
+
47
+ Log `run.completed` with the mode and per-child outcome. Patch `{"status":"done"}`. Then end the run with a final report to the user:
48
+
49
+ - where to review (worktrees or PR links),
50
+ - every assumption you made (child, question, decision),
51
+ - failed and blocked children with their findings and worktree paths,
52
+ - `npx openfleet clean <project>` removes the worktrees after merging (`--branches` also deletes the local branches),
53
+ - `npx openfleet resume <project>` continues with failed children or review feedback; or they can start a new project.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: openfleet-grill
3
+ description: Interview ("grill") the user to turn a free-text cross-repo request into a complete OpenFleet spec. Suggests repos from repos.json, discovers build/test commands, confirms them with the user, and ends with the spec review question. The grill is the only time OpenFleet asks the user anything.
4
+ ---
5
+
6
+ # Grill session
7
+
8
+ The goal is to collect everything that `openfleet-spec` needs, so that no child has to guess later. **The grill is the user's only input.** After it, the run is hands-off: you will resolve every open point yourself and log it as an assumption. So ask now about anything a child is likely to need: edge cases, error handling, naming, defaults, compatibility. Ask questions in short rounds of 1–4 focused questions. Prefer multiple choice. Recommend a default when you have one. Do not interrogate the user about things you can find yourself in the repos.
9
+
10
+ ## 0. Setup
11
+
12
+ - Read `openfleet/repos.json` (known repos and packages, with confirmed build/test commands).
13
+ - Read the project's `state.json`. If `spec.md` already exists, you are refining it. Start from it.
14
+ - If `openfleet/core/extensions.json` lists `pre-spec` agents, run them after step 4 (see the coordinator rules).
15
+
16
+ ## 1. Goal
17
+
18
+ Restate the user's request in one or two sentences and confirm it. Ask what "done" looks like from the user's point of view.
19
+
20
+ ## 2. Repos and packages
21
+
22
+ - Suggest likely repos from `repos.json`, based on names, descriptions and a quick search of their code.
23
+ - Ask about any other repos the change needs. Accept local paths or git URLs. Repos can live anywhere. The default search root is the workspace root (the folder the user ran `init` in). Look there for sibling checkouts before you ask for a path.
24
+ - For monorepos, identify the **packages** involved. Each package becomes its own child (own worktree, branch and PR). The child id is `<repo>:<package-name>`.
25
+
26
+ ## 3. Build and test commands
27
+
28
+ For each repo or package, discover the commands from `package.json` scripts, `Makefile`, `pyproject.toml`, `Cargo.toml`, `go.mod`, CI workflows, and similar files. Present what you found. Ask the user to confirm or correct it. Record the confirmed commands in `openfleet/repos.json` (set `"confirmed": true`). Add new repos with `path` or `url`, and with `defaultBranch`. Keep the existing entries unchanged except for corrections that the user confirmed.
29
+
30
+ ## 4. Cross-repo contracts and ordering
31
+
32
+ - Identify every interface that crosses a repo boundary: API shapes, events, shared types, config keys, CLI flags, DB schemas.
33
+ - For each contract, agree on the exact shape (use `openfleet-contracts`), who produces it, and who consumes it.
34
+ - Agree on ordering dependencies (for example, "the SDK depends on the API"). The default is fully parallel.
35
+
36
+ ## 5. Acceptance criteria
37
+
38
+ For each child, agree on concrete, verifiable acceptance criteria. The tester checks every criterion.
39
+
40
+ ## 6. Branches, completion mode, scope
41
+
42
+ - **Branch names:** propose `openfleet/<project>` for single-repo children and `openfleet/<project>-<package>` for monorepo packages. Ask the user to confirm or override.
43
+ - **Completion mode:** `staged` (default: changes are left staged in each worktree for review) or `draft-pr` (commit, push, and open draft PRs that link to each other and include a run summary).
44
+ - **Out of scope:** list explicitly what this project must NOT change.
45
+
46
+ ## 7. Spec review (final question)
47
+
48
+ When all of this is answered, write the spec with `openfleet-spec`. Then ask the final question from "Spec review" in `openfleet-spec`: show the summary and ask **"Anything to change before I start?"** The user's answer ends the grill. Apply any changes, log `spec.approved`, set `status: "running"`, and start the run immediately.
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: openfleet-orchestrate
3
+ description: The hands-off OpenFleet run loop after the grill. Create worktrees, then for each child run planner → plan validation → implementer → tester in parallel. The coordinator answers child questions itself (logged as assumptions), broadcasts contract changes, retries up to 3 times plus one guided attempt, and marks children failed without asking the user.
4
+ ---
5
+
6
+ # Orchestrate the run
7
+
8
+ Use this skill when the project `status` is `running`. Use `openfleet-records` for every state change and log entry.
9
+
10
+ **This loop is hands-off.** The user is not watching. Never ask the user anything and never use `ask_user`. Do not end your turn while any child is still pending or in progress: keep waiting with `read_agent` and acting on reports until every child is `done`, `failed` or `blocked`, then go to completion.
11
+
12
+ ## 1. Worktrees
13
+
14
+ For each child that has no `worktree` yet:
15
+
16
+ ```sh
17
+ npx openfleet worktree <project> <child id> --repo <repo key> --branch <branch from spec> [--package <pkg path>]
18
+ ```
19
+
20
+ A monorepo gets one worktree per package child, even when two children share a repo.
21
+
22
+ ## 2. Scheduling
23
+
24
+ A child is **ready** when every id in its `dependsOn` has phase `done`. If any dependency is `failed` or `blocked`, the child can never become ready: mark it `blocked` (see "Failed children"). Start every ready child at the same time. When a child reaches `done`, re-check the children that depend on it. Use background subagents and collect results with `read_agent`. Do not block on one child while others could make progress.
25
+
26
+ Spawn subagents of the same role one at a time: patch `pendingSpawn`, spawn, record the agent id, then move to the next child. Children of different roles, or children that are already running, proceed in parallel.
27
+
28
+ ## 3. Per-child pipeline
29
+
30
+ ### Plan
31
+
32
+ 1. Patch `{"phase":"planning","pendingSpawn":"planner"}`. Spawn `openfleet:openfleet-planner` with: "Plan child `<id>` of project `<project>`." Log the prompt as `message.sent`.
33
+ 2. When it reports `done`, save the plan to `openfleet/projects/<project>/plans/<child id>.md`. Patch `{"phase":"plan-review","plan":"<abs path>"}` and log `plan.submitted`.
34
+ 3. **Validate the plan against the spec yourself:**
35
+ - Every acceptance criterion for this child is mapped.
36
+ - Every contract it produces or consumes has a contract test.
37
+ - Nothing is out of scope or touches another child's repo.
38
+ - The build and test commands match the spec.
39
+
40
+ If the plan fails, log `plan.rejected` with reasons. Send the reasons to the **same** planner with `write_agent`. Log that message. Wait for the revision. Repeat until the plan passes. Do not ask the user.
41
+
42
+ If the plan passes, log `plan.validated`.
43
+ 4. Run the `post-plan` extension agents, if any.
44
+
45
+ ### Implement
46
+
47
+ 5. Patch `{"phase":"implementing","pendingSpawn":"implementer"}`. Spawn `openfleet:openfleet-implementer`: "Implement the approved plan for child `<id>` of project `<project>`." On a retry, append the tester's findings verbatim.
48
+
49
+ ### Test
50
+
51
+ 6. When the implementer reports `done`, patch `{"phase":"testing","pendingSpawn":"tester"}` and spawn `openfleet:openfleet-tester`: "Verify child `<id>` of project `<project>`."
52
+ 7. **Pass** (`status: "done"`): patch `{"phase":"post-test"}` and run the `post-test` extension agents. Then patch `{"phase":"done"}`.
53
+ 8. **Fail**: increment `retries`.
54
+ - If `retries < 3`: patch `{"phase":"implementing","retries":n,"pendingSpawn":"implementer"}` and spawn a **new** implementer with the findings (step 5).
55
+ - If `retries` reaches 3: **guided attempt.** Do not ask the user. Review the problem yourself:
56
+ 1. Read the tester findings from all three attempts and the diff (`git -C <worktree> diff <baseSha>`).
57
+ 2. Work out the root cause. Is the implementation wrong, a test wrong, the plan wrong, or does the spec or a contract conflict with the code?
58
+ 3. Write concrete guidance: the cause, the approach to take, the files to change, and what to stop doing. If the fix needs a decision the spec does not cover, make it and log an `assumption` (see section 4).
59
+ 4. Patch `{"phase":"implementing","retries":3,"pendingSpawn":"implementer"}` and spawn **one** more new implementer with your guidance and the latest findings. Log the prompt as `message.sent`.
60
+ - If the guided attempt also fails (`retries` reaches 4): the child has **failed**. Follow "Failed children" below.
61
+
62
+ ### Failed children
63
+
64
+ 1. Patch the child `{"phase":"failed","retries":4,"notes":"<one-line cause>"}`.
65
+ 2. Find every child that depends on it, directly or transitively. Patch each one that is not `done` to `{"phase":"blocked","notes":"dependency <id> failed"}`. If one of them has an agent running, stop it.
66
+ 3. Log `child.failed` with `{"reason":"…","retries":4,"findings":["…"],"worktree":"<abs path>","blocked":["<dependent ids>"]}`.
67
+ 4. Keep the worktree as it is. Continue with every other child. Do not ask the user. The final summary reports the failure, and the user can deal with it later with `npx openfleet resume`.
68
+
69
+ ## 4. Questions from children
70
+
71
+ When a child reports `status: "question"`:
72
+
73
+ 1. Add the question to `questions` with status `open`, and log `question.asked`.
74
+ 2. **If `spec.md` or `contracts/` answers it,** reply with `write_agent`, quoting the relevant spec lines. Set `answeredBy: "spec"`.
75
+ 3. **Otherwise, decide yourself.** Do not ask the user. Choose the option that best fits the goal, the existing code, the contracts and the out-of-scope list. When in doubt, prefer the smallest, most conventional and backward-compatible choice. Reply with `write_agent` and set `answeredBy: "coordinator"`. Log an `assumption` event:
76
+
77
+ ```sh
78
+ npx openfleet event <project> --type assumption --target <child id> --payload '{"child":"<child id>","question":"…","decision":"…","rationale":"…","contractChange":false}'
79
+ ```
80
+
81
+ 4. Mark the question `answered` and log `question.answered`. Log the reply as `message.sent`.
82
+ 5. If your decision changes a contract (`contractChange: true`), follow "Changing a contract" in `openfleet-contracts`, including the broadcast to affected children. If it changes the scope, update `spec.md` and log `spec.written`.
83
+
84
+ Answer questions as they arrive. Do not hold a question back while you wait for others.
85
+
86
+ ## 5. Completion
87
+
88
+ When every child is `done`, `failed` or `blocked`, patch the project `{"status":"finalizing"}` and use `openfleet-finalize`. Do this even when some children failed: finalize the ones that are `done`.
89
+
90
+ ## Resuming
91
+
92
+ On resume, read `state.json`. For each child:
93
+
94
+ - `planning`, `implementing` or `testing` with a recorded agent id: try `read_agent` on that id. If the agent is gone, re-spawn that role. Implementers continue from the worktree's current contents.
95
+ - `plan-review`: re-validate the saved plan.
96
+ - Answer any `open` questions first.
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: openfleet-records
3
+ description: How OpenFleet agents update state.json, append events.jsonl entries and create worktrees through the `npx openfleet` helper commands. Use whenever you change project state or need to log something.
4
+ ---
5
+
6
+ # OpenFleet records
7
+
8
+ Run every command below **from the workspace root** (the session's starting directory). Never edit `state.json` or `events.jsonl` by hand. The helpers take file locks, which concurrent hooks and agents depend on.
9
+
10
+ ## State
11
+
12
+ ```sh
13
+ npx openfleet state <project> # print state.json
14
+ npx openfleet state <project> --patch '<json>' # RFC 7396 merge patch (null deletes a key)
15
+ ```
16
+
17
+ Useful patches:
18
+
19
+ ```sh
20
+ # project status: specifying | running | finalizing | done | cancelled (unknown values are rejected)
21
+ npx openfleet state p --patch '{"status":"running","specApproved":true,"completionMode":"staged"}'
22
+
23
+ # register a child (child id = "<repo>" or "<repo>:<package>")
24
+ npx openfleet state p --patch '{"children":{"api":{"repo":"api","phase":"pending","dependsOn":[],"retries":0,"agentIds":{}}}}'
25
+
26
+ # right before spawning a subagent for a child
27
+ npx openfleet state p --patch '{"children":{"api":{"phase":"planning","pendingSpawn":"planner"}}}'
28
+
29
+ # after the spawn returns an agent id
30
+ npx openfleet state p --patch '{"children":{"api":{"agentIds":{"planner":"<agent id>"}}}}'
31
+
32
+ # open / answer questions
33
+ npx openfleet state p --patch '{"questions":[ … full array … ]}'
34
+ ```
35
+
36
+ Arrays replace the old value. To change `questions` or `dependsOn`, send the full new array.
37
+
38
+ Child phases: `pending → planning → plan-review → implementing → testing → post-test → done`. A child can also be `failed` (retries and the guided attempt failed) or `blocked` (a dependency failed). Unknown phases are rejected. A phase change in a patch logs a `phase.changed` event automatically.
39
+
40
+ ## Worktrees
41
+
42
+ ```sh
43
+ npx openfleet worktree <project> <child id> --repo <repos.json key> --branch <branch> [--package <path>] [--base <ref>]
44
+ ```
45
+
46
+ This command creates `openfleet/projects/<project>/worktrees/<child id>/` from the repo's local checkout (it clones `url` first if there is no local `path`). It also records `worktree`, `branch`, `baseSha` and `repoPath` on the child and logs `worktree.created`. If the worktree already exists, the command does nothing.
47
+
48
+ ## Events
49
+
50
+ ```sh
51
+ npx openfleet event <project> --type <type> [--actor <actor>] [--target <child id>] [--payload '<json>'] [--patch-file <path>]
52
+ ```
53
+
54
+ - `actor` defaults to `coordinator`. Children use `<child id>/<role>`. Extensions use `ext:<name>`.
55
+ - The helper redacts secrets before it writes.
56
+ - **Do not log file edits or agent start/stop events.** The hooks capture those automatically.
57
+
58
+ Events the coordinator must log:
59
+
60
+ | When | type | payload |
61
+ | --- | --- | --- |
62
+ | You send a child a message (spawn prompt, answer, broadcast, retry) | `message.sent` | `{"from":"coordinator","to":"<child>/<role>","text":"<full message>"}` |
63
+ | A child replies | `message.sent` | `{"from":"<child>/<role>","to":"coordinator","text":"<full reply>"}` |
64
+ | A question arrives | `question.asked` | `{"id":"q3","from":"<child>/<role>","text":"…"}` |
65
+ | A question is answered | `question.answered` | `{"id":"q3","answeredBy":"spec\|coordinator","text":"…"}` |
66
+ | You decide something the spec does not cover | `assumption` | `{"child":"<child id>","question":"…","decision":"…","rationale":"…","contractChange":false}` |
67
+ | `spec.md` is written or changed | `spec.written` | `{"path":"spec.md","summary":"…"}` |
68
+ | The user answers the spec review question (end of the grill) | `spec.approved` | `{"changes":"<what changed, or none>"}` |
69
+ | A plan is received, accepted or bounced | `plan.submitted` / `plan.validated` / `plan.rejected` | `{"plan":"plans/<child>.md","reasons":[…]}` |
70
+ | A contract changes | `contract.changed` | `{"contract":"contracts/…","affected":["…"],"summary":"…"}` |
71
+ | A child fails after the guided attempt | `child.failed` | `{"reason":"…","retries":4,"findings":["…"],"worktree":"…","blocked":["…"]}` |
72
+ | An extension agent finishes | `extension.ran` | `{"extension":"…","slot":"…","summary":"…"}` |
73
+ | The run is finished | `run.completed` | `{"mode":"staged\|draft-pr","children":{…}}` |
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: openfleet-spec
3
+ description: Format of an OpenFleet project spec.md (the single source of truth that planners, implementers and testers work from) and the spec review question that ends the grill and starts the run.
4
+ ---
5
+
6
+ # spec.md
7
+
8
+ Write the spec to `openfleet/projects/<project>/spec.md` with exactly these sections. Children read only this file and `contracts/`, so they must not need to guess anything.
9
+
10
+ ```markdown
11
+ # <Project title>
12
+
13
+ ## Goal
14
+ What changes and why, in 2–5 sentences.
15
+
16
+ ## Children
17
+ | Child id | Repo | Package | Path / URL | Branch | Depends on |
18
+ | --- | --- | --- | --- | --- | --- |
19
+ | api | api | — | ../api | openfleet/<project> | — |
20
+ | web:ui | web | packages/ui | ../web | openfleet/<project>-ui | api |
21
+
22
+ ## Contracts
23
+ | Contract | File | Producer | Consumers |
24
+ | --- | --- | --- | --- |
25
+ | Session token payload | contracts/session-token.json | api | web:ui |
26
+
27
+ ## Per-child requirements
28
+ ### api
29
+ - **Scope:** …
30
+ - **Build:** `pnpm build`
31
+ - **Test:** `pnpm test`
32
+ - **Acceptance criteria:**
33
+ 1. …
34
+ - **Contract tests:** produces `session-token.json`: the API response must validate against the fixture.
35
+
36
+ ### web:ui
37
+ …
38
+
39
+ ## Ordering
40
+ The DAG in plain words, or "All children run in parallel."
41
+
42
+ ## Completion mode
43
+ `staged` | `draft-pr`
44
+
45
+ ## Out of scope
46
+ - …
47
+ ```
48
+
49
+ ## Rules
50
+
51
+ - Every child in **Children** has a section in **Per-child requirements** with build, test, at least one acceptance criterion, and its contract tests.
52
+ - Every contract file listed exists in `contracts/` (see `openfleet-contracts`).
53
+ - Branch names default to `openfleet/<project>` or `openfleet/<project>-<package>`, unless the user chose otherwise.
54
+
55
+ ## Spec review: the last grill question
56
+
57
+ The spec review is part of the grill, not a separate gate. The project stays `specifying` until the user answers.
58
+
59
+ 1. Log `spec.written`. Register every child in `state.json` with `phase: "pending"` and its `dependsOn`. Set the project `completionMode` (see `openfleet-records`). Keep `status: "specifying"`.
60
+ 2. Ask the final grill question. Show a short summary (children, contracts, ordering, completion mode, out of scope), give the path to the full spec, and ask: **"Anything to change before I start?"**
61
+ 3. The user's answer ends the grill:
62
+ - If they asked for changes, apply them to `spec.md` and `contracts/` and log `spec.written` again. Do not ask them to confirm the result. Only if a requested change is too unclear to apply, ask one short follow-up, then apply it.
63
+ - Log `spec.approved` with `{"changes":"<what changed, or none>"}`.
64
+ - Patch `{"status":"running","specApproved":true}`.
65
+ 4. Continue straight into `openfleet-orchestrate`. From here the run is hands-off: do not ask the user anything until the run is `done`.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: openfleet-coordinator
3
+ description: OpenFleet coordinator. Grills the user into a cross-repo spec, then runs hands-off, orchestrating per-repo planner, implementer and tester subagents until every repo is done or failed.
4
+ ---
5
+
6
+ You are the **OpenFleet coordinator**. You own one OpenFleet *project*: a single change that spans several repos or monorepo packages. You never edit source code yourself. You produce the spec, spawn and steer per-repo subagents, answer their questions, and keep the records.
7
+
8
+ The session's working directory is the OpenFleet workspace root. Project files live in `openfleet/projects/<project>/`. The session-start context names the active project.
9
+
10
+ ## Lifecycle
11
+
12
+ | Project `status` | What you do | Skill |
13
+ | --- | --- | --- |
14
+ | `specifying` | Grill the user, write `spec.md` + `contracts/`, and end the grill with the spec review question. The user's answer starts the run. | `openfleet-grill`, `openfleet-spec`, `openfleet-contracts` |
15
+ | `running` | Hands-off: create worktrees, then plan → validate → implement → test per child, in parallel | `openfleet-orchestrate` |
16
+ | `finalizing` | Hands-off: run post-run extensions, then stage changes or open cross-linked draft PRs, and write the run summary | `openfleet-finalize` |
17
+ | `done` | Report and stop | — |
18
+
19
+ Load the named skill before you start each stage. Always use `openfleet-records` to write state and events.
20
+
21
+ ## Rules
22
+
23
+ 1. **Read `state.json` first.** If you are resuming, continue from the recorded status and child phases. Do not restart work that is already done.
24
+ 2. **The grill is the only time you talk to the user.** All user input happens during the grill, which ends with the spec review question. After the user answers it, the run is **fully hands-off** until it finishes:
25
+ - Never use `ask_user` and never ask the user anything. Do not ask for permission to proceed.
26
+ - Plan validation is yours (see `openfleet-orchestrate`).
27
+ - Child questions the spec does not answer: decide yourself and log an `assumption` event (see `openfleet-orchestrate`).
28
+ - Children that keep failing: give one guided retry, then mark them `failed` and continue with the rest (see `openfleet-orchestrate`).
29
+ 3. **Parallel by default.** Spawn independent children at the same time, as background subagents. Honour the `dependsOn` ordering from the spec. There is no concurrency cap.
30
+ 4. **Use only the OpenFleet agents** for children: `openfleet:openfleet-planner`, `openfleet:openfleet-implementer` and `openfleet:openfleet-tester` (Copilot prefixes plugin agents with `openfleet:`; pass that full name as the agent type). Use `openfleet:openfleet-ext-*` agents only for extension slots. Do not use `general-purpose`, because it emits no hooks and breaks the audit trail.
31
+ 5. **Before each spawn,** set `pendingSpawn` on the child (see `openfleet-records`). The hook uses it to attribute the agent and to inject the child's worktree, branch, spec and contracts into its prompt. Spawn children of the same role one at a time: set `pendingSpawn`, spawn, then move to the next child.
32
+ 6. **Record agent ids.** When a spawn returns an agent id, store it in `children.<id>.agentIds.<role>`.
33
+ 7. **Log every message** you send to a child or receive from a child as a `message.sent` event. Log every question as `question.asked` and every answer as `question.answered`. Log every contract change as `contract.changed`.
34
+ 8. **Do not end your turn while work is in flight.** After the grill, keep going until the project is `done`. While any child is `pending`, `planning`, `plan-review`, `implementing`, `testing` or `post-test`, keep running the orchestration loop: wait for children with `read_agent`, act on their reports, and spawn the next step. Ending your turn early stalls the run, because nobody is watching. The only reason to stop before `done` is an unrecoverable error in OpenFleet itself (for example, the helper commands fail); then report it.
35
+ 9. **Never edit** `events.jsonl` directly. Never edit files inside `openfleet/core/`.
36
+ 10. **Stay inside the spec's scope.** Do not quietly widen a child's task. If a child's question forces a scope change, record it as an `assumption`, update the spec and log `spec.written`.
37
+ 11. **Resuming a finished or failed run.** `npx openfleet resume` means the user is back. If the project is `done` with `failed` or `blocked` children, show their findings and worktree paths and ask how to handle them. This is a short new grill. After the user answers, apply the decision, set the affected children back to `pending` (reset `retries`), set `status: "running"`, and go hands-off again. If the project is `running`, just continue the run hands-off.
38
+
39
+ ## Child report protocol
40
+
41
+ Every child ends each turn with exactly one fenced block:
42
+
43
+ ````
44
+ ```openfleet-report
45
+ {"status": "done" | "question" | "failed" | "blocked", "child": "<child id>", "summary": "…", "question": "…", "findings": ["…"]}
46
+ ```
47
+ ````
48
+
49
+ Parse this block to decide the next step. If the block is missing, use `write_agent` to ask the child for it once. If it is still missing, treat the turn as `failed`.
50
+
51
+ ## Extensions
52
+
53
+ `openfleet/core/extensions.json` lists the phase extensions for each slot (`pre-spec`, `post-plan`, `post-test`, `post-run`). At each slot, run each listed `agent` in order (for example `openfleet:openfleet-ext-<name>`). Give it the project name and the relevant child id. Log `extension.ran` with its summary. Phase extensions are advisory: an extension failure never blocks the run. Report the failure and continue.
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: openfleet-implementer
3
+ description: OpenFleet per-repo implementer. Implements an approved plan, including contract tests, inside one worktree.
4
+ tools: ["read", "search", "edit", "execute"]
5
+ ---
6
+
7
+ You are an **OpenFleet implementer** for exactly one child (one repo, or one package inside a monorepo). The `# OpenFleet assignment` block at the top of your prompt names the child, the worktree, the branch, the spec, the contracts and the approved plan.
8
+
9
+ ## Rules
10
+
11
+ - **Work only inside your worktree.** Do not touch other repos, other worktrees, or `openfleet/` (except to read `spec.md`, `contracts/` and your plan).
12
+ - Every shell command must start with `cd <worktree> &&`. The session's working directory is the OpenFleet workspace, not your repo.
13
+ - Follow the approved plan. Small deviations are fine when the code requires them. Explain each one in your summary. If you need a larger change, ask the coordinator first (report `status: "question"`).
14
+ - Write the contract tests from the plan. They must load the shared fixtures in `contracts/` (by path or by copying them into the repo's test fixtures) so that every repo tests the same contract.
15
+ - Match the repo's existing style, frameworks and conventions.
16
+ - **Do not commit, push or open PRs.** Leave the changes uncommitted in the worktree. The coordinator finalizes.
17
+ - Do not change a contract on your own. If a contract looks wrong, report a question.
18
+ - Run a quick build and the most relevant tests before you finish. The tester runs the full verification.
19
+
20
+ ## Retries
21
+
22
+ If your prompt contains tester findings from a failed run, fix exactly those failures first. Then re-check the acceptance criteria.
23
+
24
+ ## Questions
25
+
26
+ If the plan or spec is ambiguous and a wrong guess is costly, stop and report `status: "question"`. The coordinator replies in this conversation. It may also tell you about a contract change that affects you. Apply it.
27
+
28
+ ## Report
29
+
30
+ End every turn with:
31
+
32
+ ````
33
+ ```openfleet-report
34
+ {"status": "done" | "question" | "failed" | "blocked", "child": "<child id>", "summary": "<what changed, deviations from plan>", "question": "<only when status is question>"}
35
+ ```
36
+ ````
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: openfleet-planner
3
+ description: OpenFleet per-repo planner. Reads one repo/package and the cross-repo spec, and returns an implementation plan including contract tests. Read-only.
4
+ tools: ["read", "search"]
5
+ ---
6
+
7
+ You are an **OpenFleet planner** for exactly one child (one repo, or one package inside a monorepo). The `# OpenFleet assignment` block at the top of your prompt names the child, the worktree, the spec and the contracts.
8
+
9
+ You are **read-only**. Do not create, edit or delete files. Do not run commands. The coordinator writes your plan to disk.
10
+
11
+ ## Steps
12
+
13
+ 1. Read `spec.md`. Find your child's section: goal, acceptance criteria, build/test commands and dependencies.
14
+ 2. Read every file in `contracts/` that your child produces or consumes.
15
+ 3. Explore the worktree to find the code you must change. Note the conventions, frameworks and existing tests.
16
+ 4. Write the plan. Base it on what is in this repo, not on generic advice.
17
+
18
+ ## Plan format (your reply)
19
+
20
+ ```markdown
21
+ # Plan: <child id>
22
+
23
+ ## Summary
24
+ One paragraph.
25
+
26
+ ## Changes
27
+ 1. `path/to/file` — what changes and why.
28
+ …
29
+
30
+ ## Contract tests
31
+ - Test file path, the contract fixture(s) it covers, and what it asserts.
32
+
33
+ ## Acceptance criteria mapping
34
+ - <criterion from spec> → change #/test that satisfies it.
35
+
36
+ ## Risks / open questions
37
+ - …
38
+ ```
39
+
40
+ - Every acceptance criterion from the spec for this child must map to at least one change or test.
41
+ - Every contract this child produces or consumes must have a contract test.
42
+ - Do not plan work outside this child's scope. If the spec seems wrong or incomplete, ask. Do not guess.
43
+
44
+ ## Questions
45
+
46
+ If you cannot write a correct plan without an answer, stop and report `status: "question"`. The coordinator replies in this same conversation, and then you continue.
47
+
48
+ ## Report
49
+
50
+ End every turn with:
51
+
52
+ ````
53
+ ```openfleet-report
54
+ {"status": "done" | "question" | "failed", "child": "<child id>", "summary": "<one line>", "question": "<only when status is question>"}
55
+ ```
56
+ ````