docs: re-init CLAUDE.md and align all four harness prompts - #2
Conversation
`/init` replaced the scaffold seed `CLAUDE.md` with a runtime prompt grounded in this repo, and the other three harness files were brought in line with it — each written for its own harness rather than restating the same text. - CLAUDE.md: command block (tests, single test, every lint/rubric/smoke gate), the cross-file CLI wiring (`_CliArgumentParser.error()` override, the `_json_hint` argv peek, the `parser_class` propagation trap, `CliError`, the stdout/stderr split, the catalog walked by `tests/test_cli.py`), a five-place checklist for adding a Substack noun, and `_PROMPT_FILE` vs `_RESIDENT_PROMPT`. - QWEN.md: the coding-session machinery for a Qwen Code session. - AGENTS.override.md: context only (identity stays in `.pi/SYSTEM.md`), and tells Pi's non-coding lane to report the scaffold gap rather than infer an implementation from the project description. - AGENTS.colleague.md: rewritten around colleague as the `/ask-colleague` second mind — per-verb expectations, the contracts a diff must respect, and the colleague#494 empty-skills caveat. - README.md: template-clone instructions replaced by this repo's own Status / CLI / Development sections. Fixes four drifts the docs carried: a Substack surface (posts, comments, statistics, subscribers) that does not exist on disk; a quickstart using `uv run substack-cli …` when `[project.scripts]` installs the binary as `substack`; a skill count of 11 against 19 on disk; and three files calling `CLAUDE.md` "the fullest write-up" while it was still the `/init` seed. Verified: 117 tests pass, `teken cli doctor . --strict` PASS, `harness-smoke --stage config` 6/6 PASS, scan-secrets clean, markdownlint clean, `devex pr lint` no violations. Qwen and Pi were asked "Who are you, and what can you do?" in this tree and both answered from their new files. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01VaCYnmwSaYL2DLxDtd1fTs
|
/agentic_review |
PR Summary by QodoAlign harness prompts with substack-cli scaffold reality
AI Description
Diagram
High-Level Assessment
Files changed (8)
|
Code Review by Qodo
1.
|
The Worktrees section claimed the vendored skill's fan-out example uses a shared `../worktrees/` path that must be overridden. It does not: the current `.claude/skills/assign-to-workforce/SKILL.md` mandates the same repo-named `.worktrees.<repo-name>` root this file does, and explicitly says "Never use a bare `../worktrees/`". The claim was inherited from culture-agent-template's CLAUDE.md and describes an older revision of the vendored file. Only the branch-name half of the override still applies (`agent/<task-id>`). Found by `ask-colleague review` on this PR. Its other two findings: the "eight skills originate in devague" phrasing is correct as written (docs/skill-sources.md lists exactly eight devague-origin rows, all re-broadcast via guildmaster — the direct-from-devague vendoring it recalled is marked superseded in that ledger), and the code-side "clonable template" strings are filed as #3 rather than folded into a doc-only PR. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01VaCYnmwSaYL2DLxDtd1fTs
|
Ran 1. FIX — my citation of the vendored 2. Deferred to #3 — the code still self-describes as a template. 3. PUSHBACK — "eight skills originate in devague" is correct as written. Colleague read it as seven-plus-one and suggested naming the two legs. Colleague was explicit about what it did not check: it did not run the suite or Remaining CI failure is repo setup, not this branch. |
…ecision Six inline findings from the Qodo review on PR #2, each verified against disk before acting: - Mark the Substack surface `(planned)` at first mention in all four harness files and on the "Adding the Substack surface" heading, per this repo's own rule that anything ahead of disk carries the marker. - Note that `markdownlint-cli2` is an npm prerequisite, not something `uv sync` installs — CI installs it separately, so a clean checkout following the documented sequence stopped there. - Stop implying all four harnesses load the shared skill tree: the symlinks are shared wiring, but colleague 1.76.0 loads 0 of the 19 (colleague#494). The caveat was in AGENTS.colleague.md only; it is now in CLAUDE.md and QWEN.md where the "one tree, four loaders" claim was made. - Qualify the CliError contract. "Every failure raises CliError" contradicted two deliberate paths: `_CliArgumentParser.error()` emits a CliError then raises SystemExit, and `doctor` returns 1 for an unhealthy report rather than raising. Both are now named so neither gets "fixed" by a future change. - AGENTS.colleague.md claimed nothing from a read-only run reaches the asker's checkout. Tracked files, correct — but the run artifact is copied into the gitignored `.colleague/` dir for grading. Stated. - docs/skill-sources.md listed 17 rows while `.claude/skills/` holds 19: `recall` and `remember` were vendored without ledger entries. Added both (guildmaster, scope literal adapted), plus a header line accounting for all 19. Qodo read the gap as "guildmaster does not supply these two" — it does ship both; the defect was the missing rows, not the supplier. Also corrected the kit description in CLAUDE.md, QWEN.md and README.md: 19 skills is 17 guildmaster + ask-colleague direct from colleague, not a single "canonical guildmaster kit". Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01VaCYnmwSaYL2DLxDtd1fTs
|
FIX — dd96960. Fair reading of this repo's own rule (anything ahead of disk carries
|
|
FIX — dd96960. Correct and worth catching:
|
|
FIX — dd96960. The caveat existed in
|
|
FIX — dd96960. Verified both paths in source:
|
|
FIX — dd96960. Confirmed empirically, not just by reading
|
|
FIX on the defect, PUSHBACK on the diagnosis — dd96960. The gap is real: But guildmaster does supply them — One thing the ledger now records that neither of us started from:
|
|
…lass (v0.10.0) (#5) * docs: re-init CLAUDE.md and align all four harness prompts `/init` replaced the scaffold seed `CLAUDE.md` with a runtime prompt grounded in this repo, and the other three harness files were brought in line with it — each written for its own harness rather than restating the same text. - CLAUDE.md: command block (tests, single test, every lint/rubric/smoke gate), the cross-file CLI wiring (`_CliArgumentParser.error()` override, the `_json_hint` argv peek, the `parser_class` propagation trap, `CliError`, the stdout/stderr split, the catalog walked by `tests/test_cli.py`), a five-place checklist for adding a Substack noun, and `_PROMPT_FILE` vs `_RESIDENT_PROMPT`. - QWEN.md: the coding-session machinery for a Qwen Code session. - AGENTS.override.md: context only (identity stays in `.pi/SYSTEM.md`), and tells Pi's non-coding lane to report the scaffold gap rather than infer an implementation from the project description. - AGENTS.colleague.md: rewritten around colleague as the `/ask-colleague` second mind — per-verb expectations, the contracts a diff must respect, and the colleague#494 empty-skills caveat. - README.md: template-clone instructions replaced by this repo's own Status / CLI / Development sections. Fixes four drifts the docs carried: a Substack surface (posts, comments, statistics, subscribers) that does not exist on disk; a quickstart using `uv run substack-cli …` when `[project.scripts]` installs the binary as `substack`; a skill count of 11 against 19 on disk; and three files calling `CLAUDE.md` "the fullest write-up" while it was still the `/init` seed. Verified: 117 tests pass, `teken cli doctor . --strict` PASS, `harness-smoke --stage config` 6/6 PASS, scan-secrets clean, markdownlint clean, `devex pr lint` no violations. Qwen and Pi were asked "Who are you, and what can you do?" in this tree and both answered from their new files. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01VaCYnmwSaYL2DLxDtd1fTs * docs: correct the assign-to-workforce worktree citation in CLAUDE.md The Worktrees section claimed the vendored skill's fan-out example uses a shared `../worktrees/` path that must be overridden. It does not: the current `.claude/skills/assign-to-workforce/SKILL.md` mandates the same repo-named `.worktrees.<repo-name>` root this file does, and explicitly says "Never use a bare `../worktrees/`". The claim was inherited from culture-agent-template's CLAUDE.md and describes an older revision of the vendored file. Only the branch-name half of the override still applies (`agent/<task-id>`). Found by `ask-colleague review` on this PR. Its other two findings: the "eight skills originate in devague" phrasing is correct as written (docs/skill-sources.md lists exactly eight devague-origin rows, all re-broadcast via guildmaster — the direct-from-devague vendoring it recalled is marked superseded in that ledger), and the code-side "clonable template" strings are filed as #3 rather than folded into a doc-only PR. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01VaCYnmwSaYL2DLxDtd1fTs * docs: address Qodo review — planned markers, lint prereq, contract precision Six inline findings from the Qodo review on PR #2, each verified against disk before acting: - Mark the Substack surface `(planned)` at first mention in all four harness files and on the "Adding the Substack surface" heading, per this repo's own rule that anything ahead of disk carries the marker. - Note that `markdownlint-cli2` is an npm prerequisite, not something `uv sync` installs — CI installs it separately, so a clean checkout following the documented sequence stopped there. - Stop implying all four harnesses load the shared skill tree: the symlinks are shared wiring, but colleague 1.76.0 loads 0 of the 19 (colleague#494). The caveat was in AGENTS.colleague.md only; it is now in CLAUDE.md and QWEN.md where the "one tree, four loaders" claim was made. - Qualify the CliError contract. "Every failure raises CliError" contradicted two deliberate paths: `_CliArgumentParser.error()` emits a CliError then raises SystemExit, and `doctor` returns 1 for an unhealthy report rather than raising. Both are now named so neither gets "fixed" by a future change. - AGENTS.colleague.md claimed nothing from a read-only run reaches the asker's checkout. Tracked files, correct — but the run artifact is copied into the gitignored `.colleague/` dir for grading. Stated. - docs/skill-sources.md listed 17 rows while `.claude/skills/` holds 19: `recall` and `remember` were vendored without ledger entries. Added both (guildmaster, scope literal adapted), plus a header line accounting for all 19. Qodo read the gap as "guildmaster does not supply these two" — it does ship both; the defect was the missing rows, not the supplier. Also corrected the kit description in CLAUDE.md, QWEN.md and README.md: 19 skills is 17 guildmaster + ask-colleague direct from colleague, not a single "canonical guildmaster kit". Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01VaCYnmwSaYL2DLxDtd1fTs * spec: substack-domain-surface (devague /scope + /think) Converged frame for the Substack control surface: post/feed/comment/ reaction/account nouns, webglass-cli as the runtime browser plane, public read verbs first, owner verbs gated on webglass authenticated sessions (agentculture/webglass-cli#17). Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * spec: challenge pass on substack-domain-surface (devague /challenge) Rigorous pass (hard-to-reverse publish + security-sensitive session): webglass has no network lens (capture via Chrome-MCP now, lens asked in webglass-cli#17), two API hosts, markdown->ProseMirror is real work, no auto-retry on writes, partial-state reporting, three-state auth probe, untrusted third-party text, containment twins for every write verb, draft-first publish with --no-email for live proofs. One self-reported lapse (l1) confirmed. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * plan: substack-domain-surface (devague /spec-to-plan) 17 tasks in 7 waves covering all 56 spec targets: baseline, HTTP transport, webglass adapter, untrusted-text helper, Chrome capture; five nouns; post write side + markdown body; parser/learn/catalog wiring; docs, version bump, CI gates; public and owner live proofs. Owner proof (t18) is a follow-up risk on webglass-cli#17. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * plan: implementation split (gate 2 approved) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t1: record pre-feature learn baseline Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t4: untrusted third-party text renderer Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t3: webglass subprocess adapter Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t2: stdlib HTTP transport with host validation and GET-only backoff Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t6: post noun read side (list, get, overview) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t5: account noun (whoami auth probe, overview) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t12: observed Substack API endpoints for the v1 verbs Captured 2026-09-13 in the owner's logged-in browser on jetsonailab.substack.com: drafts create/update/publish/schedule/ unschedule/unpublish/delete, comments create/reply/delete, post and comment reactions add/remove, public archive/post/comments reads, the subscription endpoint as the whoami source, and the substack.com reader feed. Unobserved paths are marked as such. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t12: reword a query-string example the secrets gate flagged Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t5: whoami reads user_id from /api/v1/subscription Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t9: feed noun (read, overview) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t7: comment noun (list, reply, delete, overview) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t8: reaction noun (list, add, remove, overview) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t10: post write side (publish, schedule, unpublish, delete) and markdown body builder Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t13: wire the five Substack nouns into the parser, learn and explain Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t15: bump version to 0.10.0 Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * http: descriptive User-Agent and fail-fast on non-retryable 4xx The live public-read proof returned 403: Substack rejects urllib's default Python-urllib agent (a descriptive substack-cli/<version> agent is accepted; verified with curl). The GET loop also retried every HTTPError; it now retries only 429, 5xx and transport errors, per spec claim c38. Two tests that asserted four attempts on a 404 now assert one. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t16: CI gates — socket-blocking fixture, repo invariants, coverage floor Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t14: document the Substack surface across README and the four harness prompts Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * t17: public-half live proof against two publication hosts Evidence stored as a text record with a header line (JSON body): scripts/scan-secrets.py fails any JSON-parsable file whose url keys point off localhost, and the t2 invariant forbids tracked *.json files naming substack.com. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * delivery: summarize the substack-domain-surface workforce run Partial run: 16 of 17 plan tasks delivered, t18 (owner-half live proof) blocked on agentculture/webglass-cli#17. Deviations d1-d4, lapses l1-l15, validation ledger o1-o23/e1-e22/b1-b4 all adjudicated. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * fix: address Qodo review on PR #5 (comments 3998832718, 3998832722, 3998832725, 3998832730, 3998832732, 3998832734, 3998832736, 3998832739) - 3998832718: `comment list` now sends the observed query (all_comments=true&sort=best_first, urlencoded) and flattens nested `children` replies depth-first, parents before replies, keeping parent_id/ancestor_path on each item. - 3998832722: reaction add/remove build their URL from http.publication_base(), so SUBSTACK_API_BASE reaches writes as it does reads. - 3998832725: `feed read` builds limit/cursor with urllib.parse.urlencode, so a cursor containing &, #, + or % can no longer forge or truncate the query. - 3998832730: run_webglass passes a finite timeout (120s, SUBSTACK_WEBGLASS_TIMEOUT; invalid -> CliError(1)) and maps TimeoutExpired to CliError(2) naming the variable. - 3998832732: http passes a finite timeout to opener.open (30s, SUBSTACK_HTTP_TIMEOUT; invalid -> CliError(1)); timeouts retry on GET and raise a single CliError(2) on writes. - 3998832734: UnicodeDecodeError/JSONDecodeError around response decoding on both the GET and write paths -> CliError(2) naming the URL, never retried. - 3998832736: an argparse usage/unknown-verb answer from webglass now maps to CliError(2) saying webglass-cli has no authenticated request verb yet, citing agentculture/webglass-cli#17. The verbs stay registered. - 3998832739: --body-json must decode to {"type": "doc", "content": [...]}; anything else is CliError(1) with the ProseMirror remediation. - 3998832738 (--send): behaviour unchanged by design; the help text and docstring now say the send:true path is unverified against the live API. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * refactor: address SonarCloud smells on the Substack surface (S1192, S8513, S3358, S5799, S9073, S9100) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * refactor: drop redundant HTTPError from except tuples (S5713); split a composite assert (S9073) HTTPError derives from URLError, so catching both is redundant; the behaviour is unchanged. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV * refactor: single-return account handlers (S3516), split map_failure's HTTP branch (S3776), merge a literal (S5799) Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01CH5jAgaWUmCiXBJ3nKWdUV --------- Co-authored-by: Claude Opus 5 (1M context) <[email protected]>



What
/initreplaced the scaffold seedCLAUDE.mdwith a runtime prompt grounded inthis repo, and the other three harness prompt files were brought in line with it —
each written for its own harness rather than restating the same text.
CLAUDE.mdQWEN.mdAGENTS.override.mdassociatelane — context only, identity stays in.pi/SYSTEM.mdAGENTS.colleague.md/ask-colleaguesecond mindREADME.mddrops the clone-and-rename-the-template instructions (this repo isthe clone) in favour of its own Status / CLI / Development sections.
Why
The scaffold left every doc describing
culture-agent-template, notsubstack-cli. Four concrete drifts are fixed:statistics and subscribers; no such noun groups are registered in
_commands/. Every file now states the scaffold status explicitly, andAGENTS.override.mdtells Pi's read-only lane to report that gap ratherthan infer an implementation from the project description.
uv run substack-cli whoami— but[project.scripts]installs the binary assubstack. Quickstart corrected;the binary-vs-prog-name mismatch is documented in all four harness files.
Left as a doc note deliberately — picking a canonical name is a code
change, not a docs one (see Follow-ups).
CLAUDE.md"the fullest write-up of the repo'sconventions" and pointed at a "Cloning this template" section it did not
contain — while
CLAUDE.mdwas still the/initseed placeholder.What's in CLAUDE.md now
Beyond commands: the cross-file CLI wiring that is not discoverable from any
single file — the
_CliArgumentParser.error()override that keeps argparsefailures inside the
error:/hint:contract, the_json_hintargv peek, theparser_classpropagation trap for nested nouns,CliErrorand the exit-codepolicy, the strict stdout/stderr split, and the fact that
tests/test_cli.pywalks
known_paths()so an uncatalogued verb fails the suite. Plus a five-placechecklist for adding a Substack noun, and the
_PROMPT_FILE(recognition) vs_RESIDENT_PROMPT(health) distinction thattests/test_doctor_resident_prompt.pypins shut.
Verification
uv run pytest -n auto— 117 passed, 1 skipped (the known report-onlycross-repo gap in
test_harness_registries.py)uv run teken cli doctor . --strict— PASSuv run python scripts/harness-smoke.py --stage config --require config— 6/6 PASSpython3 scripts/scan-secrets.py— clean;markdownlint-cli2— 0 errorsdevex pr lint— no violations;devex pr deltarun (alignment-file rule):no sibling follow-up needed, this PR touches no vendored skill.
Behavioural check. Both interactive harnesses were asked "Who are you, and
what can you do?" in this tree and answered from their new files — Qwen Code
named the repo by its real domain and framed the Substack verbs as work to add;
Pi answered with
associate's non-coding bounds from.pi/SYSTEM.mdplus thescaffold status from
AGENTS.override.md, volunteering that the Substacksurface "doesn't exist on disk yet".
ask-colleague explorewas also run — but it works from a throwaway worktree atHEAD, so it read the pre-change docs. Independently, from a cold read, it
flagged the same four drifts this PR fixes. A
reviewof the committed diff isrunning and findings will be folded in before merge.
Follow-ups (not in this PR)
substackvssubstack-cli: decide which is canonical and align[project.scripts]with the argparseprog, the explain catalog,learn,and the tests. Documented here, not papered over.
whoami.py's hand-rolledculture.yamlparser stops at the first agent blockwith no warning (raised by colleague). Harmless today — this repo declares one
agent — but worth a look before a multi-agent clone hits it.
substack-cli (Claude)