Addresses both review findings on #993.
1. skill_plugin_emitter.py's module docstring still described the behaviour this
PR removed. Its tree diagram called plugin.json the "manifest with
./skills/<slug> + attribution", and the rights-gate paragraph said
cleared_for_distribution is recorded "in the manifest" -- both now the
sidecar. A docstring asserting the opposite of its own file's point is worse
than no docstring, and it is what `--help` readers see.
Also corrects a third instance the review did not name but which shares the
root cause: the tree diagram never listed authoring-notes.json at all, even
though this PR's fix is what creates it. Added, with the issue #954 reason
stated inline so the next reader knows why provenance cannot live in the
manifest.
2. CLAUDE.md said the resident core is 2,066 tokens while, twelve lines later,
the same file said 2,101. 2,066 predates the worked invocation block added
for write-a-skill checklist item 5; token_budget_estimator.py reports 2,101
on the current tree, matching CHANGELOG.md and the PR body. CLAUDE.md was
the only stale copy and it contradicted itself.
Docstring-only and prose-only; no behaviour change. Verified the emitter still
emits both plugin.json and authoring-notes.json via --sample after the edit.
Gates: compileall, check_plugin_json --all, check_paths, check_frontmatter,
check_dual_publish, check_model_freshness, smoke_scripts (696/696),
derive_counters --check, book_skill_validator --strict.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UySnyf5upm4y8xhYA3w6yw
Addresses both review findings on #993.
1. The changelog/CLAUDE.md counter line said "commands 147 → 150", which
asserts this plugin adds three commands. It adds exactly one
(commands/cs-spinning-up-deep-rl.md). 147 was this branch's pre-merge
baseline; after merging dev the delta had to be restated against dev's
baseline, and that one figure was carried over unchanged while the others
were updated. Verified empirically rather than by arithmetic: derive_counters
on an origin/dev worktree reports 149 commands, and the raw command-file
count goes 281 → 282 across the merge. Corrected to 149 → 150. The other
three figures on that line (skills 387 → 388, agents 117 → 118, plugins
98 → 99) were already right.
2. README POWERFUL-tier row had a stray space before a comma:
"calculator) , **spinning-up-deep-rl**". Removed.
Neither affected derive_counters --check, which reads the tree rather than the
prose -- which is exactly why a wrong delta in prose can survive a green gate,
and why it was worth fixing in a repo this strict about counters being
trustworthy.
Gates re-run: compileall, check_plugin_json --all, check_paths,
check_frontmatter, check_dual_publish, check_model_freshness, smoke_scripts
(696/696), derive_counters --check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UySnyf5upm4y8xhYA3w6yw
dev moved: PR #994 landed engineering/deep-learning-book, which collides with
this branch on every headline-counter and registry surface.
Conflicts resolved in four files, keeping both sides' content:
- .claude-plugin/marketplace.json -- both plugin entries kept; the registry now
carries spinning-up-deep-rl and deep-learning-book. 99 plugins.
- CHANGELOG.md -- both Unreleased sections kept.
- CLAUDE.md, README.md -- dev's prose taken as the newer baseline, then this
branch's engineering-row entry restored and every counter re-derived rather
than hand-picked from either side.
Counters re-derived from the merged tree with derive_counters.py, which is the
ground truth, and trued up across all five surfaces: 388 skills, 99 plugins,
727 tools, 842 references, 118 agents, 150 commands.
Both changelog/CLAUDE.md delta lines are restated: each side was written against
its own base and both claimed 386 -> 387, which is no longer true of either now
that they land together. This branch's entry is now stated as the delta on top of
deep-learning-book.
Gates re-run on the resolved merge: no conflict markers left in the tree,
compileall, check_plugin_json --all, check_skill_names, check_paths,
check_frontmatter, check_dual_publish, check_model_freshness, smoke_scripts
(696/696), derive_counters --check, book_skill_validator --strict, and a
JSON/YAML parse of every file touched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UySnyf5upm4y8xhYA3w6yw
Ninth review on PR #994 found that --underparameterized-max and
--overparameterized-min, added two commits earlier, were never checked against each
other. Reproduced, and the consequence is sharper than a silent misclassification:
with --underparameterized-max 20 --overparameterized-min 5 and a ratio of 10, the
tool reported a model ten times overparameterized as "underparameterized" and exited
0. That verdict ranks "shrink the model" FIRST rather than last, inverting the exact
double-descent correction this tool exists to apply.
Added an argparse guard rejecting under-max >= over-min with a message naming both
values (exit 2, the documented usage-error code). Equal bands are rejected too,
since they leave the near-interpolation regime unreachable.
Verified: inverted and equal bands both exit 2; a valid override still moves the
regime (--overparameterized-min 500 gives near-interpolation); defaults unchanged at
overparameterized / OVERFIT / 240.0 with smaller-model last; the other exit codes
still 1 for an action, 0 for balanced, 4 for a leaky split.
Worth noting for the two flags' own history: they were added to close a consistency
nit, and introduced this defect in doing so. A new option is new surface, and its
interaction with existing options is part of it.
Gates green: compileall, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check,
check_skill_names, check_plugin_json, book_skill_validator, and --help +
--sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Eighth review on PR #994 found that _matches()'s (?:s|es)? suffix reintroduced a
smaller version of the substring bug it was written to fix: "rag" + "es" matches the
standalone word "rages", so --goal "why overfitting still rages in large models"
exited 3, refused as out-of-scope retrieval-augmented-generation work.
Reproduced before fixing, then checked whether the -es branch earns its keep at all.
It does not: every keyword in the table ending in s, x, z, ch or sh is already plural
or non-count (basics, features, foundations, prerequisites, statistics, speech,
mlops, fairness, mathematics, time series), so no token needs -es appended. Narrowed
the auto-plural to plain -s and documented that irregular forms belong in
SURFACE_FORMS, spelled out, the way fine-tuning, prompting and agentic already are.
Verified: "rages" no longer matches while standalone "rag" still does; transformers,
embeddings, autoencoders and agentic still match; the goal above is now correctly
unroutable (exit 4) rather than confidently misrouted. RLHF, LoRA fine-tuning, RAG
pipelines and prompt/agent goals still exit 3; sequence, vision, generative and
practitioner routing unchanged.
That makes two rounds of false out-of-scope refusals from the same root cause —
approximate string matching standing in for a word list. The refusal path is the
part of this tool users are least able to second-guess, so it is the wrong place to
approximate.
Gates green: compileall, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check,
check_skill_names, check_plugin_json, book_skill_validator, and --help +
--sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Seventh review on PR #994 noted that capacity_planner.py exposes --overfit-rel-gap
but hardcodes the two params-per-example regime bands, unlike its sibling scripts
where every threshold is overridable. The reviewer called it fine as shipped; the
inconsistency is small enough to close rather than carry.
The band matters more than a typical default: it decides whether "shrink the model"
is ranked last, which is the double-descent correction this tool exists to apply.
The interpolation point depends on task, architecture and label noise, so a user
whose model sits elsewhere had no way to say so.
Adds --underparameterized-max and --overparameterized-min, threaded through plan()
and classify_regime() as keyword arguments defaulting to the existing constants, and
reports all three thresholds in --output json the way training_diagnostics.py already
does. The help text repeats that these are heuristic bands, not a threshold theorem.
Defaults preserve behaviour exactly: the --sample fixture still reports
overparameterized / OVERFIT / 240.0 params-per-example with smaller-model ranked
last, identical to before the change. An override demonstrably moves the regime
(--overparameterized-min 500 reclassifies the same model as near-interpolation).
Exit codes unchanged: 1 for an action, 0 for balanced, 4 for a leaky split.
Not fixed here: CHANGELOG.md's duplicate [Unreleased] header, also noted in that
review. Verified pre-existing rather than introduced by this branch — the count is
2 at the merge-base with main and 2 at HEAD. Left for a separate changelog cleanup.
Gates green: compileall, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check,
check_skill_names, check_plugin_json, book_skill_validator, and --help +
--sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Sixth review on PR #994 noted that --include-intro appeared to have an observable
effect only on the complete lane. Checked it, and it was worse than reported: the
flag was inert on every lane, complete included.
Two reasons compounded. ch01 is not a prerequisite of any chapter, so it never
arrived through prerequisite closure; and the only lane that targets it, complete,
skipped the ch01 filter entirely. The filter therefore removed a chapter that was
never present, and the flag that controlled it could not change any output.
This also means my own verification of the parameter rename in c75500f was
inconclusive: it compared the complete lane with the flag against the vision lane
without it, and those differ for reasons unrelated to the flag. A test that cannot
fail proves nothing.
Inverted the logic so the flag adds ch01 rather than un-removing it, which gives it
a real effect on every lane while leaving complete unchanged (ch01 is already among
its targets). Help text now states what it does and that no lane pulls ch01 in on
its own.
Verified per lane: complete unchanged; vision, generative and foundations each gain
ch01 with the flag and are untouched without it; ch01 sorts first and never precedes
a chapter it would violate. Routing and both refusal paths are unchanged — sequence,
vision, generative and practitioner all route as before, out-of-scope still exits 3,
unroutable still exits 4.
Gates green: compileall, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check,
check_skill_names, check_plugin_json, book_skill_validator, and --help +
--sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Fifth review on PR #994 found the one numeric spec field I missed when adding typed
validation in the previous commit: embedding's seq_len still went through a bare
int(), so it bypassed the checks every sibling field had just been given.
Both failure modes reproduced before fixing:
seq_len "ten" -> uncaught ValueError, traceback, exit 1 (documented: exit 4)
seq_len 0 -> no error at all; reported a plausible "0x8" layer with zero
activation elements and exited 0, presenting a degenerate model
as a valid one
Routed through _positive_int with the existing default (the incoming sequence
length, or 1), so both now exit 4 naming the layer and field. Verified the default
fallback still resolves to the input shape (16x8) and an explicit valid seq_len is
still honoured (32x8).
Swept the file afterwards rather than fixing only the reported instance: all 13
numeric spec fields now go through _positive_int, and no raw int() on a spec field
remains. The reference specs are unchanged — convnet 545,098 parameters, transformer
asset 7,087,872.
Gates green: compileall, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check,
check_skill_names, check_plugin_json, book_skill_validator, and --help +
--sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Fourth review on PR #994 raised two findings against this plugin's scripts. Both
reproduced before fixing; the review's other findings are against marketing/linkedin,
which this branch carries from main but does not touch (see the PR comment).
1. reading_path_planner.py matched keywords by bare substring, so "rag" matched
inside "storage", "lora" inside "exploratory", "conv" inside "converge" and
"text" inside "context". Confirmed: --goal "train models for image storage and
retrieval" exited 3, confidently refused as out-of-scope RAG work, and
"an exploratory look at optimization" exited 3 citing LoRA. A tool whose stated
design is to refuse rather than guess was guessing, and doing it with certainty.
Matching is now word-boundary anchored with an optional plural, plus an explicit
surface-form table for the few tokens whose inflections a word-boundary match
would otherwise miss (fine-tuning, prompting, agentic). Verified: both goals above
now route correctly (exit 0 / the optimization lane), "converge" reaches the
optimization lane rather than vision, and the real refusals still refuse — RLHF,
LoRA fine-tuning, RAG pipelines and prompt/agent goals all still exit 3.
2. model_arithmetic.py documented exit 4 for a spec it cannot parse but only caught
SpecError and ShapeError, so malformed input escaped as a traceback with exit 1.
Confirmed across five cases: a non-dict top-level JSON, a non-dict layer entry,
stride 0, groups 0, and a non-numeric filters value. Numeric fields now go through
a checked accessor that rejects non-integer and non-positive values, the input
layer's shape is validated, and the top-level spec and every layer entry are
type-checked. All five now exit 4 with a message naming the layer and field.
Regression battery over eight goals routes exactly as before; the convnet sample
still reports 545,098 parameters and the transformer asset 7,087,872.
Gates green: compileall, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check,
check_skill_names, check_plugin_json, book_skill_validator, and --help +
--sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Third review on PR #994 found a real bug in the flagship example asset. Verified
before fixing: assets/example_layer_spec.json reported 1,207,962,624 parameters
for the feedforward up-projection instead of 2,362,368 — off by exactly 512x, the
sequence length — putting the block's total at ~1.21B instead of ~7.09M.
Root cause was in the tool, not only the asset. model_arithmetic.py's mha layer
emits (seq, d_model) but linear refused any 2-D input, so the only way to attach a
feedforward block was to flatten first. Flattening collapses all 512 positions into
one 393,216-element vector, which models a dense layer over the whole sequence — a
different layer, with seq_len times the parameters. A transformer FFN was therefore
not expressible at all, and the shipped example walked straight into it. Clean exit
is not correct numbers, which is why --sample exit-code testing never caught it.
Fixed the cause: linear on a 2-D (seq, features) input is now position-wise — one
weight matrix shared across positions, parameters independent of sequence length,
compute linear in it. Documented in the module docstring; the 3-D path still refuses
with an updated message pointing at flatten. Removed the flatten from the example
asset and recorded in its comment why it must not come back.
Verified: the corrected block reports 7,087,872 parameters, matching a hand-check of
2*(2*768) + (4*768^2+4*768) + (768*3072+3072) + (3072*768+768) exactly, and the size
of a BERT-base encoder layer. The convnet --sample is unchanged at 545,098, and
linear on 3-D input still exits 5.
Also adds the missing CHANGELOG.md [Unreleased] entry, which the same review noted:
CLAUDE.md, README.md and marketplace.json carried the new skill and its counter
deltas but CHANGELOG.md did not.
Gates green: compileall, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check,
check_skill_names, check_plugin_json, book_skill_validator, and --help +
--sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Second independent review on PR #994 observed that reading_path_planner.py's
score_lanes() broke equal-hit ties alphabetically by lane key, so SKILL.md's own
documented example "train a transformer" resolved to the practitioner lane rather
than sequence.
Reproduced: the goal hits practitioner on "train" and sequence on "transformer",
one keyword each, and alphabetical ordering picked practitioner.
Fixed the cause rather than the example. Ties now break on keyword specificity —
the lane whose longest matched keyword is longest wins — because an equal hit
count between a generic term and a discriminating one should not be settled by
luck. Lane key remains the final tie-break so ordering stays deterministic.
Regression battery over eight goals: "train a transformer" now routes to sequence;
vision, generative, foundations, practitioner, complete, representation and
sequence goals all route exactly as before. Refusal paths unchanged (out-of-scope
exit 3, unroutable exit 4, sample exit 0).
Gates green after the change: compileall, check_paths, check_frontmatter,
check_dual_publish, check_model_freshness, smoke_scripts (696 passed),
derive_counters --check, check_skill_names, check_plugin_json, book_skill_validator,
and --help + --sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Two small findings from the automated review on PR #994, both verified against the
source before fixing.
1. reading_path_planner.py: the plan() parameter was named include_optional while
the CLI flag and call site both use include_intro, and it only ever gates ch01.
Renamed the parameter and its use for consistency. Behavior unchanged, confirmed
both ways: --include-intro keeps ch01 first, the default drops it.
2. model_arithmetic.py: conv2d "same" padding computes ceil(H / stride), which is
the TensorFlow/Keras SAME convention, and the tool did not disclose which
framework it matches. Documented it in the module docstring — including that
PyTorch's padding='same' is symmetric-only and rejects a stride other than 1, so
a strided PyTorch layer will not match, with "valid" named as the exact-case
workaround — plus a pointer comment at the computation itself. No arithmetic
change; the sample stack reports identical parameters and FLOPs.
The reviewer's third point was that it could not execute the gates in a sandboxed
environment. No code change: those gates were run locally and are green.
Verified after the change: compileall, check_paths, check_frontmatter,
check_dual_publish, check_model_freshness, smoke_scripts (696 passed),
derive_counters --check, check_skill_names, check_plugin_json, the book-skill
validator, and --sample --output json on all four tools.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
CI gate G1 (scripts/check_paths.py) failed on the previous commit: the agent and
command files live at engineering/deep-learning-book/{agents,commands}/, so bare
references/*.md and assets/*.md tokens resolved against neither the plugin root,
the file's own directory, nor the repo root — the three bases the linter accepts.
The files they point at live under skills/deep-learning-book/.
Prefix the nine offending links with skills/deep-learning-book/ so they resolve
from the plugin root. Content unchanged otherwise; SKILL.md's own relative links
were already correct and were not touched.
Reproduced the failure locally (9 unresolvable references across 4 files), then
confirmed the same check clean, plus every other blocking gate: compileall,
check_plugin_json, check_skill_names, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (696 passed), derive_counters --check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
Addresses the review observation on #993: the compiled skill's
authoring-notes.json carried only a `source` block (how it was built) even
though its content is derived from an external MIT-licensed work, where the
rest of the repo uses an `attribution` block for that. check_plugin_json.py's
NOTES_ALLOWED permits both keys, so the two coexist.
Adds `attribution` to engineering/spinning-up-deep-rl following the shape used
by book-to-skill and skillopt-sleep: derived_from, upstream_docs, upstream_path,
original_author, original_license, original_copyright, derivation_note.
The emitter is deliberately NOT changed to synthesise this. It knows only
`--source-note` free text and a rights basis -- not an upstream URL, author or
licence -- and a half-filled attribution block is worse than none. Instead
Step 11 of conversion_workflow.md now says attribution is added by hand
whenever `--rights` is anything but internal-docs, names the field shape, and
restates that the actual obligation is the LICENSE notice and README credit --
authoring-notes.json is metadata Claude Code never reads, and a sidecar JSON
file is not a licence notice.
Gates re-run clean: check_plugin_json --all, check_paths, check_frontmatter,
check_dual_publish, check_model_freshness, smoke_scripts (692/692),
derive_counters --check, book_skill_validator --strict.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UySnyf5upm4y8xhYA3w6yw
Requested as "convert deeplearningbook.org into a skill". Built as a companion
rather than a compilation, because the repo's own rights gate forbids the latter
for a public plugin.
Why not book-to-skill: its emitter refuses a shareable package without
public-domain / open-license / internal-docs / author-permission, none of which
applies to an MIT Press title whose site states its HTML-only format exists as a
friction against copying under the authors' contract. Its rights reference lists
publishing a compiled skill of a copyrighted book to a public marketplace under
"Do not", and its hard rule 1 forbids scraping a book from the web, so the
pipeline could not have run against a URL either.
What shipped instead: the compiled-skill shape (master SKILL.md ~2.0k tokens with
chapter and topic indexes, chapters/ch01..ch20, glossary, patterns, cheatsheet)
filled with original synthesis and linking to the official free chapters. No
passages, figures, or per-paragraph paraphrase. Passes book-to-skill's own
book_skill_validator.py clean, with every file inside token_budget_estimator's caps.
The differentiator is the delta layer. A compilation freezes a source at its
publication date; this one dates it. Every chapter carries "What changed after
2016", and references/book_to_2026_delta.md gives five corrections with primary
citations and per-claim confidence levels: double descent qualifying Ch 5's
U-curve, AdamW splitting weight decay from L2, transformers displacing Ch 10's
recurrence, diffusion growing out of Ch 18's score matching, and self-supervised
learning vindicating Ch 15 while replacing its methods. Two claims are marked
contested rather than propagated, two named as folklore.
Four stdlib-only tools, each with a real refusal:
- reading_path_planner.py — prerequisite closure over the book's actual dependency
graph; exit 3 for a goal the book does not cover, exit 4 with forcing questions
- training_diagnostics.py — Ch 11's rules in priority order, so a NaN is never
reported as overfitting; exit 4 rather than diagnosing with no instruments
- capacity_planner.py — regularization ladder in cost order, "shrink the model"
ranked last in the overparameterized regime; exit 4 on a val-below-train split
- model_arithmetic.py — params/FLOPs/activation memory for conv, linear, MHA and
LSTM/GRU stacks; exit 5 naming the layer whose shapes do not connect
Also: 4 references citing 7-8 sources each, 3 assets, cs-deep-learning-tutor
agent, /cs:deep-learning + /cs:dl-reading-path + /cs:dl-diagnose.
Counters: skills 386 to 387, tools 723 to 727, refs 838 to 842, agents 116 to 117,
commands 146 to 149, plugins 97 to 98 (verified by derive_counters.py --check).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BswsZp5zrJWFAGU6KWNA1s
dev's derive_counters.py gained two additional check targets that main's copy
did not have -- mkdocs.yml's site_description and .codex-plugin/plugin.json's
description / shortDescription / longDescription. Both carried the pre-linkedin,
pre-skill-doctor numbers (380 skills / 706 tools / 823 refs / 114 agents /
138 commands / 96 plugins), so the blocking gate fails on this branch the moment
dev's checker meets main's tree.
Synced all six to the derived values: 387 skills, 723 tools, 838 references,
117 agents, 147 commands, 98 plugins.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UySnyf5upm4y8xhYA3w6yw
Runs engineering/book-to-skill end to end on its first real source: OpenAI's
Spinning Up in Deep RL (MIT, (c) 2018 OpenAI; primarily developed by Joshua
Achiam). Cloned openai/spinningup and compiled its docs/ reStructuredText tree
(38 files, ~37k words, ~49K tokens) through the full pipeline -- extract
--mode technical, analysis, 20 chapter files, glossary/patterns/cheatsheet,
master SKILL.md, validator, plugin emitter.
The compiled skill passes book_skill_validator.py in --strict mode with every
file inside budget: a 2,101-token resident core (cap 4,000) plus 20 on-demand
chapters averaging ~1,256 tokens each.
Chapter structure follows the source's own toctree rather than a heading scan:
user documentation (ch01-06), Introduction to RL Parts 1-3 (ch07-09), the
researcher essay / key papers / exercises / benchmarks (ch10-13), one chapter
per algorithm in lineage order (ch14-19: VPG to TRPO to PPO, DDPG to TD3 and
SAC), and the logger/MPI/ExperimentGrid utilities (ch20).
Rights basis is open-license, not fair use -- the emitter's Step-11 gate
refuses a shareable package without one. Upstream's MIT notice is reproduced
in full in the plugin's LICENSE beside this package's own, and README.md names
the source, the author and the source's frozen version; a sidecar JSON is not
a license notice.
Also fixes a defect the emitter only reveals at its final step:
skill_plugin_emitter.py wrote its whole `source` provenance block into
plugin.json, on a stale inline claim that `source`/`attribution` were approved
extension fields. Claude Code rejects an entire manifest on any unrecognized
key (issue #954) and scripts/check_plugin_json.py hard-fails such a manifest,
so every package the emitter produced failed the blocking CI gate on commit.
_plugin_manifest() now emits spec fields only and a new _authoring_notes()
writes .claude-plugin/authoring-notes.json. Recorded as deviation 26 in
engineering/book-to-skill/README.md; the printed marketplace.json snippet is
unchanged, since `source` is a valid key there.
Counters: skills 386 -> 387, agents 116 -> 117, commands 146 -> 147, plugins
97 -> 98. Tools and references unchanged -- a compiled knowledge base ships
notes, not scripts.
All blocking CI gates verified locally: compileall, check_plugin_json --all,
check_skill_names, check_paths, check_frontmatter, check_dual_publish,
check_model_freshness, smoke_scripts (692/692), derive_counters --check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UySnyf5upm4y8xhYA3w6yw
Answers discussion #934, which asked for a strategic assistant for growing a
LinkedIn presence organically rather than a post generator.
Six skills under marketing/linkedin/: an orchestrator (context: fork) plus
profile, strategy, content, engagement, and analytics lanes. 17 stdlib-only
tools, 15 references, 2 agents, 8 /cs:* commands.
The design constraint is the differentiator: no LinkedIn credentials, no API
calls, no scraping, nothing auto-sent. Automated posting, connecting, and
commenting are prohibited by LinkedIn's User Agreement 8.2, and a restricted
account ends a compounding asset. linkedin_policy_gate.py runs before any
drafting and refuses seven request classes — automation, scraping, engagement
pods, bulk messaging, fake identity, fabricated proof, named third-party
automation platforms — each carrying the policy anchor and a compliant
substitute, so the gate never just says no.
Refusals are real rather than advisory. A cadence under 90 minutes a week
returns a comment-only plan instead of a schedule that dies in week five. A
newsletter whose six-month cost exceeds the budget is refused before the promise
is made. An experiment needing more posts than a quarter allows is reported
infeasible rather than quietly re-sized. The pattern miner refuses to test
anything below 10 posts and reports NOTHING_SURVIVED as a finding.
Evidence discipline: two widely repeated claims are corrected rather than
propagated. The "personalised note triples acceptance" claim is not supported by
the largest samples (acceptance is near-identical either way, ~26.4%); what a
note moves is the post-accept reply rate (~5.4% to ~9.4%), which is why the
message builder refuses an ask in a first-touch note. The ~19% in-body link
reach reduction has never been confirmed by LinkedIn as a penalty and has a
plausible dwell-time explanation, so it is a warning rather than a block. Every
reference carries per-claim confidence levels.
Accessibility is a blocking lint finding: Unicode pseudo-bold is announced by
screen readers as mathematical symbols and is not indexed by search.
All six SKILL.md files are 6/6 PASS on the write-a-skill checklist. Every tool
supports --help, --sample, and --output json with typed exit codes.
Counters: skills 380 -> 386; plugins 96 -> 97; tools 706 -> 723; refs 823 -> 838;
agents 114 -> 116; commands 138 -> 146 (derive_counters.py --check).
Also syncs three previously-merged skills (agent-memory, hivemind, skill-doctor)
into the .hermes/ and .vibe/ mirror trees, which had drifted behind .codex/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JSPxUHU6utqme7qC6EwHEh
Two reviewer nits batched: derive_counters.py's module docstring and --check
help still described the pre-#989 three-source coverage (flagged on #989);
check_model_freshness.py's EXCLUDED_DIRS did double duty as a directory AND
filename exclusion set, which the name hid (flagged on #985 and #988's
reviews) — renamed with a comment stating both roles. No behavior change;
both gates re-verified passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Review follow-up on #989: shortDescription/longDescription carry their own
counts and were just trued — include them in the gated source text so
standardized-phrasing claims in them are checked (non-matching prose is
simply not read). Verified: planting 997 in shortDescription fails the
gate; restored passes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Adopts the two verified findings from PR #940 (credit: @benrfairless):
- .codex-plugin/plugin.json still said v2.2.0 / 223 skills / 23 agents /
298 tools / 9 domains — roughly nine releases behind, and it is the
manifest Codex users see. Version, description, and the interface
short/long descriptions are trued to the v2.12.0 counters (380 skills /
20 domains / 706 tools / 823 refs / 114 agents / 138 commands / 96
plugins), with the top-level description written in the standardized
claim phrasing so the gate can read it.
- mkdocs.yml's site_description was content-correct after v2.12.0 but
ungated and phrased invisibly to extract_claims ('agent skills',
'installable plugins') — reworded to the standardized phrasing.
- derive_counters.py run_check() now reads both as claim sources
(mkdocs.yml restricted to the site_description line since its !!python
tags reject safe_load). Verified: planting 999/998 in the two sites
fails the gate naming both; restored values pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Caught by review on the v2.12.0 promotion PR #985: README's Skills Overview
heading still said 370 and CLAUDE.md's footer Status line said 379 while the
banner/badges/scope line say the derived 380. Both wordings ('370 skills
across', '379 skills deployed across') were invisible to derive_counters.py's
claim patterns, which is why they could drift — reworded both into the
standardized '<N> production-ready skills across <D> domains' phrasing, made
extract_claims() validate every occurrence of a claim pattern instead of only
the first, and run_check() now reads CLAUDE.md's Status footer line alongside
Current Scope. Verified: planting 999/998 in the two lines fails the gate
naming both; restored values pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
The quality-review workflow's parse fallback emits 'unknown|0|0|0|ERROR'
whenever the tessl CLI dies (auth/quota/npm failure), and the verdict logic
only compared SCORE against the threshold — so a tool outage rendered as
0/100 'NEEDS WORK' and blocked the merge, indistinguishable from a genuinely
zero-quality skill. Both the v2.12.0 promotion PR (#985) and #984 hit this:
four skills scored an identical 0/100 with the whole review loop finishing
in ~8 seconds.
Now VSTATUS=ERROR renders as a 'TOOL ERROR (not scored)' row with the CLI's
actual output surfaced as a :⚠️: annotation and a report footer, and
does not set the blocking exit code. Genuine sub-threshold scores still
block. Verified with a mocked-tessl simulation: error -> non-blocking warn,
85/100 -> PASS, 40/100 -> blocking NEEDS WORK, all-error run -> job passes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
PR #984's counter true-up bumped README badges and CHANGELOG to the derived
114 agents / 138 commands but left the CLAUDE.md Current Scope line and
marketplace.json metadata.description at the stale 111/131 (caught by review
on #984). derive_counters.py --check passed because CLAIM_PATTERNS had no
agents/commands patterns — added both (agents anchored on the "(cs-" suffix
so prose like "9 more coding agents" can't false-match), verified the new
gate fails on the pre-fix docs and passes post-fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
The Skill Security Audit failed PR #984 with 2 CRITICAL CMD-INJECT findings
on hivemind's Node scripts — pre-existing since #979 merged while Actions
wasn't triggering; touching the skill's agent files pulled it into audit
scope. Spawning headless opencode worker processes is this skill's core,
documented function (SKILL.md Prerequisites + the PR #979 dependency
disclosure), so the imports carry the auditor's own suppression directive
with the justification inline. Re-audit: PASS, 0 critical / 0 high.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
- CHANGELOG.md gains the [2.12.0] entry (first tagged release since v2.9.0):
consolidates the previously documented but untagged v2.10.0-v2.11.2 work,
all post-2.11.2 merges, and the full 17-issue triage sweep; the ten stacked
[Unreleased] sections are demoted into the 2.12.0 body so the Release
workflow tags and publishes the whole span. Verified parseable with
scripts/extract_release_notes.py (version 2.12.0, 554-line body).
- Version markers bumped to 2.12.0: marketplace.json metadata,
CLAUDE.md current-version header + footer.
- Counters trued to the derived values (380 skills / 96 plugins / 20 domains /
706 tools / 823 refs / 114 agents / 138 commands) in README badges + prose,
CLAUDE.md, marketplace.json, and the long-stale mkdocs.yml/docs/index.md
site description (was still claiming 345/78/17).
- Docs site regenerated via scripts/generate-docs.py (568 generated pages;
new pages for the recently merged plugins); codex/gemini mirrors resynced;
mkdocs build verified locally with the same plugin set static.yml uses
(670 HTML pages, no errors).
- Fix: the three hivemind worker personas (assets/agents/{coder,scout,tester}.md,
merged via #979 while Actions was not triggering) lacked the frontmatter
`name:` field and hard-failed the blocking G10 gate — named
hive-coder/hive-scout/hive-tester; 645 files now scan with 0 errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Two doc nits from #981 review: (1) CLAUDE.md's 'Not auto-registered' paragraph used
'integrations/<name>/src/index.ts' in one sentence and 'integrations/<name>-mcp' two
sentences later — <name> meant two different things; align both to <name>-mcp.
(2) skills/pw/SKILL.md 'What's Included' listed '2 MCP servers ... integrations' with no
caveat, unlike README's equivalent line — add '(optional — not auto-registered)'.
dev landed a parallel #978 fix (deleted .mcp.json, added integrations/mcp-servers.example.json
opt-in template + README flow). Per maintainer decision, keep this PR's approach:
- README.md resolved to this branch's version (softened tagline/commands/heading + caveats).
- .mcp.json kept as empty {"mcpServers":{}} (servers not auto-registered).
- Restored dev's mcp-servers.example.json in full (a rename-merge artifact had gutted it to {}).
- Retains this PR's additive doc softening dev lacked: plugin.json + marketplace.json
descriptions, CLAUDE.md + testrail/browserstack/pw SKILL.md caveats.
All other dev changes merged cleanly.
- collect_sessions.py: name-only repo matches (worktree/basename fallback,
which can match an unrelated same-named repo) are now recorded per session
(repo_match), counted in inventory.json, called out in the summary, and
excludable via a new --strict-repo flag
- score_aggregator.py: never-scored detection tracks session ids in a set
instead of substring-matching error text, so a prefix-style id can no
longer suppress another session's never-scored error
- redact_secrets(): broader patterns no longer stack markers on top of an
already-redacted value
- session files read through the MAX_FILE_BYTES cap instead of slurped whole
- README deviations 21-22 recorded; count trued to 22 in CLAUDE.md and
authoring-notes; prefix-id regression + single-marker redaction verified
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017yFdbrdBnFL8Gw7DLrdg19
Earlier commits added a caveat before 'Integrations Setup' but left three earlier
spots in the same README describing TestRail/BrowserStack as working out of the box:
the H1 tagline, the /pw:testrail + /pw:browserstack Commands-table rows, and the
'2 MCP Integrations' heading under What's Inside. Add pointers/caveats to each so a
reader skimming the top of the README gets the same 'optional, manually enabled'
signal. Per review feedback on #981.
The CLAUDE.md caveat said 'cd integrations/<name>' but the real directories are
integrations/testrail-mcp and integrations/browserstack-mcp (the -mcp suffix that the
removed .mcp.json used and that the other four touched docs already spell correctly).
Following it literally would cd into a nonexistent dir. Per review feedback on #981.
Companion to the plugin.json description fix: the marketplace listing (the copy users
see before install) still advertised 'TestRail + BrowserStack MCP integrations' as
bundled. Match the softened plugin.json wording ('optional (manually enabled) ...') so
both listings are consistent. Per review feedback on #981.
Five of six findings were real. Verified each against the code rather than
taking them at face value; one was wrong and is noted below.
1. validate_examples.py carried a stale header from the spec-only phase --
"PARKED AS AN ASSET (deliberately not .py yet)... ON IMPLEMENTATION: rename
to skills/agent-memory/scripts/validate_examples.py". The file is already at
exactly that path. Rewritten to describe what it now is, keeping the
substantive part: why it exists, the seven check families, why it compares
the doc's algorithm by source text rather than exec()-ing a code fence, and
that nothing runs it automatically.
2. Missing shebang -- added. The same finding also claimed mode 100644; that
half is wrong, `git ls-files -s` shows 100755 for all five scripts.
3. hooks.json's description still opened "CONTRACT ONLY -- the referenced
scripts are not yet implemented", true of none of them now. Trimmed to keep
only the UserPromptSubmit provisionality (9.5 is genuinely still open) and
to record the measured latency alongside it.
4. The session-id fallback was the finding worth the most. `session_id` is the
right key -- engineering/security-guidance's shipped hook reads the same one
-- but the fallback was the CONSTANT "unknown-session", and sessions dedupe
by value. Had the key ever been absent, every session would collapse onto
one id, len(set(sessions)) would plateau at 1, and every claim would cap at
L1 forever with no error anywhere. Now falls back to the transcript's own
basename, which IS the session id. Verified end-to-end with session_id
omitted from the payload: the atom records the real session UUID.
5. Dead `now` parameter on _eligible_l1 -- removed.
6. marketplace.json metadata still said 104 agents / 120 slash commands,
pre-existing drift on a line this branch already edits. Trued up to 110/130.
Re-verified after: 69 checks 0 failures, SKILL.md 6/6 PASS, both blocking gates
still fire by name, check_paths 620 files clean, counters and plugin-json pass,
all 5 scripts --help, all 3 hooks parse.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Marketplace listing said 'sync with TestRail, run on BrowserStack' which reads as
out-of-the-box capability; the integrations now require manual enablement. Reword to
'optional (manually enabled) TestRail/BrowserStack integrations' so the listing itself
doesn't oversell. Per review feedback on #981.
Addresses review feedback on #981: README.md, skills/pw/SKILL.md, and the
testrail/browserstack SKILL.md files still described the integrations as working
after just exporting env vars. Add a caveat to each that pw-testrail/pw-browserstack
are no longer auto-registered and that /pw:testrail // /pw:browserstack (and the
testrail_*/browserstack_* MCP tools) fail with 'tool not found' until the server is
enabled manually, pointing to the CLAUDE.md Integrations section.
The freshly merged agent-launcher plugin's six SKILL.md files referenced
scripts and references relative to the plugin root (skills/<s>/scripts/x.py,
references/x.md), which resolves from none of the path linter's bases — so
check_paths.py --all fails on dev with 24 findings, and G1 is a blocking
gate on every future PR. Script commands now use repo-relative paths and
reference labels use the skill-dir-relative ../../references/ form that the
existing markdown link targets already used. 0 unresolvable after the fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
The pw-testrail and pw-browserstack servers were declared in playwright-pro/.mcp.json
and launched via `npx tsx integrations/<name>/src/index.ts`, but the plugin ships no
node_modules and nothing installs @modelcontextprotocol/sdk. Both therefore failed to
connect for every user — permanent 'Failed to connect' lines in `claude mcp list` —
whether or not TestRail/BrowserStack was configured.
Empty the .mcp.json server map (no build systems per repo convention; the integration
TS sources stay in-tree) and document in CLAUDE.md that the two integrations are no
longer auto-registered plus how to enable them manually (npm install + user/project
MCP config).
The two MCP servers registered in .mcp.json could never start: their
@modelcontextprotocol/sdk dependency is declared but never installed
(the plugin ships no node_modules and nothing runs npm install), so every
user saw a permanent 'Failed to connect' pair in `claude mcp list`.
Per the reporter's option 4 + docs: the registrations move to
integrations/mcp-servers.example.json (no longer auto-loaded), and the
README's Integrations Setup section now documents the two-step opt-in
(npm install inside the integration folder, copy the example to .mcp.json).
The integrations themselves are unchanged and keep working for users who
enable them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Turns DESIGN.md from a spec into a working plugin. Five stdlib scripts, three
hooks, agent, command, three references, plugin manifests.
The gates are the design:
L1 -> L2 >= 3 distinct sessions spanning >= 2 distinct calendar days
(`stated` = 2 sessions, day rule still applies; `verified` = 1
observation and is the only day-exempt path)
L2 -> L3 >= 2 distinct projects, >= 30 days, uncontested
Two gates refuse rather than guess. `redacted: true` blocks promotion on any
volume of evidence -- a durability-independent barrier, since a secret restated
across five sessions passes every recurrence gate; the flag firing means the
text was altered, a lexical filter finding one secret is not proof it found all
of them, and L2/L3 are committed to git. An open contradiction freezes both
claims, found by reverse join because the newer atom carries no flag.
All three hooks fail open: a broken memory system costs memory, never a session.
SessionEnd stages promotions to .memory/staged/ and never touches a CLAUDE.md;
only an explicit human adopt does, after backing both files up.
Verified, not asserted:
- all three pinned atom ids from DESIGN.md reproduce exactly
- both blocking gates demonstrated on sample input, named in the output
- end-to-end: two transcripts across two calendar days -> merged L1 atom ->
staged L2 promotion with the path prefix stripped
- reverse join blocks the unflagged newer atom
- cross-tier L2/L3 collision marked at injection time
- recall p50 29ms / p95 31ms / max 35ms spawn-to-exit, scoring itself 2-3ms
over 500 atoms -- interpreter cold start is the entire cost
- validate_examples.py 69 checks 0 failures; SKILL.md 6/6 PASS
- derive_counters --check, check_plugin_json --all, check_paths all clean
DESIGN.md 10.1's "+6" tool estimate corrected to +8 -- the delivered surface is
5 scripts + 3 hooks. README.md's deviations list is authoritative for that and
five other divergences from the pre-implementation spec.
Concept from TencentCloud/TencentDB-Agent-Memory (MIT). No upstream code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
- root CLAUDE.md: Navigation Map row, Repository Structure tree line, and an
'Unreleased (post-v2.11.2, PR #961 merged)' narrative for the agent-launcher
domain (grep previously returned zero mentions)
- CHANGELOG: the verification sentence no longer points at
agent-launcher/DELIVERY-REPORT.md — per the maintainer finish-plan
(audit/pr-stream-2026-08) that report moved to gitignored documentation/;
SPEC.md remains the public build target
- sync scripts: v2.12 comment/description strings -> 'unreleased, post-v2.11.2'
to match the normalized plugin version; codex index regenerated
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FwXG6TqCXKZQvF4iD69cv
check_paths.py resolves path tokens against the sub-skill root, the file's own
directory, or the repo root — the SKILL.md bash examples used plugin-root-relative
paths (skills/<skill>/scripts/x.py) that none of those bases resolve, and shared-
reference link texts (references/x.md) only resolved from the domain root. Bash
examples now use skill-dir-relative scripts/x.py; reference links use explicit
../../references/x.md. 617 files scanned, 0 findings; all other blocking gates
(G3/G4/G7/G8/G10, plugin.json, skill names) verified green locally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FwXG6TqCXKZQvF4iD69cv
Adds agent-launcher to the four sync scripts' domain lists and re-runs them:
.codex + .gemini indexes now carry the 6 skills; .vibe + .hermes repo trees
regenerated (also catches up skills merged since the last sync). The pre-existing
.codex/skills/run symlink collision (autoresearch-agent vs agenthub, both named
'run') is left at its previous target.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FwXG6TqCXKZQvF4iD69cv
- CHANGELOG: [Unreleased] section for the agent-launcher domain (PR #961, merged 2026-08-21)
- 8-phase plugin audit: PASS WITH WARNINGS — structure 84.8-91.3 (orchestrator
EXCELLENT), security 0 critical/high across all 6 sub-skills, 18/18 scripts PASS
- audit auto-fixes: per-sub-skill READMEs (6), SKILL.md versions aligned to the
2.11.2 normalization from the merge, removed untracked scripts/my-agent/ test
debris (the one real security finding), my-agent/ added to .gitignore so user
launch artifacts can never be committed
- PUBLISH-CLAWHUB.md: publish order, slug-conflict fallbacks (cs- prefix registry-
only), 5-skills/hour drip constraint
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FwXG6TqCXKZQvF4iD69cv
- tighten the SKILL.md description from 390 to 300 chars, core trigger first
- validate HIVEMIND_SERVER_URL and spawn opencode serve with an args array and
shell:false, so no environment value is shell-interpolated
- add LICENSE.txt (Apache 2.0); frontmatter stays name + description per CONVENTIONS
Hivemind delegates grunt work to headless opencode workers (scout/coder/tester)
while the orchestrating agent stays the planner, reviewer, and merger.
- placed under engineering/ per repo layout; targets dev per CONTRIBUTING
- frontmatter is name + description only; SKILL.md is 165 lines
- anti-patterns and cross-references sections included
- external opencode CLI dependency and free-model caveats documented up front
- runtime state (.runs/) gitignored, not committed
Round-44 review, three findings, all verified before fixing.
1. The schema's `redacted` description has always asserted "never
promoted to a committed tier without human review" -- a real gate that
DESIGN.md stated nowhere. Confirmed by grep. Added to 4.1 with the
reason the flag carries: redacted:true means the pass ALTERED the
claim, which is positive evidence the source was sensitive, and
redaction is lexical so finding one thing is not proof of finding
everything. Recurrence cannot substitute -- three sightings of a
scrubbed claim are three sightings of the same unresolved risk.
2. hooks.json did not quote ${CLAUDE_PLUGIN_ROOT} while both precedents
this PR cites do (handoff: python3 "${...}/hooks/session_start.py";
skillopt-sleep: "${...}/hooks/on-session-end.sh"). A path with a space
would break the command. Quoted all three.
3. 4.2.1 says "both sit at L1" but the schema marks only the older atom
(contested, contested_by), so the promotion gate cannot be a field
read on both sides. Specified the reverse join: blocked if own
`contested` is set OR own id appears in another atom's contested_by.
Deliberately not a mirrored `contests` field -- same fact in two
places, needing sync, with nothing able to say which copy is right.
Cheap by construction: 5.2 caps the store at 500 atoms and measured a
full pass at 2-3ms.
Did NOT add a schema->doc dangling-section-ref check. Wrote one, it
reported 3.1.1 and 4.1.2 as dangling, and both exist -- my heading regex
required a trailing period that sub-sections do not carry. Re-ran
correctly: zero dangling refs. A brittle checker for an empty class,
which I got wrong twice inside two minutes, is worse than no checker.
Verified: hooks.json parses; 69 checks, 0 failures; derive_counters.py
--check passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-43 review found the Windows gap that 42 rounds missed. Verified it
is a hard break, not cosmetic: the schema's L1 pattern is
^~/\.claude/projects/[^/]+/[A-Za-z0-9._-]+\.jsonl#L[0-9]+$ -- literal ~/
and forward slashes -- so a path built from %USERPROFILE%\.claude\...
matches nothing and an extractor recording the OS path verbatim emits an
atom the schema rejects outright.
Resolved rather than added to 9, because it is mechanical: `source` and
`first_source` store a canonical form, not an observed one. The extractor
derives the ~/-relative forward-slash form from whatever the platform
handed it, the same way 3.1.1's promotion derives the stripped form
rather than storing what it saw -- recording is already a transform here.
Worth noting the blast radius: L2 and L3 are already platform-neutral,
since the stripped form is a bare <session>.jsonl#L<n> with no path.
Nothing committed is affected, only the gitignored L1. 3.1.1's
de-identification stripping bought portability for free.
Also stated first-run behaviour, which 5.4 skipped while specifying
concurrent writers in detail: a missing .memory/atoms.jsonl is the normal
initial state, read as an empty store and created on first write, with
recall returning nothing rather than failing.
Verified: 69 checks, 0 failures; derive_counters.py --check passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-42 review: the "run the validator before editing" requirement lived
in 10.1 and the PR body. Someone opening DESIGN.md six months from now
reads neither -- and "a future editor who does not know the file exists"
is the exact failure the doc names. Now a callout at the top with the
command in it. Fourth time this review series has turned up a rule
stated somewhere other than where the person who needs it is looking.
Also sharpened what round 41 recorded about 9. The reviewer read "~700
lines of settled contract downstream of an unmeasured question" as a
reason to trim 4-5 until the extraction spike reports. Worth being
precise instead: a "no" on (2) does not make the promotion machinery
wrong -- recurrence counting, the tier caps and the contradiction
detector operate on atoms however they were produced, and none reference
the extraction method. It makes them unused. Content that would need
rework is worth deferring; content that would go unread is not, since
deleting reviewed text to re-derive it later costs more than leaving it.
Recorded as a sequencing lesson for the next spec this size rather than
a call to cut.
Verified: 69 checks, 0 failures; derive_counters.py --check passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-41 review, two findings.
The 1 size claim went stale in a way worth being precise about. 85,875
bytes was correct at 67a1228, but merging dev moved this branch's base
and the file is now 90,312 -- and the parenthetical says "measured at
this branch's base", so it was false as written. Updated to 88 KB /
90,312, and noted that it grew 4,437 bytes while this PR was open, which
is 1's own thesis demonstrating itself on the file it is about. Round
29's principle still holds: the checker verifies the sentence's internal
consistency (method named, units agree), never a live comparison -- both
checks pass on the new figures.
Second, and the better finding: 9 listed six decisions as a flat set,
which understated that two of them decide whether there is a system at
all. (2) extraction-without-an-LLM gates everything downstream -- the
session gate, the tier caps, the contradiction detector are only as good
as what the extractor produces -- and (3) is answered by (2), since
9.3's 2-week trial IS the test of it. The other four are local: each
changes one mechanism and leaves the rest standing, including (5), whose
worst case deletes one hook while the tiering survives on SessionStart.
Now a table, with the cost stated plainly: ~700 lines of settled contract
sit downstream of a question nobody has measured.
Verified: 69 checks, 0 failures; derive_counters.py --check passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-40 review made a point the spec had left to inference: the
recurrence gates are a durability filter, not a secrets filter. A secret
seen in three sessions across three days is exactly as much a secret as
one seen once, so the gates were never protecting CLAUDE.md from a leak
-- they only made one slower. The `verified` fast path removes even that,
taking a claim from a single sighting to a committed marker block with
6 rule 1's redaction pass as the sole barrier.
Stated in the fast-path block itself rather than left to a reader
combining 4.1 with 6 -- the third time this review has turned up a rule
living in one section while the surface an implementer builds from lives
in another. Two consequences named: redaction must not be shortcut on the
`verified` path ("a script confirmed it" says nothing about whether the
text holds a credential -- "the staging key sk-... works" is a plausible
verified claim), and a verified 1-observation atom carrying a secret is
the first behavioural test memory_promote.py should have, since it is the
shortest path in the system from raw transcript to committed file.
Verified: 69 checks, 0 failures; derive_counters.py --check passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
The decision-driving §2 predated engineering/memory-engineering landing on
dev (#947) and never mentioned it. Adds the missing subsection: layer
distinction (it audits memory systems; this would be one), the namespace
fence both SKILL.mds must carry, a commitment that §5.1's eviction and
contradiction rules stay expressible in forgetting_policy_linter.py's F1/F4
form, and memory_cost_profiler.py as the §7 budget framework. Conclusion
renumbered 2.5 -> 2.6. Counters untouched by design (spec-only folder).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Bzm6Pafyxja6g4jUDPcei
- Conflict resolution takes dev's counter surfaces and re-applies the
agent-launcher marketplace entry (description trimmed to 950 chars for the
new <=1024 guard) and README domain row
- plugin.json source/attribution moved verbatim to authoring-notes.json per
the post-#954 schema dev now enforces; version aligned to 2.11.2
- claude-opus-4-8 (retired, G7-blocking since #938) pinned to claude-opus-5
across 5 scripts + example build sheet; all touched scripts re-smoke-tested
- 4 references topped up with external sources (7-8 each)
- DELIVERY-REPORT.md removed from the public tree (sprint artifact; content
preserved in PR #961 body and git history) — SPEC.md stays as build target
- Gates green: derive_counters --check pass, plugin-json 94 OK + marketplace
guard OK, frontmatter 0 errors, model freshness 0 findings, smoke 0 failed,
hooks exit 0 with and without AGENT_LAUNCHER_SESSION
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Bzm6Pafyxja6g4jUDPcei
Round-2 sweep after re-auditing all 15 reported issues against the merged dev:
- #885 generalized: the original fix only renamed self-improving-agent's
status/review, but three more plugins shipped skills whose bare names
shadow Claude Code built-ins. Renamed with the same convention:
playwright-pro init/review -> pw-init/pw-review, agenthub init/status ->
hub-init/hub-status, autoresearch-agent status/resume -> ar-status/
ar-resume. All command references (/pw: /hub: /ar:), docs, audit records,
harness manifests, and mirror trees/indexes updated; the flat mirror
namespace no longer collides on 'status'. New scripts/check_skill_names.py
gate (wired into ci-quality-gate.yml as blocking) fails CI on any future
bare reserved name; rule added to SKILL-AUTHORING-STANDARD.md.
- #969 follow-through: five more scripts print box-drawing characters that
cannot exist in cp1252 (api_scorecard, api_linter,
breaking_change_detector, humanizer_scorer, content_scorer) — same
guarded UTF-8 reconfigure applied; all smoke-tested under a forced
legacy encoding.
Verified: check_skill_names (incl. negative test), check_plugin_json,
check_paths, derive_counters, check_dual_publish, smoke_scripts (634/634),
0 broken mirror symlinks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Review follow-up on PR #972: the Windows Notes section now sits between
Verification & Testing and Troubleshooting, matching the Table of Contents
order, and the four scripts patched for #969 are back to exactly two blank
lines after the reconfigure block.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Review follow-up on PR #972: docs/plugins/index.md still described the old
"two approved extension fields in plugin.json" policy reversed by #954 —
rewritten to point at .claude-plugin/authoring-notes.json and the CI
hard-fail. 32 generated docs pages still linked the gitignored megaprompts/
tree via absolute GitHub URLs (404s); converted to the same annotated
plain-text form used in the source files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
Public audit record audit/pr-stream-2026-08/: every open PR against dev
(#788-#967) deep-read and re-executed against the repo's own gates.
Verdicts: 8 MERGE, 8 MERGE-WITH-CHANGES, 6 CLOSE, 3 maintainer-draft
finish plans. Names the four blocking maintainer decisions (extension-key
policy #966-vs-#940, agent skills: preloading, DESIGN-only folders,
release framing), a six-phase global merge order, and per-PR executable
verification plans.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Bzm6Pafyxja6g4jUDPcei
- #954: strip non-spec source/attribution keys from all 39 plugin.json
manifests so Claude Code's validator accepts them; metadata preserved in
new .claude-plugin/authoring-notes.json sidecars; check_plugin_json.py now
hard-fails manifests carrying those keys and sanity-checks the sidecar;
CLAUDE.md ClawHub schema section updated to the new rule.
- #949: move the c-level-agents plugin out of c-level-advisor/ to a
top-level directory so the two marketplace sources no longer overlap;
updated marketplace.json source, homepage, descriptions, all
cross-references, docs, harness manifest, mirror-tree symlinks/indexes,
and rebased the moved files' relative links; domain counters trued up
(18 -> 19 domains).
- #933: replace dead links to the gitignored maintainer-local megaprompts/
tree with annotated plain-text references (44 files: SKILL.md, READMEs,
agents, commands).
- #931: DynamoDB on-demand pricing updated to post-Nov-2024 rates
($0.625/M writes, $0.125/M strongly consistent reads).
- #969: skill_security_auditor.py and the three dossier scripts reconfigure
stdout/stderr to UTF-8 (errors=replace) so legacy Windows codepages no
longer crash at print time; PYTHONUTF8=1 documented.
- #968: Windows Notes section in INSTALLATION.md + README pointer for the
core.symlinks mirror-tree checkout caveat.
- #924/#885 residuals: hook commands quote "${CLAUDE_PLUGIN_ROOT}" paths in
all plugin hooks.json/settings.json (space-safe roots); removed the stale
pre-rename status/review mirror symlinks and index entries left over from
the memory-status/memory-review rename.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qgc6RYXWJPr5oW9DHU7zR4
GitHub Copilot CLI reads .claude-plugin/marketplace.json but enforces a
1024-character cap on each plugin's description. Four entries exceed it, so
Copilot rejects the entire catalog with:
Invalid marketplace.json: plugins.N.description: String must contain at most
1024 character(s)
Shortens engineering-advanced-skills (1132 -> 986), research-ops-skills
(1593 -> 957), markdown-html-skills (1240 -> 914) and memory-engineering
(1044 -> 964), trimming only redundant parenthetical detail. Skill inventories,
version history, hard rules, tool/reference counts and attributions are kept.
No other field is touched.
Verified with Copilot CLI: marketplace adds successfully and all 90 plugins are
listed.
Independent 10-agent verification workflow: 9/9 spec parts PASS, overall PASS,
zero differences from spec. Records the verdict table, design decisions, and
reproducible verification steps.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FwXG6TqCXKZQvF4iD69cv
Adds the agent-launcher/ top-level domain — a plugin re-implementation of
Anthropic's launch-your-agent reference skill (Apache-2.0; independent, not a
fork) for building Claude Managed Agents (CMA) in the user's own account.
Every session starts with a goal (./my-agent/goal.json, surfaced by an opt-in
AGENT_LAUNCHER_SESSION=1 SessionStart hook + /cs:goal); loop_compiler.py
compiles that goal into a bounded grade->iterate loop (CMA user.define_outcome
self-grading, max_iterations 1..20), a recurring POSIX-cron scheduled-deployment
loop, or a single-pass interview->stage->launch workflow.
- 6 skills: agent-launcher-orchestrator (context: fork goal router) + interview
+ stage-launch + grade-iterate + run-without-you + wrap-up
- 18 stdlib-only deterministic scaffolder tools (NO network/API calls; live
launches emitted as BYOK curl that never prints the key); all pass --help/--sample
- 4 agents (orchestrator + interviewer + grader + deployer), 8 /cs:* commands
- opt-in SessionStart/SessionEnd hooks (exit 0 on any error), 5 shared
references, 4 assets (build-sheet schema + overview/next-directions templates
+ example)
- validators enforce CMA limits (<=20 skills/session, <=8 memory stores,
depth-1 multiagent, max_iterations <=20, <=1000 deployments/org)
- registered in marketplace.json; headline counters trued up via
derive_counters.py --check (skills 362->368, domains 18->19, tools 644->664,
refs 741->746, agents 102->106, commands 116->124, plugins 88->89)
Distinct from engineering/agent-harness (generic bounded loop over any domain)
and engineering/write-a-skill (authors Claude Code skills, not CMAs).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FwXG6TqCXKZQvF4iD69cv
Round-38 review noticed that the committed contract files already encode
an answer to some of 9's open decisions -- hooks.json wires
UserPromptSubmit even though 9.5's option (c) is to delete that hook.
The doc knew: 9.5 already says "if (c) wins, hooks.json must shrink too."
But that only helps a reader holding both files. Read on its own a
hooks.json says "these three hooks exist", which is precisely the wrong
impression, and a contract file is exactly the artifact someone reads on
its own before implementing. Same lesson as round 36's contested-tag gap,
one level up: a cross-reference is not a contract, and that applies
between files as much as between sections.
hooks.json's own description now marks the entry PROVISIONAL, names the
open decision, gives the reason (the budget is dominated by interpreter
cold-start, not by the script's work), and says plainly that listing the
hook is a contract for the shape it would take IF it survives -- not
evidence the decision was made. SessionStart and SessionEnd are marked
not provisional so the warning stays scoped.
Verified: hooks.json parses; 69 checks, 0 failures; derive_counters.py
--check unchanged (363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-37 review. The substantive finding: 9.5's options (a) fits /
(b) raise the budget / (c) drop the hook all treat spawn cost as a
constant to tolerate -- while last round's measurement showed spawn cost
is the ONLY cost that matters (scan 2-3ms, interpreter ~20ms). None of
the three attacks the measured bottleneck. That follows directly from a
number this doc already carried, and I should have drawn it rather than
waiting for a reviewer to.
Added (d): a warm resident process holding the store in memory, with the
hook reduced to a socket round-trip. Named as a real option because it is
the only one that removes the dominant term, explicitly NOT as the
recommendation -- its costs land on this design's own properties. A
"never blocks, exit 0" hook gains a liveness dependency and must keep the
cold path anyway, so complexity is added to rather than swapped for what
(a)-(c) need; lifecycle and stale-socket handling are a second heuristic
alongside 5.4's; a resident process holding memory contents in RAM is a
different security surface; and stdlib-scripts-that-exit is this repo's
shape. Sequenced behind the busy-machine measurement: if 100ms holds
under load, a daemon buys latency nobody needed.
Also trimmed the three passages the review named as archive-not-spec.
One of them ("the sentence went stale twice (53 -> 57 -> 67)") was itself
stale at 69, which is the argument for cutting it rather than updating it.
Verified: 69 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-36 review, three real findings.
1. Session-id uniqueness was the one load-bearing claim in 3.1.1 asserted
rather than evidenced, while everything around it cites line numbers or
arithmetic. Measured it: transcript filenames on a live install are
RFC-4122 UUIDs (version 5, RFC-4122 variant), shown with the commands
that produced them. One install is enough to establish shape, not to
promise the scheme is stable -- so the more useful half of the fix is
the fallback the reviewer noted was missing. The glob now has defined
behaviour for all three outcomes, and the >= 2 row is the one that
matters: without it a naive implementation takes the first match and
attributes a claim to the wrong session, which is a *wrong* citation
rather than a missing one, and 6 rule 6 cares about that distinction.
2. 4.2 states the contested-rendering rule tier-agnostically, but 5.2 is
the contract user_prompt_submit.py actually gets built from and never
mentioned it. An implementer working strictly from 5.2 ships a recall
path that surfaces a contested claim as plain fact. Stated in both
places now -- cross-references are not a contract.
3. L1 had a stored cap (500 atoms); L2/L3 had only injection budgets, so
a marker block could grow without bound while every session saw a
silently truncated view -- the 1 failure this design exists to prevent,
one layer down. L2 caps at 60 atoms with overflow demoted to L1
(recoverable, re-promotable); L3 caps at 30 and refuses further
promotions instead of deleting, since "never auto-demoted" means the
cap blocks inflow rather than choosing what to lose.
Verified: 69 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-35 review called the 100ms recall budget the highest-risk
unverified assumption, and estimated interpreter cold start at 20-40ms.
9.5 has prescribed the measurement since it was written -- "time a no-op
python3 -c pass plus a 500-atom scoring pass at p50/p95" -- so I ran it
rather than citing an estimate.
n=40, Linux container, otherwise idle:
python3 -c pass p50 12.4 p95 30.8 max 36.0
spawn + 500 atoms + score + top-5 p50 23.2 p95 30.1 max 50.6
...of which in-script work p50 2.1 p95 3.0
This reframes the risk rather than settling it. The scoring pass is
~2-3ms, so the 500-atom cap is not the binding constraint and never was
-- cold start is essentially the whole cost, which makes the budget a
process-spawn question rather than an algorithmic one. 100ms holds with
~3x headroom here; the 50.6ms max shows a real tail that would widen
under load. Recorded as a floor, not the answer: 9.5 asks for a busy
machine and this was an idle container.
Also cut two asides the review named as review-thread artifact rather
than spec: the 3.1 paragraph on why a rationale cannot be a $comment
inside a fixture (5 lines -> 3, keeping the reason), and the validator's
8-line comment on not whitelisting $comment (-> 4, keeping the warning a
future editor needs).
Verified: 69 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-34 review, two actionable items.
5.1 had no internal-budget discussion while 5.2 argues at length that its
1s hook timeout is a backstop rather than the target -- an asymmetry a
reader can only resolve by guessing. Stated why it is deliberate: this
hook runs once per session rather than once per prompt, so a slow run
costs one startup instead of compounding; and its work is bounded by the
2KB/4KB byte caps rather than by a scan that grows with history, where
recall scores up to 500 atoms. Also noted that 9.5's cold-start finding
lands here too if it comes back bad.
Addressed the .py.txt parking as a *precedent* rather than defending this
instance. What makes it legitimate is not intent, which is unfalsifiable,
but that the file is not a tool: no plugin ships it, no skill owns it,
nothing invokes it, and counting it would make python_tools less accurate
rather than more. The abuse it could be mistaken for -- a real tool
renamed to keep a headline number down -- is separable by one question a
reviewer can ask: is anything supposed to run this? Pointed at 11's
audit/ option as the way to avoid the pattern entirely.
Not changed: hooks.json naming three scripts that do not exist. Checked
whether the hypothetical lint exists -- nothing in scripts/ or
.github/workflows/ references hooks.json at all -- so the file's own
"CONTRACT ONLY" description is the whole mitigation needed today.
Verified: 69 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-33 review. 4.1's L1->L2 gate has two clauses -- >= 3 sessions AND
>= 2 distinct calendar days (UTC) -- and family 4 only checked the count.
The days clause is the half that stops one long working day from minting
an L2 claim, which is the exact case 4.1 calls out for the `stated` fast
path, and it had neither a check nor a fixture exercising it.
Added it for L2 atoms whose confidence is not `verified` (4.1 names
`verified` as the only exempt path). Worth stating why the test is
sound rather than approximate: first_seen and last_seen bound every
observation, so date(first) != date(last) is equivalent to ">= 2 distinct
days", not a proxy for it. Same date means every observation fell inside
it; different dates means at least two were touched.
Verified by shrinking the L2 fixture's window to one day:
FAILED: atm_961f033d spans >= 2 distinct calendar days
FAILED: atm_961f033d/L2 promoted_at falls inside its own observation window
The second is family 7 catching a side effect of the same injection,
which is the intended overlap.
Also fixed the placement section's framing. It claimed "neither option is
endorsed here" and then introduced its bullets with "both cut against
staying here" -- a lean, contradicting the sentence above it, and the
third reviewer in a row to read it as one. Now two symmetric cost lists
with nothing weighed.
Verified: 68 -> 69 checks, 0 failures; derive_counters.py --check
unchanged (363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-32 review. 4.1.1 step 3 enumerated nine of the schema's thirteen
required fields, so a memory_promote.py written literally against it
would emit a schema-invalid atom. The reviewer also caught that 4.1.3's
confidence-merge rule is scoped to "(5.3)" -- the same-tier SessionEnd
merge -- so it does not cover this cross-project one by implication.
Added a table for the four: `claim` from the earliest contributor (the
group normalizes identically; earliest is for determinism, since
normalization is lossy on case and punctuation), `confidence` = max()
across all contributors (4.1.3's principle, restated rather than
assumed), `redacted` = true if any is (over-claiming costs nothing,
under-claiming loses the signal), and `kind` must agree or the group is
ineligible -- `kind` is not in the hash key, so two projects classifying
the same sentence differently means the "same claim" premise is what is
shaky. Refusing keeps this section's one-directional property: L3
under-fires, it never mis-fires.
This step has now shipped three omissions (`source`,
`promoted_from_projects`, and these four), each caught by a human
reading the list against the schema. Added a check for the class: every
schema-required field must appear in 4.1.1. Re-injecting the omission
fails on ['kind', 'redacted'].
Two notes on that check, both found by verifying it rather than trusting
it. It first reported first_seen/last_seen/first_source as missing --
false, because norm_prose strips `_` as an italic marker, so the needles
had to be normalized the same way. And it is a substring test over the
section, so `confidence` and `claim` satisfy it via incidental mentions
elsewhere; that limit is now stated in the code rather than implied.
Verified: 67 -> 68 checks, 0 failures; derive_counters.py --check
unchanged (363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-31 review spotted "other-project" sitting inert in the validator's
allow-list. It is inert for a reason worth fixing rather than tidying:
the check only scanned the path-embedded `-home-user-<slug>` form, so
`project` and `promoted_from_projects` -- where names appear bare -- were
never checked at all. That is the whole coverage gap, not a dead entry.
The consequence was the exact leak 6.5 exists to prevent. The rule came
from a fixture that named a private repo; a fixture naming one in
`project` rather than in a path would have passed clean. Verified by
injecting one:
FAILED: no unknown project names in fixtures, in paths or in fields
['acme-internal-private']
Now gathers names from both sources before comparing. Check count
unchanged at 67.
Verified: 67 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Two of three notes from the eighth PR review round; the third needed no change.
1. `--max-rounds` was per-invocation, so `open` and a later `close` could
disagree about the cap and G5 escalation depended on how the command
happened to be typed. `open` now records the agreed cap in gate state and
status/collect/close inherit it. Passing the flag again is an explicit
renegotiation and prints the change rather than silently overriding.
Before: `open --max-rounds 2` then `status` -> "max_rounds": 5
After: same sequence -> "max_rounds": 2
2. The protocol-relative and own-asset URL allowances were documented in a
comment but nothing checked them, unlike the void-element and template-token
regressions which each got a fixture. `--sample` fixtures now carry
must-keep / must-drop URL assertions alongside the block count, and
`SAMPLE_HTML` exercises all three cases (`//host/x`, `https:` image,
`javascript:`). Verified the assertion bites: adding "javascript" to the
scheme allowlist turns --sample red with `FAIL - kept javascript:`, exit 2.
3. No change for cross-origin `<svg><use href="https://...">`. `href` is
already in URL_ATTRS and scheme-checked; `https:` is allowed there by the
same deliberate rule that lets a reviewed page's own `<img src>` load. It is
not a gap in the allowlist, it is the allowlist working as designed.
Gates: derive_counters --check pass, check_plugin_json --all pass, all three
scripts --help/--sample exit 0, write-a-skill checklist PASS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Round-30 review: ~70 lines of meta-discussion about where this file
should live stood between a reader and the tiering design. Moved to a
new 11 at the end, leaving a three-line pointer at the top. Old 11
(Attribution) renumbered to 12; the heading-order linter confirms the
sequence is still consistent.
The content is kept rather than dropped -- it is the record of an open
maintainer decision that three reviewers have now asked about -- but it
is not part of the design and should not be read first.
Verified: 67 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-29 review. Family 6 compared 1's cited byte count against the
CURRENT size of the repo-root CLAUDE.md -- a file this repo appends a
release note to on nearly every point release. The next unrelated PR
touching it would have turned this suite red for a reason with nothing
to do with this folder. 10.1's own thesis is that a checker must own its
ground truth; this one borrowed a moving one.
Snapshotting the byte count as a constant in the checker was the
reviewer's other suggestion and is not better: it puts the same number in
a second place that can drift from the first, with nothing able to say
which is wrong.
Replaced with two properties of the sentence itself, both of which the
doc controls: the claim must name `wc -c` and carry a real byte figure,
and its two units must agree (84 KB == 85,875 bytes). That still catches
the defect this check was written for -- 1 once read "~40 KB",
eyeballed, off by more than 2x -- verified by re-injecting it:
A (eyeballed, no byte figure): FAILED names `wc -c` and cites a byte figure
B (42 KB vs 85,875 bytes): FAILED KB and byte figures agree
Check count is unchanged at 67 (two removed, two added), so the
self-referential count assertion still holds. Also fixed a docstring in
_find() that still described the repo-root lookup this removes.
Verified: 67 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-28 review. Three changes, two held.
5.1 now carries the consequence 9.6 leaves live: L2 and L3 are injected
together and 4.2.1's detector cannot reach L3, so nothing upstream
guarantees they agree. Stated as a constraint on the hook -- never emit
two colliding claims as plain assertions -- rather than a mechanism, so
it holds under all three of 9.6's candidates. The reviewer is right that
retrofitting conflict-marking after session_start.py ships costs more
than honouring it in the first version; that does not require settling
9.6 itself, only refusing to ship the unmarked case.
AGENT_MEMORY_RECALL -> AGENT_MEMORY_USERPROMPTSUBMIT, in DESIGN.md and
hooks.json. The old justification (shorter; matches section 3's
vocabulary) traded away a property worth more: with all three vars
mirroring their hook name, a user who knows Claude Code's hook names can
derive all three without reading this doc. Three vars under two
conventions also invites the typo report the reviewer predicts.
Added the exact CI workflow snippet to 10.1. Still not wiring it into
ci-quality-gate.yml -- that runs on every PR in the repo, for a folder
9.3 permits deleting after a two-week trial -- but saying yes now costs
one paste rather than a design conversation.
Held: the placement decision, and the suggestion to split mechanical
rationale into references/. The second turns out to be blocked by the
first, which was worth measuring: a references/*.md under
engineering/agent-memory/ moves the references counter 746 -> 747, while
the same file under audit/ is pruned and free. The status header now
tables that alongside the parking hack and the double-relocation cost --
three open items resolving from one decision, which is the argument for
answering it before the implementation PR.
Verified: 67 checks, 0 failures; hooks.json parses; derive_counters.py
--check unchanged (363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Three findings from the seventh PR review round.
1. `marketplace.json` still said "zero network requests" flat. An earlier
commit corrected exactly that wording in README.md, SKILL.md and
plugin.json — a reviewed HTML artifact's own https: assets do load, and
deliberately so — but missed marketplace.json. Now matches the others.
2. `GATED_ELSEWHERE` lived in human_gate.py as free-text prefixes matched
against messages generated in feedback_parser.py: an implicit cross-file
contract nothing enforced. The prefixes now live beside the
`problems.append()` calls that emit them and are read from the loaded
parser module, with the old literal kept only as a fallback for an older
parser.
Reproduced the drift on pre-fix code by rewording the G3 message:
G3 round 1 has no named reviewer
G7 round 1 integrity: unknown severity/kind 'BLOKCER'
G7 round 1 integrity: the sidecar names no reviewer - ... <- duplicate
Same reword post-fix produces only the first two lines.
3. `ATTR_RE` truncated a quoted header attribute at the first space:
`target="q3 plan.md"` parsed as `q3`. Quoted values now parse, and the
docstring states the quoting rule and that `target` is a display hint —
quote verification runs against the `--target` path.
Gates: derive_counters --check pass, check_plugin_json --all 90/90 OK,
marketplace.json parses, all three scripts --help/--sample exit 0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Round-27 review: DESIGN.md had accumulated its own review history inline
("round 3's fixture fix", "round 7 shipped two ids", "an earlier draft
violated..."), which reads as a PR changelog in a document an
implementer reads once. Fair, and I had been adding to it every round --
the previous commit put "until round 26" into 10.1.
Rewrote every such site to state the rule and the failure it prevents,
without the narration of who found it when. The rationale is what stops
a rule being re-broken; the round number is not. Two examples:
- 3.1's lifecycle callout now names the drift a "one lifecycle" claim
invites (two atoms that each validate alone and contradict each other
side by side) rather than reporting that a draft once did it.
- 10.1's property 1 now reads as a prohibition -- "it must not get this
property by exec-ing the fence" -- which is what a future editor needs,
instead of a note about when the exec was removed.
Same pass over the validator's comments, keeping the warnings (a future
editor of that file does need to know why $comment is not whitelisted)
and dropping the round counters.
Also stopped the status header reading as a lean toward audit/. Two
consecutive reviewers took "a better fit than this note originally
claimed" as an endorsement; it was meant as a correction to the note.
Now states plainly that neither option is endorsed and the decision is
the maintainer's, with the costs of each listed below it.
No rules, thresholds or contracts changed. Verified: 67 checks, 0
failures; derive_counters.py --check unchanged (363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Round-26 review asked for a trust-boundary comment on published_normalize()'s
exec of a fenced block extracted from DESIGN.md. Removed the exec instead,
because the same review's other finding turns the comment into an
insufficient answer.
Findings 1 and 2 interact. Wiring the validator into CI -- correctly
observed to be possible today, since a temp .py copy is never seen by
derive_counters.py -- would have escalated the exec from "a maintainer
runs this on a branch they trust" to "any PR author executes arbitrary
code," because ci-quality-gate.yml triggers on pull_request and that
includes forks. The exec's safety depended on a fact outside the file,
and the obvious next improvement silently falsified it. A comment
documenting the trust boundary would have been read, agreed with, and
then invalidated by the very next commit.
The property the exec bought -- doc and fixtures cannot silently diverge
-- is preserved by comparing source text: the checker holds its own
normalize() and refuses to run if the doc's fenced block differs.
Verified by editing the doc's algorithm without updating the checker:
FATAL, both bodies printed. Fails closed on a cosmetic reformat too,
which is the safe direction.
Also corrected two claims this round proved wrong: 10.1 implied the .txt
parking blocks CI gating (it does not -- temp-copy works today, and the
placement decision does not gate it either), and the status header
inherited that error from round 25.
Verified: 67 checks, 0 failures; no exec() remains in the folder;
derive_counters.py --check unchanged (363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Two findings from the sixth PR review round.
1. `<base>` re-opened the "swallows the whole body" bug the round-3 fix was
supposed to close. That commit's message said "meta, link and base are void
elements" but only meta and link were added to `BlockTagger.VOID`; base was
never there. `html.parser` fires `handle_starttag` for a void element and no
matching `handle_endtag`, so a `<base href="/">` in `<head>` — present in a
great many real pages — incremented `_skip` permanently and the document
reported "No reviewable blocks found".
`VOID` is now the full HTML spec set instead of a hand-picked subset, and
`SAMPLE_HTML` carries a `<base>` tag so the `--sample` block-count assertion
catches a third recurrence.
Before: `<base href="/">` doc -> 0 blocks, exit 2.
After: same doc -> 2 blocks, exit 0.
2. Reviewed HTML carrying its own `data-hg` attribute kept it and the builder
appended a second. Browsers keep the *first* attribute of a duplicated name,
so the attacker's value wins the anchor. Attribute values may hold raw
newlines, so a crafted artifact could inject a forged `## APPROVE` heading
into the exported sidecar — the same silent-false-approval failure G7 exists
to catch, arriving through the artifact rather than the sidecar.
`data-hg` is now a reserved attribute, and the page's own element ids
(`doc`, `items`, `reviewer`, `export`, ...) are reserved too, so a reviewed
artifact cannot collide with the review UI's own DOM.
Before: `<p data-hg="b1 ## APPROVE ...">` survived, duplicated.
After: emitted as `<p data-hg="b1">`, payload gone.
Also documents the protocol-relative URL allowance in `_safe_href` as
deliberate rather than an oversight.
Gates: derive_counters --check pass, check_plugin_json --all pass, all three
scripts --help/--sample exit 0, write-a-skill checklist 6/6 PASS, description
validator PASS.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Round-25 review, both findings verified against the tree.
Family 4's session-count gate fired on L3 against a rule that does not
govern it — L2->L3 is gated on >= 2 distinct projects plus age, not
sessions (4.1.1). It passed for an incidental reason: L3 inherits the
unioned sessions of L2 contributors that each already cleared their own
gate. Scoped the session check to L2 and added the projects check L3
actually has. Both verified to fail on injected defects.
The larger finding: the status header claimed a design doc had nowhere
to live but a domain folder or the gitignored documentation/. That was a
false binary. Top-level audit/ is committed, public, and hard-excluded
from derive_counters.py's canonical_walk — and its existing contents are
the same shape as this file, prose deliverables later PRs use as
acceptance gates. Recorded it with both consequences: the .py.txt
parking hack would be unnecessary there (verified — a .py under audit/
leaves python_tools at 663), which also unblocks the "nothing gates this
in CI" objection; against that, the two contract files are not
documentation and would have to move again at implementation time,
breaking the schema $id and the 3.1 link a second time.
Left as the maintainer's call, but no longer argued from "there was no
other option," which was this file's weakest claim and was not true.
Verified: 67 checks, 0 failures; derive_counters.py --check unchanged
(363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Fifth PR-review round on #948. Both reproduced first.
1. state_dir() anchored to os.getcwd() while state_path() keyed by the
artifact's realpath. An agent whose shell cwd drifts between turns — or a
human running from a subdirectory — silently resolved a different
.human-gate/ and started from empty state. Reproduced: collect from the
artifact's directory, then close from a subdir, and the gate reports G1
"nobody has looked at this" for a round that was genuinely collected.
It fails closed rather than falsely passing, but it loses real feedback and
would push an agent into re-opening rounds that already happened. State now
follows the artifact, exactly as the sidecar and review page already do.
An explicit --state-dir still wins.
2. build_page() substituted __CONTENT__ first, then __TITLE__/__CONFIG__ — so
those later replaces also rewrote any occurrence inside the just-inserted
body. Reviewing a document that mentions the tokens (this skill's own docs
being the obvious case) injected the entire JSON config into the visible
page, not just a garbled title. Worse than the report suggested.
All three slots now fill in one re.sub pass, so no substituted value can be
re-substituted — which also covers the reverse direction, where block text
inside the config JSON contains __CONTENT__. The Markdown --sample fixture
now carries the token text, so the case is guarded rather than reasoned
about.
Minor: `--waive` with nothing to waive now prints "nothing to waive" instead of
silently discarding the flag.
Re-verified: derive_counters --check, check_plugin_json --all, checklist 6/6
PASS, description validator PASS, all three scripts --help/--sample green,
--sample asserts both fixtures' block counts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Round-24 review. One actionable finding, verified: 4.2 promised
contradiction handling "at L2/L3", but 4.2.1's detector groups atoms by
`project` and an L3 atom is scope=global with no `project` field — the
schema forbids one. Detection can never fire against L3, the one tier
that is always in context and never auto-demoted.
Scoped 4.2 to L1/L2 and split detection from rendering: the injected
`[contested]` tag stays tier-agnostic, since the schema permits
`contested` anywhere and a human can set it at adopt.
Added 9.6 rather than a loop change, because the L3 case is
underdetermined, not unbuilt. A project claim that differs from a global
one is either a correction to an over-generalised L3 atom or a
legitimate local exception, and no string-shape rule separates them.
Guessing "correction" is the expensive direction: it would tag the
persona tier as unreliable the first time any project deviates —
section 1's false-permanence failure, inverted. Records the live
consequence (5.1 injects L2 and L3 together, so two contradictory lines
can enter one context block unmarked) and three candidates, leaning
specificity-wins for v1.
Also: the "53 checks in six families" claim in 10.1 was stale by two
rounds and a reviewer quoted it back. Rather than correcting the number,
made the program own it — a final check asserts the doc cites the count
actually executed, so the sentence cannot go stale again. Documented the
working invocation in 10.1 too; the `.txt` parking means nothing in CI
gates this yet, and `python3 <(cat ...)` does not work because path
resolution walks up from __file__.
Verified: 69 checks, 0 failures; the count check fails when the doc
disagrees. derive_counters.py --check unchanged (363/89/663).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Fourth PR-review round on #948. All four reproduced first.
1. The gate was one flag away from opt-out. --waive applied to whatever
gate_refusals() returned, including G1 "no review round has been collected",
so `close --waive "no time"` exited 0 with nobody having looked at the
artifact. That is the most tempting shortcut for an agent under time
pressure and it defeats the skill's whole premise.
G1 is now unwaivable, with its own refusal message: a waiver accepts
objections a reviewer raised, it cannot manufacture a review that never
happened. Waiving a genuine objection (G2/G3/G4/G7) still works.
2. Inline `style` was unsanitized, so a reviewed draft containing
`background-image:url(https://attacker/beacon.png)` fired a request the
moment the reviewer opened the page — no script needed, and directly
contrary to the no-network property the README and manifest advertise.
Added to DROP_ATTRS. The <style> tag was already dropped, so keeping the
attribute was inconsistent as well as leaky.
3. Markdown `` never rendered. LINK's regex was not anchored against
a preceding `!`, so an image became `!<a href=...>` — and _safe_href's
image=True branch, which exists to allowlist data:image URIs, was dead code
on that path. Added an IMAGE regex ahead of LINK, negative-lookbehind on
LINK, and real <img> rendering through the same scheme allowlist. Verified a
javascript: src degrades to inert alt text.
4. An unterminated <script> silently swallowed the rest of the body — same
confusing failure shape as the void-tag bug, though it fails safe. Now emits
a named diagnostic to stderr instead of vanishing.
Nit: raw-HTML `target="_blank"` anchors get the rel="noreferrer noopener" the
Markdown path already added to its own.
Re-verified: derive_counters --check, check_plugin_json --all, checklist 6/6
PASS, description validator PASS, all three scripts --help/--sample green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Round-23 review. All three findings verified against the tree first.
Fixture drift (3.1 L1 vs the schema's L2 example, captioned "one atom's
lifecycle read side by side"): the L1 snapshot carried the L2's
last_seen as its own first_seen, putting the first sighting three weeks
*after* the promotion it precedes. A second incoherence in the same pair
went unmentioned by the review and is arguably worse: the L1
back-pointer used the L2's `source` line (#L412) where its `first_source`
(#L77) belonged, which 3.1.1 forbids — promotion strips the path prefix
and nothing else, so a line number cannot drift across it. Both fixed by
anchoring the L1 fixture on the L2's first-sighting fields.
Added family 7 to the checker: within an atom, first_seen <= promoted_at
<= last_seen; across a lifecycle group, first_seen identical (4.1.1 takes
the min), last_seen/observations monotonic, sessions a superset, and
first_source surviving with only the prefix stripped. Families 1-6 all
passed the broken fixtures because each atom was independently
well-formed and nothing compared them — a prose claim that two fixtures
are one story imposes constraints no per-atom check can see. Verified by
re-injecting the old values: 2 failures, both named.
Manifest precedent was "5 for 5" and is 4 of 5. llm-wiki uses the same
on-disk nesting but declares the bare ["./skills"] — which IS one of root
CLAUDE.md's documented forms. That inverts the maintainer follow-up: the
question is which of two shapes the repo wants, not whether to bless an
undocumented fourth one, since a documented form already covers this
layout.
10.1 cited 644 -> 645 for the counter delta while a sibling file in the
same PR cited 663 -> 664. 663 is current; 644 predates book-to-skill.
Verified: 57 -> 68 checks, 0 failures; derive_counters.py --check
unchanged (363 skills, 89 plugins, 663 tools).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Three findings from the automated review, all contract-level:
- memory_schema.json: the tier=L3 -> promoted_from_projects conditional
was one-sided, so an L1/L2 atom carrying promoted_from_projects was
accepted. Added the else branch forbidding it outside L3 — the field
is not merely unnecessary there, it is meaningless, since scope is
still `project` and the array would claim cross-project evidence the
atom does not have.
- hooks.json: SessionStart declared no timeout and fell back to the
Claude Code default. Pinned to 5s. UserPromptSubmit keeps its 1s
backstop; SessionEnd stays async.
- DESIGN.md 4.1.1: state that the L2 -> L3 merge is lexical. normalize()
collapses whitespace/case/punctuation only, so two projects holding
the same rule in different words never merge. The failure is
one-directional — L3 under-fires, the claim stays live at L2 in each
project — and widening it needs an LLM or a per-user synonym table,
neither of which belongs in v1. Named in the same style as 4.2.1's
contradiction-detector limits.
Verified: assets/validate_examples.py.txt 57 checks / 0 failures; all
three schema examples still validate; an L1 atom carrying
promoted_from_projects is now rejected; derive_counters.py --check
passes unchanged (363 skills, 89 plugins, 663 tools).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Third PR-review round on #948. All three reproduced first.
1. HIGH — every realistic HTML5 document produced zero blocks. meta, link and
base are void elements: html.parser fires handle_starttag for them but never
a matching handle_endtag. They were also in DROP_TAGS, so each bare
`<meta charset>` incremented self._skip permanently and every subsequent
starttag/endtag/data callback inside <body> hit the skip guard. Result:
empty out, empty blocks, "No reviewable blocks found", exit 2.
The documented landing-page use case therefore did not work at all. It
survived three review rounds because every HTML fixture I wrote used only
<title>/<style> in head — the sanitizer test included. Void drop-tags no
longer touch the counter.
--sample now builds BOTH fixtures (Markdown + a full DOCTYPE HTML5 doc with
bare meta/link), asserts the expected block count for each, and exits 2 on
regression, so this cannot come back silently. It also writes to a temp dir
instead of cwd — the same class of mistake that leaked a stray artifact into
an earlier commit.
2. MEDIUM — xlink:href bypassed the URL allowlist. SVG anchors still honour it,
so `<svg><a xlink:href="javascript:alert(1)">` survived the hardening added
one commit earlier. Added with xlink:role and xlink:arcrole.
3. MEDIUM — status did not mirror close. It inspected only blocking_open, so a
round with no named reviewer reported exit 0 while close refused on G3 —
directly contradicting the exit-code contract the docstring advertises.
Both now call a shared gate_refusals(), so they cannot drift: verified they
agree on 2 (G3 open) and on 0 (clean round). status also prints which rules
would refuse rather than just a count.
Re-verified: derive_counters --check, check_plugin_json --all, checklist 6/6
PASS, description validator PASS, all three scripts --help/--sample green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Twenty-first review round. One fresh finding, and its sharp half is the
round-20 failure mode again in a new place.
validate_examples.py.txt derived BASE as dirname(dirname(__file__)) —
correct only at its current depth (assets/, two below the plugin root).
§10.1 moves it to skills/agent-memory/scripts/, four below, where that
form lands on the SKILL root instead. Verified by simulating both
layouts rather than reasoning about it:
- SCHEMA still resolved, by coincidence (assets/ and scripts/ become
siblings under the skill).
- DESIGN resolved to a path that does not exist and raised.
- The repo-root CLAUDE.md size check resolved to a nonexistent path and
was SKIPPED by its own `if os.path.exists(root)` guard — so the 84 KB
claim would stop being verified with the suite still printing green.
That last one is what makes this worth more than a path fix. Round 20 was
a whitelist that made a checker excuse the author's defect; this is a
guard that makes a checker excuse its own inability to run. Both report
success while checking nothing. A check that cannot locate its input has
FAILED, not passed, so the exists() guard is now an assertion.
BASE is anchored on a marker (walk up to DESIGN.md) instead of a fixed
dirname count, so the move cannot quietly disable anything. The repo root
is found by predicate — the directory holding BOTH CLAUDE.md and
scripts/derive_counters.py — because `.claude-plugin` alone is not a
repo-root marker: engineering/ carries one too, and anchoring on it lands
one level short. My first attempt did exactly that and the new assertion
caught it, which is the argument for the assertion.
Verified in three layouts: current (57 checks, 0 failures), the simulated
post-§10.1 move with links updated (57 checks, 0 failures — identical
count, so nothing is dropped by the move), and an orphaned copy with no
repo root above it (fails loudly, exit 1).
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Twentieth review round. One real defect, and the worse half is mine.
examples[0] embedded a $comment inside the atom object. `examples` entries
are INSTANCE data, and the schema declares additionalProperties: false
with no $comment in properties — so under any real validator (jsonschema,
ajv) that fixture fails the very schema it exists to demonstrate. The
distinction that makes this a bug rather than a style choice: $comment is
a SCHEMA keyword. It is legal at schema top level and inside the allOf
branches — where it still lives, untouched — and illegal in an instance.
The worse half: validate_examples.py.txt computed its allowed-property set
as `set(schema["properties"]) | {"$comment"}`. I wrote that whitelist to
make my own annotation pass. That is not a missing check; it is a check
deliberately weakened to tolerate the author's defect, which is strictly
worse than the round-8 happy-path gap — that one failed to look, this one
looked and was told to ignore what it saw. It also falsified the PR's own
testing claim, which said the examples validate against
additionalProperties when what they validated against was a checker built
to excuse them.
Fixed by removing the annotation from the fixture (option b) rather than
widening the schema, because instance data must be valid instance data.
The rationale it carried — why a third, L1 fixture exists at all: it is
the only thing exercising the L1 branch of the back-pointer conditional,
the one with PII consequences — now lives in §3.1 prose, where an
annotation about the fixtures belongs.
The workaround is gone from the checker, with a comment recording why it
must not come back. Verified both directions: re-injecting a $comment into
an example now fails "declares no unknown fields" (exit 1), and an
independent pass confirms all three fixtures carry zero undeclared keys.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Nineteenth review round, no blocking issues. Two acted on.
1. §4.1.1's "age >= 30 days" gate and §4.3's demotion both key off
promoted_at, but nothing required it — so an atom could reach L2
without recording when, never satisfy the age test, and sit
un-promotable forever without anything flagging it. Exactly the
silent-skip mode that made `redacted` required last round.
Now conditionally required at L2/L3. Deliberately NOT forbidden at L1,
which the reviewer's phrasing already got right and which matters more
than it looks: §4.3 demotes an expired L2 claim BACK to L1, and that
atom legitimately keeps the promoted_at from its earlier life —
forbidding it there would make every demoted atom invalid. The
asymmetry is documented in the field description rather than left for
someone to rediscover.
Added to the committed checker too, not just the schema (56 checks now,
was 54): a schema conditional nothing exercises is the same class of
gap as the rule it fixes. Verified — deleting promoted_at from the L2
fixture fails "committed tier records promoted_at", exit 1.
2. §8's citations were unverifiable to a reviewer without the upstream
repo. They are now checkable: the clone was read at commit
b44c6db5f5b1a011eed645efb1949840f99f961a (2026-08-05, tip of main at
inspection), and the Chinese source comment quoted in point 1 is
verbatim from MemoryProxy/src/agent-adapters/claude-code.ts lines 2-6.
Pinning the sha means the citation stays checkable even after upstream
moves.
Not acted on: the root CLAUDE.md pointer (same answer as last round — it
advertises the convention before it is ruled on, so it lands with the
maintainer's yes), and blessing the .py.txt parking pattern, which is the
same convention call and belongs in the same decision.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
README and SKILL.md were corrected in 70c908a; the manifest still carried the
flat 'zero network requests'. The page makes no request of its own, but a
reviewed HTML artifact's own https: assets do load. Also notes the HTML
sanitization added in the same commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Eighteenth review round, no correctness bugs found. Two items acted on.
1. §6 rule 1 calls redaction "non-negotiable ... before any write", but
`redacted` was optional in the schema — so an atom that skipped the
pass entirely was schema-VALID, which is precisely the state the rule
forbids. The reviewer's framing is right: an invariant the schema
does not carry is a promise, not a guarantee.
`redacted` is now the 13th unconditionally required field. All four
fixtures already set it, so the rule is enforced immediately rather
than aspirationally, and memory_promote.py can now CHECK that
redaction ran instead of trusting every writer to remember. §3.1
separates it from the genuinely later-stage fields (contested,
contested_by, promoted_at) and says why it differs: those are set by
contradiction handling and promotion, whereas redaction has already
run by the time any atom exists on disk.
2. validate_examples.py.txt's published_normalize() did a bare
re.search(...).group(0) — a moved or renamed fence would raise a raw
AttributeError from inside a checker whose entire job is to fail
legibly. Now three explicit SystemExit paths (fence missing, fence
present but not valid Python, block ran but defined no normalize),
each naming the cause and the fix. Verified by renaming the function:
the checker prints the guidance and exits 1 rather than tracebacking.
Both regressions confirmed caught: dropping `redacted` from a fixture now
fails "has all required fields" (exit 1); the clean tree still passes 54
checks (exit 0).
Items 3 and 4 not acted on. 3 is the maintainer's convention call, now
raised by six reviewers. 4 (a pointer in root CLAUDE.md's Unreleased
section) is deliberately coupled to it — advertising this folder in the
repo's headline changelog would pre-empt the very decision I have been
declining to settle by commit, and would need reverting if the ruling
goes the other way.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Second PR-review round on #948. All four reproduced before fixing.
1. HIGH — reviewed HTML executed in the review page. BlockTagger re-emitted
attributes verbatim, escaping values but never filtering attribute names or
URL schemes. The Markdown path has had _safe_href scheme-allowlisting all
along; the HTML path had nothing. Reproduced: a draft.html containing
`<img src=x onerror=...>`, `<a href="javascript:alert(1)">` and an <iframe>
passed straight into the page a reviewer opens — and reviewing a landing-page
draft is a documented use of this skill.
sanitize_attrs() drops on* handlers, srcdoc and srcset, and runs href/src/
action/formaction/poster/cite/background through the scheme allowlist.
_safe_href now strips control characters before reading the scheme (so
`java\tscript:` cannot smuggle one) and allows data:image only for image
attributes. DROP_TAGS removes iframe/object/embed/frame/base/applet as well
as script/style/head/link/meta. Verified: handlers, javascript: (plain and
tab-smuggled), and iframes all gone; https links and relative images kept.
2. MEDIUM — verify_quotes compared rendered text against raw markup. A quote
comes from window.getSelection(), which is what the browser rendered, so
selecting a sentence containing **bold**, `code` or a link never matched the
raw source. G7 had just made that blocking, so this refused legitimate
closes. Now matched against raw OR a rendered-text projection (inline markup
stripped for Markdown, tags stripped and entities unescaped for HTML). A
fabricated quote is still caught — verified both directions.
3. MEDIUM — state["waiver"] was never cleared, so after waived-close → reopen →
a clean round, close still printed the old waiver reason. For a tool whose
premise is an honest record of what was actually reviewed and waived, that is
its own integrity bug. Cleared whenever a close passes with zero refusals.
4. LOW — status returned 4 for both "no sidecar yet" and "collected, blockers
open". The blocked case now returns 2, matching close, so an agent can branch
on the exit code alone: 0 clear, 2 blocked, 3 collect, 4 nothing yet.
Also corrected an over-broad claim of my own: the page makes no network request
of its own, but a reviewed HTML artifact's own https: assets do load, as they
must for the review to be faithful. README and SKILL.md now say that precisely.
Re-verified: derive_counters --check, check_plugin_json --all, checklist 6/6
PASS, description validator PASS, all three scripts --help/--sample green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Seventeenth review round, nothing blocking. One suggestion acted on, two
already-open items left open.
The reviewer's point on automating the example<->schema check is right,
and the sharpest version of it is one I had not weighed when declining
this twice on counter grounds: my verification logic has lived only in
throwaway shell heredocs, so it dies with the session that wrote it. The
next person editing this spec inherits nothing. Drift between DESIGN.md,
the schema and the fixtures has been the DOMINANT defect class across the
review — required-field drift, a tier the examples never exercised, ids
that stopped reproducing, headings inserted out of order, a confidence
value contradicting its own lifecycle narrative. Losing the checks that
found those is the real cost.
Added assets/validate_examples.py.txt — stdlib-only, 54 checks in six
families. Two properties make it more than a linter:
1. It EXECUTES the normalize() that DESIGN.md publishes rather than
reimplementing it, so doc and fixtures cannot silently disagree.
2. It is tested against INJECTED regressions, not just the happy path.
Four deliberate defects — an unstripped back-pointer (the OS-username
leak), a broken tier->scope pair, a wrong id, a confidence downgrade
— each make it exit 1; the clean tree exits 0. A checker that only
ever passes proves nothing, which is why the happy-path-only version
of this check missed the round-8 gap.
Parked as .txt, not .py, deliberately: this PR is spec-only and a .py
here is counted by derive_counters.py (measured 663 -> 664), producing a
counted tool belonging to no plugin in a folder that deliberately has no
SKILL.md. New §10.1 records that, names it the FIRST file the
implementation PR should land — before memory_extract.py, since
everything else is written against the contract it guards — and states
the reversal condition: if a spec-stage folder may carry tooling, it
becomes a .py and three counter files move, nothing else.
Suggestions 2 and 3 (the DESIGN.md-only convention; resolving §9.2 before
merge) are maintainer decisions already surfaced in the PR body. Five
reviewers have now independently raised the first.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Sixteenth review round. One real inconsistency, one scoping fix.
The §3.1 atom (atm_961f033d, L1) carries confidence "observed"; the same
id at L2 in the schema carries "stated" — and round 14 explicitly paired
those two as "one atom's lifecycle", so the pairing turned an
undocumented transition into a visible contradiction. Nothing in §4.1 or
§5.3's merge description said confidence could change at all.
This is not cosmetic: confidence selects both the session count (3/2/1)
and the distinct-days exemption, so WHEN it may change decides which gate
an atom is held to. Left unstated, two implementers would reasonably
build different machines.
Resolved by documenting the transition rather than flattening the
examples, because upgrading is correct on the merits — a claim the agent
inferred can later be stated outright or confirmed by a check, and
freezing confidence at extraction would hold the atom to a stricter gate
than its evidence warrants. New §4.1.3: total order observed < stated <
verified; merge takes max(existing, incoming); never downgrades, so a
weak re-observation cannot silently re-impose the slower gate; the gate
re-reads confidence at promotion time, not creation. §5.3's merge step
now lists it alongside observations and sessions.
Verification proves the example pair is a legal upgrade and that the L2
atom clears the gate its own confidence implies, rather than asserting
the prose is consistent.
Also scoped the fast paths to "(L1 → L2 only)" — L2 → L3 is gated on
distinct projects, not session count, so neither shortcut applies there.
Note: the heading-order linter added in round 13 caught me repeating the
round-13 mistake — §4.1.3 was inserted between 4.1.1 and 4.1.2. Fixed
before commit. That is the linter earning its keep one round after being
written.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Both from PR review on #948, both reproduced before fixing.
G7 — a real hole in the skill's core promise. feedback_parser downgrades an
unrecognised severity heading to NIT and records it only as advisory prose in
`problems`, which cmd_close never read. Reproduced: a sidecar with `## BLOKCER`
carrying "No source. Do not ship this." collected as a NIT, and close exited 0 —
a reviewer's genuine blocker lost to a typo. Same gap covered EDIT items with no
`+ after:` line and quotes that do not appear in the target file.
close now refuses (exit 2) while the last collected round carries unresolved
integrity problems. Problems that already have their own rule are filtered via
GATED_ELSEWHERE so G2/G3 are not double-reported. Verified: typo'd severity,
missing EDIT replacement, and quote-not-in-file each refuse; a clean sidecar
still passes; a missing reviewer still reports G3 alone.
Stray artifact — quarterly-plan.review.html was committed at the repo root. It
came from a `review_page_builder.py --sample` run during the post-merge
verification sweep with cwd at the repo root, then got swept up by `git add -A`.
Removed, and .gitignore now covers `*.review.html` + `.human-gate/` so neither
this repo nor a user of the skill re-commits a disposable review page. The
sidecar (<artifact>.review.md) is deliberately NOT ignored — that is the
reviewer's feedback and belongs in git.
G7 documented in the script docstring, SKILL.md, README, the command, plugin.json
(description + derivation_note) and CHANGELOG. Not acted on: the reviewer's note
that cmd_status's success line is terse — they flagged it as "not a real issue"
and the JSON branch already carries blocking_open.
Re-verified: derive_counters --check passes, check_plugin_json --all 90/90,
write-a-skill checklist 6/6 PASS, description validator PASS, all three scripts
--help/--sample green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Fifteenth review round, no correctness findings. Three concrete gaps,
all worth closing before implementation starts.
1. §5.4 said a writer that cannot acquire the lock "gives up and drops
its atoms, logging the loss" — and never said where. That is the one
place in the design where data disappears silently, so an unspecified
destination made the sentence decorative. Pinned to
.memory/errors.log (gitignored, 0600, capped 200 lines), added to the
§6 layout, and explicitly NOT stderr: SessionEnd is async, so its
stderr reaches nobody, which would make "logging the loss" a fiction.
/cs:memory status surfaces recent entries — a log nobody is pointed at
is the same as no log.
2. §10's planned tree moves assets/ under skills/agent-memory/, which
silently breaks two references: DESIGN.md's relative link to the
schema, and the schema's own $id. DESIGN.md stays at the plugin root
(it documents the plugin, not the skill), so the link lengthens rather
than staying put. Both now called out in a table with their post-move
values, matching how every other forward-looking wrinkle in this doc
is handled.
3. Open decision #2 has a repo-wide cost if it resolves toward an LLM
extractor that nobody had priced. Root CLAUDE.md's anti-patterns bullet
reads "one documented, opt-in exception" and names skillopt-sleep by
file; a second LLM-calling script makes that sentence false. The
implementation PR would have to amend that bullet rather than become a
silent second carve-out. Recorded as part of the cost of (b) — it is a
real argument for the rule-based path beyond recall.
Also stated in the Status header why a design doc lives under
engineering/ rather than the gitignored documentation/ folder (nothing
there is visible in a PR), while keeping the "is this a repeatable
pattern" question explicitly open for the maintainer.
Link checking now strips code spans before resolving relative links —
the previous version flagged the illustrative post-move path in item 2's
table as a dead link, which it is not.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
book-to-skill landed in dev while this branch was open. All four conflicts were
counter/registry collisions in the shared headline files — resolved by taking
dev's side, then re-deriving from the tree so both plugins are counted:
skills 363 -> 364 · tools 663 -> 666 · refs 746 -> 749
agents 103 -> 104 · commands 118 -> 119 · plugins 89 -> 90
README engineering row 85 -> 86
Also fixed two merge artifacts: the README engineering row lost its human-gate
mention (dev edited the same row for book-to-skill), and the both-sides CHANGELOG
resolution left an orphaned duplicate fable-goal header at the seam — dev had
retitled the real entry "(previous PR)".
Verified after merge: derive_counters --check passes, check_plugin_json --all 90/90
OK, human-gate 6/6 on the write-a-skill checklist, all three scripts --sample green,
no conflict markers left in the tree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Fourteenth review round, no correctness findings. Three clarity items,
all of which were real double-takes rather than nitpicks.
1. §5.4's 60s stale-break and 5s acquire timeout read as contradictory
("5 < 60, so how does stale-break ever fire?") because the doc never
said they answer different questions. Added a table: 60s is an mtime
AGE test — older than that, break immediately, no waiting; 5s is how
long a writer waits on a lock that is live and younger than 60s. The
stale path is checked first, not gated behind the wait.
2. AGENT_MEMORY_RECALL breaks the naming symmetry its two siblings keep
(they mirror SessionStart/SessionEnd exactly). Recorded why:
AGENT_MEMORY_USERPROMPTSUBMIT is the consistent name and is rejected
on ergonomics, since this is the variable a user reaches for most
often. Marked deliberate so a later round does not "fix" it.
3. atm_961f033d appears at tier L1 in DESIGN.md and tier L2 in the
schema, which reads like copy-paste. It is the atom's lifecycle: id
hashes claim+project with no tier component, so L1->L2 keeps it, and
stability is required because merge-on-re-observation keys on the id.
Writing that callout surfaced a defect in my own first draft of it: I
claimed promotion never mints a new id, but §4.1.1 step 3 does exactly
that at L2->L3, because dropping the project component changes the
hash input. Corrected before commit, and verification now PROVES both
halves by computing them (aid(claim, project) == the L1/L2 id;
aid(claim) != it) rather than asserting the prose is right.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Audits petergyang/human-review and ships a conceptual derivation that fits this
repo's stdlib-only conventions.
Audit (audit/human-review-2026-08/AUDIT.md): upstream is a well-engineered ~5,200
LOC Node app — its own test suite passes 90/90, and its security model (loopback
bind, DNS-rebinding Host check, constant-time token compare, realpath traversal
guard, inert Markdown renderer, 45-min idle shutdown) is better than most
local-server tools. It still does not fit: Node 20 + an npm runtime dependency
fails the same stdlib-only test that kept the heavier skillopt package out in
v2.11.2. Seven findings, three material — F1 (HIGH) unpinned `npx -y` executes a
newly published version on every run; F2 (MED) "do not end your turn" plus
re-poll on timeout with no headless guard or retry cap; F3 (MED) only /api/* is
token-gated.
Also: despite the name it is not a humanizer. This is human approval, not human
voice — no overlap with behuman or content-humanizer.
New plugin engineering/human-gate, three stdlib scripts, no server or socket:
- review_page_builder.py — Markdown/HTML to a single-file anchored review page
with zero network requests (~11 KB, opens over file://). Escapes before
applying inline markup, scheme-allowlists hrefs, drops script/style on HTML
input.
- feedback_parser.py — sidecar to batch.v1 JSON. BLOCKER/MAJOR/MINOR/NIT
(matching md-review) plus EDIT/NOTE/APPROVE. Verifies quotes against the real
file; strips HTML comments so a documented example cannot parse as a real
sign-off.
- human_gate.py — open/status/collect/close/reset with atomic writes and
0700/0600 state. Rules G1-G6 refuse to close on: no collected round, an open
BLOCKER/MAJOR, an unnamed reviewer, a sidecar changed after collection, an
exhausted round cap (exit 5 = escalate), or an undocumented waiver.
Loop discipline deliberately inverts upstream: no blocking poll, a headless
guard, a round cap that escalates. The sidecar is hand-writable Markdown, so the
loop closes over SSH and in CI. The optional bridge to upstream is opt-in and
always version-pinned.
Adds 3 references (7-8 sources each), a batch.v1 schema, a worked example,
cs-human-gate agent, /cs:human-gate command. SKILL.md passes the write-a-skill
6-item checklist 6/6; description validator PASS.
Counters: skills 362->363, tools 644->647, refs 741->744, agents 102->103,
commands 116->117, plugins 88->89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01233Eggb2cjSYf96X6C3pCm
Thirteenth review round. Three structural defects, all introduced by my
own earlier edits rather than present in the original draft.
1. §4.1.2 was placed physically BEFORE §4.1.1 — and §4.1.2's argument
cites the L2→L3 merge as the reason a state is unreachable, so a
reader met the citation before the section defining it. Reordered.
2. §4.1.1 and §4.1.2 were ### (h3), the same level as §4.1 itself,
while §3.1.1/§3.1.2 and §4.2.1 correctly use ####. Both bumped to
####. Both defects date to round 11, where the two sections were
spliced in without reconciling against the document's own structure.
3. "Hashing" was orphaned on its own line, residue from the round-7 edit
that replaced the text around it. Reattached.
The reviewer's framing is the right one: these undercut a document whose
pitch is self-checking rigor. So the fix is not just the three edits —
verification now includes a structural linter that derives expectations
from the numbering itself rather than checking known strings: heading
LEVEL must equal numbering depth + 1, and heading NUMBERS must ascend in
document order. Both would have failed on this state before the fix, and
they cover every section, not the three that happened to break.
Also the sixth round where a check failed on my own assertion rather than
the artifact (backticks in `scope`). Prose checks now normalize markdown
emphasis and code markers alongside case and whitespace, which is the
last of the three ways these assertions have been brittle.
Counters unchanged: 363 / 89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Fourth review on PR #947 reported two functional bugs, explicitly noting it had
not run anything. Both reproduced, and the first is severe.
1. F1 -- the blocking gate -- could be bypassed by a typo.
_check_forgetting_rule() failed only when `rule` was literally
"none"/""/"never", and otherwise inferred PASS from what the rule was *not*.
So anything unrecognized fell through to the PASS branch with an empty
mechanism list. Reproduced:
{"rule": "asdf"} -> F1=PASS "Forgetting is designed: ."
{"rule": "ttl"} (no ttl_days)-> F1=PASS "Forgetting is designed: ."
A misspelling silently passed the one check this entire skill is built
around, and the nonsensical detail string was the only hint.
The check is now allowlist-based: PASS is unreachable unless a concrete
mechanism is actually found (ttl_days > 0, max_records/max_bytes > 0, or a
decay setting). Failure messages now distinguish an unrecognized rule from a
declared-but-unconfigured one, so a typo is never mistaken for a deliberate
decision not to forget. Booleans are rejected where a number is expected,
and ttl_days=0 counts as absent.
Verified across 10 cases: all six bypass variants now FAIL at exit 4, all
four legitimate mechanisms still PASS, and the empty-mechanism string can no
longer be emitted.
2. --print-sample-spec was unreachable on all three scripts that offer it.
The flag sat outside a mutually-exclusive group declared required=True, and
argparse enforces that during parse_args() -- before any of our code runs.
So the flag alone exited 2 with a usage error, which broke the first line of
the workflow SKILL.md documents verbatim:
python scripts/memory_cost_profiler.py --print-sample-spec > workload.json
The group is now required=False with explicit post-parse validation, so
no-args still errors helpfully and names all valid entry points. Verified the
full round-trip on all three: --print-sample-spec > f.json, then feed f.json
back in.
This slipped through because the PR's own checklist covered --help, --sample
and --output json, but never ran --print-sample-spec standalone.
Also removed the identity dict in render() flagged as a nit.
Verified: 4/4 scripts help/sample/json; error paths 3/4/4; all six blocking
gates; checklist 6/6 PASS; security auditor PASS (0 critical, 0 high, 0 info).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Twelfth review round.
1. Section 1 and section 9.1 both claimed root CLAUDE.md is "~40 KB".
It is 85,875 bytes — 84 KB, more than 2x the stated figure. The
argument survives (the real number strengthens the bloat case), but
the error is the embarrassing kind for this doc specifically: section
2 opens "verified by reading the code, not the docs", and this was
eyeballed. Both sites now carry the measured figure with the method
(wc -c) so it is checkable rather than asserted, and verification
recomputes it from the file instead of matching a string.
2. The promotion table read "observations >= 3 across >= 3 distinct
sessions", presenting two conditions where there is one. The schema's
own observations description says the field is informational and the
gate counts sessions; since observations is always >= len(sessions),
the extra clause adds nothing except the risk that an implementer
gates on the wrong field — the exact confusion the sessions-as-a-set
rule exists to prevent. Row now names sessions as the gate and says
explicitly that observations is not it.
Also fifth round running where a verification check failed on my own
assertion rather than the artifact (this time case: "Informational" vs
"informational"). Prose checks now normalize case and whitespace once at
the top rather than being patched per-match.
Counters verified on the merged base: 363 / 89, unchanged by this PR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Third review on PR #947 caught a counter this branch's sync missed.
README.md line 30 read "**Reference docs** — 746 templates, checklists, and
domain-specific knowledge files". The sync pass replaced the string "746
reference guides", which is the phrasing used in CLAUDE.md and
marketplace.json, so this differently-worded line was never matched.
Root cause worth recording: `derive_counters.py --check` does not cover this
line. Verified by setting it to a deliberately wrong 111 — the gate still
passes. So this class of drift is invisible to CI, which is why a reviewer
found it and the automated gate did not. Not fixing the checker here: it is
shared infra, and widening its coverage could surface pre-existing drift in
unrelated rows and turn CI red for reasons that have nothing to do with this
PR. Flagged on the PR for the maintainer instead.
Also swept README for any other stale counter adjacent to counter vocabulary
(skills/tools/references/agents/commands/plugins, old value vs new): no other
occurrences. Badges and both prose lines now read 364 / 667 / 750 / 104 / 120 / 90.
Left untouched: CLAUDE.md line 183, which records book-to-skill's own
"refs 741 -> 746" delta. That is historically correct for that release note
and must not be re-pointed at the current total.
All six blocking gates pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Second automated review on PR #947 found a real bug, verified by execution:
`pick()` looks up `tuple(sorted([winner, runner_up]))`, but two of the four
TIE_BREAKERS keys were authored in the other order, so they could never match:
('flat_rag', 'structured_rag') sorted -> matches
('structured_rag', 'agentic') sorted -> ('agentic', ...) DEAD
('long_context', 'flat_rag') sorted -> ('flat_rag', ...) DEAD
('long_context', 'structured_rag') sorted -> matches
Only 2 of 4 authored questions were reachable. The two dead ones are the
plausible near-ties (structured_rag vs agentic on a high-recall/high-mutability
workload; long_context vs flat_rag under build-budget pressure), so the tool's
most distinctive behaviour — an authored, specific tie-breaking question —
silently degraded to the generic fallback with no error.
Keys are now normalized through sorted() at import, with a collision check that
raises if two entries describe the same pair. Verified by injecting a duplicate
in the reverse order: the guard fires. This repo has no test suite, so the check
runs at import rather than living in a test.
Confirmed by execution, not inspection: all 4 keys reachable, and a constraint
set that ties structured_rag against agentic now returns the authored question
("Does your memory need to correct itself without a human in the loop?")
instead of the fallback.
Also from the review: the SKILL.md workflow block labelled steps 1-4 while the
prose referenced a step 5, so a reader skimming only the code block would not
know it existed. Added a `# 5 - No command.` line and compensated elsewhere to
stay within the checklist's 100-line limit (still 6/6 PASS).
Verified: 4/4 scripts --help/--sample/--output json; all six blocking gates.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Eleventh review round. Two genuine design gaps in the state machine, both
of which would have surfaced mid-implementation.
1. A tier=L1/scope=global atom was schema-legal but could never promote.
The scope field's own description said scope "is assigned at
extraction", so an extractor could mint one; but L1->L2 requires "same
project" and a global atom has no project field, while L2->L3 is a
merge over two or more L2 atoms. Such an atom would sit at L1 until it
expired at 90 days, silently, since nothing flagged it.
Closed by making scope a function of tier rather than a free choice:
L1 and L2 are project, global exists ONLY as the product of the L2->L3
merge. Enforced with a tier/scope conditional so a wrong extractor
fails validation instead of quietly producing orphans. This is also
correct on the merits — whether a claim is global is not knowable at
extraction; it becomes global by holding in a second project, which is
exactly what the merge represents. New section 4.1.2.
2. Section 4.1 gated L1->L2 on "no contradiction open", but 4.2 defined
contradiction handling only at L2/L3 — so the gate referenced a state
nothing produced. New section 4.2.1 defines detection at L1 with two
deterministic rules (explicit negation; same-subject different-value),
run at merge time within a project. States plainly what they do NOT
catch (semantic contradiction needs meaning, not string shape) and why
that is acceptable: the miss is bounded, since 4.2's L2/L3 handling
catches it one tier later and the human gate at adopt is what actually
holds. A narrow detector claiming completeness would be worse than one
that documents its edge.
Also: merged dev (branch was cut before #941) so the "adds nothing
countable" claim is verified against the real base — derive_counters
--check passes at 363 skills / 89 plugins, up from the 362/88 the branch
was cut at. Corrected the stale productivity/handoff evidence in section
10 (7 scripts + 2 hooks = 9 counted tools, not 5 + 2); the underlying
claim that hooks/*.py count was independently verified and is unchanged.
Section 1's skill count is now "360+" so it stops drifting with dev.
Counters verified on the merged base: 363 / 89, unchanged by this PR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Automated review on PR #947 flagged find_duplicates() undercounting. Verified
and fixed, though the diagnosis was incomplete in a way that changes the fix.
`seen.add(j)` only ever recorded the second member of a matching pair, so for
a fully-connected cluster of k mutually-duplicate records len(seen) == k-1.
That number is not meaningless -- it is exactly the count of redundant copies
you could delete. The actual defect is that it was reported under the name
`records_with_a_duplicate`, and rendered as "N records have a near-duplicate",
which describes participants (k), not redundant copies (k-1). Two valid
metrics, one reported under the other's name.
So rather than just adding `seen.add(i)`, both are now computed and reported:
participants -- every record with >= 1 near-duplicate; drives duplicate_share
and the DUPLICATE_BLOATED threshold, matching the wording
redundant -- participants minus one survivor per connected cluster
Clusters are resolved with union-find, not by counting pair endpoints: a
3-record cluster emits pairs (i,j), (i,k), (j,k), so endpoint arithmetic gets
the redundant count wrong. Verified k=2/3/4 give participants=k, redundant=k-1,
and that a 3-cluster plus an unrelated record still gives 3/2.
Sample output moves from "1 record (17%)" to "2 records (33%), of which 1
redundant" -- the reviewer's point that this could tip a real store under the
15% threshold was correct.
Also from the same review:
- Dropped the stale `-> list[dict]` hint (the function returns a tuple); the
return shape is documented in the docstring instead.
- Capped the O(n^2) scan at MAX_DUPLICATE_SCAN=2000 eligible records and made
the tool print how many were skipped, per this repo's no-silent-caps rule --
a quiet cap reads as "no duplicates found".
Verified: 4/4 scripts --help/--sample/--output json; all six blocking gates;
skill checklist 6/6 PASS; real-directory run unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Keeps the branch current with dev (363 skills / 89 plugins) so the
'adds nothing countable' claim is verified against the real base rather
than the stale one the branch was cut from.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
dev moved 8 commits ahead (engineering/book-to-skill), and both branches
touched the same three headline-counter files, so marketplace.json, CLAUDE.md
and README.md all conflicted.
Resolved by taking dev's version of each file wholesale, then re-applying this
branch's additions on top — rather than hand-merging the counter arithmetic,
which is exactly the kind of edit that silently drifts:
- marketplace.json: re-inserted the memory-engineering entry next to
agent-harness (dev's 89 plugins -> 90)
- CLAUDE.md: re-applied the memory-engineering release note above the
fable-goal note
- README.md: engineering-POWERFUL row 85 -> 86 plus the plugin mention
Then re-derived every headline number from the merged tree instead of
assuming my original deltas still held — they did not, since book-to-skill
had already consumed them. True values are now skills 364, tools 667, refs
750, agents 104, commands 120, plugins 90. The release note's own delta line
was rewritten to sit on top of book-to-skill rather than claiming the stale
362->363 range.
Verified on the merged tree: all six blocking gates pass (check_plugin_json,
check_paths, check_dual_publish, smoke_scripts, smoke_json_output,
derive_counters --check), compileall clean, skill checklist still 6/6 PASS,
no conflict markers remain.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Tenth review round, no blocking findings. All three folded in.
1. The examples array held only L2 and L3 atoms, both using the stripped
back-pointer form — so the L1 branch of the tier conditional, the one
the $comment calls out as having PII consequences, was never exercised
by the schema's own self-test. DESIGN.md showed an L1 atom in prose,
but the schema read standalone never demonstrated the prefixed form.
My own verification had the same hole: it hand-evaluated L1 with a
synthetic case rather than a committed fixture, so nothing in the
repo pinned it.
Added a third example at tier L1 carrying the full <cwd-slug> path.
Chose a claim with kind='failure' so it also demonstrates a third
kind (the others were constraint and preference) rather than only
patching the coverage gap. Verification now asserts the examples span
all three tiers and both scope branches, and still rejects both an
unstripped L2 pointer and a prefix-less L1.
2. The L1->L2 row read "≥ 3 distinct sessions, ≥ 2 of them on distinct
days", which invites the wrong reading (2 of which sessions?). The
intent, stated precisely later in 4.1, is that the sessions SPAN two
days. Row now reads "spanning ≥ 2 distinct calendar days (UTC)",
matching the precision used elsewhere.
3. Recorded the stale-lock TOCTOU as a deliberate acceptance rather than
leaving it to be discovered. Two writers can both judge a lock stale;
the consequence is bounded by the design already there — each still
commits via os.replace, so the loser's atoms are lost, not corrupted,
and lost L1 candidates re-observe next session. A true mutex costs
portability (fcntl semantics vary across NFS and Windows) to buy
durability this tier does not need. Noted that it should not be
"fixed" without first showing the loss is observable.
Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Ninth review round, no blocking findings. Three of four folded in; the
fourth is a maintainer call I have deliberately not made.
1. Added section 3.1.2 — the invariants JSON Schema CANNOT enforce,
because it validates one atom at a time and a valid atom does not
imply a valid store: first_seen <= last_seen (no cross-field
comparison), id uniqueness across atoms.jsonl, and per-claim session
uniqueness across records (uniqueItems is within-array only). Each is
assigned an owner in memory_extract.py / memory_promote.py. Verified
the one thing the schema DOES enforce — within-atom sessions
uniqueness, which is what the durability gate actually depends on, so
the boundary is exact rather than hand-waved. Recorded because "the
schema validates" is easy to mistake for "the store is consistent".
2. Section 9.5 now says that if the cold-start measurement forces
outcome (c) — drop UserPromptSubmit — hooks/hooks.json must shrink
with it. Deleting the hook from the design alone would leave the
contract file asserting a hook the design no longer wants; a contract
must not outlive the decision that justified it.
3. Recorded the $id rationale as a $comment in the schema. Three
separate review rounds have now proposed conflicting changes to this
non-functional field (blob-vs-raw, dev-vs-main), so the reasoning is
written down to stop the churn: raw.githubusercontent because
github.com/blob/ serves HTML and breaks $ref dereferencing, and main
because $id identifies the published artifact — a dead link until the
dev -> main promotion lands is accepted deliberately over a URL that
goes stale the moment it does.
Not acted on: whether a DESIGN.md-only folder under a domain is a
pattern to keep or a one-off. Two reviewers have now raised it; it is a
repo-convention decision for the maintainer, not one to settle by
pushing a commit.
Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Eighth review round. Three findings, one of which closes a gap round 7
opened.
1. The tier-dependent back-pointer rule was prose-only. Round 7 argued
hard that stripping the ~/.claude/projects/<cwd-slug>/ prefix at
promotion is "not cosmetic" — an unstripped L2/L3 back-pointer commits
a contributor's OS username to a shared CLAUDE.md. But the schema left
source/first_source as bare {"type":"string"} with a description,
while the two OTHER promotion rules (project<->scope,
promoted_from_projects<->tier) were both machine-enforced
conditionals. The one rule with PII consequences was the one relying
on prose — which contradicts round 7's own framing that a contract
must be self-checking rather than self-asserting.
Added a tier-keyed conditional: at L1, source and first_source must
match ^~/\.claude/projects/[^/]+/...\.jsonl#L[0-9]+$; at L2/L3 they
must match ^[A-Za-z0-9._-]+\.jsonl#L[0-9]+$, which no path-prefixed
value can satisfy. memory_promote.py now fails loudly on a bad
promotion instead of leaking silently.
Verification hand-evaluates the conditional (jsonschema is not
available — stdlib-only repo) against three cases beyond the fixtures:
an unstripped L2 pointer is REJECTED, the stripped form is ACCEPTED,
and a prefix-less L1 is REJECTED so the local form stays
direct-openable. Asserting the rule fires is the point; asserting only
that the fixtures pass would have missed it.
2. Section 4.3 cited section 5.3 for the L3 cap. 5.3 is SessionEnd
capture; the cap ("Budget: 2 KB L3 + 4 KB L2", truncate by last_seen)
is in 5.1, SessionStart read. Corrected, and the check now confirms
the cited section actually contains the budget rather than trusting
the number.
3. The section 3.1.1 insertion split section 3.1's field bullet list,
leaving the `confidence` bullet abutting 3.1.1's closing paragraph
where it read as a stray continuation. Moved 3.1.1 to after the
complete list, so the list stays whole and the back-pointer deep-dive
is its own uninterrupted unit.
Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
CI gate G1 (scripts/check_paths.py) failed with 8 unresolvable references.
Both command files referenced `scripts/<tool>.py` and `assets/<file>` as if
they were relative to the command file, but commands/ sits at the plugin root
while the scripts live under skills/memory-engineering/. SKILL.md was correct
already — it sits inside the skill directory, so its bare `scripts/...` paths
resolve — which is why this only showed up in the two command files.
Rewritten to the plugin-root-relative form
(`skills/memory-engineering/scripts/...`), matching how agent-harness writes
its command paths.
check_paths.py --all now reports 0 findings across 586 files. Also re-ran the
other five blocking gates locally: check_plugin_json, check_dual_publish,
smoke_scripts, smoke_json_output, derive_counters --check — all pass, plus
compileall on the plugin.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Two follow-ups after running the repo's own CI auditors locally:
- Removed `from __future__ import annotations` from all 4 scripts. The repo's
skill_validator.py counts it as an external import (script_tester.py
disagrees and reports the same files as stdlib-only, but the stricter of the
two is what CI surfaces). PEP 585 generics are native on the 3.11 CI runner,
and the single PEP 604 union annotation was the only thing needing the
import — it is now unannotated. Takes this skill from 7 validator errors to
3, matching productivity/weekly-review and better than productivity/fable-goal
(4). The 3 remaining are the legacy v2.0.0 schema checks (min-100-lines, and
Tier/Category/Features/Usage frontmatter+sections) that directly contradict
the Matt Pocock checklist CLAUDE.md declares binding for post-v2.6.0 skills —
every recently-merged skill carries the same ones.
- SKILL.md: steps 4 and 5 used a bold-number style left over from the
compression pass while steps 1-3 had become prose. Reworded to match; still
exactly 100 lines and 6/6 PASS.
Verified after the change: 4/4 scripts pass --help / --sample / --output json;
script_tester 5/5 PASS; security auditor PASS (0 critical, 0 high, 0 info).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Seventh review round. Two real defects, both in the contract file.
1. The back-pointer format contradicted the de-identification rule it is
promoted through. source/first_source are required at EVERY tier, and
the format is ~/.claude/projects/<cwd-slug>/<session>.jsonl#L<line>
where <cwd-slug> is Claude Code's slugification of the ABSOLUTE working
directory — so on a real machine it reads -home-alice-work-... and
embeds the OS username. A strictly-compliant implementation of rule 4
("cite, don't invent") would therefore write a contributor's username
into a shared, git-tracked CLAUDE.md on the first promotion, violating
section 6's de-identification requirement. Rule 4 would have won,
being the more mechanical of the two.
Resolution: the format is now explicitly tier-dependent. L1
(gitignored) keeps the full local path; promotion into L2/L3 strips
the prefix to <session>.jsonl#L<line>. Nothing is lost — session ids
are globally unique, so the prefix is recoverable at read time by
globbing ~/.claude/projects/*/<session>.jsonl. Required at BOTH
promotion boundaries, since L1->L2 is the first crossing into
committed territory.
Round 3's fixture fix masked this: the placeholder read -home-user-,
which looks de-identified only because that machine's username is
literally "user". The L2/L3 fixtures now carry the portable form, so
the examples demonstrate the rule instead of hiding it.
2. Neither worked example id reproduced. atm_7f3a9c21 / atm_b41c8de0
were invented in round 1, before sha256 was pinned in round 3, and
nothing since re-derived them — in the file that calls itself the
contract. Recomputed to atm_961f033d / atm_12cc1dc2, and the exact
normalize() is now pinned in the doc (collapse whitespace, casefold,
strip trailing punctuation — order matters). Verification executes
that published function and re-derives every id, so the contract is
self-checking rather than self-asserting.
Also: stale-lock threshold quantified at 60s (the one unquantified
number in the doc), and the section 10 manifest form recorded as a
follow-up for root CLAUDE.md rather than silently changed here.
Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
New engineering/memory-engineering/ plugin. The repo had no skill for
designing, pricing, or auditing an agent memory system: llm-wiki maintains
one vault, skillopt-sleep runs a consolidation loop, agent-harness bounds a
task loop. This bounds a store.
Four stdlib scripts, one per lens:
- memory_cost_profiler.py — construction vs query split, cost per correct
answer, amortization ratio, construction co-location warning
- memory_architecture_picker.py — scores the four paradigm families,
disqualifies on hard constraints, names the cost the choice makes you pay,
and refuses to pick when the top two tie (exit 2 + tie-breaking question)
- memory_density_auditor.py — classifies records FACT/SKILL/LOG/PROSE, finds
near-duplicates, flags staleness and time-relative wording, scores density;
runs on a real --dir or --jsonl
- forgetting_policy_linter.py — the gate. 8 checks; F1 (explicit forgetting
rule) and F4 (contradictions surfaced, never auto-merged) block at exit 4
Evidence discipline: the four-lens framing is synthesized from @N01ennn's
"How to be a Memory Engineer", but every quantitative claim is re-cited to
the primary source, and two of the article's paraphrases are corrected in the
references rather than propagated — the 47x energy figure is the spread across
ten evaluated systems (not an accuracy-matched pair), and the 97%
first-pass-error figure is Rakuten's named vendor testimonial (not a
controlled study). Per-claim confidence levels throughout.
Three classifier defects found and fixed during the build, each of which would
have produced garbage on a real repo: markdown headings inside fenced code
blocks were splitting records (258 phantom records -> 107 on a real directory);
short fragments matched trivially at 1.00 Jaccard (41 false-positive
duplicates); and signal-less prose was labeled LOG, firing LOG_HEAVY at 74% on
a documentation folder — now its own PROSE class.
Also ships 4 references (7 sources each), a seven-question forcing worksheet,
a combined example spec consumed by all three spec-taking scripts, an F1–F8
policy template, cs-memory-engineer, /cs:memory-engineering and
/cs:forgetting-audit.
Verified: all 4 scripts pass --help / --sample / --output json, stdlib-only,
correct exit codes on error paths; SKILL.md 6/6 PASS on the write-a-skill
checklist; check_plugin_json.py --all and derive_counters.py --check both pass.
Counters: skills 362->363, tools 644->648, refs 741->745, agents 102->103,
commands 116->118, plugins 88->89.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jt1sqt5kQmopyfXu2Hhjnv
Sixth review round, one substantive nit.
Section 3.1 opened "Every field is mandatory", which is false: 12 of the
18 fields are unconditionally required, and the example directly beneath
it shows two that are not (project is conditional on scope, redacted is
set by a later stage). Left as-is this would push whoever writes
memory_extract.py to over-constrain the extractor — emitting fields at
extraction time that belong to redaction, contradiction handling, or
promotion, and emitting `project` on global-scoped atoms where the schema
forbids it outright.
Replaced with the true count plus an explicit accounting of why each of
the other six is conditional or deferred, and a note that the example
carries project/redacted because of what that particular atom is, not
because either is universal. Verification now cross-checks the prose
against the schema field by field rather than pattern-matching a phrase,
so the two cannot drift apart again.
Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Fifth review round. Three findings, all verified empirically rather than
reasoned about — two were wrong in ways that would have broken the
implementation PR's CI.
1. Section 10 claimed "tools +3", counting only scripts/*.py.
derive_counters.py counts EVERY .py outside repo-root scripts/, so the
three hooks/*.py count too. Verified by adding one file under hooks/
in this tree: python_tools moved 644 -> 645. productivity/handoff
confirms it independently — 5 scripts/ + 2 hooks/ files, documented
repo-wide as "7 stdlib-only Python tools". Corrected to +6, with the
evidence recorded so the implementation PR does not trip
derive_counters.py --check.
2. The planned layout put SKILL.md flat at the plugin root. Every
comparable agents+commands plugin nests it under skills/<name>/ —
skillopt-sleep, write-a-skill, agent-harness, handoff and llm-wiki are
5 for 5, and two of them are already cited in this doc for their hook
and staging patterns, so matching their directory shape too is the
consistent call. Tree corrected, and the plugin.json skills form
pinned to ["./skills/agent-memory"] to match.
3. Section 6 listed .memory/ as gitignored while marking adopted.log
inside it as committed, with no pattern shown. Not a contradiction but
it needed stating, because the obvious spelling does not work: a
directory-level `.memory/` ignore is never descended into, so a `!`
negation cannot re-include anything under it. Verified both spellings
in a scratch repo — `.memory/*` + negation tracks adopted.log,
`.memory/` + negation tracks nothing. Documented the working pattern
and why adopted.log is public by design (it records what already
cleared the L2/L3 bar into CLAUDE.md).
Also scoped the chmod non-negotiable to runtime-created files: git
tracks no POSIX mode beyond the executable bit, so a fresh checkout
materializes adopted.log at the cloner's umask and no in-repo
declaration changes that. Anything whose confidentiality depends on
mode bits must be gitignored, which is now stated as the reason
atoms.jsonl and staged/ are.
Counters unchanged (362 / 88) — still no SKILL.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Fourth review round. Five findings, all valid.
1. Section 4.1.1's L2->L3 merge assigned first_source but never source,
though the schema requires both — so memory_promote.py written against
this contract would have emitted atoms the schema rejects. Same class
as the promoted_from_projects gap from round 3. Merge now sets source
from the contributor with the latest last_seen, which also preserves
the field contract (first_source = oldest, source = newest) across the
merge boundary rather than only within one atom's history.
2. Concurrency was entirely unaddressed. SessionEnd is async and does a
read-modify-write on .memory/atoms.jsonl; two sessions on one repo
(several terminals, or worktrees) interleave and lose writes, and the
recall read can catch a partially-rewritten file. New section 5.4
reuses the repo's existing pattern rather than inventing one, citing
both precedents by line: agent-harness loop_controller.py:54-62 and
skillopt-sleep state.py:77. Writers take an exclusive lock then temp +
os.replace; readers take NO lock, because blocking UserPromptSubmit on
a lock held by an async SessionEnd would blow the 100ms budget for a
hook whose failure mode is meant to be "return nothing" — atomic
replacement is what makes lock-free reads safe. Writers that cannot
acquire within 5s drop their atoms and log it: losing one session's
candidates is recoverable, a wedged SessionEnd is not.
3. The aggregate collision claim was wrong. "Likelier than not across ~30
users" does not follow from a 0.29% per-file rate — 30 files give
8.4%, and even odds needs ~239. Replaced with the correct figures. The
conclusion (widen the id if the cap rises) was unaffected, but the
stated justification was false.
4. Fixtures used the real session id that generated this PR, which
section 6.5 — added last round precisely to stop fixture-realism
violations — forbids. All seven ids are now uniformly synthetic
(01SESSION<X>...), so none can be mistaken for real and the pattern is
assertable.
5. confidence:"verified" is the sharpest form of the extraction risk
section 9.2 only gestured at generally: hardest to assign lexically
(it requires recognising a check actually ran) yet lowest promotion
bar (1 observation, exempt from the distinct-days clause). Leaning
recorded: a rule-based extractor must never assign it — reserve it for
atoms minted by a tool that ran the check and can name it.
Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Third review round. Both findings valid; the first is sharper than the
report framed it.
1. The spec violated its OWN admission policy inside its own examples.
Section 6 requires committed content be "interpreted, de-identified,
non-confidential" — and the fixtures named a repo that appears nowhere
in this public tree and embedded its local transcript path. Two costs:
the section 6 analogy was unverifiable to any reader of this repo, and
a project name that was not ours to publish shipped in a committed
file. Fixtures are committed data; the policy binds them.
Fixed by genericizing the example project and restating the admission
analogy against llm-wiki, which is in this tree and checkable. Added
rule 6.5 making the policy explicitly binding on the spec's own
examples, since the underlying mistake was treating fixture data as
exempt — that is the part that would otherwise recur.
2. The id hash was unspecified. Section 4.1 said hash() without naming a
function, which for Python is actively dangerous: the builtin hash()
is salted per process for str, so ids would differ every run and
merging — the mechanism the whole durability gate rests on — would
silently never fire. Now pinned to stdlib hashlib.sha256 truncated to
8 hex, with the salting hazard called out.
Also replaced the unstated 32-bit id-space assumption with arithmetic:
birthday collision is 0.0029% at the 500-atom cap, 0.29% at 5000, so
raising the cap requires widening the id. A collision silently merges
two unrelated claims' durability counters, which is the same failure
project-scoping was added to prevent.
Verification now asserts fixtures carry no unknown project slugs, and
recomputes the collision table rather than trusting the numbers in prose.
Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Second review round. Two findings were real schema bugs that would have
corrupted promotion logic once memory_promote.py was written against it.
1. The schema could not represent the L2->L3 criterion it exists to gate.
Section 4.1 requires a claim hold at L2 in >= 2 distinct projects, but
`project` is a single string and the scope conditional FORBIDS it once
scope flips to "global" — so the multi-project evidence was discarded
at exactly the moment it stopped being an eligibility test and became
an audit trail. Added `promoted_from_projects`, required at L3 with a
minItems:2 conditional so the rule is enforced by the schema rather
than merely described in prose.
2. Atom identity was not project-scoped. `id` hashed claim text alone, so
two unrelated claims normalizing alike in different repos ("tests must
pass before merge") would collide and merge their `sessions` arrays
across projects — manufacturing false durability, since the L1->L2
gate requires sessions from the SAME project. Now
hash(claim + NUL + project) for project-scoped atoms.
This made a genuinely missing step visible: with project-scoped ids a
claim held in two projects is TWO atoms, so L2->L3 is a merge, not a
flag flip. That step was undocumented anywhere. New section 4.1.1
specifies it — group by the project-free hash, union sessions, sum
observations, min/max the timestamps, record contributors, retain the
contributing L2 atoms as the provenance chain.
3. `source` was a single string overwritten on every merge, so an
"anti-fabrication" field retained only the latest sighting and lost
the evidence that first justified the claim. Added `first_source`,
written once and never overwritten; both are now required.
Also fixed the $id ref dev -> main for a stable identifier. Deliberately
NOT switched to the github.com/blob/ form used by the repo's one other
schema: blob URLs serve HTML, not JSON, so that convention breaks any
tooling that resolves $id. Noted as pre-existing rather than propagated.
Verification now walks every JSON block in DESIGN.md plus the schema
examples, and asserts the L3 conditional is enforced rather than only
documented. Counters unchanged (362 / 88).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Six findings from automated review, all verified against the files before
acting. None architectural; all resolved in place.
1. Latency budget contradicted its own contract. DESIGN.md led with a
"hard 100 ms budget" while hooks.json set "timeout": 1 — the hook
timeout field is in SECONDS, so the contract permitted 10x the stated
budget. Split into two explicitly-named limits: a 100 ms internal
self-budget the script enforces against a monotonic clock, and the 1 s
hook timeout as a wedged-process backstop. States outright that
finishing under 1 s does not satisfy the spec.
2. The 100 ms budget was asserted with no mechanism to reach it. Bounded
the work: .memory/atoms.jsonl capped at 500 atoms with last_seen
eviction, single linear pass, bounded top-5 heap. Added open decision
9.5 requiring the budget be MEASURED before implementation, since
interpreter cold-start is the dominant cost and is not controllable
from inside the script — and naming "drop UserPromptSubmit entirely"
as an acceptable outcome. A recall hook that misses its budget every
prompt is worse than no recall hook.
3. The section 3.1 atom example omitted the required `tier` field, so a
reader could copy an invalid atom out of the doc that is meant to BE
the contract. Added; verification now parses every JSON block in
DESIGN.md, not only the schema's own examples, which is why this
drifted undetected.
4. Session ids were 8 chars in the schema examples and 24 in DESIGN.md.
Normalized to 24 everywhere; check asserts a single length across all
examples.
5. Schema $id was not a resolvable URL (GitHub blob path missing /blob/
<ref>/), which fails silently if tooling ever resolves it for $ref.
Now a raw.githubusercontent.com URL.
6. The "stated" fast path (2 sessions instead of 3) did not say whether
the >= 2-distinct-days clause survived, so one long working day could
have minted an L2 claim. Clause explicitly retained; "verified"
documented as the only exemption.
Counters unchanged (362 skills / 88 plugins) — still no SKILL.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Design spec only — no SKILL.md, no plugin.json, no Python. Repo counters
are deliberately untouched (derive_counters counts skills by SKILL.md).
Derived from an inspection of TencentCloud/TencentDB-Agent-Memory (MIT).
Borrows two design ideas — the L0->L3 memory tiering and the
ownership/visibility model — and rejects its integration mechanism. No
code vendored.
The core idea: flat CLAUDE.md has exactly one injection policy (always,
in full), which causes bloat, staleness, and false permanence. Tiering
splits memory by durability and gives each tier its own retrieval policy:
L0 transcripts never injected, L1 atoms recalled on relevance, L2
injected per-project at SessionStart, L3 always in context under a cap.
Promotion is deterministic and recurrence-based (>= 3 distinct sessions
across >= 2 days for L1->L2), not importance-based, and requires a live
L0 back-pointer — keeping it stdlib-only per the no-LLM-in-scripts rule.
Includes a grounded overlap analysis against existing skills. Notably
skillopt-sleep already implements the L0 reader (harvest.py walks
~/.claude/projects/*/*.jsonl) and the protected-marker-block write; the
delta is tiering, prompt-time recall, and a durability gate. Spec
concludes agent-memory must be a separate self-contained plugin rather
than an extension, since skillopt-sleep is a vendored copy carrying 23
re-vendor deviations, and cross-skill imports are a repo anti-pattern.
Rejects MemoryProxy (ANTHROPIC_BASE_URL interception) on four grounds:
reverse-engineered CC internals, subscription-to-metered billing change,
raw conversation persistence incompatible with the repo's compliance
posture, and zero test coverage.
Files: DESIGN.md, hooks/hooks.json (contract), assets/memory_schema.json.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
Addresses the residual TOCTOU raised in the fourth review. The reviewer called
it non-blocking; it verified as slightly worse than described, and the fix is
small, so it is closed rather than deferred.
The claim checks out: `mkdir(parents=True, exist_ok=True)` does NOT raise on a
symlink-to-directory, because its exists-branch tests `is_dir()`, which follows
symlinks. Demonstrated directly — mkdir succeeded silently on a planted link and
a subsequent write landed in the attacker's directory.
What the review did not note is why the second layer failed to catch it: a file
inside a swapped directory is an ordinary file, not a symlink, so
`_write_private`'s `is_symlink()` check could never see a directory swap. The
artifact-level guard did not back up the directory-level one at all.
Three changes:
- `resolve_workdir()` attempts `mkdir` FIRST and only inspects a path that
already existed, via `os.lstat` — which does not follow the final component.
That removes the check-then-create ordering.
- `open_workdir()` pins the directory with `O_NOFOLLOW|O_DIRECTORY`, and both
artifacts are written through that descriptor. An fd names an inode, so a
rename or symlink swap of the path afterwards cannot redirect the write.
- `_write_private()` creates with `O_CREAT|O_EXCL|O_NOFOLLOW` at mode 0600 —
no check-then-act window at all. An artifact from a previous run into the same
--workdir is unlinked first; unlink removes the link, never its target.
Verified against a live race: pin the directory, rename it away, plant a symlink
to an attacker directory, then write — data lands in the pinned inode, attacker
directory stays empty. Also verified a pre-planted `full_text.txt -> victim`
symlink leaves the victim's content intact and is replaced by a 0600 file we own,
and that re-running into the same --workdir still succeeds.
Degrades to the previous path-based checks where `dir_fd`/`O_NOFOLLOW` are
unavailable (Windows).
Recorded as deviation 25. Full regression re-run: EPUB bomb, EPUB entity,
extensionless sniff bomb, DOCX bomb, emitter symlink, rights gate and the
estimator path check all still refuse; a clean EPUB still extracts. All gates
green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zu9Gmm9S78c2t3kDLnpPX
Read the skill as a skill rather than as code, which the previous three review
rounds had not done. Four findings, all now fixed and verified.
1. The documented quick-start did not run. SKILL.md's copy-paste block referenced
$WORKDIR and $SKILLS_HOME without ever assigning them, so following it
literally produced a FileNotFoundError traceback at step 2. Both are now real
assignments, and all five steps were executed verbatim end to end as a check.
The plugin README's block had the same defect and is fixed the same way. A
quick-start that does not run is the worst kind of doc bug: it is the part a
reader trusts most.
2. A gate tool reported success for a path that was not there.
`token_budget_estimator.py --skill-dir <typo>` produced a complete,
plausible-looking budget audit — every row "missing", every cap satisfied,
exit 0 — which reads as a pass. It now refuses a missing directory, a
non-directory, and a directory with no SKILL.md (exit 2). `--full-text
<missing>` raised a bare traceback and now refuses cleanly. The other three
tools already validated their inputs; this one was the outlier.
3. Three upstream artifacts cleaned, one of them load-bearing. epub.py's
`except (KeyError, Exception)` is simply `except Exception` — it swallowed
everything including the size refusal `safe_read()` now raises, quietly
disarming deviation 17 at that call site. Narrowed so ExtractionError
propagates and only genuine parse failures fall through to the .opf glob.
utils.py emitted a dynamic {pages_label: pages} key beside a literal "pages",
colliding whenever the label was "pages"; the alias is now conditional. A
stray artifact word removed from a pdf.py comment.
4. `tool | head` no longer tracebacks. Observed once on the emitter (racy on
flush timing, 0/20 on retry) — all four CLIs now exit 141 quietly, the
standard SIGPIPE convention.
Token cost re-measured: SKILL.md 2,256 tokens resident (229 lines), references
10,216 on demand. Healthy against the ~5k practical ceiling for a resident body.
Full security regression re-run after the changes: EPUB bomb, EPUB entity,
extensionless sniff bomb, DOCX bomb, planted workdir symlink, emitter symlink
and the rights gate all still refuse; a clean EPUB still extracts.
Recorded as deviations 21-24; count synced across plugin.json, CLAUDE.md and
CHANGELOG. All gates green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zu9Gmm9S78c2t3kDLnpPX
Addresses the third automated review on PR #941.
[High] The magic-byte sniffing path bypassed the zip-bomb budget it was built
to enforce. extract_single_file() reads a `mimetype` member with a bare
zf.read() when the extension is unrecognized — the earliest attacker-controlled
point in the pipeline, running before a format is chosen and before any check in
zip_safety.py. zip_safety.py's own docstring claims "every read goes through
safe_read()"; this one did not, which makes it a documentation defect as much as
a security one. Now routed through safe_read(). Its ExtractionError sits outside
the surrounding except tuple on purpose, so a bomb reports as a bomb rather than
as a generic unsupported format.
Verified: a 200 MB / 1029x fixture with no file extension is refused at ~15 MB
peak RSS instead of being decompressed.
[Medium] --author / --author-url never reached the printed marketplace entry.
_plugin_manifest() threaded them correctly into the emitted plugin.json, but
_marketplace_entry() took no author parameter and hardcoded one name — so the
snippet whose entire purpose is preventing hand-edit mistakes contradicted the
manifest sitting next to it for anyone but the default author. Threaded through.
Verified: --author "Jane Doe" now appears in both.
[Low] Narrow TOCTOU between _assert_no_symlinks() and copytree. copytree already
runs with symlinks=True, so a link planted in that window is copied as a link
rather than dereferenced — no content leak. Now fully closed: the emitted tree
is re-walked after the copy, and the package is deleted rather than shipped if
any link appeared.
Verified with a monkeypatched guard that plants a symlink immediately after the
check passes: refused, package removed, secret content absent.
[Nit] plugin.json asserted "license": "MIT" unconditionally, with the "MIT
covers the converter, not the compiled content" caveat living only in README
prose. Added source.license_scope stating it in the manifest, so a tool reading
only the manifest sees the distinction, plus a code comment at the assignment.
Recorded as deviations 19 and 20; count synced across plugin.json, CLAUDE.md
and CHANGELOG.
All gates green: compileall, check_paths --all, check_dual_publish,
smoke_scripts (0 failed), derive_counters --check, check_plugin_json --all
(0 FAIL). All four CLIs pass --help / --sample.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zu9Gmm9S78c2t3kDLnpPX
Addresses the second automated review on PR #941. All three code findings
verified against the actual behaviour, not just patched.
[Medium] shutil.copytree dereferenced symlinks the validator never saw. The
validator checks SKILL.md, the three supporting files and chapters/*.md; the
copy then followed a link anywhere else in the tree (assets/, any subdirectory)
and baked the target's real content into a package that can go out as
--distribution shareable. _assert_no_symlinks() now walks the whole tree and
refuses, and runs BEFORE the validation branch so --skip-validation cannot
bypass it. copytree also passes symlinks=True so loosening that check later
cannot silently reintroduce dereferencing.
Verified: a symlink in assets/ pointing at a secret file is refused both with
and without --skip-validation, the secret never lands in a package, and a clean
tree still emits.
[Medium] The DOCX XXE/entity guard did not extend to EPUB's ebooklib path.
Upstream hardened DOCX only. EPUB is the same zip-of-XML shape and ebooklib —
one of the packages this skill recommends installing — parsed container.xml,
the OPF and content docs with no equivalent pre-check. The guard moved to a new
book_to_skill/zip_safety.py and now runs for both formats.
Verified: an EPUB whose OPF declares an entity is refused; a clean EPUB still
extracts and detects its chapter.
[Low] No size cap before decompressing zip members. Every archive read now goes
through safe_read(), which checks the declared uncompressed size and the
compression ratio against the central directory before decompressing, and
charges actual bytes against a per-archive budget so a lying directory cannot
get past it either.
Verified: a 200 MB / 1029x bomb is refused at ~14 MB peak RSS instead of being
materialized.
[Low] The PR body's "12 numbered items" was stale against README's list. Fixed
in the PR description; the in-repo count is synced to 18 across plugin.json,
CLAUDE.md and CHANGELOG.
Recorded as deviations 17 and 18. Counters: tools 662 -> 663 (zip_safety.py);
that module is allowlisted in smoke_exceptions.txt like its siblings.
All gates green: compileall, check_paths --all, check_dual_publish,
smoke_scripts (0 failed), derive_counters --check, check_plugin_json --all
(0 FAIL). Security auditor unchanged at 0 critical / 4 high.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zu9Gmm9S78c2t3kDLnpPX
Addresses the automated review on PR #941.
Security (the one item flagged as wanted-before-merge): upstream defaults the
extraction workdir to a fixed `<tempdir>/book_skill_work`. On a shared host that
is CWE-377/CWE-59 — any local user can pre-create the directory in a
world-writable /tmp (the sticky bit prevents deletion, not creation) and plant a
symlink named full_text.txt or metadata.json pointing at a file the victim can
write, because Path.write_text follows symlinks. Two concurrent runs also
silently clobber each other.
- Default workdir is now a fresh `tempfile.mkdtemp(prefix="book_skill_work_")`:
unpredictable name, 0700 by construction, never shared with a concurrent run.
The path is printed and carried in metadata.json's `output_text`.
- Artifacts are written 0600, and each write refuses a symlink at the target.
- An explicit --workdir / BOOK_SKILL_WORKDIR is still honoured, but is
symlink-refused, created 0700, and chmod-tightened if it already exists.
- parsers/calibre.py no longer writes its ebook-convert scratch file to the
shared directory. That also fixes a real bug the review did not name: it read
a module-level OUTPUT_DIR constant, so the scratch file ignored --workdir
entirely and escaped the directory the caller asked for.
Verified: default workdir 0700 with 0600 artifacts and a per-invocation name;
two runs get distinct directories; a 777 --workdir is tightened to 700; a
symlinked workdir is refused; and a planted `full_text.txt -> victim` symlink is
refused with the victim file left untouched.
Also from the review:
- book_skill_validator.py and token_budget_estimator.py restated the same
BUDGETS dict. Both now import SKILL_FILE_BUDGETS / CHAPTER_TOKEN_CEILING from
book_to_skill/config.py so the two gating tools cannot drift.
- Corrected the smoke_exceptions.txt rationale: the list is "modules the G8
probe trips on", not "modules that aren't CLIs". config.py, exceptions.py,
sanitize.py, parsers/__init__.py, parsers/pdf.py and parsers/text.py are
equally not CLIs and pass only because they have no argv handling.
Recorded as deviations 15 and 16; count synced in plugin.json, CLAUDE.md and
CHANGELOG. Docs updated: the workdir path is now read from the tool's output
rather than hardcoded.
All gates green: compileall, check_paths --all, check_dual_publish,
smoke_scripts (0 failed), derive_counters --check, check_plugin_json --all
(0 FAIL). Security auditor unchanged at 0 critical / 4 high (documented).
End-to-end pipeline re-run clean: extract -> verdict -> validate -> emit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zu9Gmm9S78c2t3kDLnpPX
CI gate G1 (check_paths.py) failed: the agent's tool table referenced
`scripts/<tool>.py`, which resolves relative to the agent's own folder, not the
skill's. Now uses `../skills/book-to-skill/scripts/...` like cs-skill-author.
Two more issues found running the full gate set locally:
- Renamed `parsers/html.py` -> `parsers/html_text.py`. A module named `html.py`
shadows the stdlib `html` package whenever its own directory lands on
sys.path[0], and `import html.parser` then fails with "'html' is not a
package". Renaming removes the hazard rather than documenting it; two import
lines changed. Verified: HTML extraction still detects chapters, emits block
boundaries, and tab-joins table cells.
- Registered the eight vendored library modules in scripts/smoke_exceptions.txt.
They are imported as `book_to_skill.*`, never run as CLIs, so gate G8's
`--help` probe can only ever fail on them. The four real entry points are
smoke-tested normally and pass.
Recorded as deviations 13 and 14 in the plugin README; count synced in
plugin.json, CLAUDE.md and CHANGELOG.
All blocking gates green locally: compileall, check_plugin_json --all (89 OK),
check_paths --all (0 findings), check_dual_publish (0 drift), smoke_scripts
(0 failed), derive_counters --check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zu9Gmm9S78c2t3kDLnpPX
Derived from virgiliojr94/book-to-skill (MIT). Compiles a book, docs folder, or
spec collection (PDF, EPUB, DOCX, HTML, Markdown, RST, AsciiDoc, RTF, MOBI/AZW)
into an agent skill: a resident master SKILL.md (core frameworks + chapter index
+ topic index, capped at 4k tokens) plus on-demand chapter files, a glossary, a
patterns file, and a decision cheatsheet.
The extraction library (scripts/book_to_skill/, 12 modules incl. 7 per-format
parsers) is vendored close to verbatim and keeps upstream's format chains,
chapter detection across Latin/Roman/Chinese/Thai/Korean heading styles,
invisible-Unicode (Trojan Source) sanitization, and the DOCX entity guard.
12 numbered deviations recorded in the plugin README (authoritative list):
- No implicit installs: --install-missing defaults to `report`, printing the pip
command and using the stdlib fallback, where upstream prompts on a TTY and
installs into the caller's environment.
- Rights gate: emitting a shareable package refuses without --rights from
public-domain|open-license|internal-docs|author-permission. `fair-use` is
deliberately excluded — a defence, not a licence.
- Validator merged and extended: upstream's two validators become one four-family
gate, adding budget (token caps) and index (dead chapter links, unindexed
chapters, dangling topic refs) — the failure that silently breaks navigation
while the skill still looks complete.
- Folded YAML scalars now parse, so a wrapped description no longer under-reports
its length past the 1024-char cap.
- token_budget_estimator replaces discovery_tax: tiktoken path dropped for one
deterministic estimator, post-flight budget audit added, plus an explicit
worth-converting verdict that says "just read it" below ~3x the compiled size.
- Two PRIV-ESC criticals fixed: upstream install hints contained a literal
`sudo apt install`; they now name the package manager without escalating.
Repo-native addition with no upstream counterpart — Step 11 / /cs:book-to-plugin:
upstream stops at a bare ~/.claude/skills folder this library cannot route to.
skill_plugin_emitter.py wraps a compiled skill as a full plugin package (manifest
+ cs-<slug> agent + /cs:<slug> command + README) and prints the marketplace entry
without editing marketplace.json. Its --force path is guarded against symlinks,
paths outside the destination root, and non-package directories.
Ships 4 stdlib-only tools (all --help/--sample/--output json), 5 references citing
7-8 sources each, 3 asset templates, cs-book-to-skill agent, 2 commands.
Cross-linked into write-a-skill ("author first, compile second").
Regenerated the engineering harness manifest: picked up book-to-skill plus three
skills that had drifted out (minimalist, skillopt-sleep, strict-api), 81 -> 85.
Counters: skills 362 -> 363, tools 644 -> 662, refs 741 -> 746, agents 102 -> 103,
commands 116 -> 118, plugins 88 -> 89 (derive_counters.py --check passes).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zu9Gmm9S78c2t3kDLnpPX
Clears every reference the new G7 lint flags, then makes it blocking so the
class cannot drift back. audit/engineering-agentic-2026-07 marked the
senior-ml-engineer half of this STILL-OPEN.
Deleted rather than updated:
- agent-designer/agent_evaluator.py's _define_cost_benchmarks() held
per-token prices for gpt-4, gpt-3.5-turbo and claude-3 at 2024 rates. The
result was assigned to self.cost_benchmarks and never read by anything, so
the method is gone. Cost analysis uses the cost_usd the caller supplies per
execution log, which is the only figure that can be accurate
Made model-agnostic, following the precedent already set by
senior-prompt-engineer/scripts/prompt_optimizer.py's --price-per-mtok:
- senior-ml-engineer SKILL.md and llm_integration_guide.md drop both 2024
price tables and the context-window table (which claimed GPT-4 = 8,192).
calculate_cost() takes rates as parameters; count_tokens() takes an
encoding name, since encodings outlive model IDs and
encoding_for_model() raises KeyError on anything unmapped
- OpenAIProvider loses its default model, so the caller must pass one
- llm-cost-optimizer's routing table names tiers, not models
Pinned to current IDs where an example genuinely needs one: SKILL_PIPELINE.md
(claude-opus-4-6 -> claude-opus-5), prompt-governance (claude-sonnet-4-5 ->
claude-sonnet-5), agent-designer README. Both dual-publish copies of the CAIO
pricing move together, so G4 stays green.
TEAM_STRUCTURE_GUIDE.md documented `prompt_optimizer.py --model gpt-4 --task
classification`. That contract no longer exists: there is no --task flag and
`prompt` is a required positional. Replaced with a runnable invocation.
Four references stay, with reasons in the allowlist: two litreview examples
where the retired model is the subject of the literature being reviewed, one
dated Computer Use citation, and the embedding benchmark already labelled a
2024 snapshot.
Assisted-by: Claude Code:claude-opus-5
audit/newgen-2026-06/00-MASTER.md proposed a "model-name freshness ... regex
deny-list for retired model identifiers" gate. It was never built, which is
why retired IDs and 2024 price tables survived both the June and July 2026
audits and are still in the tree today.
check_model_freshness.py flags references that mislead or break on execution:
script defaults, config values, cost tables keyed on a retired model, and
copy-pasteable CLI examples pinning a retired versioned ID. It distinguishes
these from legitimate dated citations, which stay silent when the line carries
a year, an arXiv ID, or wording like "model card" / "as of" / "historical" —
unless the line also looks like a live default, since
`model: str = "claude-3-opus" # 2024 default` still breaks.
Haiku 4.5 is excluded from the Claude 4 sweep in the patterns rather than
per-file, because claude-haiku-4-5-20251001 is current.
Advisory (continue-on-error) for now: it reports 34 references, 13 of them in
executable positions, and the content fixes land in the next change. Flip to
blocking there. --executable-only prints just the 13 that matter first.
Assisted-by: Claude Code:claude-opus-5
Every existing gate reads frontmatter with a regex or a line scan
(generate-docs.py, sync-codex-skills.py, check_paths.py), so a block that is
not valid YAML passed CI while Claude Code loaded the skill with no metadata.
The 14 files fixed in the previous commit had drifted that way unnoticed.
check_frontmatter.py parses each block with yaml.safe_load and enforces what
Claude Code actually reads:
errors - unparseable YAML, non-mapping frontmatter, missing description,
missing agent name, an agent name containing ':' (refused since
CC 2.1.218), or a missing frontmatter block
warnings - keys outside the current skill/agent frontmatter spec, and a
combined description + when_to_use over the 1536-char cap that
the skill listing truncates at
Warnings are non-blocking so this lands without requiring the wider metadata
cleanup; --strict flips them fatal. The run also tallies the off-spec keys no
runtime reads (license 172, metadata 125, domain 76, compatible_tools 37,
triggers 14), which gives that cleanup a worklist regenerated on every run.
Clean on the current tree: 593 files, 0 errors, 17 warnings.
Assisted-by: Claude Code:claude-opus-5
skill_validator.py required frontmatter fields ["Name", "Tier", "Category",
"Dependencies", "Author", "Version"] and sections ["Name", "Description",
"Features", "Usage", "Examples"]. That is the bold key/value convention used
by its own assets/sample-skill fixture, not YAML frontmatter and not a schema
any real skill has followed. All 362 skills failed both checks identically, so
skill-quality-review.yml has been printing the same two errors on every run
and nobody has acted on them.
- frontmatter now requires name + description, what Claude Code actually
reads, and lists the current optional fields for reference
- the fixed section list becomes a scored recommendation drawn from measured
usage. No heading appears in even 30% of the 361 real SKILL.md files, so a
required list cannot be justified; a miss is now a warning, not an error
- _check_external_imports uses sys.stdlib_module_names instead of a
hand-maintained set. The old set omitted __future__, so every script using
`from __future__ import annotations` was reported as carrying an external
dependency. Real third-party imports are still caught
- the sample-skill fixture gets valid YAML frontmatter, so the reference
implementation stops teaching the schema that caused this
cfo-advisor goes from 86.4 with 2 bogus errors to 95.5 with none. The one
remaining error class, "SKILL.md too short: minimum 100 lines", is left alone:
it contradicts skill_review_checklist_runner.py's under-100-lines check and
SKILL-AUTHORING-STANDARD.md's 10KB cap, and picking a winner belongs with the
wider CONVENTIONS.md reconciliation.
Assisted-by: Claude Code:claude-opus-5
Twelve files had frontmatter that yaml.safe_load rejects, all from the same
cause: an unquoted plain scalar containing ": " inside description. Claude Code
responds by loading the body with empty metadata, so the skill keeps working
via /name but has no description for the model to match against, and the seven
affected agents (where name and description are required) may not load at all.
Eleven are fixed by quoting the existing scalar, leaving the text
byte-identical. design-system carries both ' and " so quoting would defeat the
repo's regex extractors in generate-docs.py and sync-codex-skills.py; its one
colon-space is reworded instead ("Precedence:" -> "Precedence is").
Two agents had no frontmatter at all and were being listed with a placeholder
description; both now declare name and description. tools is deliberately
omitted so they keep inheriting the full set, as before.
Assisted-by: Claude Code:claude-opus-5
- Replace subprocess.run(cmd, shell=True) with shlex.split(cmd, comments=True) +
shell=False. Recipe templates contain unquoted {placeholder} tokens clearly
meant for future parameter substitution; shell=True combined with any future
substitution logic is a straightforward shell command injection vector, since
none of the placeholder positions are quoted. Removing shell=True closes that
class of bug now, before substitution is added, instead of relying on future
contributors to remember to quote/escape interpolated values.
- Require an explicit --yes flag before executing a non-dry-run recipe. Several
recipes are irreversible (gws drive files emptyTrash, gws gmail
users.messages send, gws drive permissions create, ...); previously --run
alone (without --dry-run) executed them immediately with no confirmation
gate.
This document outlines a skill for suggesting and vetting business names that align with cultural origins and market appropriateness. It includes steps for gathering information, running fit checks, suggesting names, and verifying their suitability.
Review round 8 on PR #921 found the third misattribution path: plain
'Name will ...' lines credited any sentence-initial capitalized word
outside a small pronoun list — 'Friday will be a half day' rendered as
a commitment owned by 'Friday' with no ORPHAN flag. Two deterministic
guards added, applied to both the entry pattern and the checkbox
refine pass:
- NON_OWNER_WORDS: pronouns + weekdays + months + common non-name
sentence starters (Today/Tomorrow/Next/Last/There/...)
- STATIVE_CONTINUATIONS: 'will be/need/probably/likely/not/...' reads
as a prediction or status, not a commitment — the line is simply not
an action item
Verified: all three reviewer examples no longer captured; real
commitments (Maria will send..., Alex will confirm...), checkbox
refines, the round-5 committer case, and the round-7 ORPHAN case all
unchanged; --help/--sample clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
Review round 7 gut-check on the MENTION_ANY fallback, resolved in favor
of scoping: '- [ ] follow up with @sam about pricing' no longer credits
sam — a mid-text mention is the task's object, not its owner (the same
misattribution shape as the round-5 bug, via a different entry path).
Head-anchored mentions ('@sam: book the room', '@sam book the room',
'@sam to book the room') still attribute and strip the owner phrase;
object-only lines now flag ORPHAN for a human to assign, per the
skill's never-silently-guess rule. Docstrings updated; unused
MENTION_ANY_RE removed.
Verified across six patterns incl. the round-5 regression case;
--help/--sample clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
Review round 6 on PR #921 found (and execution confirmed) that batch B
was appended directly, bypassing advance(): on tight schedules
(start_b == cursor) two work blocks landed back-to-back with
'Buffers 0min', violating the docstring's own buffer invariant. The
backward pass now reserves BUFFER_MIN whenever batch B would directly
follow a work block: the overflow check includes it (a day that only
fits without the buffer is now correctly refused, exit 2) and a
explicit Buffer event is emitted when it fits.
Also fixes the cosmetic inconsistency in action_item_extractor's
ACTION:/TODO: path — a leading '@owner will/to' inside the captured
text now strips the owner phrase (matching the Name-will branch), so
'ACTION: @sam to book X' renders as 'book X' under sam.
Verified: tight two-batch day refuses by exactly 10 min; +10-min day
fits with visible buffer; deep->batchB and roomy (buffer+flex) days
correct; --help/--sample clean on both scripts; mid-text-mention and
ORPHAN behavior unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
Review round 5 on PR #921 found a real, silent misattribution:
'@maria will ask @sam to review the doc by Friday' credited sam (the
person being asked) instead of maria (the committer), because
extract() ran the _extract_owner_and_text refine pass unconditionally
and MENTION_ANY_RE matched the second @mention. The refine pass now
runs only when no owner was captured at the head of the line — its
original purpose (checkbox/ACTION-prefix lines that start ownerless).
Verified all four paths: owned-@mention keeps the committer, 'Name
will ... @other' prose keeps the committer, checkbox '@sam to ...'
still refines to sam, ownerless lines still flag ORPHAN; --help and
--sample unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
Closes the last open note from PR #921's review loop: usage errors
(malformed --topic, missing/bad flags) now exit 1 like
meeting_cost_calculator, keeping exit codes 0/2/3 exclusively for
verdicts across the 9-script batch. Epilog updated; all five exit
paths re-verified (usage=1, no-outcome=2, overflow=3, sample/help=0).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
- meeting_cost_calculator.py: usage errors now exit 1 instead of 2, so
the ASYNC verdict (exit 2) is unambiguous for exit-code-driven
callers; epilog documents the new code
- focus_session_logger.py: top-level --json now works with --sample
(canned JSON status), matching the uniform --sample --json contract
of the other 8 scripts; subcommand --json unchanged
- time_block_planner.py: deep-only overflow no longer says 'defer
shallow work ... trim the deep blocks' — it now names deep demand as
the cause when there is no shallow work to defer
Verified: usage-err=1 / ASYNC=2 / MEET-sample=0; --sample --json parses
as JSON; subcommand --json regression-checked against a real state
file; deep-only overflow message exercised; --help sweep clean on all
30 productivity scripts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
Per review note on PR #921 — the three new plugins were stamped 2.11.1;
new entries should carry the current release version. plugin.json +
marketplace entries updated; validators and counter check still clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
- agenda_builder.py: parse --topic with right-anchored split so desired
outcomes may contain colons (structured minutes/owner fields split
from the right, title at the first colon); clearer malformed-spec
error text
- focus_session_logger.py / action_item_extractor.py: bare tuple return
annotations -> typing.Tuple for consistency with the files' own style
Verified: --help/--sample exit 0 on all touched scripts; colon-bearing
outcome ('Decide: usage-based vs seat-based') parses and still sorts
decision-first; malformed topic still hard-errors. The reviewer's
time_block_planner lunch/overflow edge case was checked empirically:
batch B is anchored to --end and backward-pass lunch insertion is
guarded by 'lunch + 30 <= start_b', so the day never extends past
--end; the worst case is an explicit 'lunch could not be placed' note.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
Picks up weekly-review, deep-work, meetings — plus previously unsynced
skills (fable-goal, skillopt-sleep, agent-harness, and other strays the
automation had not yet mirrored). Vibe/Hermes/Codebuff home-dir syncs
verified in-session (11 productivity skills discovered each).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQLKzYb1bR2LYqwYUupm5f
Resolves conflicts in CLAUDE.md, README.md, and marketplace.json between
this branch's v2.11.2 skillopt-sleep vendoring and dev's productivity/fable-goal
addition — both narratives are kept, ordered by landing time. Headline
counters (skills/tools/refs/agents/commands/plugins) re-derived from the
merged tree via scripts/derive_counters.py and brought back into agreement
across all three files (--check now passes).
parser.error (exit 2) instead of silently preferring --sample when both
a prompt file and --sample are passed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYh4KrhicuBaS5nRtBeLXK
Sixth review round asked for the CHANGELOG.md entry matching the
established [Unreleased] backfill convention (roast, local-seo-manager).
Mirrors the CLAUDE.md post-v2.11.1 narrative block.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYh4KrhicuBaS5nRtBeLXK
- CLAUDE.md gains an 'Unreleased (post-v2.11.1)' narrative block for
fable-goal so the changelog-of-record covers the addition without
inventing a release version (review round 5 ask; counters in arrow
form to stay clear of derive_counters claim regexes — check passes)
- goal_prompt_self_check.py destination pattern now matches 'the N
links' phrasing ('the \d*\s*links?'); --sample still 6/6, verified
'the 3 links' now matches standalone
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYh4KrhicuBaS5nRtBeLXK
Two independent reviews flagged the missing scripts/ folder against the
productivity-domain convention and the repo's 'Algorithm over AI'
principle. Adds one stdlib tool, goal_prompt_self_check.py, which
mechanically verifies the checkable subset of the SKILL.md step-5
self-check on a drafted /goal prompt: word count in the 150-350 band,
goal line, autonomy directive, verification-loop language,
creative-freedom grant, and delivery destination. Exit 0/1/2; --sample
and --output json supported; judgment calls (deliverable concreteness,
resource verification) explicitly stay with the author.
Smoke-verified: --help OK, --sample passes 6/6, degenerate prompt fails
0/6 with exit 1. SKILL.md references the runner in step 5 (79 lines,
checklist still full PASS). agents/ and assets/ remain intentionally
omitted: a single reasoning pass has nothing to orchestrate and no
templates to ship. Counters: python_tools 602 -> 603.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYh4KrhicuBaS5nRtBeLXK
- plugin.json + marketplace version 2.11.2 → 2.11.1 (tracks repo version
at touch time, matching sibling plugins)
- attribution block clarifies the upstream informal grant is not SPDX and
that the MIT declaration covers only text authored in this repository
- /cs:fable-goal command gains argument-hint frontmatter (roast/handoff
convention)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYh4KrhicuBaS5nRtBeLXK
Improved port of duncan-buildroom/freeskills fable-goal ('free to use and
modify'). Converts a rambling description of a desired outcome into one
polished, copy-paste /goal prompt for a fresh autonomous session.
Improvements over upstream:
- Wrong-tool check (build-now vs write-the-prompt) promoted into the body
- Observable-done principle: every deliverable gets a self-checkable
completion condition
- Six-slot extraction (deliverable/quantity/stakes/tools/quality/destination)
- Per-medium verification defaults (web, CLI, video, written, data, design)
- Six-point pre-delivery self-check
- Anti-pattern list + failure-mode catalog reference with rationale per
anatomy part
- Second worked example in a non-web medium (CLI with dry-run verification)
- /cs:fable-goal command; attribution block in plugin.json
SKILL.md passes the write-a-skill 6-item checklist (full PASS, 77 lines).
Counters trued up via scripts/derive_counters.py (includes pre-existing
engineering drift 81→83): skills 355→358, refs 731→732, commands 109→110,
plugins 83→84.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYh4KrhicuBaS5nRtBeLXK
ceo-advisor and cto-advisor SKILL.md files live under skills/, but the
README links pointed one directory too shallow.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A tenth review pass, after confirming all nine prior rounds of fixes
hold up under independent re-reading, found two more low-severity
gaps and offered to accept a follow-up -- fixed both now for
consistency with how every prior round's findings were handled:
1. schedule had no confirmation gate at the CLI layer. The "confirm
with the user before schedule" safeguard (deviation #15) lived only
in commands/skillopt-sleep.md's agent-facing instructions --
cmd_schedule() called scheduler.schedule() directly and installed a
real crontab entry immediately. Fine for the documented Claude Code
agent workflow (which confirms in chat first), but anyone invoking
`python -m skillopt_sleep schedule` directly bypassed it entirely.
Fixed: schedule now requires --yes; an interactive terminal without
it gets a [y/N] prompt, a non-interactive one refuses outright
(exit 2) pointing at --yes. commands/skillopt-sleep.md updated so
the driving agent passes --yes once it has confirmed with the user
in chat -- that's what --yes records, not a redundant re-prompt
that would hang forever with no TTY inside a non-interactive Bash
tool call.
2. mkdir-then-chmod wasn't atomic in write_staging()/SleepState.save(),
leaving a brief window where a freshly-created sensitive directory
sat at the process's default umask. Fixed: the os.makedirs() calls
creating the state dir, staging leaf dir, and backup dir now pass
mode=0o700 directly, on top of (not instead of) the existing
post-creation chmod calls, which still matter for intermediate
parent dirs and pre-existing directories that mode= doesn't cover.
The equivalent race for individual files was judged a larger
rewrite (every open() call site would need os.open() with an
explicit mode) than this specific low-severity finding warranted --
documented as a known, narrower residual gap rather than silently
claimed as fully closed.
Verified: non-interactive schedule without --yes refuses with exit 2,
with --yes it proceeds to the same scheduler.schedule() call as
before; a synthetic run confirms state dir/state.json/staging leaf
still land at 0700/0600/0700 after the mode= change.
Added as README deviations #22-23 and reconciled the count across all
three documents to 23 (6 cosmetic, 17 safety/hardening) across ten
review rounds -- cross-checked with grep.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
A ninth review pass found scheduler.py's schedule()/unschedule() both
located "this project's" managed cron line via marker not in ln, a
bare substring test, not an exact-match or delimiter-anchored check.
Failure scenario: two projects scheduled where one path is a literal
prefix of the other (e.g. /home/user/app and /home/user/app-v2) --
"# project=/home/user/app" is itself a substring of
"# project=/home/user/app-v2"'s line. Running schedule() or
unschedule() for /home/user/app would silently drop app-v2's cron
entry too, with no error or warning.
harvest.py's _project_matches() (added in this same PR) already gets
this right via delimiter-anchored comparison; scheduler.py's marker
matching didn't follow the same discipline.
Fixed: added _line_matches_project(), anchored on
ln.rstrip().endswith(marker) since the marker is always the last token
of a generated line -- used at both call sites.
Also fixed the related minor nit: install-cron.sh's printed --backend
value was unquoted next to otherwise-quoted ${RUNNER}/${PROJECT} in
its heredoc (low risk since that script only prints a line for the
user to copy, never executes anything itself, but inconsistent with
the quoting discipline everywhere else).
Verified two ways: a standalone reproduction confirmed the bug before
the fix and its absence after, and a full schedule()/unschedule()
round-trip through the actual public API (crontab -l/crontab - swapped
for an in-memory fake) confirmed scheduling both /home/user/app and
/home/user/app-v2, then unscheduling only app, correctly leaves
app-v2's line intact.
Added as README deviations #20-21 and reconciled the count across all
three documents to 21 (6 cosmetic, 15 safety/hardening) across nine
review rounds -- cross-checked with grep.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
An eighth review pass found that seven rounds of redaction fixes were
all file-level (write_staging(), diagnostics.json, state.json's
archive) but __main__.py's cmd_run() reads the same in-memory Report
object and prints EditRecord.content directly to the console, and
_report_payload() serializes it unredacted for --json --
write_staging()'s redaction runs on a copy (report.to_dict()) used
only for the on-disk JSON, it never touches report.edits itself.
Concretely: scheduler.py's cron entry redirects run's stdout/stderr
straight into <project>/.skillopt-sleep/cron.log -- a secret that
leaked into a proposed edit's content would land there in plaintext on
every scheduled night, in a file that (unlike state.json/staged files)
also had no chmod protection.
Fixed:
- _report_payload() and cmd_run()'s plain-text edit printing now run
through redact_secrets(), gated on the same redact_secrets config
flag as everywhere else.
- cmd_harvest()'s debug output (--json, --output <file>, and the
plain-text loop) gets the same treatment -- it prints raw mined
TaskRecord.intent text so a human can review it before setting
"reviewed": true on a --tasks-file, and redaction only strips
secret-shaped substrings, so it doesn't reduce what's reviewable
while closing the same leak path.
- scheduler.py's generated cron line now chmod 700s the .skillopt-sleep
log dir and chmod 600s cron.log itself (best-effort, 2>/dev/null)
before each run appends to it -- that file was never covered by the
state/staging chmod pass in an earlier round.
Verified: a synthetic secret seeded into a task's intent no longer
appears in cmd_run's --json payload, plain-text edit output, or
cmd_harvest's redacted payload; executing the actual generated cron
line end-to-end (not just inspecting the string) produces a 0700 log
dir and 0600 log file on disk.
Added as README deviation #19 and reconciled the count across all
three documents to 19 (5 cosmetic, 14 safety/hardening) across eight
review rounds -- cross-checked with grep.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
A seventh review pass noted plugin.json's top-level description
(930 chars) was noticeably longer than this repo's typical plugin.json
descriptions (median ~600 chars) -- it duplicated detail that
attribution.derivation_note already carries in full. Trimmed to a
single dense paragraph (705 chars) that keeps the essential
what-it-does/safety-model/trigger-phrase content and points to
derivation_note for the full vendoring story, rather than repeating it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
A sixth review pass found sleep.sh and run-sleep.sh still described and
partially resolved against upstream's <repo>/plugins/claude-code/ and
<repo>/plugins/run-sleep.sh layout, not this vendored copy's actual
layout (scripts/ and skillopt_sleep/ as siblings directly under the
plugin root, engineering/skillopt-sleep/). The primary co-located and
repo-relative resolution branches happen to still succeed regardless
(so this was unreachable in normal operation), but the documented
SKILLOPT_SLEEP_REPO and CLAUDE_PLUGIN_ROOT escape hatches would have
silently failed for anyone actually relying on them -- e.g. after a
future re-vendor that missed copying run-sleep.sh into scripts/.
Fixed: sleep.sh's SKILLOPT_SLEEP_REPO branch now checks
$SKILLOPT_SLEEP_REPO/scripts/run-sleep.sh; run-sleep.sh's
CLAUDE_PLUGIN_ROOT branch now checks $CLAUDE_PLUGIN_ROOT/skillopt_sleep
(this repo's actual layout) ahead of the upstream two-levels-up check
(kept for portability if this script is ever reused in that shape
again). Header comments in both files corrected to describe the real
layout instead of upstream's.
Verified both previously-broken fallback branches resolve correctly
when isolated from the co-located script (copied each launcher to a
scratch dir and ran it standalone with only the relevant env var set).
Added as README deviation #18 (cosmetic/hardening) and reconciled the
count across all three documents to 18 (5 cosmetic, 13 safety/
hardening) across six review rounds -- cross-checked with grep.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
A fifth review pass found staging.py's sk-[A-Za-z0-9_-]{10,} secret
pattern -- which matches OpenAI, Anthropic (sk-ant-...), and other
vendors sharing the sk- prefix convention -- was labeled
[REDACTED_OPENAI_KEY] regardless of which vendor's key shape it
actually matched. Redaction itself was unaffected (the text was
scrubbed either way), just a misleading placeholder if a user reads it
literally. Relabeled to [REDACTED_API_KEY].
Added as README deviation #17 (cosmetic) and reconciled the count
across all three documents (README.md's numbered list, plugin.json,
CLAUDE.md) to 17 (4 cosmetic, 13 safety/hardening) across five review
rounds -- cross-checked with grep, not just eyeballed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
A fourth automated review pass on PR #907 found the deviation count had
drifted out of sync across the three places that document it, plus two
more real gaps in the vendored plugin:
1. Deviation count inconsistency: plugin.json and README.md both said
13 (after round 3), but CLAUDE.md's v2.11.2 section said "8
deviations" with an itemized list that didn't map onto the real
13-item README list -- it named a "dead cross-reference to a
non-vendored design doc" as a cosmetic item that was never actually
added as a numbered README deviation (it was fixed in round 3's
commit but never itemized). Fixed: added it as README deviation
#14, updated plugin.json's derivation_note with a note that
README.md's numbered list is the single source of truth if any
summary disagrees again, and rewrote CLAUDE.md's bullet to match.
2. commands/skillopt-sleep.md's action table listed `schedule` as an
ordinary action alongside safe previews (`status`/`dry-run`/`run`),
while its own "Safety reminders" section separately said to point
users at the print-only install-cron.sh instead -- two
uncoordinated stories about the same action. scheduler.schedule()
writes directly to the user's real crontab the moment it runs, with
no confirmation step. Fixed (README deviation #15): "Steps to
follow" now has an explicit step 1 telling the agent to confirm
with the user before running `schedule`; "Safety reminders" no
longer contradicts the action table.
3. state.json (the cross-night task archive) and
.skillopt-sleep/staging/<ts>/'s proposal/report/diagnostics files
contain real harvested session content in plaintext, created via
plain os.makedirs/open(...,"w") -- world-readable-by-default on a
typical multi-user box. Fixed (README deviation #16): state.py and
staging.py now chmod every directory they create to 0700 and every
file they write to 0600 (best-effort). Live CLAUDE.md/SKILL.md
files are intentionally left alone -- those are the user's own,
often-committed files, not new output this plugin introduces.
All three documents (README.md's numbered list, plugin.json's
derivation_note, CLAUDE.md's v2.11.2 section) now agree on 16
deviations (3 cosmetic, 13 safety/hardening) -- verified by grep.
Verified: py_compile clean, mock-backend dry-run still exits 0, a
synthetic test confirms state dir/state.json/staging dir/staging files
land at 0700/0600/0700/0600 respectively after this fix (previously
default umask permissions), all 4 repo CI gates pass locally.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
A third automated review pass on PR #907 found 2 HIGH and 5 further
gaps in the vendored skillopt-sleep plugin, all in the same family as
rounds 1-2 (a safety claim in the docs the code didn't fully back up):
HIGH:
1. state.py's add_to_archive() persisted raw TaskRecord content
(intent/context_excerpt/attempted_solution -- real harvested
prompt/response text) to ~/.skillopt-sleep/state.json indefinitely,
entirely outside the staging dir a user is ever told to review.
Fixed: cycle.py now redacts each task dict before archiving, using
the same redact_enabled flag as everything else.
2. report.md / report.json were never redacted, despite being the two
files a human is told to read FIRST (the SKILL.md's own workflow:
"show the user the exact proposed edits"). EditRecord.content/
.rationale come from the optimizer's reflect() output over real
failing task responses. Fixed: write_staging() now redacts the
rendered report_md string and report.to_dict() before writing.
MEDIUM/LOW:
3. replay_mode: "fresh" (worktree replay) was declared in config but
never implemented anywhere -- only fed a cosmetic report label.
Implementing real worktree isolation was judged too invasive for a
vendored copy; instead cycle.py now warns loudly when it's set to
anything but "mock" rather than silently implying isolation that
isn't happening.
4. backend.py shipped an AzureOpenAIBackend/AzureResponsesBackend pair
with 5 internal-looking Azure endpoint hostnames and a hardcoded
Managed Identity client ID, commented as sourced from "the intern's
avail_api.md" -- reads like leaked internal Microsoft dev infra.
Already unreachable from this plugin's documented mock/claude/
codex/copilot --backend choices and requires deps this repo doesn't
vendor. Removed entirely (classes, constants, get_backend()/
build_backend() dispatch branches, the now-unused azure_endpoint
param); get_backend("azure") now safely falls back to MockBackend.
5. attempt_with_tools() (all three CLI backends) used a task's tool
name both as a shim filename and interpolated unescaped into the
shim's generated shell body. Tool names originate from a
hand-authored --tasks-file's judge.checks[].arg, never validated --
not reachable via harvest/mine today, but a documented user-facing
input. Fixed: a shared _sanitize_tool_names() helper filters to a
safe-identifier allowlist before any name is used as a filename or
shell text.
6. SKILL.md pointed to a design doc path (docs/superpowers/specs/...)
that was deliberately not vendored. Fixed: points to the real
upstream guide URL instead, with a note on why the local path is
absent.
7. CLAUDE.md's "Current Scope" line claimed v2.11.2 but no dated
version section existed for it. Added one matching the repo's
established per-release convention.
All 13 deviations (2 cosmetic, 11 safety/hardening) cross-documented
in plugin.json's derivation_note and README.md's "Deviations from
upstream" + "Safety model" + "What was and wasn't vendored" sections.
Verified: py_compile clean, mock-backend dry-run still exits 0, all 4
repo CI gates pass, and a synthetic test with a real API-key-shaped
secret confirms it appears in NONE of state.json's task archive,
report.md, or report.json after this fix (all three fired positive
signal for the leak before it).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
A second automated review pass on PR #907 confirmed the prior 3 safety
patches and found 3 more small gaps:
1. plugin.json's attribution.derivation_note still asserted "no logic
modified" after the round-1 patches changed staging.py/scheduler.py/
cycle.py/backend.py. Updated to match README.md's deviation log.
2. redact_secrets was declared in config.py's DEFAULTS but never read
anywhere -- write_staging() redacted unconditionally regardless of
the flag (safe direction, but a dead config knob). Wired
cfg.get("redact_secrets", True) through write_staging() and the
diagnostics.json fields; disabling it is honored but never
silently -- fires a loud report note.
3. scheduler.py's _runner_cmd shlex.quote()-d project/logdir/log/repo
root (round-1 fix) but left the `extra` flags parameter raw. Not
exploitable today (it's only ever a hardcoded literal), but closes
the same class of gap defensively via shlex.split + per-token
shlex.quote so a future multi-flag `extra` can't reopen it.
Also applied the reviewer's non-blocking hardening suggestion: adopt()
now re-runs redact_secrets() on staged content before writing to the
live path (read+redact+write instead of a raw shutil.copy2), covering
the case where a staged proposal is hand-edited between `stage` and
`adopt` -- exactly the workflow staging exists to allow.
All 6 deviations now cross-documented in plugin.json's
derivation_note and README.md's "Deviations from upstream" +
"Safety model" sections so re-vendoring can't silently drop them.
Verified: py_compile clean, mock-backend dry-run still exits 0,
synthetic tests confirm both the empty/populated extra-quoting paths
and the redact_secrets on/off report-note behavior, all four repo CI
gates (smoke_scripts, check_plugin_json, check_paths, derive_counters)
pass locally.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
Automated review on PR #907 read the actual module code (not just the
surface docs) and found the vendored plugin's own safety claims didn't
fully match its behavior. Patches applied directly to our vendored copy
(documented as deviations in the plugin README for re-vendor):
1. staging.py: redact_secrets() was applied to diagnostics.json but not
to proposed_SKILL.md/proposed_CLAUDE.md -- the exact files adopt()
copies over the live CLAUDE.md/SKILL.md (with --auto-adopt, with no
human in the loop). A secret pasted into a real debugging session
could have landed in live memory unredacted. Now redacted before
write_staging() persists either file.
2. scheduler.py: the generated crontab line interpolated an arbitrary
project path via unescaped f-string into a command cron runs through
sh -c on every fire. A path containing shell metacharacters could
break out of the quoting. Now shlex.quote()-d.
3. cycle.py: max_tokens_per_night was declared in config.py's DEFAULTS
and budget.py already had a Budget/plan_depth heuristic built for
it, but nothing in the production run_sleep_cycle() path ever read
it -- a real-backend night had no actual token ceiling. Now a
Budget starts right after backend construction (harvest/mine spend
counts too), sizes dream_rollouts down via plan_depth() when
remaining budget is tight, and the report notes when it caps
rollouts or the budget is exhausted -- no silent truncation. This
caps rollout depth per task, not a hard mid-call abort; documented
as a residual limitation in the README.
Also dropped a leftover hardcoded nvm path in backend.py's
resolve_codex_path() (the generic scan a few lines below already
covers it) and added a one-line acknowledgment to CLAUDE.md's
Anti-Patterns list that this plugin's non-mock backends are a
documented, opt-in exception to "no LLM calls in scripts" -- not
precedent for adding LLM calls to analysis/reference skills.
Verified: py_compile clean, mock-backend dry-run still exits 0,
synthetic test confirms dream_rollouts capping actually engages under
a tight budget and is a no-op under the default budget, all repo CI
gates (smoke_scripts, check_plugin_json, check_paths, derive_counters)
still pass.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
.gemini/skills/memory-status/SKILL.md symlink was added in the
previous commit but its skills-index.json entry was missed, so the
skill was discoverable on disk but not listed in the generated index.
Added the entry (mirroring the memory-review one already present) and
bumped total_skills 419 -> 420 to match.
Addresses review feedback on PR #906.
scripts/smoke_scripts.py runs every .py file standalone as
`python3 <file> --help`, but the vendored skillopt_sleep engine is a
package meant to be invoked only via `python -m skillopt_sleep` (already
verified working). Running any single file directly breaks two ways:
1. skillopt_sleep/types.py shadows the stdlib `types` module once the
file's own directory is prepended to sys.path, cascading into
"cannot import name 'GenericAlias'/'asdict' from partially
initialized module" for every sibling that imports
dataclasses/typing.
2. experiments/*.py use absolute `from skillopt_sleep.x import y`
imports that require the package's parent directory on sys.path,
which standalone execution doesn't provide.
Listed all 29 affected files in smoke_exceptions.txt with reasons,
following the existing autoresearch-agent/handoff precedent for
fixed-contract, non-standalone scripts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
Renaming engineering-team/self-improving-agent/skills/{review,status}
to memory-{review,status} left several committed generated mirrors
pointing at now-deleted source paths:
- .codex/skills/review and .gemini/skills/review/SKILL.md were dangling
symlinks; repointed to engineering-team/playwright-pro/skills/review,
the plugin that actually owns the bare "review" name now that
self-improving-agent no longer collides with it.
- Added .codex/skills/memory-review, .codex/skills/memory-status,
.gemini/skills/memory-review/, .gemini/skills/memory-status/
symlinks, and matching entries in both skills-index.json files
(counts bumped accordingly).
- Regenerated the engineering-team agent-harness manifest
(harness_manifest_builder.py --domain engineering-team) so its
path/name/description entries match the renamed skills.
Scoped by hand to just the self-improving-agent review/status entries
rather than a full re-sync, to avoid pulling in unrelated pre-existing
sync drift (skills added in earlier merges that were never synced) and
unrelated non-deterministic name-collision reordering (e.g. "status"
between autoresearch-agent/agenthub, "run" likewise) that a full
regen would otherwise touch. .hermes/ and .vibe/ were verified
unaffected — self-improving-agent is mirrored there only as a single
symlink to the plugin's main skill, not per-sub-skill.
Addresses review feedback on PR #906.
CI's check_paths.py regex-matches any "<word>/SKILL.md" substring as a
relative path reference. The vendored SKILL.md frontmatter said
"CLAUDE.md/SKILL.md" in prose, which the linter misread as an
unresolvable path. Reworded to "CLAUDE.md and SKILL.md" — no behavior
or meaning changed. Documented the deviation in the plugin's README so
it carries forward on re-vendor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
Verbatim copy of the stdlib-only skillopt_sleep engine + Claude Code
plugin surface (skills/hooks/commands/scripts) into
engineering/skillopt-sleep/. Gives a local agent a nightly gated
self-improvement cycle: read-only harvest of past Claude Code session
transcripts -> mine recurring tasks -> offline replay -> held-out-gated
CLAUDE.md/SKILL.md edits -> staged for explicit /skillopt-sleep adopt.
Nothing live changes without that explicit step.
The heavier skillopt training package (needs numpy/openai/azure-* +
hand-labeled benchmarks per task) was deliberately not vendored, since
it optimizes one narrow scoreable task at a time and doesn't fit this
repo's broad domain-expertise skills or no-ML-in-scripts convention.
Attribution preserved in plugin.json + LICENSE + README.md (MIT,
Microsoft Corporation / Yifan Yang), following the same verbatim-vendor
pattern already used for loop-library/. Registered as its own
marketplace plugin; headline counters in README.md/CLAUDE.md/
marketplace.json trued up via scripts/derive_counters.py --check.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TX374i2YGrjNV4Yi3AmaKS
.claude-plugin/marketplace.json (the marketplace registry, not a
generated tool-sync mirror) still advertised /si:review and /si:status
after the memory-review/memory-status rename in the previous commit.
Addresses review feedback on PR #906.
- convert.sh's SKILL.md finder now excludes .claude, .codex, .codex-plugin,
.gemini, .hermes, .vibe, and docs — these are generated/symlinked mirrors
for other tools, not source-of-truth skills. On platforms where git
materializes symlinks as plain text (e.g. Git Bash on Windows), the
mirrored files were being parsed as SKILL.md candidates and failing
frontmatter extraction, flooding the run with "Skipping invalid
frontmatter" warnings (#897).
- Renamed the self-improving-agent (si) plugin's `status` and `review`
skills to `memory-status` and `memory-review` so their bare `name:`
values no longer collide with Claude Code's built-in `/status` and
`/review` commands (#885). Updated all in-plugin references
(CLAUDE.md, README, agents, hooks, references, settings.json,
plugin.json) to the new `/si:memory-status` / `/si:memory-review`
invocations.
Fixes#897 (duplicate of #896), #885.
The demo company is explicitly Brazil-set (Jurisdiction: Brazil), so
preserving the local legal-entity term is more faithful than genericizing
it: 'MEI — Microempreendedor Individual, sole-proprietor entity — to be
defined'. Mirror re-synced; example lint PASS; counter (G3) + dual-publish
gates exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
The '(English)' parenthetical made sense only as the '(PT-BR)' flag on
the original Portuguese description; on an English description it's
redundant. Now matches the marketplace.json / codex-index phrasing
('Company Architect: builds...'). plugin gate exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
- .codex/skills-index.json: reset to dev and re-applied ONLY the two
arquiteto description changes via a JSON round-trip, dropping the
unrelated review/run/status entry reorderings the full regen had pulled
in (diff is now exactly 2 lines, no ambiguous-name churn).
- phase_playbook.md: the data-protection question kept the specific
citation instead of a bare generic — 'data-protection law — e.g. GDPR /
LGPD / CCPA, per jurisdiction' (jurisdiction-aware, not Brazil-only).
- exemplo-bundle/index.md: suggested-next-step no longer says 'finish
problema-solucao.md' (that stub now has content) — points at the real
remaining PHASE-1 gap (manifesto.md) instead.
Mirror identical; example-bundle lint PASS; dual-publish/plugin/counter
gates exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Normalize the usage-line comment gap left misaligned by the earlier
./minha-empresa -> ./my-company rename (path was 3 chars longer).
Cosmetic docstring-only; no behavior change. Mirror re-synced identical.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
The translated skill left two discovery surfaces describing it in Portuguese:
- .claude-plugin/marketplace.json (ClawHub-facing): description rewritten to
English, keywords de-Portuguese-d (drop 'empresa-como-codigo',
'bundle-de-conhecimento', 'pt-br'; add 'company-architect'); slug keyword
'arquiteto-de-empresa' kept for discovery under the preserved slug.
- .codex/skills-index.json (Codex CLI routing): regenerated via
sync-codex-skills.py; both dual-publish entries now carry the English
SKILL.md description + English triggers.
Reverted 3 unrelated symlink retargets the codex sync emitted for ambiguous
skill names (review/run/status) — out of scope for this PR. Both JSON files
validate; plugin + counter gates exit 0; no Portuguese remains in either
registry for this skill.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Final review sweep caught two non-accented residuals a prose-grep misses:
- scaffold_bundle.py slugify() fallback "empresa" -> "company" (a code
default, not a preserved slug — fires only on all-punctuation input)
- example destination path ./minha-empresa -> ./my-company in SKILL.md
and the 3 scripts' usage docstrings, so the translated display name
'My Company' no longer maps to a Portuguese folder in the same line
Mirror re-synced identical; scaffold --sample JSON ok; example-bundle
lint PASS; py_compile clean; dual-publish exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Fixes two cosmetic inconsistencies I introduced in the problema-solucao.md
example stub:
- tags: [fundacao, problema-solucao] -> [foundation, problem-solution]
(was residual Portuguese metadata the prose-grep sweep missed)
- 'Café Aurora' -> 'Aurora Café' to match the 7 other uses across the
example bundle's sibling files
Mirror re-synced; example-bundle lint PASS; dual-publish exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Replaces the inline-code workaround for the example's dangling link with a
real stub concept: adds assets/exemplo-bundle/00-fundacao/problema-solucao.md
(type: Problem-Solution + [ASSUMPTION]) and restores the markdown link from
identidade.md so the example shows the OKF link graph it is meant to teach
(okf_conformance Rule 3), instead of merely silencing the linter. Folder
index lists the new concept. Mirror re-synced; example-bundle lint PASS
(0 problems); dual-publish exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Addresses PR #900 review nit — the versao: frontmatter key stayed
Portuguese in 4 template/example/reference files. No script keys on it
(parse_frontmatter is a generic grabber), so it's a safe cosmetic rename.
Mirror re-synced; example-bundle lint still PASS; dual-publish exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Translates the entire arquiteto-de-empresa (Company Architect) skill from
Brazilian Portuguese to professional English across all 18 files in both
dual-published locations:
- SKILL.md, README, cs-arquiteto agent + command, plugin.json description
- 3 references (okf_conformance, type_vocabulary, phase_playbook)
- 7 assets (templates + exemplo-bundle example)
- 3 stdlib scripts (scaffold_bundle, okf_linter, index_generator):
docstrings, argparse help, printed strings, finding-rule slugs
Consistency preserved end-to-end:
- Controlled OKF vocabulary translated (Fundação->Foundation, etc.)
and kept identical across type_vocabulary.md, okf_linter VALID_TYPES,
scaffold_bundle FOLDERS/DASHBOARD labels, and the example-bundle
frontmatter, so the linter still passes.
- Status enum rascunho/em-revisao/aprovado -> draft/in-review/approved.
- [SUPOSIÇÃO] -> [ASSUMPTION]; language: pt-BR -> en.
Identifiers intentionally preserved (published marketplace slug + tool
contract): skill slug arquiteto-de-empresa, cs-arquiteto agent/command,
phase-dir slugs (00-fundacao..11-governanca), concept filename slugs.
A slug rename to English is a separate reversible decision.
Also fixes a pre-existing broken link in the example bundle (identidade.md
pointed at a nonexistent problema-solucao.md — the original pt-BR bundle
also failed the linter there) and trues up two stale README badges
(agents 97->99, commands 103->109) that were drifting on dev.
Validation: okf_linter --sample PASS, example-bundle lint PASS (0 errors),
py_compile clean, all 3 scripts --help ok, dual-publish mirror identical,
plugin/paths/counters/G9 gates all exit 0.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
- jira_snapshot_bridge.py: a malformed --as-of now refuses with exit 2 instead of
raising TypeError (same guard as discovery_cadence_tracker).
- user_story_generator.py / persona_generator.py: add a real --sample flag so the
harness manifests can smoke-test them (supports_sample now true; product-team
manifest regenerated).
- ost_linter.py: document the --sample-always-exits-0 exception in the exit-code
contract.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Uzm8dKoeXPayJVMojpSbw
- Relabel this release v2.10.4 -> v2.11.1 (dev already carries v2.11.0 from the
engineering agent-harness PR); add a proper Current Version changelog entry and
sync marketplace metadata.version + both plugin manifests + SKILL.md frontmatter.
- jira_snapshot_bridge.py: Monte Carlo forecast now samples zero-filled weekly
throughput over the full observed span (Vacanti: dead weeks are observations),
and the 4-week refusal gate counts observed calendar weeks; regenerated the
pinned fixture. normalize() skips non-dict records instead of crashing.
- discovery_cadence_tracker.py: --as-of earlier than the interview history now
refuses cleanly with exit 5 instead of raising.
- harness_manifest_builder.py: descriptions truncate on word boundaries with an
ellipsis instead of mid-word; regenerated all 18 domain manifests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Uzm8dKoeXPayJVMojpSbw
Per PR #891 review: check_readme_badges silently skipped a badge whose regex
found no match, so a renamed or removed shield would quietly drop out of the
gate — the same silent-drift class this gate exists to catch. Now a missing
badge appends a mismatch (mirrors run_check's "no recognizable counter claims
found" precedent), so it fails loudly. Verified: renaming a badge trips exit 1;
the current README still passes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4JerbGv6vqitUMhqHPA9g
Per PR #891 review: `mismatches: list = []` was an inconsistent drive-by
annotation vs the un-annotated locals elsewhere in the file. Revert to keep
the diff minimal and the style consistent. No behavior change.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4JerbGv6vqitUMhqHPA9g
Follow-up to the merged agent-harness PR (#890), applying the automated review nits:
- loop_controller.py: drop unused `import shlex`; simplify cmd_record's exit-code
expression to the clearer form already used in cmd_verify (behavior-equivalent)
- SKILL.md + references/verification_discipline.md: document that plan/state files are
a trust boundary (verify shell-executes their cmd strings) — run the harness only on
files produced by goal_compiler, never untrusted input
- README.md: bump Agents 96->97 and Commands 102->103 badges (drift the previous PR
missed because derive_counters didn't validate these badges)
- scripts/derive_counters.py: add check_readme_badges — validates the Skills/Agents/
Commands shields against derived counts, closing the CI blind spot that let the badge
drift ship. Verified it fails (exit 1) on drift and passes when correct.
All gates green: plugin.json (83 OK), smoke --help/--sample (600 pass), JSON output
(0 fail), path linter (0 findings), derive_counters --check (pass).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4JerbGv6vqitUMhqHPA9g
Follow-up to the llms.txt footer links (PR #879). The automated review noted
the URL join assumed site_url ends in "/". Compute the base once with
trim('/') so the links stay correct whether or not site_url has a trailing
slash; trim only strips '/' from the ends, leaving "https://" intact.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sy9WFFurEjL8gjCp9fs7bp
Add machine-readable repository descriptions following the llmstxt.org
convention so AI agents and crawlers can discover a structured overview
of the entire skills library.
- docs/llms.txt: concise curated index (site sections + 18 domains)
- docs/llms-full.txt: comprehensive self-contained repo description
(scale, design principles, skill package pattern, per-domain detail,
plugin/git rules, and how an agent should use the library)
- Override partials/copyright.html to surface both files as footer links
on every page; add matching styles to stylesheets/extra.css
Both files build to the site root (verified: /llms.txt, /llms-full.txt)
and the footer links resolve to absolute site URLs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sy9WFFurEjL8gjCp9fs7bp
Two housekeeping items surfaced during the contributor-PR hardening session.
1. CHANGELOG backfill — add [Unreleased] entries for five skills that merged
without their own changelog blocks (roast #865, named-persona-adversarial-review
#867, agent-decision-receipts #868/#869, zero-hallucination-coder #870,
deep-research #872). Earlier merges updated headline counters but not this log.
2. Per-domain counter validation — scripts/derive_counters.py --check now also
validates the README "Skills Overview" per-domain table: each domain row's
count must equal the SKILL.md count in its linked folder, and every on-disk
domain must have a row. Previously --check only validated headline aggregates,
so per-domain rows drifted silently. Verified: passes on the fixed state, fails
on a wrong count, fails on a missing row, and parses exactly the 18 real domain
rows (bold-first-cell install/skills-vs-agents tables are not false-flagged).
Trued up the README table to make the new check pass: fixed six stale row
counts (engineering-team 51->52, engineering 78->80, marketing 47->48,
productivity 6->7, ra-qm-team 18->19, c-level 66->68), added the missing
markdown-html row (5), and named the newly-merged skills in their domain
descriptions. Per-domain rows now sum to the 354 headline.
Headline aggregates unchanged (354 skills / 722 refs / 82 plugins / 18 domains).
#872 merged before these automated-review fixes were pushed, so applying them
as a fresh follow-up:
- README: research (academic) domain row 8 -> 9 and add deep-research to the
8-specialist list + the intro-paragraph research stack (the global counters
were bumped in #872 but the per-domain row wasn't — derive_counters --check
only validates headline aggregates, not per-domain rows).
- research router SKILL.md: add a deep-research escalation note after the
Specialist Registry so router users learn about the high-stakes path
(router = fast, deep-research = heavyweight).
- cs-deep-research agent: fix the cs-research Related-Agents link (was a bare
directory, now points at the actual agent file).
Methodology-only scope retained per maintainer decision (no scripts added).
Adds a disciplined multi-source meta-research skill — the heavyweight,
rigor-first alternative to the fast research router. 9-phase pipeline
(reframe into falsifiable hypotheses -> plan -> capability discovery ->
parallel sub-agent fan-out -> score & triangulate -> synthesize + adversarial
pass -> verify -> refresh targets), triangulation against >=3 independent
differently-typed sources, per-source files with verbatim quotes, and a
hard no-fabricated-citations rule.
Concept + SKILL.md contributed by @Socialpranker in PR #851. Hardened for the
research/ per-skill-plugin convention (the PR shipped only the SKILL.md):
- Packaged as a full plugin to match every sibling (pulse/litreview/dossier/...):
added .claude-plugin/plugin.json, marketplace.json entry, cs-deep-research
agent, /cs:deep-research command, and README.
- Dropped a dangling claude-api cross-reference (not a repo skill); the other
cross-refs (research router, competitive-teardown, litreview/dossier/patent)
are all real.
- Preserved the contributed SKILL.md + references/full-catalog.md (the upstream
source-catalog pointer) verbatim otherwise; attribution + upstream link in
plugin.json and README.
Counters trued up via scripts/derive_counters.py --check (passes):
354 skills, 722 references, 96 agents, 102 commands, 82 plugins.
Co-authored-by: Socialpranker <273312799+Socialpranker@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kmw1eZQoSMDr2diHbCcUkF
- schema_generator: _build_aggregate_rating no longer fabricates a 4.8 rating.
It now requires BOTH count AND average and returns None otherwise — a made-up
ratingValue in live JSON-LD contradicts the skill's own anti-fabrication
guidance (Google cross-checks aggregateRating against GBP). Verified: count-only
config emits no AggregateRating; count+average emits the real value.
- nap_checker: normalize_address now expands ALL US state abbreviations via a
US_STATE_ABBREVIATIONS map, not just CA. "TX" vs "Texas" (and every other state)
now compares equal — the skill serves businesses nationwide, so CA-only
normalization silently under-reported mismatches for everyone else.
- SKILL.md: softened the "< 50 reviews" proactive trigger from "most SF Bay Area
markets" (inherited from the original author's metro) to "most competitive metro
markets".
All 3 scripts pass --help + sample run.
- Wire local-seo-manager into marketing-ops routing matrix (SEO Pod). Routing is
matrix-driven, so without this the router never sends "GBP audit" / "NAP
consistency" / "Map Pack" queries to the new skill. (medium — the flagged item)
- nap_checker: only report a "(missing)" phone mismatch when the canonical record
actually has a phone (elif canon_phone and not listing.get('phone')). Previously
a listing with no phone vs a canonical with no phone produced a misleading line.
Verified: no phantom mismatch when neither side has a phone.
- SKILL.md References section now lists review-response-templates.md (the 3rd
shipped reference, previously cited inline in Mode 1 but omitted from the list).
- marketplace.json: true up the stale marketing-skills plugin description
(44 skills / 59 tools / 86 refs -> 47 / 62 / 89) since this PR already edits
that file.
Config-key KeyError guard remains a deliberately-deferred nit (stdlib demo tools,
sample path fully covered). All 3 scripts still pass --help + sample run.
Address the two actionable items from the second automated review on #871:
- Add a CHANGELOG.md [Unreleased] entry for local-seo-manager (the repo maintains
per-PR changelog entries; the earlier commits missed it).
- Bump the README per-domain Marketing row 46 -> 47 to reflect the added skill
(this row isn't CI-validated, but it's the domain this PR touches).
The 3rd observation (config KeyError guard) remains a deliberately-deferred nit.
- service_area_generator: wire the previously-dropped inputs into the brief.
`business_type`, the `services` list, and `state` were accepted (and threaded
from config) but never rendered — the user's service list and state silently
vanished. Now surfaced in the opening-paragraph guidance and meta/CTA lines.
- schema_generator: stop emitting an empty geo block. The top-level empty-value
filter didn't reach into the nested dict, so `{"latitude":"","longitude":""}`
survived and produced invalid JSON-LD. geo is now only added when both
coordinates are supplied (verified: omitted for sample, present when provided).
- Removed the unused `import sys` from all three scripts.
(Config-key KeyError guard — the 4th, nit-level finding — left as-is; the scripts
are stdlib demo tools and the sample path supplies all keys.)
All three scripts still pass --help + sample run.
Adds a marketing skill for local service-area businesses (appliance repair,
HVAC, plumbing, cleaning, electrical): 4 modes — GBP audit, service-area page
generation, NAP consistency, and LocalBusiness schema — with 3 stdlib scripts
(nap_checker, service_area_generator, schema_generator), 3 references (80-point
checklist, schema types, review-response templates). Fills a genuine gap: the
library had national/technical SEO (seo-audit, programmatic-seo) but no
local/Map-Pack SEO skill.
Contributed by @Steffonet in PR #797. Light hardening before merge:
- Fixed two dangling skill cross-references: ai-seo -> aeo (the repo's actual
Answer Engine Optimization skill; 2 places), and removed the reference to a
non-existent gbp-content-creator companion skill.
- Reworded the description's first sentence ("Manage local SEO...") so it passes
skill_description_validator.
Placement is correct as-is (marketing-skills plugin globs ./skills), so no
plugin.json or marketplace entry is needed. All 3 scripts pass --help + sample.
Counters trued up via scripts/derive_counters.py --check (passes):
353 skills, 593 tools, 721 references.
Co-authored-by: Steffonet <214469854+Steffonet@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kmw1eZQoSMDr2diHbCcUkF
* bug: several bug fixes and improvements (see comments)
- [bug] fixed the shebang for portability (wouldn't run on my system)
- [feat] improved the inline python scripts; the `--all` and `--category` flags now read/dedupe names from the `skills-index.json` file so that stale entries (e.g. `.codex/skills/playwright-pro`) do not get treated as installable skills
- [bug] fixed the counter from installed++/failed++ to ++installed/++failed, which caused the script to exit upon installing the first skill
- [style] formatting fix
* fix(codex-install): improve error handling and validation for skill and category installation
---------
Co-authored-by: Alireza Rezvani <5697919+alirezarezvani@users.noreply.github.com>
Adds an opt-in coding-discipline skill: a Discuss -> Map -> Decompose ->
Execute -> Verify loop that grounds code in verified structure (KNOWN/INFERRED/
UNKNOWN codebase mapping, atomic-story decomposition, a lazy-senior-dev YAGNI
ladder) with no invented APIs, assumed imports, or placeholder code. Synthesizes
four MIT/open-source projects (Ralph, GSD Core, Graphify, Ponytail).
Concept + SKILL.md contributed by @mehanshbarthwal-lab in PR #854. Hardened for
this repo:
- Scoped activation to OPT-IN (high-stakes / complex / multi-file / explicitly
requested rigor) instead of auto-firing on every coding verb, so it doesn't
hijack all coding requests in users' setups.
- Fixed plugin.json: skills ["./skills/zero-hallucination-coder"] (was bare
"./", which fails check_plugin_json), version 2.10.3 (was stale 2.1.2),
author aligned to repo owner + attribution block crediting the contributor
and all four source repos.
- Restructured to the engineering standalone-plugin layout
(engineering/<plugin>/skills/<name>/SKILL.md) matching caveman/grill-me/handoff.
- Trimmed the ~130-line embedded multi-method install guide + external-tool
install promo (marketplace handles install); kept the credits table.
- Fixed the description to pass skill_description_validator (third person +
explicit "Use when" trigger).
- Registered in marketplace.json.
Counters trued up via scripts/derive_counters.py --check (passes):
352 skills, 81 plugins.
Co-authored-by: mehanshbarthwal-lab <227379980+mehanshbarthwal-lab@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kmw1eZQoSMDr2diHbCcUkF
The "Decision 2" table listed inputs_hash under "required keys this skill
enforces," but build_action_manifest.py only enforces four required keys
(agent_id, operation, target, policy). inputs_hash and decision_label are
auto-added, not required input. Clarified: 4 required + 2 auto-added, so the
doc matches the script.
Follow-up to #868 (agent-decision-receipts), which merged before this fix landed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kmw1eZQoSMDr2diHbCcUkF
Adds a ra-qm-team skill that mints tamper-evident, post-quantum-signed receipts
for consequential agent actions (EU AI Act Article 12 record-keeping, OWASP
Agentic excessive-agency). A stdlib-only script builds/validates the action
manifest; signing is delegated to the open-source openagentontology package
(Apache-2.0, opt-in install — adds no repo dependency).
Concept + script contributed by @CWNApps in PR #863. Hardened for this repo:
- Moved from the orphaned ra-qm-team/agent-decision-receipts/ (a sibling of
skills/, not picked up by the ra-qm-skills plugin's ./skills glob) into
ra-qm-team/skills/agent-decision-receipts/ so it is actually distributed.
- Stripped self-promotion of the contributor's other products (SalesGPT /
OpenOutreach / Trust Gate MCP / "CWN distribution") from the references doc;
kept the technical PQ-strict-mode pattern, genericized the env var name.
- Removed the 25-term SEO keyword-stuffing block (not a repo convention).
- Fixed the description to third person (passes skill_description_validator).
- Repointed cross-refs to the real sibling skills (eu-ai-act-specialist,
iso42001-specialist).
The stdlib script is preserved as-authored (clean; builds + validates the
manifest, rejects missing fields, enforces ASCII reproducibility).
Counters trued up via scripts/derive_counters.py --check (passes):
351 skills, 590 tools, 718 references.
Co-authored-by: CWNApps <129076989+CWNApps@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kmw1eZQoSMDr2diHbCcUkF
Adds a philosophy-grounded code-review skill: review through the lens of real
engineers' *documented, sourced* principles (Torvalds, Thompson, Carmack, Beck,
Brooks + Jobs, Cagan, Traynor), complementing engineering-team/adversarial-reviewer
(abstract roles) and code-reviewer (general quality).
Concept contributed by @YuhaoLin2005 in PR #866. Hardened for this repo's
conventions before merge:
- Consolidated to ONE location (engineering-team/skills/, auto-included via the
engineering-skills plugin's ./skills glob). Dropped the orphaned top-level
skills/ copy the original PR also added — no such plugin root exists in the tree.
- Added anti-fabrication discipline: cite the sourced principle (not an invented
verbatim quote), confidence levels on every attribution, drop a persona rather
than fabricate — mirrors productivity/andreessen's citation rule. LLMs hallucinate
quotes; attributing invented words to real living engineers is the core risk.
- Added references/persona_principles.md grounding every persona in a real,
citeable source with a confidence level (7+ sources incl. de Bono, Kahneman, Feynman).
- Removed the dangling /adversarial-review slash command reference and the
non-English trigger phrase; description passes skill_description_validator.
Counters trued up via scripts/derive_counters.py --check (passes):
350 skills, 717 references, 80 plugins.
Claude-Session: https://claude.ai/code/session_01Kmw1eZQoSMDr2diHbCcUkF
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: YuhaoLin2005 <278400118+YuhaoLin2005@users.noreply.github.com>
New productivity/roast/ plugin. Convenes five independent reviewers (The Critic,
The Champion, The Analyst, The Investigator, The Customer) in parallel on a business
idea, then a Judge synthesizes one GO / RESHAPE / KILL verdict with the cheapest
48-hour test to de-risk it.
Renamed the personas/steps from the source draft to be self-explanatory for users:
Critic/Champion/Analyst/Investigator/Customer (was Contrarian/Expansionist/Logician/
Researcher/Buyer) and Frame the idea / Run the 5-angle panel / Call the verdict.
Path-B contract:
- 3 stdlib tools (no LLM calls): brief_builder, verdict_synthesizer (weighted,
non-compensatory veto gates, tension detection — never a plain average),
cheapest_test_designer (risk → falsifiable 48-hour test)
- 3 references (5-7 cited sources each), 2 assets, cs-roast-judge agent, /cs:roast command
- source.distinct_from disambiguates vs andreessen (single lens), boardroom
(enterprise pipeline), grill-me (no verdict)
Counters trued up via scripts/derive_counters.py --check (passes):
346 skills, 582 tools, 708 refs, 94 agents, 100 commands, 79 plugins.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kmw1eZQoSMDr2diHbCcUkF
Address internal-consistency gaps from the count bump: the marketplace.json
root description still read 347/17 (only metadata.description was updated),
and the README skills table had no loop-library row despite the "18 domains"
heading. Both now reflect 348 skills / 18 domains with loop-library listed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KEJH6wwyaEs1d6AAca2HLR
Gate G1 (check_paths.py --all) was failing on dev's arquiteto-de-empresa
skill, surfaced into this branch by the dev merge. The 3 references are
genuine false positives: two are inside a markdown code-example showing
OKF bundle link syntax in the user's generated output, and one is a
command doc pointing at its sibling skill's references/ dir. Added to
check_paths_allowlist.txt per the workflow's documented remedy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KEJH6wwyaEs1d6AAca2HLR
Adding the loop-library/ folder bumped the derived counters. Sync the
headline claims in README.md, CLAUDE.md, and marketplace.json so
scripts/derive_counters.py --check passes: skills 345->346, domains
17->18, references 705->707.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KEJH6wwyaEs1d6AAca2HLR
Install the loop-library skill from Forward-Future/loop-library into the
repo, preserving the upstream skill folder exactly. SKILL.md, agents/openai.yaml,
references/discover.md, and references/audit.md are byte-for-byte copies of
upstream (skills/loop-library/). Adds the MIT LICENSE and a provenance README.
The published loops themselves are served live from the database-backed catalog
(catalog.md / catalog.json) and are intentionally not committed to Git upstream;
the skill fetches them at runtime as the single source of truth.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KEJH6wwyaEs1d6AAca2HLR
mcp-server-builder, performance-profiler, ci-cd-pipeline-builder, and four
ra-qm-team skill sources changed after the last docs regeneration; refresh
their generated pages so the published site matches the SKILL.md sources.
https://claude.ai/code/session_015bYZ97nV4oRb3LbxCRFVcP
Keeps the three most safety-critical nudges (secrets in env, host
allowlists, additive-only contract changes) scannable in SKILL.md's
'Harden for Production' step instead of two hops away; merges the
Tier/Category/Domain boilerplate onto one line to stay under the
100-line ceiling.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
First tranche of the Matt Pocock 100-line SKILL.md refactor (issue #655).
Pattern: keep the operational core (overview, capabilities, workflows,
script interfaces) in SKILL.md; move the advisory layer verbatim into a
new reference doc, linked with a one-line summary.
- ci-cd-pipeline-builder: 147 → 89 lines; pitfalls/best-practices/
heuristics/strategy/platform-notes/validation/scaling moved to
references/pipeline-design-notes.md
- mcp-server-builder: 164 → 97 lines; auth-safety/versioning/pitfalls/
best-practices/architecture/quality-gates/testing/deployment/security
moved to references/production-hardening-guide.md
Both skills now pass skill_structure_validator (verdict PASS). No content
deleted — everything moved verbatim. Path linter, dual-publish guard, and
counter checks green.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Resolves the import-placement asymmetry flagged across review rounds by
moving the remaining inside-guard import (argparse) up to join sys at the
file-level import block.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Adds FileNotFoundError / JSONDecodeError / missing-key handling to
team_scaling_calculator's input_file path, matching the other five
sample-pattern tools (pre-existing gap, surfaced by review).
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Hoists the embedded defaults to SAMPLE_CURRENT_STATE / SAMPLE_GROWTH_TARGETS
module constants so the loading flow can use the same top-of-branch
if/elif/else shape as the other five tools without duplicating the fixture.
The silent default-to-sample when no input is given is pre-existing,
documented behavior (kept; noted in the constant's comment).
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
- incident_triage.py: --sample help text now documents the intentional
exit-2 SEV1 signal so &&-chained callers aren't surprised
- team_scaling_calculator.py: consolidate the split warn/load blocks into
the single if/else pattern the other five tools use
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
- health_score_calculator + pipeline_analyzer: warn on stderr when --sample
overrides a provided input (now consistent across all six tools)
- pmf_scorer: --sample checked before --input (matches the batch), with the
same override warning
- pipeline_analyzer: comment the intentionally stale D-3 fixture deal
- contrast_checker: user-facing --sample help text
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Review of PR #842 found qms-audit-expert's crosswalk still presenting QSR
sections as current; an exhaustive domain sweep found one more
(regulatory-affairs-head's fda-submission-guide QSR bullet list). Both now
carry the QMSR banner with ISO 13485 clauses as current authority and 820.x
as labeled historical index; the audit playbook's transition paragraph
updated to past tense (rule took effect 2026-02-02). Also standardized the
one divergent column header per review.
Domain-wide grep now shows zero unlabeled 820.x-as-current claims in
ra-qm-team/ and compliance-os/ (residuals are TOC anchors inside the
banner-framed historical reference).
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
- team_scaling_calculator.py: move sys import to the file-level import block
(was inline in the conditional); behavior unchanged
- incident_triage.py: warn on stderr when --sample overrides a provided
--input, matching team_scaling_calculator's convention
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
- pmf_scorer.py: the no-input fallback notice now goes to stderr, so a bare
`pmf_scorer.py --json` emits parseable JSON on stdout
- team_scaling_calculator.py: warn on stderr when --sample overrides a
provided input_file instead of silently discarding it
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
capa-officer, quality-documentation-manager, quality-manager-qmr,
quality-manager-qms-iso13485, and the ra-qm-skills router still presented
legacy QSR 820.x subsections as current FDA law — the same P0-class defect
fixed in fda-consultant-specialist (PR #835), deferred by that wave's agent.
Applied the identical validated pattern: QMSR status banner (final rule
89 FR 7496, ISO 13485:2016 incorporated by reference, effective 2026-02-02),
820.x relabeled historical with ISO 13485 clause as current authority
(CAPA -> 8.5.2/8.5.3; doc/record control -> 4.2.3/4.2.4/4.2.5 + retained
820.35; QMR/management review -> 5.5.2/5.6), and decision-discipline blocks
added where missing (closure/compliance calls route to named owners).
Substantive content unchanged; no scripts contained 820.x claims.
Verified: zero present-tense 820.x-as-current-law claims remain (all under
historical labels/banners); check_paths 0 findings; counters unchanged.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
Brings G9 JSON-output coverage from 19 to 25 tools (25/25 verified):
- business-growth: health_score_calculator (embedded 2-customer fixture),
pipeline_analyzer (embedded 4-deal pipeline fixture)
- c-level-advisor: pmf_scorer (--sample flag for its existing sample_data(),
suppressing the stdout notice that corrupted JSON piping),
team_scaling_calculator (--sample flag for its embedded defaults)
- engineering-team: incident_triage (embedded synthetic ransomware event),
contrast_checker (--sample as alias of the existing --demo)
Required-arg behavior unchanged when --sample is absent (still exits 2 with
a usage error). All gates green: G9 25/25, G8, dual-publish, path linter.
Together with the 5 #654-named tools, 4 JSON-honor fixes, and the pre-existing
sample-pattern tools, more than 20 tools now support the embedded-sample
convention — meeting #654's acceptance bar.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
- Rewrite docs/stylesheets/extra.css with a warm clay/coral design system:
aurora hero with eyebrow badge and stats strip, gradient card hairlines,
pill tool badges, numbered steps component, reduced-motion support
- Rewrite homepage copy: plain-language 'What is an Agent Skill?' section,
3-step how-it-works, all 17 domain cards, guides section, accurate stats
(337 skills / 17 domains / 66 plugins)
- Add missing markdown-html domain to generate-docs.py (17th domain) and
regenerate catalog: +12 new pages (md-document/md-review/md-slides skills,
cs-markdown-html-orchestrator + cs-scraping-architect agents, 7 commands)
- Fix skill-internal link rewriting in the generator (./SIBLING.md and
ALL-CAPS companion files now resolve to GitHub URLs) — mkdocs --strict
now passes with zero warnings
- Refresh stale counters site-wide (177/192/204/311/338 → 337) in skills
index, plugins index, getting-started, integrations, custom-gpts, guides
- Rebuild plugins page from live marketplace.json: 13 domain bundles + 53
standalone plugins, accurate bundle table and full 66-plugin listing
- Add Guides section to nav (5 existing SEO guide pages, URLs unchanged),
point homepage tool badges at tool-specific guides and real anchors
- Tighten site_description and JSON-LD keywords for 'agent skills' /
'agent plugins' queries; update announce bar to the markdown-html launch
- No existing slugs or URLs changed — all edits are additive or in-place
https://claude.ai/code/session_015bYZ97nV4oRb3LbxCRFVcP
- calculate_cac.py: hoist 'import argparse' to module top per repo convention
- smoke_scripts.py: comment the exit-1-over-exit-3 precedence
- check_paths_allowlist.txt: reword the etc/passwd note ('outside repo root if
resolved literally', not 'deep checkouts')
- cs-scraping-architect.md: clarify both warning and error share exit 1 — parse
the JSON status field for the distinction
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
- smoke_scripts.py: --help epilog now documents the exit-code table
(0 ok / 1 smoke failure / 3 stale exceptions)
- calculate_cac.py: real argparse --help with an epilog stating the
edit-example_data limitation and the planned --file/stdin enhancement
- cs-scraping-architect.md: add 'model: sonnet' to match sibling agents
Item 4 (senior-security references) was a non-issue — all three referenced
files exist and the now-blocking path gate is green.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
The blocking G1 path gate flagged '../../../etc/passwd' — a path-traversal
ATTACK EXAMPLE in a pen-testing skill's attack-vector table, not a real file
reference. It passed locally only because a deep checkout makes ../../../ climb
to the host's real /etc/passwd; on the CI runner it doesn't resolve. Allowlisted
with a reason, per the gate's documented edge-case process.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
Implements issue #654 Option A (embedded-sample convention) plus the
verification harness the issue asked for:
- scripts/smoke_json_output.py — new advisory gate (G9) that discovers
every tool whose --help advertises JSON output, runs <tool> --sample
<json-flag>, and asserts the stdout parses as JSON. Tools advertising
JSON without --sample are reported as 'uncovered' (a backlog, not a
failure) so the gate can be adopted incrementally; --strict flips that
to a hard failure once coverage is high. Wired into ci-quality-gate.yml
alongside G8.
- Added --sample embedded fixtures to the 5 tools named in #654:
error_budget_calculator, slo_review, blast_radius_calculator,
audit_log_analyzer, api_linter. Their required args are now optional
when --sample is passed; missing-arg behavior is unchanged otherwise.
- Fixed 4 tools the new gate surfaced (prompt_rater, coach_tip_classifier,
cheat_code_filter, redaction_linter): their --sample path printed human
text and ignored --json; it now honors the JSON flag.
- Synced the 3 dual-published standalone copies (slo-architect x2,
chaos-engineering) so the drift guard stays green.
Gate now reports 16 tools covered, 16 verified, 0 failures.
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
- senior-prompt-engineer: rebuilt on the new-gen pattern; 2023-era cheatsheet
dropped; scripts made model-agnostic and rot-proof (user-supplied pricing,
no hardcoded model/cost tables); 5 workflows with executable exit-code
gates; zero stale model names remain
- senior-security: 445 -> 64 lines; owns only its unique STRIDE/DREAD value
with exact CLIs; 10-row lane table routes everything the v2.2 security
suite covers (all paths verified)
- engineering-team docs: all dead computer:/// links repointed to live
skills/ folders; all 14 stale .zip archives deleted (0 references remain;
folders are the canonical distribution)
- universal-scraping-architect: placeholder cs-scraping-architect agent and
cs-scrape command rewritten with verified CLIs, refusal gates, and the
empirically-confirmed validate_extraction.py exit-code contract
Gates at HEAD: check_paths 0 findings; check_dual_publish 0 drifted;
smoke 582/582; counters match; 78 manifests OK; compileall clean.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
- cs-content-creator retargeted off the deprecated content-creator stub to
marketing-skill/skills/content-production; Use-when description; all 4
script CLIs verified; workflows end at the skill's documented thresholds
(score >= 70, quality gates as publish blocker)
- cs-demand-gen-specialist now orchestrates all 3 verified targets
(marketing-demand-acquisition, paid-ads, email-sequence); hard rules
(margin-adjusted ROAS, no scaling without verified tracking); honest CLI
for calculate_cac.py (script takes no args — old agent documented a
phantom invocation)
- marketing-demand-acquisition SKILL.md: same phantom calculate_cac
invocation corrected (verified no-args run exits 0)
- marketing_skills_roadmap.md deleted: stale planning material, now
unreferenced after the agent rewrites (was kept in wave-3 only because
these two agents linked it)
Verified: check_paths 0 findings on both agents; 8 documented CLIs pass
--help; descriptions <= 1024 with Use-when phrasing.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
- enforce-pr-target.yml: drop the no-op split/trim/join on the comment body
(array join already produces the final text)
- ci-quality-gate.yml: safety findings now emit a workflow warning instead
of being silently absorbed by '|| true'
- check_paths.py: fnmatch import hoisted to module level
- smoke_scripts.py: stale exception entries now fail the gate (exit 3) so
scripts/smoke_exceptions.txt stays tidy
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
Every advisory run was green through PR #835, so the burn-in SLA
(2026-07-01 or 10 green runs) is satisfied early. Edge cases route to the
in-repo allowlists (check_paths_allowlist.txt, smoke_exceptions.txt)
instead of continue-on-error.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
- derive_counters.py: python_tools condition simplified to the equivalent
parts[0] != 'scripts' (reviewer M1); dead root_scripts variable removed;
--check still passes with identical values
- fda-consultant-specialist quick-start: 820.30 example annotated as a legacy
checklist key mapping to ISO 13485 §7.3 (reviewer m3 — note: switching the
example to '--section 7.3' as suggested would break; the checker's CLI keys
are intentionally the legacy 820.x checklist indices, documented in --help)
- CLAUDE.md: audit/ directory documented as an intentional public audit
record, distinct from the gitignored AUDIT_REPORT.md (reviewer m2)
Reviewer m1 (agents/CLAUDE.md 'engineering-team/' link) is a false positive:
agents/engineering-team/ exists as an agents subfolder containing exactly the
two linked files; check_paths.py confirms 0 unresolvable references.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
- enforce-pr-target.yml: the maintainer exemption let any maintainer PR
target main — replaced with the branch-based hard rule from CLAUDE.md:
only dev->main promotion PRs are allowed, regardless of author.
Maintainer PRs now fail the check with retarget instructions (not
auto-closed); non-maintainer PRs are commented and closed as before.
Re-checks on edited/ready_for_review so retargeting clears it.
- ci-quality-gate.yml: flip-to-blocking SLA documented for the 4 advisory
gates (2026-07-01 or 10 consecutive green runs on dev)
- CHANGELOG.md: Deprecated/Removed Skills section with migration paths for
command-guide, ai-seo (-> aeo), release-manager (-> changelog-generator)
Addresses automated review feedback on PR #835 (items 1, 3, 6).
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
The skill was the repo's only SKILL.md at plugin-root depth
(engineering/universal-scraping-architect/SKILL.md). That nonstandard shape:
- made it the only skill the Tessl quality gate's depth-2 detector fires on
(the gate then fails with an error-fallback 0/100 because the workflow has
no Tessl credentials)
- hid it from convert.sh (-mindepth 4)
- was flagged twice in the newgen audit
Now matches the standalone-plugin convention (skills/<name>/SKILL.md, agents/
+ commands/ + .claude-plugin at plugin root, skills: ['./skills']).
No content changes. Marketplace source path unchanged and still valid.
Gates: 78 manifests OK, 0 unresolvable paths, 0 dual-publish drift,
smoke 582/582, counters match.
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
Adds an unmissable blockquote to the Git Workflow section: every PR (human or
AI) uses --base dev; main only receives dev->main promotion PRs from the
maintainer. Also trues the Current Scope counters to derived values
(344 skills / 579 tools / 698 references after wave-3 merges and removals).
https://claude.ai/code/session_019AJddAL1NADWMXsy1qNPQF
- #805: insert missing skills/ segment in all per-skill install commands
across 5 domain READMEs (engineering-team, project-management,
marketing-skill, c-level-advisor, ra-qm-team); every path now resolves
to a real directory
- #806: pr-review-expert SKILL.md curl examples now pass Jira/Linear
credentials via stdin curl config (-K -) instead of argv, with a netrc
note, so tokens never reach the process list or shell history
- #807: implement the documented interfaces for the three senior-devops
scripts (terraform_scaffolder: aws/gcp/azure module skeletons with
optional terraform fmt/validate; pipeline_generator: GitHub Actions /
CircleCI configs with build,test,security,deploy stages and runtime
detection; deployment_manager: blue-green/rolling manifests + kubectl
runbooks with deploy/rollback/analyze subcommands); align SKILL.md
- #807: ci-cd-pipeline-builder stack_detector now detects Terraform and
Docker stacks and emits their lint/test/build commands; downstream
pipeline_generator gains a generic job for non-node/python/go stacks
- #748: sync-vibe-skills.py defaults to a flat layout one level below
~/.vibe/skills (the only depth Vibe discovers), with collision-safe
naming and a --nested flag for the legacy namespaced layout
- #785: new scripts/sync-codebuff-skills.py syncs all skills into
Codebuff's ~/.agents/skills using the same flat-layout machinery
https://claude.ai/code/session_01CUWsrUNZP9jpxvAwq67UiT
Adds the collab-proof AI-collaboration retrospective skill from PR #788
(contributor: dong7812) without the regressions in that branch:
- Net-add marketplace entry (PR #788 overwrote the youtube-full plugin
slot; that entry is preserved here).
- marketplace.json kept as raw UTF-8 (PR #788 re-serialized with
ensure_ascii, escaping ~109 chars and polluting the diff).
- Header counters bumped from current dev (344 skills / 695 references /
65 plugins) instead of reverting to the stale v2.9.0 header.
Skill content (SKILL.md, 4 references, plugin.json, LICENSE) is taken
verbatim from #788. plugin.json passes check_plugin_json.
https://claude.ai/code/session_012iCc6XcNqiJzCGfKHz1DKi
Adds cs-webinar-marketer agent + /cs:webinar command wiring the webinar-marketing skill (SKILL.md, stdlib funnel scorer, references, templates, evals) under marketing-skill/skills/. Includes a Windows cross-platform fix to scripts/generate-docs.py (normalizes os.sep to forward slashes — verified no-op on Linux) and regenerated docs. Verified: scorer runs (89/100 sample), frontmatter valid, clean merge into dev with no conflicts.
Ports ZeroPointRepo/youtube-skills (MIT) into marketing-skill/. Adds SKILL.md with MIT license + attribution, .claude-plugin/plugin.json, and marketplace.json entry. Documents BYOK/free-tier model and OSS fallbacks (youtube-transcript-api / yt-dlp / YouTube RSS). All four prior owner-review items addressed.
Adds the fourth skill to the markdown-html/ domain. The Tier-2 use case
from Shihipar's essay ("Code Review and PR Writeups"): a markdown PR
writeup with ```diff blocks and severity callouts becomes a single-file
2-column HTML review with top jump-nav, diff on the left, severity-tagged
annotation cards on the right, and a mandatory named reviewer footer.
Three stdlib tools pipeline together:
1. diff_parser.py — scans markdown for ```diff fenced blocks, parses each
as a unified diff (--- a/file, +++ b/file, @@ -10,7 +10,8 @@,
space/+/- body lines), assigns per-line numbers on both old (lo) and
new (ln) sides, preserves the per-hunk @@ header context. Supports
--infer-diff for unfenced blocks. Stdlib regex + state machine.
2. annotation_extractor.py — extracts severity callouts (GFM
> [!BLOCKER] style) and inline markers (nit:, blocker:, etc.).
Default convention BLOCKER/MAJOR/MINOR/NIT per Google's Code Review
Developer Guide; overridable via --severity-convention. Attaches each
annotation to the nearest preceding diff block by source-line index;
unanchored annotations go to a "general comments" section. Also
captures LGTM/approve markers separately as approvals.
3. review_html_renderer.py — emits single-file 2-col HTML. Top jump-nav
lists every annotation with severity badge + 80-char preview + jump
link + per-tier counts in heading. Each hunk-row is a CSS grid with
diff on the left (per-line numbers, +/- marks, addition/deletion bg
tints from --md-success/--md-warn via color-mix) and annotation cards
on the right. WCAG-1.4.1-compliant severity badges (color + icon +
aria-label + text — color is NEVER the sole signal); BLOCKER danger
color computed by hue-rotating the design-system accent 120° toward
red so it stays brand-coherent. Approval bar when LGTM markers
present and no findings. Collapses to stacked on viewports < 900px.
Mandatory --reviewer (refuses exit 3 otherwise — research-ops
named-owner discipline). Refuses exit 4 if no hunks present (wrong
skill → route to md-document). No Prism CDN (diff coloring conflicts
with syntax highlighting).
Plus 3 references each citing 5-7 sources:
- diff_rendering_canon.md — POSIX diff format + GitHub/GitLab UI +
difftastic + SWE at Google ch. 9
- severity_coding.md — WCAG 1.4.1 + Google review taxonomy + Don
Norman Design of Everyday Things + NN/g color UX
- pr_annotation_ux.md — convergent 2-col UX from GitHub / GitLab /
Reviewable / CodeStream + SWE at Google + NN/g F-shape
1 template asset documenting the canonical 2-col review HTML shape.
/cs:md-review slash command with 4 pre-flight gates
(under-100-lines, no-onboarding, missing-reviewer, no-hunks) + pipeline
+ output digest.
Repo-level updates:
- markdown-html/.claude-plugin/plugin.json: skills array adds
./skills/md-review; version 2.10.1 → 2.10.2; description updated.
- .claude-plugin/marketplace.json: markdown-html-skills entry version
and description; top-level counters 341 → 342 skills, 542 → 545 Python
tools, 685 → 688 references, 88 → 89 slash commands; metadata.version
2.10.1 → 2.10.2.
- Root CLAUDE.md: v2.10.2 release-notes block above v2.10.1.
Validation:
- check_plugin_json.py → OK
- sync-codex-skills.py --dry-run → 1 new symlink, documentation: 4 skills,
total 343
- skill_description_validator.py → PASS (all 5 checks: present, length,
third-person, trigger, action verb)
- skill_review_checklist_runner.py → 5/6 PASS (97 lines passes
under-100-lines check; minor WARN on "user" vs "developer" terminology
which are contextually distinct — converter operator vs review subject)
- All 3 tools pass --help and --sample
- Hard rules verified end-to-end:
no --reviewer → exit 3 with refusal message
no hunks → exit 4 with refusal message + md-document routing hint
custom severity convention "critical,important,suggestion,nit" works
- Full pipeline on sample PR (2 diff blocks, 2 callouts) produces 11.3 KB
single-file HTML with all 14 expected components (reviewer footer, PR
title, aria-labels per WCAG 1.4.1, --md-danger computed color, modern
color-mix tints, 2-col grid, 900px responsive collapse, both file
paths, annotation cards, jump-nav, addition+deletion classes, Findings
heading).
Coming in v2.10.3: md-slides — slide splitter + presenter-notes parser
+ arrow-key/space-bar nav + @media print for PDF export. Reuses
md-document's renderer scaffolding + design-system/scripts/config_loader.py.
https://claude.ai/code/session_01BK2KoQot1U7J5oSosrCQdc
Register the ECC marketplace (affaan-m/ECC) and enable the ecc@ecc plugin
in committed .claude/settings.json so the 63 agents / 249 skills / 79
commands / hooks load at runtime for anyone who opens this repo (one-time
trust prompt). Uses ECC's recommended plugin path; files are not vendored,
so there is no collision with the existing skills library.
https://claude.ai/code/session_01Vw7LCQLH5Wi7WHrrN47Hj6
Adds the universal-scraping-architect skill (Firecrawl + local Python extraction) salvaged from #706, with all merge-blockers fixed, CI workflow validator paths corrected (engineering/skills reorg), and code-review feedback addressed. Tessl quality review intentionally bypassed (CLI unauthenticated in CI — advisory only). Co-authored with @mehanshbarthwal-lab.
Phase 2 / Tier 1 of the post-#769 audit. Until now, the deterministic
analyzer (scripts/code_quality_checker.py) had language-specific smell
detectors only for C# and Java; C / C++ / Rust / Ruby / PHP / Dart all
fell through to generic checks. This PR brings C onto the same footing
as C# and Java -- the security delta is largest for memory-unsafe
languages, so C goes first per the audit ranking.
What's detected (CERT C + CWE catalogue patterns)
- Banned functions: gets, strcpy, strcat, sprintf, vsprintf
(CWE-242 / CWE-120 family -- no bounds check on any of them)
- Format-string vulnerability: printf(var) / syslog(var) where the
first arg is a bare identifier instead of a literal (CWE-134).
Suppressed when the first arg is a literal string.
- Unbounded scanf: %s without a width specifier (CWE-120).
Suppressed when a width is present (e.g. %31s).
- malloc/calloc/realloc result not NULL-checked within 5 lines
(CWE-690). Recognises if (p == NULL), if (NULL == p), if (!p),
if (p != NULL).
- free(p) without setting p = NULL on the next real line
(CWE-416 use-after-free guardrail). Low severity since some
style guides skip the zeroing convention.
- system() with a non-literal argument (CWE-78 command injection).
Suppressed when the argument is a string literal or NULL.
Implementation
- New function check_c_specific_smells() in code_quality_checker.py,
placed after check_java_specific_smells(). Reuses the existing
_strip_csharp_comments helper -- C, C#, and Java share // and /* */
comment syntax.
- Wired into analyze_file() via the existing dispatcher pattern:
`if language == "c": smells.extend(check_c_specific_smells(content))`.
Fixtures (regression-detection harness)
- assets/sample_c_smells.c -- 67 lines, every detector pattern
labelled inline with its CWE. Smells fixture produces 10 C-specific
detector hits (strcpy fires twice intentionally, once in each
function). Score: 4/100 (F).
- assets/sample_c_clean.c -- same surface area refactored per
rules/universal.md + languages/c.md. Zero C-specific hits.
Score: 100/100 (A).
- expected_outputs/sample_c_smells_quality.json and
expected_outputs/sample_c_clean_quality.json -- committed JSON
output mirrors the existing C# / Java regression-guard pattern.
Documentation
- engineering-team/skills/code-reviewer/README.md
- "Language-specific smell packs" line extended to enumerate the
6 C-pack patterns alongside the existing C# and Java packs.
- Bundled-fixtures table adds the 2 new C fixture rows.
- engineering-team/skills/code-reviewer/SKILL.md
- "Adding a New Language" step 5 reference: C# and Java -> C#,
Java, and C.
- "Regression Fixtures" paragraph reference: C# and Java -> C#,
Java, and C.
- docs/skills/engineering-team/code-reviewer.md mirrors the same
SKILL.md updates.
- CHANGELOG.md gets a new [Unreleased] section above the existing
code-reviewer entry, documenting the detector + fixtures.
Regression
- All 6 fixtures (C# / Java / C x smells / clean) pass byte-for-byte
against expected_outputs/*.json. No drift introduced in C# or Java
behaviour.
Not in this PR (Phase 2 audit, subsequent PRs)
- check_<name>_specific_smells for C++, Rust, Python, Kotlin, PHP,
Ruby, Dart, Go, Swift, TypeScript, JavaScript. C++ and Rust are
the next-highest-leverage targets (smart-pointer ownership,
unsafe block discipline). Same fixture + expected_outputs pattern
will apply to each.
https://claude.ai/code/session_01SnXMhpyuAwrws26Wy4fizz
"description":"338 production-ready skills across 16 domains (engineering, engineering-core, marketing, product, c-level, compliance-os, project management, RA/QM, business growth, finance, productivity, marketing (top-level), research, research-ops, business-operations, commercial, plus standards). 533 Python tools, 676 reference guides, 51+ agents (cs-* + personas), 87+ slash commands across 63 marketplace plugins. v2.9.0 adds the research-ops domain — enterprise Research Operations (clinical-research + research-finance + market-research + product-research + orchestrator) with per-skill onboarding, customization config, and an opt-in autoresearch bridge, plus the engineering workflow-builder skill (intake-first authoring of deterministic multi-agent .js workflows for Claude Code's Workflow tool). Compatible with Claude Code, Codex CLI, Gemini CLI, Cursor, OpenClaw, Hermes Agent, Mistral Vibe, and 5 more coding agents.",
"version":"2.9.0"
"description":"388 production-ready skills across 20 domains (engineering, engineering-core, marketing, product, c-level, c-level-agents, compliance-os, project management, RA/QM, business growth, finance, productivity, marketing top-level, research, research-ops, business-operations, commercial, markdown-html, loop-library, plus standards). 727 Python tools, 842 reference guides, 118 agents (cs-* + personas), 150 slash commands across 99 marketplace plugins. v2.11.2 vendors engineering/skillopt-sleep — a verbatim copy of microsoft/SkillOpt's stdlib-only skillopt_sleep engine + Claude Code plugin surface, giving a local agent a nightly gated self-improvement cycle (read-only session harvest -> mine -> offline replay -> held-out-gated CLAUDE.md/SKILL.md edits -> staged for explicit /skillopt-sleep adopt). productivity/fable-goal (unreleased, post-v2.11.1) converts a rambling description of a desired outcome into one polished /goal prompt for a fresh autonomous session. v2.11.1 turns product-team and project-management into agent-harness domains: fork-orchestrators with deterministic goal routers, a Jira MCP snapshot bridge (Kanban flow metrics + Monte Carlo forecasting), a delegation-governance loop gate, a continuous-discovery cadence tracker, and an Opportunity Solution Tree linter, with /cs:pm and /cs:product command families. v2.10.3 completes the markdown-html domain with md-slides — slide-deck converter (arrow-key / Space / PgDn / Home/End / P keyboard navigation + presenter mode with split-view clock + speaker notes + next-slide preview + URL-hash deep linking like #3 for direct slide jumps + @media print page-per-slide for browser-native PDF export). Reuses md-document's markdown parser; vanilla JS only (no framework runtime); Prism.js opt-in via --syntax. Joins md-review (v2.10.2 code-review converter), md-document (v2.10.1 long-form converter), and the v2.10.0 foundation (orchestrator + design-system). Compatible with Claude Code, Codex CLI, Gemini CLI, Cursor, OpenClaw, Hermes Agent, Mistral Vibe, and 5 more coding agents.",
"version":"2.12.0"
},
"plugins":[
{
"name":"marketing-skills",
"source":"./marketing-skill",
"description":"44 marketing skills across 7 pods: Content, SEO, CRO, Channels, Growth, Intelligence, Sales enablement, and X/Twitter growth. 51 Python tools, 73 reference docs.",
"description":"47 marketing skills across 8 pods: Content, SEO & AEO, CRO, Channels, Growth, Intelligence, Sales enablement, and X/Twitter growth. 62 Python tools, 89 reference docs.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
@ -39,7 +39,7 @@
{
"name":"c-level-skills",
"source":"./c-level-advisor",
"description":"33 C-level advisory skills + c-level-agents plugin layer: virtual board of directors (CEO, CTO, COO, CPO, CMO, CFO, CRO, CISO, CHRO) plus General Counsel, CDO, CAIO, CCO, and VP of Engineering (DORA delivery throughput analyzer, engineering hiring funnel calculator with conversion + pipeline gap, eng team structure designer with squad/tribe + manager-trigger), executive mentor, founder coach, orchestration (Chief of Staff, board meetings, decision logger), strategic capabilities (board deck builder, scenario war room, competitive intel, M&A playbook), culture frameworks, and 13 cs-* persona agents + 21 /cs:* slash commands (founder-mode router, office-hours intake, multi-role boardroom, strategic sprint pipeline, cross-model consensus, cooldown freeze).",
"description":"33 C-level advisory skills (install the separate companion c-level-agents plugin for the persona layer): virtual board of directors (CEO, CTO, COO, CPO, CMO, CFO, CRO, CISO, CHRO) plus General Counsel, CDO, CAIO, CCO, and VP of Engineering (DORA delivery throughput analyzer, engineering hiring funnel calculator with conversion + pipeline gap, eng team structure designer with squad/tribe + manager-trigger), executive mentor, founder coach, orchestration (Chief of Staff, board meetings, decision logger), strategic capabilities (board deck builder, scenario war room, competitive intel, M&A playbook), culture frameworks. The 13 cs-* persona agents + 21 /cs:* slash commands (founder-mode router, office-hours intake, multi-role boardroom, strategic sprint pipeline, cross-model consensus, cooldown freeze) ship in the companion c-level-agents plugin.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
@ -60,7 +60,7 @@
},
{
"name":"c-level-agents",
"source":"./c-level-advisor/c-level-agents",
"source":"./c-level-agents",
"description":"Founder-mode executive team plugin: 13 cs-* C-suite agents (CFO, CMO, CRO, CPO, COO, CHRO, CISO, Chief of Staff, General Counsel, Chief Data Officer, Chief AI Officer, Chief Customer Officer, VP of Engineering) with distinct cognitive voices, plus 21 /cs:* slash commands — forcing-question office hours (CFO/CMO/CPO/CRO/CTO/CISO/GC/CDO/CAIO/CCO/VPE reviews), strategic sprint pipeline (brief → boardroom → decide → execute → post-mortem), and meta routing (/cs:founder-mode auto-router, /cs:onboard, /cs:cross-eval multi-model consensus, /cs:freeze cooldown lock). Wraps the 33 c-level skills with cognitive gearing, persona voice, and artifact-driven handoffs. The business-domain answer to YC Garry Tan's gstack.",
"description":"Company Architect: builds a business from scratch as an OKF (Open Knowledge Format) bundle — a tree of versionable .md files with a frontmatter type, links forming a graph, and reserved index.md/log.md, readable by humans and agents alike. Guides the founder through a 12-phase interview (foundation, strategy, market, financial, sales, marketing, product, operations, tech, people, legal, governance), one phase at a time, and generates conformant markdown concepts. 3 stdlib tools: scaffold_bundle (bundle scaffold), okf_linter (validates type/reserved files/links), index_generator (regenerates the index.md files). Standalone-installable; also bundled in c-level-skills. In English.",
"description":"Curate auto-memory, promote learnings to CLAUDE.md and rules, extract patterns into skills. Ships 5 slash commands (/si:review, /si:promote, /si:extract, /si:status, /si:remember) and 2 sub-agents (memory-analyst, skill-extractor).",
"version":"2.9.0",
"description":"Curate auto-memory, promote learnings to CLAUDE.md and rules, extract patterns into skills. Ships 5 slash commands (/si:memory-review, /si:promote, /si:extract, /si:memory-status, /si:remember) and 2 sub-agents (memory-analyst, skill-extractor).",
"version":"2.9.1",
"author":{
"name":"Alireza Rezvani"
},
@ -415,7 +436,7 @@
{
"name":"autoresearch-agent",
"source":"./engineering/autoresearch-agent",
"description":"Autonomous experiment loop — optimize any file by a measurable metric. 5 slash commands (/ar:setup, /ar:run, /ar:loop, /ar:status, /ar:resume), 8 built-in evaluators, configurable loop intervals (10min to monthly).",
"description":"Autonomous experiment loop — optimize any file by a measurable metric. 5 slash commands (/ar:setup, /ar:run, /ar:loop, /ar:ar-status, /ar:ar-resume), 8 built-in evaluators, configurable loop intervals (10min to monthly).",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
@ -480,7 +501,7 @@
{
"name":"agenthub",
"source":"./engineering/agenthub",
"description":"Multi-agent collaboration — spawn N parallel subagents that compete on code optimization, content drafts, research approaches, or any task that benefits from diverse solutions. 7 slash commands (/hub:init, /hub:spawn, /hub:status, /hub:eval, /hub:merge, /hub:board, /hub:run), agent templates, DAG-based orchestration, LLM judge mode, message board coordination.",
"description":"Multi-agent collaboration — spawn N parallel subagents that compete on code optimization, content drafts, research approaches, or any task that benefits from diverse solutions. 7 slash commands (/hub:hub-init, /hub:spawn, /hub:hub-status, /hub:eval, /hub:merge, /hub:board, /hub:run), agent templates, DAG-based orchestration, LLM judge mode, message board coordination.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
@ -841,6 +862,26 @@
],
"category":"development"
},
{
"name":"book-to-skill",
"source":"./engineering/book-to-skill",
"description":"Converts books, documentation folders, and source collections (PDF, EPUB, DOCX, HTML, Markdown, RST, AsciiDoc, RTF, MOBI/AZW) into structured agent skills: a master SKILL.md with core frameworks and a topic index, on-demand chapter files, a glossary, a patterns file, and a decision cheatsheet. Ships 4 stdlib-only tools (multi-format extractor with invisible-Unicode sanitization, four-family generated-skill validator covering frontmatter/safety/budget/index, pre- and post-flight token budget estimator with a worth-converting verdict, and a plugin emitter that wraps a compiled skill as an installable claude-skills package behind a rights gate), 5 references citing 7-8 sources each, a cs-book-to-skill agent, and /cs:book-to-skill + /cs:book-to-plugin commands. Derived from virgiliojr94/book-to-skill (MIT).",
"description":"A disciplined coding pipeline that grounds code in verified structure before a line is written: Discuss -> Map -> Decompose -> Execute -> Verify, with a lazy-senior-dev YAGNI ladder that deletes unnecessary code first. No invented APIs, no assumed imports, no placeholder code. Opt-in for high-stakes, complex, or multi-file work; not for trivial edits. Synthesizes four MIT/open-source projects (Ralph atomic loop, GSD Core context engineering, Graphify KNOWN/INFERRED/UNKNOWN mapping, Ponytail lazy-senior hierarchy). Contributed via PR #854.",
"version":"2.10.3",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"zero-hallucination",
"coding-pipeline",
"context-engineering",
"codebase-mapping",
"yagni",
"plan-before-code",
"engineering"
],
"category":"development"
},
{
"name":"agent-harness",
"source":"./engineering/agent-harness",
"description":"Turn any domain folder of skills into a bounded agentic loop: a manifest builder inventories a domain's skills/tools/checks, a goal compiler turns a goal into a verifiable task plan (refusing vague goals with forcing questions), and a JSON-backed loop controller drives execute->verify->close with retry caps, controller-run verification (no verification theater), human escalation on exhausted budgets, and a close gate that refuses while any task is unverified or unwaived. Ships 3 stdlib Python tools, 18 committed per-domain harness manifests + JSON schema, 3 references citing the 2024-2026 agent-harness canon (Anthropic long-running harnesses, verifier's law, SWE-agent, Ralph loop, Cognition), harness-runner agent + /cs:harness command. Use when an agent or subagent should pick up a goal, define its tasks, complete and verify them, and close the loop.",
"version":"1.0.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"agent-harness",
"agentic-loop",
"verification-gate",
"goal-compiler",
"loop-controller",
"stop-conditions",
"escalation",
"multi-agent",
"engineering"
],
"category":"development"
},
{
"name":"memory-engineering",
"source":"./engineering/memory-engineering",
"description":"Engineer an agent's forgetting, not just its remembering. Four deterministic stdlib scripts implement the four lenses of agent memory: a cost profiler that splits construction from query spend and reports cost per correct answer (construction energy exceeds total query energy across 300 queries in the Stanford characterization); an architecture picker that scores the four paradigm families — long-context, flat RAG, structure-augmented RAG, agentic — disqualifies on hard constraints, names the cost the winning choice makes you pay, and refuses to pick when the top two tie; a density auditor that classifies every record in a memory directory or JSONL export as FACT / SKILL / LOG / PROSE, finds near-duplicates, and flags stale wording; and a forgetting-policy linter that fails any design with no forgetting rule. Ships cs-memory-engineer agent, /cs:memory-engineering and /cs:forgetting-audit commands, 4 references, and a seven-question forcing worksheet.",
"version":"2.11.2",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"agent-memory",
"memory-engineering",
"forgetting-policy",
"context-engineering",
"rag",
"kv-cache",
"retention",
"write-path-cost",
"engineering"
],
"category":"development"
},
{
"name":"skill-doctor",
"source":"./engineering/skill-doctor",
"description":"Grade an agent setup from real conversation history — a rebuild of warpdotdev/common-skills' skill-doctor (MIT). Harvests recent local Claude Code and Codex sessions scoped to one repo, condenses and secret-redacts transcripts (12-pattern redactor, chmod-0600 artifacts, nothing uploaded), has the agent judge each transcript against two verbatim-preserved rubrics (efficiency, code quality — labels only), then runs a deterministic aggregation gate that derives every number from the label tables, refuses scores for unsampled sessions and suggestions that cite no scored session, and renders one self-contained zero-JS HTML report (dark-mode, print-to-PDF). Proposed skill edits stay staged as diffs until an explicit per-skill yes; zero suggestions is a valid, reportable success. Ships cs-skill-doctor agent, /cs:skill-doctor command, 3 stdlib tools, 3 references citing 7 sources each.",
"version":"2.11.2",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"skill-doctor",
"skill-grading",
"session-mining",
"llm-as-judge",
"rubric-scoring",
"transcript-analysis",
"skill-coverage",
"secret-redaction",
"agent-evals",
"engineering"
],
"category":"development"
},
{
"name":"grill-me",
"source":"./engineering/grill-me",
@ -1031,6 +1155,117 @@
],
"category":"productivity"
},
{
"name":"roast",
"source":"./productivity/roast",
"description":"Pressure-test a business idea before you build it. Convenes a 5-angle adversarial panel — The Critic (what kills this?), The Champion (the 10x upside?), The Analyst (does the logic hold?), The Investigator (what does the market say?), The Customer (would I actually pay?) — fired in parallel as independent reviewers, then a Judge synthesizes one GO / RESHAPE / KILL verdict with explicit confidence and the cheapest 48-hour test to de-risk it. Never averages the scores: a weighted synthesizer with demand/fatal-flaw/logic veto gates produces the call, backed by deterministic stdlib tools.",
"version":"2.10.3",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"roast",
"pressure-test",
"stress-test",
"idea-validation",
"adversarial-panel",
"go-no-go",
"anti-sycophancy",
"productivity"
],
"category":"productivity"
},
{
"name":"fable-goal",
"source":"./productivity/fable-goal",
"description":"Convert a rambling description of a desired outcome into one polished, autonomous /goal prompt ready to paste into a fresh session. Extracts deliverable/quantity/stakes/tools/destination, asks at most one question batch, verifies every named resource against the live environment, writes a 150-350 word prose prompt with the seven-part anatomy, and self-checks six binary criteria before delivering. The output is a single copy-paste prompt, never the build itself.",
"version":"2.11.1",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"goal-prompt",
"prompt-writing",
"autonomous-agent",
"prompt-engineering",
"fable",
"ramble-to-prompt",
"productivity"
],
"category":"productivity"
},
{
"name":"weekly-review",
"source":"./productivity/weekly-review",
"description":"GTD weekly-review loop. Scans the workspace for open loops (unchecked boxes, TODO/FIXME, stale files), walks the three-phase GET CLEAR / GET CURRENT / GET CREATIVE checklist with a refusal gate (review is never COMPLETE while a mandatory GET CURRENT step is missing), and audits commitments for stalled / no-next-action / someday candidates with a 0-100 health score. Fills the periodic-review gap from audit/productivity-2026-07.",
"version":"2.11.2",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"weekly-review",
"gtd",
"open-loops",
"review-cadence",
"productivity",
"commitments"
],
"category":"productivity"
},
{
"name":"deep-work",
"source":"./productivity/deep-work",
"description":"Deep Work day planner. Classifies tasks deep vs shallow with a shallow-work budget verdict (plus the recent-graduate forcing question), builds a time-blocked schedule (deep blocks of 90+ minutes first, shallow batched, buffers, refuses more than 4 hours of deep demand), and logs focus sessions against a weekly deep-hours target with streaks. Fills the time/attention-management gap from audit/productivity-2026-07.",
"version":"2.11.2",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"deep-work",
"time-blocking",
"focus",
"shallow-work",
"productivity",
"attention"
],
"category":"productivity"
},
{
"name":"meetings",
"source":"./productivity/meetings",
"description":"Meeting discipline. Cost-gates every meeting before it exists (MEET / ASYNC / NOT-READY verdicts with real dollar cost incl. optional refocus overhead), builds timeboxed agendas that refuse topics without a desired outcome (decision topics first), and extracts owned action items from raw notes with ORPHAN / NO-DUE flags. Fills the meeting-hygiene gap from audit/productivity-2026-07.",
"version":"2.11.2",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"meetings",
"meeting-cost",
"agenda",
"action-items",
"productivity",
"async"
],
"category":"productivity"
},
{
"name":"swedish-mentor",
"source":"./productivity/swedish-mentor",
"description":"CEFR-leveled Swedish-learning mentor: two-question placement probe, listening-first learning paths, vetted YouTube/podcast catalog (SFI, Radio Sweden pa latt svenska, Klartext), never-invent-a-URL rule.",
"version":"2.11.2",
"author":{
"name":"mh-mansouri"
},
"keywords":[
"productivity",
"language-learning",
"swedish",
"cefr",
"sfi",
"mentor"
],
"category":"productivity"
},
{
"name":"landing",
"source":"./marketing/landing",
@ -1050,6 +1285,28 @@
],
"category":"marketing"
},
{
"name":"linkedin",
"source":"./marketing/linkedin",
"description":"Organic LinkedIn presence, end to end, with LinkedIn's own rules enforced in code. Orchestrator (context: fork) gates every request against User Agreement §8.2 — refusing automation, scraping, engagement pods, bulk DMs, fake identity and fabricated proof, each with a compliant substitute — then routes to profile / strategy / content / engagement / analytics. Headline and whole-profile scoring with fixes ranked by points per hour; positioning brief with a mandatory exclusion list; cadence priced against real hours with a 90-minute floor; newsletter eligibility + six-month sustainability gate; post linter blocking on engagement bait and screen-reader-hostile Unicode pseudo-bold; repurposing with a reuse ledger; capped commenting roster and template-refusing outreach; analytics that test patterns against a seeded permutation null and refuse to conclude below 10 posts. 17 stdlib tools, 15 references with per-claim confidence levels. No credentials, no API calls, nothing auto-sent. Answers discussion #934.",
"version":"2.12.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"linkedin",
"personal-brand",
"organic-growth",
"content-strategy",
"profile-optimization",
"outreach",
"newsletter",
"social-media",
"thought-leadership",
"career-change"
],
"category":"marketing"
},
{
"name":"pulse",
"source":"./research/pulse",
@ -1070,6 +1327,25 @@
],
"category":"research"
},
{
"name":"deep-research",
"source":"./research/deep-research",
"description":"Disciplined multi-source meta-research for high-stakes questions — the heavyweight alternative to the fast research router. 9-phase pipeline (reframe into falsifiable hypotheses, plan, capability discovery, parallel sub-agent fan-out, score & triangulate, synthesize + adversarial pass, verify, refresh targets). Triangulates every thesis against >=3 independent differently-typed sources; per-source files with verbatim quotes; never fabricates a citation. Auditable, reusable folder + delta-update refresh protocol. Contributed via PR #851.",
"version":"2.10.3",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"research",
"deep-research",
"meta-research",
"triangulation",
"adversarial",
"multi-source",
"hypothesis-validation"
],
"category":"research"
},
{
"name":"litreview",
"source":"./research/litreview",
@ -1211,6 +1487,25 @@
],
"category":"research"
},
{
"name":"deepread",
"source":"./research/deepread",
"description":"Evidence-first reading of supplied documents. Five modes (quick/deep/map/feynman/book), claim-reason-evidence decomposition, confidence labels, evidence ledger, knowledge maps, Feynman teach-back.",
"version":"2.11.2",
"author":{
"name":"xiehuan123"
},
"keywords":[
"research",
"reading",
"deep-read",
"feynman",
"knowledge-map",
"evidence",
"comprehension"
],
"category":"research"
},
{
"name":"aeo",
"source":"./marketing-skill/skills/aeo",
@ -1255,6 +1550,26 @@
],
"category":"development"
},
{
"name":"skillopt-sleep",
"source":"./engineering/skillopt-sleep",
"description":"Nightly offline self-evolution for this repo's Claude agent: harvests past Claude Code sessions (read-only), mines recurring tasks, replays them offline on your own API budget, and consolidates learnings into validated CLAUDE.md memory and SKILL.md skills behind a held-out gate, staged for review (never auto-applied). Verbatim vendor of microsoft/SkillOpt's stdlib-only skillopt_sleep engine + Claude Code plugin surface (MIT).",
"description":"A universal scraping skill with intelligent routing, token budget tracking, and quota awareness. Supports Firecrawl (BYOK, free-tier compatible) and local Python extraction via requests/BeautifulSoup/pandas.",
"version":"2.9.0",
"author":{
"name":"Mehansh Barthwal",
"url":"https://github.com/mehanshbarthwal-lab"
},
"keywords":[
"scraping",
"data-extraction",
"firecrawl",
"beautifulsoup4",
"pandas",
"automation"
],
"category":"development"
},
{
"name":"research-ops-skills",
"source":"./research-ops",
"description":"Enterprise / cross-functional Research Operations domain — the managed counterpart to the academic research/ domain. v2.9.0 ships 5 skills: orchestrator (context: fork) + clinical-research (study design: protocol synopsis + endpoint selection + sample-size/power for means/proportions/survival + phase-gate feasibility) + research-finance (R&D program budgeting with F&A split + burn/runway + capitalize-vs-expense routing + portfolio ROI) + market-research (TAM/SAM/SOM computed both top-down and bottoms-up + survey sampling with FPC and per-segment minima + Kotler segmentation scoring) + product-research (goal-matched study design + method-based saturation with confidence + insight synthesis that flags single-source anecdotes). Hard rules: clinical outputs are estimates with a named clinical owner (never fact), finance outputs surface assumptions and route capex-vs-opex to a named finance owner (never auto-decide), market sizes show method + assumptions (never a single number), product insights require recurrence across independent participants. Each sub-skill ships per-skill onboarding questions (onboard.py), a customization config consumed by every tool, and an isolated opt-in autoresearch evaluator (ar_evaluator.py) bridging to engineering/autoresearch-agent. 24 stdlib Python tools (12 analysis + 12 onboarding/customization/autoresearch), 12 reference docs. Distinct from ra-qm-team (regulatory/QM submission), finance (corporate close/valuation), research/grants (funding discovery), product-team (persona/journey/live experiments), marketing-skill (campaign analytics).",
"description":"Enterprise / cross-functional Research Operations domain — the managed counterpart to the academic research/ domain. v2.9.0 ships 5 skills: orchestrator (context: fork), clinical-research (protocol synopsis, endpoint selection, sample-size/power for means/proportions/survival, phase-gate feasibility), research-finance (R&D budgeting with F&A split, burn/runway, capitalize-vs-expense routing, portfolio ROI), market-research (TAM/SAM/SOM top-down and bottoms-up, survey sampling with FPC, Kotler segmentation), and product-research (goal-matched study design, method-based saturation, insight synthesis flagging single-source anecdotes). Hard rules: outputs are estimates routed to a named clinical or finance owner, market sizes show method + assumptions, product insights require recurrence across independent participants. 24 stdlib Python tools, 12 reference docs. Distinct from ra-qm-team, finance, research/grants, product-team, and marketing-skill.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
@ -1381,6 +1715,384 @@
"grill-with-docs"
],
"category":"research-ops"
},
{
"name":"markdown-html-skills",
"source":"./markdown-html",
"description":"Convert long markdown files into world-class single-file interactive HTML — DOMAIN COMPLETE at v2.10.3 (5 skills). v2.10.3 adds md-slides, the slide-deck converter (arrow/Space/PgDn/Home/End/P navigation, presenter mode with clock + speaker notes + next-slide preview, URL-hash deep linking, @media print page-per-slide for browser-native PDF export; vanilla JS only; Prism.js opt-in via --syntax). Joins md-review (v2.10.2 code-review converter: 2-col diff, severity-tagged margin annotations, WCAG-1.4.1 badges, named reviewer footer), md-document (v2.10.1 long-form: sticky TOC, scrollspy, search, code-copy, Prism autoloader), markdown-html-orchestrator (v2.10.0 context: fork; deterministic doc-type classifier), and design-system (v2.10.0 onboarding wizard; WCAG-AA 12-token palette). 15 stdlib-only Python tools, 15 references, 4 template assets. Inspired by Thariq Shihipar's Claude Code HTML output essay.",
"version":"2.10.3",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"markdown",
"html",
"documentation",
"code-review",
"slides",
"design-system",
"single-file-html",
"brand-palette",
"wcag",
"onboarding",
"customization",
"shihipar",
"matt-pocock",
"grill-with-docs",
"context-fork"
],
"category":"documentation"
},
{
"name":"youtube-full",
"source":"./marketing-skill/skills/youtube-full",
"description":"YouTube transcripts, video search, channel browsing, playlist extraction, and upload monitoring via TranscriptAPI. BYOK — 100 free credits. OSS fallbacks: youtube-transcript-api / yt-dlp.",
"version":"2.9.0",
"author":{
"name":"therohitdas"
},
"keywords":[
"youtube",
"transcript",
"video",
"channel",
"playlist",
"search",
"content-monitoring",
"marketing",
"transcriptapi"
],
"category":"marketing"
},
{
"name":"compliance-os",
"source":"./compliance-os",
"description":"Compliance OS — meta-orchestrator for multi-framework compliance programs spanning 9 frameworks (ISO 27001, ISO 13485, ISO 42001, ISO 14971, EU AI Act, MDR 745, GDPR, SOC 2, FDA QSR). Framework selector, cross-framework control mapper, audit simulator, and consolidated evidence-pool generator (stdlib Python), plus 3 cs-* compliance agents and 3 /cs:* readiness commands.",
"description":"Snowflake SQL, data pipelines (Dynamic Tables, Streams+Tasks), Cortex AI functions, Snowpark Python, and dbt integration. Includes query helper script, reference guides, and troubleshooting.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"snowflake",
"sql",
"data-pipelines",
"snowpark",
"dbt",
"cortex",
"data-warehouse"
],
"category":"development"
},
{
"name":"behuman",
"source":"./engineering/behuman",
"description":"Self-Mirror consciousness loop for human-like AI responses. Adds inner dialogue (Self → Mirror → Conscious Response) to make AI output feel authentic, not robotic. Zero dependencies — pure prompt technique.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"prompting",
"voice",
"authenticity",
"self-mirror",
"writing"
],
"category":"development"
},
{
"name":"claude-coach",
"source":"./engineering/claude-coach",
"description":"Personal Claude power-user coach. Delivers a personalized, ranked cheat-code glossary on first activation, then surfaces at most one tip per turn when it would genuinely improve the next attempt. Ships cheat-codes glossary, coaching-rules decision tree, three stdlib Python tools, cs-claude-coach agent, and /cs:claude-coach command.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"claude-code",
"coaching",
"power-user",
"tips",
"productivity"
],
"category":"development"
},
{
"name":"grill-with-docs",
"source":"./engineering/grill-with-docs",
"description":"Docs-anchored grilling session — interrogates a plan against the project's existing language (CONTEXT.md) and recorded decisions (docs/adr/), updating those files inline as terminology and decisions crystallise. Derived from Matt Pocock's MIT-licensed grill-with-docs with stdlib validators (CONTEXT.md linter, ADR scanner, glossary-code consistency), reference docs, cs-grill-with-docs agent, and /cs:grill-with-docs command.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"planning",
"adr",
"context",
"ubiquitous-language",
"interrogation",
"matt-pocock"
],
"category":"development"
},
{
"name":"llm-cost-optimizer",
"source":"./engineering/llm-cost-optimizer",
"description":"Cut LLM API spend via model routing, prompt caching, prompt compression, and per-feature cost observability. Use when AI costs are too high, choosing between models, or launching an AI feature without cost architecture. NOT for RAG design or prompt quality (separate skills).",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"llm",
"cost-optimization",
"token-usage",
"model-routing",
"prompt-caching",
"observability"
],
"category":"development"
},
{
"name":"prompt-governance",
"source":"./engineering/prompt-governance",
"description":"Manage prompts in production at scale: prompt versioning, A/B testing, prompt registries, regression prevention, and eval pipelines for production AI features. NOT for writing individual prompts, RAG design, or cost reduction (separate skills).",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"prompts",
"versioning",
"ab-testing",
"registry",
"evals",
"regression",
"production-ai"
],
"category":"development"
},
{
"name":"business-investment-advisor",
"source":"./finance/business-investment-advisor",
"description":"Business investment analysis and capital allocation advisor. Evaluates equipment, real estate, new-business, hiring, and technology investments with ROI, IRR, NPV, payback period, build-vs-buy, lease-vs-buy, and vendor evaluation frameworks for allocating limited budget.",
"description":"Video content strategy: video scripts, YouTube channel optimization and SEO, short-form video pipelines (Reels, TikTok, Shorts), and repurposing long-form content into video. NOT for written blog content or caption-only social posts (separate skills).",
"description":"EU AI Act (Regulation (EU) 2024/1689) operational compliance specialist: AI system risk classifier (Articles 5/6/50 + Annex III), conformity assessment planner (Article 43 + Annex IV checklist), and obligation tracker (provider/deployer/importer/distributor + GPAI Articles 51-55). Article-level references and cross-framework mapping to ISO 42001, NIST AI RMF, GDPR. Stdlib-only.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"eu-ai-act",
"compliance",
"risk-classification",
"conformity-assessment",
"gpai",
"ai-regulation"
],
"category":"compliance"
},
{
"name":"compliance-team-iso42001",
"source":"./ra-qm-team/compliance-team-iso42001",
"description":"ISO/IEC 42001:2023 AI Management System (AIMS) specialist: AIMS gap analyzer (Clauses 4-10 coverage + remediation priority), AI risk register builder (Annex A 38 controls per ISO 23894), and AIMS audit scheduler (Clause 9.2 cadence + auditor independence). Cross-framework mapping to EU AI Act, NIST AI RMF, ISO 23894. Stdlib-only.",
"version":"2.9.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"iso-42001",
"aims",
"ai-governance",
"risk-register",
"internal-audit",
"compliance"
],
"category":"compliance"
},
{
"name":"collab-proof",
"source":"./engineering/collab-proof",
"description":"Assisted retrospective: after a session, calibrates what Claude contributed vs what the developer drove. LLM-assessed 4-frame analysis with explicit rubric, zero dependencies.",
"version":"1.0.0",
"author":{
"name":"dong7812",
"url":"https://github.com/dong7812"
},
"keywords":[
"ai-collaboration",
"session-retrospective",
"git-analysis",
"decision-logging",
"collab-proof"
],
"category":"engineering"
},
{
"name":"human-gate",
"source":"./engineering/human-gate",
"description":"Human-verification gate for an agent loop: builds a single-file review page (the page itself makes no network request; a reviewed HTML artifact's own https: assets still load), collects batched feedback as structured batch.v1 data instead of chat prose, and refuses to close while a BLOCKER is open, the reviewer is unnamed, or nobody has reviewed. Non-blocking, headless-guarded, round-capped. Stdlib-only.",
"version":"1.0.0",
"author":{
"name":"Alireza Rezvani",
"url":"https://alirezarezvani.com"
},
"keywords":[
"human-in-the-loop",
"review-gate",
"sign-off",
"agent-loop",
"verification",
"batched-feedback",
"human-gate"
],
"category":"engineering"
},
{
"name":"agent-launcher-skills",
"source":"./agent-launcher",
"description":"Build, launch, grade, and schedule Claude Managed Agents (CMA) in your own Anthropic account — a plugin re-implementation of Anthropic's launch-your-agent reference skill (Apache-2.0; independent, not a fork). Every session starts with a goal (./my-agent/goal.json, opt-in SessionStart hook, driven by /cs:goal); loop_compiler.py compiles it into a bounded grade->iterate loop (max_iterations 1..20), a recurring cron scheduled-deployment loop, or a single-pass interview->stage->launch workflow. 6 skills: orchestrator (context: fork goal router) + interview + stage-launch + grade-iterate + run-without-you + wrap-up. 18 stdlib-only deterministic scaffolders (no network/API calls; live launches emitted as BYOK curl that never prints the key), 4 agents, 8 commands, hooks, 5 references, 4 assets. Validators enforce CMA limits. Distinct from engineering/agent-harness (generic domain loop) and write-a-skill (authors Claude Code skills, not CMAs).",
"version":"2.11.2",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"claude-managed-agents",
"cma",
"agent-launcher",
"launch-your-agent",
"managed-agent",
"session-goal",
"grade-iterate",
"max-iterations",
"scheduled-deployment",
"run-without-you",
"byok",
"build-sheet",
"context-fork"
],
"category":"agent-development"
},
{
"name":"agent-memory",
"source":"./engineering/agent-memory",
"description":"A four-tier memory ladder for Claude Code where promotion is earned by recurrence, not asserted by confidence. L0 raw transcripts are never injected; L1 candidate atoms are gitignored and recalled on lexical relevance per prompt; L2 project context loads each session start; L3 stable persona is always loaded. L1 to L2 needs three distinct sessions spanning two distinct calendar days (a stated claim needs two; a verified claim is the only single-observation path); L2 to L3 needs two projects and thirty days. Two gates refuse rather than guess: a claim altered by the redaction pass never promotes on evidence alone, and a contradicted claim freezes until a human resolves it. Three hooks run the loop unattended and every one fails open. Nothing reaches a committed CLAUDE.md without an explicit human adopt. Ships 5 stdlib scripts, 3 hooks, a cs-memory-curator agent, /cs:memory, a JSON schema, and a 69-check validator. Concept from TencentCloud/TencentDB-Agent-Memory (MIT); no upstream code included.",
"version":"2.11.2",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"agent-memory",
"memory-tiers",
"claude-md",
"hooks",
"session-memory",
"promotion-gates",
"provenance",
"redaction",
"engineering"
],
"category":"development"
},
{
"name":"spinning-up-deep-rl",
"source":"./engineering/spinning-up-deep-rl",
"description":"Knowledge base compiled from OpenAI's Spinning Up in Deep RL (MIT, Joshua Achiam) by engineering/book-to-skill. A resident core carries the RL optimization problem, the model-free taxonomy, the policy-gradient template with its five valid weights, the safe-step family (VPG to TRPO to PPO) and the overestimation family (DDPG to TD3 and SAC); 20 on-demand chapters cover key concepts and MDPs, the algorithm taxonomy and model bias, the policy gradient derivation with the log-derivative trick and EGLP lemma, Achiam's researcher essay, the key-papers topic map, the exercises including the silent DDPG broadcasting bug, the benchmark parity disclosure, one chapter per algorithm, and the logger/MPI/ExperimentGrid utilities. Ships a glossary, a patterns file with 16 techniques, a decision cheatsheet with thresholds, a cs-spinning-up-deep-rl agent and /cs:spinning-up-deep-rl. Structured study notes, not a reproduction of the source.",
"version":"1.0.0",
"author":{
"name":"Alireza Rezvani"
},
"keywords":[
"knowledge-base",
"book-to-skill",
"reinforcement-learning",
"deep-rl",
"policy-gradient",
"ppo",
"sac",
"td3",
"openai-spinning-up",
"engineering"
],
"category":"development"
},
{
"name":"deep-learning-book",
"source":"./engineering/deep-learning-book",
"description":"Study companion for the Deep Learning textbook by Goodfellow, Bengio & Courville (MIT Press, 2016), free to read at deeplearningbook.org. Twenty chapter files, a glossary, patterns and a cheatsheet index the whole book, and a delta reference dates it against 2026 practice with per-claim confidence levels: double descent qualifying the U-curve, AdamW splitting weight decay from L2, transformers displacing Chapter 10's recurrence, diffusion growing out of Chapter 18's score matching. Four stdlib tools make it executable — a prerequisite-closed reading-path planner that refuses goals the book does not cover, a training diagnostic running Chapter 11's rules in priority order so a NaN is never reported as overfitting, a capacity planner that ranks 'shrink the model' last when overparameterized, and a parameter/FLOP/activation-memory calculator that refuses a stack whose shapes do not connect. A companion, not a compilation: the book is copyrighted, so nothing here reproduces its text.",
"description":"223 production-ready skills, 23 agents, and 298 Python tools across 9 domains — engineering, marketing, product, compliance, C-level advisory, and more. The largest open-source skills library for AI coding agents.",
"version":"2.12.0",
"description":"388 production-ready skills across 20 domains — engineering, marketing, product, compliance, C-level advisory, research, business operations, and more. 727 Python tools, 842 reference guides, 118 agents (cs-* + personas), 150 slash commands, 99 marketplace plugins. The largest open-source skills library for AI coding agents.",
"author":{
"name":"Alireza Rezvani",
"url":"https://alirezarezvani.com"
@ -27,8 +27,8 @@
"type":"cli",
"composerIcon":"./assets/icon.png",
"displayName":"Claude Code Skills",
"shortDescription":"223 production-ready skills for AI coding agents across 9 domains",
"longDescription":"The largest open-source skills library for AI coding agents. 223 skills covering engineering (architecture, DevOps, security, AI/ML), marketing (SEO, CRO, content), product management, C-level advisory, regulatory compliance (ISO 13485, SOC 2, GDPR), project management, business growth, and finance. Includes 298 stdlib-only Python CLI tools, 416 reference guides, 23 orchestration agents, and 22 slash commands. Works with Codex, Claude Code, Gemini CLI, Cursor, Aider, Windsurf, and 5 more tools.",
"shortDescription":"388 production-ready skills for AI coding agents across 20 domains",
"longDescription":"The largest open-source skills library for AI coding agents. 388 skills covering engineering (architecture, DevOps, security, AI/ML, agent tooling), marketing (SEO, AEO, CRO, content), product management, C-level advisory, regulatory compliance (ISO 13485, SOC 2, GDPR), project management, research and research operations, business operations, commercial, finance, and personal productivity. Includes 727 stdlib-only Python CLI tools, 842 reference guides, 118 orchestration agents, and 150 slash commands. Works with Codex, Claude Code, Gemini CLI, Cursor, Hermes Agent, Mistral Vibe, and 7 more tools.",