protocol agentproto.shcli cli.agentproto.shpanel /panel
agentproto

AIP-10: KNOWLEDGE.md — agentknowledge/v1 (LLM-maintained wiki)

A filesystem-first knowledge-base format where an LLM curates, links, and lints a markdown wiki on top of immutable raw sources, turning agent knowledge into a compounding artifact instead of a per-query retrieval miss.

FieldValue
AIP10
TitleKNOWLEDGE.md — agentknowledge/v1 (LLM-maintained wiki)
StatusDraft
TypeSchema
Domainknowledge.sh
Doctypesknowledge.entry/v1 (curated), knowledge.source/v1 (immutable), knowledge.workspace/v1 (manifest + view)
RequiresAIP-1, AIP-2
Composes withAIP-3 (skills), AIP-6 (companies), AIP-7 (governance), AIP-9 (operators), AIP-26 (code-workspace refs), AIP-27 (typed refs)
Reference Impl@agentproto/knowledge

Abstract

agentknowledge/v1 defines a markdown-based wiki format that an LLM owns end-to-end. Three doctypes cooperate: raw sources stay immutable (knowledge.source/v1), curated entries are rewritten by the agent on every ingest (knowledge.entry/v1), and a workspace manifest declares the wiki's shape — entity types, lint rules, retention, curation policy — in a machine-parseable file (knowledge.workspace/v1, written as KNOWLEDGE.md). The same workspace doctype, used recursively via extends:, also expresses per-context views: an operator (AIP-9), a company (AIP-6), or a skill (AIP-3) can ship its OWN KNOWLEDGE.md that adapts the base workspace for its lens — different entity focus, tone, conflict-resolution rules — without forking the wiki itself. A sibling free-form prose file (AGENTS.md) is RECOMMENDED for human readers, maintained alongside the canonical machine config. Together these turn agent knowledge into a compounding, composable artifact instead of a stateless RAG retrieval, and make the resulting knowledge base portable across runtimes.

Motivation

Most agent knowledge today lives in one of two places: an opaque vector store rebuilt at query time (RAG), or a vendor-specific "memory" object that doesn't survive across runtimes. Both treat knowledge as a retrieval problem. Neither produces an artifact a human or a different agent can read, audit, or fork.

Andrej Karpathy's "LLM Wiki" pattern (April 2026) reframes the problem: treat raw sources as source code, treat the LLM as a compiler, and let it produce a structured wiki — a compiled knowledge artifact that compounds across ingests. AIP-10 codifies that pattern as a portable file format so that:

  • A wiki built in one runtime can be opened, queried, and extended in another.
  • The workspace manifest (KNOWLEDGE.md) becomes the unit of trade — domain experts ship a workspace shape, runtimes execute it; a sibling human-readable AGENTS.md documents intent for readers and reviewers.
  • Cross-references, contradictions, and provenance live in the files themselves, not in a query-time prompt.
  • Different consumers can read the same wiki through different lenses. An operator focused on research wants Concept entries surfaced first; the same wiki seen by a sales operator wants Customer and Deal entries. Rather than fork the wiki per consumer, AIP-10 lets each consumer ship a small KNOWLEDGE.md that extends the workspace and overrides the bits that matter for its context. The wiki is one; the views are many.

This last point is the structural reason KNOWLEDGE.md is one doctype used in two modes: a workspace-root manifest at the wiki root, and a view in any operator/company/skill folder that wants its own lens. Composition is the same mechanism used by Tailwind presets, designkit overrides, and the profile registry pattern that shows up across this AIP family — the wiki ships a base shape, and consumers compose narrower shapes on top.

Prior art: Karpathy's llm-wiki gist, AGENTS.md, Anthropic's "Agent Skills" pattern (AIP-3), the filesystem-first lineage of AIP-6/AIP-7/AIP-8.

Specification

A conforming agentknowledge/v1 package is a directory tree of four layers: the workspace manifest, the immutable sources, the curated entries, and the optional human-readable schema file. Per-context views live wherever the consumer that owns them lives.

my-wiki/
├── KNOWLEDGE.md           # workspace manifest (REQUIRED, root, machine config)
├── AGENTS.md              # human-readable schema (RECOMMENDED, prose companion)
├── _index.md              # generated catalog (REQUIRED, root)
├── _log.md                # append-only activity log (REQUIRED, root)
├── _manifest.json         # provenance/dedup manifest (REQUIRED, root)
├── sources/               # raw sources (immutable; LLM reads, never writes)
│   ├── 2026-04-15-paper.pdf
│   └── 2026-04-20-meeting.md
├── entities/              # one page per real-world entity
│   └── andrej-karpathy.md
├── concepts/              # one page per abstract concept
│   └── compounding-knowledge.md
├── summaries/             # one page per ingested source
│   └── 2026-04-15-paper.md
└── timelines/             # optional ordered narratives
    └── 2026-q2-research.md

Per-context views live alongside their consumer, not under the wiki root. Conventional locations:

operators/research-analyst/KNOWLEDGE.md        # extends ../../my-wiki/KNOWLEDGE.md
companies/acme/KNOWLEDGE.md                    # extends ../../my-wiki/KNOWLEDGE.md
skills/sales-assist/KNOWLEDGE.md               # extends ../../my-wiki/KNOWLEDGE.md

