Plan — path-valued types: whole-KB migration
Context
The workshop's initial direction was commonplace-resolve-type, a CLI that reassembled (template + instructions + schema) for a (type, collection) pair at write time. That direction is dropped. See README.md for the shape we landed on instead: type: becomes a path to a hand-authored instructions doc; the write skill composes ordinary repository files at read time; no resolver CLI, no compiler, no generated write-context packet.
This is no longer an adr pilot. The implementation should move the repo from enum-valued types to path-valued types in one migration bundle. Git is the rollback mechanism: if the migration fails, revert the bundle rather than carrying old and new type mechanisms side by side.
Migration scope
- Every explicit frontmatter
type:value inkb/**/*.mdis rewritten from an enum string to a path. - Every current type contract in
kb/**/types/is represented as a*.mdtype-spec doc. *.template.mdand*.instructions.mdsidecars are absorbed and removed;*.schema.yamlfiles remain.cp-skill-write, validation, and reference docs are updated in the same migration bundle.
Decisions fixed before implementation
- No committed mixed state. Implementation may use local mechanical phases, but the committed result should switch type docs, corpus frontmatter, validator behavior, and write-skill instructions together.
- No enum-to-path redirect table. After the migration, explicit
type:values are paths. Enum values such astype: adr,type: note, ortype: snapshotare validation errors. type:paths are repo-relative markdown paths underkb/: they must start withkb/, end with.md, must not contain.., and must not be absolute paths or URLs.- Schema remains separate from authoring prose. Every type-spec doc must declare a
schema:frontmatter field. The value is a repo-relative path to the schema file, ornullwhen the type has no schema. - Collection type offerings use a readable, regular section in
COLLECTION.md:
## Types
- `adr` -> `kb/reference/types/adr.md`
Use for architecture decision records.
Implementation policy addendum
These policies are fixed before implementation so the migration does not invent behavior mid-flight.
- Note frontmatter does not gain new fields. A typed note carries a single explicit pointer:
type: kb/reference/types/adr.md
- Type-spec docs carry type metadata:
---
type: kb/types/type-spec.md
name: adr
description: Architecture decision record for accepted or proposed system decisions
schema: kb/reference/types/adr.schema.yaml
---
- Templates are authoring material, not a code contract. The validator does not inspect the body of type-spec docs, and does not check that template-produced documents conform to the declared schema. Template-to-schema conformance testing is deferred.
- The resolver loads the note's
type:path, parses the type-spec doc, and derives all runtime metadata from that doc. Internally it may expose the note's type path, the type doc path, the type docname, and the declared schema path, but none of those become note-frontmatter fields. - The internal
TypeProfileshould distinguish storage identity and validation target. Expected fields are: type_path: repo-relative path stored in note frontmatter, for examplekb/reference/types/adr.mdtype_doc_path: resolved filesystem path to the type-spec doctype_name: name from the type-spec doc frontmatter, for exampleadrschema_path: resolved filesystem path to the declared schema, orNonewhenschema: nullschema: loaded schema mapping, orNone- Schema
frontmatter.type.constvalues must be migrated to path constants when the schema validates typed frontmatter. Example:const: adrbecomesconst: kb/reference/types/adr.md. - Type-gated review metadata such as
requires-type:must migrate to path values too. Example:requires-type: definitionbecomesrequires-type: kb/types/definition.md. - Explicit
type: textis invalid after migration.textremains the implicit no-frontmatter case only. Existing explicit text-typed files must either lose frontmatter if they are truly raw text, or migrate to a real type path if they carry metadata. - Frontmatter-bearing artifacts must have an explicit path-valued
type:. A file with YAML frontmatter but notype:is invalid after migration; only files with no frontmatter at all remain implicittext. - The current explicit
type: textsource file (kb/sources/psychology-solves-ai-memory-identity-construction-2025307030651871631.md) carries metadata and should migrate totype: kb/sources/types/snapshot.md. kb/types/text.mdremains documentation for the implicit no-frontmatter type. It is not an explicit type-spec doc, is not listed in collection## Types, andtype: kb/types/text.mdis invalid in artifact frontmatter.- Source artifacts now use the reduced source type set.
snapshot,ingest-report, andsource-reviewget type-spec docs underkb/sources/types/, with schemas where present andschema: nullonly when no real schema exists. kb/sources/andkb/reports/are generated artifact areas, not normalcp-skill-writetargets. They still need type docs for validation, but they do not needCOLLECTION.mdtype-offering sections unless their authoring workflow changes.kb/tasks/is not part of the shipped scaffold today, but it has existing task type sidecars. Migrate those contracts too: createtask-active,task-backlog, andtask-recurringtype-spec docs underkb/tasks/types/withschema: nullunless real schemas are added in the same bundle. Do not addkb/tasks/COLLECTION.mdunless tasks become a normalcp-skill-writetarget in this migration.- The shipped scaffold and init tests migrate in the same bundle. Newly initialized projects must ship type-spec docs, not absorbed
*.template.md/*.instructions.mdsidecars. commonplace-initships all global type-spec docs underkb/types/:type-spec.md(the self-referential root),note.md,instruction.md,index.md,definition.md, plus the accompanying schemas (type-spec.schema.yaml,note.schema.yaml,note-base.schema.yaml,index.schema.yaml,instruction.schema.yaml,definition.schema.yaml) and thetext.mddocumentation page for the implicit no-frontmatter type. Collection-local type-spec docs (adr,structured-claim,agent-memory-system-review, source artifact types, task types) are not part of the shipped scaffold unless the corresponding collection is also part of the scaffold.- Type-spec docs are first-class validation targets even though ordinary batch note discovery currently skips
types/directories. The migration must add an explicit type-doc validation path, or widen batch validation deliberately, so malformedkb/**/types/*.mdfiles cannot pass unnoticed. - Type-aware readers must compare path-valued type identities. Any code that currently does
frontmatter["type"] == "index"or similar must either compare against the canonical path (kb/types/index.md) or resolve throughTypeProfile; do not leave enum comparisons in active behavior. spechas exactly one KB artifact usingtype: spectoday —kb/types/note.md— and that file is being replaced wholesale. After the migration there are nospec-typed artifacts in the corpus. Deletekb/notes/types/spec.schema.yamlin the same bundle and do not create aspectype-spec doc. The only remainingtype: specreference is a test fixture intest/commonplace/cli/test_validate_notes.py, which must migrate to a path-valued type or a deliberately-invalid fixture depending on what the test asserts.reviewis retired on the same basis.kb/notes/types/review.schema.yamlexists schema-only with zero KB artifacts declaringtype: review. Delete the schema in the same bundle and do not create areviewtype-spec doc. The only remainingtype: reviewreference is a test fixture intest/commonplace/lib/test_note_parser.py, which must migrate to a path-valued type or a deliberately-invalid fixture depending on what the test asserts.
Step 1: Inventory all current types
Pre-action gate: save the inventory in the PR/workshop notes before editing.
- Use the frontmatter parser, not raw grep, to list every explicit
type:value inkb/**/*.md. - Use the filesystem to list every existing type sidecar in
kb/**/types/:*.template.md,*.instructions.md, and*.schema.yaml. - Build the complete enum-to-path migration table from those two sources.
- Save the preflight inventory to
kb/work/write-type-resolver/inventory.mdbefore editing. It must include, as separate sections: - Types: every explicit frontmatter type value and the number of files using it; the target type-spec doc path for each value; the target schema path or
null; whether the type has existing template/instructions sidecars, schema-only support, no sidecar, or is implicit text; the migration action for explicittype: textfiles; generated or non-write-target classifications, especially source artifact types. - Consumers: every
src/writer that emitstype:literals; everysrc/reader that comparestype:(e.g.fm.get("type") == "index"); every non-write skill or instruction that points at absorbed sidecars; everyrequires-type:reference; every test fixture that constructs typed markdown. This section is the preflight for Step 6.5 and Step 7 test-fixture migration — results from running the Step 8 cleanup regexes against the pre-migration tree are what go here. - The inventory from 2026-04-20 had 13 explicit frontmatter type values.
specis retired in this migration (see thespecretirement policy above).type-specis introduced by this migration as the self-referential meta type declared by every type-spec doc. Logical types backed by a type-spec doc after the migration:adr,agent-memory-system-review,connect-report,definition,index,ingest-report,instruction,note,snapshot,source-review,structured-claim,type-spec. Storedtype:values are the paths to those docs (for exampletype: kb/types/note.md).textis the implicit no-frontmatter case only: files with no frontmatter aretext; explicittype: textis invalid, and there is notexttype-spec doc — only thekb/types/text.mddocumentation page. Sidecar-only contracts migrated without current artifact users (task-active,task-backlog,task-recurring) are valid type-spec docs but not part of the accepted-for-authoring list.
Step 2: Create the root type-spec doc
Pre-action gate: review before applying the full migration.
- Create
kb/types/type-spec.mdandkb/types/type-spec.schema.yamltogether. - Frontmatter:
type: kb/types/type-spec.md(self-reference);name: type-spec;description: …;schema: kb/types/type-spec.schema.yaml. - Body: describes what a valid type-spec doc is — required frontmatter fields (
type,name,description,schema) and the relationship to declared schema files. Whether to include an example, template, or authoring checklist is an authoring decision made in the body; the validator does not inspect body content. kb/types/type-spec.schema.yamlencodes the required frontmatter shape:typeis a repo-relative path underkb/ending in.md;nameis a non-empty string;descriptionis a non-empty string;schemais eithernullor a repo-relative path underkb/ending in.schema.yaml. The root type-spec self-validates against this schema; so does every other type-spec doc.- This file is the validator's terminator: when resolution reaches path-equals-self, stop descending the type chain.
Step 3: Fuse every existing type contract
Pre-action gate: review representative fused docs from each family before applying the full mechanical pass.
- For every existing
{type}.template.md/{type}.instructions.mdpair, create{type}.mdin the same type directory: - frontmatter:
type: kb/types/type-spec.md,name: <type>,description: …,schema: <repo-relative schema path or null> - body: absorbs the existing instructions prose and, when present, the existing template content; section structure and fence style are the migrating agent's choice.
- The two existing schema-only types (
spec,review) are both retired rather than fused; see the retirement policies in the implementation policy addendum. Nospec.mdorreview.mdtype-spec doc is created; both*.schema.yamlfiles are deleted. - For frontmatter type values that currently have no sidecar, create minimal type-spec docs in the owning collection's
types/directory. Source artifact types live underkb/sources/types/. - For task sidecar-only types under
kb/tasks/types/, create type-spec docs and absorb their templates/instructions even though no task artifacts currently declare those types in frontmatter. - Delete absorbed
*.template.mdand*.instructions.mdsidecars in the same migration. Leave sibling*.schema.yamlfiles in place. - Existing global types become
kb/types/<type>.md; collection-local types remain underkb/<collection>/types/<type>.md. - Existing
kb/types/note.mdis replaced wholesale. The current prose is redesigned, not copy-pasted, for its new role as an authoring spec. The rewritten file contains type-spec frontmatter (type: kb/types/type-spec.md,name: note,schema: kb/types/note.schema.yaml), authoring prose for how to write a note, a concise reference for the shared frontmatter fields (description, status ladder, trait vocabulary) so inbound links fromkb/reference/available-types.mdstill find that material, and the template content absorbed fromkb/types/note.template.md. Canonical field shape lives inkb/types/note.schema.yaml; design-principle discussion about why notes look this way moves to (or stays in) a dedicated theory note, not the type-spec doc. Updatekb/reference/available-types.mdlink anchors if section names shift. - Do not convert
kb/types/text.mdinto a type-spec doc; see thetext.mdpolicy in the implementation policy addendum.
Step 4: Declare offered types in collection conventions
Pre-action gate: review each COLLECTION.md type section before applying the full migration.
- Add or update
## Typessections in collections that accept writes:kb/notes/COLLECTION.md,kb/reference/COLLECTION.md,kb/instructions/COLLECTION.md,kb/agent-memory-systems/COLLECTION.md, andkb/work/COLLECTION.md. - List global types when the collection offers them for new writes, for example
note,index,definition, andinstruction. - List collection-local types where relevant, for example
structured-claim,adr, andagent-memory-system-review. - Do not add
COLLECTION.mdtype-offering sections forkb/sources/orkb/reports/in this migration. They are generated artifact areas with validation type docs, not normalcp-skill-writetargets. - Do not add
kb/tasks/COLLECTION.mdin this migration unless task writing is deliberately brought undercp-skill-write.
Step 5: Rewrite all corpus frontmatter
Pre-action gate: show the exact enum-to-path replacement table and the count of files affected per type.
- Rewrite every explicit frontmatter
type:enum to its path-valued type doc. - Rewrite only YAML frontmatter, not examples, code fences, templates embedded in prose, or historical discussion.
- Treat explicit
type: textas invalid input to resolve during migration. The one current explicit text-typed source carries metadata and should migrate totype: kb/sources/types/snapshot.md. - Examples:
type: note->type: kb/types/note.mdtype: instruction->type: kb/types/instruction.mdtype: adr->type: kb/reference/types/adr.mdtype: structured-claim->type: kb/notes/types/structured-claim.mdtype: snapshot->type: kb/sources/types/snapshot.md- After this step, no explicit frontmatter
type:value inkb/**/*.mdshould be a bare enum.
Step 6: Update cp-skill-write/SKILL.md
Pre-action gate: review the rewritten skill before applying the full migration.
- Replace Step 1 type-discovery prose with file-native instructions: read the path named by
type:in edit mode, or read the target collection's## Typessection in new-write mode, then open the selected type-spec file. - Remove the inline default
notetemplate.noteis now a normal global type-spec doc atkb/types/note.md. - Do not document or implement legacy enum fallback.
- Keep the hard-fail rule for missing
COLLECTION.md. - Keep search and validation procedural; the type file supplies artifact shape, not search policy.
Step 6.5: Update other writers, readers, and type-aware skills
Pre-action gate: the Consumers section of inventory.md (Step 1) must be complete — every non-validator code path and skill that writes, reads, or compares type: is listed there before editing begins.
- Update artifact-generating commands that currently emit enum frontmatter:
src/commonplace/cli/github_snapshot.py:type: snapshot->type: kb/sources/types/snapshot.mdsrc/commonplace/cli/x_snapshot.py:type: snapshot->type: kb/sources/types/snapshot.mdsrc/commonplace/lib/index_directory.py:type: index->type: kb/types/index.md- Search
src/for generated markdown frontmatter and migrate any additionaltype:literals found during implementation. - Workshop-area code (
kb/work/**/*.py) is out of scope. Workshop scripts are not migrated, even when they emit enum frontmatter into corpus areas (known case:kb/work/link-label-audit/extract_labels.py). If a workshop is revived later, update its scripts then. - Search
src/for type-value consumers, not just writers. Update direct enum comparisons and filters, including: src/commonplace/lib/index_generated.py:fm.get("type") == "index"andfm.get("type") != "index"must use the path-valued index type or a path-aware helper.src/commonplace/docs/mkdocs_hooks.py: tag-index discovery must recognizetype: kb/types/index.md.- any additional
get("type"),note_type,resolved_type, ordefinition_pathusage discovered during implementation. - Update non-write skills and instructions that point at absorbed sidecars:
cp-skill-connect: readkb/reports/types/connect-report.md, not.template.mdcp-skill-ingest: readkb/sources/types/ingest-report.md, not.template.md/.instructions.mdcp-skill-convert: verify and write path-valued note/structured-claim types, not enum valuescp-skill-snapshot-web: emit or describekb/sources/types/snapshot.md- any other instruction discovered by searching for
.template.md,.instructions.md,type: note,type: snapshot, ortype: structured-claim - Keep historical prose in ADRs and theory notes only when it is clearly describing pre-migration behavior; update operational procedures and examples.
Step 7: Update validation and docs
Pre-action gate: show the validator diff and tests before applying the full migration.
commonplace-validatetreats explicittype:values as paths.- A valid type path must exist, point under
kb/, end with.md, and resolve to a type-spec doc. - A type-spec doc is valid when its own
type:points tokb/types/type-spec.md, except the root doc, which points to itself. - A type-spec doc must include
name,description, andschema.schemamust be eithernullor a valid repo-relative path underkb/to an existing.schema.yamlfile. - The validator loads schemas from the type-spec doc's
schema:field. Missingschema:is a validation error for the type-spec doc;schema: nullmeans no schema validation for artifacts of that type. - Schema constants for
frontmatter.typemust match path-valued type references, not old enum names. - Frontmatter with no
type:is a validation error. Preserve implicittextonly for files with no frontmatter. - Remove enum fallback behavior from validation for explicit frontmatter
type:values. - Remove collection-scoped enum lookup from explicit frontmatter validation. The note's path chooses the type doc directly; the collection no longer participates in resolving an explicit type.
- Keep collection/type uniqueness checks only if they still prove something useful in the path-valued system. Otherwise replace them with checks that type doc paths are valid.
- Preserve the existing behavior that a file with no frontmatter is
textif that behavior is still needed for raw text artifacts; this is not an enum fallback. Explicit frontmattertype: textfails. - Add explicit validation coverage for type-spec docs under
kb/**/types/*.md. Current note discovery skipstypes/directories; widen batch validation to include them (filtering non-artifact side files), and rely on the uniform schema flow — every type-spec doc'stype:chain resolves tokb/types/type-spec.md, whoseschema:points atkb/types/type-spec.schema.yaml, so there is no bespoke type-spec validation pass. - Update review type gates (
requires-type) to path values or equivalent path-aware matching; do not leave enum matching against note frontmatter. - Update active type-aware readers such as generated-index syncing and MkDocs tag-index discovery so they recognize path-valued type references.
- Update reference docs: commands, type loading, available types, collections/types, and any ADR/reference page that describes enum-valued types or three-file type contracts.
- Update scaffold/init expectations so
commonplace-initseeds the global type-spec docs (type-spec,note,instruction,index,definition), their schemas (includingkb/types/type-spec.schema.yaml), and thetext.mddocumentation page, with no absorbed template/instruction sidecars. Collection-local type-spec docs follow the same ship-only-if-collection-is-shipped rule used for other collection content. - Migrate test helpers and fixtures that create typed markdown so they use path-valued frontmatter unless the test is explicitly asserting that a bare enum fails.
- Tests: path-valued type resolves; declared schema is used;
schema: nullskips schema validation; missingschemafails for type docs; type docs underkb/**/types/*.mdare validated; missing type file fails; invalid type path fails; self-reference terminates; missingtype:in frontmatter fails; bare enum frontmatter fails; explicittype: textfails; unknown explicit type no longer falls back tonote; collection-local enum lookup is gone for explicit frontmatter; generated snapshot and index commands emit path-valued types; generated-index syncing and MkDocs tag-index discovery recognize path-valuedindex; reviewrequires-typematching works with paths; init/scaffold tests assert type-spec docs are seeded and absorbed sidecars are absent.
Step 8: Validate the migrated repo
Pre-action gate: no commit until the validation result is understood.
- Run
uv run pytest. - Run the KB validator over the migrated corpus.
- Search for remaining bare enum frontmatter values with the same parser used in Step 1.
- Search for schema
frontmatter.type.constvalues that still reference bare enum names. - Search for
requires-type:values that still reference bare enum names. - Search for remaining
*.template.mdand*.instructions.mdfiles underkb/**/types/; none should remain unless explicitly justified as non-type historical material. - Search operational code and promoted skills for stale sidecar references and enum-writing examples:
rg -n "\.template\.md|\.instructions\.md|type: (note|index|definition|instruction|adr|structured-claim|agent-memory-system-review|connect-report|snapshot|ingest-report|source-review|spec|review|text)\b|requires-type: (note|index|definition|instruction|adr|structured-claim|agent-memory-system-review|connect-report|snapshot|ingest-report|source-review|spec|review|text)\b|get\(\"type\"\).*==|get\(\"type\"\).*!=" src test kb scripts AGENTS.md README.md- Treat historical ADR/theory prose as acceptable only when it clearly describes pre-migration behavior. Active instructions, reference docs, root control-plane docs, scaffolded files, tests, generated examples, and scenario docs must not retain stale operational sidecar paths or enum-valued examples.
- Search active code for direct enum type comparisons and path-model field names that should have changed:
rg -n "get\(\"type\"\)|note_type|resolved_type|definition_path|check_type_uniqueness|discover_all_types" src test scripts- Run or update
commonplace-initscaffold tests to prove new projects receive the migrated type-doc surface. - If the migrated state fails, fix forward in the same migration bundle or revert the bundle. Do not introduce a compatibility layer.
Step 9: Promote ADR 018
Pre-action gate: Steps 1-8 must be green before the ADR flips to accepted.
- Move
018-types-are-path-references-to-instruction-docs.mdtokb/reference/adr/018-types-are-path-references-to-instruction-docs.md(or the next available ADR number if 018 is taken by the time this lands). - Flip
status: proposed->status: acceptedin the frontmatter. - Harmonize the ADR prose with the migration as shipped: replace any residual sibling-schema language with the explicit
schema:pointer policy; update the "Migration" section to reference the actual merged commit instead of the plan. - Update inbound references to the draft path (workshop
README.md,plan.mdlinks, any other notes that pointed at../../reference/adr/018-types-are-path-references-to-instruction-docs.md).
Not changing
- Canonical sources of authoring contracts stay hand-authored. No compiler, no build step.
- Schema files stay separate from authoring prose, but their paths are declared in type-spec frontmatter.
- Linking conventions stay in
cp-skill-write/SKILL.md(global) +COLLECTION.md(per-collection). They are not injected into type docs. COLLECTION.mdhard-fail rule stays.
Deferred / out of scope
- A
commonplace-mv-typecommand that rewrites every pointer when a type doc moves. Worth building when the first rename happens; not needed for the migration. - A compiled type-index doc (
kb/types/index.md) for discoverability. Optional; globbing overkb/**/types/*.mdplusCOLLECTION.mdlistings suffices for now. - Broader schema metadata beyond the required
schema:pointer.
Success criteria
- Every explicit frontmatter
type:in the KB is a valid path to a type-spec doc. - No authoring type contract remains split across
*.template.mdand*.instructions.md. cp-skill-writecan author a note, instruction, ADR, and structured claim by reading ordinary repository files rather than running a resolver or following filesystem-discovery prose.- The full test suite and KB validation pass.
Closure
This workshop closes when:
- The whole-KB migration lands (Steps 1-8).
- ADR 018 is promoted per Step 9.
- Any follow-up work is limited to refinements, not compatibility with enum-valued
type:.