Skip to content

Dev Doc Update Directions

How to run /wb-dev-document — scan current changes, propose knowledge-store edits, confirm, apply by editing each unit's Markdown file (docs_edit / native Edit) plus docs_delete, validate store integrity, report. Rules for what to check and what not to clobber.

When to use

When the user invokes /wb-dev-document, or as a mandatory step inside /wb-dev-pr, or after a dev change that might have made existing knowledge units stale

Slash command: /wb-dev-document

Linked workflow: dev/dev-document

  • agent_docs
  • docs_delete
  • agent_docs_rebuild
  • docs_validate

Directions

Update the knowledge store after dev changes. Run via mcp__work-buddy__wb_run("dev-document") — the workflow DAG enforces scan → propose → confirm → apply → validate → report; you don't manually sequence the doc check anymore.

When to run

  • Before /wb-dev-pr — the commit workflow invokes this as a mandatory step; you can still run it standalone first.
  • After any architectural change that affects behavior visible in an existing knowledge unit.
  • When adding a new subsystem, skill, or workflow — new units usually need creating.

What gets checked

The scan step produces a first-pass net: - Changed files (uncommitted + untracked). - Classification by bucket (module / knowledge / slash / tests / config). - candidate_units: knowledge units whose text mentions a changed file or subsystem slug. Ranked by match strength.

You then add the semantic layer: - Read each candidate at depth="full" and judge. - Do 2-4 agent_docs(query=...) semantic searches for concepts your change touches. - Grep CLAUDE.md for keywords — it is the highest-priority surface and must not go stale.

Choosing the right kind for a new unit

Before creating a new unit, decide its kind. The decision affects how it renders, how it's discovered, and what schema fields it can carry. Getting the kind right at create-time is much cheaper than reclassifying later.