A view's extends: field points to a parent KNOWLEDGE.md (workspace root OR another view), and appliesTo: binds the view to one or more operator/company/skill workspace refs. The runtime resolves the chain on load and exposes the merged effective config to the consumer.

Layer 1 — Raw sources (sources/)

The runtime MUST treat any file under sources/ as immutable. The LLM reads these files but MUST NOT modify, rename, or delete them. New sources are added by humans (or upstream automation) and trigger ingest.

Layer 2 — Wiki pages (everywhere except sources/, KNOWLEDGE.md, and AGENTS.md)

Every wiki page is markdown with YAML frontmatter:

---
schema: knowledge/v1
slug: <kebab-case-page-id>
kind: entity | concept | summary | comparison | timeline
title: <human-readable title>
sources:                              # provenance — refs into sources/
  - sources/2026-04-15-paper.pdf
  - sources/2026-04-20-meeting.md
refs:                                 # OPTIONAL — AIP-27 Ref[]: what this page
                                      #   POINTS AT in other workspaces (a code
                                      #   file/symbol in an AIP-26 workspace, a
                                      #   page in another wiki). Canonical
                                      #   scalar form is AIP-27 compact. See
                                      #   "Cross-workspace references (AIP-27)".
  - github:agentproto/ts:packages/runtime/src/http-server.ts   # code, other workspace
  - wiki:platform/http-server                                   # page, other wiki
confidence: 0 .. 1                    # OPTIONAL, default 1.0
updated_at: <ISO 8601>
supersedes: [<slug>]                  # OPTIONAL — earlier pages this replaces
contradicts: [<slug>]                 # OPTIONAL — pages whose claims conflict
metadata:                             # OPTIONAL — vendor extensions
  <vendor>:
    <field>: <value>
---

# <title>

<body — prose, tables, code, headings>

The slug is the page's canonical identity: a bare kebab-case token ([a-z0-9-]+, no /), unique within the wiki, equal by convention to the page filename without its .md extension. It is REQUIRED. A runtime MAY namespace its internal node identifier by the page's containing directory (e.g. <dir>/<slug>) for retrieval or graph indexing, but that namespacing is the runtime's own concern and MUST NOT leak into the frontmatter contract: a conforming host MUST accept the bare frontmatter slug, MUST NOT require it to carry a path prefix, and MUST NOT reject a page whose slug equals its path basename. A runtime that refuses a conformant bare slug — or that forces the author to omit slug or spell it as a non-kebab path — is non-conforming; the portable wiki keeps its bare slugs and the runtime derives whatever internal id it needs from them.

Three reference surfaces exist on a page and MUST NOT be conflated:

  • [[slug]] body links — intra-wiki cross-references between pages of this wiki. Cross-references between pages of the same wiki MUST use the wikilink syntax [[slug]] or markdown links to relative .md paths; the runtime MUST be able to resolve both forms.
  • sources: frontmatter — provenance IN: the raw sources/ files this page was distilled FROM (Layer 1).
  • refs: frontmatter — references OUT: what this page is ABOUT / POINTS AT in other workspaces (see Cross-workspace references (AIP-27)).

