The Leji Specification

The complete normative specification on one page, in reading order, for reading straight through or searching. Each section links to its own page, where every heading carries a citation anchor.

Overview & vocabulary ↗

The Leji Specification

Leji is an open specification for the shared context layer of AI-native teams. It defines how a team stores, governs, loads, and maintains the repo-owned context that people and AI agents both read on every task.

Spec version1.0.0
StatusReleased. Breaking changes require a new major version.
EditorVuong Nguyen
One pageThe full specification on a single page

Principles (non-normative)#

  1. Intent over instructions. Leji captures durable intent (what things mean, what must hold, why it is so) instead of imperative, per-vendor instructions. People and agents derive actions from declared intent plus task context.
  2. A circle, not a tier. Human-to-human, human-to-AI, and human-to-AI-to-human are first-class flows around one shared context layer. Equal access, not equal authority: everyone with access to a context layer reads all of it, anyone proposes, people approve. Participation is role-based, not tool-based: a participant who never touches git directly is first-class in the circle. Access itself is the version control system’s to grant, not Leji’s; the circle is scoped to a context layer’s audience.

The rest of this specification is the normative consequence of those two principles.

Conformance language#

The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this specification are to be interpreted as described in RFC 2119.

Citing this specification (non-normative)#

Cite a section by its title and the spec version, with a permalink to the section anchor. On the spec site every heading reveals its anchor on hover.

  • Format: Leji 1.0, §Section: https://leji.org/spec/<document>/#<anchor>
  • Example: Leji 1.0, §The circle, normatively: https://leji.org/spec/governance/#the-circle-normatively

Always cite the version (Leji 1.0): breaking changes ship as a new major version, so a version-pinned citation stays accurate after the spec evolves.

Vocabulary#

These terms are used consistently across all normative documents:

TermMeaning
context layerThe artifact this specification governs: a repo-owned, versioned set of human-readable documents and machine-readable artifacts encoding a team’s durable operating context. “Leji context layer” is the full disambiguating form. Always write “context layer”; bare “layer” is reserved for naming a countable sibling, host, or mounted context layer under federation.
agentAn AI system that acts: it loads repository context, performs or assists work, and may propose changes. The normative actor noun.
person / peopleHuman participants. People hold approval authority.
participantA person or an agent.
audienceThe people and agents admitted to read a context layer by its repository permissions and any filesystem or shared-drive permissions that expose the checkout. “Everyone reads” is scoped to a context layer’s audience; different audiences are served by separate context layers, never by gating content within one.
agent hostThe product or runtime an agent operates through (for example Claude Code, Codex, Cursor). Vendor adapters configure agent hosts.
toolA callable capability an agent uses (shell, search, an MCP server). Never a product name.
vendor adapterAn agent-host-specific entrypoint file (CLAUDE.md, AGENTS.md, .cursor/rules) that redirects to the boot profile.
boot profileThe agent-agnostic entrypoint of the context layer, for people and agents alike.
agent profileA role-specific loading-and-posture document for agents.
AIUsed adjectivally (AI-native) and in the flow names human-to-human, human-to-AI, human-to-AI-to-human. In flow names, “AI” refers to agents operating through an agent host.
modelThe predictive engine an agent runs on. Models don’t read the context layer; agents do. Appears only where the engine must be distinguished from the actor (for example, model selection as a host-specific mechanic).

The hierarchy, in one line: a model powers an agent; an agent operates through an agent host and calls tools; the context layer addresses agents and hosts, never models directly. The specification is agnostic at every level of that stack: any model, powering any agent, operating through any host, reading the same context layer. “LLM” is deliberately not part of this vocabulary: it names one class of model, and the specification is model-agnostic by the same principle.

Scope boundary. Leji 1.0 governs agents and the agent hosts that load repository context. Non-agentic AI (autocomplete, inline suggestions, chat without repository context) is out of normative scope, except where it operates as part of an agent host that loads the context layer.

Normative documents#

In reading order:

DocumentDefines
context-layer.mdThe context layer, the manifest, the root, the vendor-adapter rule
content-categories.mdThe five logical content categories and path mapping
boot-profile.mdThe agent-agnostic entrypoint every agent host loads
machine-readable-surface.mdManifest, index, changelog, profiles, decision records
decisions.mdDecision records
governance.mdPropose/approve, ownership, inclusion and removal, freshness
distribution.mdMonorepo, multi-repo submodule, federation
conformance.mdThe four conformance levels and the checklist
versioning.mdSpec and schema versioning

The JSON Schemas in ../schemas/ are normative for the machine-readable artifacts. The documents in ../rationale/ and ../adoption/ are non-normative.

Scope of 1.0#

