@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.
- package/CHANGELOG.md +16 -1
- package/dist/types/config/model-registry.d.ts +8 -0
- package/dist/types/config/model-resolver.d.ts +4 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +26 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +44 -0
- package/dist/types/goals/tools/goal-tool.d.ts +4 -4
- package/dist/types/hooks/skill-state.d.ts +3 -0
- package/dist/types/modes/components/model-selector.d.ts +5 -7
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -4
- package/dist/types/session/agent-session.d.ts +3 -9
- package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +28 -0
- package/package.json +13 -9
- package/src/config/model-registry.ts +45 -0
- package/src/config/model-resolver.ts +5 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +30 -30
- package/src/defaults/gjc/skills/team/SKILL.md +1 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +51 -21
- package/src/gjc-runtime/team-runtime.ts +80 -1
- package/src/gjc-runtime/ultragoal-guard.ts +239 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +318 -4
- package/src/goals/tools/goal-tool.ts +10 -4
- package/src/hooks/native-skill-hook.ts +26 -0
- package/src/hooks/skill-state.ts +59 -0
- package/src/main.ts +2 -17
- package/src/modes/components/model-selector.ts +225 -33
- package/src/modes/controllers/selector-controller.ts +16 -3
- package/src/modes/interactive-mode.ts +34 -22
- package/src/modes/prompt-action-autocomplete.ts +40 -15
- package/src/sdk.ts +3 -1
- package/src/session/agent-session.ts +40 -4
- package/src/setup/model-onboarding-guidance.ts +5 -3
- package/src/skill-state/deep-interview-mutation-guard.ts +303 -0
- package/src/slash-commands/builtin-registry.ts +130 -11
- package/src/tools/ask.ts +55 -17
- package/src/tools/ast-edit.ts +7 -0
- package/src/tools/bash.ts +2 -1
- package/src/tools/gh.ts +37 -9
- package/src/tools/image-gen.ts +19 -10
- 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 `/
|
|
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
|
|
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 `
|
|
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
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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
|
|
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 `
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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**
|
|
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 `
|
|
545
|
-
- Preserve the
|
|
546
|
-
- Use `
|
|
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 `
|
|
550
|
-
- Use `
|
|
551
|
-
- Use
|
|
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 `
|
|
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
|
|
677
|
-
- [ ] Selected execution mode invoked via
|
|
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
|
|
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
|
|
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
|
-
|
|
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,
|
|
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-
|
|
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,
|
|
69
|
-
8. Checkpoint the durable ledger with that snapshot.
|
|
70
|
-
`gjc ultragoal checkpoint --goal-id <id> --status complete --evidence "<evidence>" --gjc-goal-json <get_goal-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
|
-
|
|
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
|
-
|
|
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
|
|
137
|
+
## Mandatory completion cleanup and review gate
|
|
136
138
|
|
|
137
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
"
|
|
162
|
-
|
|
163
|
-
|
|
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
|
|
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: {
|
|
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 {
|