refs: is OPTIONAL and, when present, MUST be an array of AIP-27 Ref values in AIP-27 compact form (e.g. github:…, local:…, git:…, url:…, or the wiki:<wiki-slug>/<page-slug> / ws://wikis/… spelling for cross-wiki pages). It is DISTINCT from both sources: (raw-source provenance, where the knowledge came from) and [[slug]] body links (intra-wiki navigation): refs: is the typed, cross-workspace "this page is about that thing" edge. A runtime MUST NOT treat a refs: entry as a provenance source, and MUST NOT require its target to exist inside this wiki.

Cross-workspace references (AIP-27)

The refs: page field carries AIP-27 Ref values so a knowledge page can point OUT of the wiki: at a code file or symbol in an AIP-26 code-workspace, at a resource on the web, or at a page in another wiki. refs: is the typed, machine-resolvable answer to "what is this page about, elsewhere?" — the edge a graph runtime traverses to walk code↔knowledge.

Each refs: entry is a base ref — an AIP-27 compact form or object form — OPTIONALLY carrying an AIP-10-owned #symbol=<name> addressing fragment (see below). A runtime MUST first strip any #symbol= fragment, then parse the remaining base ref with an AIP-27-conformant parser, and MUST NOT redefine that grammar. Any AIP-27 kind is admissible; the kinds a knowledge page uses in practice are local, github, git, url (code / documents) and the wiki kind — compact wiki:<wiki-slug>/<page-slug>, URI-spelled ws://wikis/<wiki-slug>/<page-slug> — for pages in other wikis (see Cross-wiki references).

Code references (AIP-26 workspaces)

A page distilled from, or documenting, code addresses that code with a file-collection ref (AIP-27 §Base collections). The code lives in a DIFFERENT workspace than the wiki, so github: (or a ws://workspaces/<slug>/… form) that names the other workspace explicitly is the primary spelling:

# A pr-review knowledge page that is ABOUT the HTTP server it reviewed:
refs:
  - github:agentproto/ts:packages/runtime/src/http-server.ts               # code in another repo
  - github:agentproto/ts:packages/runtime/src/http-server.ts#symbol=serve  # a symbol within it
  - local:packages/runtime/src/http-server.ts                              # ONLY in a monorepo (see below)

The github/local base bodies are exactly the file addresses AIP-26 uses for its code.sources[] (github = owner/repo

  • repo-relative path; local = workspace-relative path). local: resolves against the CITING wiki's own workspace root, so it addresses code cross-workspace ONLY when the wiki and the code-workspace share one filesystem root (a monorepo); otherwise use github: or the ws://workspaces/<slug>/… form, which name the other workspace explicitly.

#symbol=<name> is an AIP-10-owned addressing fragment, NOT part of AIP-27's grammar. AIP-27 reserves # for its #sha256= suffix and requires # to be percent-encoded inside path bodies, so a #symbol= fragment is opaque to a strict AIP-27 parser (it would raise InvalidRefBody, not silently strip). A runtime MUST therefore STRIP any trailing #symbol=<name> from the ref string BEFORE handing the remaining, pure-AIP-27-conforming base body to the parser. A code-aware runtime MAY then resolve the stripped symbol name to a span inside the file — only AFTER AIP-27 has resolved the file itself; a runtime that ignores the fragment resolves the whole containing file (graceful degradation, never an error). The fragment lives entirely in AIP-10's layer and neither extends nor redefines AIP-27.

Cross-wiki references

AIP-10 today describes a SINGLE wiki, but a refs: entry MAY point at a page in ANOTHER wiki, via the AIP-27 wiki kind (the wikiswiki row of AIP-27 §Reference syntax, a multi-segment body). It has two equivalent spellings — the compact form (canonical for frontmatter scalars) and the ws:// URI form — and a host MUST accept both on input:

wiki:<wiki-slug>/<page-slug>              # compact — canonical in refs:
ws://wikis/<wiki-slug>/<page-slug>        # equivalent ws:// URI spelling
# A page in the "product" wiki that is about a page in the "platform" wiki:
refs:
  - wiki:platform/http-server        # cross-wiki page ref (compact)
  - wiki:platform/rate-limiting

<wiki-slug> names a wiki the host knows; <page-slug> is that wiki's Layer-2 page slug. This ref is tenant-local by the AIP-27 mandate (a host MUST resolve it in the citing wiki's tenant scope and MUST reject cross-tenant bindings). It is DISTINCT from [[slug]], which stays intra-wiki: [[slug]] never crosses a wiki boundary; wiki:… always does.

The cross-wiki ref SYNTAX is normative here; building and traversing the graph is a RUNTIME concern. Per the Query contract, a wiki is queryable with file reads alone and a runtime MAY add auxiliary indices (BM25, embeddings, graph) on top. A runtime MAY therefore index the refs: edges — code↔knowledge and wiki↔wiki — and expose graph traversal (this is the spec a graph runtime such as gbrain implements), but the wiki files remain the source of truth and no index is required for conformance.

Layer 3 — Human-readable schema (AGENTS.md)

A RECOMMENDED root file describing, in prose, how the LLM should curate the wiki. It exists for human readers and review tooling — it is the companion artifact to the canonical machine-readable KNOWLEDGE.md (Layer 4). Conforming wikis SHOULD ship both: KNOWLEDGE.md for runtimes and linters to consume programmatically, AGENTS.md for humans to read during onboarding, review, or governance approval.

Earlier drafts of this AIP made AGENTS.md REQUIRED and treated it as the schema of record. That role now belongs to KNOWLEDGE.md; the prose file is downgraded to RECOMMENDED so that automated pipelines can ship without it, while community spec compatibility (notably agents.md) is preserved for hosts that want to co-publish.

When present, AGENTS.md SHOULD contain at least:

  • Page conventions — required frontmatter, naming, allowed kinds, body structure for each kind. (Mirrors entityTypes in KNOWLEDGE.md.)
  • Ingest workflow — what the LLM does when a new source appears in sources/: which pages to read, which pages to update, when to create new pages, how to update _index.md and append to _log.md.
  • Contradiction policy — how to resolve conflicts (recency, source authority, observation count) and how to flag unresolved conflicts via contradicts. (Mirrors curation.conflictResolution in KNOWLEDGE.md.)
  • Lint rules — which orphans/stale-claims/missing-concepts the LLM should surface during a maintenance pass. (Mirrors lints in KNOWLEDGE.md.)

A host MAY treat AGENTS.md as the source of truth for human-facing display and KNOWLEDGE.md as the source of truth for programmatic behaviour. When the two disagree, runtimes MUST prefer KNOWLEDGE.md; linters SHOULD surface the divergence as a wiki_schema_drift finding so human authors can re-sync the prose.

Layer 4 — Workspace manifest (KNOWLEDGE.md)

KNOWLEDGE.md is the canonical, machine-parseable workspace manifest. It encodes everything AGENTS.md describes in prose — entity types, lint rules, retention, curation policy — into a YAML frontmatter that runtimes can validate, merge, and diff. The body of KNOWLEDGE.md remains free-form markdown for any prose the manifest author wants to ship inline.

The same doctype, knowledge.workspace/v1, is used in TWO modes:

  • Workspace-root mode<wiki>/KNOWLEDGE.md, no extends. Declares the base shape: what entity types exist, what lints run, what tone the curator agent uses, what retention applies to sources.
  • View mode<consumer>/KNOWLEDGE.md, extends: set to a parent KNOWLEDGE.md path. Adapts the base for a specific operator (AIP-9), company (AIP-6), or skill (AIP-3). View mode is the mechanism that lets one wiki serve many lenses without forking.

Frontmatter shape

---
schema: knowledge.workspace/v1
name: <kebab-case-id>                # required
title: <human-readable>              # required
description: <one-paragraph purpose> # required
version: <semver>                    # required, the WORKSPACE version
                                     #   (bump on shape changes)

# Composition (view mode only)
extends: ../path/to/parent/KNOWLEDGE.md  # OPTIONAL — relative path to
                                         #   parent; recursive merge
appliesTo:                                # OPTIONAL — bind this view to
                                          #   specific consumers OR dimensions
  - ws://operators/<slug>                 #   AIP-9 operator
  - ws://companies/<slug>                 #   AIP-6 company
  - ws://skills/<slug>                    #   AIP-3 skill
  - <dimension>/<value>                   #   dimension ref, e.g.
                                          #   region/fr, compliance/gdpr,
                                          #   org/acme, tier/exec

# Cross-AIP refs
curator: ws://operators/<slug>          # OPTIONAL — AIP-9 operator that
                                        #   curates this workspace
governance: <path-or-ref>               # OPTIONAL — AIP-7 policy or
                                        #   audit binding

# Entity model — what TYPES of entries this workspace recognizes
entityTypes:                            # array; merge-by-name vs parent
  - name: <PascalCase>
    fields: [<field>, ...]              # canonical fields
    icon: <emoji>                       # OPTIONAL display hint
    description: <prose>                # OPTIONAL
    parent: <PascalCase>                # OPTIONAL — extends another
                                        #   local type

# Lint rules — what the curator agent checks every maintenance pass
lints:                                  # array; merge-by-id vs parent
  - id: <kebab-id>                      # required, stable
    kind: require-source | max-age | min-confidence | broken-ref
        | orphan | custom
    appliesTo: <EntityType> | "*"
    severity: error | warn | info
    params:                             # kind-specific
      <key>: <value>

# Source registry behavior
sources:
  retention: forever | days:<n>
  signing: required | optional | none   # composes with AIP-7 signing
  hashAlgo: sha256 | sha512 | blake3
  authorityDefault: primary | secondary | rumour

# Curation behavior
curation:
  tone: <free-form>                     # e.g. "academic", "sales"
  depth: shallow | medium | deep
  autoLink: byName | manual | off
  conflictResolution: defer | recency | authority
                    | observation-count | keep-both
  newEntryThreshold: <prose>            # when to promote a mention to
                                        #   a full entry

# Query hints — how consumers should retrieve from this view
queryHints:
  preferRecent: true | false
  preferAuthoritative: true | false
  scopeTo: [<EntityType>, ...]          # OPTIONAL — narrow query default

# Display / UX hints (agnostic to runtime)
display:
  homePage: <slug>                      # OPTIONAL — landing entry
  defaultGrouping: kind | tag | source

metadata:                               # vendor extensions, namespaced
  layer:                                # OPTIONAL (view mode) — composition mode
    mode: lens | constraint             #   default lens. See "Layer mode" below.
  <vendor>:
    <field>: <value>
---

# <body — markdown prose>

Conventional sections in the body include:

- ## Purpose — what this workspace is for, who uses it
- ## Conventions — naming, style, what to avoid
- ## When to extend vs replace — composition guidance
- ## Examples — short snippets of typical entries

Composition semantics

When a runtime loads a KNOWLEDGE.md whose frontmatter declares extends:, it MUST:

  1. Walk the parent chain. Recursively load the parent referenced by extends:, then that parent's parent, until a manifest with no extends is reached (the workspace root). Maximum chain depth is eight. Hosts MUST detect cycles by tracking visited absolute paths.
  2. Treat both depth overflow and cycle detection as warnings, not errors. A view whose chain is malformed MUST still load — the runtime falls back to the local manifest only and surfaces a knowledge_extends_cycle (or knowledge_extends_depth_exceeded) warning to the consumer's debug surface.
  3. Tolerate a missing parent. If extends: points to a path that does not exist, the runtime emits knowledge_extends_missing as a warning and uses the local manifest only. View activation does not abort.
  4. Merge bottom-up. Walk the chain from the workspace root toward the leaf view, merging each manifest into the accumulator using the strategy below.

Merge strategy (child wins on conflicts):

FieldStrategyNotes
name, title, description, versionoverrideChild's identity wins; the runtime exposes both.
extendsnot inheritedLocal-only field.
appliesTonot inheritedLocal-only binding.
curator, governanceoverrideChild can rebind.
entityTypesmerge-by-nameA child entry with the same name replaces the parent's; new names are appended. Subtyping is explicit via parent:.
entityTypes[].fieldsunionChild fields are appended to parent's; duplicates collapsed.
lintsmerge-by-idChild lint with same id replaces parent's; new ids are appended.
sources.*override per leaf fieldretention, signing, hashAlgo, authorityDefault each independently override.
curation.*override per leaf fieldSame shape as sources.
queryHints.*override per leaf fieldscopeTo is replaced wholesale by child if present.
display.*override per leaf field
metadatadeep-mergeRecursive merge; vendor namespaces accumulate.

The runtime MUST expose both the merged effective config AND the resolution chain (ordered list of absolute paths consumed during merge). Consumers use the merged config; tooling uses the chain to explain why a field has the value it does.

Dimension refs

appliesTo accepts, alongside the ws://operators|companies|skills/* consumer refs, dimension refs of the form <dimension>/<value>: region/fr, compliance/gdpr, org/acme, tier/exec. A dimension ref binds a view to a facet of the resolution context rather than a single named consumer, so one view can adapt the workspace for "every operator running in France" or "any tier-exec recall". The dimension namespace is open: hosts register which dimensions they resolve (a host that does not know compliance/* simply never activates such a view). A view bound to a dimension the host cannot resolve is inert, not an error; a view bound to a malformed ref (no /, empty value) emits knowledge_appliesto_unresolvable.

Layer mode — lens vs constraint

A view declares its composition mode via metadata.layer.mode (default lens):

  • lens — the view adapts the workspace and is freely overridable by higher-precedence layers and by guild-local edits. Org house-style, tier tone, regional preferences are lenses.
  • constraint — the view is a floor. Higher-precedence layers and guild-local edits MAY extend a constraint view (add entries, add fields) but MUST NOT shadow, soften, or tombstone its protected entries (its own entries/* and the lints it declares). A compliance or legal view (compliance/gdpr, region/fr labour law) ships as a constraint so a downstream org pack cannot silently bury it.

A host MUST surface, per merged field and per resolved entry, whether it originated from a constraint layer (so a reviewer sees a value is protected). Two constraint layers that conflict on the same protected entry are a governance escalation, not a silent child-wins merge — the host emits knowledge_constraint_conflict and keeps both for review.

Plane-precedence invariant

Composition happens on two planes and they resolve different things; the invariant binds them:

  1. Manifest-merge plane (extends/appliesTo, child-wins) resolves the effective shape/lens — entity types, lints, tone, query hints.
  2. Path-shadow plane (the mounted entry tree) resolves entry content — a higher layer's entries/x.md shadows a lower layer's at the same path.

Invariant. The guild-writable (highest-precedence) layer always shadows pack content on the path-shadow plane — EXCEPT a constraint-mode layer's protected entries, which neither higher packs nor guild edits may shadow or tombstone. They may only extend (author additional entries at different paths). A constraint thus overrides ordinary precedence: it is the one case where a lower layer wins.

Tombstone (whiteout)

The path-shadow plane is union + shadow only: a higher layer can replace a lower entry by re-authoring the same path, but cannot remove one (e.g. a US guild dropping an inherited region/fr entry). A higher layer removes a lower-layer entry with a tombstone: a zero-byte marker file at the sibling path <entry-path>.whiteout (to drop entries/foo.md, author entries/foo.md.whiteout). A marker file is used rather than a frontmatter flag so the resolution stays a pure path operation — hosts need not parse entry bodies to list a directory. When resolving the mounted tree a host MUST:

  • resolve each path top-down (highest-precedence layer first); the first layer that declares either the entry or its .whiteout marker decides. A real entry → present with that layer's content; a .whiteout first → the path is absent from readdir/walk and reads return not-found, as if no layer declared it.
  • hide .whiteout markers themselves from readdir/walk output.

Because resolution is top-down, a higher layer re-authoring a real entry naturally overrides a lower tombstone, and a tombstone only suppresses layers below the one declaring it.

  • Constraint entries are non-tombstoneable and non-shadowable. A constraint-mode layer's protected entries are pinned ABOVE all higher layers, so by precedence neither a higher real entry nor a .whiteout can shadow or remove them. A host that detects a higher layer attempting to shadow a protected path emits knowledge_constraint_conflict; a .whiteout targeting one emits knowledge_tombstone_blocked. In both cases the constraint content wins.

Cross-AIP refs

KNOWLEDGE.md is the binding surface where agentknowledge/v1 meets the rest of the AIP family:

FieldReferencesPurpose
curatorAIP-9 operatorNames the operator the host should activate when running ingest, curation, or lint passes against this workspace.
governanceAIP-7 policy / audit refBinds the workspace (or view) to a governance policy. Schema-poisoning mitigations and source-mutation audits flow through this ref.
appliesToAIP-3 skill, AIP-6 company, AIP-9 operator, or a dimension ref (<dimension>/<value>)A view declares which consumers OR dimensions it adapts the workspace for. Hosts MUST refuse a view whose appliesTo references a non-existent consumer or a malformed dimension ref (knowledge_appliesto_unresolvable). A view bound to a dimension the host does not resolve is inert, not refused.
extendsanother KNOWLEDGE.mdComposition.
refs (Layer-2 page field)AIP-27 Ref[]local / github / git / url / ws://…AIP-10 is a consumer of AIP-27: a page's refs: field points OUT at code files/symbols in an AIP-26 workspace and at pages in other wikis (ws://wikis/<wiki-slug>/<page-slug>). AIP-10 is also a producer in the AIP-27 registry — the wikis collection row addresses AIP-10 wikis. See Cross-workspace references (AIP-27).

appliesTo is not inherited. A view binds to its own consumers; a parent's bindings do not leak into the child. This is the rule that makes the registry-of-views pattern coherent — every view declares its own scope.

Workspace mode vs view mode — composability table

AspectWorkspace-root modeView mode
File path<wiki>/KNOWLEDGE.md<consumer>/KNOWLEDGE.md
extends:absentrequired (otherwise it's a workspace, not a view)
appliesTo:absent (a workspace has no single consumer)OPTIONAL but conventional
Effective shapethe manifest as writtenmerge of the chain, child wins
Mutabilityedits gated by governancelocal edits adapt the lens, do not affect the workspace
Use caseswiki authors, schema designersoperator/company/skill teams who want their own lens
Validationfull schema checkschema check + chain validation
Lifecycleversioned with the wikiversioned with the consumer

The same knowledge.workspace/v1 doctype, the same file name, the same schema. Only the location and the presence of extends: distinguish.

Required generated files

_index.md — content catalog. Lists every page (excluding sources/) grouped by kind, with the slug, title, and a one-line summary extracted from the page body. The runtime MUST regenerate _index.md on every ingest.

_log.md — append-only activity log. Every ingest that processes ≥1 source, query that produced a new page, and lint pass MUST append a line (an ingest that skips every source — see the Ingest contract's idempotency step — processes nothing, appends nothing, and stays a true no-op):

## [<ISO 8601>] <event-type> | <subject>

- <bullet 1>
- <bullet 2>

event-typemanual.

_manifest.json — provenance/dedup manifest. A JSON object mapping every already-processed source to the pages it produced and the hash it was processed at:

{
  "version": 1,
  "hashAlgo": "sha256",
  "sources": {
    "sources/2026-04-15-paper.pdf": { "contentHash": "ab12…", "slugs": ["compounding-knowledge", "andrej-karpathy"] },
    "sources/2026-04-20-meeting.md": { "contentHash": "cd34…", "slugs": ["2026-04-20-meeting"] }
  }
}

Each entry maps sourceId → { contentHash, slugs }, where sourceId is the sources/-relative path of the raw source, contentHash is the digest of that source's bytes computed with the workspace's sources.hashAlgo (Layer 4 KNOWLEDGE.md; default sha256), and slugs is the array of every Layer-2 page the source produced or touched — one source can create or update many pages (Ingest steps 3–5). The runtime MUST record hashAlgo in the manifest so a reader can verify a contentHash without re-reading KNOWLEDGE.md. The idempotency check keys on contentHash (source BYTES) ALONE: editing KNOWLEDGE.md or AGENTS.md changes no contentHash and so does NOT re-trigger unchanged sources — re-curation after a schema change is an explicit operation, never an automatic side effect. The runtime MUST update _manifest.json in the same transaction as _index.md and _log.md on every ingest that processes a source.

Ingest contract

When a runtime ingests source S:

  1. The runtime MUST compute S's contentHash with the workspace's sources.hashAlgo and look S's sourceId up in _manifest.json. If a manifest entry exists whose contentHash is unchanged, the runtime MUST skip S — it MUST NOT re-distill the source and MUST NOT create or mutate any page for it. This is the idempotency guarantee: re-running ingest over an unchanged sources/ tree is a no-op, and the same source never produces a duplicate page. A source whose sourceId is absent, or present with a different contentHash (the bytes changed), is (re)processed by the remaining steps.
  2. The runtime MUST read S and the current AGENTS.md.
  3. It MUST identify wiki pages affected by S (entities mentioned, concepts touched, conflicting claims) by reading _index.md plus the relevant page bodies.
  4. It MUST produce page diffs — minimal markdown patches per affected page — and apply them atomically (all or nothing). Monolithic rewrites of unaffected pages are non-conforming.
  5. It MUST create new pages for entities/concepts not yet covered.
  6. It MUST update _index.md, upsert S's entry in _manifest.json (sourceId → { contentHash, slugs }, slugs listing every page created or touched in steps 3–5), and append to _log.md — all in the same transaction.
  7. It SHOULD set confidence and supersedes based on the schema's contradiction policy. Unresolved conflicts MUST be flagged via contradicts.

Query contract

Querying a wiki MUST be possible with file reads alone — no runtime DB or vector index is required to be conforming. A runtime MAY add auxiliary indices (BM25, embeddings, graph) on top, but the wiki files remain the source of truth.

Lint contract

A maintenance pass MUST detect:

  • Orphans — pages with no inbound links from _index.md or other pages.
  • Stale claims — pages whose sources are all older than a schema-defined threshold and have not been re-confirmed.
  • Unresolved contradictions — pages with contradicts populated.
  • Broken refs — wikilinks/markdown links pointing to missing pages.

The Broken refs lint (the broken-ref lint kind) applies to intra-wiki [[slug]] and relative-markdown links ONLY. It MUST NOT flag refs: frontmatter entries: a refs: target is cross-workspace by design and is validated by AIP-27 resolution (or left unresolved), NEVER by wiki-local page existence. A refs: entry whose target does not exist inside this wiki is correct, not broken.

Lint output is appended to _log.md as an event of type lint.

Vendor extensions

Implementations MAY add fields under metadata.<vendor> (e.g. metadata.guilde, metadata.simone). Vendor fields MUST NOT change the meaning of any field defined in this AIP, and a runtime MUST ignore vendor extensions it does not understand.

Rationale

Why filesystem-first. Following AIP-6/7/8: the wiki is the folder. Adapters project it into databases or vector stores; the canonical representation stays portable.

Why mandatory _index.md and _log.md. The ingest contract requires the LLM to update both atomically. Making them part of the spec — rather than implementation detail — lets a third party verify after the fact that the wiki was maintained according to its schema, and lets a runtime detect a poorly-applied ingest by inspecting log + index alone.

Why a provenance/dedup manifest (_manifest.json). _log.md records what happened for humans; _index.md catalogs what exists for readers. Neither answers the question ingest actually needs before it does any work: "have I already processed these exact bytes, and if so which pages did they become?" Without a machine-readable sourceId → { contentHash, slugs } map, a re-run either re-distills every source (wasteful, non-deterministic LLM output) or risks emitting a second page for a source already covered. Making the manifest a REQUIRED generated file turns idempotency into a checkable property: a third party can verify that ingest skipped unchanged sources by diffing _manifest.json against the sources/ tree, and the runtime gets an O(1) skip check keyed on the existing sources.hashAlgo rather than re-reasoning over prose. It is generated integrity metadata, not a new authority — the wiki files remain the source of truth.

Why refs: (typed cross-workspace references), and why a new field. A page has three reasons to name something, and collapsing them loses information. sources: is provenance IN — the raw bytes the page was distilled from; [[slug]] is intra-wiki navigation — an edge to another page of this wiki. Neither can express "this page is about that code file in another workspace" or "…that page in another wiki". That third relation is references OUT, and it wants a typed value, not a string — hence a new field holding an AIP-27 Ref[]. The name refs: was chosen over related: deliberately: it maps one-to-one onto AIP-27's own Ref term, so the field reads as exactly what it holds ("the typed refs this page is about"), whereas related: is a vaguer word that invites overloading with [[slug]]-style intra-wiki links and blurs the very split this field exists to draw. The crisp pairing is sources: (provenance IN) vs refs: (references OUT) vs [[slug]] (navigation WITHIN) — three fields, three jobs, no ambiguity. Reusing AIP-27 rather than inventing a local encoding also means the same parser, resolver, and ws:// spelling the rest of the family already uses apply unchanged.

Why the bare slug binds the runtime, not the other way around. The slug is the wiki's portable page identity, so it must stay a bare kebab token — the same value a [[slug]] link, an _index.md row, and a _manifest.json entry all reference. A retrieval or graph runtime often wants a path-namespaced node id (notes/foo vs pr-reviews/foo) to keep same-named pages in different directories distinct; that is legitimate, but it is the runtime's internal derivation. Making the frontmatter carry the prefixed form would break the no-slash kebab rule and couple the portable artifact to one runtime's indexing scheme — the exact non-portability this AIP exists to avoid. Hence the direction of the obligation: the wiki keeps bare slugs, and a conforming runtime MUST accept them and derive its own ids. A runtime that rejects a conformant slug (forcing the author to omit it or spell a path) is non-conforming — a real case observed against a graph backend that derived the node id from the file path and then refused a differing frontmatter slug, which would have silently eroded conformance had the wiki bent to it.

Why the cross-wiki ref syntax is normative but the graph is not. AIP-10 is filesystem-first: a wiki must be queryable with file reads alone. So the spec pins the one thing that must be portable — the ws://wikis/<wiki-slug>/<page-slug> SYNTAX for addressing a page across wikis, aligned exactly with AIP-27's wikis collection — and deliberately stops there. Building an index over the refs: edges and traversing code↔knowledge / wiki↔wiki as a graph is a runtime optimization, already permitted by the Query contract's "MAY add auxiliary indices (BM25, embeddings, graph)" clause. Fixing the syntax while leaving the index optional lets a graph runtime (e.g. gbrain) implement traversal without forcing every conforming host to ship a graph engine, and keeps two hosts interoperable at the file level even when only one indexes.

Why a workspace manifest (KNOWLEDGE.md). Prose describes intent; machines need contracts. Earlier drafts of this AIP made AGENTS.md the schema of record, which works for a single team but breaks the moment multiple consumers want to share a wiki. A YAML manifest is what lets a runtime know, without re-reading prose, that an entry of type Investor is required to have a lead_partner field, that lint rule require-source runs at severity error on Concepts, that this wiki retains sources forever. The manifest is also the surface that composition operates on — merging YAML is mechanical, merging prose is interpretive. Splitting the canonical config (KNOWLEDGE.md) from the human-readable companion (AGENTS.md) lets each artifact do what it's good at, and avoids forcing tooling to parse natural language.

Why one doctype for both workspace root and view. The alternative is two doctypes — knowledge.workspace/v1 for the root and knowledge.workspace.view/v1 for the per-consumer adaptation. Two doctypes means two schemas to maintain, two validators to ship, and an asymmetric merge surface. One doctype with extends: collapses the two into a single mental model: a workspace IS its own view of itself, and every view IS a workspace bound to a different consumer. The same schema validates both, the same merge algorithm applies recursively, and the same authoring skill (./resources/aip-10/draft/skills/author-knowledge/SKILL.md) walks an agent through both flows.

Why composition over inheritance hierarchies. A wiki could ship a single workspace and then run a query-time prompt that reshapes results per consumer. That couples consumer behaviour to runtime prompts — which means swapping runtimes loses the lens. Composition via on-disk extends: chains keeps the lens portable: the same operator, re-instantiated in a different runtime, still gets the same merged config because the merge runs against files, not prompts. This is the registry-of-views pattern: the wiki is the registry, each KNOWLEDGE.md is a registered view, and consumers pick a view by location.

Why AGENTS.md is RECOMMENDED, not REQUIRED. Conforming wikis SHOULD ship both KNOWLEDGE.md and AGENTS.md. Automated pipelines — and there will be many in the lifetime of this AIP — only need KNOWLEDGE.md to operate. Forcing them to also write prose creates drift between the two files; downgrading AGENTS.md to a recommendation acknowledges that prose is for humans and machines should be free to operate on machine config alone. Linters SHOULD flag drift between the two when both are present.

Why contradicts and supersedes are first-class. Knowledge is not monotonic. A spec that pretends contradictions don't exist forces the LLM to silently overwrite — losing provenance and audit ability. Making both relations explicit lets humans and other agents reason about why a page reads the way it does.

Why no vector store in the spec. Retrieval is a runtime concern. Mandating a specific index would couple the spec to today's tooling; forbidding indices would punish runtimes that already have them. The spec defines what's on disk; runtimes choose how to reach it.

Why depth-cap and cycle-detection are warnings, not errors. A malformed extends: chain is a configuration bug — but a consumer whose view fails to load loses ALL of its lens, including the parts that don't depend on the broken parent. The runtime degrades gracefully to the local manifest and surfaces the issue, instead of refusing to activate the consumer. This matches the broader AIP family's preference for partial-availability over hard-fail.

Reference Implementation

packages/agent-framework/src/wiki — parser, ingest pipeline, lint pass, and BM25 retrieval. Used by Guilde (per-guild knowledge base, Librarian operator) and Simone (per-user personal codex, written by the Council standing pass).

The implementation defines the working schema during the Draft phase; this AIP will absorb the normative text in full as part of moving Draft → Review.

Backwards Compatibility

Not applicable — this AIP introduces a new spec.

Security Considerations

The wiki is write surface for an LLM. Threats:

  • Prompt injection via sources — a malicious source instructs the LLM to make harmful edits across the wiki. Mitigation: ingest runs in a sandboxed prompt context; the LLM MUST NOT execute instructions embedded in source bodies, only summarize them.
  • Schema poisoning — an attacker rewrites KNOWLEDGE.md (or AGENTS.md) to relax contradiction policy, expand the LLM's authority, or silently raise lint severities to info. Mitigation: both files SHOULD be subject to the same governance gate (AIP-7) as any contract — changes go through approval. The governance: field in KNOWLEDGE.md makes this binding explicit; views that override the parent's governance MUST be reviewable through the same gate (a child cannot escape a parent's policy by pointing governance: elsewhere unless the parent permits it).
  • View shadowing — a malicious view extends: a benign workspace but overrides lints or curation.conflictResolution to silently weaken the curator agent. Mitigation: hosts MUST expose the resolution chain alongside the merged config so reviewers can audit what came from where; governance policies SHOULD restrict which lints a view is allowed to soften. A legal/compliance baseline SHOULD ship as a constraint-mode view so it cannot be shadowed or tombstoned by a higher layer or a guild edit — the floor rule turns an otherwise-silent override into a knowledge_constraint_conflict / knowledge_tombstone_blocked warning.
  • Confidence laundering — an LLM marks low-quality syntheses as confidence: 1.0. Mitigation: confidence values written by the LLM during ingest are advisory; downstream consumers MAY weight them against source recency and observation count.
  • Cross-tenant leakage — when multiple tenants share a runtime, a wiki ingest pulls a source from the wrong tenant. Mitigation: runtime MUST scope sources/ reads to the wiki's tenant; the spec is filesystem-first and inherits whatever isolation the host provides.
  • Manifest integrity vs authority_manifest.json is integrity metadata, NOT a trust root. Its contentHash lets a runtime detect change (and thus skip unchanged sources); it does not by itself prove a source is authentic — an attacker who can rewrite a source under sources/ can also rewrite its manifest entry. Provenance authenticity belongs to the governance: signing gate (AIP-7), not to this file. The manifest carries its own hashAlgo (mirroring sources.hashAlgo) to keep the hash algorithm agile: as sha256 weakens, a workspace re-baselines to sha512/blake3 and the recorded hashAlgo tells a reader which digest a stored contentHash was computed with, so verification never silently compares across algorithms.
  • Cross-workspace ref resolution — a refs: entry (url:, github:, ws://…) is an AIP-27 Ref: an identity, not trusted bytes. A runtime that resolves one MUST apply AIP-27's own safeguards (path-escape rejection on local, http(s)-only on url, tenant-local resolution of ws://) and MUST treat fetched bytes as untrusted until validated. refs: never bypasses source immutability (Layer 1): it points at other workspaces, it does not import them into sources/.

Resources

Supporting artifacts for AIP-10. Links open the file on GitHub — markdown and JSON render natively in GitHub's viewer. Browse the full resource tree →