@gajae-code/coding-agent 0.1.1 → 0.1.3

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 (41) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/dist/types/config/model-registry.d.ts +8 -0
  3. package/dist/types/config/model-resolver.d.ts +4 -1
  4. package/dist/types/gjc-runtime/team-runtime.d.ts +5 -0
  5. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +26 -0
  6. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +44 -0
  7. package/dist/types/goals/tools/goal-tool.d.ts +4 -4
  8. package/dist/types/hooks/skill-state.d.ts +3 -0
  9. package/dist/types/modes/components/model-selector.d.ts +5 -7
  10. package/dist/types/modes/interactive-mode.d.ts +1 -0
  11. package/dist/types/sdk.d.ts +2 -4
  12. package/dist/types/session/agent-session.d.ts +3 -9
  13. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +28 -0
  14. package/package.json +13 -9
  15. package/src/config/model-registry.ts +45 -0
  16. package/src/config/model-resolver.ts +5 -1
  17. package/src/defaults/gjc/skills/deep-interview/SKILL.md +30 -30
  18. package/src/defaults/gjc/skills/team/SKILL.md +1 -0
  19. package/src/defaults/gjc/skills/ultragoal/SKILL.md +51 -21
  20. package/src/gjc-runtime/team-runtime.ts +80 -1
  21. package/src/gjc-runtime/ultragoal-guard.ts +239 -0
  22. package/src/gjc-runtime/ultragoal-runtime.ts +318 -4
  23. package/src/goals/tools/goal-tool.ts +10 -4
  24. package/src/hooks/native-skill-hook.ts +26 -0
  25. package/src/hooks/skill-state.ts +59 -0
  26. package/src/main.ts +2 -17
  27. package/src/modes/components/model-selector.ts +225 -33
  28. package/src/modes/controllers/selector-controller.ts +16 -3
  29. package/src/modes/interactive-mode.ts +34 -22
  30. package/src/modes/prompt-action-autocomplete.ts +40 -15
  31. package/src/sdk.ts +3 -1
  32. package/src/session/agent-session.ts +40 -4
  33. package/src/setup/model-onboarding-guidance.ts +5 -3
  34. package/src/skill-state/deep-interview-mutation-guard.ts +303 -0
  35. package/src/slash-commands/builtin-registry.ts +130 -11
  36. package/src/tools/ask.ts +55 -17
  37. package/src/tools/ast-edit.ts +7 -0
  38. package/src/tools/bash.ts +2 -1
  39. package/src/tools/gh.ts +37 -9
  40. package/src/tools/image-gen.ts +19 -10
  41. package/src/tools/path-utils.ts +1 -0
