@cleocode/skills 2026.5.4 → 2026.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/package.json +1 -1
  2. package/skills/ct-council/SKILL.md +0 -377
  3. package/skills/ct-council/optimization/HARDENING-PLAYBOOK.md +0 -107
  4. package/skills/ct-council/optimization/README.md +0 -74
  5. package/skills/ct-council/optimization/scenarios.yaml +0 -121
  6. package/skills/ct-council/optimization/scripts/campaign.py +0 -543
  7. package/skills/ct-council/optimization/scripts/test_campaign.py +0 -143
  8. package/skills/ct-council/references/chairman.md +0 -119
  9. package/skills/ct-council/references/contrarian.md +0 -70
  10. package/skills/ct-council/references/evidence-pack.md +0 -145
  11. package/skills/ct-council/references/examples.md +0 -235
  12. package/skills/ct-council/references/executor.md +0 -83
  13. package/skills/ct-council/references/expansionist.md +0 -68
  14. package/skills/ct-council/references/first-principles.md +0 -73
  15. package/skills/ct-council/references/outsider.md +0 -73
  16. package/skills/ct-council/references/peer-review.md +0 -125
  17. package/skills/ct-council/scripts/analyze_runs.py +0 -293
  18. package/skills/ct-council/scripts/fixtures/executor_multi.md +0 -198
  19. package/skills/ct-council/scripts/fixtures/missing_advisor.md +0 -117
  20. package/skills/ct-council/scripts/fixtures/missing_convergence.md +0 -190
  21. package/skills/ct-council/scripts/fixtures/thin_evidence.md +0 -193
  22. package/skills/ct-council/scripts/fixtures/valid.md +0 -226
  23. package/skills/ct-council/scripts/fixtures/valid_with_llmtxt.md +0 -226
  24. package/skills/ct-council/scripts/llmtxt_ref.py +0 -223
  25. package/skills/ct-council/scripts/run_council.py +0 -578
  26. package/skills/ct-council/scripts/telemetry.py +0 -624
  27. package/skills/ct-council/scripts/test_telemetry.py +0 -509
  28. package/skills/ct-council/scripts/test_validate.py +0 -452
  29. package/skills/ct-council/scripts/validate.py +0 -396
