Keep HTML as the geometry source and catch broken references, overlapping nodes, misattached edges and label-mask collisions through existing lint commands. Preserve the rendered templates and document the limits of static checks.
The skill now delegates screen sizes to the design reference. Check that route and retain baseline, breakpoint, and tablet coverage instead of requiring an obsolete inline width. Both guards were independently verified to fail when removed.
Explain product capabilities and privacy boundaries directly across locales. Align writing guidance and schemas so documents do not require filler captions, metaphors, or unsupported metrics.
Match HTMLParser line accounting to keep Unicode separators from hiding raw formulas. Restore incomplete checkout fonts from validated sources and retain healthy copies. Regression tests reproduce both failures on the previous code.
Separate HTML visibility evidence from document checks and group tests by responsibility without changing the CLI. Restore demo scan coverage after the layout split, reject missing repository surfaces, and keep generated examples out of source control.
README images and links still used repository-root paths after the
showcase, demo, and illustration assets moved under site/ and the
references under skills/kami. CLAUDE.md and docs/release.md described
the tracked dist/kami.zip flow that no longer exists. CI gains a bare
skills-CLI install gate so the layout contract cannot regress silently.
site/SKILL.md made the skills CLI install the website: any SKILL.md one
level below the repo root counts as a skill. The served copy is now
kami-skill.md behind a /SKILL.md rewrite. The transitional root config
gained explicit / and /SKILL.md rewrites. CI's --check-fonts paths are
skill-relative because verify resolves them against the skill root.
ensure-fonts.sh copies the root fonts into the skill checkout (ignored
there, filtered from the mirror and the package) so templates keep their
local-first font path.
The skill is now the whole of skills/kami and nothing else: the skills
CLI, the Claude and Codex plugin marketplaces (through the generated
plugins/kami copy), and the Claude Desktop archive all read that one
directory, so a bare npx skills add tw93/kami installs 1.6 MB instead of
the website. The website lives under site/ for Vercel's Root Directory
setting; its discovery files and the served SKILL.md are generated from
the skill. Commercial fonts and rendered examples stay at the repo root
outside the skill, dist/kami.zip is no longer tracked (release.yml builds
and uploads it), and the root vercel.json is a transitional rewrite that
keeps the site serving until the Vercel project points at site/.
check-update.sh printed the old universal-agent command on its own,
two tests pinned it, and the tracked kami.zip must match the changed
shared.py and check-update.sh.
Same four-block story as Waza: one skills CLI command that reaches
Claude Code, Codex, and Cursor through ~/.agents/skills, host plugins
with update commands inline, then Claude Desktop. The generic command
targets real agents instead of the universal directory that Claude Code
and Codex never read, and the stale warning against npx skills update
is gone: subpath installs update cleanly now. The site pages and the
site-facts gate carry the same command.
Align the shipped visual guidance with the templates, keep narrow landing pages usable, restore the approved showcase image, and make versioned release assets fail closed.
Reduce decorative weight across document examples, refresh the generated artifacts, and keep multilingual installation and FAQ guidance concise and non-redundant.
Fail closed on malformed TeX, HTML, and SVG while bounding renderer resources. Lock MathJax installation behavior and keep generated package mirrors in sync.
Make artifact briefs, capability checks, screenshots, and required assets fail closed. Preserve the last good render, move heavy tests onto the covered CI path, and require exact tag, SHA, and package identity before release upload.
The single-page density test pointed at assets/examples/one-pager.pdf,
which is build output and gitignored, so it passed locally and failed on
every fresh checkout. CI has been red since the test landed, through a
release, because local runs were treated as the verdict.
The fixture is now synthesised: an A4 page filled with parchment and
inked across the top third, which also pins the expected verdict rather
than inheriting whatever the template currently renders. Without PyMuPDF
the test skips, matching how the rest of the density suite behaves in the
lint-and-test job.
Claude-Session: https://claude.ai/code/session_01KgPeQ4ApebVquCZQXWKCfx
The homepage quick-reference table advertised a 0.5pt closed border with a
6pt radius for code blocks, a closed 0.5pt brand border for marking a
card, and an 8pt-radius data card. The first is the double-ring pitfall
templates are failed for, the second sits outside the three registered
left-rule weights, and the third uses a radius no template has ever set,
around a component (.metric) whose whole point is that it is not a card.
All five locale pages carried it, in four places each.
--check-docs reads Markdown fences, so it could not see any of this: the
site teaches in prose. site_facts.py now reads the rendered copy of every
locale page and fails on the combinations the design system forbids
outright, which is the surface where a stale recipe does the most damage,
since both readers and crawlers take it as current.
Claude-Session: https://claude.ai/code/session_01KgPeQ4ApebVquCZQXWKCfx
Three of these are the same shape: a convention with no gate behind it.
dist/kami.zip had no drift check. plugins/ has one and CI runs it, but
the archive Claude Desktop users download was verified for structure
only, so editing a source file and forgetting package-skill.sh left
every check green while the ZIP served the old content. The package test
now compares each entry against the file it was built from.
.callout shipped in two shapes: transparent in one-pager, ivory fill
plus radius in long-doc and equity-report, with the quick-reference
table describing only the first. One class, two forms, is what teaches a
reader that the shape is theirs to choose. It is now the filled form
everywhere, padding tightening per density, and the specs say so. The
neighbouring wording is settled too: .quote shares the rule but takes no
fill, and that is the line between a quotation and a raised passage.
CI never checked which family drew the CJK text, so a broken font
install would have shipped looking merely fine.
Claude-Session: https://claude.ai/code/session_01KgPeQ4ApebVquCZQXWKCfx
The rule shipped at four widths. Three of them are a real distinction:
2.5pt opens a section or document, 2pt lifts an aside out of the reading
flow, 1.4pt edges a block whose fill already carries the weight. The
fourth was drift, one-pager's .callout sitting at 1.8pt while the same
component is 2pt in long-doc and equity-report.
Collapsing all four into one value was the tempting fix and the wrong
one: it would flatten three roles into a single mark. What was missing
was the rule itself, which lived only in the templates and had to be
inferred by reading all of them. design.md now states it, and a test
holds the set closed, because a component at two widths is what teaches
a reader of these templates that the number is theirs to pick.
Claude-Session: https://claude.ai/code/session_01KgPeQ4ApebVquCZQXWKCfx
An agent copies a documented recipe before it reads a template, so the
docs are a shipped artifact and nothing was scanning them. CHEATSHEET.md
taught a .card pairing a 0.5pt border with an 8pt radius, the double-ring
pitfall templates are failed for, against --border-cream, a token defined
nowhere in the repo. design.md carried the same recipe plus --border-warm,
--ring-warm and --ring-deep, all equally dead, and a slide line-height the
templates set 0.10 tighter.
--check-docs scans every fenced css/html block with the template rule set
and resolves every var() against tokens.json plus what the shipped
templates define. It reuses the exemptions the template scan already
makes: SVG colors answer to the diagram palette, a `--x: #hex` line
declares rather than spends, and a line tagged /* avoid */ is the lesson.
The quick-reference tables now point at components the templates ship
instead of handing out recipes. Assembling a container from a recipe is
how a page ends up carrying three unrelated emphasis languages, and the
two most copied entries, an 8pt-radius data card and a brand left bar on
every section head, were exactly the drift showing up in generated
documents.
Claude-Session: https://claude.ai/code/session_01KgPeQ4ApebVquCZQXWKCfx
A missing CJK serif produces no fallback boxes. It silently substitutes a
sans that still reads, so a perceptual pass signs off on a page whose
typography is no longer the system's, and the commercial primary never
ships inside the skill package, so a sandboxed install hits this by
default.
--check-fonts reads the rendered PDF's span table and names the family
that drew the body ideographs, failing on a non-serif substitution or on
text split across two families. --check-visual runs it inline, since that
was checklist item 1 all along. --check-style applies the template lint
rules to a produced document, counting distinct emphasis fills so one
form reused stays clean while a new container per idea does not.
scan_density skipped page 1 as a cover exemption, which left one-page
documents with no scanned page at all.
Claude-Session: https://claude.ai/code/session_01KgPeQ4ApebVquCZQXWKCfx
The site is a static deploy of this repo, so every agent-facing discovery
document has to be a committed file. Generating them keeps the version, the
MCP tool list, and the template catalog tied to their single source instead
of a hand-copied duplicate that rots on the next release.
anti-patterns.md had six duplicate rule ids (24, 41-45), which broke the
cross-file citation scheme; rows are renumbered contiguously 1..54 and every
citation site moved with them, including the prose reference inside the file.
The typography contradictions are resolved against what the templates actually
ship rather than by preference: CJK body letter-spacing is 0.3pt, the default
tag swatch is the registered --tag-bg token, the rgba ladder collapses to the
two tints that exist, and the metric row is documented as a print/screen split
instead of two pitfalls contradicting each other. The PPTX palette drifted from
slides.py and named two constants that exist nowhere in the repo.
sitemap.xml lastmod was two weeks behind the index pages it describes.
check_off_palette blanks the :root block before scanning, so an
off-palette token defined but never used as a literal hex escaped every
guard. A dead #a64f33 terracotta second accent hid in portfolio this
way, against the single ink-blue accent invariant. Scan :root token
definitions too (print templates only; screen-local tokens and the
registered --breaking-* stay exempt), remove the dead token across the
portfolio locales, and correct the stale "orange highlight" comment in
resume that no longer matched the ink-blue .hl.
Empty-scan guards for the four config checks and two KO tests, a site
version-badge assertion tied to VERSION, a packaging coverage gate so a
new tracked script cannot silently miss the zip, a sibling placeholder
parity test locking the #38 bug class, merged multi-block :root parsing,
one-sided cross-template var drift reporting, Marp CSS joining the lint
scan, shared walk/rel/pdf helpers, single-file update-check marker with
portable version sort, and PID-suffixed font temp files with EXIT trap.
changelog CN/KO templates referenced an undefined --mono var, so inline
<code> fell back to the serif stack instead of monospace; define it to
match changelog-en. Guard checks.py fitz.open against malformed PDFs so
the orphan/density/balance checks report ERROR instead of a traceback.
Make highlight.py palette lazy so importing it never reads tokens.json
on a half-installed checkout. Extract pure density/rhythm/orphan seams
and repoint the density test off its reimplemented thresholds onto the
real logic. Align README template count and refresh sitemap lastmod.
Architecture panoramas kept getting crammed into the single 9-node
figure. Boards now have their own reference rules (five fixed layers,
bands over cards, judgment-style copy, 4px connector standoff), a
template with a real five-layer demo, and the diagram count moves to
18 across docs, site locales, the print demo, and the skill package.
Audit follow-ups. Move all template registries into shared.py so the
single-registry rule holds for diagrams too. Make the normalizer raise on
non-beautiful-mermaid input or any unresolved color instead of silently
emitting a broken diagram. Add a test that committed diagrams still carry
their .mmd source labels, guarding the no-Node regeneration gap.
Hand-tuning diagram SVG coordinates was the painful path; now agents can
write Mermaid text and get Kami-styled sequence/class/ER diagrams. A pure-
Python normalizer re-themes any beautiful-mermaid SVG and makes it
WeasyPrint-safe, so no Node ships in the package.
Installed skills had no way to surface updates: the skills CLI has no
outdated check and the plugin path's auto-update is unreliable. Add a
quiet daily check (scripts/check-update.sh) that reads the public VERSION
file, compares it to the bundled VERSION, and prints one line when a newer
release exists. It only does a read-only GET, sends no data, runs at most
once per day via a cache marker, and fails silently offline, sandboxed, or
without curl, so it never blocks work. SKILL.md runs it at task start and
relays any notice; README documents the update commands; a VERSION file is
the single source of truth. Covered by test_check_update_script.
The optional .product-shot frame paired a 0.5pt closed border with a
border-radius, which the repo's own thin-border-radius lint rejects, so
build.py --check failed on main. Keep the rounded clip and a soft shadow
and drop the border (no double-ring risk) across the en/zh/ko one-pagers
and the Mole demo. Add a test that runs the full CSS lint, so a rule
violation can no longer slip past an otherwise green suite.
The demo PDFs and PNGs are human-facing README previews; SKILL.md never
references them, yet they made up over 90% of dist/kami.zip. Filter
assets/demos/ out of the package (and add it to the forbidden-entry
audit plus the test assertion). The zip drops from 5.2MB to ~0.45MB,
which also removes the size ceiling that blocked adding more demos.
The allowlist JSON carried four font-stack var names plus an empty
per_pair_allowed hook that never held an entry. Inline the four names as a
constant in lint.py and drop the file, its loader, and the dead per-pair path.
The stabilize pipeline (overflow solver plus palette/token normalization)
produced zero changes across all templates, and every invariant it enforced
is already gated: build.py --check covers rgba/cool-gray/off-palette/token
drift, build.py --verify covers page counts. The overflow solver also
contradicted the design rule against shrinking type to fit a page count.
Removes scripts/stabilize.py, stabilizer_profiles.json, cool_gray_buckets.json,
their tests, the CI smoke step, and TemplateSpec.stabilize_max_pages; refreshes
dist/kami.zip. Keeps COOL_GRAY_BLOCKLIST (lint) and PARCHMENT_RGB (density).
Remove the --verify-filled alias and an unused CSS_VAR_RE left over from
earlier passes, fix the AGENTS marp note, and add a test asserting the
marp theme :root tokens stay in sync with tokens.json. Rebuild dist.