__
    __ _  ___ ____ ___ / /____ ____
   /  ' \/ _ `/ -_|_-</ __/ -_) __/
  /_/_/_/\_,_/\__/___/\__/\__/_/   

· living specs · v0.1.0 ·

Knowledge, kept where it’s made.
Gathered where it’s needed.

Maester is a Node CLI for aggregating documentation from many Git repositories into one central knowledge home — a citadel — so humans and AI agents can reason over your whole system from a single, current corpus.

Read the model

The problem

Docs scatter. Context dies.

Across services and packages, the documentation that matters lives in the repos that own it — where it’s easy for humans to miss and impossible for an AI agent to reliably find.

Scattered across N repos

Architecture lives one place, API contracts another, runbooks a third. Search is brittle, link-rot is rampant, ownership is unclear.

Centralized docs go stale

Copy-paste portals drift the day they’re built. Engineers update READMEs; the portal keeps showing last year’s reality.

AI agents start from zero

Every prompt rediscovers the codebase. Coding agents guess at conventions, miss decisions, and ship plausible nonsense.

api-gateway design-tokens billing-service platform-runbooks auth-service adr-archive vendor-spec ✗ ✗ ✗ ✗ ✗ ✗
seven repos, six broken paths, zero source of truth

The model

Two roles. One contract.

Source repositories declare what they publish. One central repository pulls them together. A maester can live where the source lives — or travel from the citadel to a repo that hasn’t adopted one yet.

maester

The source that publishes

A maester is a publish list — a small maester.yaml that says which files in a repository are worth aggregating. It can be defined two ways:

  • in the source repo — drop a maester.yaml at the repo root and the citadel consumes whatever it declares.
  • in the citadel — for repos you don’t control, declare a traveling maester in citadel.yaml with an includes list. The maester travels to the repo; the repo doesn’t change.
# maester.yaml — in the source repo
schemaVersion: 1
documents:
  - path: README.md
  - path: docs/adr/*.md
  - path: docs/runbooks/**/*.md

citadel

The repo that gathers

A citadel is the aggregator: a repository with a citadel.yaml that lists every source — resident or travelling — and a <baseDir>/ tree where their content materialises on sync.

# citadel.yaml
schemaVersion: 1
baseDir: context
sources:
  - name: design-system
    url:  github.com/org/design-system
  - name: astro-docs
    url:  github.com/withastro/docs
    includes:
      - src/content/docs/**/*.mdx

The flow

Source-owned. Centrally composed.

Each maester declares its publish surface in its own repo. The citadel decides which sources to pull and where to put them. Re-run maester sync any time to refresh.

maester design-system maester api-contracts maester ops-playbooks traveling astro-docs traveling vendor-api-spec citadel.yaml citadel/ ├─ design-system/ ├─ api-contracts/ ├─ ops-playbooks/ ├─ astro-docs/ └─ vendor-api-spec/ ✓ sync · idempotent ✓ provenance-tracked Engineers read · grep · onboard AI coding agents whole-system context CI · scripts freshness checks declares own surface citadel picks paths read context check

Supercharge AI workflows

Stop letting your agents guess.

AI coding tools are powerful — but only as good as the context you give them. A citadel is a single, current, structured corpus your agents can actually read.

01

One folder. Whole system.

Point Claude Code, Cursor, Codex, or Antigravity at citadel/ and the agent inherits architecture decisions, API contracts, and runbooks from every repo at once — not just the one it’s editing.

02

Provenance you can trust.

Every directory carries a .maester-source.json marker — source URL, ref, commit SHA, sync time. When an agent quotes a doc, you can trace it back to its origin.

03

Fresh by construction.

Run maester sync before any agent session — or wire it into CI. The corpus reflects the actual current state of every source, not last quarter’s snapshot.

04

Selective, by contract.

Either the source publishes its own maester.yaml, or your citadel sends a traveling maester to do the publishing in its stead. Agents see the deliberately curated surface — not the noise of a full clone.

without maester
you

Add rate limiting to the billing webhook handler.

agent

I’ll add a token-bucket middleware. Where do you want the limits configured?

agent doesn’t know your platform’s standard middleware, env-var conventions, or ADR-014 on retry policy. It guesses.

with maester
you

Add rate limiting to the billing webhook handler.

agent

Reading citadel/platform-runbooks/middleware.md and citadel/architecture-notes/adr-014-retry.md…

Using @platform/limiter at 100 req/min per tenant, matching ADR-014. Env var: BILLING_WEBHOOK_RPS. Adding the runbook entry too.

agent reads the citadel and applies the system’s actual conventions.

The Grand Maester — a cartoon character in a blue hooded robe with a gold chain and keyring, representing the installable agent skill

Optional · ships with the CLI

Meet the Grand Maester.

An installable agent skill that turns your citadel into a first-class context surface for whichever coding agent you run. It teaches the agent where the citadel lives, prefers canon files over draft, and runs maester status before substantial reads so it never answers from a stale corpus.

Supported agents

  • Claude Code
  • Codex CLI
  • Cursor
  • any AGENTS.md agent

The CLI surface

Five verbs. Nothing else to learn.

command role what it does
maester menu Interactive top-level menu. Detects your repo’s existing role and adapts.
maester init citadel Walk through registering resident and traveling maesters. Writes citadel.yaml.
maester publish maester Declare which documents this repo publishes. Writes maester.yaml.
maester sync citadel Fetch every configured source. Idempotent, atomic, parallelised. Honours --json.
maester sync <name> scoped Sync a single source by name. Useful for fast iteration on one connection.

Global flags

  • --verbose · raise log detail
  • --quiet · errors only
  • --json · one JSON object per line, for CI & agents
  • --no-color · pure monochrome
  • --theme=light · accent swaps for light terminal themes

Resident or traveling

A maester can live anywhere.

Same publish contract, same destination, same provenance. The difference is where the maester is defined — at the source, or at the citadel.

resident maester

Defined at the source

For repos you maintain. The source publishes its own maester.yaml and your citadel consumes whatever it declares — full stop.

Who declares the file list?
the source repo
Where does the maester live?
maester.yaml at the source repo root
If the source has no manifest?
the citadel falls back to the full tree
Reach for it when…
your team owns the source and you want it to control its publish surface
traveling maester

Defined at the citadel

For repos you don’t control — vendor specs, third-party docs, public projects. Declare an includes list on the source entry in your citadel.yaml; the remote needs nothing.

Who declares the file list?
the citadel
Where does the maester live?
includes on the source entry in citadel.yaml
If a glob matches zero files?
warning surfaces upstream drift
Reach for it when…
you need docs from a repo that doesn’t publish a manifest of its own

Quick start

Two commands. One citadel.

01

Init the citadel and any sources

Same command in the aggregator repo and in any repo that should publish to it — it detects the context and writes the right config.

$ npx baller-maester init
# in the citadel → writes citadel.yaml
# in a source   → writes maester.yaml
02

Sync — and keep syncing

From the citadel, any time you want a fresh snapshot.

$ maester sync
✓ 5 sources · 68 docs · 0 errors

· Node 24+ · works in Claude Code, Cursor, Codex, Antigravity, Open Code