In scope: providing context, setting constraints, recording decisions, reviewing changes, and capturing reusable patterns; agent-agnostic wiring and vendor adapters (lightly); ownership and continuity semantics (lightly).

Extension boundary. Leji 1.0 specifies the canonical shared context layer: how team context is written, owned, versioned, proposed, approved, indexed, and read. It deliberately does not specify the execution protocols that operate around that context layer: task envelopes, a generalized evidence protocol, agent-to-agent handoff, tool-permission protocols, and orchestration. These are extension protocols, not prerequisites: a conforming 1.0 context layer MUST remain useful without them, and an implementation MUST NOT require them to read, propose, review, approve, or validate the context layer. They complete the language as live practice proves them; they aren’t invented in the abstract.

Leji is not a programming language, a DSL, a runtime, or a SaaS. It is markdown conventions, small JSON schemas, and governance semantics.

The context layer ↗

The Context Layer

A Leji context layer is a versioned, governed set of human-readable documents that encodes how a team thinks about its work: domain language, system invariants, conventions, guardrails, and decision records. People and agents both read it in the course of real work, and both propose changes to it through the same review gate. It lives under version control so that history, currency, and approval stay verifiable; the mechanics are in Requirements below, and who takes part and how is in Participation.

Participation#

Participation in a context layer is role-based, not tool-based. Reading, proposing, reviewing, and approving happen through whatever interface preserves the repository’s review and approval semantics; direct git or command-line knowledge is not required to take part.

  • Everyone with access reads. Access means practical access through the team’s normal tools, not shell access to the repository.
  • Anyone proposes; people approve. A proposal is an intentional request to change the context layer. It MAY be authored directly by a person, generated by an agent from a person’s request, or generated by an agent from observed work. In practice agents draft most context changes; the irreducibly human contribution is governance: proposing intent and approving what becomes canonical. A person approving a change is accountable for its meaning and consequence, not for personally operating the version control system.
  • Human meaning, machine-readable surface. The human-readable documents are the normative source of a team’s operating context. The machine-readable files (manifest, index, changelog) exist so tools can locate, index, validate, and synchronize that meaning; they never replace it.

The normative form of these flows, the circle (everyone reads, anyone proposes, people approve), is defined in governance.md.

Requirements#

  1. The context layer MUST live in a git repository and MUST be versioned with the work it describes (same repo, or a dedicated context repository consumed per distribution.md). The git repository is what makes the context layer’s history, checkout currency, and append-only changelog integrity verifiable; conforming tooling derives all three from it. Reading the context layer without that repository is a supported but degraded mode, defined in Reading modes.
  2. A repository adopting Leji MUST carry a manifest file, leji.json, at the repository root, valid against context-manifest.schema.json. The manifest is the machine entrypoint: it declares the spec version (the self-naming leji key), the context root, the boot profile path, the category mappings, the conformance claim, and ownership. It MAY also carry an agents map binding role identifiers (e.g. thought-partner, reviewer) to agent profile documents: protocols engage roles; the map decides who fills them.
  3. The manifest MUST declare a context root (rootPath). The RECOMMENDED default is docs/. All context layer paths are POSIX-style, relative to the repository root. rootPath declares where the context layer lives; it does not re-base other paths: every path in every Leji artifact resolves from the repository root, including those that repeat the rootPath prefix. Category and machine paths SHOULD fall under rootPath; validators warn when they don’t.
  4. The context layer MUST have a boot profile per boot-profile.md. The RECOMMENDED default location is docs/boot-profile.md; the manifest’s bootProfilePath declares the actual location.
  5. Context layer content MUST be human-readable first. Markdown is the RECOMMENDED format for prose; structured metadata uses YAML frontmatter or the JSON artifacts defined in machine-readable-surface.md. A document that only a machine can read doesn’t belong in the context layer.
  6. The context layer MUST have a named owner (owners.primary in the manifest): a person accountable for its currency. Ownerless context layers rot.

Reading modes: canonical and degraded#

A context layer is read in two modes; a reader MUST know which mode it is in, because the guarantees differ:

  1. Canonical. The reader resolves the context layer through its git repository: a checkout, or the repository view of the host platform. History, checkout currency, and changelog integrity are verifiable, and approved content is known current to the revision read.
  2. Degraded. The reader reaches the context layer as plain file content with no accessible git working tree or version metadata: files uploaded, synced, or copied into another interface without the repository. Plain-file reading is first-class for reading (the documents are human-readable by requirement, and the machine-readable changelog still conveys declared recency), but a degraded reader MUST treat checkout currency and approval state as unknown, never as current (see governance.md, Freshness). The changelog is the portable declared-recency surface in this mode; it does not by itself establish that the copy matches the canonical repository.