Apply this decision flow in order; first match wins:

  1. Behavioral guide loaded by a slash command (/wb-...) → directions.
  2. Callable from MCP via wb_run → skill. An Op (a callable in work_buddy/mcp_server/ops/) plus a kind: skill declaration unit; author the declaration via docs_edit.
  3. Multi-step DAG the conductor advances → workflow. A kind: workflow unit has an immutable opaque workflow_id, mutable canonical workflow_name, optional executable workflow_aliases, and a steps DAG in frontmatter; author via docs_edit so creation mints a fresh ID.
  4. Personal/user-authored knowledge (Obsidian-vault-backed) → personal. Create via knowledge_mint.
  5. Runs on a network port internal to work-buddy → service. Examples: dashboard (5127), embedding service (5124), messaging (5123). Has ports.
  6. Primarily documents a connection to an external system → integration. Obsidian, Thunderbird, Tailscale, Hindsight, an Obsidian plugin, etc. Even if work-buddy runs a local bridge for it, the bridge is the mechanism; the external thing is the unit's identity. Has external_system, bridge_module.
  7. Coherent functional domain whose persistent state work-buddy itself owns (DB, files in .data/, etc.) → system. Examples: tasks, triage, memory. Memory ownership is the disambiguator from integration — if state lives outside work-buddy (user's vault, external server), it is an integration, not a system, even if work-buddy provides operations against it.
  8. Otherwise the unit is reference or concept. This is the most error-prone boundary — read the next subsection carefully.

reference vs concept — do not get this wrong

The naive rule "has entry_points → reference" is wrong. Both kinds may carry entry_points. Judge by the primary purpose of the content, not by whether code pointers exist.

A unit is reference when ALL of these hold: - Content is short (< ~400 words is a strong signal). - Structured around code surface: function signatures, class names, schema fields, parameter lists. - Reader's purpose is to look up the API, not understand a subsystem. - Documents 1-3 closely-related entry points. - Examples: automation/contexts (one resolver function), clarify/reference-filing (one pipeline), obsidian/vault-writer (section-aware writing).

A unit is concept when: - Content is long-form narrative (> ~400 words OR 5+ section headers is a strong signal). - Explains how and why a subsystem works, not just what's in the code. - Reader's purpose is to understand a subsystem or design — they want the mental model, not an API signature. - Section structure spans aspects (lifecycle, recovery, surfaces, decisions) rather than entry-point listings. - Even if entry_points are populated, they are pointers within the narrative, not the unit's reason for existing. - Examples: architecture/repo-structure (layout narrative), architecture/retry-queue (subsystem behavior), obsidian/typed-exceptions (error-classification policy), obsidian/vault-write-decision (architectural decision tree).

The quick test: "Would a reader consult this to call an API, or to understand how something works?" API → reference. Understanding → concept.

Multi-parent nesting for systems

A system unit can be a subsystem of another system. The parents field is a list, not a singleton; the DAG validator allows multiple parents. When creating a system unit that nests under a larger system, include the parent system in parents regardless of where the path lives. Path picks one navigation entry point; the DAG carries the relationship graph. The "subsystem-of-system" relationship is then derivable: walk a unit's parents and filter by kind == "system".

content_full vs dev_notes — choose the right field

Knowledge units have two body fields surfaced to different audiences. Picking the right one is not a stylistic call — it controls who sees what, and getting it wrong silently misleads agents in production.

  • content_full — the canonical body. Read by every agent (operational + dev) on agent_docs(depth="full"). This is the contract.
  • dev_notes — surfaced only when dev mode is on (set via mode_toggle, auto-enabled by /wb-dev). This is the workshop.

The split is the structural mechanism for the operational/developmental separation. Get it wrong and either operational agents miss the contract, or their context window fills with implementation noise they cannot act on.

What goes in content_full

Anything an agent needs to use the subsystem correctly: - Public surfaces: HTTP routes, skill names, parameter shapes. - Semantic contracts: what the API returns, idempotency, gating, error modes, the ranges of values that mean different things. - User-visible behavior: what the UI shows, what state changes mean, what a button does. - Cross-references to sibling units.

What goes in dev_notes

Anything only useful when modifying the subsystem: - Internal helper functions, snapshot/cache patterns, state-management invariants. - Refactor footguns ("don't collapse None and []", "this state must outlive the refetch", "lock order is X before Y"). - Why-decisions about non-obvious code — the kind of thing a code review would call out. - Pre-existing bug history or "we tried X and it broke Y" lore. - File paths, function names, and line-of-attack hints that only matter if you're about to edit the code.

The decision test

For each fact you're considering writing: ask "If an operational agent was calling this subsystem from a skill — would they want this in their context window?"

  • Yes → content_full.
  • No, only useful while editing the code → dev_notes.

Borderline case rule: lean toward content_full if the rule has user-visible consequences (e.g. the trichotomy of a query param affects what the API returns); lean toward dev_notes if it only affects how the rule is implemented.

Anti-patterns

  • Stuffing everything into content_full — default failure mode. Pollutes operational context with implementation noise.
  • Hiding the contract in dev_notes — operational agents can't see it, get the contract wrong, fail silently.
  • Duplicating the same fact in both — drift risk. Pick the right home and cross-reference if needed.
  • Routing by which field you're already touching, not by what the new fact is — see below.

When updating an existing unit

Route new facts by their nature, not by which field is already in front of you. If you're adding both a public surface and an internal pattern to the same unit, that's two fields keys on the same proposal: one for content_full, one for dev_notes.

If you find yourself adding a public surface to a unit whose content_full is sparse but whose dev_notes is rich, do not bury the surface in dev_notes because that's where "all the writing already lives." Move it to content_full. Conversely, if you're adding a snapshot pattern to a unit whose content_full is the public contract, route that to dev_notes even if it's the unit's first dev_notes entry.

Durable surfaces — no transient narrative

Both content_full and dev_notes are durable surfaces re-read by future agents. Whatever you write must describe the system's current behavior, not the journey of how it got there.

<>

Apply dispatch

Every unit kind is applied the same way — by editing its Markdown file: - create / update (any kind, including workflow and skill) → edit knowledge/store/<path>.md with your native Edit / Write tool (or drive the docs_edit workflow). Frontmatter holds structured fields; the body is content_full; a workflow's steps DAG lives in frontmatter with ## <step-id> body sections. - delete → docs_delete(path).

Workflow identity is a special authoring invariant even though the file substrate is shared:

  • Never propose or apply a change to an existing workflow_id.
  • docs_edit(..., create=true, kind="workflow") mints a fresh ID. For an unavoidable native creation, mint one with uv run --frozen python -c "from work_buddy.workflows.identity import new_workflow_id; print(new_workflow_id())"; never copy an ID from another definition.
  • A workflow_name rename preserves the old canonical address in workflow_aliases.
  • workflow_revision is computed from the serialized authored definition snapshot, the directly bound Directions snapshot, and compiled child-Workflow target identities. Never author it.
  • Use docs_move for path changes so the ID is preserved and path-based Directions bindings are rewritten.

After the file edits, call agent_docs_rebuild() once so the store cache + search index reflect them (the docs_edit workflow does this per unit automatically). If a Skill declaration or Workflow definition/address/schema changed, record that a reload_skill_data call is required after this editing Workflow finishes; rebuilding docs alone does not refresh the live executable registry.

To reclassify a unit (e.g. reference → concept), change its kind field in the frontmatter — a deliberate audit decision, not a routine field edit.

Validate

After apply lands, the workflow auto-runs docs_validate over the whole store. This catches structural breakage the agent easily introduces by accident: - DAG integrity (cycles, missing parents/children). - Command-to-store mappings (every wb-*.md slash command needs a matching directions unit). - Required fields per kind (directions units need a trigger; workflow units need steps). - Workflow identity and address integrity (missing/invalid/duplicate IDs, malformed aliases, and Skill/Workflow address collisions). - Parent-child symmetry (if A lists B as a parent, B must list A as a child). - Dangling path references. - Placeholder duplicates — the same <<wb:X>> target appearing more than once within a single unit. Hard error: duplicates render as back-reference markers at read time and contribute zero readable content, so they're never the right authorial choice. The editor pre-rejects them at write time; this corpus-wide check catches direct-JSON bypasses.

The report step surfaces any failures. Fix them in the same run with a follow-up edit to the offending unit's .md (via docs_edit, or a native Edit + agent_docs_rebuild; executable declaration changes then need reload_skill_data) — don't commit with a broken store.

Rules

  • No clobbering — update only changes the fields that are stale.
  • No recency bias — a unit describes its whole feature, not just your latest edit.
  • Empty proposals are valid — don't invent work if nothing is stale. But "I can't find anything" ≠ "I didn't look"; you must have loaded the top candidate_units and done semantic searches first.
  • Reconcile every edit — applying a change means editing the unit's .md; always validate (the docs_edit commit step, or docs_validate) and agent_docs_rebuild afterward so the store cache and search index stay in sync. For Skill declarations and Workflow definitions, run reload_skill_data after the active editing Workflow finishes so the executable registry also stays in sync. An unreconciled file edit is invisible to its corresponding live surface until that rebuild or reload.
  • Validation failures block the commit — not prescribed by a machine gate (validate is auto_run, not halting), but treat them as blocking: a broken store misleads every future agent.