Skip to content

Core Workflows ​

1. Ingest: Source → Claims ​

Ingesting a document is not fire-and-forget: everything the LLM extracts is staged for human review before it can become canonical knowledge. Two terms recur below — a change-set is the proposed edit (a manifest of what changed plus a diff) that a human approves or rejects, and a locator is the exact file-and-line pointer every claim carries, so each statement can be checked against its source.

bash
# Ingest a source with LLM claim extraction
wf ingest evidence/raw/my-project/docs/readme.md --extract-claims

# Dry run (no files written)
wf ingest --extract-claims --dry-run evidence/raw/foo.md

# Use a different model
WIKI_LLM_OPS_MODEL="llama3.1:70b" wf ingest evidence/raw/foo.md --extract-claims

# Bulk modes with a budget (extraction mirror of the capture window):
# a big capture wave can't detonate N extractions in one run
wf ingest --changed my-project --budget 25   # re-run continues; anti-loop safe

LLM configuration: any OpenAI-compatible endpoint works — full provider table, model tiers, and env-var overrides in Configuration.

Optional step 4b: judged effect verification ​

The ingest agent classifies each claim's effect (add | support | weaken | contradict | supersede). That classification is a self-preference risk — the model that extracted the claim grades its own homework. When the judgment tier is enabled, run the independent second opinion:

bash
wf verify-effects evidence/claims/claim-my-project-*.md
# claim-...: 12 pair(s) judged → contradicts: claim-...-007 (conf=0.35)
# verdicts → registry/effects/<claim>.effects.json (machine artifacts never sit beside pages)

Reconcile: where the judged verdict agrees with your draft, keep it; where it disagrees or lands in the near-band, re-read both claims before finalizing relations. The tier verifies; you own the edit; the human gate still applies.

2. Git History Capture: PRs, Issues, Commits → Raw Evidence ​

Code history is a second capture channel alongside docs. Two sources, one pipeline:

bash
# GitHub: PR threads + issue reports (via gh CLI)
wf capture my-project --git owner/repo                      # window: 6m, budget 30
wf capture my-project --git owner/repo --since 1y --limit 50  # budget 50: the WINDOW shrinks to fit

# Backfill slice (exclusive upper bound — don't re-ingest newer history)
wf capture my-project --git owner/repo --since 2025-06-01 --until 2026-01-01

# Local repo: high-signal commits only + churn ranking
wf capture my-project --git /path/to/repo --churn

# See what would be captured without writing
wf capture my-project --git owner/repo --dry-run

The activity-bounded window (default 6m, budget 30): on an extremely active repo, a fixed window silently truncates — the newest-30 list collapses six months of PRs into two weeks. Instead, the window itself shrinks: capture picks the largest window (6m → 3m → 1m → 2w → 1w → 3d → 1d) whose item count fits the budget, deterministically, 0 tokens. The chosen window is recorded in .last-capture (window=<date>) and reused by hook runs. Per-repo overrides:

yaml
tuning:
  git_history: { since: 6m, budget: 30 }   # global defaults
repos:
  big-repo:
    git_history: { budget: 50 }            # per-repo override; "all" disables

Why this is helpful — and why it's filtered:

