@cleocode/skills 2026.10.12 → 2026.10.13
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/package.json +1 -1
- package/skills/ct-cleo/SKILL.md +3 -3
- package/skills/ct-council/SKILL.md +25 -3
- package/skills/ct-council/scripts/run_council.py +164 -2
- package/skills/ct-council/scripts/test_docs_store.py +235 -0
- package/skills/ct-documentor/SKILL.md +20 -3
- package/skills/ct-lean/SKILL.md +20 -2
- package/skills/ct-orchestrator/SKILL.md +25 -2
- package/skills/manifest.json +5 -5
package/package.json
CHANGED
package/skills/ct-cleo/SKILL.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
name: ct-cleo
|
|
3
3
|
description: CLEO task management protocol - session, task, and workflow guidance. Use when managing tasks, sessions, or multi-agent workflows with the CLEO CLI protocol.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 2.24.
|
|
5
|
+
version: 2.24.13
|
|
6
6
|
tier: core
|
|
7
7
|
install: harness
|
|
8
8
|
covers:
|
|
9
9
|
- packages/cleo/src/cli/commands/session.ts
|
|
10
10
|
- packages/cleo/src/cli/commands/focus.ts
|
|
11
11
|
- packages/cleo/src/cli/commands/sticky.ts
|
|
12
|
-
lastReviewed: 2026-10-
|
|
12
|
+
lastReviewed: 2026-10-13
|
|
13
13
|
stability: stable
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -463,4 +463,4 @@ BRAIN ID going forward.
|
|
|
463
463
|
|
|
464
464
|
## Evidence must prove task criteria
|
|
465
465
|
|
|
466
|
-
Merged PRs and passing CI are provenance. Implementation requires changed artifacts related to the task; testing and review require their own actual results (`ci:<pr>` once the PR merged and the project sets `evidence.ciSatisfies`; else `tool:test-affected` when `testing.affectedCommand` is configured, otherwise a targeted `test-run:<json>` or `tool:test`; plan with `cleo done <id> --plan`, never run the suite by hand and again via `tool:test`). Run tests, typechecks and builds one at a time through `cleo run --wait --class <test|build|full-build> -- <cmd>` (exit 75: not admitted yet, wait and retry); never wrap `cleo run` or `cleo verify` in another queue or wrapper, and never raise heap or worker counts (`NODE_OPTIONS`, `--maxWorkers`). For tasks with canonical criteria, append explicit links such as `satisfies:T1234#AC1` to each relevant gate's evidence. Fetch the PR merge commit so artifact hashes can be inspected. A changed criterion invalidates its recorded proof. Completing a child preserves an open parent whose own criteria remain unproven; child waivers never transfer to parent criteria.
|
|
466
|
+
Merged PRs and passing CI are provenance. Implementation requires changed artifacts related to the task; testing and review require their own actual results (`ci:<pr>` once the PR merged and the project sets `evidence.ciSatisfies`; else `tool:test-affected` when `testing.affectedCommand` is configured, otherwise a targeted `test-run:<json>` or `tool:test`; after merge a scoped run carries only while the change's files are byte-identical, or when it is a `test-run:` recorded on a main HEAD descending from the merge, on the current tree, covering the change (T13673); plan with `cleo done <id> --plan`, which never plans a whole-suite `tool:test` itself (T13647); never run the suite by hand and again via `tool:test`). Run tests, typechecks and builds one at a time through `cleo run --wait --class <test|build|full-build> -- <cmd>` (exit 75: not admitted yet, wait and retry); never wrap `cleo run` or `cleo verify` in another queue or wrapper, and never raise heap or worker counts (`NODE_OPTIONS`, `--maxWorkers`). For tasks with canonical criteria, append explicit links such as `satisfies:T1234#AC1` to each relevant gate's evidence. Fetch the PR merge commit so artifact hashes can be inspected. A changed criterion invalidates its recorded proof. Completing a child preserves an open parent whose own criteria remain unproven; child waivers never transfer to parent criteria.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: ct-council
|
|
3
3
|
description: Convene "The Council" — a 5-advisor, shuffled gate-based peer-review, chairman-synthesis workflow for reviewing a plan, decision, architecture, or piece of work inside the current project. Use when the user says "convene the council" (or "counsel"), "get the council on this", "council review", "run the five advisors", "stress-test this", "get multiple perspectives", or asks for a rigorous multi-angle challenge of a proposal (Contrarian, First Principles, Expansionist, Outsider, Executor → shuffled peer review with pass/fail gates → convergence detector → Chairman verdict). Operates on the current codebase — each advisor grounds their analysis in actual files/commits before opining. Output is validated by scripts/validate.py.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 1.
|
|
5
|
+
version: 1.1.1
|
|
6
6
|
tier: on-demand
|
|
7
7
|
install: harness
|
|
8
8
|
stability: stable
|
|
@@ -67,6 +67,7 @@ Every run lives under a run directory (`<run-dir>/`, created by `scripts/run_cou
|
|
|
67
67
|
| `<run-dir>/phase3.md` | **Orchestrator** (or Chairman agent if delegated) | Phase 3 |
|
|
68
68
|
| `<run-dir>/output.md` | **Orchestrator** (assembled from above) | After Phase 3 |
|
|
69
69
|
| `<run-dir>/verdict.md`, `tldr.md` | **Auto-generated** by `run_council.py ingest` | After validate |
|
|
70
|
+
| CleoDocs store doc (slug `council-run-<run_id>`) | **Auto-written** by `run_council.py ingest` via `cleo docs add`/`cleo docs update` | After validate (T13363 AC2) |
|
|
70
71
|
|
|
71
72
|
The agent file-write contract: each Phase-1 / Phase-2 subagent must use the `Write` tool to save its full output markdown to the path above and return ONLY a one-line confirmation. The orchestrator does NOT include the agent's full output in its return-context — that bloats the orchestrator window unnecessarily.
|
|
72
73
|
|
|
@@ -295,7 +296,7 @@ The `--title` flag is optional; if omitted the title is auto-derived from the qu
|
|
|
295
296
|
|
|
296
297
|
### Validation + auto-generation
|
|
297
298
|
|
|
298
|
-
`scripts/run_council.py ingest <run-dir>` validates `output.md`, then automatically writes `verdict.md` and `tldr.md` to the same run dir, then appends a telemetry record to `.cleo/council-runs.jsonl
|
|
299
|
+
`scripts/run_council.py ingest <run-dir>` validates `output.md`, then automatically writes `verdict.md` and `tldr.md` to the same run dir, then appends a telemetry record to `.cleo/council-runs.jsonl`, then pushes the assembled `output.md` into the CleoDocs store as a sectioned `note` doc. Direct usage:
|
|
299
300
|
|
|
300
301
|
```bash
|
|
301
302
|
# Full output (default)
|
|
@@ -306,9 +307,30 @@ python3 scripts/validate.py --phase 0 <phase0.md> # only H1 + evidence pack
|
|
|
306
307
|
python3 scripts/validate.py --phase 1 <file.md> # +5 advisor sections
|
|
307
308
|
python3 scripts/validate.py --phase 2 <file.md> # +5 peer reviews
|
|
308
309
|
|
|
309
|
-
python3 scripts/run_council.py ingest <run-dir> # validate + verdict.md + tldr.md + telemetry
|
|
310
|
+
python3 scripts/run_council.py ingest <run-dir> # validate + verdict.md + tldr.md + telemetry + store doc
|
|
310
311
|
```
|
|
311
312
|
|
|
313
|
+
### Store write (T13363 AC2)
|
|
314
|
+
|
|
315
|
+
`ingest` also pushes the run's output document into the CleoDocs store so the per-phase
|
|
316
|
+
`##` sections land as CRDT-merged sections instead of only loose files:
|
|
317
|
+
|
|
318
|
+
- **Slug** — `council-run-<run_id>` (stable per run; re-ingesting the same run updates
|
|
319
|
+
the same doc instead of creating a new one). The slug is stamped into the INDEX entry
|
|
320
|
+
as `docs_slug` only when the store write succeeded.
|
|
321
|
+
- **Kind** — `note`; owner is `--owner <id>` if passed, else the `CLEO_SESSION_ID`
|
|
322
|
+
environment variable, else the session the CLI binds to (`cleo session status`; under
|
|
323
|
+
Claude Code only `CLAUDE_CODE_SESSION_ID` is set and the CLI resolves it). The markdown
|
|
324
|
+
is piped via `--content -` (stdin), never argv.
|
|
325
|
+
- **Ordered, non-fatal + additive** — the store write runs after the telemetry record and
|
|
326
|
+
the INDEX entry are written; those and the raw run dir remain the source of truth. Every
|
|
327
|
+
`cleo` call has a 60 s timeout. If it fails, times out, or no owner is resolvable,
|
|
328
|
+
ingest logs a warning and continues. `--no-store` skips the write.
|
|
329
|
+
|
|
330
|
+
Retrieve a run's doc with `cleo docs fetch council-run-<run_id>`; each re-ingest that
|
|
331
|
+
changes the bytes bumps the doc's version (see the `docVersion` field in the update
|
|
332
|
+
envelope).
|
|
333
|
+
|
|
312
334
|
The validator **auto-detects partial files** when no `--phase` is passed: if no Phase 3 header is present, it validates up to the highest phase the file contains and prints a stderr suggestion. This prevents the "12 missing-section errors" wall of red when you're checking a phase0.md or phase1-*.md mid-flight.
|
|
313
335
|
|
|
314
336
|
Exit code 0 = structurally valid. Non-zero = fix the violations before surfacing the verdict.
|
|
@@ -13,14 +13,22 @@ It does NOT spawn agents itself (the orchestrator does that — see SKILL.md
|
|
|
13
13
|
3. Validator + telemetry hooks: a validated `output.md` is automatically
|
|
14
14
|
appended to .cleo/council-runs.jsonl with optional --tokens / --wall-clock
|
|
15
15
|
stamps.
|
|
16
|
-
4.
|
|
16
|
+
4. Store write (T13363 AC2): a validated `output.md` is ALSO pushed into the
|
|
17
|
+
CleoDocs store as a sectioned `note` doc (slug `council-run-<run_id>`)
|
|
18
|
+
via `cleo docs add` / `cleo docs update` (idempotent re-ingest updates
|
|
19
|
+
the same doc). The store write is ADDITIVE and NON-FATAL — the raw run
|
|
20
|
+
dir + JSONL telemetry remain the audit source of truth.
|
|
21
|
+
5. A `--scenario` flag that names the shakedown (1..8) for telemetry
|
|
17
22
|
filtering and exit-criteria reporting.
|
|
18
23
|
|
|
19
24
|
Subcommands:
|
|
20
25
|
|
|
21
26
|
init <question> create a new run directory + skeleton phase0 prompt
|
|
22
27
|
validate <run-dir> run validate.py on the assembled output.md
|
|
23
|
-
ingest <run-dir> validate + emit telemetry to the JSONL log
|
|
28
|
+
ingest <run-dir> validate + emit telemetry to the JSONL log AND push
|
|
29
|
+
output.md into the CleoDocs store (slug
|
|
30
|
+
council-run-<run_id>; --no-store to skip,
|
|
31
|
+
--owner to override the doc owner)
|
|
24
32
|
list show all runs under the configured runs dir
|
|
25
33
|
|
|
26
34
|
Convention: assemble phase outputs into <run-dir>/output.md by hand or by
|
|
@@ -39,6 +47,7 @@ import argparse
|
|
|
39
47
|
import datetime as _dt
|
|
40
48
|
import hashlib
|
|
41
49
|
import json
|
|
50
|
+
import os
|
|
42
51
|
import re
|
|
43
52
|
import subprocess
|
|
44
53
|
import sys
|
|
@@ -234,6 +243,136 @@ def cmd_validate(args) -> int:
|
|
|
234
243
|
return code
|
|
235
244
|
|
|
236
245
|
|
|
246
|
+
# ─── CleoDocs store write (T13363 AC2) ──────────────────────────────────────
|
|
247
|
+
#
|
|
248
|
+
# The run's output document (assembled output.md — one `##` phase per agent)
|
|
249
|
+
# is pushed into the CleoDocs store so concurrent multi-agent edits land as
|
|
250
|
+
# CRDT-merged sections instead of loose files. Raw run artifacts under
|
|
251
|
+
# .cleo/council-runs/ stay the telemetry source of truth; the store write is
|
|
252
|
+
# additive and non-fatal (a failure warns and ingest continues).
|
|
253
|
+
|
|
254
|
+
def docs_slug_for_run(run_id: str) -> str:
|
|
255
|
+
"""Stable per-run store slug: `council-run-<run_id>` (kebab-case, ≤80 chars)."""
|
|
256
|
+
return f"council-run-{run_id}"
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# Bound on every `cleo` subprocess: a hung CLI must never block ingest.
|
|
260
|
+
CLEO_TIMEOUT_SEC = 60
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _bound_cleo_session() -> str | None:
|
|
264
|
+
"""The CLEO session the CLI itself binds to (CLAUDE_CODE_SESSION_ID, the
|
|
265
|
+
terminal, …), read from `cleo session status`. None on any failure."""
|
|
266
|
+
try:
|
|
267
|
+
r = subprocess.run(
|
|
268
|
+
["cleo", "session", "status", "--field", "/data/session/session/id", "--quiet"],
|
|
269
|
+
capture_output=True, text=True, timeout=CLEO_TIMEOUT_SEC,
|
|
270
|
+
)
|
|
271
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
272
|
+
return None
|
|
273
|
+
sid = (r.stdout or "").strip()
|
|
274
|
+
return sid if r.returncode == 0 and sid.startswith("ses_") else None
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def resolve_docs_owner(args) -> str | None:
|
|
278
|
+
"""Owner for the store doc: --owner flag, else CLEO_SESSION_ID, else the
|
|
279
|
+
session the CLI binds to (`cleo session status`; under Claude Code only
|
|
280
|
+
CLAUDE_CODE_SESSION_ID is set, and the CLI resolves it).
|
|
281
|
+
|
|
282
|
+
Returns None when no owner can be determined — the caller then skips the
|
|
283
|
+
store write (non-fatal).
|
|
284
|
+
"""
|
|
285
|
+
owner = getattr(args, "owner", None)
|
|
286
|
+
if owner:
|
|
287
|
+
return owner
|
|
288
|
+
return os.environ.get("CLEO_SESSION_ID") or _bound_cleo_session()
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _docs_subprocess_env(owner: str) -> dict:
|
|
292
|
+
env = dict(os.environ)
|
|
293
|
+
# Attribute the write to the owning session when the owner IS a session.
|
|
294
|
+
if owner.startswith("ses_"):
|
|
295
|
+
env["CLEO_SESSION_ID"] = owner
|
|
296
|
+
return env
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _run_cleo_docs(cmd: list, *, content: str, env: dict) -> subprocess.CompletedProcess:
|
|
300
|
+
# Content flows via stdin (`--content -`): argv never carries the markdown,
|
|
301
|
+
# so verdicts of any size are safe from shell-quoting limits.
|
|
302
|
+
return subprocess.run(
|
|
303
|
+
cmd, input=content, capture_output=True, text=True, env=env,
|
|
304
|
+
timeout=CLEO_TIMEOUT_SEC,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def push_run_to_docs_store(
|
|
309
|
+
*,
|
|
310
|
+
run_dir: Path,
|
|
311
|
+
meta: dict,
|
|
312
|
+
content: str,
|
|
313
|
+
owner: str,
|
|
314
|
+
) -> bool:
|
|
315
|
+
"""Push output.md into the CleoDocs store as a sectioned `note` doc.
|
|
316
|
+
|
|
317
|
+
Idempotent: `cleo docs add` first; on E_SLUG_RESERVED (re-ingest of a
|
|
318
|
+
known run) falls back to `cleo docs update`, which noops when the bytes
|
|
319
|
+
are unchanged. Returns True when the doc is in the store; on any failure
|
|
320
|
+
prints a warning and returns False — NEVER raises into ingest.
|
|
321
|
+
"""
|
|
322
|
+
rid = meta.get("run_id") or run_dir.name
|
|
323
|
+
slug = docs_slug_for_run(rid)
|
|
324
|
+
title = (meta.get("title") or f"Council run {rid}")[:DEFAULT_TITLE_MAX_LEN]
|
|
325
|
+
question = meta.get("question") or ""
|
|
326
|
+
desc = f"Council run {rid} — {question} (audit trail: {run_dir})".strip()
|
|
327
|
+
env = _docs_subprocess_env(owner)
|
|
328
|
+
|
|
329
|
+
add_cmd = [
|
|
330
|
+
"cleo", "docs", "add", owner,
|
|
331
|
+
"--content", "-",
|
|
332
|
+
"--type", "note",
|
|
333
|
+
"--slug", slug,
|
|
334
|
+
f"--title={title}", # one token: a title starting with "-" is never a flag
|
|
335
|
+
"--desc", desc,
|
|
336
|
+
"--attached-by", "council",
|
|
337
|
+
"--json",
|
|
338
|
+
]
|
|
339
|
+
try:
|
|
340
|
+
result = _run_cleo_docs(add_cmd, content=content, env=env)
|
|
341
|
+
except (OSError, subprocess.TimeoutExpired) as e:
|
|
342
|
+
print(f"⚠️ Store write skipped — could not run `cleo docs add`: {e}", file=sys.stderr)
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
if result.returncode == 0:
|
|
346
|
+
print(f"📦 Verdict doc written to store: slug '{slug}' (owner {owner})", file=sys.stderr)
|
|
347
|
+
return True
|
|
348
|
+
|
|
349
|
+
combined = (result.stdout or "") + (result.stderr or "")
|
|
350
|
+
if "E_SLUG_RESERVED" not in combined:
|
|
351
|
+
detail = combined.strip().splitlines()[0] if combined.strip() else f"exit {result.returncode}"
|
|
352
|
+
print(f"⚠️ Store write failed (`cleo docs add` {slug}): {detail}", file=sys.stderr)
|
|
353
|
+
return False
|
|
354
|
+
|
|
355
|
+
# Re-ingest of a known run: update the existing doc instead.
|
|
356
|
+
update_cmd = [
|
|
357
|
+
"cleo", "docs", "update", slug,
|
|
358
|
+
"--content", "-",
|
|
359
|
+
"--message", f"council re-ingest {rid}",
|
|
360
|
+
"--json",
|
|
361
|
+
]
|
|
362
|
+
try:
|
|
363
|
+
result = _run_cleo_docs(update_cmd, content=content, env=env)
|
|
364
|
+
except (OSError, subprocess.TimeoutExpired) as e:
|
|
365
|
+
print(f"⚠️ Store update skipped — could not run `cleo docs update`: {e}", file=sys.stderr)
|
|
366
|
+
return False
|
|
367
|
+
if result.returncode == 0:
|
|
368
|
+
print(f"📦 Verdict doc updated in store: slug '{slug}'", file=sys.stderr)
|
|
369
|
+
return True
|
|
370
|
+
combined = (result.stdout or "") + (result.stderr or "")
|
|
371
|
+
detail = combined.strip().splitlines()[0] if combined.strip() else f"exit {result.returncode}"
|
|
372
|
+
print(f"⚠️ Store update failed (`cleo docs update` {slug}): {detail}", file=sys.stderr)
|
|
373
|
+
return False
|
|
374
|
+
|
|
375
|
+
|
|
237
376
|
def cmd_ingest(args) -> int:
|
|
238
377
|
run_dir = Path(args.run_dir)
|
|
239
378
|
output_path = run_dir / "output.md"
|
|
@@ -331,6 +470,20 @@ def cmd_ingest(args) -> int:
|
|
|
331
470
|
"wall_clock_seconds": args.wall_clock,
|
|
332
471
|
})
|
|
333
472
|
print(f"📋 INDEX.jsonl updated at {_index_path(runs_dir)}", file=sys.stderr)
|
|
473
|
+
|
|
474
|
+
# T13363 AC2 — push the run's output document into the CleoDocs store, AFTER
|
|
475
|
+
# the telemetry record and the INDEX entry exist (the audit source of truth).
|
|
476
|
+
# Additive + non-fatal; docs_slug is stamped only when the write succeeded.
|
|
477
|
+
if not getattr(args, "no_store", False):
|
|
478
|
+
owner = resolve_docs_owner(args)
|
|
479
|
+
if owner is None:
|
|
480
|
+
print(
|
|
481
|
+
"⚠️ Store write skipped — no owner (pass --owner <id>, set CLEO_SESSION_ID, "
|
|
482
|
+
"or start a cleo session)",
|
|
483
|
+
file=sys.stderr,
|
|
484
|
+
)
|
|
485
|
+
elif push_run_to_docs_store(run_dir=run_dir, meta=meta, content=md, owner=owner) and meta.get("run_id"):
|
|
486
|
+
_upsert_index(run_dir.parent, meta["run_id"], {"docs_slug": docs_slug_for_run(meta["run_id"])})
|
|
334
487
|
return 0
|
|
335
488
|
|
|
336
489
|
|
|
@@ -550,6 +703,15 @@ def main():
|
|
|
550
703
|
p_ing.add_argument("--log", default=str(DEFAULT_LOG_PATH))
|
|
551
704
|
p_ing.add_argument("--tokens", type=int, default=None)
|
|
552
705
|
p_ing.add_argument("--wall-clock", type=float, default=None)
|
|
706
|
+
p_ing.add_argument(
|
|
707
|
+
"--owner", default=None,
|
|
708
|
+
help="Owner id for the CleoDocs store doc (default: CLEO_SESSION_ID, else the "
|
|
709
|
+
"session `cleo session status` binds to).",
|
|
710
|
+
)
|
|
711
|
+
p_ing.add_argument(
|
|
712
|
+
"--no-store", action="store_true",
|
|
713
|
+
help="Skip the CleoDocs store write (T13363 AC2) — raw artifacts only.",
|
|
714
|
+
)
|
|
553
715
|
p_ing.set_defaults(func=cmd_ingest)
|
|
554
716
|
|
|
555
717
|
p_list = sub.add_parser("list", help="List runs from INDEX.jsonl.")
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""Tests for the CleoDocs store write in run_council.py (T13363 AC2).
|
|
2
|
+
|
|
3
|
+
The store push is additive and non-fatal: these tests mock subprocess.run
|
|
4
|
+
(no real `cleo` binary or store is touched) and prove the invocation shape,
|
|
5
|
+
the idempotent add→update fallback, and that failures never raise into
|
|
6
|
+
ingest.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import json
|
|
13
|
+
import shutil
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
import tempfile
|
|
17
|
+
import unittest
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from unittest import mock
|
|
20
|
+
|
|
21
|
+
SCRIPTS_DIR = Path(__file__).resolve().parent
|
|
22
|
+
sys.path.insert(0, str(SCRIPTS_DIR))
|
|
23
|
+
import run_council # noqa: E402
|
|
24
|
+
|
|
25
|
+
CONTENT = "# The Council — retry?\n\n## Phase 1 — advisors\n\n...\n"
|
|
26
|
+
META = {
|
|
27
|
+
"run_id": "abcdef12",
|
|
28
|
+
"title": "Retry on timeout",
|
|
29
|
+
"question": "Should we retry on timeout?",
|
|
30
|
+
}
|
|
31
|
+
RUN_DIR = Path(".cleo/council-runs/20261013T000000-abcdef12")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _completed(cmd, returncode=0, stdout="", stderr=""):
|
|
35
|
+
return subprocess.CompletedProcess(cmd, returncode, stdout=stdout, stderr=stderr)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TestDocsSlug(unittest.TestCase):
|
|
39
|
+
def test_slug_scheme(self):
|
|
40
|
+
self.assertEqual(run_council.docs_slug_for_run("abcdef12"), "council-run-abcdef12")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TestResolveOwner(unittest.TestCase):
|
|
44
|
+
def test_flag_wins(self):
|
|
45
|
+
args = mock.Mock(owner="T1234", spec=["owner"])
|
|
46
|
+
self.assertEqual(run_council.resolve_docs_owner(args), "T1234")
|
|
47
|
+
|
|
48
|
+
def test_env_fallback(self):
|
|
49
|
+
args = mock.Mock(owner=None, spec=["owner"])
|
|
50
|
+
with mock.patch.dict("os.environ", {"CLEO_SESSION_ID": "ses_x"}, clear=True):
|
|
51
|
+
self.assertEqual(run_council.resolve_docs_owner(args), "ses_x")
|
|
52
|
+
|
|
53
|
+
def test_none_when_unset(self):
|
|
54
|
+
args = mock.Mock(owner=None, spec=["owner"])
|
|
55
|
+
with mock.patch.dict("os.environ", {}, clear=True), \
|
|
56
|
+
mock.patch.object(run_council.subprocess, "run", side_effect=OSError("no cleo")):
|
|
57
|
+
self.assertIsNone(run_council.resolve_docs_owner(args))
|
|
58
|
+
|
|
59
|
+
def test_claude_code_session_only_resolves_through_the_cli(self):
|
|
60
|
+
# T13658: under Claude Code only CLAUDE_CODE_SESSION_ID is set; the CLI
|
|
61
|
+
# binds it to a cleo session, which becomes the owner.
|
|
62
|
+
args = mock.Mock(owner=None, spec=["owner"])
|
|
63
|
+
with mock.patch.dict("os.environ", {"CLAUDE_CODE_SESSION_ID": "cc-123"}, clear=True), \
|
|
64
|
+
mock.patch.object(run_council.subprocess, "run") as m:
|
|
65
|
+
m.return_value = _completed([], returncode=0, stdout="ses_bound\n")
|
|
66
|
+
self.assertEqual(run_council.resolve_docs_owner(args), "ses_bound")
|
|
67
|
+
(cmd,), kwargs = m.call_args
|
|
68
|
+
self.assertEqual(cmd[:3], ["cleo", "session", "status"])
|
|
69
|
+
self.assertIn("timeout", kwargs)
|
|
70
|
+
|
|
71
|
+
def test_hung_session_status_is_none(self):
|
|
72
|
+
args = mock.Mock(owner=None, spec=["owner"])
|
|
73
|
+
with mock.patch.dict("os.environ", {}, clear=True), \
|
|
74
|
+
mock.patch.object(run_council.subprocess, "run",
|
|
75
|
+
side_effect=subprocess.TimeoutExpired(["cleo"], 60)):
|
|
76
|
+
self.assertIsNone(run_council.resolve_docs_owner(args))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class TestPushRunToDocsStore(unittest.TestCase):
|
|
80
|
+
def _push(self, mock_run, **kwargs):
|
|
81
|
+
defaults = dict(run_dir=RUN_DIR, meta=dict(META), content=CONTENT, owner="ses_x")
|
|
82
|
+
defaults.update(kwargs)
|
|
83
|
+
return run_council.push_run_to_docs_store(**defaults)
|
|
84
|
+
|
|
85
|
+
def test_add_invocation_shape(self):
|
|
86
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
87
|
+
m.return_value = _completed([], returncode=0, stdout='{"success":true}')
|
|
88
|
+
ok = self._push(m)
|
|
89
|
+
self.assertTrue(ok)
|
|
90
|
+
(cmd,), kwargs = m.call_args
|
|
91
|
+
self.assertEqual(cmd[:4], ["cleo", "docs", "add", "ses_x"])
|
|
92
|
+
self.assertIn("--content", cmd)
|
|
93
|
+
self.assertEqual(cmd[cmd.index("--content") + 1], "-") # stdin, never argv
|
|
94
|
+
self.assertEqual(cmd[cmd.index("--type") + 1], "note")
|
|
95
|
+
self.assertEqual(cmd[cmd.index("--slug") + 1], "council-run-abcdef12")
|
|
96
|
+
self.assertEqual(kwargs["input"], CONTENT) # markdown flows via stdin
|
|
97
|
+
self.assertEqual(kwargs["env"]["CLEO_SESSION_ID"], "ses_x")
|
|
98
|
+
self.assertEqual(kwargs["timeout"], run_council.CLEO_TIMEOUT_SEC)
|
|
99
|
+
self.assertIn("--title=Retry on timeout", cmd)
|
|
100
|
+
|
|
101
|
+
def test_dash_title_stays_one_token(self):
|
|
102
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
103
|
+
m.return_value = _completed([], returncode=0)
|
|
104
|
+
self._push(m, meta={**META, "title": "--force everything"})
|
|
105
|
+
(cmd,), _ = m.call_args
|
|
106
|
+
self.assertIn("--title=--force everything", cmd)
|
|
107
|
+
self.assertNotIn("--force everything", cmd)
|
|
108
|
+
|
|
109
|
+
def test_hung_cleo_is_non_fatal(self):
|
|
110
|
+
with mock.patch.object(run_council.subprocess, "run",
|
|
111
|
+
side_effect=subprocess.TimeoutExpired(["cleo"], 60)):
|
|
112
|
+
self.assertFalse(self._push(mock.Mock()))
|
|
113
|
+
|
|
114
|
+
def test_session_env_only_for_session_owner(self):
|
|
115
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
116
|
+
m.return_value = _completed([], returncode=0)
|
|
117
|
+
with mock.patch.dict("os.environ", {"CLEO_SESSION_ID": "ses_other"}, clear=True):
|
|
118
|
+
ok = self._push(m, owner="T1234")
|
|
119
|
+
self.assertTrue(ok)
|
|
120
|
+
(_,), kwargs = m.call_args
|
|
121
|
+
self.assertEqual(kwargs["env"]["CLEO_SESSION_ID"], "ses_other")
|
|
122
|
+
|
|
123
|
+
def test_slug_reserved_falls_back_to_update(self):
|
|
124
|
+
reserved = _completed([], returncode=1, stdout='{"success":false,"error":{"codeName":"E_SLUG_RESERVED"}}')
|
|
125
|
+
updated = _completed([], returncode=0, stdout='{"success":true}')
|
|
126
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
127
|
+
m.side_effect = [reserved, updated]
|
|
128
|
+
ok = self._push(m)
|
|
129
|
+
self.assertTrue(ok)
|
|
130
|
+
self.assertEqual(m.call_count, 2)
|
|
131
|
+
(cmd,), _ = m.call_args
|
|
132
|
+
self.assertEqual(cmd[:3], ["cleo", "docs", "update"])
|
|
133
|
+
self.assertEqual(cmd[3], "council-run-abcdef12")
|
|
134
|
+
self.assertIn("abcdef12", cmd[cmd.index("--message") + 1])
|
|
135
|
+
|
|
136
|
+
def test_add_failure_is_non_fatal(self):
|
|
137
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
138
|
+
m.return_value = _completed([], returncode=1, stdout='{"success":false,"error":{"codeName":"E_BOOM"}}')
|
|
139
|
+
ok = self._push(m)
|
|
140
|
+
self.assertFalse(ok)
|
|
141
|
+
self.assertEqual(m.call_count, 1) # no update fallback on other errors
|
|
142
|
+
|
|
143
|
+
def test_missing_binary_is_non_fatal(self):
|
|
144
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
145
|
+
m.side_effect = OSError("No such file or directory: 'cleo'")
|
|
146
|
+
ok = self._push(m)
|
|
147
|
+
self.assertFalse(ok)
|
|
148
|
+
|
|
149
|
+
def test_update_failure_is_non_fatal(self):
|
|
150
|
+
reserved = _completed([], returncode=1, stdout="E_SLUG_RESERVED")
|
|
151
|
+
failed = _completed([], returncode=1, stderr="boom")
|
|
152
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
153
|
+
m.side_effect = [reserved, failed]
|
|
154
|
+
ok = self._push(m)
|
|
155
|
+
self.assertFalse(ok)
|
|
156
|
+
|
|
157
|
+
def test_fallback_requires_slug_reserved_marker(self):
|
|
158
|
+
# A non-reserved add failure must NOT attempt an update.
|
|
159
|
+
with mock.patch.object(run_council.subprocess, "run") as m:
|
|
160
|
+
m.return_value = _completed([], returncode=1, stderr="E_VALIDATION")
|
|
161
|
+
ok = self._push(m)
|
|
162
|
+
self.assertFalse(ok)
|
|
163
|
+
self.assertEqual(m.call_count, 1)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class TestIngestOrdering(unittest.TestCase):
|
|
167
|
+
"""T13659: telemetry + INDEX are written first; docs_slug only on success."""
|
|
168
|
+
|
|
169
|
+
REAL_RUN = staticmethod(subprocess.run)
|
|
170
|
+
|
|
171
|
+
def setUp(self):
|
|
172
|
+
self.tmp = Path(tempfile.mkdtemp(prefix="council-ingest-"))
|
|
173
|
+
self.run_dir = self.tmp / "runs" / "20261013T000000-abcdef12"
|
|
174
|
+
self.run_dir.mkdir(parents=True)
|
|
175
|
+
shutil.copy(SCRIPTS_DIR / "fixtures" / "valid.md", self.run_dir / "output.md")
|
|
176
|
+
(self.run_dir / "run.json").write_text(json.dumps(META))
|
|
177
|
+
self.log = self.tmp / "council-runs.jsonl"
|
|
178
|
+
|
|
179
|
+
def tearDown(self):
|
|
180
|
+
shutil.rmtree(self.tmp, ignore_errors=True)
|
|
181
|
+
|
|
182
|
+
def _ingest(self, cleo_behaviour):
|
|
183
|
+
def fake_run(cmd, *a, **kw):
|
|
184
|
+
if cmd and cmd[0] == "cleo":
|
|
185
|
+
return cleo_behaviour(cmd)
|
|
186
|
+
return self.REAL_RUN(cmd, *a, **kw) # real validate.py / telemetry.py
|
|
187
|
+
|
|
188
|
+
args = argparse.Namespace(run_dir=str(self.run_dir), log=str(self.log), tokens=None,
|
|
189
|
+
wall_clock=None, owner="ses_x", no_store=False)
|
|
190
|
+
with mock.patch.object(run_council.subprocess, "run", side_effect=fake_run) as m:
|
|
191
|
+
code = run_council.cmd_ingest(args)
|
|
192
|
+
index = [json.loads(line) for line in (self.tmp / "runs" / "INDEX.jsonl").read_text().splitlines()]
|
|
193
|
+
return code, m, index[0]
|
|
194
|
+
|
|
195
|
+
def _assert_records_written(self, code, entry):
|
|
196
|
+
self.assertEqual(code, 0)
|
|
197
|
+
self.assertTrue(self.log.read_text().strip(), "telemetry JSONL record missing")
|
|
198
|
+
self.assertEqual(entry["status"], "ingested")
|
|
199
|
+
|
|
200
|
+
def test_hung_cleo_does_not_block_and_records_still_land(self):
|
|
201
|
+
def hung(cmd):
|
|
202
|
+
raise subprocess.TimeoutExpired(cmd, run_council.CLEO_TIMEOUT_SEC)
|
|
203
|
+
code, _, entry = self._ingest(hung)
|
|
204
|
+
self._assert_records_written(code, entry)
|
|
205
|
+
self.assertNotIn("docs_slug", entry)
|
|
206
|
+
|
|
207
|
+
def test_failed_write_stamps_no_docs_slug(self):
|
|
208
|
+
code, _, entry = self._ingest(lambda cmd: _completed(cmd, returncode=1, stderr="E_BOOM"))
|
|
209
|
+
self._assert_records_written(code, entry)
|
|
210
|
+
self.assertNotIn("docs_slug", entry)
|
|
211
|
+
|
|
212
|
+
def test_skipped_write_stamps_no_docs_slug(self):
|
|
213
|
+
args_owner = mock.patch.object(run_council, "resolve_docs_owner", return_value=None)
|
|
214
|
+
with args_owner:
|
|
215
|
+
code, m, entry = self._ingest(lambda cmd: _completed(cmd, returncode=0))
|
|
216
|
+
self._assert_records_written(code, entry)
|
|
217
|
+
self.assertNotIn("docs_slug", entry)
|
|
218
|
+
self.assertFalse(any(c.args[0][0] == "cleo" for c in m.call_args_list))
|
|
219
|
+
|
|
220
|
+
def test_successful_write_runs_last_and_stamps_docs_slug(self):
|
|
221
|
+
order = []
|
|
222
|
+
|
|
223
|
+
def ok(cmd):
|
|
224
|
+
order.append("cleo")
|
|
225
|
+
self.assertTrue(self.log.read_text().strip(), "store write ran before telemetry")
|
|
226
|
+
self.assertTrue((self.tmp / "runs" / "INDEX.jsonl").exists(), "store write ran before INDEX")
|
|
227
|
+
return _completed(cmd, returncode=0)
|
|
228
|
+
code, _, entry = self._ingest(ok)
|
|
229
|
+
self._assert_records_written(code, entry)
|
|
230
|
+
self.assertEqual(order, ["cleo"])
|
|
231
|
+
self.assertEqual(entry["docs_slug"], "council-run-abcdef12")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
if __name__ == "__main__":
|
|
235
|
+
unittest.main()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ct-documentor
|
|
3
3
|
description: Documentation coordinator with CLEO style guide compliance. Routes every canonical-doc write (spec, adr, research, handoff, note, llm-readme) through the docs SSoT via `cleo docs add` / `cleo docs publish` / `cleo docs fetch` — never raw filesystem writes. Carries the CLEO writing and review guides as references and coordinates ct-spec-writer and ct-adr-recorder. Use when creating or updating documentation files, consolidating scattered documentation, or validating documentation against style standards. Triggers on documentation tasks, doc update requests, or style guide compliance checks.
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.25.1
|
|
5
5
|
protocol: null
|
|
6
6
|
dependencies:
|
|
7
7
|
- ct-spec-writer
|
|
@@ -16,13 +16,13 @@ compatibility:
|
|
|
16
16
|
- gemini-cli
|
|
17
17
|
license: MIT
|
|
18
18
|
metadata:
|
|
19
|
-
version: 3.
|
|
19
|
+
version: 3.25.1
|
|
20
20
|
tier: core
|
|
21
21
|
install: harness
|
|
22
22
|
covers:
|
|
23
23
|
- packages/cleo/src/cli/commands/docs.ts
|
|
24
24
|
- packages/contracts/src/docs-taxonomy.ts
|
|
25
|
-
lastReviewed: 2026-10-
|
|
25
|
+
lastReviewed: 2026-10-14
|
|
26
26
|
stability: stable
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -59,12 +59,28 @@ T13361 retired the legacy verbs `search`, `find`, `rank` (use `query`),
|
|
|
59
59
|
`import`; `sync` stays until the T9645 reingest workflow migrates, and
|
|
60
60
|
`status` stays agent-facing per `cleodocs-rearch-design` §6.
|
|
61
61
|
|
|
62
|
+
`cleo docs stats` (T13363) is a read-only adoption-metrics probe: add:update
|
|
63
|
+
ratio from the docs audit log, loose-markdown count (gitignore-aware scan),
|
|
64
|
+
`docs_wikilinks` edge count, and live `decision_adr_links` count. Use it for
|
|
65
|
+
pilot baseline comparisons — it never writes.
|
|
66
|
+
|
|
62
67
|
`cleo docs doctor` (T13447) audits the docs store — dangling `local-file`
|
|
63
68
|
pointers, docVersion skew vs the audit log, empty topics/related_tasks,
|
|
64
69
|
`docs_wikilinks` drift, legacy store surfaces, stale drafts — and with
|
|
65
70
|
`--apply` repairs them after creating a backup automatically. Use it for
|
|
66
71
|
store hygiene checks; it never edits doc content.
|
|
67
72
|
|
|
73
|
+
`cleo docs migrate` (T13360) imports legacy docs + history into the re-keyed
|
|
74
|
+
conduit store inside the migration safety harness (pre-step backup, verified
|
|
75
|
+
rollback, COMMIT only on full verification). It is additive and idempotent:
|
|
76
|
+
every imported history row is labeled `origin: migrated`, authors come from
|
|
77
|
+
the legacy audit log (or the honest `system:migration` attribution — never
|
|
78
|
+
invented), docs whose content pointers dangle are content-captured or
|
|
79
|
+
recorded dangling in `conduit_doc_migration_ledger`, and a re-run is a
|
|
80
|
+
verified no-op. Legacy slugs that already exist natively are counted as
|
|
81
|
+
native-conflict skips, never clobbered. Run it once per project before the
|
|
82
|
+
T13361/T13362 retirement lands; it needs no `--force`.
|
|
83
|
+
|
|
68
84
|
For discovery (`find`, `search`, `schema`, `list-types`), prefer `cleo docs list`
|
|
69
85
|
first — it returns slug + owner + type without forcing a filesystem walk. Use
|
|
70
86
|
legacy discovery verbs only when `list` is insufficient.
|
|
@@ -173,6 +189,7 @@ Before adding a new doc, ALWAYS ask: is this **a new doc**, **a change to an exi
|
|
|
173
189
|
- **"Fix a typo in ADR-076 saga-first-class"** - `cleo docs update adr-076-saga-first-class --file /tmp/fixed.md --message "fix typo in §2"` (canonical - T10161). NOT a new doc. NOT a supersession. Just patch in place; T10161 squashes patches within a 5-minute window so consecutive typo fixes don't bloat the audit log.
|
|
174
190
|
- **"Accept a spec that review signed off"** - `cleo docs update <slug> --status accepted` (T12654). `--status` alone changes only the lifecycle status (draft, proposed, accepted, superseded, archived, deprecated); the stored bytes are kept, so there is no need to re-supply `--file` or `--content`. Any content edit without `--status` resets the doc to `draft`.
|
|
175
191
|
- **"Replace a doc's body from a pipe"** - `cat new.md | cleo docs update <slug> --content -` (T13564). As in `docs add`, `-` reads stdin; an empty or bare `-` body is refused, never stored.
|
|
192
|
+
- **"Editing a doc another agent may touch"** - `cleo docs fetch <slug>` first, note `metadata.headVersionUid`, then `cleo docs update <slug> --file new.md --base-version-uid <headVersionUid>` (T13674). A stale base merges append edits into the head (`staleBaseMerged: true`) or records `sectionConflicts` — a concurrent writer's edit is never silently dropped; a base that no longer resolves is refused with `E_DOC_BASE_UNKNOWN`. `--file` must be UTF-8 text when a base is given (`E_DOC_BASE_UNSUPPORTED` otherwise). The update result's `headVersionUid` is the base for your next edit, so chained edits need no re-fetch.
|
|
176
193
|
- **"Trace an ADR to the decisions it ratifies"** - `cleo docs link-decision <adr-slug> D####` (T13598): the slug must be an existing doc and the decision a stored one, since a link is permanent. `cleo docs fetch <adr-slug>` then lists them as `linkedDecisions`. `cleo docs unlink-decision <adr-slug> D####` cannot be undone: the revoke is a permanent tombstone, and that pair can never be re-linked.
|
|
177
194
|
|
|
178
195
|
- **"Replace the entire saga-orchestration model with v2" (ADVANCED)** - `cleo docs add T9999 v2.md --type adr --slug adr-080-saga-orchestration-v2` followed by `cleo docs supersede adr-073-above-epic-naming adr-080-saga-orchestration-v2 --reason "v2 canonicalizes the SG- prefix + 4-tier hierarchy"`. Both rows survive in the attachments table; readers see `lifecycle_status=superseded` on v1 and `supersedes=adr-073` on v2.
|
package/skills/ct-lean/SKILL.md
CHANGED
|
@@ -8,12 +8,13 @@ description: >-
|
|
|
8
8
|
gates, package boundaries, validation, data safety or anything the task asked for.
|
|
9
9
|
license: MIT
|
|
10
10
|
metadata:
|
|
11
|
-
version: 1.
|
|
11
|
+
version: 1.1.0
|
|
12
12
|
tier: core
|
|
13
13
|
install: harness
|
|
14
14
|
covers:
|
|
15
15
|
- packages/core/src/orchestration/lean-change.ts
|
|
16
|
-
|
|
16
|
+
- packages/cleo/src/cli/commands/lean.ts
|
|
17
|
+
lastReviewed: 2026-10-13
|
|
17
18
|
stability: stable
|
|
18
19
|
attribution: Adapted from Ponytail 5.1.0 by DietrichGebert (MIT) — https://github.com/DietrichGebert/ponytail
|
|
19
20
|
---
|
|
@@ -24,6 +25,20 @@ The best code is the code never written. Solve the whole task with the least new
|
|
|
24
25
|
then end the reply with one or two lines: what you skipped or did not check, and any risk
|
|
25
26
|
the owner must know.
|
|
26
27
|
|
|
28
|
+
## Levels
|
|
29
|
+
|
|
30
|
+
| Level | What changes |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `lite` | Build what was asked. When a smaller option fully works, name it in one line and let the owner pick. |
|
|
33
|
+
| `full` | The rules below. Default. |
|
|
34
|
+
| `ultra` | `full`, and question the request first: push back on any part the need does not justify. |
|
|
35
|
+
| `off` | No lean rules. |
|
|
36
|
+
|
|
37
|
+
The level resolves from `CLEO_LEAN_LEVEL`, then the session level, then the `lean.level`
|
|
38
|
+
config key, then `full`. When the owner asks for a level ("go ultra", "lean off"), set it:
|
|
39
|
+
`cleo lean level ultra --session` for this session, `cleo lean level lite` for the project,
|
|
40
|
+
`--global` for every project. `cleo lean level` alone shows the level and its source.
|
|
41
|
+
|
|
27
42
|
## Before you write
|
|
28
43
|
|
|
29
44
|
Read the task (`cleo show <id> --full`) and the code it touches. List every place the
|
|
@@ -65,7 +80,10 @@ callers that stop working, stores it would migrate. That is scope. Extra feature
|
|
|
65
80
|
## Never cut
|
|
66
81
|
|
|
67
82
|
- Validation at trust boundaries, error handling that prevents data loss, security,
|
|
83
|
+
privacy (one user's data never reaches another, e.g. many recipients go in BCC, not To),
|
|
68
84
|
accessibility, and anything the task or owner asked for.
|
|
85
|
+
- A risk your change creates is part of the change: when the fix is small and in scope,
|
|
86
|
+
make it, then name it in the reply. Only report a risk you cannot fix in scope.
|
|
69
87
|
- CLEO evidence: every gate gets programmatic evidence (`cleo verify`), never self-attested.
|
|
70
88
|
- Type safety: no `any`, no `as unknown as X`; shared types live in `packages/contracts/`.
|
|
71
89
|
- The package boundary and the `cleo check arch` gates; a smaller diff in the wrong package
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
name: ct-orchestrator
|
|
3
3
|
description: "Pipeline-aware orchestration skill for managing complex workflows through subagent delegation. Use when the user asks to \"orchestrate\", \"orchestrator mode\", \"run as orchestrator\", \"delegate to subagents\", \"coordinate agents\", \"spawn subagents\", \"multi-agent workflow\", \"context-protected workflow\", \"agent farm\", \"HITL orchestration\", \"pipeline management\", or needs to manage complex workflows by delegating work to subagents while protecting the main context window. Enforces ORC-001 through ORC-009 constraints. Provider-neutral — works with any AI agent runtime."
|
|
4
4
|
metadata:
|
|
5
|
-
version: 4.0.
|
|
5
|
+
version: 4.0.15
|
|
6
6
|
tier: core
|
|
7
7
|
install: harness
|
|
8
8
|
covers:
|
|
9
9
|
- packages/cleo/src/cli/commands/orchestrate.ts
|
|
10
10
|
- packages/core/src/orchestration/spawn-prompt.ts
|
|
11
|
-
lastReviewed: 2026-10-
|
|
11
|
+
lastReviewed: 2026-10-13
|
|
12
12
|
stability: stable
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -148,6 +148,10 @@ cleo orchestrate spawn T1586 --json
|
|
|
148
148
|
|
|
149
149
|
Returns: resolved prompt with base protocol + conditional protocol + task context + all `{{TOKEN}}` placeholders filled.
|
|
150
150
|
|
|
151
|
+
The prompt's `## Lean Change` block follows the effective ct-lean level (T13663):
|
|
152
|
+
`CLEO_LEAN_LEVEL`, then the spawning session's `cleo lean level --session`, then `lean.level`,
|
|
153
|
+
then `full`. At `off` the block is omitted, so set the level before spawning, not after.
|
|
154
|
+
|
|
151
155
|
The spawn provisions the worker's worktree, and its `pnpm install` is admitted through the heavy queue or deferred to the worker; the envelope's `install.status` says which. `cleo orchestrate spawn T1586 --no-install` provisions without installing, and the envelope names the command the worker runs instead (T13524).
|
|
152
156
|
|
|
153
157
|
### Step 2: Execute (Provider-Specific)
|
|
@@ -217,6 +221,25 @@ cleo orchestrate start T1575 # Full state: session, pipeline, next task
|
|
|
217
221
|
4. Present plan to human for approval
|
|
218
222
|
```
|
|
219
223
|
|
|
224
|
+
**Stage output documents go to the store (T13363 AC2).** When a stage finishes its
|
|
225
|
+
output document (research findings, consensus record, spec), keep the working copy at
|
|
226
|
+
`.cleo/rcasd/<epic>/<stage>/` AND push the finished document into the CleoDocs store
|
|
227
|
+
so its `##` sections land as versioned, collaboratively-mergeable sections:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# First time — owner is the epic task, kind matches the stage
|
|
231
|
+
cleo docs add T1575 .cleo/rcasd/T1575/research/T1575-research.md \
|
|
232
|
+
--type research --slug t1575-research
|
|
233
|
+
|
|
234
|
+
# Re-runs / refreshes update the same doc (noop when bytes are unchanged)
|
|
235
|
+
cleo docs update t1575-research --file .cleo/rcasd/T1575/research/T1575-research.md \
|
|
236
|
+
--message "research stage refresh"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Retrieve with `cleo docs fetch t1575-research`. The raw stage file stays the working
|
|
240
|
+
copy and gate input; the store doc is the durable sectioned record. Skipping the store
|
|
241
|
+
write is not fatal — but a stage is not "published" until the store doc exists.
|
|
242
|
+
|
|
220
243
|
### 3. IVTR — Execute the Work
|
|
221
244
|
|
|
222
245
|
```
|
package/skills/manifest.json
CHANGED
|
@@ -226,7 +226,7 @@
|
|
|
226
226
|
},
|
|
227
227
|
{
|
|
228
228
|
"name": "ct-cleo",
|
|
229
|
-
"version": "2.24.
|
|
229
|
+
"version": "2.24.13",
|
|
230
230
|
"description": "CLEO task management protocol - session, task, and workflow guidance. Use when managing tasks, sessions, or multi-agent workflows with the CLEO CLI protocol.",
|
|
231
231
|
"path": "skills/ct-cleo",
|
|
232
232
|
"tier": 0,
|
|
@@ -479,7 +479,7 @@
|
|
|
479
479
|
},
|
|
480
480
|
{
|
|
481
481
|
"name": "ct-council",
|
|
482
|
-
"version": "1.
|
|
482
|
+
"version": "1.1.1",
|
|
483
483
|
"description": "Convene \"The Council\" — a 5-advisor, shuffled gate-based peer-review, chairman-synthesis workflow for reviewing a plan, decision, architecture, or piece of work inside the current project. Use when the user says \"convene the council\" (or \"counsel\"), \"get the council on this\", \"council review\", \"run the five advisors\", \"stress-test this\", \"get multiple perspectives\", or asks for a rigorous multi-angle challenge of a proposal (Contrarian, First Principles, Expansionist, Outsider, Executor → shuffled peer review with pass/fail gates → convergence detector → Chairman verdict). Operates on the current codebase — each advisor grounds their analysis in actual files/commits before opining. Output is validated by scripts/validate.py.",
|
|
484
484
|
"path": "skills/ct-council",
|
|
485
485
|
"tier": 1,
|
|
@@ -642,7 +642,7 @@
|
|
|
642
642
|
},
|
|
643
643
|
{
|
|
644
644
|
"name": "ct-documentor",
|
|
645
|
-
"version": "3.
|
|
645
|
+
"version": "3.25.1",
|
|
646
646
|
"description": "Documentation coordinator with CLEO style guide compliance. Routes every canonical-doc write (spec, adr, research, handoff, note, llm-readme) through the docs SSoT via `cleo docs add` / `cleo docs publish` / `cleo docs fetch` — never raw filesystem writes. Carries the CLEO writing and review guides as references and coordinates ct-spec-writer and ct-adr-recorder. Use when creating or updating documentation files, consolidating scattered documentation, or validating documentation against style standards. Triggers on documentation tasks, doc update requests, or style guide compliance checks.",
|
|
647
647
|
"path": "skills/ct-documentor",
|
|
648
648
|
"tier": 0,
|
|
@@ -983,7 +983,7 @@
|
|
|
983
983
|
},
|
|
984
984
|
{
|
|
985
985
|
"name": "ct-lean",
|
|
986
|
-
"version": "1.
|
|
986
|
+
"version": "1.1.0",
|
|
987
987
|
"description": "Lean change discipline for CLEO work: the smallest change that fully solves the task, and a reply a busy owner understands in one read. Use on every coding task (writing, fixing, refactoring, reviewing, choosing dependencies) and when the owner asks for the simplest solution, YAGNI, or complains about over-engineering or bloat. Never trades away evidence gates, package boundaries, validation, data safety or anything the task asked for.",
|
|
988
988
|
"path": "skills/ct-lean",
|
|
989
989
|
"tier": 0,
|
|
@@ -1001,7 +1001,7 @@
|
|
|
1001
1001
|
},
|
|
1002
1002
|
{
|
|
1003
1003
|
"name": "ct-orchestrator",
|
|
1004
|
-
"version": "4.0.
|
|
1004
|
+
"version": "4.0.15",
|
|
1005
1005
|
"description": "Pipeline-aware orchestration skill for managing complex workflows through subagent delegation. Use when the user asks to \\\"orchestrate\\\", \\\"orchestrator mode\\\", \\\"run as orchestrator\\\", \\\"delegate to subagents\\\", \\\"coordinate agents\\\", \\\"spawn subagents\\\", \\\"multi-agent workflow\\\", \\\"context-protected workflow\\\", \\\"agent farm\\\", \\\"HITL orchestration\\\", \\\"pipeline management\\\", or needs to manage complex workflows by delegating work to subagents while protecting the main context window. Enforces ORC-001 through ORC-009 constraints. Provider-neutral — works with any AI agent runtime.",
|
|
1006
1006
|
"path": "skills/ct-orchestrator",
|
|
1007
1007
|
"tier": 0,
|