← Corpus / lossless-monorepo / agent-skill
Three Skills Shipped, Two Date Families Untangled, and a Repo That Can Keep a Secret
A skill library that publishes everything needs somewhere to put the things it can't. This session built that boundary — gitignored config read by instruction, an audit grep that has to come back empty, and a rule against injecting our conventions into repos we only have READ on — then shipped three skills through it and finally wrote down the frontmatter standard the tree had been running on tacitly for months.
- Path
- agent-skills/changelog/2026-08-15_01.md
- Authors
- Michael Staton
- Augmented with
- Claude Code on Claude Opus 5
- Tags
- Agent-Skills · Conventions · Frontmatter · Context-Vigilance
Why Care?
The through-line of this session was making tacit practice legible — and discovering, twice, that the thing standing in the way was a boundary nobody had drawn yet.
The first was privacy. A public skill library can’t hold operator particulars, but a skill stripped of them stops working. That got resolved earlier the same evening (2026-08-14_01) and immediately paid for itself: the expense-report skill shipped through the same audit, and the CRM skill’s own §1 was caught inlining exactly the values its example config existed to hold.
The second was dates. Two families of them — editorial and filesystem — had been coexisting across context-v/ and changelog/ for months with no document saying which answers what. Agents kept guessing, and kept guessing wrong in a specific direction: stamping date_modified as a proxy for “when did this change,” which Obsidian bumps merely for opening a file.
Both are the same failure mode. A convention that lives only in someone’s head is one an agent will violate confidently.
What’s New?
Two new skills
-
expense-report-generation— turning raw card and bank statement downloads into a claim a client’s finance team can approve without asking a question. The expensive part isn’t arithmetic, it’s identification: card descriptors name the billing entity, not the product, so Loom bills asATLASSIANand Trae asBYTEDANCE, and a reviewer sees a vendor the claimant never mentioned. The skill’s answer is timeline continuity — pull every charge for both descriptors in date order, and if A stops the exact period B starts on the same billing day with no overlap and no gap, it’s one subscription that changed descriptors. Paired with a hard never-invent-a-product-name rule, the BASE/EXTENDED split that lets a reviewer decline one section without unpicking the other, and the statement-close gap that silently truncates any trip spanning two billing periods. -
prep-images-for-embed— screenshots to CDN-hosted, SEO-correct embeds in one call, with a shippedprep-images.mjs. Headline finding is measured rather than assumed: upload JPEG, never WebP. ImageKit converts to WebP for browsers that accept it and falls back for those that don’t — upload WebP and that fallback becomes a PNG up to 3× larger. Alt text is not optional; the script rejectsalt="screenshot".
Conventions written down
-
The frontmatter standard, finally explicit.
context-vigilanceandchangelog-conventionsnow both carry the editorial vs. filesystem date split:date_authored_initial_draft/date_authored_current_draftanswer “when was this written and last meaningfully revised,” and are what timelines should read.date_created/date_modifiedanswer “when did these bytes appear and change,” and lie in both directions —date_modifiedoverstates recency (Obsidian bumps mtime on open), anddate_createdcan overstate age-of-origin, because a machine recovery in this tree reset birthtime on a batch of files. Where frontmatter records an earlier creation date than the filesystem, the frontmatter wins.Two rules with teeth came out of it. Deleting an unrecognized key is always wrong — the extended date vocabulary is applied unevenly on purpose, different surfaces read different keys, and an empty
date_authored_final_draft:means “not final yet,” not “unused.” And renaming a key can break a consumer:date:→date_authored_initial_draftsilently broke two changelog ingesters, one that readdateas its metadata field and one that used it as a temporal anchor. Renaming a key across 85 files is easy; noticing what read it is the actual work.The directed-sweep carve-out is now spelled out too — “show, don’t enforce” governs incidental edits and was never meant to forbid an operator asking for a repo to be brought up to standard. Under a sweep: additive only, no YAML round-trips (they collapse multi-line
lede:blocks and reorder hand-authored keys), never touch the body, edit originals rather than rollups, and judgepublishby reading the document — word counts get it backwards in both directions. -
changelog-conventionscomposes withprep-images-for-embed. An entry that wants images is itself the trigger; the user shouldn’t have to name both skills. With it, the rule that relative image paths are not a style preference — they break: changelog entries get rolled up into parent splash sites, soresolves locally and resolves to nothing once rendered elsewhere. A CDN URL survives every aggregation. -
gh-cliConvention 3b — git worktrees makeHEADambiguous. The link recipe resolves both repo root and branch from wherever the shell is standing, which is per-worktree, not per-repository. With adevelopmentworktree and amainworktree side by side, the directories are indistinguishable at a glance and running the recipe from the wrong one yields a well-formed URL that 404s only for the reader. PinBRANCHexplicitly when scripting; audit withgit worktree list --porcelain, because branches checked out in another worktree are marked+rather than*and quietly break anything grepping for*.
Repo hygiene that turned out to be load-bearing
-
CLAUDE.mdfor the skills repo, which had none. It carries the symlink-sync habit plus the two failure modes that silently break discovery: a directory name disagreeing with the frontmattername:loads a skill without its description, so it never triggers; and renaming a skill directory strands the old symlink, because the sync script adds but never removes. Both were live — the CRM skill shipped asguidlinesagainst a frontmatter readingguidelines. -
Lossless conventions no longer get injected into vendored repos. The tree-wide browser-drive rollout wrote its sentinel block into 16
CLAUDE.mdfiles, one of which waschroma-agent-skills/— pinned fromchroma-core/agent-skills, where we have READ permission only. That copy could never be committed: a commit inside it would be unpushable and would leave this repo’s gitlink pointing at a SHA existing on no remote, which is the loss scenario thepseudomonoreposHARD STOP exists to prevent. Block moved into this repo’s ownCLAUDE.md, vendored file restored, submodule clean. -
.gitignoregrew two depth-anywhere rules —**/config/private.jsonand**/private-data/— because~/.claude/skills/<skill>symlinks into this repo, so anything a skill creates at its documented paths lands inside the repo and is seen by git.
Notes
The convention list at the top of gh-cli-projects-tasks-conventions is ordered by priority to adhere to, not chronologically. Per-item (added YYYY-MM-DD) tags made it read as a timeline, so out-of-order dates looked like a defect and invited a renumber that would have demoted a deliberately higher-ranked convention. Tags stripped, principle stated inline.
Upstream chroma-core/agent-skills was verified current against the GitHub API rather than a local fetch: main is at 5669a50, last pushed 2026-04-20. The skill-split branch that looks like unreleased work is refs/pull/6/head — already merged.
Related
- 2026-08-14_01 — the public-skills/private-config pattern and
lossless-crm-interface-guidelines, the first skill built to it. This entry picks up where that one ends.