@tekyzinc/gsd-t 2.74.13 → 3.10.10
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 +165 -0
- package/README.md +117 -1
- package/bin/advisor-integration.js +93 -0
- package/bin/check-headless-sessions.js +140 -0
- package/bin/context-meter-config.cjs +101 -0
- package/bin/context-meter-config.test.cjs +101 -0
- package/bin/gsd-t-unattended-platform.js +381 -0
- package/bin/gsd-t-unattended-safety.js +766 -0
- package/bin/gsd-t-unattended.js +1259 -0
- package/bin/gsd-t.js +723 -19
- package/bin/handoff-lock.js +249 -0
- package/bin/headless-auto-spawn.js +328 -0
- package/bin/model-selector.js +224 -0
- package/bin/runway-estimator.js +242 -0
- package/bin/token-budget.js +96 -89
- package/bin/token-optimizer.js +471 -0
- package/bin/token-telemetry.js +246 -0
- package/commands/gsd-t-audit.md +3 -3
- package/commands/gsd-t-backlog-list.md +38 -0
- package/commands/gsd-t-brainstorm.md +3 -3
- package/commands/gsd-t-complete-milestone.md +24 -0
- package/commands/gsd-t-debug.md +124 -7
- package/commands/gsd-t-discuss.md +10 -3
- package/commands/gsd-t-doc-ripple.md +32 -4
- package/commands/gsd-t-execute.md +107 -52
- package/commands/gsd-t-help.md +22 -0
- package/commands/gsd-t-integrate.md +67 -4
- package/commands/gsd-t-optimization-apply.md +91 -0
- package/commands/gsd-t-optimization-reject.md +94 -0
- package/commands/gsd-t-partition.md +7 -0
- package/commands/gsd-t-pause.md +3 -0
- package/commands/gsd-t-plan.md +10 -3
- package/commands/gsd-t-prd.md +3 -3
- package/commands/gsd-t-quick.md +71 -9
- package/commands/gsd-t-reflect.md +3 -7
- package/commands/gsd-t-resume.md +86 -1
- package/commands/gsd-t-status.md +31 -0
- package/commands/gsd-t-test-sync.md +7 -0
- package/commands/gsd-t-unattended-stop.md +83 -0
- package/commands/gsd-t-unattended-watch.md +290 -0
- package/commands/gsd-t-unattended.md +414 -0
- package/commands/gsd-t-verify.md +12 -5
- package/commands/gsd-t-visualize.md +3 -7
- package/commands/gsd-t-wave.md +82 -18
- package/docs/GSD-T-README.md +69 -0
- package/docs/architecture.md +176 -4
- package/docs/infrastructure.md +221 -0
- package/docs/methodology.md +44 -0
- package/docs/prd-harness-evolution.md +51 -37
- package/docs/requirements.md +95 -0
- package/docs/unattended-windows-caveats.md +245 -0
- package/package.json +2 -2
- package/scripts/context-meter/count-tokens-client.js +221 -0
- package/scripts/context-meter/count-tokens-client.test.js +308 -0
- package/scripts/context-meter/test-injector.js +55 -0
- package/scripts/context-meter/threshold.js +88 -0
- package/scripts/context-meter/threshold.test.js +255 -0
- package/scripts/context-meter/transcript-parser.js +252 -0
- package/scripts/context-meter/transcript-parser.test.js +320 -0
- package/scripts/gsd-t-context-meter.e2e.test.js +415 -0
- package/scripts/gsd-t-context-meter.js +350 -0
- package/scripts/gsd-t-context-meter.test.js +417 -0
- package/scripts/gsd-t-heartbeat.js +2 -2
- package/scripts/gsd-t-statusline.js +23 -8
- package/templates/CLAUDE-global.md +17 -1
- package/templates/CLAUDE-project.md +26 -6
- package/templates/context-meter-config.json +10 -0
- package/templates/prompts/README.md +1 -1
- package/bin/task-counter.cjs +0 -161
package/commands/gsd-t-verify.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
You are the lead agent coordinating verification of the completed work. Each verification dimension should be thorough and independent.
|
|
4
4
|
|
|
5
|
+
## Model Assignment
|
|
6
|
+
|
|
7
|
+
Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0.
|
|
8
|
+
|
|
9
|
+
- **Default**: `opus` (`selectModel({phase: "verify"})`) — milestone verification is the final quality gate before completion. High stakes.
|
|
10
|
+
- **Escalation**: already at opus; there is no stronger tier. Verify judgments are always made at full quality.
|
|
11
|
+
|
|
5
12
|
## Step 1: Load State
|
|
6
13
|
|
|
7
14
|
Read:
|
|
@@ -161,9 +168,9 @@ Before spawning — run via Bash:
|
|
|
161
168
|
`T_START=$(date +%s) && DT_START=$(date +"%Y-%m-%d %H:%M")`
|
|
162
169
|
Spawn a Task subagent to run the full test suite and contract audit.
|
|
163
170
|
After subagent returns — run via Bash:
|
|
164
|
-
`T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
|
|
165
|
-
Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes |
|
|
166
|
-
`| {DT_START} | {DT_END} | gsd-t-verify | Step 4 | haiku | {DURATION}s | test audit + contract review | {
|
|
171
|
+
`T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START)) && CTX_PCT=$(node -e "const tb=require('./bin/token-budget.js'); process.stdout.write(String(tb.getSessionStatus('.').pct||'N/A'))" 2>/dev/null || echo "N/A")`
|
|
172
|
+
Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Ctx% |` if missing):
|
|
173
|
+
`| {DT_START} | {DT_END} | gsd-t-verify | Step 4 | haiku | {DURATION}s | test audit + contract review | {CTX_PCT} |`
|
|
167
174
|
Collect all reports, synthesize, create remediation plan.
|
|
168
175
|
```
|
|
169
176
|
|
|
@@ -367,9 +374,9 @@ Report back: one-line status summary."
|
|
|
367
374
|
```
|
|
368
375
|
|
|
369
376
|
After subagent returns — run via Bash:
|
|
370
|
-
`T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
|
|
377
|
+
`T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START)) && CTX_PCT=$(node -e "const tb=require('./bin/token-budget.js'); process.stdout.write(String(tb.getSessionStatus('.').pct||'N/A'))" 2>/dev/null || echo "N/A")`
|
|
371
378
|
Append to `.gsd-t/token-log.md`:
|
|
372
|
-
`| {DT_START} | {DT_END} | gsd-t-verify | Step 8 | sonnet | {DURATION}s | auto-complete-milestone | | | {
|
|
379
|
+
`| {DT_START} | {DT_END} | gsd-t-verify | Step 8 | sonnet | {DURATION}s | auto-complete-milestone | | | {CTX_PCT} |`
|
|
373
380
|
|
|
374
381
|
3. Verify subagent result: Read `.gsd-t/progress.md` — confirm status is COMPLETED. If not, report the failure.
|
|
375
382
|
|
|
@@ -21,14 +21,10 @@ Skip Step 0 — you are already the subagent."
|
|
|
21
21
|
**OBSERVABILITY LOGGING — after subagent returns:**
|
|
22
22
|
|
|
23
23
|
Run via Bash:
|
|
24
|
-
`T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
|
|
24
|
+
`T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START)) && CTX_PCT=$(node -e "const tb=require('./bin/token-budget.js'); process.stdout.write(String(tb.getSessionStatus('.').pct||'N/A'))" 2>/dev/null || echo "N/A")`
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
- Compaction detected (TOK_END < TOK_START): `TOKENS=$(((TOK_MAX-TOK_START)+TOK_END))`, COMPACTED=$DT_END
|
|
29
|
-
|
|
30
|
-
Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Tasks-Since-Reset |` if missing):
|
|
31
|
-
`| {DT_START} | {DT_END} | gsd-t-visualize | Step 0 | sonnet | {DURATION}s | dashboard launched | {COUNTER} |`
|
|
26
|
+
Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Ctx% |` if missing):
|
|
27
|
+
`| {DT_START} | {DT_END} | gsd-t-visualize | Step 0 | sonnet | {DURATION}s | dashboard launched | {CTX_PCT} |`
|
|
32
28
|
|
|
33
29
|
Return the subagent's output and stop. Only skip Step 0 if you are already running as a subagent.
|
|
34
30
|
|
package/commands/gsd-t-wave.md
CHANGED
|
@@ -2,15 +2,77 @@
|
|
|
2
2
|
|
|
3
3
|
You are the wave orchestrator. You do NOT execute phases yourself. Instead, you spawn an **independent agent for each phase**, giving each a fresh context window. This eliminates context accumulation across phases and prevents mid-wave compaction.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Model Assignment
|
|
6
|
+
|
|
7
|
+
Per `.gsd-t/contracts/model-selection-contract.md` v1.0.0. Each phase spawn picks its tier from `bin/model-selector.js` — the wave orchestrator itself is routine coordination work.
|
|
8
|
+
|
|
9
|
+
- **Wave orchestrator (this agent)**: `sonnet` (`selectModel({phase: "wave"})`).
|
|
10
|
+
- **Per-phase spawns**: each phase agent selects its own tier — `partition` → opus, `discuss` → opus, `plan` → sonnet, `execute` → sonnet (with mechanical haiku subroutines and opus Red Team), `test-sync` → sonnet, `integrate` → sonnet, `verify` → opus, `doc-ripple` → sonnet. The phase command files carry their own Model Assignment blocks.
|
|
11
|
+
- **Escalation**: `/advisor` convention-based fallback from `bin/advisor-integration.js` at declared high-stakes sub-decisions (see `.gsd-t/M35-advisor-findings.md`). Never silently downgrade the model or skip phases under context pressure — M35 removed that behavior.
|
|
12
|
+
|
|
13
|
+
## Per-Spawn Token Bracket (MANDATORY — wrap EVERY phase agent spawn)
|
|
14
|
+
|
|
15
|
+
Per `.gsd-t/contracts/token-telemetry-contract.md` v1.0.0. Every phase agent spawn in the Phase Agent Spawn Pattern below **MUST** be wrapped in this token bracket so `.gsd-t/token-metrics.jsonl` gets one record per spawn. This is additive — the existing OBSERVABILITY LOGGING blocks in each spawn site are preserved unmodified alongside this bracket.
|
|
16
|
+
|
|
17
|
+
**Before each phase spawn — read starting context tokens:**
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
T0_TOKENS=$(node -e "try{const s=require('fs').readFileSync('.gsd-t/.context-meter-state.json','utf8');process.stdout.write(String(JSON.parse(s).inputTokens||0))}catch(_){process.stdout.write('0')}")
|
|
21
|
+
T0_PCT=$(node -e "try{const tb=require('./bin/token-budget.js');process.stdout.write(String(tb.getSessionStatus('.').pct||0))}catch(_){process.stdout.write('0')}")
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**After each phase spawn — record the bracket:**
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
T1_TOKENS=$(node -e "try{const s=require('fs').readFileSync('.gsd-t/.context-meter-state.json','utf8');process.stdout.write(String(JSON.parse(s).inputTokens||0))}catch(_){process.stdout.write('0')}")
|
|
28
|
+
T1_PCT=$(node -e "try{const tb=require('./bin/token-budget.js');process.stdout.write(String(tb.getSessionStatus('.').pct||0))}catch(_){process.stdout.write('0')}")
|
|
29
|
+
node -e "require('./bin/token-telemetry.js').recordSpawn({timestamp:new Date().toISOString(),milestone:process.env.GSD_T_MILESTONE||'',command:'gsd-t-wave',phase:'${PHASE:-}',step:'${STEP:-}',domain:'${DOMAIN:-}',domain_type:'${DOMAIN_TYPE:-}',task:'${TASK:-}',model:'${MODEL:-sonnet}',duration_s:${DURATION:-0},input_tokens_before:${T0_TOKENS},input_tokens_after:${T1_TOKENS},tokens_consumed:${T1_TOKENS}-${T0_TOKENS},context_window_pct_before:${T0_PCT},context_window_pct_after:${T1_PCT},outcome:'${OUTCOME:-success}',halt_type:${HALT_TYPE:-null},escalated_via_advisor:${ESCALATED_VIA_ADVISOR:-false}})" 2>/dev/null || true
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The bracket is additive to the existing `.gsd-t/token-log.md` OBSERVABILITY LOGGING rows. Both sinks coexist — token-log.md is human-readable with context percentage, token-metrics.jsonl is machine-readable with the full 18-field schema for `gsd-t metrics --tokens/--halts/--context-window` aggregation.
|
|
33
|
+
|
|
34
|
+
## Step 0: Runway Check (MANDATORY — before any other work in a fresh session)
|
|
35
|
+
|
|
36
|
+
Count the wave's total task count (sum of atomic tasks across domains in the current wave). Then run via Bash:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node -e "
|
|
40
|
+
const r = require('./bin/runway-estimator.js').estimateRunway({
|
|
41
|
+
command: 'gsd-t-wave',
|
|
42
|
+
domain_type: '',
|
|
43
|
+
remaining_tasks: {N},
|
|
44
|
+
projectDir: '.'
|
|
45
|
+
});
|
|
46
|
+
console.log(JSON.stringify(r, null, 2));
|
|
47
|
+
if (!r.can_start) {
|
|
48
|
+
console.log('⛔ Insufficient runway — projected ' + r.projected_end_pct + '% (current ' + r.current_pct + '%, ' + r.pct_per_task + '%/task, ' + r.confidence + ' confidence, ' + r.confidence_basis + ' records)');
|
|
49
|
+
console.log('Auto-spawning headless to continue in a fresh context.');
|
|
50
|
+
const s = require('./bin/headless-auto-spawn.js').autoSpawnHeadless({
|
|
51
|
+
command: 'gsd-t-wave', args: [], continue_from: '.'
|
|
52
|
+
});
|
|
53
|
+
console.log('Session ID: ' + s.id);
|
|
54
|
+
console.log('Status: tail ' + s.logPath);
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log('Your interactive session remains idle — you can use it for other work.');
|
|
57
|
+
console.log('You will be notified when the headless run completes.');
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If `can_start === false`, the headless continuation has already been spawned and the interactive session must stop here. Do NOT proceed to Step 0.1.
|
|
64
|
+
|
|
65
|
+
**Contract**: `.gsd-t/contracts/runway-estimator-contract.md` v1.0.0; stop threshold (85%) mirrors `.gsd-t/contracts/token-budget-contract.md` v3.0.0.
|
|
66
|
+
|
|
67
|
+
## Step 0.1: Verify Context Gate Readiness (MANDATORY — first thing in a fresh session)
|
|
6
68
|
|
|
7
69
|
Run via Bash:
|
|
8
70
|
|
|
9
71
|
```bash
|
|
10
|
-
node bin/
|
|
72
|
+
node -e "const tb = require('./bin/token-budget.js'); const s = tb.getSessionStatus('.'); console.log(JSON.stringify(s));"
|
|
11
73
|
```
|
|
12
74
|
|
|
13
|
-
This
|
|
75
|
+
This calls `getSessionStatus()` (v2.0.0) which reads `.gsd-t/.context-meter-state.json` produced by the Context Meter PostToolUse hook. The returned `threshold` drives the gate logic in the Phase Agent Spawn Pattern below — it enforces the three-band stop boundary (85%) so the wave orchestrator itself never runs out of context mid-wave. When the state file is absent or stale, the call falls back to a historical heuristic from `.gsd-t/token-log.md`. Band boundaries and `modelWindowSize` are configured in `.gsd-t/context-meter-config.json` and `bin/token-budget.js` (THRESHOLDS constant).
|
|
14
76
|
|
|
15
77
|
## Step 1: Load State (Lightweight)
|
|
16
78
|
|
|
@@ -96,10 +158,10 @@ If STACK_RULES is empty (no templates/stacks/ dir or no matches), skip silently.
|
|
|
96
158
|
Run via Bash:
|
|
97
159
|
`node -e "const tb = require('./bin/token-budget.js'); const s = tb.getSessionStatus('.'); process.stdout.write(s.threshold);" 2>/dev/null`
|
|
98
160
|
|
|
161
|
+
Three-band model per `token-budget-contract.md` v3.0.0 (never silently degrade quality):
|
|
99
162
|
- `normal` or file missing → proceed normally
|
|
100
|
-
- `
|
|
101
|
-
- `
|
|
102
|
-
- `stop` → checkpoint all progress and output: "Token budget exhausted — wave paused. Resume after session reset." then halt
|
|
163
|
+
- `warn` (≥70%) → log the warning to `.gsd-t/token-log.md` and proceed at full quality; **do NOT downgrade models or skip phases** — M35 removed that behavior intentionally
|
|
164
|
+
- `stop` (≥85%) → checkpoint all progress and output: "Wave orchestrator context gate reached ({pct}%). Progress saved. Resume after session reset." then halt
|
|
103
165
|
|
|
104
166
|
**OBSERVABILITY LOGGING (MANDATORY) — repeat for every phase spawn:**
|
|
105
167
|
Before spawning — run via Bash:
|
|
@@ -126,29 +188,31 @@ Task agent (subagent_type: "general-purpose", mode: "bypassPermissions"):
|
|
|
126
188
|
After phase agent returns — run via Bash:
|
|
127
189
|
`T_END=$(date +%s) && DT_END=$(date +"%Y-%m-%d %H:%M") && DURATION=$((T_END-T_START))`
|
|
128
190
|
|
|
129
|
-
**Wave Orchestrator
|
|
191
|
+
**Wave Orchestrator Context Gate (MANDATORY) — real-count measurement via Context Meter state file:**
|
|
130
192
|
|
|
131
193
|
Run via Bash AFTER each phase agent returns:
|
|
132
194
|
|
|
133
195
|
```bash
|
|
134
|
-
node bin/
|
|
196
|
+
node -e "const tb=require('./bin/token-budget.js'); const s=tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s)); if(s.threshold==='stop')process.exit(10); if(s.threshold==='warn')process.exit(13);"
|
|
135
197
|
```
|
|
136
198
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
199
|
+
The JSON on stdout contains `{consumed, estimated_remaining, pct, threshold}` — capture `pct` as `{CTX_PCT}` for the token-log row.
|
|
200
|
+
|
|
201
|
+
Exit-code handling (three-band model per `token-budget-contract.md` v3.0.0):
|
|
202
|
+
- `0` (normal, <70%) → proceed to the next phase at full quality.
|
|
203
|
+
- `13` (warn, 70–85%) → log the warning to `.gsd-t/token-log.md` and proceed to the next phase at full quality. **Never downgrade models or skip phases** — the runway estimator (m35-runway-estimator) is responsible for halting cleanly before reaching `stop`.
|
|
204
|
+
- `10` (stop, ≥85%) → STOP the wave loop. Save checkpoint to `.gsd-t/progress.md` — record which phases are complete, which remain. Call `autoSpawnHeadless({command: 'gsd-t-wave', args, projectDir})` — this spawns a fresh headless session that auto-resumes via `/gsd-t-resume` without any manual `/clear`. Output: `⏸️ Wave orchestrator context gate reached ({pct}% of model window) — handing off to a fresh headless session (ID: {id}). Progress saved.` Return cleanly. Do NOT spawn the next phase agent, do NOT exit with a special code — the handoff is the success path.
|
|
141
205
|
|
|
142
|
-
|
|
206
|
+
As of v2.0.0 (M34), the wave orchestrator reads the SAME `bin/token-budget.js` real-source measurement as the execute orchestrator — both trace back to `.gsd-t/.context-meter-state.json` produced by the Context Meter PostToolUse hook. Each phase spawn (PARTITION, DISCUSS, PLAN, IMPACT, EXECUTE, TEST-SYNC, INTEGRATE, VERIFY+COMPLETE, DOC-RIPPLE) causes post-call updates to the state file, so each subsequent gate check reflects the real context consumption trajectory. When the state file is absent or stale, the call falls back to the historical heuristic.
|
|
143
207
|
|
|
144
|
-
The previous version
|
|
208
|
+
The previous v1.x version relied on an environment-variable-based context check which Claude Code never populated; v2.74.12 stood in a proxy task counter; v2.0.0 (M34) retires both and uses the real count_tokens measurement.
|
|
145
209
|
|
|
146
|
-
**On wave entry**,
|
|
210
|
+
**On wave entry**, Step 0 runs `getSessionStatus()` once for a readiness confirmation. No counter reset is needed — `/clear` plus the next tool call will cause the Context Meter hook to refresh the state file with the new session's starting `input_tokens`.
|
|
147
211
|
|
|
148
|
-
Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Domain | Task |
|
|
149
|
-
`| {DT_START} | {DT_END} | gsd-t-wave | {PHASE} | sonnet | {DURATION}s | phase: {PHASE} | | | {
|
|
212
|
+
Append to `.gsd-t/token-log.md` (create with header `| Datetime-start | Datetime-end | Command | Step | Model | Duration(s) | Notes | Domain | Task | Ctx% |` if missing):
|
|
213
|
+
`| {DT_START} | {DT_END} | gsd-t-wave | {PHASE} | sonnet | {DURATION}s | phase: {PHASE} | | | {CTX_PCT} |`
|
|
150
214
|
|
|
151
|
-
Where `{
|
|
215
|
+
Where `{CTX_PCT}` is the `pct` field from the JSON the getSessionStatus command just printed.
|
|
152
216
|
|
|
153
217
|
### Phase Sequence
|
|
154
218
|
|
package/docs/GSD-T-README.md
CHANGED
|
@@ -114,6 +114,9 @@ GSD-T reads all state files and tells you exactly where you left off.
|
|
|
114
114
|
|
|
115
115
|
| Command | Purpose | Auto |
|
|
116
116
|
|---------|---------|------|
|
|
117
|
+
| `/user:gsd-t-unattended` | Launch detached supervisor — runs active milestone to completion with zero human intervention | Manual |
|
|
118
|
+
| `/user:gsd-t-unattended-watch` | Watch tick — fires every 270s via ScheduleWakeup, reports supervisor status | Auto |
|
|
119
|
+
| `/user:gsd-t-unattended-stop` | Touch stop sentinel — supervisor halts after current worker finishes | Manual |
|
|
117
120
|
| `/user:gsd-t-wave` | Full cycle, auto-advances all phases | Manual |
|
|
118
121
|
| `/user:gsd-t-status` | Cross-domain progress view with token breakdown, global ELO and cross-project rankings | Manual |
|
|
119
122
|
| `/user:gsd-t-resume` | Restore context, continue | Manual |
|
|
@@ -286,6 +289,20 @@ Drop a `.md` file into `templates/stacks/` to add a new stack. Files prefixed wi
|
|
|
286
289
|
|
|
287
290
|
---
|
|
288
291
|
|
|
292
|
+
## Unattended Execution (M36)
|
|
293
|
+
|
|
294
|
+
Run the active milestone to completion over hours or days with zero human intervention. The unattended supervisor is an OS-level process that spawns `claude -p` workers in a relay — each worker runs in a fresh context window, completing one round of wave tasks before handing off to the next. The supervisor survives `/clear`, terminal close, and sleep/wake cycles (macOS/Linux; see `docs/unattended-windows-caveats.md` for Windows).
|
|
295
|
+
|
|
296
|
+
**Relay model**: Each iteration spawns a fresh `claude -p` session with a compact prompt derived from `.gsd-t/progress.md` state. The supervisor waits for the worker to exit, records the exit code in `state.json`, runs safety checks (gutter detection, blocker sentinel scan), and spawns the next worker. Workers never overlap. Context rot is impossible — each worker starts clean.
|
|
297
|
+
|
|
298
|
+
**Watch loop**: `/user:gsd-t-unattended` starts an in-session ScheduleWakeup loop that ticks every 270 seconds. Each tick reads `state.json` and `supervisor.pid` to render a live progress block. When the supervisor reaches a terminal state (`done`, `failed`, `stopped`), the watch loop stops rescheduling and prints a final summary. A `/clear` + `/user:gsd-t-resume` transparently re-attaches: the resume command checks for a live `supervisor.pid` and re-starts the watch loop automatically.
|
|
299
|
+
|
|
300
|
+
**Safety rails**: Branch protection (refuses to run on `main`/`master`/`release/*` by default), dirty-tree check (whitelists GSD-T runtime files), per-iteration gutter detection (repeated error patterns, file thrash, no-progress stall), wall-clock and iteration caps, and a blocker sentinel that halts on unrecoverable worker errors.
|
|
301
|
+
|
|
302
|
+
**Contract**: `.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0 is the authoritative reference for the state file schema, exit codes, CLI surface, and platform matrix.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
289
306
|
## Headless Mode
|
|
290
307
|
|
|
291
308
|
Run GSD-T non-interactively in CI/CD pipelines or automated workflows.
|
|
@@ -423,6 +440,58 @@ Recommended `.gsd-t/config.json`:
|
|
|
423
440
|
}
|
|
424
441
|
```
|
|
425
442
|
|
|
443
|
+
### Context Meter (M34)
|
|
444
|
+
|
|
445
|
+
The Context Meter is a PostToolUse hook that runs after every tool call, streams the current Claude Code transcript to the Anthropic `count_tokens` API, and writes the exact input-token count and threshold band to `.gsd-t/.context-meter-state.json`. The GSD-T orchestrator (`gsd-t-execute`, `gsd-t-wave`, `gsd-t-quick`, `gsd-t-integrate`, `gsd-t-debug`) reads this state file via `token-budget.getSessionStatus()` as the authoritative context-burn signal — replacing the v2.74.12 task-counter proxy.
|
|
446
|
+
|
|
447
|
+
Setup:
|
|
448
|
+
|
|
449
|
+
1. **Export an API key** — `export ANTHROPIC_API_KEY="sk-ant-..."` (free-tier key is sufficient; `count_tokens` is inexpensive).
|
|
450
|
+
2. **Install the hook** — `npx @tekyzinc/gsd-t install` (registers the PostToolUse hook globally) then `npx @tekyzinc/gsd-t init` in each project (copies the hook runtime and config template).
|
|
451
|
+
3. **Verify with doctor** — `npx @tekyzinc/gsd-t doctor` hard-gates on API key presence, hook registration, script existence, config validity, and a live `count_tokens` dry-run.
|
|
452
|
+
4. **Check status** — `npx @tekyzinc/gsd-t status` shows a Context line with `{pct}% of {window} tokens ({band}) — last check {time ago}`.
|
|
453
|
+
|
|
454
|
+
`.gsd-t/context-meter-config.json` controls the meter:
|
|
455
|
+
|
|
456
|
+
```json
|
|
457
|
+
{
|
|
458
|
+
"enabled": true,
|
|
459
|
+
"apiKeyEnvVar": "ANTHROPIC_API_KEY",
|
|
460
|
+
"modelWindowSize": 200000,
|
|
461
|
+
"thresholdPct": 85,
|
|
462
|
+
"checkFrequency": 1
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Threshold bands used by the orchestrator gate (v3.0.0 three-band model as of M35 / v2.76.10):
|
|
467
|
+
|
|
468
|
+
| Band | Range | Orchestrator action |
|
|
469
|
+
|-----------|-------------|-----------------------------------------------------------------|
|
|
470
|
+
| normal | 0–69% | Proceed as normal |
|
|
471
|
+
| warn | 70–84% | Surface warning; runway estimator refuses if projection crosses |
|
|
472
|
+
| stop | ≥85% | Halt cleanly; headless auto-spawn continues in a fresh context |
|
|
473
|
+
|
|
474
|
+
**Zero silent quality degradation.** There is no `downgrade` or `conserve` band anymore. When the runway estimator (`bin/runway-estimator.js`) projects a run will cross the 85% stop threshold, the command refuses to start. Instead of printing "please `/clear` and resume," it calls `bin/headless-auto-spawn.js` which detaches a child process to continue the work. The interactive session receives a single ⛔ banner and exits cleanly; the user is never blocked.
|
|
475
|
+
|
|
476
|
+
**Per-phase model selection** — see `bin/model-selector.js` for the declarative rules table (≥13 phase mappings). Each command file carries a `## Model Assignment` block documenting which phases run on haiku / sonnet / opus. Complexity signals (`cross_module_refactor`, `security_boundary`, `data_loss_risk`, `contract_design`) escalate sonnet→opus at plan time.
|
|
477
|
+
|
|
478
|
+
**`/advisor` escalation** — mid-phase escalation channel. If `/advisor` is programmable in the runtime, subagents invoke it directly; otherwise, the convention-based fallback (`bin/advisor-integration.js`) appends a `missed_escalation` marker to `.gsd-t/token-log.md` that surfaces at `gsd-t-reflect`. See `.gsd-t/contracts/model-selection-contract.md` v1.0.0.
|
|
479
|
+
|
|
480
|
+
**`gsd-t metrics` CLI** — `gsd-t metrics --tokens [--by model,command,phase,milestone,domain,domain_type]` aggregates `.gsd-t/token-metrics.jsonl` into a count/total/mean/median/p95 table. `gsd-t metrics --halts` breaks halts down by type (`clean`, `runway-refusal`, `headless-handoff`, `native-compact`). `gsd-t metrics --tokens --context-window` buckets spawns by `context_window_pct_before` in 10% increments. See `.gsd-t/contracts/token-telemetry-contract.md` v1.0.0.
|
|
481
|
+
|
|
482
|
+
**Optimization apply/reject** — `/user:gsd-t-optimization-apply {ID}` promotes a pending recommendation; `/user:gsd-t-optimization-reject {ID} [--reason "text"]` dismisses it with a 5-milestone cooldown. Both are idempotent. See `commands/gsd-t-optimization-apply.md` and `commands/gsd-t-optimization-reject.md`.
|
|
483
|
+
|
|
484
|
+
**Observability logging columns** — as of M34, the `.gsd-t/token-log.md` header includes `Ctx%` (the real session-wide context percentage at the time of the subagent spawn) replacing the earlier `Tasks-Since-Reset` column. The old column was a proxy count of how many tasks had run since the last `/clear`; the new column is the actual measurement.
|
|
485
|
+
|
|
486
|
+
**Upgrading from pre-M34** — `gsd-t update-all` handles the migration automatically:
|
|
487
|
+
- Copies the hook script, runtime files, and config template into every registered project
|
|
488
|
+
- Runs a one-time task-counter retirement (`bin/task-counter.cjs` + `.task-counter*` files deleted, `.gsd-t/.task-counter-retired-v1` marker written)
|
|
489
|
+
- Idempotent on second run
|
|
490
|
+
|
|
491
|
+
After upgrading, you **must** set `ANTHROPIC_API_KEY` or `gsd-t doctor` will fail.
|
|
492
|
+
|
|
493
|
+
**Historical note on v2.74.12–13**: between 2026-03 and 2026-04, the orchestrator used `bin/task-counter.cjs` as a proxy — it assumed N tasks ≈ M% context used. That was itself a replacement for an earlier env-var-based check (`CLAUDE_CONTEXT_TOKENS_USED` / `CLAUDE_CONTEXT_TOKENS_MAX`) that never worked because Claude Code does not export those vars. The Context Meter (v2.75.10, M34) is the first version that measures context burn from the authoritative source: the Anthropic API itself.
|
|
494
|
+
|
|
426
495
|
---
|
|
427
496
|
|
|
428
497
|
## License
|
package/docs/architecture.md
CHANGED
|
@@ -68,14 +68,14 @@ The framework has no runtime — it is consumed entirely by Claude Code's slash
|
|
|
68
68
|
|
|
69
69
|
### Headless Mode (M23 — complete)
|
|
70
70
|
- **doHeadless(args)**: Dispatch function for the `headless` CLI subcommand.
|
|
71
|
-
- **doHeadlessExec(command, cmdArgs, flags)**: Wraps `claude -p "/
|
|
71
|
+
- **doHeadlessExec(command, cmdArgs, flags)**: Wraps `claude -p "/gsd-t-{command}"` via `execFileSync`. Verifies claude CLI availability, enforces timeout, writes log file if `--log` requested. Returns structured JSON if `--json` flag set. (M36 Phase 0: prompt form is `/gsd-t-X`, NOT `/user:gsd-t-X` — non-interactive mode rejects the `/user:` namespace prefix.)
|
|
72
72
|
- **parseHeadlessFlags(args)**: Extracts `--json`, `--timeout=N`, `--log` from raw args. Returns `{ flags, positional }`.
|
|
73
|
-
- **buildHeadlessCmd(command, cmdArgs)**: Builds the `/
|
|
74
|
-
- **mapHeadlessExitCode(processExitCode, output)**: Maps process exit code + output text patterns to GSD-T exit codes (0–
|
|
73
|
+
- **buildHeadlessCmd(command, cmdArgs)**: Builds the bare `/gsd-t-{command}` prompt string. Interactive-mode `/user:` prefix deliberately omitted — see `.gsd-t/M36-spike-findings.md` Spike A.
|
|
74
|
+
- **mapHeadlessExitCode(processExitCode, output)**: Maps process exit code + output text patterns to GSD-T exit codes (0–5).
|
|
75
75
|
- **headlessLogPath(projectDir, timestamp)**: Generates `.gsd-t/headless-{timestamp}.log` path.
|
|
76
76
|
- **doHeadlessQuery(type)**: Dispatches to one of 7 query functions. All pure Node.js file reads, no LLM calls, <100ms.
|
|
77
77
|
- **Query functions** (7): `queryStatus`, `queryDomains`, `queryContracts`, `queryDebt`, `queryContext`, `queryBacklog`, `queryGraph` — each reads corresponding `.gsd-t/` file and returns typed JSON result.
|
|
78
|
-
- **Exit codes**: 0=success, 1=verify-fail, 2=context-budget-exceeded, 3=error, 4=blocked-needs-human
|
|
78
|
+
- **Exit codes**: 0=success, 1=verify-fail, 2=context-budget-exceeded, 3=error, 4=blocked-needs-human, 5=command-dispatch-failed (M36 Phase 0 — `claude -p` returned `Unknown command:` for the slash command; caller should treat as a bug not a transient failure)
|
|
79
79
|
- **CI/CD examples**: `docs/ci-examples/github-actions.yml` (GitHub Actions), `docs/ci-examples/gitlab-ci.yml` (GitLab CI)
|
|
80
80
|
|
|
81
81
|
### Compaction-Proof Debug Loop (M29 — complete)
|
|
@@ -272,6 +272,83 @@ QA runs inline or as Task subagent depending on phase (M10 refactor). Removed fr
|
|
|
272
272
|
- **Resource limits**: Heartbeat stdin capped at 1MB, HTTP responses capped at 1MB (M5), 5s/8s timeouts, 7-day file cleanup
|
|
273
273
|
- **Wave security**: `bypassPermissions` mode documented with attack surface analysis and mitigations (M5)
|
|
274
274
|
|
|
275
|
+
## Unattended Supervisor (M36)
|
|
276
|
+
|
|
277
|
+
The unattended supervisor is a cross-session relay engine that runs an active GSD-T milestone to completion over hours or days without human intervention. It spans the boundary between the interactive Claude session and the OS process layer.
|
|
278
|
+
|
|
279
|
+
### Component Diagram
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
Interactive Claude session
|
|
283
|
+
└── /user:gsd-t-unattended (launch command)
|
|
284
|
+
├── Pre-flight safety checks (branch, dirty tree)
|
|
285
|
+
└── spawn(detached) → Supervisor process (bin/gsd-t-unattended.js)
|
|
286
|
+
├── writes .gsd-t/.unattended/supervisor.pid
|
|
287
|
+
├── writes .gsd-t/.unattended/state.json (atomic rewrite each iter)
|
|
288
|
+
├── appends .gsd-t/.unattended/run.log (worker stdout+stderr)
|
|
289
|
+
├── checks .gsd-t/.unattended/stop (sentinel — presence = halt)
|
|
290
|
+
└── relay loop:
|
|
291
|
+
spawnSync('claude -p "/gsd-t-resume"')
|
|
292
|
+
→ worker exits → post-worker safety check → next iter
|
|
293
|
+
|
|
294
|
+
In-session watch loop (every 270s via ScheduleWakeup)
|
|
295
|
+
└── /user:gsd-t-unattended-watch
|
|
296
|
+
├── reads supervisor.pid (kill -0 liveness)
|
|
297
|
+
├── reads state.json (status, iter, lastTick)
|
|
298
|
+
└── reschedules or reports final status
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### State Directory Layout
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
.gsd-t/.unattended/
|
|
305
|
+
├── supervisor.pid — Integer PID. Exists ONLY while supervisor is alive.
|
|
306
|
+
├── state.json — Live state snapshot. Atomically rewritten between iterations.
|
|
307
|
+
├── run.log — Append-only worker stdout+stderr. Never truncated during a run.
|
|
308
|
+
├── stop — Sentinel file. Absence = run. Presence = user-requested stop.
|
|
309
|
+
└── config.json — Optional per-project config overrides (maxIterations, hours, etc.)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Sibling: `.gsd-t/.handoff/` — owned by M35-gap-fixes for single-shot handoff locks (see below).
|
|
313
|
+
|
|
314
|
+
### Contract
|
|
315
|
+
|
|
316
|
+
`.gsd-t/contracts/unattended-supervisor-contract.md` v1.0.0 — authoritative source for: state schema, status enum, exit-code table, launch handshake, watch tick decision tree, resume auto-reattach handshake, stop mechanism, safety-rails hook points, and CLI surface.
|
|
317
|
+
|
|
318
|
+
### Platform Abstraction Layer (`bin/gsd-t-unattended-platform.js`)
|
|
319
|
+
|
|
320
|
+
Exports four cross-platform functions:
|
|
321
|
+
|
|
322
|
+
| Export | macOS | Linux | Windows |
|
|
323
|
+
|--------|-------|-------|---------|
|
|
324
|
+
| `spawnSupervisor(args)` | `spawn(node, ...)` detached | same | same (`windowsHide:true`) |
|
|
325
|
+
| `preventSleep()` | `caffeinate -i` subprocess | `systemd-inhibit` or no-op | no-op (not supported — see docs/unattended-windows-caveats.md) |
|
|
326
|
+
| `releaseSleep(handle)` | kill caffeinate PID | release inhibit or no-op | no-op |
|
|
327
|
+
| `notify(title, msg, level)` | `osascript` | `notify-send` | no-op |
|
|
328
|
+
| `resolveClaudePath()` | PATH lookup | PATH lookup | `claude.cmd` via PATH |
|
|
329
|
+
|
|
330
|
+
### Safety Rails (`bin/gsd-t-unattended-safety.js`)
|
|
331
|
+
|
|
332
|
+
Called at four supervisor hook points (pre-launch, supervisor-init, pre-worker, post-worker):
|
|
333
|
+
|
|
334
|
+
- **Gutter detection**: stall pattern — repeated identical errors or no file changes for N iterations
|
|
335
|
+
- **Blocker sentinels**: scan worker stdout for unrecoverable-error markers (`BLOCKED_NEEDS_HUMAN`, `DISPATCH_FAILED`)
|
|
336
|
+
- **Iteration cap**: `maxIterations` guard (default 200)
|
|
337
|
+
- **Wall-clock cap**: `hours` guard (default 24h)
|
|
338
|
+
- **Branch/dirty-tree pre-flight**: refuses to start on protected branches or uncleaned worktrees
|
|
339
|
+
|
|
340
|
+
Each check returns `{ ok, reason?, code? }`. A `false` result halts with `status = 'failed'` and the corresponding exit code (6=gutter, 7=protected-branch, 8=dirty-tree).
|
|
341
|
+
|
|
342
|
+
### Handoff-Lock Primitive (`bin/handoff-lock.js`)
|
|
343
|
+
|
|
344
|
+
Closes the M35 parent/child race in `bin/headless-auto-spawn.js`. When the runway estimator fires `autoSpawnHeadless()`, the parent session writes a lock file in `.gsd-t/.handoff/` before spawning the child and removes it only after the child has confirmed PID + state-ready. Prevents the child from beginning execution before the parent has cleanly exited — eliminating the race where both sessions wrote to the same `.gsd-t/` files simultaneously.
|
|
345
|
+
|
|
346
|
+
### Resume Auto-Reattach
|
|
347
|
+
|
|
348
|
+
`/user:gsd-t-resume` Step 0 checks for a live supervisor before any other resume logic. If `supervisor.pid` exists and `kill -0` succeeds and `state.json.status` is non-terminal, the resume command skips normal resume flow entirely, prints the current watch block, and calls `ScheduleWakeup(270, '/user:gsd-t-unattended-watch', ...)`. The user transparently re-enters the watch loop without any manual step.
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
275
352
|
## Design Decisions
|
|
276
353
|
|
|
277
354
|
| Date | Decision | Rationale | Alternatives Considered |
|
|
@@ -368,6 +445,101 @@ During partition, UI/frontend projects automatically receive `.gsd-t/contracts/d
|
|
|
368
445
|
|
|
369
446
|
When Playwright MCP is registered in Claude Code settings, QA agents get 3 minutes of interactive exploration and Red Team gets 5 minutes after all scripted tests pass. Findings are tagged `[EXPLORATORY]` in qa-issues.md and red-team-report.md, and tracked separately in QA calibration (category key: `exploratory` — does NOT count against scripted pass/fail ratio). Silent skip when Playwright MCP absent. Wired into: execute, quick, integrate, debug.
|
|
370
447
|
|
|
448
|
+
## Context Meter Architecture (M34, v2.75.10+)
|
|
449
|
+
|
|
450
|
+
The Context Meter is the authoritative source for session context-burn measurement in GSD-T. It replaces the v2.74.12 `bin/task-counter.cjs` proxy (and the pre-v2.74.12 `CLAUDE_CONTEXT_TOKENS_USED` env-var approach, which never worked because Claude Code does not export those vars).
|
|
451
|
+
|
|
452
|
+
**Data flow:**
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
Claude Code tool call finishes
|
|
456
|
+
│
|
|
457
|
+
▼
|
|
458
|
+
PostToolUse hook (~/.claude/settings.json registered)
|
|
459
|
+
│
|
|
460
|
+
▼
|
|
461
|
+
scripts/gsd-t-context-meter.js (runMeter)
|
|
462
|
+
│
|
|
463
|
+
├── 1. loadConfig(.gsd-t/context-meter-config.json)
|
|
464
|
+
├── 2. check-frequency gate — short-circuits if tool-call % freq != 0
|
|
465
|
+
├── 3. parseTranscript(hook.transcript_path)
|
|
466
|
+
│ → { system, messages } shaped for count_tokens
|
|
467
|
+
├── 4. countTokens({apiKey, model, system, messages, timeoutMs:200})
|
|
468
|
+
│ → POST https://api.anthropic.com/v1/messages/count_tokens
|
|
469
|
+
│ → 200 { input_tokens } | failure → null
|
|
470
|
+
├── 5. computePct(inputTokens, modelWindowSize)
|
|
471
|
+
├── 6. bandFor(pct) → "normal" | "warn" | "stop" (v3.0.0 three-band model)
|
|
472
|
+
└── 7. atomic write .gsd-t/.context-meter-state.json
|
|
473
|
+
{ version, timestamp, inputTokens, modelWindowSize, pct, threshold, checkCount, lastError? }
|
|
474
|
+
│
|
|
475
|
+
▼
|
|
476
|
+
bin/token-budget.js getSessionStatus(projectDir) ── v3.0.0: normal/warn/stop only
|
|
477
|
+
│
|
|
478
|
+
├── readContextMeterState(dir)
|
|
479
|
+
│ if fresh (timestamp within 5 min):
|
|
480
|
+
│ return { consumed, estimated_remaining, pct, threshold }
|
|
481
|
+
│ else: null
|
|
482
|
+
│
|
|
483
|
+
└── fallback: readSessionConsumed(dir) from .gsd-t/token-log.md (heuristic)
|
|
484
|
+
│
|
|
485
|
+
▼
|
|
486
|
+
bin/runway-estimator.js estimateRunway({command, domain_type, remaining_tasks})
|
|
487
|
+
│ reads current_pct from .context-meter-state.json
|
|
488
|
+
│ queries .gsd-t/token-metrics.jsonl for historical pct-delta per spawn
|
|
489
|
+
│ projects current_pct + pct_per_task × remaining_tasks × skew
|
|
490
|
+
│ confidence: high ≥50 records, medium ≥10, low <10 (+1.25× skew)
|
|
491
|
+
│ returns {can_start, projected_end_pct, confidence, recommendation}
|
|
492
|
+
▼
|
|
493
|
+
Command file Step 0 — runway gate (execute/wave/quick/integrate/debug):
|
|
494
|
+
if (!decision.can_start) {
|
|
495
|
+
print ⛔ banner
|
|
496
|
+
autoSpawnHeadless({command, continue_from: '.'}) ── bin/headless-auto-spawn.js
|
|
497
|
+
process.exit(0) ── never prompts user
|
|
498
|
+
} else {
|
|
499
|
+
proceed to Step 0.1 (Verify Context Gate Readiness) and Step 1
|
|
500
|
+
}
|
|
501
|
+
│
|
|
502
|
+
▼
|
|
503
|
+
bin/headless-auto-spawn.js (when refused)
|
|
504
|
+
│ detached child: node bin/gsd-t.js headless {command} --log
|
|
505
|
+
│ child.unref(); interactive session returns immediately
|
|
506
|
+
│ writes .gsd-t/headless-sessions/{id}.json (status: "running")
|
|
507
|
+
│ 2s poll watcher: process.kill(pid, 0) → mac osascript notification on exit
|
|
508
|
+
│
|
|
509
|
+
▼
|
|
510
|
+
Orchestrator Context Gate — v3.0.0 semantics:
|
|
511
|
+
normal → proceed
|
|
512
|
+
warn → log to .gsd-t/token-log.md, proceed at full quality (informational only)
|
|
513
|
+
stop → halt cleanly, runway estimator hands off to headless-auto-spawn
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
**Key constraints:**
|
|
517
|
+
- **Fail-open**: every stage catches errors and writes a partial state file. Never crashes Claude Code.
|
|
518
|
+
- **No message content in state or log files** — only token counts, band names, error codes.
|
|
519
|
+
- **Never logs or writes the API key** anywhere.
|
|
520
|
+
- **State staleness window**: 5 minutes — after that, heuristic fallback takes over.
|
|
521
|
+
- **Hook latency budget**: 200ms (timeoutMs on the HTTP call), enforced by `req.setTimeout` + `req.destroy()`.
|
|
522
|
+
|
|
523
|
+
**Contracts:**
|
|
524
|
+
- `.gsd-t/contracts/context-meter-contract.md` — schema, state file format, hook I/O
|
|
525
|
+
- `.gsd-t/contracts/context-observability-contract.md` v2.0.0 — Ctx% as the real session-wide signal (replaces Tasks-Since-Reset)
|
|
526
|
+
- `.gsd-t/contracts/token-budget-contract.md` v3.0.0 — three-band stop-at-85 (M35 clean break from v2.0.0)
|
|
527
|
+
- `.gsd-t/contracts/token-telemetry-contract.md` v1.0.0 — per-spawn 18-field JSONL at `.gsd-t/token-metrics.jsonl`
|
|
528
|
+
- `.gsd-t/contracts/runway-estimator-contract.md` v1.0.0 — pre-flight projection, confidence grading, refusal/headless handoff
|
|
529
|
+
- `.gsd-t/contracts/headless-auto-spawn-contract.md` v1.0.0 — detached continuation, session schema, macOS notification channel
|
|
530
|
+
- `.gsd-t/contracts/model-selection-contract.md` v1.0.0 — per-phase tier mapping + complexity-signal escalation, consumed by `bin/model-selector.js`
|
|
531
|
+
|
|
532
|
+
**M35 supporting components** (outside the context-meter dataflow):
|
|
533
|
+
- `bin/model-selector.js` — declarative rules table mapping phases to haiku/sonnet/opus; consulted at plan time, never at runtime under pressure
|
|
534
|
+
- `bin/token-optimizer.js` — at `complete-milestone`, scans the last 3 milestones of `.gsd-t/token-metrics.jsonl` and appends recalibration recommendations to `.gsd-t/optimization-backlog.md` (never auto-applied; user promotes via `/user:gsd-t-optimization-apply` or rejects via `/user:gsd-t-optimization-reject` with 5-milestone cooldown)
|
|
535
|
+
- `bin/check-headless-sessions.js` — renders the read-back banner on `/user:gsd-t-resume` and `/user:gsd-t-status` for completed-but-not-yet-surfaced headless sessions
|
|
536
|
+
|
|
537
|
+
**Installer integration** (`bin/gsd-t.js`):
|
|
538
|
+
- `install` / `init` — copy hook runtime, merge PostToolUse entry into `~/.claude/settings.json`, copy config template, prompt for API key (skippable, TTY-only)
|
|
539
|
+
- `doctor` — RED on missing API key, missing hook, missing script, invalid config, failed count_tokens dry-run
|
|
540
|
+
- `status` — displays `Context: {pct}% of {window} tokens ({band}) — last check {rel}` line
|
|
541
|
+
- `update-all` — one-shot task-counter retirement migration (deletes legacy files, writes `.gsd-t/.task-counter-retired-v1` marker)
|
|
542
|
+
|
|
371
543
|
## Planned Architecture Changes (M23-M24)
|
|
372
544
|
|
|
373
545
|
**M23: Headless Mode**
|