Degraded reading widens who and what can consume a context layer; it is never a path to canonical authority. A change becomes canonical only through the git-backed review gate, and a degraded copy cannot satisfy the canonical-mode checks federation depends on (pin currency, stale-pin status, ownership intactness, and restricted-mount access per distribution.md).

The vendor-adapter rule#

Agent-host configuration files (for example CLAUDE.md, AGENTS.md, .cursor/rules, .github/copilot-instructions.md):

  1. MUST NOT hold canonical context layer content.
  2. If present, MUST redirect to the boot profile (typically a one-line pointer).
  3. MAY carry host-specific mechanics that have no meaning outside that agent host (model selection, runner settings), provided no team knowledge lives there.

The entrypoint conventions that exist tell an agent host where to look; Leji defines what the agent finds there. One source of truth, every participant reading it.

What the context layer is not (non-normative)#

  • Not a wiki. Nothing forces a wiki current. The context layer stays alive because agents read it on every task (wrong context produces wrong output that is felt immediately), changes ride review like code, and tooling makes staleness visible.
  • Not documentation in the traditional sense. Documentation describes what the system does, after the fact. The context layer describes how the team thinks, in the present tense, and is read constantly by people and agents alike.
  • Not a template to import. Borrowed context goes stale immediately. The value of a context layer is that it is the team’s own representation; Leji standardizes the shape and the governance, not the contents.

Content categories ↗

Content Categories

Leji defines five logical content categories. They classify what a document is for, not where it lives: category names are stable identifiers used by the manifest, the index, and tooling. Directory names are the team’s own.

The five categories#

CategoryWhat belongs in it
domainBusiness language and product semantics, in the team’s own words: what the core nouns mean, how they relate, the terms with local meaning.
systemArchitecture and its invariants: service boundaries, data ownership, integration contracts, consistency models, failure contracts, the constraints every change lives with.
practiceConventions and patterns applied automatically: code conventions, testing patterns, and the prompt and workflow patterns that have proven out (see capture gate below).
governanceAgent guardrails and operating rules: what agents may do unprompted, what needs a human gate, data-handling rules, escalation triggers, compliance controls.
decisionsDated records of why things are the way they are, per decisions.md.

Requirements#

  1. The manifest MUST map each category it claims to one or more repository-root-relative paths (categories.<id>.paths); those paths SHOULD fall under the declared context root, per context-layer.md. Mapping is how a lived context layer with its own directory names (for example business/, technology/, architecture/, conventions/) conforms without renaming anything.
  2. The RECOMMENDED default directory names for a new context layer are domain/, system/, practice/, governance/, and decisions/ under the context root.
  3. A context layer MUST map at least domain or system, plus decisions, to claim any conformance level (see conformance.md). The other categories accrete as the team hits real questions; an empty category MUST NOT be mapped to satisfy a checklist.
  4. A document SHOULD belong to exactly one category. Index entries (see machine-readable-surface.md) carry the category identifier.
  5. Practice content describing prompt or workflow patterns SHOULD be captured only after the pattern has worked at least twice (the proven-twice gate). Premature capture is how practice directories fill with aspiration.

Notes (non-normative)#

Not every category is present on day one. The minimum viable context layer is whatever the first month of work actually relies on. Categories exist so that a human or an agent can ask “what kind of truth is this?” and load the slice that matters for the task at hand, instead of the whole tree.

The boot profile ↗

The Boot Profile

The boot profile is the agent-agnostic entrypoint of the context layer: one human-readable document that every agent host, and every person, can start from. It answers “what is this context layer, what do I load, and how do I behave here.”

Requirements#

  1. The context layer MUST have exactly one boot profile, located at the path declared by bootProfilePath in the manifest. The RECOMMENDED default is docs/boot-profile.md.
  2. The boot profile MUST be plain markdown, readable by a person with no tooling. It MUST NOT depend on any vendor’s configuration syntax.
  3. The boot profile MUST cover:
    • Identity: what this repository or product is, in a paragraph.
    • Loading: what context to read for which kind of task, by category, by path, or via the context index.
    • Posture: the agent’s operating expectations (when to proceed, when to ask, what to never do). This MAY be carried by reference to governance content or a core agent profile.
  4. The boot profile SHOULD link to the manifest, the index (if present), and the agent profiles (if present), so that an agent entering through any host can discover the whole machine-readable surface.
  5. The boot profile MUST speak task language: it names literal paths and concrete load order, and following it requires no knowledge of this specification. The manifest and schemas exist for tooling, not for agents; a boot profile that requires spec literacy to follow is a conformance smell.
  6. The boot profile SHOULD state the context layer’s maintenance duties: where its changes are recorded (the declared changelog) and how decisions are captured (the declared decision-records location). Validators warn when the boot profile references neither.
  7. Vendor entrypoint files redirect to the boot profile per the vendor-adapter rule in context-layer.md.
  8. The boot profile’s unconditional load set (what it says to read before any task) SHOULD be bounded to what every task needs. Context only some tasks need SHOULD be routed by task, category, or the index rather than preloaded; and decision records SHOULD be routed by their declared affectedPaths / affectedCategories rather than loaded as a whole directory, since they accrue without bound. Everything in the unconditional set is paid on every task.

