The rulebook. How content is structured, how it grows, how skills enforce discipline. Read once; cite from skills and files rather than re-stating.
Sibling documents:
CLAUDE.md— short always-loaded entry file for any agent landing in this repo; imports the two files belowSTATE.md— always-loaded current truth about the project; update it whenever an outcome, number, price or status changesALIASES.md— always-loaded shorthand → canonical name → hub file.claude/rules/— retrieval, writing, drafting and research-framing rules (some always loaded, some path-scoped)AGENT-GUIDE.md— routing table: "where does X go?"INDEX.md— auto-generated one-line index per top-level folder; each folder has its ownINDEX.mdlisting entriesGLOSSARY.md— vocabulary used across this KB and the external patterns it borrows fromLIMITS.md— what this KB deliberately does not try to captureREADING-GUIDES.md— per-persona entry pathsschema/kb-schema.yaml— machine-readable frontmatter contract
A startup's running knowledge base — research, architecture decisions, brainstorms, experiments, competitor analyses, customer interviews, advisor outreach, strategy, GTM, fundraising. Everything the team needs to reason about together that isn't already authoritatively documented inside a sub-project's source tree.
Overlay, not rewrite. When authoritative content exists in another repo (a product codebase, a separate ops repo), cite with relative wikilinks instead of duplicating.
Every file declares a product: in frontmatter. The default schema ships three placeholder tracks — rename them once for your project and never again.
| Track (default) | What it's for |
|---|---|
track-a |
Your primary product line |
track-b |
A second product line, intermediate play, or OSS variant |
shared |
Cross-cutting material that applies to multiple tracks |
To rename: edit schema/kb-schema.yaml §enums.product, then update any existing files via search-and-replace. Single-track projects can collapse all three to one value (e.g. always track-a) without breaking anything.
Strategic threads are orthogonal to tracks. Use optional strategic-thread: frontmatter (multi-value) to tag cross-cutting initiatives: oss, gtm, fundraising, partnerships, hiring, etc. Edit schema/kb-schema.yaml §enums.strategic_thread to match your initiatives. Cross-folder thread rollup is not auto-generated — use grep -l 'strategic-thread:.*fundraising' to find entries for a given thread.
| Folder | Purpose | When written |
|---|---|---|
synthesis/ |
Architecture snapshots — one per product. Most recent dated file per product: = current view. |
On explicit ask to "synthesize" / "snapshot" |
brainstorming/ |
Exploratory thought processes — options weighed, half-formed ideas, train of thought. | On explicit ask to "save this brainstorm" |
strategy/ |
Crystallized decisions on GTM, positioning, pricing, fundraising, partnerships. Distinct from brainstorming: strategy is settled, brainstorming is open. | When a strategic choice has been made and should be recorded |
competitions/ |
External competitions / multi-round programs we enter. Entity-folder per program (<slug>/) holding logs, snapshots, forms, correspondence, round results. Distinct from strategy/ (reusable positioning not bound to one program). |
When entering/submitting to a program or logging a round |
decisions/ |
One file per architectural or strategic decision. Company-level record — scannable via git log + decisions/INDEX.md. |
After a decision is resolved and commits a direction |
questions/ |
Lightweight open questions. Promoted to research-dispatches/ when formalized. |
On demand — "add this to questions" |
research-dispatches/ |
Formal: hypothesis → prior → findings → recommendation. Re-opens appended as dated ## Update sections. |
When asked to research a specific question |
experiments/ |
What we tried, measured, learned. Distinct from benchmarks which hold the spec. | After running an experiment |
benchmarks/ |
Eval specs — what we measure, how, why. | On explicit ask |
comparisons/ |
Head-to-head competitor / alternative analyses. Carry decision_status. |
On explicit ask |
sources/ |
Digested external references — papers, articles, repos, tools. Factual, not opinionated. | Unprompted — whenever user drops a new external source |
study-sessions/ |
Per-source study logs — append-only H2 checkpoints from /study sessions. Filename mirrors source exactly. |
On explicit ask — /study <source> |
concepts/ |
Meta-topics spanning multiple sources. One folder per concept: README.md (research digest, type: concept) + study-log.md (type: study-log). |
On explicit ask — /study <concept> |
discovery/ |
Customer / prospect calls, VC interviews, pilot feedback. Entity-folder pattern for firms that recur. | After a call or interview |
advisors/ |
Academic + advisor outreach: professor profiles, email drafts, collaboration angles, meeting notes. Entity-folder pattern default. | When researching or contacting an advisor |
meetings/ |
Meeting/call notes (any counterparty); the verbatim transcript is its own file in raw/transcripts/, and the notes link to its lines as [T:NN](../raw/transcripts/<file>.md#LNN). Load-bearing extracts propagate to todos//strategy//advisors/. |
Via /meeting — whenever a transcript/notes exist |
traction/ |
Dated metric snapshots — corpus stats, customer pipeline, qualitative signals. | On explicit ask |
finances/ |
Cash-flow tracking — append-only ledger.csv (one row per transaction), redacted statement snapshots, stored receipts, generated summaries. Structured data, not prose. |
Via /finance (ingest) + /financial-summary |
tools/ |
Bookmark-class entries — utility URLs, GPTs, reference docs to find/reuse later. Distinct from sources/ (digest). |
Unprompted — whenever user shares a useful tool/URL |
todos/ |
Tasks, events, deadlines. Completed items move to todos/completed/. |
On explicit ask — /add-todo |
archive/ |
Preserved-but-retired content. Never deleted; history is the point. | On explicit ask — /kb-archive |
runs/ |
KB maintenance runs — audits, syntheses, migrations. Also holds .lock for single-writer coordination. |
By skills themselves (audit, synthesize, etc.) |
schema/ |
Machine-readable schema + per-type templates. Source of truth for what each file type must contain. | When the schema evolves |
scripts/ |
Validation + helper scripts (kb-lint.py, install-hooks.sh). |
When tooling evolves |
sources/ and tools/ are the only folders written unprompted. Everything else is write-on-demand.
Dated files sort chronologically in a flat ls:
- Flat file:
<folder>/YYYY-MM-DD-<slug>.md— lowercase, hyphenated - Entity folder:
<folder>/<entity-slug>/README.md+<YYYY-MM-DD>-<event>.mddated children — used when the subject is a living thing (competitor, advisor, customer firm) accumulating evidence over time. Promote from flat file → folder when content exceeds ~300 lines OR a second dated event is added. - Todos use deadline date, not creation date:
todos/YYYY-MM-DD-<slug>.md(deadline = sortable)
Every file has YAML frontmatter. Fields, allowed values, and per-type requirements are defined in schema/kb-schema.yaml and enforced by scripts/kb-lint.py (called by the pre-commit hook).
Common fields across types:
---
title: "Short descriptive title"
type: brainstorm | synthesis | benchmark-spec | source | research-dispatch | comparison | experiment | decision | question | strategy | interview | lead | advisor | meeting | todo | event | traction-snapshot | study-log | concept | tool
product: track-a | track-b | shared # rename to your tracks in schema/kb-schema.yaml §enums.product
strategic-thread: [oss, gtm, fundraising, partnerships, hiring] # optional multi-value; customize in schema
source: "URL, conversation date, or origin"
date_found: YYYY-MM-DD
tags: [relevant, topic, tags]
status: raw | reviewed | incorporated | superseded | archived
confidence: high | medium | low | uncertain # required on synthesis, comparisons, decisions
supersedes: path/to/prior-doc.md # optional — explicit pointer to the doc this replaces
superseded_by: path/to/newer-doc.md # set on the OLD file in the same commit (lint enforces the pair)
decision_status: considered | adopted | rejected | borrowed-partial # comparisons only
---Keep frontmatter synchronized with content. If status or decision changes, update frontmatter in the same edit.
Anti-sycophancy rules stolen from shannholmberg-llm-wikid and applied across decision-carrying files:
- Synthesis must include
## Counter-argumentsand## Data gaps - Decisions must include
## Whyand## What we're giving up - Comparisons must include a
## Decisionsection that setsdecision_status - Entity-folder README (competitor, advisor, customer firm) body is current truth, rewritten as it changes. Dated sibling files in the same folder form the timeline. No
## Timelinesection in the README — usels <folder>/for chronology.
study-sessions/ and concepts/*/study-log.md use type: study-log. Append-only: each /study session adds one H2 checkpoint at session end (not mid-session). Newest at the bottom. Checkpoint shape:
## Checkpoint — YYYY-MM-DD (session N)- What we covered — topics touched this session
- What I now understand — incremental delta
- Candidate questions / decisions — inline
[?question]/[?decision]tags - Related sources touched — wikilinks triggering the cross-ref rule below
- Open threads → next session — resume hints
Tag syntax — [?question] and [?decision]. Used inline inside checkpoints to flag candidates. Never auto-promoted. Promotion to questions/ or decisions/ happens only when the user explicitly asks ("promote the [?question] from session 3 to questions/"). The /study skill picks up the tagged line and routes to /add-entry or /kb-promote. Tags are an affordance, not a commitment.
Bidirectional cross-reference rule. When a session on Source A meaningfully touches Source B (or concept C):
- A's study file gets the full checkpoint with
[[study-sessions/B]] §checkpoint-Nunder "Related sources touched" - B's study file gets a short reciprocal checkpoint — one sentence, pointer back (
from [[study-sessions/A]] §checkpoint-N), no primary-study progress claimed
Both sides know about the link. last_checkpoint: in frontmatter updates on both files.
Concept promotion is user-prompted. If a source session keeps revealing cross-cutting themes, /study suggests "promote to a concept folder?" — never automatic.
Three-tier format. Escalate only as needed.
| Tier | Form | Use |
|---|---|---|
| Whole doc | [[comparisons/YYYY-MM-DD-competitor-slug]] |
Pointing at a doc as one concept |
| Section-precise | [[comparisons/YYYY-MM-DD-competitor-slug]] §"Decision" |
Default — points at one section |
| Quote-precise | [[comparisons/YYYY-MM-DD-competitor-slug]] §"Decision" ("verbatim claim here") |
When the reader must read one verbatim claim |
No line-range citations ([[foo#L42-58]]). They rot silently.
One exception: transcript line links. Meeting notes cite their verbatim transcript as [T:NN](../raw/transcripts/<file>.md#LNN). This is safe because a transcript in raw/transcripts/ is never edited after filing, so its line numbers cannot drift. Never use line links into any file that gets edited.
Self-firing artifacts — section headings only. Hooks, skill files, scripts, and memory entries fire without a human re-reading the target. Line numbers (file.md:42, file.md:129-141) rot silently: the artifact keeps pointing at what used to be that line. Always cite by section heading (file.md § "Header").
- ✗
AGENT-GUIDE.md:129-141 - ✓
AGENT-GUIDE.md § "Login-walled content"
Chat-layer narration to the user (Claude pinning a claim during conversation) may still use file.md:42 — the user verifies immediately, and precision beats rot risk for live reading. The split: who reads the citation, and when.
Keep H3 subsections ~10-50 lines. A cited section is only useful if it fits in a reader's context cheaply.
Cross-project wikilinks use relative paths:
[[../your-product-repo/TECH-DECISIONS]][[../your-other-repo/notes/2026-04-10-architecture]]
Git-backed: when file history is needed, git log --follow <file> is authoritative — the semantic supersedes: chain and the syntactic git history complement each other.
How the KB expands over time. Followed by skills; violate only with justification.
Canonical thresholds. Every numeric rule below references one of these names. Skills, scripts, and hooks cite the NAME, not the value — so changing a value here propagates to every enforcer in one edit. Prefer a name over a number anywhere you'd otherwise hardcode a threshold.
# Staleness (flagged by /kb-audit)
STALE_DRAFT_DAYS=90 # status: raw/prospect unchanged beyond → stale
OVERSIZED_FILE_LINES=500 # hard oversized; reactive (you missed PROMOTE_TO_MULTICHAPTER_LINES)
UNDECIDED_COMPARISON_DAYS=60 # decision_status: considered, no commit → flagged
# Growth / promotion (proactive signals)
PROMOTE_TO_MULTICHAPTER_LINES=300 # single file exceeds → split into multi-chapter
FOLDER_SPLIT_FILE_COUNT=15 # folder exceeds → split into by-<facet>/ subdirs
ANTI_CRAMMING_MAX_MAJOR_SECTIONS=2 # appending one more (3rd) → split to new file instead
ANTI_THINNING_MIN_LINES=30 # file below → fold into existing (description: field already gives it a one-line presence in parent INDEX.md)
# New-folder gate (/kb-add-folder)
NEW_FOLDER_MIN_FILES=3 # minimum files that fit the new category
NEW_FOLDER_INDEX_MAX_LINES=25 # INDEX.md size ceiling (proves the category is tight)
# Archiving (/kb-archive)
ARCHIVE_UNCITED_MONTHS=3 # superseded + uncited for this long → eligible
Adding a new folder — only if ALL:
- At least
NEW_FOLDER_MIN_FILESfiles fit the category - They don't fit existing folders
- There is a clear structural difference (not just a topic; topics live in tags)
- You can write its
INDEX.mdwithinNEW_FOLDER_INDEX_MAX_LINESlines without hand-waving
Use /kb-add-folder to force the justification + creation of <newfolder>/README.md with type: folder frontmatter. The generator picks up the new folder on the next run.
Promoting a file to a multi-chapter subdirectory — when a single file exceeds PROMOTE_TO_MULTICHAPTER_LINES AND has a natural progression. Start flat; promote when the signal appears. Use a comparisons/YYYY-MM-DD-competitor-slug/ directory with README.md as the entry point and per-chapter sibling files.
Splitting a folder into sub-taxonomy — more than FOLDER_SPLIT_FILE_COUNT files with 2-3 natural clusters. Use <folder>/by-<facet>/ subdirectories; don't refactor frontmatter.
Archiving — move to archive/ when fully superseded AND uncited for ARCHIVE_UNCITED_MONTHS months AND no active decision references it. Moving the file automatically removes its listing from the source folder's INDEX.md (regenerator skips files in archive/). Never delete.
Resolution stamps (partial supersede) — when new content answers an open thread inside an otherwise-live doc, do NOT supersede, archive, or rewrite the whole doc. Supersede is whole-file replacement (supersedes: frontmatter, a successor file); a resolution stamp closes one question inside a file that's still current. This is the lightweight sibling of supersede, and the common case — a new entry often settles a thread recorded elsewhere without invalidating the host doc.
- Format:
**Resolved YYYY-MM-DD → [[resolver-file]]:** <one line on what was settled>, placed at the head of the resolved bullet/section. Leave the original question text below it — don't delete it; the open thread is part of the history, the stamp just caps it. - Pairs with the open-thread vocabulary: a stamp closes a
## Open threadsbullet, a[?question]/[?decision]tag (/study), or any line phrased as an unresolved question. Reuse those markers so threads stay greppable. - Bidirectional: the resolving doc links back to the doc it resolved (a
## Relatedwikilink is enough). Both sides know about the link, same as supersede. - Trigger: any write that settles a question recorded elsewhere — most often mid-
/add-entryor/meeting, when the new entry happens to answer an older thread. The skills prompt for it; the obligation holds for any write, skill or hand edit. - Mechanics: it's a hand edit, no skill of its own. No
supersedes:/superseded_by:frontmatter (that's whole-file), no archive (the host doc stays live). Do it inside the same lock + commit session as the content that triggered it.
Anti-cramming — if appending a new major section would push the doc past ANTI_CRAMMING_MAX_MAJOR_SECTIONS, consider splitting into a new file first.
Anti-thinning — file below ANTI_THINNING_MIN_LINES lines that isn't a glossary/source entry? Fold into an existing file. The file's description: frontmatter already gives it one-line presence in the parent folder's auto-generated INDEX.md; a whole file for one sentence is wasteful.
Promotion path — questions/ (lightweight) → research-dispatches/ (formalized) → decisions/ (company-level resolution) → synthesis/ (rolled up). /kb-promote handles the backlinks.
Audit flags (/kb-audit surfaces, doesn't fix):
- Raw drafts unchanged for more than
STALE_DRAFT_DAYSdays. - Files exceeding
OVERSIZED_FILE_LINESlines. - Comparisons at
decision_status: consideredwith no commit in the lastUNDECIDED_COMPARISON_DAYSdays.
Only one agent performs KB writes at a time. Any write OR browser-tool operation (treated as a write because it consumes the single browser session) touches a lock file runs/.lock with session ID + timestamp. Other agents check the lock before starting; either wait or abort with "another agent is writing, retry later."
Manual override: rm runs/.lock if a previous session died.
All write-capable skills enforce this as their first/last step. You don't have to think about it.
LinkedIn / X ingestion is login-walled — WebFetch cannot see it (a hook denies it). The main agent uses a logged-in browser tool; which one is a per-machine choice (see AGENT-GUIDE.md § "Login-walled content"). Subagents never drive a browser. Subject to the single-writer rule.
One commit per atomic change, not one per session. Use conventional-commit-style prefixes that make git log --oneline scannable.
| Prefix | For | Example |
|---|---|---|
source: |
New external reference | source: add 2026-04-17-paper-slug |
comparison: |
Competitor analysis | comparison: add 2026-04-17-competitor-slug |
decision: |
Architectural / strategic decision | decision: add 2026-04-17-example-model-choice |
experiment: |
Experiment log | experiment: log 2026-04-17-corpus-run |
synthesis: |
Snapshot | synthesis: snapshot track-a @ 2026-04-17 |
brainstorm: |
Thought-process writeup | brainstorm: add 2026-04-17-pricing-tiers |
strategy: |
Crystallized strategy entry | strategy: add 2026-04-17-oss-positioning |
interview: / discovery: |
Customer/prospect call | interview: add 2026-04-17-acme-capital-partner-call |
lead: |
Pre-call prospect event (signup, outreach sent/received) | lead: add 2026-04-21-prospect-signup / lead: contacted 2026-04-23-prospect-slug |
advisor: |
Advisor profile / event | advisor: contact 2026-04-17-example-advisor-email-sent |
meeting: |
Meeting/call record (+ its propagated extracts) | meeting: add 2026-04-17-example-advisor-pricing |
question: |
Open question | question: add 2026-04-17-embedding-model / question: promote 2026-04-17-embedding-model → research-dispatches/ |
research: |
Research dispatch | research: add 2026-04-17-example-research-question |
tool: |
New tool/bookmark | tool: add 2026-04-27-example-tool |
todo: |
Todo/event | todo: add 2026-04-20-email-advisor / todo: complete 2026-04-17-customer-intro |
finance: |
Ledger ingest or summary | finance: log 2026-05-30 Example SaaS $40 (saas) / finance: reconcile 2026-05 / finance: summary 2026-05 |
archive: |
Archived file | archive: 2026-04-10-old-brainstorm |
study: |
Study log checkpoint append, new concept folder, or study-system seed | study: checkpoint paper-slug session 1 / study: add concepts/example-concept |
index: |
Regeneration of auto-generated INDEX.md files | index: regenerate after description edits |
conventions: |
Rulebook edit | conventions: add growth rules section |
schema: |
Schema edit | schema: add advisor type |
skill: |
Skill edit | skill: update add-entry to use schema templates |
kb: |
Structural / meta change | kb: add .claude/rules/kb-writes.md |
When to commit:
- After each new entry (each source, comparison, decision, interview, advisor event, etc.)
- After each synthesis snapshot
- After each description-only edit that regenerates INDEX.md files
- After each CONVENTIONS / AGENT-GUIDE / GLOSSARY edit
- After each skill edit
- After each schema change
- After each structural move (archive, promotion, rename)
Always git push after every commit. No local-only buffering. Skills handle stage → commit → push as a unit.
All commits end with:
Co-Authored-By: <the model that made the commit> <noreply@anthropic.com>
- Don't write opinionated takes inside
sources/files (opinions go to brainstorming or comparisons). - Don't write synthesis / benchmark / comparison / dispatch / experiment / decision / strategy / advisor / discovery files without being asked. These are explicit milestones, not running commentary.
- Don't create dated "session" subfolders. Flat-date naming is the structure, except the multi-chapter exception for entities.
- Don't delete or overwrite old files when superseding. Write a new dated file with
supersedes:, and back-stamp the old one in the same commit (status: superseded,superseded_by:, a> ⚠️ Superseded by [[...]]banner); lint enforces the pair, and the regenerated INDEX tags the old entry[superseded]. History is the point. - Don't hand-label a doc "current" or "canonical" (in a description, README, or hub). The label rots the day a newer version lands; the current version is the newest one without
superseded_by:. - Don't supersede, archive, or rewrite a whole doc when only one thread inside it got resolved — use an inline resolution stamp (see §"Growth rules" → "Resolution stamps"). And don't leave the thread silently resolved either: stamp it so the next reader doesn't re-litigate a settled question.
- Don't duplicate content that lives authoritatively in a sibling repo (your product code, an ops repo, a separate research repo). Cite out.
- Don't bypass the single-writer lock.
- Don't skip the pre-commit lint.
- Don't batch commits. One logical change per commit; push after each.
- Don't shorten named entities. Customers, advisors, and companies get their full canonical name on every mention — see
GLOSSARY.md§ "Named entities — canonical names" (e.g. Example Co, never bare "Example"). This applies to drafts written for the user (emails, applications, decks) as much as to KB files. - Don't leave current truth stale. A write that changes an outcome, status, number or price also updates the matching line in
STATE.mdand itsas-of:date.