@@ -1,226 +0,0 @@
1
- # The Council — Should we add a retry-on-timeout wrapper to outbound HTTP calls?
2
-
3
- ## Evidence pack
4
-
5
- 1. `packages/core/src/http.ts:L12-L58` — current httpGet/httpPost; no retry logic.
6
- 2. `packages/core/src/circuit-breaker.ts` — exists with zero callers.
7
- 3. commit `a1b2c3d "drop retries from http client"` — retries removed 18 months ago citing retry storms.
8
-
9
- ## Phase 1 — Advisor analyses
10
-
11
- ### Advisor: Contrarian
12
-
13
- **Frame:** Assume the plan is wrong. What fails first? What's been overlooked? Why is this a worse idea than it looks?
14
-
15
- **Evidence anchored:**
16
- - commit `a1b2c3d` — retries were pulled for a documented reason.
17
- - `packages/core/src/http.ts` — zero per-caller rate limits.
18
-
19
- **Findings (failure modes):**
20
- 1. **Retry storm** — triggers when upstream latency spikes. Fails by multiplying load. Detected silently until breaker trips.
21
-
22
- **Verdict from this lens:** Plan re-introduces a known incident class.
23
-
24
- **Single sharpest point:** A global retry wrapper without a circuit breaker reproduces the exact bug retries were removed to fix.
25
-
26
- ### Advisor: First Principles
27
-
28
- **Frame:** Ignore everything that was said. What is actually true here? Break this down to first principles and answer from zero.
29
-
30
- **Evidence anchored:**
31
- - RFC 7231 — HTTP POST semantics.
32
- - `packages/core/src/http.ts:L12-L58` — current implementation.
33
-
34
- **Atomic truths:**
35
- 1. Some errors are transient; some are not.
36
- 2. Idempotent requests can be retried; non-idempotent cannot.
37
- 3. Unbounded retries are always wrong.
38
-
39
- **Reconstructed solution:** classify errors, retry only idempotent methods on retryable errors, gate through circuit breaker.
40
-
41
- **Reconstruction vs. plan:**
42
- - Convergences: retry on timeout.
43
- - Divergences: no idempotency classification — genuine error.
44
-
45
- **Verdict from this lens:** Plan covers one-third of correct design.
46
-
47
- **Single sharpest point:** Non-idempotent requests cannot be blindly retried.
48
-
49
- ### Advisor: Expansionist
50
-
51
- **Frame:** Forget the constraints. What's the biggest version of this? What opportunity is sitting right in front of us that nobody is talking about?
52
-
53
- **Evidence anchored:**
54
- - `packages/core/src/circuit-breaker.ts` — dormant asset.
55
- - `MEMORY.md` — flaky CI is #2 pain source.
56
-
57
- **Findings (opportunities):**
58
- 1. **Wire breaker** — captures system-wide resilience. Asymmetry: 200 lines for permanent optionality.
59
-
60
- **Verdict from this lens:** Owner is thinking too small; there's a platform layer hiding here.
61
-
62
- **Single sharpest point:** Wire the circuit breaker as part of this change for asymmetric upside.
63
-
64
- ### Advisor: Outsider
65
-
66
- **Frame:** You have no context. Ignore all backstory. Look only at what's in front of you. Tell me what a complete stranger would conclude.
67
-
68
- **Evidence anchored:**
69
- - `packages/core/src/circuit-breaker.ts` — zero callers.
70
- - `docs/adr/ADR-021-http-client.md` — "revisit when circuit-breaker lands".
71
-
72
- **Findings (stranger's eyes):**
73
- 1. Unused module whose ADR says it's the precondition for this exact change.
74
-
75
- **What the artifact claims vs. shows:** ADR claims design awaits the breaker; code shows breaker has landed.
76
-
77
- **Verdict from this lens:** Project prepared but didn't close the loop.
78
-
79
- **Single sharpest point:** ADR-021 says do this when the breaker lands; the breaker has landed; plan ignores both.
80
-
81
- ### Advisor: Executor
82
-
83
- **Frame:** Don't analyze. Don't debate. What is the single most important action to take right now? Give me one step I can start in the next hour.
84
-
85
- **Evidence anchored:**
86
- - `packages/core/test/http.test.ts::handles timeout` — baseline test.
87
- - `packages/core/src/circuit-breaker.ts` — has `execute()` method.
88
-
89
- **The action (one):**
90
- Write `packages/core/test/http-retry.test.ts` with one failing test: httpGet retries once on TimeoutError, httpPost does not.
91
-
92
- **Expected outcome (60 minutes from now):**
93
- New test file, one failing test with message "retries not implemented".
94
-
95
- **What this unblocks:**
96
- Test-first implementation; forces idempotency decision.
97
-
98
- **Verdict from this lens:** Pin the design in a failing test before prose.
99
-
100
- **Single sharpest point:** Write packages/core/test/http-retry.test.ts with retry-on-GET / no-retry-on-POST assertion.
101
-
102
- ## Phase 2 — Shuffled peer reviews
103
-
104
- ### Contrarian reviewing First Principles
105
-
106
- **Gate results:**
107
- - G1 Rigor: PASS — "Non-idempotent requests cannot be blindly retried" is specific.
108
- - G2 Evidence grounding: PASS — cited RFC 7231 and http.ts.
109
- - G3 Frame integrity: PASS — stayed in atomic-truth lane.
110
- - G4 Actionability: PASS — "idempotency classification is mandatory" is decidable.
111
-
112
- **Strongest finding (from reviewee):** The idempotency atom.
113
-
114
- **Gap from Contrarian's frame:** Didn't name the incident class duplicate writes enable.
115
-
116
- **What I would add:** Idempotency omission is not just correctness — it's data-integrity hazard.
117
-
118
- **Disposition:** Accept — correctness framing holds.
119
-
120
- ### First Principles reviewing Expansionist
121
-
122
- **Gate results:**
123
- - G1 Rigor: PASS — names specific opportunity (wire the breaker).
124
- - G2 Evidence grounding: PASS — cites circuit-breaker.ts.
125
- - G3 Frame integrity: PASS — stayed on upside.
126
- - G4 Actionability: PASS — "wire the breaker as part of this change".
127
-
128
- **Strongest finding (from reviewee):** Dormant-asset observation.
129
-
130
- **Gap from First Principles' frame:** 2s timeout claim not derived from atoms.
131
-
132
- **What I would add:** Breaker is a correctness tool, not a performance tool.
133
-
134
- **Disposition:** Accept — core upside is valid.
135
-
136
- ### Expansionist reviewing Outsider
137
-
138
- **Gate results:**
139
- - G1 Rigor: PASS — crisp claim/reality gap.
140
- - G2 Evidence grounding: PASS — cited exact ADR sentence.
141
- - G3 Frame integrity: PASS — no backstory smuggled.
142
- - G4 Actionability: PASS — observation directly decides plan revision.
143
-
144
- **Strongest finding (from reviewee):** ADR says do this when breaker lands; breaker has landed.
145
-
146
- **Gap from Expansionist's frame:** Didn't notice the upside of the unused breaker.
147
-
148
- **What I would add:** Gap isn't just mismatch; it's shovel-ready upgrade.
149
-
150
- **Disposition:** Accept — observation is decisive.
151
-
152
- ### Outsider reviewing Executor
153
-
154
- **Gate results:**
155
- - G1 Rigor: PASS — action is precise, outcome unambiguous.
156
- - G2 Evidence grounding: PASS — test file anchor.
157
- - G3 Frame integrity: PASS — one action, no analysis creep.
158
- - G4 Actionability: PASS — test-writing.
159
-
160
- **Strongest finding (from reviewee):** Pin design in failing test before code.
161
-
162
- **Gap from Outsider's frame:** Action is standard TDD, not novel.
163
-
164
- **What I would add:** Nothing — recognizable good practice validates it.
165
-
166
- **Disposition:** Accept — start now.
167
-
168
- ### Executor reviewing Contrarian
169
-
170
- **Gate results:**
171
- - G1 Rigor: PASS — names specific incident class with trigger.
172
- - G2 Evidence grounding: PASS — cites historical commit and ADR.
173
- - G3 Frame integrity: PASS — pure risk, no upside creep.
174
- - G4 Actionability: PASS — failure is mitigable by wiring the breaker first.
175
-
176
- **Strongest finding (from reviewee):** Retry-storm claim.
177
-
178
- **Gap from Executor's frame:** Says dangerous but doesn't name the action that discharges the risk.
179
-
180
- **What I would add:** The action is: wire the breaker before retries.
181
-
182
- **Disposition:** Accept — risk is real, mitigation is bounded.
183
-
184
- ## Phase 2.5 — Convergence check
185
-
186
- Compared the five "single sharpest point" statements. Distinct subjects: retry storms, idempotency, breaker wiring, ADR-precondition gap, test-first action. No convergence flag raised. Proceeding to Phase 3.
187
-
188
- ## Phase 3 — Chairman's verdict
189
-
190
- ### Gate summary
191
-
192
- | Advisor | G1 Rigor | G2 Evidence | G3 Frame | G4 Actionability | Weight |
193
- |---|---|---|---|---|---|
194
- | Contrarian | PASS | PASS | PASS | PASS | full |
195
- | First Principles | PASS | PASS | PASS | PASS | full |
196
- | Expansionist | PASS | PASS | PASS | PASS | full |
197
- | Outsider | PASS | PASS | PASS | PASS | full |
198
- | Executor | PASS | PASS | PASS | PASS | full |
199
-
200
- ### Recommendation
201
-
202
- Do not ship retries alone. Wire the circuit breaker first, then add retries scoped to idempotent methods (GET) only, driven by a failing test.
203
-
204
- ### Why this, not the alternatives
205
-
206
- Four of five frames converged on the same structural point from different angles: Contrarian flagged retry storms as re-incident risk; First Principles derived idempotency as an atomic truth the plan violated; Outsider identified ADR-021's explicit precondition as already met; Executor chose an action that forces the idempotency decision into a test. The Expansionist's broader frame (system-wide resilience layer) was sharp but out of scope; defer that to follow-up. No unresolved contention.
207
-
208
- ### What each advisor got right (carried forward)
209
-
210
- - **Contrarian's fatal flaw to mitigate:** A retry wrapper without a circuit breaker reproduces the 18-month-old retry-storm incident.
211
- - **First Principles' atomic truth worth protecting:** Non-idempotent requests cannot be blindly retried.
212
- - **Expansionist's upside to pursue (or defer):** The dormant circuit breaker is a system-wide resilience asset; wire it in-scope for this change.
213
- - **Outsider's pattern flag:** ADR-021 said this exact precondition must be met; it has been; the plan ignores both facts.
214
- - **Executor's action (validated):** Write `packages/core/test/http-retry.test.ts` asserting retry-on-GET, no-retry-on-POST.
215
-
216
- ### Conditions on the recommendation
217
-
218
- Conditional on: (1) the failing test being written first, (2) the circuit breaker wired in the same PR as retries, not a follow-up.
219
-
220
- ### Next 60-minute action
221
-
222
- Write `packages/core/test/http-retry.test.ts` with one failing test: httpGet retries once on TimeoutError, httpPost does not retry. Document the idempotency decision in the describe block.
223
-
224
- ### Confidence
225
-
226
- High — four independent frames converged; no unresolved contention; action is startable immediately.
@@ -1,226 +0,0 @@
1
- # The Council — Should we add a retry-on-timeout wrapper to outbound HTTP calls?
2
-
3
- ## Evidence pack
4
-
5
- 1. `packages/core/src/http.ts:L12-L58` — current httpGet/httpPost; no retry logic.
6
- 2. `llmtxt:circuit-breaker-spec@v1` — compressed external spec, fetched via scripts/llmtxt_ref.py.
7
- 3. commit `a1b2c3d "drop retries from http client"` — retries removed 18 months ago citing retry storms.
8
-
9
- ## Phase 1 — Advisor analyses
10
-
11
- ### Advisor: Contrarian
12
-
13
- **Frame:** Assume the plan is wrong. What fails first? What's been overlooked? Why is this a worse idea than it looks?
14
-
15
- **Evidence anchored:**
16
- - commit `a1b2c3d` — retries were pulled for a documented reason.
17
- - `packages/core/src/http.ts` — zero per-caller rate limits.
18
-
19
- **Findings (failure modes):**
20
- 1. **Retry storm** — triggers when upstream latency spikes. Fails by multiplying load. Detected silently until breaker trips.
21
-
22
- **Verdict from this lens:** Plan re-introduces a known incident class.
23
-
24
- **Single sharpest point:** A global retry wrapper without a circuit breaker reproduces the exact bug retries were removed to fix.
25
-
26
- ### Advisor: First Principles
27
-
28
- **Frame:** Ignore everything that was said. What is actually true here? Break this down to first principles and answer from zero.
29
-
30
- **Evidence anchored:**
31
- - RFC 7231 — HTTP POST semantics.
32
- - `packages/core/src/http.ts:L12-L58` — current implementation.
33
-
34
- **Atomic truths:**
35
- 1. Some errors are transient; some are not.
36
- 2. Idempotent requests can be retried; non-idempotent cannot.
37
- 3. Unbounded retries are always wrong.
38
-
39
- **Reconstructed solution:** classify errors, retry only idempotent methods on retryable errors, gate through circuit breaker.
40
-
41
- **Reconstruction vs. plan:**
42
- - Convergences: retry on timeout.
43
- - Divergences: no idempotency classification — genuine error.
44
-
45
- **Verdict from this lens:** Plan covers one-third of correct design.
46
-
47
- **Single sharpest point:** Non-idempotent requests cannot be blindly retried.
48
-
49
- ### Advisor: Expansionist
50
-
51
- **Frame:** Forget the constraints. What's the biggest version of this? What opportunity is sitting right in front of us that nobody is talking about?
52
-
53
- **Evidence anchored:**
54
- - `packages/core/src/circuit-breaker.ts` — dormant asset.
55
- - `MEMORY.md` — flaky CI is #2 pain source.
56
-
57
- **Findings (opportunities):**
58
- 1. **Wire breaker** — captures system-wide resilience. Asymmetry: 200 lines for permanent optionality.
59
-
60
- **Verdict from this lens:** Owner is thinking too small; there's a platform layer hiding here.
61
-
62
- **Single sharpest point:** Wire the circuit breaker as part of this change for asymmetric upside.
63
-
64
- ### Advisor: Outsider
65
-
66
- **Frame:** You have no context. Ignore all backstory. Look only at what's in front of you. Tell me what a complete stranger would conclude.
67
-
68
- **Evidence anchored:**
69
- - `packages/core/src/circuit-breaker.ts` — zero callers.
70
- - `docs/adr/ADR-021-http-client.md` — "revisit when circuit-breaker lands".
71
-
72
- **Findings (stranger's eyes):**
73
- 1. Unused module whose ADR says it's the precondition for this exact change.
74
-
75
- **What the artifact claims vs. shows:** ADR claims design awaits the breaker; code shows breaker has landed.
76
-
77
- **Verdict from this lens:** Project prepared but didn't close the loop.
78
-
79
- **Single sharpest point:** ADR-021 says do this when the breaker lands; the breaker has landed; plan ignores both.
80
-
81
- ### Advisor: Executor
82
-
83
- **Frame:** Don't analyze. Don't debate. What is the single most important action to take right now? Give me one step I can start in the next hour.
84
-
85
- **Evidence anchored:**
86
- - `packages/core/test/http.test.ts::handles timeout` — baseline test.
87
- - `packages/core/src/circuit-breaker.ts` — has `execute()` method.
88
-
89
- **The action (one):**
90
- Write `packages/core/test/http-retry.test.ts` with one failing test: httpGet retries once on TimeoutError, httpPost does not.
91
-
92
- **Expected outcome (60 minutes from now):**
93
- New test file, one failing test with message "retries not implemented".
94
-
95
- **What this unblocks:**
96
- Test-first implementation; forces idempotency decision.
97
-
98
- **Verdict from this lens:** Pin the design in a failing test before prose.
99
-
100
- **Single sharpest point:** Write packages/core/test/http-retry.test.ts with retry-on-GET / no-retry-on-POST assertion.
101
-
102
- ## Phase 2 — Shuffled peer reviews
103
-
104
- ### Contrarian reviewing First Principles
105
-
106
- **Gate results:**
107
- - G1 Rigor: PASS — "Non-idempotent requests cannot be blindly retried" is specific.
108
- - G2 Evidence grounding: PASS — cited RFC 7231 and http.ts.
109
- - G3 Frame integrity: PASS — stayed in atomic-truth lane.
110
- - G4 Actionability: PASS — "idempotency classification is mandatory" is decidable.
111
-
112
- **Strongest finding (from reviewee):** The idempotency atom.
113
-
114
- **Gap from Contrarian's frame:** Didn't name the incident class duplicate writes enable.
115
-
116
- **What I would add:** Idempotency omission is not just correctness — it's data-integrity hazard.
117
-
118
- **Disposition:** Accept — correctness framing holds.
119
-
120
- ### First Principles reviewing Expansionist
121
-
122
- **Gate results:**
123
- - G1 Rigor: PASS — names specific opportunity (wire the breaker).
124
- - G2 Evidence grounding: PASS — cites circuit-breaker.ts.
125
- - G3 Frame integrity: PASS — stayed on upside.
126
- - G4 Actionability: PASS — "wire the breaker as part of this change".
127
-
128
- **Strongest finding (from reviewee):** Dormant-asset observation.
129
-
130
- **Gap from First Principles' frame:** 2s timeout claim not derived from atoms.
131
-
132
- **What I would add:** Breaker is a correctness tool, not a performance tool.
133
-
134
- **Disposition:** Accept — core upside is valid.
135
-
136
- ### Expansionist reviewing Outsider
137
-
138
- **Gate results:**
139
- - G1 Rigor: PASS — crisp claim/reality gap.
140
- - G2 Evidence grounding: PASS — cited exact ADR sentence.
141
- - G3 Frame integrity: PASS — no backstory smuggled.
142
- - G4 Actionability: PASS — observation directly decides plan revision.
143
-
144
- **Strongest finding (from reviewee):** ADR says do this when breaker lands; breaker has landed.
145
-
146
- **Gap from Expansionist's frame:** Didn't notice the upside of the unused breaker.
147
-
148
- **What I would add:** Gap isn't just mismatch; it's shovel-ready upgrade.
149
-
150
- **Disposition:** Accept — observation is decisive.
151
-
152
- ### Outsider reviewing Executor
153
-
154
- **Gate results:**
155
- - G1 Rigor: PASS — action is precise, outcome unambiguous.
156
- - G2 Evidence grounding: PASS — test file anchor.
157
- - G3 Frame integrity: PASS — one action, no analysis creep.
158
- - G4 Actionability: PASS — test-writing.
159
-
160
- **Strongest finding (from reviewee):** Pin design in failing test before code.
161
-
162
- **Gap from Outsider's frame:** Action is standard TDD, not novel.
163
-
164
- **What I would add:** Nothing — recognizable good practice validates it.
165
-
166
- **Disposition:** Accept — start now.
167
-
168
- ### Executor reviewing Contrarian
169
-
170
- **Gate results:**
171
- - G1 Rigor: PASS — names specific incident class with trigger.
172
- - G2 Evidence grounding: PASS — cites historical commit and ADR.
173
- - G3 Frame integrity: PASS — pure risk, no upside creep.
174
- - G4 Actionability: PASS — failure is mitigable by wiring the breaker first.
175
-
176
- **Strongest finding (from reviewee):** Retry-storm claim.
177
-
178
- **Gap from Executor's frame:** Says dangerous but doesn't name the action that discharges the risk.
179
-
180
- **What I would add:** The action is: wire the breaker before retries.
181
-
182
- **Disposition:** Accept — risk is real, mitigation is bounded.
183
-
184
- ## Phase 2.5 — Convergence check
185
-
186
- Compared the five "single sharpest point" statements. Distinct subjects: retry storms, idempotency, breaker wiring, ADR-precondition gap, test-first action. No convergence flag raised. Proceeding to Phase 3.
187
-
188
- ## Phase 3 — Chairman's verdict
189
-
190
- ### Gate summary
191
-
192
- | Advisor | G1 Rigor | G2 Evidence | G3 Frame | G4 Actionability | Weight |
193
- |---|---|---|---|---|---|
194
- | Contrarian | PASS | PASS | PASS | PASS | full |
195
- | First Principles | PASS | PASS | PASS | PASS | full |
196
- | Expansionist | PASS | PASS | PASS | PASS | full |
197
- | Outsider | PASS | PASS | PASS | PASS | full |
198
- | Executor | PASS | PASS | PASS | PASS | full |
199
-
200
- ### Recommendation
201
-
202
- Do not ship retries alone. Wire the circuit breaker first, then add retries scoped to idempotent methods (GET) only, driven by a failing test.
203
-
204
- ### Why this, not the alternatives
205
-
206
- Four of five frames converged on the same structural point from different angles: Contrarian flagged retry storms as re-incident risk; First Principles derived idempotency as an atomic truth the plan violated; Outsider identified ADR-021's explicit precondition as already met; Executor chose an action that forces the idempotency decision into a test. The Expansionist's broader frame (system-wide resilience layer) was sharp but out of scope; defer that to follow-up. No unresolved contention.
207
-
208
- ### What each advisor got right (carried forward)
209
-
210
- - **Contrarian's fatal flaw to mitigate:** A retry wrapper without a circuit breaker reproduces the 18-month-old retry-storm incident.
211
- - **First Principles' atomic truth worth protecting:** Non-idempotent requests cannot be blindly retried.
212
- - **Expansionist's upside to pursue (or defer):** The dormant circuit breaker is a system-wide resilience asset; wire it in-scope for this change.
213
- - **Outsider's pattern flag:** ADR-021 said this exact precondition must be met; it has been; the plan ignores both facts.
214
- - **Executor's action (validated):** Write `packages/core/test/http-retry.test.ts` asserting retry-on-GET, no-retry-on-POST.
215
-
216
- ### Conditions on the recommendation
217
-
218
- Conditional on: (1) the failing test being written first, (2) the circuit breaker wired in the same PR as retries, not a follow-up.
219
-
220
- ### Next 60-minute action
221
-
222
- Write `packages/core/test/http-retry.test.ts` with one failing test: httpGet retries once on TimeoutError, httpPost does not retry. Document the idempotency decision in the describe block.
223
-
224
- ### Confidence
225
-
226
- High — four independent frames converged; no unresolved contention; action is startable immediately.
@@ -1,223 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- llmtxt_ref.py — fetch an llmtxt overview for use as a Council evidence-pack item.
4
-
5
- The llmtxt.my service provides progressive-disclosure document overviews that
6
- compress long external docs (library refs, API specs, ADRs) into 60–80% fewer
7
- tokens, letting the Council ground in external material without blowing out the
8
- evidence pack when five advisor subagents each receive it.
9
-
10
- Usage:
11
- llmtxt_ref.py <slug>[@<version>]
12
- llmtxt_ref.py <slug> --no-cache
13
- llmtxt_ref.py <slug> --json
14
- llmtxt_ref.py <slug> --raw # suppress the evidence-pack header
15
-
16
- Output (stdout):
17
- Markdown-formatted overview, ready to paste into a Phase 0 evidence pack.
18
-
19
- Auth:
20
- Public documents: no auth required (anonymous mode handled server-side).
21
- Private/org documents: set LLMTXT_API_KEY (Bearer token, prefix 'llmtxt_').
22
-
23
- Rate limits (anonymous, per-IP): 60 reads/min. The wrapper honors
24
- x-ratelimit-remaining / x-ratelimit-reset / retry-after headers and surfaces
25
- warnings on stderr.
26
-
27
- Cache:
28
- ~/.cache/council/llmtxt/<slug>/<version>.md (immutable — indefinite)
29
- ~/.cache/council/llmtxt/<slug>/_latest.md (60s TTL)
30
-
31
- Override cache location with COUNCIL_CACHE_DIR; override API base with
32
- LLMTXT_API_BASE (default: https://api.llmtxt.my).
33
-
34
- Exit codes:
35
- 0 — success, overview printed
36
- 1 — network / service error
37
- 2 — not found (404) or not accessible without auth
38
- 3 — invalid slug format / usage error
39
- """
40
-
41
- from __future__ import annotations
42
-
43
- import argparse
44
- import http.cookiejar as cookiejar
45
- import json
46
- import os
47
- import re
48
- import sys
49
- import time
50
- import urllib.error
51
- import urllib.request
52
- from pathlib import Path
53
-
54
- API_BASE = os.environ.get("LLMTXT_API_BASE", "https://api.llmtxt.my")
55
- CACHE_DIR = Path(os.environ.get(
56
- "COUNCIL_CACHE_DIR",
57
- str(Path.home() / ".cache" / "council" / "llmtxt"),
58
- ))
59
- COOKIE_JAR_PATH = CACHE_DIR.parent / "cookies.txt"
60
- LATEST_TTL_SECONDS = 60
61
- TIMEOUT = 30
62
-
63
- SLUG_PATTERN = re.compile(r"^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$")
64
-
65
-
66
- def parse_ref(ref: str) -> tuple[str, str | None]:
67
- """Parse a <slug> or <slug>@<version> reference. Raises ValueError on malformed slug."""
68
- if "@" in ref:
69
- slug, version = ref.split("@", 1)
70
- if not version:
71
- raise ValueError(f"Empty version in reference: {ref!r}")
72
- else:
73
- slug, version = ref, None
74
- if not SLUG_PATTERN.match(slug):
75
- raise ValueError(
76
- f"Invalid slug format: {slug!r}. "
77
- "Expected lowercase alphanumeric with dashes, 1–64 chars, no leading/trailing dash."
78
- )
79
- return slug, version
80
-
81
-
82
- def cache_path(slug: str, version: str | None) -> Path:
83
- """Return the cache path for (slug, version). No filesystem side effects."""
84
- if version:
85
- # Sanitize version for filename safety without altering the slug.
86
- safe_version = re.sub(r"[^a-zA-Z0-9._-]", "_", version)
87
- return CACHE_DIR / slug / f"{safe_version}.md"
88
- return CACHE_DIR / slug / "_latest.md"
89
-
90
-
91
- def cache_is_fresh(path: Path, immutable: bool) -> bool:
92
- """True if the cached file exists and (if mutable) is newer than LATEST_TTL_SECONDS."""
93
- if not path.exists():
94
- return False
95
- if immutable:
96
- return True
97
- age = time.time() - path.stat().st_mtime
98
- return age < LATEST_TTL_SECONDS
99
-
100
-
101
- def _build_opener() -> urllib.request.OpenerDirector:
102
- """Build a URL opener with persistent cookie jar so anonymous sessions survive invocations."""
103
- jar = cookiejar.MozillaCookieJar(str(COOKIE_JAR_PATH))
104
- if COOKIE_JAR_PATH.exists():
105
- try:
106
- jar.load(ignore_discard=True)
107
- except Exception:
108
- # Corrupt cookie file — ignore and overwrite on next save.
109
- pass
110
- opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
111
- return opener
112
-
113
-
114
- def _save_cookies(opener: urllib.request.OpenerDirector) -> None:
115
- for handler in opener.handlers:
116
- if isinstance(handler, urllib.request.HTTPCookieProcessor):
117
- jar = handler.cookiejar
118
- if isinstance(jar, cookiejar.MozillaCookieJar):
119
- COOKIE_JAR_PATH.parent.mkdir(parents=True, exist_ok=True)
120
- try:
121
- jar.save(ignore_discard=True)
122
- except Exception:
123
- pass
124
- return
125
-
126
-
127
- def fetch_overview(slug: str, version: str | None, timeout: int = TIMEOUT) -> str:
128
- """Fetch overview from api.llmtxt.my. Raises LookupError for 404, RuntimeError otherwise.
129
-
130
- Uses a persistent cookie jar so anonymous sessions (better-auth anonymous plugin,
131
- 24h TTL) survive across invocations. For private/org documents, set LLMTXT_API_KEY.
132
- """
133
- url = f"{API_BASE}/api/documents/{slug}/overview"
134
- if version:
135
- url += f"?version={version}"
136
- req = urllib.request.Request(url, headers={"User-Agent": "council-skill/1.0"})
137
- api_key = os.environ.get("LLMTXT_API_KEY")
138
- if api_key:
139
- req.add_header("Authorization", f"Bearer {api_key}")
140
-
141
- opener = _build_opener()
142
- try:
143
- with opener.open(req, timeout=timeout) as resp:
144
- body = resp.read().decode("utf-8")
145
- remaining = resp.headers.get("x-ratelimit-remaining")
146
- if remaining and remaining.isdigit() and int(remaining) == 0:
147
- reset = resp.headers.get("x-ratelimit-reset", "unknown")
148
- print(f"⚠️ llmtxt rate limit exhausted; resets at {reset}.", file=sys.stderr)
149
- _save_cookies(opener)
150
- return body
151
- except urllib.error.HTTPError as e:
152
- # Even on error, the server may have set an anonymous session cookie.
153
- _save_cookies(opener)
154
- if e.code == 404:
155
- raise LookupError(f"Document not found or not accessible: {slug}") from e
156
- if e.code == 429:
157
- try:
158
- payload = json.loads(e.read().decode("utf-8"))
159
- retry = payload.get("retryAfter", e.headers.get("retry-after", "unknown"))
160
- except Exception:
161
- retry = e.headers.get("retry-after", "unknown")
162
- raise RuntimeError(f"Rate limited by api.llmtxt.my; retry after {retry}s") from e
163
- if e.code in (401, 403):
164
- raise RuntimeError(
165
- f"HTTP {e.code}: {e.reason}. "
166
- "Document requires auth — set LLMTXT_API_KEY (Bearer llmtxt_<43-char-token>)."
167
- ) from e
168
- raise RuntimeError(f"HTTP {e.code}: {e.reason}") from e
169
- except urllib.error.URLError as e:
170
- raise RuntimeError(f"Network error: {e.reason}") from e
171
-
172
-
173
- def get_overview(slug: str, version: str | None = None, use_cache: bool = True) -> str:
174
- """Cache-aware read. Returns the overview body as markdown."""
175
- path = cache_path(slug, version)
176
- immutable = version is not None
177
- if use_cache and cache_is_fresh(path, immutable):
178
- return path.read_text()
179
- body = fetch_overview(slug, version)
180
- path.parent.mkdir(parents=True, exist_ok=True)
181
- path.write_text(body)
182
- return body
183
-
184
-
185
- def format_for_evidence_pack(slug: str, version: str | None, body: str) -> str:
186
- """Wrap the overview body with an evidence-pack-friendly header."""
187
- ref = f"llmtxt:{slug}" + (f"@{version}" if version else "")
188
- return f"<!-- evidence-pack item: `{ref}` -->\n\n{body.rstrip()}\n"
189
-
190
-
191
- def main():
192
- parser = argparse.ArgumentParser(
193
- description="Fetch an llmtxt overview for a Council evidence pack.",
194
- )
195
- parser.add_argument("ref", help="Document reference: <slug> or <slug>@<version>")
196
- parser.add_argument("--no-cache", action="store_true", help="Bypass the local cache.")
197
- parser.add_argument("--json", action="store_true", help="Emit the raw API response.")
198
- parser.add_argument("--raw", action="store_true", help="Suppress the evidence-pack header.")
199
- args = parser.parse_args()
200
-
201
- try:
202
- slug, version = parse_ref(args.ref)
203
- except ValueError as e:
204
- print(f"❌ {e}", file=sys.stderr)
205
- sys.exit(3)
206
-
207
- try:
208
- body = get_overview(slug, version, use_cache=not args.no_cache)
209
- except LookupError as e:
210
- print(f"❌ {e}", file=sys.stderr)
211
- sys.exit(2)
212
- except RuntimeError as e:
213
- print(f"❌ {e}", file=sys.stderr)
214
- sys.exit(1)
215
-
216
- if args.json or args.raw:
217
- print(body)
218
- else:
219
- print(format_for_evidence_pack(slug, version, body))
220
-
221
-
222
- if __name__ == "__main__":
223
- main()