@tekyzinc/gsd-t 3.10.11 → 3.10.12
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 +41 -0
- package/bin/gsd-t.js +13 -4
- package/bin/token-budget.js +51 -0
- package/commands/gsd-t-execute.md +4 -4
- package/commands/gsd-t-resume.md +29 -0
- package/commands/gsd-t-wave.md +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,47 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [3.10.12] - 2026-04-15
|
|
6
|
+
|
|
7
|
+
### Fixed — P0 context meter regression (M36 /compact incidents)
|
|
8
|
+
|
|
9
|
+
**Background**: During M36 execution the user hit Claude Code's native `/compact` prompt multiple times — the exact scenario M34's Context Meter was built to prevent. Audit of `.gsd-t/.context-meter-state.json` revealed `checkCount=2102` with `pct=0` and `lastError: missing_key` forever. Every one of 2102 PostToolUse hook calls had silently failed at the `ANTHROPIC_API_KEY` check and returned `{}` per the fail-open invariant. `token-budget.getSessionStatus()` read `pct: 0` and reported `threshold: "normal"` to the gate, so the gate was **blind since installation** with no user-visible alarm at any layer.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **`bin/token-budget.js`** — fourth `stale` band in `getSessionStatus()`. When the state file exists but is dead (`lastError` set, `timestamp` null, state older than 5 min, or JSON corrupt), returns `{threshold: "stale", deadReason}` with one of `meter_error:missing_key`, `meter_error:api_error`, `meter_error:parse_failure`, `meter_error:no_transcript`, `meter_never_measured`, `meter_state_stale`, `state_file_corrupt`, `state_file_unreadable`. Previously fell through to the heuristic (which reported 0% and was indistinguishable from a healthy fresh session).
|
|
13
|
+
- **`bin/token-budget.js`** — `buildBandResponse()` handles the `stale` band with a loud message pointing at `gsd-t doctor` and `ANTHROPIC_API_KEY`.
|
|
14
|
+
- **`commands/gsd-t-resume.md`** — new Step 0.6 "Context Meter Health Check" runs after the headless read-back banner and before state loading. If the meter is stale, prints a prominent warning, runs `gsd-t doctor` inline, and refuses to auto-advance into gated commands (`execute`, `wave`, `integrate`, `quick`, `debug`) until fixed.
|
|
15
|
+
- **`.gsd-t/contracts/context-meter-contract.md` v1.1.0** — new §"Stale Band and Resume Gating" documents the regression, the fix, and the mandatory resume-time health check. Also adds a "measurement only, never inference" rule to the configuration section clarifying that the API key named in `apiKeyEnvVar` must never be used for `/v1/messages` inference — inference always runs through the Claude Code subscription.
|
|
16
|
+
- **`.gsd-t/contracts/token-budget-contract.md` v3.1.0** — fourth band added to the threshold table with explicit "gate treats stale as exit-10 stop but does NOT auto-spawn" semantics (a fresh session would have the same broken guardrail).
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **`commands/gsd-t-execute.md`** — Step 3.5 gate snippet (Orchestrator Context Gate) and Step 7 per-domain context gate re-check now exit 10 on `s.threshold==='stop'||s.threshold==='stale'`. Both sites print different user-facing messages for each band: `stop` → "halt cleanly, hand off to runway estimator"; `stale` → "run `gsd-t doctor` and fix the cause".
|
|
20
|
+
- **`commands/gsd-t-wave.md`** — Wave Orchestrator Context Gate snippet now exits 10 on `stale` in addition to `stop`. The `stale` path does NOT call `autoSpawnHeadless()` — a fresh session would have the same broken guardrail.
|
|
21
|
+
- **`bin/gsd-t.js`** — `showStatusContextMeter()` promotes the dead-meter line from a dim ignorable whisper to a red `✗ CONTEXT METER DEAD` alarm with actionable fix instructions (explicitly calls out "measurement only — inference stays on Claude Code subscription" when the cause is `missing_key`). This is the line the user would have seen on every `gsd-t status` run during M36 if it had been loud enough to notice.
|
|
22
|
+
|
|
23
|
+
### Root cause and the 6 hypotheses
|
|
24
|
+
|
|
25
|
+
The continue-here file for this session listed 6 plausible failure modes. The audit disproved 5 of them and proved the sixth:
|
|
26
|
+
1. ❌ Gate only fires at subagent-spawn boundaries — FALSE, coverage is broad (16 command files call `getSessionStatus`, `execute` alone has 13 call sites).
|
|
27
|
+
2. ❌ Coverage holes in command files — FALSE, the 4 gated commands (`execute`, `wave`, `integrate`, `quick`, `debug`) all call the gate.
|
|
28
|
+
3. ❌ `.gsd-t/.context-meter-state.json` stale due to silent hook failure — PARTIALLY; the state was not stale, it was **never fresh**. The file had `timestamp: null` after 2102 checks.
|
|
29
|
+
4. ✅ **PostToolUse hook silent failure on missing `ANTHROPIC_API_KEY` — CONFIRMED root cause.** The hook's `runMeter()` step 5 checks the env var, writes `lastError: {code: "missing_key"}`, persists the state, and returns `{}`. This is correct per the hook's fail-open invariant. But nothing downstream was LOUD about it: `token-budget.js` fell through to the heuristic; the gate saw `threshold: "normal"`; `gsd-t status` printed a dim line.
|
|
30
|
+
5. ❌ Session-tokens vs main-transcript measurement gap — MOOT, you can't have a measurement gap if you never measured.
|
|
31
|
+
6. ❌ 85% stop band too thin — MOOT for the same reason.
|
|
32
|
+
|
|
33
|
+
The v3.10.12 fix targets only the real root cause: **make the gate fail loud when the meter is dead**, and add a resume-time health check so future sessions can't silently run without the guardrail.
|
|
34
|
+
|
|
35
|
+
### User-visible fix
|
|
36
|
+
|
|
37
|
+
If you see `✗ CONTEXT METER DEAD` on `gsd-t status` or `⚠ Context meter is DEAD` from `gsd-t-resume`, set `ANTHROPIC_API_KEY` in your shell profile:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
echo 'export ANTHROPIC_API_KEY="sk-ant-..."' >> ~/.zshrc
|
|
41
|
+
source ~/.zshrc
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Important:** this key is used ONLY for `count_tokens` measurement via the PostToolUse hook and `gsd-t doctor` diagnostics. It is NEVER used for model inference — inference always runs through the Claude Code subscription. The contract `context-meter-contract.md` v1.1.0 Rule #3 enforces this.
|
|
45
|
+
|
|
5
46
|
## [3.10.11] - 2026-04-15
|
|
6
47
|
|
|
7
48
|
### Added
|
package/bin/gsd-t.js
CHANGED
|
@@ -1515,11 +1515,20 @@ function showStatusContextMeter() {
|
|
|
1515
1515
|
return;
|
|
1516
1516
|
}
|
|
1517
1517
|
|
|
1518
|
-
// Error case:
|
|
1519
|
-
|
|
1518
|
+
// Error case: lastError set. Promoted from DIM to ERROR in v3.10.12.
|
|
1519
|
+
// Before: a silent dim line nobody read. After: a red alarm so users see
|
|
1520
|
+
// that the context-window guardrail is DEAD (M36 regression fix).
|
|
1521
|
+
if (state.lastError) {
|
|
1520
1522
|
const code = (state.lastError && state.lastError.code) || "unknown";
|
|
1521
|
-
const rel = state.timestamp ? formatRelativeTime(state.timestamp) : "
|
|
1522
|
-
log(` ${
|
|
1523
|
+
const rel = state.timestamp ? formatRelativeTime(state.timestamp) : "never measured";
|
|
1524
|
+
log(` ${RED}${BOLD}✗ CONTEXT METER DEAD${RESET} ${RED}— error: ${code}, last check: ${rel}${RESET}`);
|
|
1525
|
+
log(` ${RED}The context-window guardrail is NOT working. Long sessions will hit /compact.${RESET}`);
|
|
1526
|
+
if (code === "missing_key") {
|
|
1527
|
+
log(` ${YELLOW}Fix: export ANTHROPIC_API_KEY in your shell profile${RESET}`);
|
|
1528
|
+
log(` ${YELLOW} (measurement only — inference stays on Claude Code subscription)${RESET}`);
|
|
1529
|
+
} else {
|
|
1530
|
+
log(` ${YELLOW}Fix: run 'gsd-t doctor' for diagnostics${RESET}`);
|
|
1531
|
+
}
|
|
1523
1532
|
return;
|
|
1524
1533
|
}
|
|
1525
1534
|
|
package/bin/token-budget.js
CHANGED
|
@@ -115,6 +115,21 @@ function getSessionStatus(projectDir) {
|
|
|
115
115
|
const threshold = resolveThreshold(pct);
|
|
116
116
|
return { consumed, estimated_remaining, pct, threshold };
|
|
117
117
|
}
|
|
118
|
+
// Meter exists but is dead (file present, API key missing, parse/API error,
|
|
119
|
+
// or timestamp stale). Return a `stale` band so callers halt instead of
|
|
120
|
+
// silently running with a blind gate. This is the fix for the M36 /compact
|
|
121
|
+
// regression where checkCount=2102 but every hook call failed fail-open.
|
|
122
|
+
const dead = readContextMeterDead(dir);
|
|
123
|
+
if (dead) {
|
|
124
|
+
const window = dead.modelWindowSize > 0 ? dead.modelWindowSize : 200000;
|
|
125
|
+
return {
|
|
126
|
+
consumed: 0,
|
|
127
|
+
estimated_remaining: window,
|
|
128
|
+
pct: 0,
|
|
129
|
+
threshold: "stale",
|
|
130
|
+
deadReason: dead.reason,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
118
133
|
return getSessionStatusHeuristic(dir);
|
|
119
134
|
}
|
|
120
135
|
|
|
@@ -127,12 +142,42 @@ function readContextMeterState(dir) {
|
|
|
127
142
|
if (!s.timestamp) return null;
|
|
128
143
|
const age = Date.now() - Date.parse(s.timestamp);
|
|
129
144
|
if (isNaN(age) || age > STATE_STALE_MS || age < 0) return null;
|
|
145
|
+
if (s.lastError && typeof s.lastError === "object") return null;
|
|
130
146
|
return s;
|
|
131
147
|
} catch (_) {
|
|
132
148
|
return null;
|
|
133
149
|
}
|
|
134
150
|
}
|
|
135
151
|
|
|
152
|
+
// Return { reason, modelWindowSize } when the state file exists but the meter
|
|
153
|
+
// is not producing a fresh, clean reading. Returns null when the file is
|
|
154
|
+
// missing entirely (no meter installed — fall through to heuristic).
|
|
155
|
+
function readContextMeterDead(dir) {
|
|
156
|
+
try {
|
|
157
|
+
const fp = path.join(dir, STATE_FILE_REL);
|
|
158
|
+
if (!fs.existsSync(fp)) return null;
|
|
159
|
+
const raw = fs.readFileSync(fp, "utf8");
|
|
160
|
+
const s = JSON.parse(raw);
|
|
161
|
+
if (!s || typeof s !== "object") {
|
|
162
|
+
return { reason: "state_file_corrupt", modelWindowSize: 0 };
|
|
163
|
+
}
|
|
164
|
+
const window = Number.isInteger(s.modelWindowSize) ? s.modelWindowSize : 0;
|
|
165
|
+
if (s.lastError && typeof s.lastError === "object" && typeof s.lastError.code === "string") {
|
|
166
|
+
return { reason: `meter_error:${s.lastError.code}`, modelWindowSize: window };
|
|
167
|
+
}
|
|
168
|
+
if (!s.timestamp) {
|
|
169
|
+
return { reason: "meter_never_measured", modelWindowSize: window };
|
|
170
|
+
}
|
|
171
|
+
const age = Date.now() - Date.parse(s.timestamp);
|
|
172
|
+
if (isNaN(age) || age < 0 || age > STATE_STALE_MS) {
|
|
173
|
+
return { reason: "meter_state_stale", modelWindowSize: window };
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
} catch (_) {
|
|
177
|
+
return { reason: "state_file_unreadable", modelWindowSize: 0 };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
136
181
|
function getSessionStatusHeuristic(dir) {
|
|
137
182
|
const window = 200000;
|
|
138
183
|
const consumed = readSessionConsumed(dir);
|
|
@@ -218,6 +263,12 @@ function buildBandResponse(band, pct) {
|
|
|
218
263
|
pct: safePct,
|
|
219
264
|
message: `Context ${safePct.toFixed(1)}% — stop band (≥${STOP_THRESHOLD_PCT}%). Halt cleanly; hand off to runway estimator / headless auto-spawn.`,
|
|
220
265
|
};
|
|
266
|
+
case "stale":
|
|
267
|
+
return {
|
|
268
|
+
band: "stale",
|
|
269
|
+
pct: safePct,
|
|
270
|
+
message: `Context meter is DEAD — no fresh measurements. Gate treats this as STOP. Run: gsd-t doctor. Fix the cause (usually missing ANTHROPIC_API_KEY) before running gated commands.`,
|
|
271
|
+
};
|
|
221
272
|
case "normal":
|
|
222
273
|
default:
|
|
223
274
|
return {
|
|
@@ -529,7 +529,7 @@ Report back:
|
|
|
529
529
|
|
|
530
530
|
6. **Per-domain Red Team** — invoke Step 5.5 (Red Team) NOW for this domain. This is the first place Red Team runs in v2.74.12 — there is no global post-execute Red Team anymore. If Red Team returns FAIL, fix bugs and re-run before proceeding to the next domain (max 2 fix-and-verify cycles); if bugs persist, log to `.gsd-t/deferred-items.md` and present to user.
|
|
531
531
|
|
|
532
|
-
7. **Context gate re-check** — run `node -e "const tb=require('./bin/token-budget.js'); const s=tb.getSessionStatus('.'); if(s.threshold==='stop')process.exit(10); if(s.threshold==='warn')process.exit(13);"`. If exit code is `10`, follow the Step 3.5 STOP procedure now (do NOT spawn the next domain). If exit code is `13`, log the warning and proceed at full quality for the next domain (no model overrides, no phase skips — quality is never silently degraded).
|
|
532
|
+
7. **Context gate re-check** — run `node -e "const tb=require('./bin/token-budget.js'); const s=tb.getSessionStatus('.'); if(s.threshold==='stop'||s.threshold==='stale')process.exit(10); if(s.threshold==='warn')process.exit(13);"`. If exit code is `10`, follow the Step 3.5 STOP procedure now (do NOT spawn the next domain). `stale` means the context meter is dead (usually missing `ANTHROPIC_API_KEY`) and is treated as STOP — print `⚠ Context meter DEAD — run 'gsd-t doctor' and fix before continuing` and halt. If exit code is `13`, log the warning and proceed at full quality for the next domain (no model overrides, no phase skips — quality is never silently degraded).
|
|
533
533
|
|
|
534
534
|
### Team Mode (when agent teams are enabled)
|
|
535
535
|
Spawn teammates for domains within the same wave. Only domains in the same wave can run in parallel — do not spawn teammates for domains in different waves simultaneously. Each teammate uses the **domain task-dispatcher pattern** — one subagent per task within their domain (same as solo mode).
|
|
@@ -680,13 +680,13 @@ The orchestrator MUST check `getSessionStatus()` BEFORE every task subagent spaw
|
|
|
680
680
|
**Before each task spawn — gate check:**
|
|
681
681
|
|
|
682
682
|
```bash
|
|
683
|
-
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);"
|
|
683
|
+
node -e "const tb=require('./bin/token-budget.js'); const s=tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s)); if(s.threshold==='stop'||s.threshold==='stale')process.exit(10); if(s.threshold==='warn')process.exit(13);"
|
|
684
684
|
```
|
|
685
685
|
|
|
686
|
-
Exit code semantics (three-band model per `token-budget-contract.md` v3.0.0):
|
|
686
|
+
Exit code semantics (three-band model per `token-budget-contract.md` v3.0.0, extended with a fourth `stale` guard in v3.10.12):
|
|
687
687
|
- `0` → `normal` band (< 70% ctx). Proceed with standard model assignments.
|
|
688
688
|
- `13` → `warn` band (70–85%). Log the warning to `.gsd-t/token-log.md` and proceed at full quality. **Never downgrade models or skip phases** — M35 removed that behavior intentionally. If the projected runway is insufficient, the runway estimator (m35-runway-estimator) will halt cleanly before reaching `stop`.
|
|
689
|
-
- `10` → `stop` band (≥ 85%)
|
|
689
|
+
- `10` → `stop` band (≥ 85%) **OR `stale` band (meter dead)**. STOP immediately. Do NOT spawn the next task. Jump straight to the STOP procedure below. For `stale`, also print `⚠ Context meter DEAD — run 'gsd-t doctor' and fix the cause (usually missing ANTHROPIC_API_KEY) before resuming` and halt the session — `stale` is not a resumable halt, it means the guardrail is BROKEN, not that the session is full.
|
|
690
690
|
|
|
691
691
|
The JSON on stdout contains `{consumed, estimated_remaining, pct, threshold}` — capture `pct` as `{CTX_PCT}` for the token-log `Ctx%` column on the NEXT spawn.
|
|
692
692
|
|
package/commands/gsd-t-resume.md
CHANGED
|
@@ -72,6 +72,35 @@ This prints a `## Headless runs since you left` banner listing any completed ses
|
|
|
72
72
|
|
|
73
73
|
Contract: `.gsd-t/contracts/headless-auto-spawn-contract.md` v1.0.0
|
|
74
74
|
|
|
75
|
+
## Step 0.6: Context Meter Health Check (MANDATORY, v3.10.12+)
|
|
76
|
+
|
|
77
|
+
Before loading any other state, verify the Context Meter (M34) is actually alive. A dead meter was the root cause of the M36 `/compact` regression (2026-04-15) — `checkCount=2102` but every hook call failed fail-open because `ANTHROPIC_API_KEY` was unset, and the gate silently reported `pct=0` forever.
|
|
78
|
+
|
|
79
|
+
Run via Bash:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
node -e "
|
|
83
|
+
const tb=require('./bin/token-budget.js');
|
|
84
|
+
const s=tb.getSessionStatus('.');
|
|
85
|
+
if (s.threshold === 'stale') {
|
|
86
|
+
console.error('⚠ Context meter is DEAD — reason: ' + (s.deadReason || 'unknown'));
|
|
87
|
+
console.error(' The context-window guardrail is BROKEN. Without it, long sessions will hit /compact silently.');
|
|
88
|
+
console.error(' Fix: set ANTHROPIC_API_KEY in your shell profile (measurement only, never inference).');
|
|
89
|
+
console.error(' Run: gsd-t doctor');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
process.stdout.write('context-meter: ok (' + s.threshold + ', ' + s.pct + '%)\\n');
|
|
93
|
+
" || true
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
If the meter is stale:
|
|
97
|
+
1. **Print the warning** exactly as above (non-fatal — do not halt resume).
|
|
98
|
+
2. **Run `node bin/gsd-t.js doctor`** inline and show the output so the user sees the actionable check list.
|
|
99
|
+
3. **Continue with resume** — but add a prominent `⚠ CONTEXT METER DEAD — gate will treat future gate checks as STOP until fixed` line to your end-of-resume status block so the user cannot miss it.
|
|
100
|
+
4. **Refuse to auto-advance into `execute` / `wave` / `integrate`** until the meter is healthy. If the continue-here file says the next action is one of those gated commands, stop at "meter dead — fix before continuing" instead.
|
|
101
|
+
|
|
102
|
+
Contract: `context-meter-contract.md` v1.1.0 (v3.10.12) — §"Stale Band and Resume Gating"
|
|
103
|
+
|
|
75
104
|
## Step 1: Load Full State (cross-session only)
|
|
76
105
|
|
|
77
106
|
Read in this exact order:
|
package/commands/gsd-t-wave.md
CHANGED
|
@@ -193,15 +193,16 @@ After phase agent returns — run via Bash:
|
|
|
193
193
|
Run via Bash AFTER each phase agent returns:
|
|
194
194
|
|
|
195
195
|
```bash
|
|
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);"
|
|
196
|
+
node -e "const tb=require('./bin/token-budget.js'); const s=tb.getSessionStatus('.'); process.stdout.write(JSON.stringify(s)); if(s.threshold==='stop'||s.threshold==='stale')process.exit(10); if(s.threshold==='warn')process.exit(13);"
|
|
197
197
|
```
|
|
198
198
|
|
|
199
199
|
The JSON on stdout contains `{consumed, estimated_remaining, pct, threshold}` — capture `pct` as `{CTX_PCT}` for the token-log row.
|
|
200
200
|
|
|
201
|
-
Exit-code handling (three-band model per `token-budget-contract.md` v3.0.0):
|
|
201
|
+
Exit-code handling (three-band model per `token-budget-contract.md` v3.0.0, extended with a fourth `stale` guard in v3.10.12):
|
|
202
202
|
- `0` (normal, <70%) → proceed to the next phase at full quality.
|
|
203
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
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.
|
|
205
|
+
- `10` (stale, meter dead) → **not resumable**. The context meter is dead (usually missing `ANTHROPIC_API_KEY`). Do NOT auto-spawn a fresh session — a fresh session would have the same broken guardrail. Instead, halt the wave and print `⚠ Context meter DEAD — run 'gsd-t doctor' and fix the cause before resuming`.
|
|
205
206
|
|
|
206
207
|
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.
|
|
207
208
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.12",
|
|
4
4
|
"description": "GSD-T: Contract-Driven Development for Claude Code — 61 slash commands with unattended supervisor relay, headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
|
|
5
5
|
"author": "Tekyz, Inc.",
|
|
6
6
|
"license": "MIT",
|