Persona-add scaling refactor. Reduces the contributor surface for
adding a new persona from ~85 hand-written touchpoints to ~7 source
files, and introduces a featured/catalog tier so the landing demos
don't grow unboundedly.
No behavior change for the five installed personas.
Schema additions to rules//_meta.json
- featured (bool): whether the persona appears in landing-page demos.
All five current personas set featured: true. Personas #6+ default
to featured: false (catalog tier) β they appear in tables and
dropdowns but not in hand-written demo prose. load_meta enforces
strict-bool typing. - register_short (string): one-line summary used by table generators
across surfaces. Single source vs the previous three different
per-surface descriptions. load_meta enforces non-empty and rejects
table-breaking characters (|, newlines, backticks).
scripts/render.py extensions (~750 lines added)
-
Marker-based partial injection: render_zone, inject_marker,
check_marker, find_markers. Multi-format markers (HTML comments
for .md/.mdc, # comments for .sh/.yml/.yaml). Marker ids enforced
as [a-z0-9-]+ across all four functions. Recursion guard refuses
content containing the same marker id. -
JSON field-replace: update_json_field / check_json_field. Compares
parsed-data semantic equality (not text-equality), so hand-edited
4-space-indented JSON is NOT rewritten by no-op mutators. Accepts
both mutate-in-place and return-new-dict mutator styles. -
Featured/catalog filters with strict-bool semantics.
-
Schema validation in load_meta: required fields, exactly one default
flavor, non-empty/safe register_short, non-empty triggers,
strict-bool featured. Catches contributor typos at the
canonical-source boundary. -
Eight pure-function partial generators (gen_persona_table,
gen_personas_command_table, gen_slash_commands_table,
gen_subagents_table, gen_trigger_phrases_list, gen_cp_skills_block,
gen_hooks_allow_list, gen_dramaturg_skills,
gen_personas_catalog_index_body). Empty input raises ValueError.
Trigger text is markdown-escaped to handle special characters. -
Two new full-file outputs: commands/personas.md and agents/dramaturg.md.
Body templates extracted to scripts/templates/ β keeps prose edits
in plain markdown. commands/personas.md fixes the v1.1.0 stale
4-row table bug (was missing ontario-bud). -
All Path.read_text / write_text now pass encoding="utf-8" (was
inheriting platform default β broken on Windows cp1252). -
Consumer-file marker injection (inject_consumer_markers /
check_consumer_markers). Always loads the FULL persona set,
ignoring the caller's subset, soscripts/render.py shakespeare
cannot silently corrupt README/docs/hooks tables. Per-zone
errors are batched into one ValueError so contributors see all
failing zones at once. Distinguishes "marker pair missing"
(structural) from "content drifted" in error messages.
Marker-injected zones in consumer files
13 zones across README.md, docs/index.md, docs/personas/index.md,
docs/subagents.md, docs/install/{claude-code,index}.md,
hooks/{activate,session-start}.sh. Content between markers is
auto-rendered from rules//_meta.json; surrounding prose
stays hand-edited. CI gate (--check) detects manual edits inside
zones and fails the PR.
README trim
The per-persona Demo blocks (~80 lines of hand-curated flavor demos
for 4 of 5 personas, never updated for ontario-bud) are replaced
with one short example + link to the docs site. Removes ongoing
per-flavor demo maintenance.
Tests: 51 β 124 (+73)
New tests/test_partial_injection.py covers marker mechanism, JSON
field-replace, featured filter, load_meta validation (11 rejection
cases), empty-input guards, markdown escaping, recursion guard,
consumer-marker wiring (subset-render protection, missing-vs-drift
errors, batched failures), and registry validity (every registered
marker exists in its file, no duplicates).
tests/test_render.py adds TestHandWrittenPerPersonaFiles enforcing
that every persona has commands/.md and agents/-reviewer.md
with the right frontmatter β prevents the v1.1.0 bug class
(persona PR merging without these files) from recurring.
tests/test_manifest.py and tests/test_render.py replace two
hardcoded 4-tuples with dynamic enumeration of rules/. The hardcoded
lists were missing ontario-bud β masking real coverage gaps that
shipped in v1.1.0.
Documentation
CONTRIBUTING.md "Adding a new persona" section rewritten with the
new ~7-file workflow plus an explicit featured-tier promotion
process (maintainer-only, capped at 5).
CLAUDE.md replaces the two-class generated/hand-written split with
the new three-class taxonomy (fully generated / marker-injected
zones / hand-written) and points to CONTRIBUTING.md for the
add-a-persona checklist.
Commits since v1.1.0
- fix(render): Phase 2 review hardening β subset corruption, register_short validation, missing-marker error, batched inject
- chore: release v1.2.0
- refactor(render): wire marker injection into consumer files; trim README; rewrite CONTRIBUTING
- refactor(render): marker-injection foundation + featured tier + auto-gen commands/personas + dramaturg