D196 — The onboarding skills route to references for artifact authoring and the encryption flow¶
Status: implemented. Closes #251.
Context. kb-create and kb-import take an operator from "no KB" to "KB mounted and a client
connected", and stop there. The two things a first onboarding actually struggles with are the two
things neither skill contained.
Artifact authoring was absent. Neither skill named artifact_write, artifact_read,
artifact_list or artifact_delete even once. kb-create offered skill_list/skill_install,
which copy a bundled skill into the KB — a different operation from authoring one. An operator
finishing the skill had a KB with concepts and no idea how to put a skill, a subagent, a hook or an
MCP descriptor into it: not the six accepted paths, not the shape of each, not the optimistic-write
protocol (if_match required on update, forbidden on create — an agent that guesses wrong fails its
first two attempts), not the client-side naming rules of D191, and not the manifest → trust →
projection → materialization chain that is what actually makes an artifact appear in a client.
The encryption flow was one sentence — "if the KB has SOPS secrets, add its age key as
<nome>.age" — which is the deployment half. Every step the operator must perform and Cartographer
never will was missing: the age key, the root .sops.yaml creation rules, the first encrypted file.
kb-import was worse: its secrets check told the operator that findings are "moved to the SOPS
flow" and never said what that flow was.
These are bundled skills, so this is not a documentation nit: their text is what an agent acts on, and the operator experiences the gap in the product.
Decisions.
- The skills become routers, not longer documents.
kb-createwas already 128 lines; inlining two procedures would triple it and bury the common path. Each SKILL.md gains a Reference Files table mapping task → file, with the instruction to read only the matching one. This needed no code change://go:embed all:bundledalready embeds every file in a skill directory,LoadSkillreads frontmatter fromSKILL.mdonly and is indifferent to siblings, and provisioning already transports auxiliary files as raw bytes. - The encryption reference is organized around the boundary, not the tool list. Its spine is a
table of who does what — operator: age key,
.sops.yaml, first encrypted file, recipients; Cartographer:secret_seton an existing file,secret_resolve,service_get. The gap people fall into is that boundary, so the document is shaped like it, anddocs/skills-services-secrets.mdwas corrected to state it as a boundary rather than as a remark inside thesecret_setparagraph. - It opens with "do you need this at all". A KB with no service credentials needs none of it; saying so first makes the section skippable instead of intimidating.
- Failure modes are indexed by the symptom, not by the cause.
sopsmissing, a key that cannot decrypt,rwscope missing over HTTP,secrets_on_non_service, a pointer that does not exist,secret_seton a file that does not exist, and a committed file that turned out to be plaintext because thepath_regexdid not match — that last one carries the instruction to treat the value as compromised, because git history is forever. - The artifact reference states the client-side naming rules as author-side requirements. From the author's perspective that is what they are: D191 had landed, so the implemented rules are quoted rather than cited as pending.
- Every command is runnable as printed (the D192 standard), with placeholders written as placeholders. These files are read by an agent that executes them literally.
kb-createstep 2 now leads withcartographer kb create <name> --remote <url>, which scaffolds, attaches the remote and pushes in one command, with theserve --kb --init+ manual remote sequence demoted to the fallback for a machine that cannot reach the remote. Flags were checked againstcmd/cartographer/kbcmd.go, not paraphrased.- The three defects D192 item 5 owned were verified gone, not re-fixed: the
.cartographer.yamledit, the missingcartographer client bind, and the naming self-contradiction are all already corrected onmain. - A test guards the routing in both directions.
internal/skillbundlenow asserts that everyreferences/file is reachable from the embedded FS and non-empty, and that every one of them is mentioned by its skill'sSKILL.md. A reference added to the tree but not to the embed, or one no skill routes to, can no longer ship silently. - No new MCP tool and no new CLI flag. This ships documentation inside the binary.
Invariants kept. Bundled skills keep their frontmatter contract and are validated on load;
only version: changed (kb-create 2.4 → 3.0, kb-import 1.0 → 1.1) plus the kb-create
description, which had to say what the skill now covers or the router would never be loaded.
skill_install copies what it always copied. No MCP tool behaviour, destination or config key
changed. The GitOps/Kubernetes procedure stays kb-create's primary topology.
Consequences. Bundled-skill content only, no behaviour change. A KB that installed kb-create
with skill_install keeps its old copy until reinstalled — a stale installed copy is exactly the
confusion this closes, so it is worth a release note.