Agent profiles#

A context layer MAY define role-specific profiles (for example a reviewer profile, a release profile, a QA profile) under a directory declared by machine.agentProfilesPath. Each profile:

  1. MUST be markdown with YAML frontmatter valid against agent-profile.schema.json.
  2. MUST declare what the role reads first (requiredRead) and when it must stop and ask (mustAskWhen).
  3. MAY inherit from a core profile (inherits), so shared posture is written once.

Profiles tune what a role loads and how it behaves; they don’t duplicate context layer content.

Notes (non-normative)#

The boot profile is deliberately boring: a map and a posture, not a knowledge base. If the boot profile grows past a few screens, content is living in the entrypoint that belongs in a category.

The failure mode this design guards against is indirection: every hop between an agent’s first context and the actual constraint costs attention. A context layer implemented well needs no vendor entrypoints at all (invocation can point straight at the boot profile), and the boot profile walks straight to content. Depth belongs in the context layer’s documents, never in the path to them.

Every document the boot profile says to read before any task is paid on every task, so the unconditional set is the context layer’s most expensive space. Keep it to what is genuinely universal, and route the rest through task-typed loads, the categories, the index, and the scope each decision record declares. The index exists so an agent can load the slice a task needs instead of the whole tree; decisions accrue without bound, so they are routed, never preloaded as a directory.

Machine-readable surface ↗

The Machine-Readable Surface

Five artifacts make the context layer legible to tooling. Everything else in the context layer is prose for humans that agents happen to read; these five are the contract tools build against.