SignalWhat it gives the fabricCost control
PR bodies + review threadsThe why behind changes — problem, debate, tradeoffs rejected and chosen. This is pre-written experience-event material (structured records of problem → what we tried → what happened — see §3 below), written by people who were thereThe activity-bounded window + budget bound the blast radius (1 LLM call per source at ingest is budgeted separately — --budget / tuning.ingest.budget)
IssuesStructured observed_problem reports, often with repro steps and environment detailsFiltered by the window on updatedAt — an old issue with fresh comments re-captures (it's live activity); closed/stale issues usually aren't worth extracting
Revert commitsFailed interventions — the seeds of anti-patterns. A revert says "we tried this and it was wrong", which docs never recordDeterministic prefix filter, 0 tokens
Conventional commits (fix:, feat:, perf:)Hotspot trail: which subsystems keep breakingchore:/style:/test:/ci: skipped — most commits are noise
--churn rankingTells you where to spend ingest budget: high-churn files are where the knowledge isPure git analysis, 0 tokens, 0 LLM calls

The key discipline: LLM extraction is the most expensive operation in the fabric (1 call per source), so git capture pre-filters deterministically and only the high-signal subset goes through ingest. A repo with 2,000 commits might yield 40 capturable threads — and those 40 carry more decision history than all the docs combined. Every captured thread keeps its PR number / commit SHA, which are valid claim locators — auditable the same way line ranges are.

Scenario — archaeology on an inherited codebase. You inherit a repo with thin docs and 8,000 commits. Instead of skimming git log by hand, run wf capture my-project --git owner/repo --since 1y then ingest the captured threads. The fabric compiles claims like "auth middleware was rewritten to token-based auth because stateful sessions broke horizontally-scaled sessions (PR #342, review thread)" — context no doc contains, each anchored to a PR you can open. --churn shows the payment module changed 400 times in 6 months: that's where the tribal knowledge lives, so ingest its PR threads first.

Scenario — avoiding a repeat failure. A revert commit says a caching layer was tried and rolled back. Captured and ingested, it becomes an experience event with a negative outcome — and months later, when a new session proposes "add a cache here", wf query "have we tried caching X?" returns the revert's history before anyone re-runs the same experiment.

Scenario — onboarding onto an unfamiliar codebase. Your project's docs are scattered across a README, docs/, and ADRs. Bootstrap the project, wf capture, then ingest each doc. Within an hour you have a claim graph: "writes serialize on the main thread (L42)", "batching collapses N round-trips to 1 (L55)". Ask wf query "Why is the write path slow?" and get an answer citing exact lines you can open — not a hallucinated summary. New docs re-captured later trigger re-ingest only where the sha256 changed.

Scenario — auditing an upstream dependency. Before adopting a library, capture its docs and changelog into the fabric. After each release, wf update re-captures; hash drift flags exactly which claims are affected by the new version — so "we rely on their single-writer guarantee" gets re-verified against the new source text, not forgotten.

Scenario — bootstrapping from PR history. Docs tell you what a system does; PR and issue history tells you why. See Git History Capture (§2): the "problem → intervention" debates that never make it into docs, deterministically pre-filtered so LLM extraction stays cheap, with --churn pointing ingest budget at the highest-traffic areas.

3. Query: Question → Evidence-Backed Answer ​

When the agent asks a question mid-task, it can't afford hallucinated summaries or token-billed retrieval. wf query routes the question by type, scores pages deterministically, and returns a structured answer with citations you can open:

bash
# Ask anything
wf query "Why does my code batch writes but pipeline reads?"

# Save reusable answers as synthesis pages
wf query "What patterns apply to batch-write systems?" --save   # file as a synthesis page (a reusable, citable query result)

# Force query type
wf query "What did we decide about the bridge?" --type decision

# The temporal axis (#189): capture-date ranked, ordered earliest → latest
# with per-step locators (auto-detected for "what changed / how did" queries)
wf query "what changed about our retry handling?" --type changed

Scenario — mid-session architectural question. While refactoring, the agent wonders "do we serialize writes here, or is that only in the other project?" A lexical query costs 0 tokens and returns the relevant claims with locators — the agent reads the underlying sources itself instead of asking you to repeat project history you half-remember.

What the answer actually looks like (this repo's fabric, real output):

text
$ wf query "why does config go stale"

## Bottom line
Go-live thresholds are configured under `go_live` in settings.yaml via
src.config.risk.GoLiveConfig.

## Evidence
- Go-live thresholds are configured under `go_live` in settings.yaml ...
  [L27-L30] quote: "Thresholds are configured under `go_live` in `settings.yaml`..."
  status=supported conf=high ev=primary
...

## Code-reachable evidence (graphify)
- The Market Data Agent performs technical analysis...
  [L286-L288] quote: "**Purpose**: Technical analysis..."
  symbols: `config`

## Confidence
10 claims cited: 10 supported, 6 primary evidence.
Cross-validated across 6 sources.

## Suggested next action
File this answer as a synthesis page if reusable: `--save` flag.

Every claim carries its line locator and verbatim quote — you verify any line by opening the source at that span. With the judgment tier enabled, the top candidates additionally get the System One fusion rerank (measured separations: 0.970 direct answer vs 0.026 word-collision — the false positive the lexical layer alone cannot kill), and graph expansion hops get gated by the same local decision model. --verbose prints both reranks; --no-rerank forces the pure-lexical path.

Scenario — contradicting sources. Two docs disagree about a throughput figure. Ingesting both produces a status: contested claim with a contradicts relation, not a silently merged average. Querying the topic surfaces the conflict with both locators side by side, so a human settles it instead of a model averaging it.

4. Experience → Pattern → Skill (Compounding Loop) ​

bash
# Capture an experience event
wf log --project my-project \
  --problem "API froze under concurrent writes" \
  --intervention "Added write queue with undo grouping" \
  --outcomes "errors=12→0" --tags "my-project,performance"

# List projects + event counts
wf log --list

# Friction-free memory notes (S6): corrections/preferences mid-session, no ceremony.
# Mining reads them — a repeated note becomes a promotion candidate.
wf remember my-project --note "never edit whitelists without reading the guard" --kind feedback
wf remember --list           # standing notes
wf remember --expire         # the ephemeral sweep (30-90d by kind)

# Mine for cross-project patterns
wf mine promotions --dry-run
wf mine promotions

# Chat-mined candidates (#89): stage durable takeaways as gated candidates
wf mine chats <project> --propose
wf promote-patterns --list    # wf gate surfaces them too
wf promote-patterns --apply <id>

# The judged auto-apply tier (#190; opt-in — tuning.promotion.auto_apply: true):
# deterministic preconditions + one calibrated judgment per candidate.
# Confident (>= auto_threshold) applies — stamped + reversible; near-band
# escalates to you; below stays (verdict recorded, --list annotates).
wf promote-patterns --auto          # the whole inbox, banded
wf promote-patterns --unapply <id>  # roll an auto-apply back

# Review dossier, then promote
wf promote --list
wf promote --promote <dossier-file>.md

Scenario — the same bug bites twice. Project A hits a deadlock from concurrent writes; you log the event with measured outcomes. Three weeks later, project B (a completely different codebase) shows the same signature. After the second wf log, mining clusters the two events into a promotion dossier: same problem shape, same intervention, independent evidence. After your review, the pattern is promoted — and project C, bootstrapped next month, inherits the skill "serialize writes + verify parity" automatically instead of rediscovering the bug a third time.

Scenario — killing a bad habit. Experience events aren't only wins: log failed interventions too. Mined clusters can produce anti-patterns ("parallel validation writes caused 3 separate incidents") that future sessions surface as warnings when they detect the setup.

5. Bootstrapping: Connect a New Project ​

bash
# One-time global install
wf install

# Per-project setup
wf bootstrap /path/to/my-project --name "My Project" \
  --domain agent-systems --domain web-systems \
  --skill serialize-and-verify-writes --init-git

# Then capture + ingest sources
wf capture my-project
wf ingest evidence/raw/my-project/docs/*.md --extract-claims

The bootstrap additively merges into existing opencode.json (never overwrites your MCP config, rules, or references).

Scenario — spinning up project five. You've got four projects connected and start a new one. Bootstrap takes a minute: it writes .wiki-overlay.md, creates projects/<slug>/, and merges into opencode.json without touching your MCP servers. At the next session start, the agent loads the global fabric plus this project's overlay — and immediately knows about the three patterns promoted from your other projects, the domain ontology, and which skills apply here. No copying of wiki folders, no "let me catch you up" prompt engineering.

6. Maintenance ​

Keeping the fabric current is mostly deterministic. (Graphify — an optional integration, see its page — builds a code call-graph so the fabric can detect when code changes invalidate stored claims.)

bash
# Rebuild index from actual files (writes registry/catalog.json)
wf rebuild-index
wf rebuild-index --json   # print machine-readable registry to stdout

# Verify health (human-readable)
wf lint

# Verify health (machine-readable, for CI + agent harnesses)
wf lint --format json

# Run formal evaluation (golden corpus)
WIKI_LLM_OPS_MODEL="qwen3.8:27b-mlx" wf eval golden

# Discover new domains from evidence
wf propose-domains

# ONE health report (what status audits — now the bash CLI delegates here)
wf status
#  ✓  Fabric: /Users/johnd/Development/vault
#  ✓  Vault:  /Users/johnd/Development/vault/corpus/wiki (fresh)
#  ✓  LLM:    qwen2.5-coder:7b
#  ✓  Local:  gemma4:e4b-fixed (ollama-served)
#  Inventory: Claims/Sources/Concepts/Patterns/Projects/Discovered
#  ✓  Lint: clean

# Scheduled upstream drift (dry-run first; scheduled on corpus CI)
wf freshness --dry-run

# What's awaiting a human, in one place
wf gate

# Graphify integration (optional, 0 token cost)
graphify update                              # refresh each connected repo's graph (AST-only)
wf graphify all                    # update → import → enrich → diff
wf graphify status                 # dashboard
wf graphify diff                   # staleness check

Run the graphify refresh after code refactors (it's AST-only — a few seconds, no LLM): graphify update in each connected repo, then graphify-bridge --import to sync hashes and --diff to see which claims reference symbols that moved. The fabric's own repo appears in the bridge once it has a repos: entry pointing at . — its self-graph lives in graphify-out/ (see Integrations).

Scenario — docs went stale. You refactor gather_reads into collect_reads; the claim "gather_reads makes O(N) reads ~O(1)" now points at a symbol that no longer exists. The graphify diff (AST-only — Abstract Syntax Tree parsing, no LLM) detects the rename and flags the affected claims as stale. Refresh re-ingests only the changed source, and the claim either updates or is superseded — with the change recorded in the change-set manifest, never silently rewritten.

7. Hooks: The Loop Runs Itself ​

Hooks are a requirement, not a garnish — the freshness guarantee in Staying in Sync rests on them. Without a hook, doc drift only becomes fabric knowledge when someone remembers to run wf capture. wf bootstrap installs it automatically (capture-only, 0 tokens; --no-hook skips; --hook-extract-claims adds LLM compilation; wf hook install freshens projects bootstrapped before this default). Marker-delimited, append-safe, detached; modeled on graphify's git-hook system:

bash
cd ~/Development/my-project
wf hook install                     # post-commit: capture+ingest drift (no LLM)
wf hook install --extract-claims    # + LLM claim extraction on every drift
wf hook status                      # per-repo hook state
wf hook uninstall
WIKI_SKIP_HOOK=1 git commit ...     # skip once, per command

Enhancements over the graphify design, adapted to a content pipeline:

  • Drift-gated ingest: capture exits 2 only when sha256 drift exists, so unchanged docs cost zero LLM calls. When drift DOES exist and re-ingest runs: old-revision claims are mechanically stamped stale_after + flip contested (0 tokens) until the new revision is re-extracted and re-verified — the staleness trigger is now part of the loop, not a lint report that arrives later.
  • Source staleness tiers: every source record carries review_after derived from its capture kind (pr/commit 30d, chats 45d, docs 180d); wf review --verify-sources rolls, stamps, or expires (status: expired when the upstream vanished — tombstone with provenance).
  • Self-skip: commits touching only fabric-owned paths (evidence/, registry/, …) never re-trigger — no capture/ingest loop.
  • CWD-independent: the hook passes --project-root; ingest writes are anchored to the fabric root, so running from inside the project repo can't scatter evidence/ into the wrong repo.
  • Chainable: the block is appended inside a subshell — exit 0 inside it never kills the rest of an existing hook (keep other hooks' first lines non-exec).
  • Bootstrap wiring: wf bootstrap <path> --hook --hook-extract-claims sets it up at project creation.

Always-on agent instructions (like graphify claude install):

bash
wf harness install         # always-on block + procedures in every detected harness
                           # (Claude Code, Codex, Copilot, Gemini CLI, Cursor, Pi, ...)
wf harness status          # per-harness state: detected / installed / —

Bootstrap also installs .opencode/plugins/wiki-fabric.js — a session-start nudge (modeled on graphify's plugin) reminding the agent to prefer wf context / wf query over grep.

8. Generating the Wiki (writer/bookkeeper) ​

The wiki has two producers: the deterministic renderer (wf export wiki — topics, projects, deep dives, staleness) and the generation protocol — for narrative articles that go beyond mechanical assembly, a writer/bookkeeper split keeps token accounting honest and survives interruptions:

bash
wf wiki-generate begin --project my-project   # deterministic outline (0 tokens)
wf wiki-generate next                          # next page job: sections + claims-to-cite
# ...your agent writes the cited prose...
wf wiki-generate submit --page token-rotation --file draft.md --confirm a b
wf wiki-generate finish                        # refuses if any page lacks durable state
  • begin checkpoints the run at evidence/traces/wiki-runs/<id>/.run.json; re-begin resumes, completed pages are never redone.
  • submit validates citations: every assigned claim must appear as [[claim-id]] — a zero-citation page is rejected with the missing list (or retract it via --retract). Accepted = durable boundary: markdown + reconciled claim deltas + verification entry.
  • The same lifecycle is exposed as MCP tools (wiki_begin → wiki_finish) so your coding agent runs it mid-session.
  • Finished pages land under wiki/staged/ → the change-set flow takes over.
  • Generated pages with zero claim citations fail lint (GENERATED).

9. Publish the wiki ​

wf publish stages the wiki output into Quartz v4 (cloned at a pinned release for reproducible builds) and emits a static site — graph view, full-text search, backlinks — a view of the wiki, never the canonical form (vault/corpus/wiki/ stays canonical):

bash
wf publish                        # local: builds to <vault>/site/public
wf publish --out /var/www/wiki    # any target dir
wf publish --dry-run              # no npm, no clone

Measured (fresh sandbox fabric, 24-topic wiki): clone@v4.5.2 → npm ci → build ≈ under a minute; output index.html + per-topic pages + RSS (index.xml).

Three consumers of the same site:

whohow
youopen site/public/index.html or npx quartz serve locally
a hostcopy site/public/ to any static host (GitHub Pages, Netlify, a NAS)
the corpus CIthe scaffolded wiki-publish.yml runs it daily and opens a docs PR when content changed (no-op clean: the export's wiki-export-manifest.json hash means an unchanged wiki commits nothing)

The chain of truths:

Editing site/public/ by hand is the anti-pattern: publish regenerates it. Curate by editing evidence (claims, patterns) or the human vault layer — the views track.

Slow-lane protection (maintenance) ​

Pattern pages accumulate negative knowledge — applicability.excludes and counterexamples. These are protected slow-lane content: bulk ingest-driven edits that change them fail lint (SLOW-REGION) unless the change carries a slow-update justification (verified[].reason: "slow-update: …"), which only the human review path records. Mining never overwrites protected content — it proposes pattern-<id>.revision.md for re-review instead.

bash
wf apply-changeset <slug> --override-slow   # explicit escape hatch

Alpha — expect breaking changes.