@@ -60,11 +60,11 @@ Inspired by the [Ouroboros project](https://github.com/Q00/ouroboros) which demo
60
60
 
61
61
  ## Native Plugin Invocation Guard (Issue #3030)
62
62
 
63
- If this raw bundled skill is loaded by GJC's native skill loader through `/gajae-code:deep-interview` or `Skill("gajae-code:deep-interview")`, do not treat that path as permission to skip rendered GJC setup. The user-facing invocation is `/skill:deep-interview`; do not recommend or advertise `/deep-interview` or `/gajae-code:deep-interview` as the deep-interview entrypoint. Regardless of invocation path, Phase 0 below remains blocking and must resolve `gjc.deepInterview.ambiguityThreshold` from settings before any announcement, state write, question, or ambiguity score.
63
+ If this raw bundled skill is loaded by GJC's native skill loader through `/skill:deep-interview` or `gjc deep-interview`, do not treat that path as permission to skip rendered GJC setup. The user-facing invocation is `/skill:deep-interview`; do not recommend or advertise deprecated aliases as the deep-interview entrypoint. Regardless of invocation path, Phase 0 below remains blocking and must resolve `gjc.deepInterview.ambiguityThreshold` from settings before any announcement, state write, question, or ambiguity score.
64
64
 
65
65
  ## Phase 0: Resolve Ambiguity Threshold (blocking prerequisite)
66
66
 
67
- Complete this phase before Phase 1, before brownfield exploration, before `state_write`, before Round 0, and before any ambiguity scoring. Do not continue if the resolved threshold and source are unknown.
67
+ Complete this phase before Phase 1, before brownfield exploration, before GJC state persistence, before Round 0, and before any ambiguity scoring. Do not continue if the resolved threshold and source are unknown.
68
68
 
69
69
  1. **Read threshold settings in precedence order**:
70
70
  - User settings: `[$GJC_CONFIG_DIR|~/.gjc]/settings.json`
@@ -81,7 +81,7 @@ Deep Interview threshold: <resolvedThresholdPercent> (source: <resolvedThreshold
81
81
 
82
82
  4. **Carry threshold source forward mechanically**:
83
83
  - Substitute `<resolvedThreshold>`, `<resolvedThresholdPercent>`, and `<resolvedThresholdSource>` throughout the remaining instructions before continuing.
84
- - Include `threshold_source` in the first `state_write(mode="deep-interview")` state payload and preserve it on later state updates.
84
+ - Include `threshold_source` in the first `gjc state write` payload (or `.gjc/state/` state file) and preserve it on later state updates.
85
85
  - Include both threshold and source in the final spec metadata.
86
86
 
87
87
  ## Phase 1: Initialize
@@ -106,9 +106,9 @@ Deep Interview threshold: <resolvedThresholdPercent> (source: <resolvedThreshold
106
106
  - Wait until the summary exists before ambiguity scoring, weakest-dimension selection, brownfield exploration prompts, or any bridge to `ralplan`, `execution`, `execution`, or `team`.
107
107
  3.7. **Artifact path discipline**:
108
108
  - Final specs MUST be written to `.gjc/specs/deep-interview-{slug}.md` exactly.
109
- - Ephemeral interview artifacts (scoring scratchpads, prompt-safe summaries, transient queues, resume metadata) belong in `.gjc/state/` or in `state_write` state, never in the repo root or arbitrary working files.
109
+ - Ephemeral interview artifacts (scoring scratchpads, prompt-safe summaries, transient queues, resume metadata) belong in `.gjc/state/` or via `gjc state write` when available, never in the repo root or arbitrary working files.
110
110
 
111
- 4. **Initialize state** via `state_write(mode="deep-interview")`:
111
+ 4. **Initialize state** via `gjc state write` when available, otherwise by writing the deep-interview state under `.gjc/state/`:
112
112
 
113
113
  ```json
114
114
  {
@@ -226,7 +226,7 @@ Build the question generation prompt with:
226
226
  - Brownfield codebase context (if applicable), summarized to cited paths/symbols/patterns instead of raw dumps
227
227
  - Locked topology from Round 0, including active components, deferred components, prior per-component scores, and `last_targeted_component_id`
228
228
 
229
- If any prompt input is too large, summarize it first and then continue from the summary. Do not ask the next `AskUserQuestion`, score ambiguity, or hand off to execution from an over-budget raw transcript.
229
+ If any prompt input is too large, summarize it first and then continue from the summary. Do not ask the next the `ask` tool, score ambiguity, or hand off to execution from an over-budget raw transcript.
230
230
 
231
231
  **Question targeting strategy:**
232
232
  - Identify the active component + dimension pair with the LOWEST clarity score across the locked topology
@@ -247,7 +247,7 @@ If any prompt input is too large, summarize it first and then continue from the
247
247
 
248
248
  ### Step 2b: Ask the Question
249
249
 
250
- Use `AskUserQuestion` with the generated question. Present it clearly with the current ambiguity context:
250
+ Use the `ask` tool with the generated question. Present it clearly with the current ambiguity context:
251
251
 
252
252
  ```
253
253
  Round {n} | Component: {target_component_name} | Targeting: {weakest_dimension} | Why now: {one_sentence_targeting_rationale} | Ambiguity: {score}%
@@ -354,7 +354,7 @@ Round {n} complete.
354
354
 
355
355
  ### Step 2e: Update State
356
356
 
357
- Update interview state with the new round, global scores, per-component `topology.components[].clarity_scores`, `topology.components[].weakest_dimension`, ontology snapshot, and `topology.last_targeted_component_id` via `state_write`.
357
+ Update interview state with the new round, global scores, per-component `topology.components[].clarity_scores`, `topology.components[].weakest_dimension`, ontology snapshot, and `topology.last_targeted_component_id` via `gjc state write`.
358
358
 
359
359
  ### Step 2f: Check Soft Limits
360
360
 
@@ -388,7 +388,7 @@ When ambiguity ≤ threshold (or hard cap / early exit):
388
388
  1. **Generate the specification** using opus model with the prompt-safe transcript. If the full interview transcript or initial context is too large, include the summary plus all concrete decisions, acceptance criteria, unresolved gaps, and ontology snapshots; never overflow the prompt with raw oversized context.
389
389
  2. **Write to file**: `.gjc/specs/deep-interview-{slug}.md`
390
390
  - Always use this exact final spec path. Do not write temporary working files to the repo root or other ad hoc paths; repos may allowlist `.gjc/` for planning artifacts while protecting product branches.
391
- - For ephemeral artifacts during interview rounds (for example scoring intermediate results, prompt-safe summaries, question queues, or resume metadata), use `.gjc/state/` or in-memory state via `state_write`.
391
+ - For ephemeral artifacts during interview rounds (for example scoring intermediate results, prompt-safe summaries, question queues, or resume metadata), use `.gjc/state/` or in-memory state via `gjc state write`.
392
392
  - Persist the final `spec_path` in state when available so downstream skills and resumed sessions can pass the artifact path explicitly.
393
393
 
394
394
  Spec structure:
@@ -483,9 +483,9 @@ Spec structure:
483
483
 
484
484
  ## Phase 5: Execution Bridge
485
485
 
486
- **Research workflow override:** if `--research-setup` is active, skip the standard execution options below. The only valid bridge is the `Skill("gajae-code:research workflow")` handoff described above. The `gjc research workflow` CLI is a hard-deprecated shim and must not be used for execution.
486
+ **Research workflow override:** if `--research-setup` is active, skip the standard execution options below and write a pending-approval spec that names research setup as an unresolved follow-up. Do not invoke deprecated research workflow shims.
487
487
 
488
- After the spec is written, mark it `pending approval` and present execution options via `AskUserQuestion`. Until the user selects an execution option, the deep-interview module MUST NOT run mutation-oriented shell commands, edit source files, commit, push, open PRs, invoke execution skills, or delegate implementation tasks:
488
+ After the spec is written, mark it `pending approval` and present execution options via the `ask` tool. Until the user selects an execution option, the deep-interview module MUST NOT run mutation-oriented shell commands, edit source files, commit, push, open PRs, invoke execution skills, or delegate implementation tasks:
489
489
 
490
490
  **Question:** "Your spec is ready (ambiguity: {score}%). How would you like to proceed?"
491
491
 
@@ -493,26 +493,26 @@ After the spec is written, mark it `pending approval` and present execution opti
493
493
 
494
494
  1. **Refine with ralplan consensus (Recommended)**
495
495
  - Description: "Consensus-refine this spec with Planner/Architect/Critic, then stop for explicit execution approval. Maximum quality."
496
- - Action: Only after the user selects this option, invoke `Skill("gajae-code:plan")` with `--consensus --direct` flags and the spec file path as context. The `--direct` flag skips the ralplan skill's interview phase (the deep interview already gathered requirements), while `--consensus` triggers the Planner/Architect/Critic loop. When consensus completes and produces a plan in `.gjc/plans/`, stop with that plan marked `pending approval`; do not automatically invoke execution or any other execution skill.
496
+ - Action: Only after the user selects this option, invoke `/skill:ralplan` or `gjc ralplan --consensus --direct` with the spec file path as context. The `--direct` flag skips the ralplan skill's interview phase (the deep interview already gathered requirements), while `--consensus` triggers the Planner/Architect/Critic loop. When consensus completes and produces a plan in `.gjc/plans/`, stop with that plan marked `pending approval`; do not automatically invoke execution or any other execution skill.
497
497
  - Pipeline: `deep-interview spec → explicit approval to refine → ralplan --consensus --direct → pending approval → separate execution approval`
498
498
 
499
499
  2. **Execute with team**
500
500
  - Description: "Full autonomous pipeline — planning, parallel implementation, QA, validation. Faster but without consensus refinement."
501
- - Action: Invoke `Skill("gajae-code:execution")` with the spec file path as context only after the user explicitly selects this execution option. The spec replaces execution's Phase 0 — execution starts at Phase 1 (Planning).
501
+ - Action: Invoke `/skill:team` or `gjc team` with the spec file path as context only after the user explicitly selects this execution option. The spec replaces team planning input.
502
502
 
503
503
  3. **Execute with team**
504
504
  - Description: "Persistence loop with architect verification — keeps working until all acceptance criteria pass"
505
- - Action: Invoke `Skill("gajae-code:execution")` with the spec file path as the task definition.
505
+ - Action: Invoke `/skill:team` or `gjc team` with the spec file path as the task definition.
506
506
 
507
507
  4. **Execute with team**
508
508
  - Description: "N coordinated parallel agents — fastest execution for large specs"
509
- - Action: Invoke `Skill("gajae-code:team")` with the spec file path as the shared plan.
509
+ - Action: Invoke `/skill:team` or `gjc team` with the spec file path as the shared plan.
510
510
 
511
511
  5. **Refine further**
512
512
  - Description: "Continue interviewing to improve clarity (current: {score}%)"
513
513
  - Action: Return to Phase 2 interview loop.
514
514
 
515
- **IMPORTANT:** On explicit execution selection, **MUST** invoke the chosen skill via `Skill()`. Do NOT implement directly. The deep-interview agent is a requirements agent, not an execution agent. If oversized initial context was summarized, pass the spec and prompt-safe summary forward, not the raw oversized source material. Without explicit execution selection, stop with the spec marked `pending approval`.
515
+ **IMPORTANT:** On explicit execution selection, **MUST** use the chosen public GJC workflow entrypoint (`/skill:ralplan`, `/skill:team`, `gjc ralplan`, or `gjc team`). Do NOT implement directly. The deep-interview agent is a requirements agent, not an execution agent. If oversized initial context was summarized, pass the spec and prompt-safe summary forward, not the raw oversized source material. Without explicit execution selection, stop with the spec marked `pending approval`.
516
516
 
517
517
  ### Approval-Gated Refinement Path (Recommended)
518
518
 
@@ -541,14 +541,14 @@ Skipping any stage is possible but reduces quality assurance:
541
541
  </Steps>
542
542
 
543
543
  <Tool_Usage>
544
- - Use `AskUserQuestion` for each interview question — provides clickable UI with contextual options
545
- - Preserve the AskUserQuestion path for GJC-native interaction; do not introduce GJC-only structured-question transport into this skill
546
- - Use `Task(subagent_type="gajae-code:explore", model="haiku")` for brownfield codebase exploration (run BEFORE asking user about codebase)
544
+ - Use the `ask` tool for each interview question — provides clickable UI with contextual options
545
+ - Preserve the GJC `ask` tool path for native interaction; do not introduce parallel structured-question transport into this skill
546
+ - Use `read/search/find exploration or a bounded read-only planner/architect subagent` for brownfield codebase exploration (run BEFORE asking user about codebase)
547
547
  - Use opus model (temperature 0.1) for ambiguity scoring — consistency is critical
548
548
  - Round 0 topology confirmation happens before ambiguity scoring; Phase 2 scoring must honor locked topology and rotate targeting across active components when more than one is present
549
- - Use `state_write` / `state_read` for interview state persistence; the initial and subsequent deep-interview state payloads must include `threshold_source` alongside `threshold`
550
- - Use `Write` tool to save the final spec to `.gjc/specs/deep-interview-{slug}.md` exactly; use `.gjc/state/` or `state_write` for ephemeral artifacts
551
- - Use `Skill()` to bridge to execution modes only after explicit execution approval — never implement directly
549
+ - Use `gjc state write` / `gjc state read` for interview state persistence; the initial and subsequent deep-interview state payloads must include `threshold_source` alongside `threshold`
550
+ - Use the `write` tool to save the final spec to `.gjc/specs/deep-interview-{slug}.md` exactly; use `.gjc/state/` or `gjc state write` for ephemeral artifacts
551
+ - Use public GJC workflow entrypoints to bridge to ralplan/team only after explicit execution approval — never implement directly
552
552
  - Challenge agent modes are prompt injections, not separate agent spawns
553
553
  </Tool_Usage>
554
554
 
@@ -671,12 +671,12 @@ Why bad: 45% ambiguity means nearly half the requirements are unclear. The mathe
671
671
  - [ ] Ambiguity score displayed after every round
672
672
  - [ ] Every round explicitly names the weakest dimension and why it is the next target
673
673
  - [ ] Challenge agents activated at correct thresholds (round 4, 6, 8)
674
- - [ ] Spec file written to `.gjc/specs/deep-interview-{slug}.md` exactly; ephemeral artifacts stayed under `.gjc/state/` or `state_write`
674
+ - [ ] Spec file written to `.gjc/specs/deep-interview-{slug}.md` exactly; ephemeral artifacts stayed under `.gjc/state/` or `gjc state write`
675
675
  - [ ] Spec includes: topology, goal, constraints, acceptance criteria, clarity breakdown, transcript
676
- - [ ] Execution bridge presented via AskUserQuestion
677
- - [ ] Selected execution mode invoked via Skill() only after explicit execution approval (never direct implementation)
676
+ - [ ] Execution bridge presented via the `ask` tool
677
+ - [ ] Selected execution mode invoked via public GJC workflow entrypoint only after explicit execution approval (never direct implementation)
678
678
  - [ ] If 3-stage pipeline selected: ralplan --consensus --direct invoked, then stopped with the consensus plan marked `pending approval` until the user explicitly approves execution
679
- - [ ] State cleaned up after execution handoff
679
+ - [ ] State cleaned up after approved workflow handoff
680
680
  - [ ] Brownfield confirmation questions cite repo evidence (file/path/pattern) before asking the user to decide
681
681
  - [ ] Scope-fuzzy tasks can trigger ontology-style questioning to stabilize the core entity before feature elaboration
682
682
  - [ ] Round 0 topology gate completed before ambiguity scoring and persisted `topology.confirmed_at`
@@ -712,17 +712,17 @@ Optional settings in `.gjc/settings.json`:
712
712
 
713
713
  If interrupted, run `/skill:deep-interview` again. The skill reads state from `.gjc/state/deep-interview-state.json` and resumes from the last completed round.
714
714
 
715
- ## Integration with Staged execution
715
+ ## Integration with staged team routing
716
716
 
717
717
  When team receives a vague input (no file paths, function names, or concrete anchors), it can redirect to deep-interview:
718
718
 
719
719
  ```
720
720
  User: "team build me a thing"
721
- Staged execution: "Your request is quite open-ended. Would you like to run a deep interview first to clarify requirements?"
721
+ Team routing: "Your request is quite open-ended. Would you like to run a deep interview first to clarify requirements?"
722
722
  [Yes, interview first] [No, expand directly]
723
723
  ```
724
724
 
725
- If the user chooses interview, execution invokes `/skill:deep-interview`. When the interview completes and the user selects "Execute with team", the spec becomes Phase 0 output and execution continues from Phase 1 (Planning).
725
+ If the user chooses interview, team routing invokes `/skill:deep-interview`. When the interview completes and the user selects "Execute with team", the spec becomes Phase 0 output and team proceeds from the approved spec.
726
726
 
727
727
  ## Approval-Gated Pipeline: deep-interview → ralplan → pending approval
728
728
 
@@ -753,7 +753,7 @@ The recommended refinement path chains clarity and feasibility gates, then stops
753
753
 
754
754
  ## Integration with Ralplan Gate
755
755
 
756
- The ralplan pre-execution gate already redirects vague prompts to planning. Deep interview can serve as an alternative redirect target for prompts that are too vague even for ralplan:
756
+ The ralplan pre-approval gate already redirects vague prompts to planning. Deep interview can serve as an alternative redirect target for prompts that are too vague even for ralplan:
757
757
 
758
758
  ```
759
759
  Vague prompt → ralplan gate → deep-interview (if extremely vague) → ralplan (with clear spec) → pending approval → explicitly approved execution
@@ -155,6 +155,7 @@ Important:
155
155
 
156
156
  - Leader remains in the existing left pane.
157
157
  - Worker panes are independent full GJC worker CLI sessions on the right side of a leader-left/worker-right split.
158
+ - Worker CLI selection is teammate-only: `GJC_TEAM_WORKER_CLI` and `GJC_TEAM_WORKER_CLI_MAP` accept only `auto` or `gjc`; legacy/provider values such as `codex`, `claude`, or `gemini` are rejected before launch.
158
159
  - The worker may run in a dedicated git worktree (`gjc team --worktree[=<name>]`) while sharing the team state root.
159
160
  - `shutdown` kills only the recorded worker pane after confirming it still belongs to the stored tmux target and is not the leader pane. It never kills the tmux session.
160
161
 
@@ -65,14 +65,14 @@ Loop until `gjc ultragoal status` reports all goals complete:
65
65
  4. If no active GJC goal exists, call `create_goal({"objective":"<printed payload objective>"})` with the printed payload. In aggregate mode, if the same aggregate objective is already active, continue the current GJC story without creating a new GJC goal.
66
66
  5. Complete the current GJC story only.
67
67
  6. Run a completion audit against the story objective and real artifacts/tests.
68
- 7. In aggregate mode, do **not** call `update_goal` for intermediate stories; checkpoint with a fresh `get_goal({})` snapshot whose aggregate objective is still `active`. On the final story only, first run the mandatory final cleanup/review gate below; call `update_goal({"status":"complete"})` only after that gate is clean, then call `get_goal({})` again for a fresh `complete` snapshot.
69
- 8. Checkpoint the durable ledger with that snapshot. Intermediate aggregate checkpoints use only `--gjc-goal-json`; final clean checkpoints also require `--quality-gate-json`:
70
- `gjc ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --gjc-goal-json <get_goal-json-or-path> [--quality-gate-json <quality-gate-json-or-path>]`
68
+ 7. Before any `--status complete` checkpoint, run the mandatory final cleanup/review gate below. In aggregate mode, do **not** call `update_goal` for intermediate stories; checkpoint with a fresh `get_goal({})` snapshot whose aggregate objective is still `active`. On the final story only, call `update_goal({"status":"complete"})` after the gate is clean, then call `get_goal({})` again for a fresh `complete` snapshot.
69
+ 8. Checkpoint the durable ledger with that snapshot. Complete checkpoints require `--quality-gate-json`; the runtime hook rejects closure without a clean architect review:
70
+ `gjc ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --gjc-goal-json <get_goal-json-or-path> --quality-gate-json <quality-gate-json-or-path>`
71
71
  9. If blocked or failed, checkpoint failure:
72
72
  `gjc ultragoal checkpoint --goal-id <id> --status failed --evidence "<blocker/evidence>"`
73
- 10. For legacy per-story completed-goal blockers, preserve the non-terminal blocker with:
73
+ 11. For legacy per-story completed-goal blockers, preserve the non-terminal blocker with:
74
74
  `gjc ultragoal checkpoint --goal-id <id> --status blocked --evidence "<completed legacy GJC goal blocks create_goal in this thread>" --gjc-goal-json <get_goal-json-or-path>`
75
- 11. Resume failed goals with `gjc ultragoal complete-goals --retry-failed`.
75
+ 12. Resume failed goals with `gjc ultragoal complete-goals --retry-failed`.
76
76
 
77
77
  ## Dynamic steering
78
78
 
@@ -120,6 +120,8 @@ If an Ultragoal request has no approved plan or consensus artifact, run `ralplan
120
120
 
121
121
  The Ultragoal leader owns `.gjc/ultragoal/goals.json` and `.gjc/ultragoal/ledger.jsonl`. Role agents return implementation/review evidence; they do not checkpoint Ultragoal or mutate goal state.
122
122
 
123
+ For large subgoals with independent slices, the Ultragoal leader must spawn parallel `executor` subagents instead of doing serial solo work. Split only cleanly separable files/surfaces, give each executor bounded targets and acceptance criteria, and keep checkpoint ownership in the leader. Use `architect` / `critic` review lanes after integration; do not let worker agents mutate `.gjc/ultragoal` or call goal tools.
124
+
123
125
  ## Use Ultragoal and Team together
124
126
 
125
127
  Use ultragoal and team together for a durable Ultragoal story that benefits from one visible tmux worker session. Ultragoal remains leader-owned: `.gjc/ultragoal/goals.json` stores the story plan and `.gjc/ultragoal/ledger.jsonl` stores checkpoints. Team is the single-worker tmux execution engine and returns task/evidence status to the leader.
@@ -132,9 +134,9 @@ gjc ultragoal checkpoint --goal-id <id> --status complete --evidence "<team evid
132
134
 
133
135
  Workers do not own ultragoal goal state, do not create worker ultragoal ledgers, and do not checkpoint Ultragoal. Team launch remains explicit; Ultragoal does not auto-launch Team and performs no hidden goal mutation.
134
136
 
135
- ## Mandatory final cleanup and review gate
137
+ ## Mandatory completion cleanup and review gate
136
138
 
137
- The final ultragoal story is not complete until the active agent has run the final quality gate:
139
+ An ultragoal story cannot be checkpointed `complete` until the active agent has run the quality gate:
138
140
 
139
141
  1. Run targeted verification for the story.
140
142
  2. Run a cleanup/refactor review pass on changed files only; if there are no relevant edits, the cleaner still runs and records a passed/no-op report.
@@ -142,28 +144,56 @@ The final ultragoal story is not complete until the active agent has run the fin
142
144
  4. Run a final code review pass. Clean means `codeReview.recommendation: "APPROVE"` and `codeReview.architectStatus: "CLEAR"`; `COMMENT`, `WATCH`, `REQUEST CHANGES`, and `BLOCK` are non-clean.
143
145
  5. If review is non-clean, do **not** call `update_goal`. Record durable blocker work instead:
144
146
 
147
+ 1. Run targeted implementation verification for the story.
148
+ 2. Delegate an `architect` review covering all three lanes:
149
+ - architecture-side: system boundaries, layering, data/control flow, operational risks.
150
+ - product-side: user-visible behavior, acceptance criteria, edge cases, regressions.
151
+ - code-side: maintainability, tests, integration points, and unsafe shortcuts.
152
+ 3. Delegate an `executor` QA/red-team lane to build and run the e2e/read-teaming QA suite appropriate for the story. This lane must try to break the change, not just confirm the happy path.
153
+ 4. If any lane finds an issue, do **not** checkpoint `complete` and do **not** call `update_goal`. Record durable blocker work instead:
145
154
  ```sh
146
- gjc ultragoal record-review-blockers --goal-id <id> --title "Resolve final review blockers" --objective "<blocker-resolution objective>" --evidence "<review findings>" --gjc-goal-json <active-get-goal-json-or-path>
155
+ gjc ultragoal record-review-blockers --goal-id <id> --title "Resolve verification blockers" --objective "<blocker-resolution objective>" --evidence "<architect/executor findings>" --gjc-goal-json <active-get-goal-json-or-path>
147
156
  ```
157
+ 5. Complete or steer through the blocker story, then rerun the full blocking verification loop. Repeat until all verifier lanes are clean.
158
+ 6. Only after the loop is clean, checkpoint the story as complete with a structured quality gate. The checkpoint creates a receipt; `goals.json.status` alone is not proof. Aggregate direct completion requires a fresh final aggregate receipt covering the full required-goal set before `update_goal({"status":"complete"})` is allowed.
148
159
 
149
- This marks the current story `review_blocked`, appends a pending blocker-resolution story, keeps the GJC goal active, and lets `gjc ultragoal complete-goals` start the blocker next. In legacy per-story mode, the blocker may need an available GJC goal context because the old per-story GJC goal remains active/incomplete.
150
-
151
- 6. If review is clean, call `update_goal({"status":"complete"})`, call `get_goal({})`, and checkpoint with a structured final gate:
152
-
153
- ```sh
154
- gjc ultragoal checkpoint --goal-id <id> --status complete --evidence "<tests/files/review evidence>" --gjc-goal-json <fresh-complete-get-goal-json-or-path> --quality-gate-json <quality-gate-json-or-path>
155
- ```
156
-
157
- `--quality-gate-json` must include:
160
+ The native `checkpoint --status complete` command rejects missing or shallow gates. `--quality-gate-json` must include:
158
161
 
159
162
  ```json
160
163
  {
161
- "aiSlopCleaner": { "status": "passed", "evidence": "cleaner report" },
162
- "verification": { "status": "passed", "commands": ["npm test"], "evidence": "post-cleaner verification" },
163
- "codeReview": { "recommendation": "APPROVE", "architectStatus": "CLEAR", "evidence": "final review synthesis" }
164
+ "architectReview": {
165
+ "architectureStatus": "CLEAR",
166
+ "productStatus": "CLEAR",
167
+ "codeStatus": "CLEAR",
168
+ "recommendation": "APPROVE",
169
+ "evidence": "architect review synthesis with architecture/product/code coverage",
170
+ "commands": ["architect review command or agent evidence id"],
171
+ "blockers": []
172
+ },
173
+ "executorQa": {
174
+ "status": "passed",
175
+ "e2eStatus": "passed",
176
+ "redTeamStatus": "passed",
177
+ "evidence": "executor-built e2e and red-team QA commands/results",
178
+ "e2eCommands": ["bun test:e2e"],
179
+ "redTeamCommands": ["bun test:red-team"],
180
+ "blockers": []
181
+ },
182
+ "iteration": {
183
+ "status": "passed",
184
+ "evidence": "blockers were absent or resolved and the full verification loop was rerun cleanly",
185
+ "fullRerun": true,
186
+ "rerunCommands": ["bun test:e2e", "bun test:red-team"],
187
+ "blockers": []
188
+ }
164
189
  }
165
190
  ```
166
191
 
192
+ Receipts are freshness-scoped:
193
+ - Per-goal receipts remain fresh for their target goal unless that goal, its blocker metadata, or its supersession metadata changes.
194
+ - Normal later `goal_started` or clean receipt-backed `goal_checkpointed` events for other goals do not stale older per-goal receipts.
195
+ - Appending required goals or changing final required-goal state stales final aggregate receipts. Final aggregate completion requires a fresh final aggregate receipt proving no incomplete, blocked, or `review_blocked` required goals remain.
196
+
167
197
  ## Constraints
168
198
 
169
199
  - The shell command cannot directly invoke interactive `/goal`; it emits a model-facing handoff for the active GJC agent.
@@ -171,6 +201,6 @@ The final ultragoal story is not complete until the active agent has run the fin
171
201
  - After a completed aggregate ultragoal run, clear the goal manually with `/goal clear` before starting another ultragoal run in the same session/thread.
172
202
  - Never call `create_goal` when `get_goal` reports a different active goal.
173
203
  - Never call `update_goal` unless the aggregate run or legacy per-story goal is actually complete.
174
- - In aggregate mode, intermediate story checkpoints require a matching `active` GJC goal snapshot; final story completion requires a matching `complete` snapshot after `update_goal`.
204
+ - In aggregate mode, intermediate story checkpoints require a matching `active` GJC goal snapshot; final story checkpoint also uses the active snapshot and creates the final aggregate receipt. Only after that receipt exists may `update_goal({"status":"complete"})` reconcile the inline goal state.
175
205
  - Completion checkpoints require read-only goal snapshot reconciliation: pass fresh `get_goal` JSON/path with `--gjc-goal-json`; shell commands and hooks must not mutate goal state.
176
206
  - Treat `ledger.jsonl` as the durable audit trail; checkpoint after every success or failure.
@@ -8,6 +8,11 @@ export type GjcWorkerStatusState = "idle" | "working" | "blocked" | "done" | "fa
8
8
 
9
9
  export const GJC_TEAM_DEFAULT_WORKERS = 3;
10
10
  export const GJC_TEAM_MAX_WORKERS = 20;
11
+ const GJC_TEAM_WORKER_CLI_ENV = "GJC_TEAM_WORKER_CLI";
12
+ const GJC_TEAM_WORKER_CLI_MAP_ENV = "GJC_TEAM_WORKER_CLI_MAP";
13
+
14
+ export type GjcTeamWorkerCli = "gjc";
15
+ type GjcTeamWorkerCliMode = "auto" | GjcTeamWorkerCli;
11
16
 
12
17
  export interface GjcTeamLeader {
13
18
  session_id: string;
@@ -75,6 +80,7 @@ export interface GjcTeamConfig {
75
80
  max_workers: number;
76
81
  state_root: string;
77
82
  worker_command: string;
83
+ worker_cli_plan: GjcTeamWorkerCli[];
78
84
  tmux_command: string;
79
85
  tmux_session: string;
80
86
  tmux_session_name: string;
@@ -159,6 +165,70 @@ export interface GjcTeamMailboxMessage {
159
165
  interface FsError {
160
166
  code?: string;
161
167
  }
168
+
169
+ function normalizeGjcTeamWorkerCliMode(
170
+ raw: string | undefined,
171
+ sourceEnv = GJC_TEAM_WORKER_CLI_ENV,
172
+ ): GjcTeamWorkerCliMode {
173
+ const normalized = String(raw ?? "auto")
174
+ .trim()
175
+ .toLowerCase();
176
+ if (normalized === "" || normalized === "auto") return "auto";
177
+ if (normalized === "gjc") return "gjc";
178
+ if (normalized === "codex" || normalized === "claude" || normalized === "gemini") {
179
+ throw new Error(`Unsupported ${sourceEnv} value "${raw}". GJC team launches GJC teammate sessions only.`);
180
+ }
181
+ throw new Error(`Invalid ${sourceEnv} value "${raw}". Expected: auto or gjc`);
182
+ }
183
+
184
+ export function resolveGjcTeamWorkerCli(env: NodeJS.ProcessEnv = process.env): GjcTeamWorkerCli {
185
+ const mode = normalizeGjcTeamWorkerCliMode(env[GJC_TEAM_WORKER_CLI_ENV]);
186
+ return mode === "auto" ? "gjc" : mode;
187
+ }
188
+
189
+ export function resolveGjcTeamWorkerCliPlan(
190
+ workerCount: number,
191
+ env: NodeJS.ProcessEnv = process.env,
192
+ ): GjcTeamWorkerCli[] {
193
+ if (!Number.isInteger(workerCount) || workerCount < 1) {
194
+ throw new Error(`workerCount must be >= 1 (got ${workerCount})`);
195
+ }
196
+ normalizeGjcTeamWorkerCliMode(env[GJC_TEAM_WORKER_CLI_ENV]);
197
+ const rawMap = String(env[GJC_TEAM_WORKER_CLI_MAP_ENV] ?? "").trim();
198
+ if (rawMap === "") {
199
+ const cli = resolveGjcTeamWorkerCli(env);
200
+ return Array.from({ length: workerCount }, () => cli);
201
+ }
202
+ const entries = rawMap.split(",").map(entry => entry.trim());
203
+ if (entries.length === 0 || entries.every(entry => entry.length === 0)) {
204
+ throw new Error(
205
+ `Invalid ${GJC_TEAM_WORKER_CLI_MAP_ENV} value "${env[GJC_TEAM_WORKER_CLI_MAP_ENV]}". Expected: auto or gjc`,
206
+ );
207
+ }
208
+ if (entries.some(entry => entry.length === 0)) {
209
+ throw new Error(
210
+ `Invalid ${GJC_TEAM_WORKER_CLI_MAP_ENV} value "${env[GJC_TEAM_WORKER_CLI_MAP_ENV]}". Empty entries are not allowed.`,
211
+ );
212
+ }
213
+ if (entries.length !== 1 && entries.length !== workerCount) {
214
+ throw new Error(
215
+ `Invalid ${GJC_TEAM_WORKER_CLI_MAP_ENV} length ${entries.length}; expected 1 or ${workerCount} comma-separated values.`,
216
+ );
217
+ }
218
+ const expanded = entries.length === 1 ? Array.from({ length: workerCount }, () => entries[0] ?? "") : entries;
219
+ return expanded.map(entry => {
220
+ const mode = normalizeGjcTeamWorkerCliMode(entry, GJC_TEAM_WORKER_CLI_MAP_ENV);
221
+ return mode === "auto" ? "gjc" : mode;
222
+ });
223
+ }
224
+
225
+ export function translateGjcWorkerLaunchArgsForCli(workerCli: GjcTeamWorkerCli, args: string[]): string[] {
226
+ if (workerCli !== "gjc") {
227
+ throw new Error(`Unsupported team worker CLI "${workerCli}". GJC team launches GJC teammate sessions only.`);
228
+ }
229
+ return [...args];
230
+ }
231
+
162
232
  interface GjcTmuxLeaderContext {
163
233
  sessionName: string;
164
234
  windowIndex: string;
@@ -341,6 +411,7 @@ async function readConfig(dir: string): Promise<GjcTeamConfig> {
341
411
  tmux_target: config.tmux_target ?? config.tmux_session ?? tmuxSessionName,
342
412
  leader_cwd: config.leader_cwd ?? config.leader.cwd,
343
413
  team_state_root: config.team_state_root ?? config.state_root,
414
+ worker_cli_plan: config.worker_cli_plan ?? Array.from({ length: config.worker_count }, () => "gjc"),
344
415
  };
345
416
  }
346
417
  async function readPhase(dir: string): Promise<GjcTeamPhase> {
@@ -1227,6 +1298,7 @@ export async function startGjcTeam(options: GjcTeamStartOptions): Promise<GjcTea
1227
1298
  const env = options.env ?? process.env;
1228
1299
  if (!Number.isInteger(options.workerCount) || options.workerCount < 1 || options.workerCount > GJC_TEAM_MAX_WORKERS)
1229
1300
  throw new Error(`invalid_team_worker_count:${options.workerCount}:expected_1_${GJC_TEAM_MAX_WORKERS}`);
1301
+ const workerCliPlan = resolveGjcTeamWorkerCliPlan(options.workerCount, env);
1230
1302
  const stateRoot = resolveGjcTeamStateRoot(cwd, env);
1231
1303
  const teamName = sanitizeName(options.teamName ?? makeTeamName(options.task, env));
1232
1304
  const displayName = sanitizeName(options.teamName ?? options.task).slice(0, 30) || teamName;
@@ -1256,6 +1328,7 @@ export async function startGjcTeam(options: GjcTeamStartOptions): Promise<GjcTea
1256
1328
  max_workers: GJC_TEAM_MAX_WORKERS,
1257
1329
  state_root: stateRoot,
1258
1330
  worker_command: resolveGjcWorkerCommand(cwd, env),
1331
+ worker_cli_plan: workerCliPlan,
1259
1332
  tmux_command: tmuxCommand,
1260
1333
  tmux_session: tmuxContext.sessionName,
1261
1334
  tmux_session_name: tmuxContext.sessionName,
@@ -1279,6 +1352,7 @@ export async function startGjcTeam(options: GjcTeamStartOptions): Promise<GjcTea
1279
1352
  tmux_session_name: config.tmux_session_name,
1280
1353
  tmux_target: config.tmux_target,
1281
1354
  worker_command: config.worker_command,
1355
+ worker_cli_plan: config.worker_cli_plan,
1282
1356
  tmux_command: config.tmux_command,
1283
1357
  leader: config.leader,
1284
1358
  workers: config.workers,
@@ -1296,7 +1370,12 @@ export async function startGjcTeam(options: GjcTeamStartOptions): Promise<GjcTea
1296
1370
  await appendTelemetry(dir, {
1297
1371
  type: "team_runtime",
1298
1372
  message: "Native gjc team runtime initialized",
1299
- data: { state_root: stateRoot, worker_command: config.worker_command, workspace_mode: config.workspace_mode },
1373
+ data: {
1374
+ state_root: stateRoot,
1375
+ worker_command: config.worker_command,
1376
+ worker_cli_plan: workerCliPlan,
1377
+ workspace_mode: config.workspace_mode,
1378
+ },
1300
1379
  });
1301
1380
  let tmuxWorkers: GjcTeamWorker[];
1302
1381
  try {