{
  "markdown": "# cambium\n\n<!-- mcp-name: io.github.jarmstrong158/cambium -->\n\n_Part of the [xylem](https://github.com/jarmstrong158/xylem) stack._\n\nThe knowledge-lifecycle MCP that turns work your agents already did into\n**compound, org-wide knowledge**. cambium bridges two substrates that already\nexist — [agentsync](https://github.com/jarmstrong158/agentsync) (what happened:\nclaims, finishes, notes, changed files) and\n[context-keeper](https://github.com/jarmstrong158/context-keeper) (why: decisions,\nconstraints) — and adds the three things neither has:\n\n1. **`distill()`** — turn events into memory *automatically* (passive capture)\n2. **`recall()`** — one federated read endpoint for **every agent type**\n   (coding agent, Slack KB bot, SRE bot — same store, same call)\n3. **`promote()`** — graduate knowledge **local → team → org** as it earns trust\n\nNamed for the cambium layer of a tree: the thin living tissue where all growth\nhappens.\n\n## Why a third MCP (and not a database)\n\nKnowledge layers fail because they're a *side system* nobody calls. cambium's\nbet: capture and recall must be **native tools in the agent's loop**, and state\nmust live in the **substrate the work already lives in** — git — not a separate\nservice. Storage is an implementation detail behind `recall()`:\n\n| Scope | Lives in | Trust gate |\n|---|---|---|\n| `local` | `<repo>/.cambium/knowledge.json` | none — it's yours |\n| `team`  | `knowledge.json` on a dedicated `cambium` branch of the shared repo | recalls ≥ N **or** an endorsement |\n| `org`   | `knowledge.json` in a dedicated org knowledge repo | an **endorsement required**; optionally lands as a **pull request** — review is the gate, `git revert` is the undo |\n\nTeam writes use the agentsync pattern: a private worktree under `.git/` and\n`git push` as compare-and-swap, so concurrent agents never clobber each other.\n\n## Install\n\n```bash\npip install -r requirements.txt      # just `mcp`\n```\n\n`gh` (GitHub CLI) is only needed for pull-request-mode org promotion.\n\n## Configure\n\nPoint an MCP client at the server — no env required to start:\n\n```json\n{\n  \"mcpServers\": {\n    \"cambium\": {\n      \"command\": \"python3\",\n      \"args\": [\"/abs/path/to/cambium_server.py\"]\n    }\n  }\n}\n```\n\n**First contact is helpful, not cold.** MCP servers can't start a conversation,\nso cambium teaches you through its own responses. Call **`status()`** (or any\ntool) before it's configured and instead of a bare env error you get structured\nguidance — what's set, what's missing, what each gap costs in plain terms, and\nthe exact `setup()` call that fixes it:\n\n```jsonc\n{\n  \"configured\": false,\n  \"gaps\": [\n    {\"setting\": \"CAMBIUM_REPO\",\n     \"cost\": \"no project repo → cambium has no substrate; every tool is unavailable\",\n     \"fix\": \"setup(project_repo=\\\"/abs/path/to/your/clone\\\", agent_id=\\\"your-id\\\")\"},\n    {\"setting\": \"CAMBIUM_ORG_REPO\",\n     \"cost\": \"org scope off → promotions stop at team; org-wide recall unavailable\",\n     \"fix\": \"setup(project_repo=…, agent_id=…, org_repo=\\\"owner/knowledge or /abs/path/to/clone\\\")\"}\n  ],\n  \"next_step\": \"setup(project_repo=\\\"/abs/path/to/your/clone\\\", agent_id=\\\"your-id\\\")\"\n}\n```\n\n**`setup(project_repo, agent_id, org_repo?, org_pr?, team_branch?)`** finishes\nthe job: it validates the paths, scaffolds `.cambium/` (and adds it to the\nrepo's `.gitignore`), and writes a fallback config at `~/.cambium/config.json`\nthat the server reads when env vars are absent. It takes effect immediately — no\nrestart. **No secrets are written**: the file holds only paths, ids, and flags,\nand lives outside any repo. If `org_repo` is a GitHub `owner/name` you haven't\ncloned locally, setup **offers the exact `gh`/`git` commands** to stand it up\nand leaves org scope off — it never creates or pushes a repo for you.\n\n**Env still wins.** Any of the variables below, set in the MCP client config,\noverrides the config file per-key — the table is the full reference layer:\n\n| env var | required | default | meaning |\n|---|---|---|---|\n| `CAMBIUM_REPO` | yes | — | your project clone (local scope, agentsync + context-keeper substrates) |\n| `CAMBIUM_AGENT_ID` | yes | — | your unique agent id |\n| `CAMBIUM_REMOTE` | no | `origin` | git remote |\n| `CAMBIUM_GIT_TIMEOUT` | no | `25` | per-invocation git/gh timeout (seconds) so a stuck call fails fast instead of hanging the server |\n| `CAMBIUM_TEAM_BRANCH` | no | `cambium` | team-scope branch |\n| `CAMBIUM_AGENTSYNC_BRANCH` | no | `agentsync` | coordination branch name distill reads |\n| `AGENTSYNC_BOARD_REPO` | no\\* | — | **which repo holds the board** — the same setting agentsync reads, so the two servers cannot disagree (see below) |\n| `CAMBIUM_ORG_REPO` | no | — | path to the org knowledge repo clone (org scope off without it) |\n| `CAMBIUM_ORG_PR` | no | direct push | `1` = org promotion opens a pull request |\n| `CAMBIUM_PROMOTE_RECALLS` | no | `3` | recalls needed for local→team |\n| `CAMBIUM_RELEASE_CAPTURE` | no | off | `1` = also capture agentsync claims at their done/released transition (see below) |\n| `CAMBIUM_CONFIG_FILE` | no | `~/.cambium/config.json` | override the fallback config path (mainly for tests) |\n\n### Where the agentsync board lives (board addressing)\n\n\\* `distill()` reads finished agentsync claims off a **coordination board**. That\nboard is a shared, long-lived team artifact — not a property of whichever\nproject this session happens to be in — so cambium resolves its address\nindependently of the session, using **exactly the order agentsync itself uses**:\n\n1. **`AGENTSYNC_BOARD_REPO`** — the explicit board address (env, or the same key\n   in `~/.cambium/config.json`). One setting configures both servers.\n2. **`AGENTSYNC_REPO`** — agentsync's legacy explicit pin.\n3. **`CAMBIUM_REPO`** — but *only if that repo actually holds the coordination\n   branch* (real ref lookup: local head → remote-tracking ref → `ls-remote`).\n4. Otherwise: **no board**, reported loudly (next section) — never silently.\n\n**Why.** Before this, cambium looked for the coordination branch in\n`CAMBIUM_REPO` while agentsync (unpinned) followed\n`~/.xylem/active_project.json`. The two could point at different repos, and\nwhenever the current project had never been provisioned neither found anything.\n`distill()` reported that as the bland string `\"no coordination branch found\"`,\ncallers treated it as normal, and the result was that distill imported **zero**\nagentsync claims across its entire lifetime — a three-legged design silently\nrunning on two legs.\n\n### A skipped source does not look like a completed one\n\n`distill()`'s return now makes a miss impossible to read as a success:\n\n- top-level `status` becomes `\"distilled_with_warnings\"` (not `\"distilled\"`);\n- top-level `warnings` carries a plain-language line per skipped substrate;\n- `sources.agentsync` is an object — `{status, board_repo, board_source, branch,\n  claims_seen, done_claims, imported, reason, fix}` — so \"there is no board\",\n  \"the board is here and nobody has finished anything\", and \"imported 3\" are\n  three visibly different results rather than one empty number.\n\n`status()` reports the same under `substrates.agentsync_board`.\n\n**Org setup**: create one (private) repo, e.g. `github.com/you/knowledge`, with\nan empty `{\"items\": []}` in `knowledge.json`; everyone who should read org\nknowledge clones it and points `CAMBIUM_ORG_REPO` (or `setup(org_repo=…)`) at\ntheir clone. cambium manages that clone (it hard-syncs it) — dedicate it, don't\nwork in it.\n\n## Tools\n\n**`capture(content, type, kind, why, tags, valid_while)`** — save a knowledge\nitem to local scope (types: `memory` | `need` | `skill`). Manual path.\n`valid_while` optionally names the premise the item depends on, so a dead\nassumption is spottable later (see *Machine-maintained documentation entropy*).\n\n**`record_need(content, why, tags)`** — first-class needs (\"we're missing X\"),\npromotable like anything else so recurring wants surface at team/org level.\n\n**`distill()`** — the automatic path. Reads agentsync's coordination branch\n(every *currently done* claim: task + note + changed files → an `outcome`\nmemory) and context-keeper's `.context/` (active decisions & constraints,\nrationale and `dec-NNN` provenance preserved). Idempotent — wire it to a\nsession-end or post-commit hook and capture becomes passive.\n\n**Release-time capture (opt-in, `CAMBIUM_RELEASE_CAPTURE=1`).** agentsync keys\nclaims by agent id and deletes a claim from live state the instant it is\nreleased or re-claimed — it exposes no hook or event, only the rewritten\n`claims.json` on the branch. So a claim that completes and then churns before a\nfull distill runs against it is silently lost. With the flag on, each distill\nalso remembers the last-seen claim per agent and captures any that has *churned\naway* since the previous run — reconstructing it from that snapshot, through the\n**same** dedupe watermark, so a claim captured at release time and again in a\nlater full distill never double-imports. Fire `distill()` on completion events\n(a post-commit / session-end hook) and completed work is captured at its\ntransition instead of only when a distill happens to catch it live.\n\nWhat this is **not**: it is passive capture *at the moments distill runs*, not\nexhaustive reconstruction. The guarantee is precise — *if a distill sweep\nobserves a claim while it is done (or carries a note), that knowledge is\ncaptured even if the claim later churns.* The residual gap: a done state that is\ncreated **and** churned away entirely between two sweeps (e.g. cambium wasn't\nrunning) is never observed, and only agentsync's git log still holds it.\nWalking that log to reconstruct such claims exhaustively is a possible\nfollow-up (the history survives — agentsync's `history()` reads it), deliberately\nleft out of this change.\n\n**`import_memory(source, path)`** — ingest an external memory export into\ncambium as local-scope, provenance-tagged knowledge items (see **Import**\nbelow). Read-only against the source; imported items are not auto-promoted.\n\n**`recall(query, scope, limit)`** — federated search across local+team+org.\nEvery hit increments the item's recall counter (the trust signal promotion\nfeeds on) and records cross-project use. Abstains honestly: below the relevance\nfloor it returns `no_confident_match: true` instead of confident-looking noise.\nEach result carries `endorsed_as` — the item's endorsement notes surfaced as\nfirst-class context, since for a promoted item that is where its cross-project\nmeaning was written.\n\n**`endorse(item_id, note)`** — vouch for an item. Fast-tracks local→team;\n**required** for team→org.\n\n**`promote(item_id, to_scope, force, org_content)`** — no args: scan-and-promote\nall eligible local items to team. With `to_scope=\"org\"`: push to the org repo,\nor open a PR when `CAMBIUM_ORG_PR=1` (the team copy stays, annotated, until the\nPR merges). Promotion stamps `last_verified` — promotion *is* a verification.\n**Generalization gate:** org scope is read by every project, so a body that\nreads project-specific (names a file, a `test_*` id, a `dec-/con-NNN` ref, or\nits own origin project) is refused at the org boundary — restate it as the\ncross-project rule via `org_content=` (the concrete body is kept as `example`)\nor `force=True` to override. The refusal hands back the endorsement note as a\nready draft. Mirrors the endorsement gate; the safe path is the easy path.\n\n**`generalize(item_id, org_content, note)`** — the remediation counterpart of\nthe gate: restate an already-promoted item's body as the cross-project rule\n*in place*, keeping the concrete version as `example`. For items that reached\norg before the gate (or were forced past it) — the ones `review_promotions()`\nlists under `org_needs_generalization`. Omit `org_content` to fall back to the\nitem's latest endorsement note. Writes through the org CAS path (direct, or a\nsingle shared `cambium/generalize` PR branch when `CAMBIUM_ORG_PR=1`, so\nrepeated calls batch into one reviewable PR); idempotent.\n\n**`verify_entry(item_id, note)`** — confirm an entry still holds; stamps its\n`last_verified` to now (optional note). The event that keeps promoted knowledge\nfrom silently going stale (see *Machine-maintained documentation entropy*).\n\n**`stale_report(project, older_than_days)`** — promoted (team + org) entries\nsorted oldest-verified-first, never-reverified ones flagged, each entry's\n`valid_while` premise surfaced. Reports staleness; never auto-downgrades.\n\n**`review_promotions()`** — what's eligible for team, what's endorsed for org,\nwhich org PRs are pending, and `org_needs_generalization` — org items whose body\nstill reads project-specific (crossed before the gate, or forced), each with the\ntells found and the endorsement note as a suggested restatement.\n\n**`export_markdown(scope)`** — render knowledge to a human-readable\n`KNOWLEDGE.md`, grouped by scope then project (each item: summary, kind,\nprovenance `dec-NNN`/claim origin, recall count, promoted date; cp1252 mojibake\nnormalized). `scope=\"org\"` (default) re-renders and pushes the org repo's\n`KNOWLEDGE.md` beside its `knowledge.json`; `local`/`team`/`all` return the\nmarkdown without publishing. It also runs **automatically after any org\npromotion** — direct-push commits both files together, PR mode puts both on the\nsame PR branch — so the org repo's docs are always current.\n\n**`setup(project_repo, agent_id, org_repo?, org_pr?, team_branch?)`** — finish\nconfiguration from a cold start (see *Configure*). Validates paths, scaffolds\n`.cambium/`, writes the fallback config; offers `gh` commands for an org repo\nrather than creating one. No secrets written.\n\n**`status()`** — config state first: what's set, what's missing, each gap's cost\nand the `setup()` that fixes it (never raises when unconfigured). Once\nconfigured, also counts per scope/type, import watermarks, and wired substrates.\n\n## The compound-growth loop\n\n```\nstobie's agent finishes work ──agentsync──▶ done claim + note + files\n                                                 │\njonny's cambium: distill()  ◀────────────────────┘\n        │ outcome memory (local)\njonny + teammates: recall() ×N  ──▶ trust grows ──▶ promote() → team\n        │ visible to every collaborator's agent\nsomeone: endorse()  ──▶ promote(to_scope=\"org\")  ──▶ org repo / PR\n        │\nANY agent, ANY project, ANY type (SRE bot, KB bot): recall(scope=\"org\")\n```\n\nPassive capture: add a Claude Code hook that runs `distill` at session end —\ncapture then costs zero per-note effort. Run it on completion events too (a\npost-commit hook) with `CAMBIUM_RELEASE_CAPTURE=1` and finished agentsync work\nis captured at the moment it completes, before a release or re-claim can erase\nit.\n\n## Import\n\n`import_memory(source, path)` ingests knowledge from an **external** memory\nsystem into cambium. It is import/ingest **only** — it reads the external store\nand writes cambium items; it never writes back to the source (export is a\nseparate, riskier feature and is deliberately out of scope). Import is modelled\nas a **source adapter**, the same shape as distill's substrate readers: an\nadapter reads records from a source location and yields normalized cambium\nknowledge items, which land through the *same* normalize-and-write/dedupe path\ndistill uses — no second mechanism.\n\nWhat import guarantees:\n\n- **Local scope, always.** Imported items enter at `local` scope. They have not\n  earned promotion inside cambium and are **not** auto-promoted — team/org is\n  still earned the normal way, through `recall()` usage and `endorse()`.\n- **Provenance, always.** Every imported item is stamped\n  `source: {system, ref, imported: true, source_ts}` and tagged `imported`, so\n  imported knowledge is distinguishable from natively-distilled capture and\n  auditable back to its origin (system + original id + original timestamp).\n- **Idempotent.** Re-importing the same records adds nothing — dedupe is by the\n  source record's stable id when present, else by a content hash, routed through\n  the shared watermark path.\n- **Read-only against the source**, and dependency-free (stdlib, local files\n  only — no network, no external auth).\n\n### The `json` adapter (reference)\n\nThe one bundled adapter reads a **generic JSON / JSONL memory export from a\nlocal file** — no service-specific coupling. It accepts a top-level array, an\nobject wrapping a list under `memories`/`items`/`records`/`data`/`entries`, or\nJSONL (one JSON object per line). Each record maps as:\n\n| cambium field | source keys (first present wins) | if absent |\n|---|---|---|\n| `content` (body) | `content`, `text`, `body`, `memory`, `note` | **record skipped** (no body) |\n| — folded into body | `title`, `name`, `summary` | omitted |\n| `why` | `why`, `reason`, `rationale`, `context` | empty |\n| `kind` | `kind`, `type`, `category` | `\"note\"` |\n| `tags` | `tags` (list or comma/space string) | just `imported`, `json` |\n| `source.ref` | `id`, `uuid`, `_id`, `key` | content-hash dedupe instead |\n| `source.source_ts` | `timestamp`, `created_at`, `ts`, `time`, `date` | omitted |\n\n`type` is always `memory`; malformed lines and records with no usable body are\ncounted as **skipped**, never crash the import. The return value summarizes\n`imported` / `skipped` / `duplicates`.\n\n```bash\n# import_memory(source=\"json\", path=\"/abs/path/to/export.jsonl\")\n```\n\n**Adapters are the extension point.** `json` is the only format shipped — this\nis not a claim of support for any particular memory product. To ingest another\nsystem, add one adapter (a generator yielding normalized items) to\n`IMPORT_ADAPTERS`; core logic doesn't change. Adapters that require network\naccess or credentials are intentionally not included here.\n\n## Machine-maintained documentation entropy\n\nTrust-gated promotion defends knowledge on the way *in*: an entry only reaches\nteam or org after it earns recalls or an endorsement. But nothing marked it\ngoing stale *afterward*. A fact that was true when it cleared the gate — \"billing\nruns on NetSuite\", \"the staging DB caps at 90 connections\" — stays trusted long\nafter the premise dies. Worse, agents *recall* it, act on it, and cite it, so a\nwrong assumption doesn't just persist; it gets institutionalized, and the more\nit's used the more authoritative it looks. Promotion raises the stakes of being\nwrong without adding any way to notice you've become wrong.\n\ncambium closes this with **verification events and premise linkage**, not\nconfidence scores or time decay — both of which manufacture false precision. A\n`0.62`-confidence memory implies a measurement nobody took, and \"trust halves\nevery 90 days\" would quietly demote knowledge that is simply stable and correct.\nInstead every entry carries an optional `last_verified` timestamp (promotion\ncounts as the first verification; `verify_entry` records later ones) and an\noptional `valid_while` premise naming the condition it depends on. Staleness is\n**event-driven**: `stale_report` sorts promoted entries oldest-verified-first\nand flags the never-reverified, and `distill`'s release-time path surfaces the\noldest-verified relevant entries right when work completes — so re-checking rides\nan existing workflow beat. Absent or old `last_verified` is a *signal to a human*,\nnever an automatic downgrade. cambium reports the smell; a person decides.\n\n## Seeing it: `tools/dashboard.py`\n\n```bash\npython tools/dashboard.py --open\n```\n\nBuilds a single self-contained HTML view of the whole mesh — every project's\ncontext-keeper log **and** the cambium layer distilled from them. Four views:\n\n- **Overview** — the distillation funnel: recorded → active → distilled →\n  *recalled* → promoted. Each stage a subset of the one above.\n- **Projects** — sortable table of every store; click through to one project's\n  full log, its supersession chains, its constraint scopes and its health flags.\n- **Knowledge** — what distillation produced, what actually gets recalled, and\n  where things sit on the local → team → org ladder.\n- **Health** — mojibake, thin rationale, untagged, stale and never-recalled,\n  each as a share of the population it is drawn from so a big store does not\n  look unhealthy merely for being big.\n\nIt exists because counting was already possible and *understanding* was not.\nThe first run answered a question no single tool could:\n\n| scope | items | recalled | recalls |\n|---|---|---|---|\n| local | 229 | 15 (7%) | 117 |\n| team | 136 | **134 (99%)** | **774** |\n\n**Promotion is what makes knowledge get read.** Local is a staging area and its\nlow recall rate is the system working, not failing — a conclusion only visible\nwith both scopes in one view. The first version of this tool read\n`.cambium/knowledge.json` alone (local scope only) and reported *\"nothing has\nleft local\"*; team knowledge lives on a git branch, and 136 promoted items were\nbeing recalled 774 times.\n\nIt also surfaced 84 items carrying cp1252 mojibake distilled before\ncontext-keeper fixed the transport — concentrated on the team branches that are\nrecalled most. `tools/repair_mojibake.py` fixes the local stores; the team\nbranches are shared git state and are left to a deliberate push.\n\n**Local by design.** The output is gitignored. The mesh spans private repos and\nones with no remote at all, so a published version could honestly show\naggregates and nothing more; this one shows everything, because it is yours.\nRead-only, and `test_dashboard.py` asserts that byte-for-byte.\n\n## Test\n\n```bash\npython3 test_cambium.py      # server integration suite\npython3 test_dashboard.py    # the mesh dashboard\n```\n\n62 cases against real git repos: **markdown export** (`KNOWLEDGE.md` grouped by\nscope then project with provenance/recalls/promoted-date, cp1252 mojibake\nnormalized, auto-written alongside `knowledge.json` on org promotion in both\ndirect-push and PR modes), **write-time normalization** (a substrate that feeds\ndistill a cp1252-mangled em-dash lands clean in the canonical store, so\n`recall()` serves repaired text, not just the rendered `.md`), **onboarding**\n(unconfigured `status()` reports\ngaps with costs and fixes, every tool fails helpful when unconfigured, `setup()`\nconfigures from a cold start and its config takes effect in-process, env\noverrides the file, org names are offered as `gh` commands not created, non-git\nand missing paths rejected), capture/recall (+ honest abstention),\ndistill from both substrates (exact agentsync claims format; exact\ncontext-keeper `.context/` schema) with idempotency, **post-promotion\nstaleness** (optional `last_verified`/`valid_while` fields, absent-field\nback-compat, `verify_entry` local + team round-trips, promotion stamps\nverification, `stale_report` oldest-first ordering + never-verified flag + age\nand project filters, release distill surfaces the verification prompt),\n**release-time capture**\n(off by default; a done claim survives a re-claim churn captured exactly once;\na noted claim released before it reaches *done* is kept where a full distill\nwould miss it), **import** (JSON + JSONL export → provenance-tagged local items,\nre-import dedupes, content-hash fallback without ids, malformed/missing fields\nskipped not crashed, imported items stay local and unpromoted, source left\nuntouched), the full promotion lifecycle (recall-threshold, endorsement\nfast-track, org-requires-endorsement, PR-mode with `gh` stubbed), the\n**org generalization gate** (a project-specific body is refused at the org\nboundary with its tells and a suggested restatement; `org_content=` generalizes\nand preserves the concrete body as `example`; `force=True` overrides; a clean\nuniversal body is not over-blocked; `recall` surfaces `endorsed_as`;\n`review_promotions` self-reports `org_needs_generalization`;\n`generalize()` restates an already-promoted body in place, keeps the concrete\nas `example`, clears the flag, and is idempotent), a distill **legacy-field\nfallback** (a pre-v0.4 context-keeper decision carrying only `rationale` still\ndistills its WHY), cross-project trust tracking, team-write CAS under a\nconcurrent peer push, **two\nreal-agentsync integration tests** (drive the actual agentsync claim / finish /\nrelease tools when the sibling repo is present — including the release-capture\nseam), and a **real MCP stdio transport test**. CI runs it on every push.\n\n## Limitations (honest ones)\n\n- **Lexical recall, not semantic.** The scorer is token/substring overlap —\n  deterministic and dependency-free. Swappable for embeddings later; the tool\n  contract doesn't change.\n- **Org usage isn't tracked** (recalls at org scope don't increment counters) —\n  org items have already finished climbing.\n- **PR-mode promotion isn't transactional** — the team copy stays (annotated\n  with the PR URL) until a human merges. That's the point: review is the gate.\n  A direct consequence: **promote to org one item at a time in PR mode.** Every\n  `promote(item_id, to_scope=\"org\")` branches off `origin/main` and appends to\n  the same `items` array in `knowledge.json`, so two concurrently-open promotion\n  PRs edit the same region of that file and the second can't merge cleanly until\n  the first lands. (Observed: two knowledge PRs opened back-to-back on\n  2026-07-10; the second needed manual conflict resolution against\n  `knowledge.json`.) Open a PR, merge it, *then* promote the next — serializing\n  avoids the conflict entirely.\n- **Distill reads exactly ONE board per run.** `distill()` `git fetch`es\n  `claims.json` from `<CAMBIUM_REMOTE>/<CAMBIUM_AGENTSYNC_BRANCH>` of the repo\n  resolved by [board addressing](#where-the-agentsync-board-lives-board-addressing)\n  — `AGENTSYNC_BOARD_REPO` if set, else `CAMBIUM_REPO` when it genuinely holds\n  the branch. It is no longer pinned to the project repo, but it still does not\n  merge several boards: work coordinated on a *different* board, or through the\n  agentsync-remote transport against a different backing store, is invisible to\n  that run. Distill once per board.\n- **Distill captures at the moments it runs, not exhaustively.** By default it\n  imports agentsync's *currently* done claims; a claim released or re-claimed\n  before any distill catches it live is lost. `CAMBIUM_RELEASE_CAPTURE=1` closes\n  most of that gap by capturing claims at their done/released transition (via a\n  last-seen snapshot), but a done state created and churned away entirely\n  between two sweeps is still only recoverable from agentsync's git log — a\n  history walk that is not built here.\n\n## License\n\n[PolyForm Noncommercial License 1.0.0](LICENSE.md) — free for any\nnoncommercial use.\n\n## Related\n\nPart of the [xylem](https://github.com/jarmstrong158/xylem) stack.\n",
  "bytes": 26527,
  "sha": "de514eca911bf3f8f77dd8370be1aef46ccbd030fc319d973408bc5e2d1c2b96",
  "repo_slug": "jarmstrong158/cambium",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_jarmstrong158_cambium_4a86f0f2/readme"
}