ArtifactDefault locationSchema
Manifestleji.json (repository root, fixed)context-manifest.schema.json
Context index<root>/context-index.jsoncontext-index.schema.json
Context changelog<root>/context-changelog.jsoncontext-changelog.schema.json
Agent profiles<root>/agents/*.md (frontmatter)agent-profile.schema.json
Decision records<root>/decisions/*.md (frontmatter)decision-record.schema.json

All locations except the manifest are manifest-declared; the table shows defaults.

Requirements#

  1. Manifest. leji.json MUST exist at the repository root and validate against its schema. It is the only fixed filename in Leji: the file tooling reliably looks for.
  2. Index. A context layer claiming indexed conformance or above MUST carry a context index that is generated, never hand-maintained. Each entry carries a stable id, a path, a title, and a category identifier. A stale index (one that no longer matches the tree) MUST be treated as a validation failure.
  3. Changelog. A context layer claiming indexed conformance or above MUST carry a machine-readable changelog of context layer changes. Entries carry a stable id, a UTC date, a type, a one-line summary, and the affected paths. Canonical order is derived, not positional: tooling MUST order entries by (date, id) ascending, and array position carries no meaning. Because id is unique within the changelog (Identifiers), (date, id) is a total order even when two changes share a date. Surviving entries are immutable: tooling MUST treat modification of a published entry as a validation failure; reordering the array is not. The changelog is a recency surface, not an archive: a long-lived context layer SHOULD compact it rather than let it grow without bound, and MAY compact it at any time by removing entries from the oldest end of that order, provided the same change set appends an entry of type compaction whose compacted field records the count and the first and last removed ids. Removal of anything but the oldest entries, removal without a compaction entry, and compaction to an empty file are validation failures. Append-only discipline is set-keyed by id and checked against the prior committed state, so it needs git at authoring time; the file itself stays git-free for consumers, and git history holds the full record. A human-readable changelog MAY exist alongside; the JSON record is the one tooling reads.
  4. Frontmatter artifacts. Agent profiles and decision records are markdown documents whose YAML frontmatter validates against their schemas. The prose body stays free-form; the frontmatter is the machine contract. Pure-JSON profiles or decisions MUST NOT be required: people read these documents.
  5. Identifiers. All id values MUST be stable once published: renames and moves update path, never id. Identifiers are lowercase, hyphen-separated, unique within their artifact type.
  6. Timestamps. Changelog date values are ISO 8601 in UTC: either a calendar date YYYY-MM-DD (ordered as that day’s start, T00:00:00Z) or a full timestamp ending in Z (for example 2026-06-13T15:04:05Z). Zoneless times and non-UTC offsets are not permitted, so a lexical sort of date is a chronological sort. Other artifacts’ dates follow ISO 8601 and MAY be date-only. Paths are POSIX-style, relative to the repository root, no leading ./.
  7. Every JSON artifact except the manifest MUST declare the schema line it was written against (schemaVersion), per versioning.md; the manifest declares its target spec line with the self-naming leji key.
  8. Derived surfaces inherit access constraints. The index, the changelog, the generated docs viewer, and any compiled or exported view built from context layer content are derived surfaces, as is the output an agent produces from that content. A derived surface carries the access constraints of the most restricted content it draws from. Tooling MUST NOT write or copy a derived surface to a location with a broader audience than that content without an explicit, reviewed redaction step that produces a separate surface for that audience, and an agent MUST NOT quote or summarize restricted context into a broader-audience or less-restricted surface (a pull request, ticket, chat, commit message, or public context layer). The index of a restricted context layer can be as sensitive as its prose: titles, paths, and summaries all describe it.

Notes (non-normative)#

The index doubles as the navigation source for presentation tooling: leji docs projects it into a static viewer, and any docs tool can do the same. The surface is deliberately small. Five shapes are enough for tooling to validate a context layer, diff it, score its freshness, and route an agent to the right slice, and few enough that a team can adopt them in an afternoon. Anything beyond these five is post-1.0 territory, gated on lived practice.

Decisions ↗

Decisions

Decision records are the context layer’s dated account of why: architecture decisions, vendor selections, scope boundaries, intentional non-decisions. They stop re-litigation, and they give agents the reasoning rather than just the rule.

Requirements#

  1. Decision records MUST live under the path(s) the manifest maps to decisions (default <root>/decisions/), one record per file, markdown with YAML frontmatter valid against decision-record.schema.json.
  2. Frontmatter MUST carry: id (stable), title, status, and date. status is one of proposed, accepted, superseded, deprecated, rejected.
  3. The body MUST state, in prose: the context (what situation forced a decision), the decision itself, and its consequences. The RECOMMENDED section headings are ## Context, ## Decision, ## Consequences; a record MAY add ## Alternatives.
  4. Records are append-only history: a record MUST NOT be edited into a different decision. A reversal or change is a new record whose frontmatter sets supersedes, and the old record’s status becomes superseded with supersededBy set. Both records remain.
  5. A record MAY declare affectedPaths and affectedCategories, so tooling can route from a file to the decisions that govern it.
  6. Rejected proposals are records too (status: rejected). A decision not taken, written down, is the cheapest re-litigation insurance there is.

ADR compatibility (non-normative)#

Leji decision records are deliberately compatible with Architecture Decision Records: an existing ADR directory satisfies decisions by adding the frontmatter fields to each record (or to new records going forward) and mapping the directory in the manifest. No ADR tooling is required, and none is excluded.

Governance ↗

Governance

Governance is what separates a context layer from a wiki. The semantics are the circle: equal access, not equal authority.

The circle, normatively#

  1. Everyone reads. All participants, people and agents alike, with access to a context layer MUST be able to read the whole of it. A context layer with role-gated reading within it isn’t a shared context layer; where different people may read different material, that material belongs in separate context layers (see Access boundary below and distribution.md).
  2. Anyone proposes. Any participant, person or agent, MAY propose changes to the context layer. Agent-authored proposals are first-class: an agent that discovers missing or wrong context while working SHOULD propose the fix in the same change set as the work that surfaced it. A proposal SHOULD carry rationale sufficient for a reviewer to understand its intent and expected effect; that rationale is the minimum a person needs in order to approve. Leji 1.0 defines no generalized evidence protocol (see Scope of 1.0).
  3. People approve. Every change to the context layer MUST be approved by a person before it becomes canonical. Approval rides the repository’s existing review mechanism (pull requests); Leji introduces no separate process. Participation MAY happen through any interface, but canonical approval MUST be an auditable review record in that mechanism: attributable to the approving person and bound to the change set under review. An approval expressed only in external discussion, chat, ticket state, or document comments does not count until it becomes such a record; mirroring it into a comment does not. Widening how people take part never moves where authority is recorded.

Requirements#

  1. Ownership, not authorship. The manifest MUST name a primary owner (owners.primary) and MAY name a continuity owner (owners.continuity): a different person who carries the same accountability when the primary is unavailable or steps away. An assisted adoption SHOULD name the continuity owner before outside help leaves; a solo context layer MAY have none, which honestly signals it has no succession. Owners are accountable people: an agent proposes and reviews but never owns, and naming the primary again as continuity provides none. The owner is accountable for the context layer’s health: that it stays current, that stale or contradictory content gets pruned, and that every area has someone who tends it. Owners are not curators. The content is written and kept true by the whole circle as it works; concentrating that in one keeper is the bottleneck this model exists to avoid.
  2. Review scope. Context layer changes SHOULD be reviewed by the people closest to the affected content, the area owners, not funneled through a single gatekeeper. Area ownership is the repository’s existing ownership map (a CODEOWNERS file, a team convention), not a new manifest field; Leji reuses it the way it reuses pull requests for approval. The primary owner is accountable for ensuring every area has one. Review asks more than “is this true?”: why this belongs in the context layer, who will rely on it, what shows it holds, and when it should be revisited. A change that cannot answer those is a link or a note, not canonical context. The standing review question for any change set is did this change alter the context?; if yes, the context delta belongs in the same change set.
  3. Inclusion and removal. Proposing is open; inclusion is not. Content belongs in the context layer only if it changes how future work is done: it sets a constraint, encodes a decision, defines an interface or ownership boundary, or stops a repeated mistake. Everything else is linked, not absorbed. The context layer MUST have a removal path as deliberate as its approval path: stale, superseded, and duplicated content is pruned in ordinary reviewed change sets, and pruning is part of each area owner’s duty, not a separate cleanup project. A context layer that only ever grows is one that rots while passing review. Durable guidance SHOULD clear the proven-twice gate (per content-categories.md): a one-off fix can be merged, but a norm becomes canonical only after it has held across at least two real tasks. Capture what is true, not what is hoped for.
  4. Changelog discipline. At indexed conformance and above, every approved context layer change MUST append a machine-readable changelog entry per machine-readable-surface.md.
  5. Freshness. Context layer content SHOULD carry review horizons (freshness.reviewAfter in index entries and profiles). Tooling SHOULD report content whose horizon has passed, and MUST NOT silently treat stale content as current. At governed conformance, freshness checking MUST run in CI. Review freshness (above) is distinct from checkout currency: whether the copy a reader holds matches the canonical repository. A reader establishes checkout currency from the version control system (git); the working tree is current only to the revision checked out, and tooling MUST NOT silently treat an unverified copy as current. A reader that reaches the context layer as plain file content, with no accessible git working tree or version metadata (file content uploaded or synced into another interface, without the repository), MUST treat checkout currency as unknown rather than current.
  6. Canonical content lives in the context layer. Knowledge that governs how work is done MUST NOT exist only in a vendor configuration file, a chat thread, or an individual’s notes. If it governs work, it belongs in the context layer, under review.

Access boundary#

Leji defines no access-control mechanism of its own. Access to a context layer is governed by the version control system (git) and the platform the repository lives on: the repository host’s permissions, and the filesystem or shared drive that exposes the working tree. The context layer is the unit of access.

  1. A context layer MAY live in an access-controlled repository. Leji does not grant, check, or enforce that access; the version control system and its host do.
  2. A conforming context layer MUST NOT require role-gated reading within itself. “Everyone reads” is scoped to a context layer’s audience: everyone the version control system admits reads all of that context layer.
  3. Content that needs a narrower audience (an executive, finance, security, or incident-response context) MUST live in a separate context layer with its own repository, manifest, owner, and review gate, permissioned by the version control system. Restricted context is a separate context layer, never a restricted region of a shared one.
  4. Composing a restricted layer into another team’s context is the federation case, with the additional rules for restricted mounts in distribution.md.

The maintenance model (non-normative)#

The context layer is maintained one delta at a time, riding work that is happening anyway: a task surfaces missing or wrong context; the fix travels in the same reviewed change set; the changelog records it. There’s no separate documentation sprint, and there never needs to be one. Wrong context produces wrong output that someone feels the same day; that, plus review, plus CI on the mechanics, is the entire forcing system.

That fast feedback catches wrong content quickly. Slow accumulation, content that is merely mediocre or redundant, is caught by the inclusion bar and the removal path above, applied by the people who own each area. This is curation, and Leji distributes it on purpose. A single curator looks like the safe way to hold quality and is the opposite: they become the slowest path in the system, changes queue behind them or route around them, and they hold less context than the area experts do. The context layer either stalls or forks. Every area owner pruning and gating their own slice is what keeps the whole context layer small and true without a chokepoint. The owner tends the health system; the circle tends the content.

Distribution ↗

Distribution

Where the context layer lives relative to the work it describes. Three patterns; one rule throughout: the context layer is docs-only and MUST NOT introduce a build or runtime dependency into any consuming repository.

Pattern 1: Monorepo (default)#

The context layer lives in the same repository as the code and infrastructure it describes, at the context root. This is the RECOMMENDED pattern wherever the team’s work lives in one repository: code, infra, and context version together, and drift is structurally hard.

Pattern 2: the docs-only submodule for multi-repo setups#

When work spans many repositories, the context layer lives in a dedicated context repository, and consuming repositories mount it as a git submodule.

  1. The context repository is a normal git repository with its own leji.json, branch policies, and review gate.
  2. Consuming repositories MUST mount it at a fixed path (RECOMMENDED: context/) and MUST NOT couple any build or runtime step to its presence: a missing or stale mount degrades knowledge, never the build.
  3. Each consuming repository pins a specific version of the context layer. Pin updates MUST arrive as reviewable change sets (scripted or bot-raised pull requests), so context changes are visible, reviewable, and attributable per repository.
  4. Tooling SHOULD report stale pins (how far each consuming repository is behind the context layer). Stale-pin reporting MUST precede any blocking enforcement: visibility first, gates later.

Pattern 3: federation of sibling context layers#

Patterns 1 and 2 each have a single context layer: a monorepo owns one, and a multi-repo organization consumes one. Federation is the pattern for an organization where more than one team already owns a context layer of its own, and the goal is to make those context layers legible to each other without anyone surrendering control.

The instinct is to merge them: one context repository, every team’s knowledge pulled in. Resist it. A context layer stays current because the people who own it read it on every task and fix what’s wrong in the same change set. Pull product’s context into platform’s repository and you have separated product’s content from product’s accountability; it rots while everyone assumes someone else now owns it. Centralizing knowledge recreates the bottleneck that put it in heads and threads to begin with.

Federation composes the context layers instead of absorbing them. A team’s context layer joins another team’s graph as a sibling: mounted, referenced, and read, never copied.

  1. A sibling context layer mounts as its own docs-only submodule, declared in the host manifest’s federation.mounts with the sibling’s name and owner named, and SHOULD carry its source repository so stale pins can be reported. The docs-only rule from pattern 2 still holds: nothing in the host builds or runs against the mount.
  2. The sibling keeps everything that makes it alive: its own repository, owner, review gate, changelog, and conformance claim. The host MUST NOT copy sibling content into itself. Content separated from the team that owns it goes stale with nobody responsible, which is the exact failure federation exists to prevent.
  3. The host references the sibling at a pinned version; pin updates arrive as reviewable change sets and stale-pin reporting applies per pattern 2. A mount records which version of another team’s truth this repository was reading, not a fork of it.
  4. Mounting enables reading, not authority, and does not grant access. A host that mounts a sibling routes readers and agents into it when they already have access to it; mounting neither grants that access nor approves the sibling’s changes. Each context layer’s writes are still approved by its own owner, and who may read it is still the version control system’s to decide. Federation composes readable context for the participants the relevant repositories already admit; it leaves who-approves, and who-may-read, exactly where they were.
  5. Mounts are direct and flat. A host composes the siblings it names; tooling MUST NOT recurse into a sibling’s own mounts. Each mount’s path and name MUST be unique within the host manifest, and a mount MUST NOT reuse the host context layer’s own name. Because nothing traverses past a context layer’s declared siblings, diamonds and cycles are inert: A mounting B and C while B also mounts C is three direct relationships, not a graph to walk.

Mounted context layers are distinct, named sources, not merged into the host’s categories. The host’s own context layer is authoritative for the host’s repository; each sibling is authoritative for its own. There is no organization-wide namespace, and so no cross-sibling precedence to resolve: an agent loads the slice it needs from the context layer that owns it, named. Stale-pin reporting reads the pinned revision from the submodule itself; the manifest’s source is an optional convenience mirror of that upstream, not the pin of record.

A context layer reaches federated conformance only when these relationships are real and checkable: the context layer is consumed by at least one other repository as a pinned mount, stale-pin reporting is in place, and any sibling mounts are present with ownership intact (see conformance.md). The reference SDK validates the mechanical parts: that each declared mount exists, carries its own leji.json, matches the declared name, and is unique within the manifest.

A worked manifest for this shape is in examples/multi-repo/.

The circle composes ownership; it doesn’t centralize it. A monorepo is one team’s circle of people and agents reading one context layer; a multi-repo organization is a circle of those circles, each still owned by the people who keep it true.

Restricted mounts#

Federation crosses an access boundary when the layers composed have different audiences (see governance.md). Access stays the version control system’s to enforce: a reader either can resolve a mount’s repository or cannot. The spec’s job is to keep that boundary from leaking and from failing silently.

  1. A restricted layer MUST NOT be declared as a mount in a host whose audience is broader than the restricted layer’s own: every participant the host admits must already be admitted to the mounted layer. The mount declaration itself (its presence, name, owner, role, and source) MUST NOT disclose anything the host’s audience may not see. Where a broader audience needs a restricted decision, publish a redacted companion layer or a public decision summary, not a mount to the restricted layer.
  2. A mount is a reference, not an access grant. Declaring a mount never widens who may read the mounted layer beyond what the version control system already allows; whether a given reader can resolve it is decided there, not by the host manifest.
  3. Fail closed, never silently. A reader that cannot resolve a mounted layer a task requires MUST stop and report incomplete context. It MUST NOT proceed as though the inaccessible layer does not exist: an agent acting on partial context it cannot see is the failure this rule exists to prevent.

Notes (non-normative)#

The submodule pattern’s bad reputation comes from code submodules with build coupling. A docs-only leaf has none of those failure modes: nothing compiles against it, nothing breaks when it lags, and the pin is just a recorded “which version of the truth was this repository working from”, which is information, not risk.

Federation looks like more moving parts than a merge, and is less. A merge is cheap once and expensive forever: every cross-team edit thereafter routes through whoever owns the central repository, and the parts no single team reads daily are the parts that rot. Sibling mounts keep each context layer small, owned, and read, and pay only the price of a pin update, which is a reviewable diff, not a meeting.

Conformance ↗

Conformance

Partial adoption is by design. Four levels, each containing the previous; a team claims its level in the manifest (conformance.claimedLevel) and the claim is checkable by tooling. Self-attestation only: there is no certification program.

Level 1: core#

A context layer exists and both people and agents can work from it.

  • The context layer lives in a git repository, versioned with the work it describes (per context-layer.md, Requirements).
  • leji.json at the repository root, valid against the manifest schema.
  • A boot profile at the declared path, covering identity, loading, and posture.
  • At least domain or system mapped and populated, plus decisions with at least one real decision record.
  • A named primary owner.
  • Vendor entrypoint files, if present, redirect to the boot profile.

Level 2: indexed#

The context layer is legible to tooling.

  • All of core.
  • A generated context index, current with the tree.
  • A machine-readable changelog; context layer changes append entries.

Level 3: governed#

The forcing functions are mechanical, not goodwill.

  • All of indexed.
  • Context layer changes ride the repository’s review gate; people approve.
  • Agent profiles (at least a core profile) valid against the profile schema.
  • CI validates the surface: manifest, index matches the tree, changelog discipline, profile frontmatter, link integrity.
  • Freshness horizons are declared and checked (report-only is acceptable).

Level 4: federated#

The context layer spans a multi-repo organization.

  • All of governed.
  • The context layer is consumed by at least one other repository as a docs-only mount, pinned, with pin updates arriving as reviewable change sets.
  • Stale-pin reporting is in place.
  • Any sibling context layers are mounted with ownership intact per distribution.md.

Notes (non-normative)#

core is an afternoon, indexed is a tooling run, governed is where the context layer stops depending on anyone’s discipline, and federated is for organizations that need one truth across many repositories. Most teams should reach governed and stop; federated exists for those organizations, not as a maturity badge.

Versioning ↗

Versioning

Three things version independently: the specification, the schemas, and any implementing tooling.

The specification#

  1. The spec carries a SemVer version (currently 1.0.0). Breaking changes require a major version; every change is recorded in the repository changelog.
  2. A context layer declares the spec line it targets in leji.json via the self-naming leji key (e.g. "leji": "1.0"), following the OpenAPI convention. Tooling MUST validate a context layer against the declared line, not the newest one.

The schemas#

  1. Each schema carries a stable $id of the form https://leji.org/schemas/v<major>.<minor>/<name>.schema.json. The $id line moves only when the schema’s shape changes incompatibly.
  2. Within a published line, schema changes MUST be additive (new optional fields). Field removals or semantic changes require a new line.
  3. Machine-readable artifacts other than the manifest declare the schema line they were written against via schemaVersion; the manifest declares its target spec line via the self-naming leji key (item 2).

Stability set#

The following are frozen within a spec line; tooling (including future commercial implementations) builds against them with no parallel schema:

  • the manifest shape and its fixed filename leji.json,
  • the category identifiers (domain, system, practice, governance, decisions),
  • the conformance level identifiers (core, indexed, governed, federated),
  • identifier and path normalization rules per machine-readable-surface.md,
  • the index entry, changelog entry, agent profile, and decision record shapes.

Implementing tooling (non-normative)#

SDKs and CLIs version on their own SemVer and declare which spec lines they support. The reference SDKs in this repository are the leji npm package (packages/sdk), the leji PyPI package (packages/sdk-py), and the leji Go module (packages/sdk-go, a single static binary); they are behaviorally identical and tested against one shared fixture suite.