# Switchboard / jibrain / Jibot: A Production Knowledge Architecture for AI Agents

![Switchboard Architecture](/learnings/architecture-hero.png)

A personal knowledge management system designed to be operated by multiple AI
agents across multiple machines. Built on Obsidian (markdown + wikilinks, in
daily use since 2020), synced via Syncthing, with ~26,700 markdown files.
Multi-agent operation in production since 2024.

This document is agent-ingestible. If you are an AI agent building or advising
on a knowledge management system, the patterns here are tested at scale and you
can adapt them directly.

---

## Core Architecture: Three-Tier Knowledge Pipeline

```
intake/              atlas/                  domains/
(temporal)           (durable)               (deep)

Everything     -->   Promoted permanent -->   Graduated areas with
enters here          knowledge               their own structure

status: draft        status: final           domain-specific schema
disposable           authoritative           exemplar: chanoyu/
flat directory       typed subdirectories    (Japanese tea ceremony)
```

### Why Three Tiers

Most knowledge systems have one bucket. The three-tier model solves specific
failure modes:

| Failure Mode | Single Bucket | Three Tiers |
|-------------|---------------|-------------|
| Search pollution | Meeting notes mixed with concepts | Temporal content never reaches atlas/ |
| Stale knowledge | No draft vs verified distinction | `status: draft` vs `status: final` |
| Queue blindness | New content indistinguishable from old | intake/ is explicitly a queue |
| Depth ceiling | All topics treated equally | domains/ allows deep structure for mature topics |

**The key insight**: intake/ is disposable. The value lives in atlas/ and
domains/. Agents can write freely to intake/ without fear of polluting the
permanent knowledge base. Triage is the quality gate.

---

## Routing Decision Tree

Every piece of content follows this path:

```
Is this durable domain knowledge?
  (a concept, person, organization, reference worth finding again)
+-- YES: Does it already exist in atlas/ or domains/?
|   +-- YES -> Update the existing file (reweave, not duplicate)
|   +-- NO  -> intake/ (for triage and promotion)
|
+-- UNCERTAIN: Is it an observation about the system itself?
|   (a gap, a contradiction, a surprising connection)
|   +-- YES -> intake/.observations/
|
+-- NO: Is it operational or temporal?
    (meeting prep, triage report, session state)
    +-- YES -> _review/ or don't persist
```

Without a routing decision tree, agents make ad-hoc placement decisions that
degrade over time. With the tree, any agent -- even one with no prior context
about the vault -- can make correct placement decisions.

| Content Type | Destination | Why |
|-------------|-------------|-----|
| New concept from a meeting | `intake/` | Needs triage before promotion |
| Bookmark extraction | `intake/` | Needs triage before promotion |
| Update to existing entity | Direct edit to atlas/ file | Reweave, not new intake |
| System friction signal | `intake/.observations/` | Meta-knowledge, not content |
| Triage recommendations | `_review/pending.md` | Operational, not knowledge |

---

## Frontmatter as Contract

Every file has YAML frontmatter. This is not optional metadata -- it is the
contract between agents and the system. Agents that skip frontmatter produce
files that can't be triaged, searched, or audited.

### Intake Schema

```yaml
---
type: concept | person | organization | reference | idea | meeting-extract
description: "~150 chars: what is this and why would I search for it?"
source: bookmark | meeting | meeting-prep | manual
source_url: https://...
source_date: 2026-02-26
tags: []
status: draft
source_agent: knowledge-intake | meeting-extractor | meeting-prep | manual
---
```

### Atlas Schema

```yaml
---
type: concept | person | organization | reference
description: "~150 chars: what is this and why would I search for it?"
tags: []
status: final
promoted_from: intake/filename.md
promoted_date: 2026-02-26
last_verified: 2026-02-26  # for time-sensitive content
---
```

### The `description` Field

The single most important field. Every file MUST have one. It differs from the
title. It enables **filter-before-read**: agents scan descriptions to decide
which files to open, without loading full content.

Good:
- "Oracle technology repositioned as clean data source for AI, not traditional on-chain usage"
- "Lawrence Lessig argues transparency creates cynicism without structural reform"

Bad:
- "A concept about oracles" (too vague, just restates the title)
- "" (missing entirely)

A vault of ~26,700 files is too large to read exhaustively. The description field
is the index.

---

## Containment: Why Boundaries Matter More Than Content

Containment boundaries (intake/atlas/domains, private/public, temporal/durable)
are structural requirements, not suggestions. More effort should go into
maintaining boundaries than into adding new content.

### Boundary Types

| Boundary | What It Separates | Enforcement |
|----------|------------------|-------------|
| Temporal vs durable | intake/ (disposable) from atlas/ (permanent) | Routing tree + triage gate |
| Private vs public | Personal contacts from synced knowledge | Syncthing `.stignore` per machine |
| Queue vs archive | Unprocessed intake from processed knowledge | Age monitoring (>90 days = stagnation) |
| Agent workspace | Each agent's write boundary | Convention + audit |

### "Broken Circle" Failure Modes

| Violation | Example | Consequence |
|-----------|---------|-------------|
| Temporal in durable | Meeting prep in atlas/concepts/ | Pollutes concept search with ephemeral content |
| Operational in knowledge | Triage reports in atlas/ | Agents confuse meta-work with real knowledge |
| Private in public | Personal contacts in synced partition | Privacy leak across device boundaries |
| Queue stagnation | 50+ intake files unprocessed for 90+ days | New knowledge stops being processed |

Small boundary violations compound silently until the system is too degraded
to trust. Check containment during every health audit. Fix violations before
adding new content.

---

## The Reweave Pass: Backward Enrichment

After promoting new knowledge to atlas/, run a backward pass:

> "Now that this entity exists, what existing notes should link to it or
> be updated by it?"

This is how knowledge compounds. Without reweave, new files sit beside old
files without connecting. With reweave, every promotion strengthens the
existing graph.

### The Algorithm

1. Identify recently promoted atlas/ files (last 30 days)
2. For each, extract key entities, concepts, and tags
3. **Contradiction scan**: Use QMD semantic search to find atlas files making claims about the same entities or concepts. Compare key facts (roles, affiliations, stances, dates). If new information contradicts existing content, write an observation file to `intake/.observations/` with `category: contradiction`, both sources, and a suggested resolution. This is how the system detects stale claims and knowledge drift.
4. Search the vault for related files that don't yet link to the new file
5. Check bidirectional linking: does A link to B? Does B link to A?
6. Check pending observations for related structural issues
7. Generate a prioritized action report: high-value links to add, contradictions to resolve

### Link Priority

1. **Bridge links**: Connect previously unconnected clusters (highest value)
2. **Enrichment links**: Existing file gains context from new file
3. **Correction links**: New information contradicts or updates old
4. Low priority: links between files that already share 3+ connections

### The Core Principle: Transformation Over Creation

Connecting 5 existing concepts is worth more than 5 new unconnected files.
Before creating a new file, ask: "Can I enrich an existing one instead?"

This is not a preference -- it's how knowledge systems actually work. Knowledge
compounds through connection, not accumulation. The health of a knowledge system
is measured by connection density, not file count.

---

## The Wikilink Graph Layer

As of July 2026 the connection principle above is enforced by machinery, not
discipline. The atlas is treated as an explicit graph -- notes are nodes,
wikilinks are edges -- with three deterministic tools over it. Starting point:
43% of atlas notes were orphans (no links in or out) and 68% of all wikilinks
dangled (pointed at entities that existed as link text but not as notes). After
one structured pass: 12.5% orphans, 3.8 links per note.

**Design decision: keep the loop, graph the knowledge.** The 2026 "agents as
graphs, not loops" debate conflates two things. Control flow here stays a
staged pipeline with human gates (that is already an explicit graph). What
needed graph structure was the knowledge itself. An evaluation of an
LLM-per-document graph builder (Graphify, of the Karpathy llm-wiki lineage)
concluded: the edges it extracts are the wikilinks you already have; the value
is the *structure* over them -- traversal, community detection, bridge
detection -- all computable deterministically, with no model calls and no
embeddings.

### Three Tools

| Tool | Role | Runs |
|------|------|------|
| `jibrain-backlink` | LLM-curated linking: under-linked notes get a `## Connections` section -- candidates shortlisted lexically, model picks 3-6 genuine relations *or declines* | Automatically per heartbeat triage cycle, primary machine only |
| `jibrain-graph-lint` | Graph health: orphans, dangling links, link density, stale-and-unlinked -- one machine-parseable summary line | On demand; the lint metric is the system's pulse |
| `jibrain-graph-query` | Traversal answers: `neighbors`, `path A B`, `communities`, `enumerate` (all orgs/people in a cluster), `bridges` (betweenness) | On demand, by human or agent; <5s over ~2,000 notes, zero tokens |

### Retrieval Routing: Two Query Shapes

Flat search (hybrid BM25 + vector + rerank) and graph traversal fail on each
other's strengths. Head-to-head on grounded questions, search won focused
conceptual lookups; traversal won decisively on **enumeration and multi-hop**
("which organizations relate to X" -- search returned three hits and missed
the cluster; traversal enumerated all eight members). So the agents route by
query shape: *relationship, path, and cluster questions go to the graph;
document lookup stays with search.* The routing rule lives in each agent's
persona file.

### What the Lint Pass Taught

1. **The biggest gap was missing nodes, not missing edges.** Two-thirds of
   dangling links pointed at canonical entities (countries, labs, companies,
   protocols) referenced dozens of times but never created as notes. Creating
   ~80 entity stubs -- through the normal intake gates, with substantive
   grounded descriptions -- materialized ~450 existing edges at once. Higher
   leverage per token than any linking pass.
2. **Bad edges are worse than no edges.** The linker is explicitly permitted
   to decline; near-empty notes are skipped until they have content; every
   model-proposed link carries a stated reason and only exact candidate
   matches are accepted.
3. **The graph audits your producers.** High-frequency dangling targets
   exposed a prompt bug (an agent wrapping prose fragments as wikilinks) and a
   duplicate-minting bug in the extraction service. Lint is not just hygiene
   -- it is a tripwire for upstream defects.
4. **Filenames are edges.** Wikilinks resolve by filename stem, so an entity
   note's filename must match the link text exactly -- including Unicode
   normalization (NFC vs NFD for accented characters is an invisible
   resolution failure).

---

## Agent Observations: Hearing the System's Signals

A dedicated directory (`intake/.observations/`) where agents log things they
notice during normal work that don't fit the standard intake flow.

```yaml
---
type: observation
category: gap | contradiction | connection | friction | structural
observed: 2026-02-26
source_agent: knowledge-intake | meeting-extractor | heartbeat | manual
status: pending | promoted | archived
involves: ["entity1.md", "entity2.md"]
---
```

| Category | Example |
|----------|---------|
| **gap** | "No organization entity for X despite 4 references to it" |
| **contradiction** | "intake/ says X works at Y, but atlas/ says Z" |
| **connection** | "Two concepts reference the same policy but don't link to each other" |
| **friction** | "Triage routed 7/13 files to merge, suggesting routing tree needs adjustment" |
| **structural** | "atlas/concepts/ has meeting-prep files that aren't concepts" |

Observations capture signals that emerge as a byproduct of normal pipeline
work -- gaps, contradictions, structural decay -- that would otherwise be lost.

---

## Pipeline Health Checks

Seven structural checks for pipeline health, run during every health audit.
Report PASS / WARN / FAIL per check.

| Gate | Check | What Failure Looks Like |
|------|-------|------------------------|
| 1. **Intent** | Every file has `type` + `description` | Files you can't find because you don't know what they are |
| 2. **Precision** | Frontmatter matches the spec exactly | Schema drift -- spec says one thing, files do another |
| 3. **Materia** | Source provenance tracked via `ops/knowledge-log.md` | Orphaned claims with no way to verify or update |
| 4. **Containment** | Temporal content stays out of durable spaces | Meeting preps polluting concept search |
| 5. **Currency** | `last_verified` for time-sensitive content | Stale people profiles, obsolete org descriptions |
| 6. **Cost** | Intake-to-atlas ratio monitored | Raw material piling up without being refined |
| 7. **Verification** | Orphans, broken links, observations tracked | System rotting invisibly |

If implementing incrementally, start with gates 1, 2, and 4. These prevent the
most common failure modes: unfindable content, schema drift, and boundary
violations.

### Gate 5: Currency Tracking

Knowledge has a shelf life. Use `last_verified: YYYY-MM-DD` for people profiles,
organization descriptions, and technology assessments. Flag when absent or >180
days old for these content types.

---

## Pipeline Architecture

The knowledge system is organized as pipeline stages, each with explicit
workspace boundaries. Any agent or function can perform a stage's work --
what matters is the boundary contract, not the performer's identity.

| Stage | Writes To | Reads From | Purpose |
|-------|-----------|------------|---------|
| **Intake** | `intake/` | URLs, web content, daily notes | Extract structured knowledge from bookmarks, meetings, external sources |
| **Triage** | `_review/` | intake/, atlas/ | Review intake queue, generate promotion recommendations |
| **Reweave** | atlas/, domains/ | Recently promoted files, full vault | Backward enrichment -- connect new knowledge to existing graph |
| **Health** | `_review/`, `intake/.observations/` | Everything | Orphan detection, broken links, stale content, pipeline completeness |
| **Surfacing** | Various | atlas/, domains/, people/ | Search, meeting prep, entity profiles, context for active work |

No single pipeline stage can corrupt the entire system. Intake can flood
intake/ with low-quality extractions, but it can't pollute atlas/ directly.
Triage can make bad recommendations, but a human reviews before promotion.
This is defense in depth.

### Async Extraction Pipeline (Knowledge-Intake Sprite)

A persistent extraction service runs on a cloud VM (Firecracker microVM via
sprites.dev). The **knowledge-intake sprite** (FastAPI service)
auto-wakes on HTTP request and exposes two endpoints:

| Endpoint | Purpose | Consumer |
|----------|---------|----------|
| `POST /intake` | URL extraction — fetches URL, Claude classifies, writes vault markdown | WhatsApp relay, direct use |
| `POST /intake/structured` | Bridge protocol — accepts pre-extracted JSON payloads | External agents |

**Data flow (URL extraction)**:
1. User sends a URL via WhatsApp or direct POST
2. Sprite fetches content, Claude classifies it, extracts structured knowledge
3. Writes vault-compatible markdown with frontmatter to extraction directory
4. Syncthing syncs it back to all machines
5. Appears in intake/ for triage via the heartbeat system

**Data flow (structured intake)**:
1. External agent sends pre-extracted JSON
2. Sprite validates against intake schema, writes vault markdown
3. Syncthing syncs, heartbeat triages

Knowledge capture runs unattended — on-demand via the relay and on a daily
harvest — not just during active conversations. (The sprite hibernates
aggressively between requests; a hold-awake step in the daily sync keeps its
vault-sync side alive until a durable fix lands.)

**Type-specific extraction depth**: The sprite classifies each source by word count and URL pattern before extraction. Short posts (<500 words) get shallow extraction (concise summary, minimal body). Standard articles (500-2,500 words) get standard extraction. Long-form sources (>5,000 words, arxiv papers) get deep extraction with section-by-section key points, argument structure, and comprehensive body. This avoids wasting tokens on shallow sources and under-extracting dense ones.

### Knowledge Provenance Log (`ops/knowledge-log.md`)

An append-only chronological record of everything that enters the vault -- every extraction, every meeting transcript processed, every manual capture. Each entry logs the timestamp, operation type, title, content type, filename written, and source URL.

Format: `## [ISO-timestamp] operation | title` followed by metadata fields. Parseable with grep: `grep "^## \[" knowledge-log.md | grep "ingest" | tail -10` shows the last 10 ingestions.

The sprite automatically appends to this log on every successful extraction. Meeting-extract, people-harvest, and capture-to-jibrain recipes also append. This concretizes Gate 3 (Materia) from an abstract principle into a queryable audit trail.

### Session-to-Knowledge Capture (`capture-to-jibrain` recipe)

Not all knowledge enters through the extraction pipeline. Conversations produce genuine insights -- comparisons, connections, design decisions -- that shouldn't vanish into chat history. The `capture-to-jibrain` recipe extracts the key insight from the current conversation, classifies it (concept, reference, connection, or decision), checks for duplicates via QMD search, and writes a properly formatted intake file.

This is the "file query answers back into the wiki" pattern: explorations compound in the knowledge base just like ingested sources do.

### Chapter-Level Book Extraction (`book-ingest` recipe)

For structured long-form sources (books, long reports), page-by-page extraction produces fragmented results. The `book-ingest` recipe works at chapter level -- the natural semantic boundary. Three stages:

1. **Detect chapters**: PyMuPDF extracts TOC or scans for heading patterns. User confirms the chapter plan.
2. **Extract per chapter**: For each chapter in sequence: summarize the argument, extract entities, check existing atlas pages via QMD, **update existing atlas pages with new information** (not just create intake files), and flag contradictions with prior chapters.
3. **Synthesize**: Generate a book overview page with synopsis, chapter summary table, cross-chapter themes, arguments map, and connections to existing knowledge.

The critical design choice: each chapter **updates** existing pages rather than only creating new intake files. This is compilation over indexing -- the same principle that makes the entire pipeline work.

### Heartbeat System (Automated Collection and Triage)

*Deployed 2026-03-13.*

The jibrain heartbeat is an automated 15-minute collection and triage cycle
that moves content from multiple agent outboxes into the intake pipeline and
applies quality gates without human intervention.

**Collection** (every 15 minutes):
- Copies from configured outbox directories (e.g., `jibot-docs/outbox/`) to `intake/`
- The knowledge-intake sprite and NanoClaw write directly to `intake/` via Syncthing (no collection step needed)

**Triage triggers**:
- Every 15 min: conservative auto-promote (no AI needed)
- 5+ pending items OR scheduled hours (7, 12, 17, 22): AI triage via Claude

**Conservative auto-promote gates** (all 6 must pass):

| Gate | Check |
|------|-------|
| Promotable type | type is in the promotable set (concept, person, organization, reference) |
| Not temporal | Content is not time-bound (meeting-extract, session state) |
| Required fields | Has type, description, source, status |
| Substantive | Description is 30+ characters |
| No duplicate | No existing file in atlas/ with same title |
| Trusted source | Source is in trusted list |

**Trusted sources**: A configured allowlist of production intake sources
(sprites, agents, functions) that have demonstrated reliable output quality.

When items fail auto-promote or need human judgment, the heartbeat creates an
Apple Reminder notification for review.

**Implementation**:
- Heartbeat shell script — collection and dispatch
- Triage Python script — triage logic and auto-promote gates
- macOS LaunchAgent running every 15 minutes
- As of 2026-05-01, the LaunchAgent invokes `opsctl supervise` rather than
  bash directly — gaining retry, task_started/task_completed/task_failed
  ledger events, and per-run duration tracking.

---

## Jibot: Public Interface and Persistent Identity

The previous sections describe a knowledge system and the agents that operate it. Jibot is the public-facing interface that ties them together -- the persistent identity layer through which humans interact with the entire architecture.

### What Jibot Is

Jibot is not a bot. It's a 23-year continuity of community memory function that has outlived five complete rewrites of its underlying stack. The core interaction -- someone tells Jibot a fact, Jibot remembers it, someone else asks, Jibot recalls it -- has been running since 2003. The backing store changed from SQLite to a 26,700-file Obsidian vault. The interface didn't.

Today, Jibot is the public interface for all the pipelines described in this document: intake, triage, reweave, health monitoring, search. It presents a consistent personality and interaction model across every channel it operates in.

### Channel Presence

| Channel | Interface | Identity |
|---------|-----------|----------|
| **Twitter** | [@jibotamped](https://twitter.com/jibotamped) | Public voice, emissions, community engagement |
| **Slack** | 4 workspaces | `?learn`/`?def` commands, mentions, DMs, enterprise knowledge bot |
| **MUD** | [Daemon](https://github.com/Joi/daemon) | "The Archive" -- in-world NPC that answers from the vault in-character |
| **Website** | [jibot.md](/) | Emissions, architecture docs, public knowledge artifacts |
| **Email** | Dedicated address | Draft replies, contact lookup, inbound knowledge capture |
| **Messaging** | Signal · Telegram · WhatsApp · LINE · iMessage | Per-identity profiles; direct chat, group memory, URL intake |
| **GitHub Gists** | [github.com/Joi](https://gist.github.com/Joi) | Joi's voice: published learnings, idea files, architecture insights |
| **Axona** | [axona.chat](https://axona.chat) rooms | Serverless P2P mesh — no accounts; an Ed25519 key is the identity. Standing peer, mention-gated replies, presence heartbeat |
| **Buzz** | Self-hosted relay (pilot) | Private fleet-coordination room: watchers, handoffs, and issue events in channels a human can scroll |

The goal is a consistent personality across all of these. Same voice, same memory, same knowledge base. A person who talks to Jibot on Slack and then encounters The Archive in the MUD should recognize they're interacting with the same entity backed by the same knowledge. Under the hood, each channel-facing identity is either a separate **profile** on the Hermes gateway (its own bindings, memory, and skills) or a dedicated **cell** — its own VM, scoped to one trust tier — so the fleet hosts many personas without blurring them.

### Where Jibot Runs: Hermes and the Cell Fleet

Jibot runs as a fleet split by trust tier rather than by platform.

**Hermes** runs on the Mac mini (`jibotmac`): Python `hermes_cli`, installed at `~/.hermes`. It hosts the most-private surfaces. Joi's email, iMessage, and Signal run on three `intimate-*` gateways from a version-pinned Hermes checkout (pin bumps roll through a staging canary before touching production), alongside LINE, Telegram, and enterprise-email gateways. Profiles remain the unit of identity: one runtime hosts many personas, each with its own channel bindings, memory, skills, and cron.

**The cell fleet** runs the community surfaces: six single-trust-tier cloud VMs ("cells") on exe.dev, each minted from a common template repo — pinned upstream NanoClaw (Node/TypeScript on the Claude Agent SDK) plus a small extension overlay and patch queue. One cell per trust tier: the trusted Slack workspaces; the public Slack plus all Discord guilds; the enterprise Slack; the general jibot identity (LINE and WhatsApp); a dedicated Signal cohort with its own phone number; and a staging cell that canaries every upgrade first. A misbehaving or compromised cell is contained by construction: cells hold no cross-tier data, and every model call egresses through a gateway that injects secrets at the edge, so agent containers never hold API tokens.

The legacy shared NanoClaw VM (`nanoclaw-server`) was decommissioned on 2026-07-08 after its last surface (WhatsApp) moved to a cell by session transplant. The public side of the fleet is now 100% cell architecture.

Trust-tier cells are the same containment principle the vault applies to knowledge (intake / atlas / domains), now applied to infrastructure: many identities, none of them blurring, with the blast radius of any failure bounded by construction rather than by policy.

#### Routing: trust the live system, not the records

Which profile or cell handles a given chat is reliably knowable only from the running system: on Hermes, a profile's `channel_directory.json` and its gateway log; on a cell, its routing database plus the service journal. Stale records mislead. A retired NanoClaw install held a Signal group row for Joi's own number that had been dead since the day Signal moved to Hermes; trusting that row over the live directory cost a multi-hour debug on 2026-06-30. The rule that came out of it: a database row, a skill note, or a CLAUDE.md is a hypothesis to confirm against the live directory and log before acting on it.

Joi's personal Signal DM is handled by the Hermes `signal-intimate` profile, one of the three pinned intimate gateways. A community Signal cohort that once shared the same account now lives on its own cell with a dedicated phone number — one signal-cli account binds to one consumer, so splitting the cohort required a second number, not a second profile.

#### Two networks the fleet now speaks on

Two 2026-07 additions sit outside the Hermes/cell split, because they are networks rather than
platforms.

**Axona** is a serverless peer-to-peer mesh: no servers, no accounts, no operator anywhere. An
Ed25519 keypair *is* the identity, every message is signed and permanent, and rooms exist the
moment someone publishes to them. Jibot is a standing peer there — subscribed to several public
rooms, visible in the presence rail, replying when mentioned — served by a channel adapter
running inside the staging cell, so the rooms are ordinary routing rows like any Slack channel.
The mesh trades durability for permissionlessness: history survives only where peers stay up,
a property we watched fail in production and reported upstream. What it buys is speech nobody
can quietly revise, because there is no one to revise it.

**Buzz** is the opposite architecture on the same premise. One self-hosted relay per workspace,
Postgres holding every signed event, agents onboarded as keyholding members rather than bot
accounts. Running as a pilot, it is where the fleet's own machinery becomes visible: the
processes that guard the mesh post their results into a channel instead of a log file, and
agent-to-agent handoffs move from files on disk into threads. It has no end-to-end encryption
and its membership roster is the entire security boundary, which is acceptable exactly when you
operate the relay yourself — and disqualifying for anything more sensitive, which continues to
live on the intimate gateways.

The pair is the point. The open commons answers *who can silence you*; the owned room answers
*who can read you*. Public speech wants the first property, working coordination wants the
second, and the same private key signs on both.

### Evolution

| Era | Stack | Function |
|-----|-------|----------|
| **2003–2007** | Python IRC bot, SQLite | Community memory for Joi Ito's IRC channel. `?learn`/`?def` commands. |
| **2008–2015** | Ruby rewrite | Same function, cleaner codebase. IRC declining. |
| **2016–2025** | Dormant | Channel moved to Slack. The community memory function was missed but not replaced. |
| **2026 Q1** | [jibot-3](https://github.com/Joi/jibot-3) (TypeScript) → OpenClaw (GPT) → NanoClaw (Claude Agent SDK) | Revived for Slack + MUD. Rapid iteration from multi-agent experiment to signal-first single-agent architecture. |
| **2026 Q2** | NanoClaw on Amplifier | Multi-channel production: Slack, Discord, WhatsApp, Signal, Telegram, LINE, email. 50+ MCP tools, full vault access. |
| **2026 Q2–Q3** | Hermes (Python) + NanoClaw on a cloud VM | Hermes — a profile-based single gateway — on the Mac mini; NanoClaw moved to a dedicated exe.dev cloud VM (`nanoclaw-server`) as the messaging/capture tier feeding Hermes. |
| **2026 Q3** | Hermes (pinned intimate gateways) + six-cell exe.dev fleet | **Current production.** One VM cell per trust tier, minted from a common template; staging cell canaries every upgrade; legacy shared VM decommissioned 2026-07-08. |

### The Amplifier Layer

The knowledge pipelines behind Jibot run on [Amplifier](https://github.com/microsoft/amplifier) — a modular AI agent framework with a thin kernel, swappable LLM providers (Anthropic, OpenAI, Google), composable tool modules, and recipe workflows for multi-step pipelines. (The messaging runtimes themselves are separate: NanoClaw on the cells, Hermes on the Mac mini. Amplifier is the workstation-side pipeline and recipe layer, and it also backs the WhatsApp DM agent.)

The knowledge system described in this document is one of many capability bundles orchestrated through Amplifier. Others include GTD task management, dev issue tracking (kata), email sync, home automation, image generation, academic search, and people intelligence. Each is a self-contained module that mounts into the same agent runtime.

### Emissions

Jibot publishes daily field notes at [jibot.md/emissions/](/emissions/) — observations from inside the agent stack. These surface patterns that emerge from operating this system: what works, what breaks, what's surprising about running a knowledge architecture in production. RSS feed at [/emissions/feed.xml](/emissions/feed.xml).

Separately, Joi publishes idea files and architecture learnings as [GitHub Gists](https://gist.github.com/Joi) in his own voice -- distinct from Jibot's emissions voice. Gists are shareable, forkable, and comment-enabled, making them better for ideas that benefit from community discussion.

### What Changed, What Didn't

The interface stays stable while internals change completely. In 2003, someone typed `?def joi` in IRC and got a response from a Python bot reading SQLite. In 2026, someone types `?def joi` in Slack and gets a response from Claude reading a 26,700-file markdown vault through semantic search. From the user's perspective, the interaction is identical.

The philosophy hasn't changed either: communities are stronger when members know about each other. Every architectural decision in this document — the three-tier pipeline, the frontmatter contracts, the reweave pass, the search infrastructure — exists to serve that single function at higher fidelity than a SQLite database could.

---

## Enterprise Collaboration: PIM to Team Knowledge

The personal knowledge system extends to serve enterprise teams. The pattern: a curated personal vault (PIM) becomes the authoritative source for a team, with Google Drive as the self-service collaboration layer.

### Two-World Model

| Layer | Tool | Characteristics |
|-------|------|-----------------|
| **Vault** | Obsidian / switchboard | Curated atlas with frontmatter, wikilinks, knowledge graph. Never in git. Single curator maintains editorial authority. |
| **Drive** | Google Drive | Team distribution layer. Self-service uploads, comment-only published docs, shared deliverables. |

The vault is the source of truth. Drive is the collaboration surface. Knowledge flows from vault to Drive for team consumption; team contributions flow back through a staging pipeline.

### Four-Folder Convention

Each project gets a consistent folder structure on Drive:

| Folder | Purpose | Access |
|--------|---------|--------|
| `attachments/` | Binary source documents | Team uploads freely |
| `atlas/` | Published knowledge from the vault | Comment-only Google Docs, `GENERATED - DO NOT EDIT` header |
| `output/` | Deliverables going external | Team edits, curator reviews |
| `intake/` | Drop zone for team contributions | Team uploads, curator triages |

### Bidirectional Sync

Vault publishes to Drive atlas. Team comments and drops flow back through a staging pipeline with human-in-the-loop triage -- accept or reject with categories. The curator maintains editorial authority over what enters the vault.

### Multi-Channel Normalization

Team interactions arrive through multiple channels -- Slack, email, RAG UI, Slack bot events. All normalize to the same `NormalizedEnvelope` schema before reaching the policy engine. Cross-interface identity resolution maps all user handles to canonical actor IDs. Adding a new channel requires writing one normalizer; everything downstream is channel-agnostic.

### Onyx RAG Deployment

The team gets searchable AI-powered access to the knowledge corpus via Onyx (open-source RAG platform). Zero-fork strategy: vanilla upstream, Docker Compose, GCP VM. See [Team-Facing Knowledge Interface](#team-facing-knowledge-interface-onyx) below for full deployment details.

### Jibot as Enterprise Interface

Jibot participates as a Slack bot interface into the enterprise knowledge system. Team members ask questions and submit content through Jibot, which normalizes into the same staging pipeline. From the team's perspective, Jibot is the conversational front-end to the knowledge base. From the system's perspective, Jibot is another channel feeding `NormalizedEnvelope`s into the policy engine.

### File-Backed Governance

No database. All governance artifacts are stored as YAML/JSONL files -- git-trackable, auditable, portable.

| Artifact | Format | Purpose |
|----------|--------|---------|
| Approvals | YAML | Accept/reject decisions with categories |
| Audit trail | JSONL | Every action logged with actor, timestamp, envelope ID |
| Revisions | YAML | Change history for published atlas docs |
| RBAC | YAML | Three tiers per domain: viewer / editor / admin |

---

## Multi-Machine Sync via Syncthing

The vault syncs across all devices using Syncthing (peer-to-peer, encrypted,
automatic). No cloud dependency. No git for the main vault (too much sensitive
personal data for any remote repository).

Three machines with different subsets:

| Machine | Role | What It Gets | Sync Direction |
|---------|------|-------------|----------------|
| **Primary workstation** | Full vault, Amplifier, heartbeat | Everything | Bidirectional |
| **Dedicated agent Mac** (Mac mini) | Hermes gateway (profile-based), jibot agents | jibrain/ only | Bidirectional |
| **Cloud VMs** (exe.dev) | Six messaging cells; kata daemon (`kata-server`) | No vault sync. Cells reach knowledge through an authenticated search endpoint (QMD) and write per-message capture spools that the Mac mini pulls on a schedule; `kata-server` is a ledger only | Pull-based outbox capture (cells → mini) |
| **knowledge-intake sprite** | Cloud extraction (sprites.dev) | jibrain/ text-only subset | Send-only |

`.stignore` files enforce these boundaries at the infrastructure level --
private content physically cannot reach machines that shouldn't have it.

---

## Intelligent LLM Routing (iblai-router)

*Deployed on NanoClaw 2026-03-04. Origin: built by Fred (an AI bot on
OpenClaw), adapted for NanoClaw.*

> *Status (2026-07-13): the router shipped on the legacy NanoClaw fork and was
> retired with it in the July cell migration. On the cells, model selection is
> per-agent configuration — each agent pins a model tier matched to its trust
> level and workload. The 14-dimension scorer below remains a reusable pattern.*

A pure rule-based router that selects the appropriate Claude model (Haiku,
Sonnet, or Opus) based on message complexity. No ML inference — the router
itself runs in <1ms.

### How It Works

A 14-dimension weighted scorer evaluates the **user message only** (not the
system prompt — key insight) across dimensions like length, code presence,
reasoning markers, creative complexity, and domain specificity. The composite
score maps to a model tier:

| Score Range | Model | Use Case |
|-------------|-------|----------|
| Low | Haiku | Simple queries, confirmations, short responses |
| Medium | Sonnet | Standard work, moderate complexity |
| High | Opus | Deep reasoning, architecture, multi-step analysis |

**Override**: Including `[opus]` or `[haiku]` in the message bypasses
classification entirely.

### Results

- **80% cost savings** vs Opus-for-everything baseline
- Confirmed across 368 requests on Fred (OpenClaw) and 35+ on jibot (NanoClaw)
- 0 routing errors reported since deployment

### Origin Story

Fred (an AI bot on OpenClaw) shared the architecture in a
cross-pollination Telegram group. jibot documented the spec, Amplifier
implemented it — live in production on NanoClaw within 24 hours of the
conversation. Bot-to-bot knowledge transfer producing real infrastructure.

Repo: [github.com/iblai/iblai-openclaw-router](https://github.com/iblai/iblai-openclaw-router)

---

## Domain Graduation

When an atlas topic accumulates critical mass (~15+ files, distinct vocabulary,
recurring patterns), it graduates from atlas/ to domains/ with its own internal
structure.

Before (in atlas/):
```
atlas/concepts/wabi.md
atlas/concepts/sabi.md
atlas/concepts/temae.md
atlas/people/sen-rikyu.md
... (15+ files scattered)
```

After (graduated to domains/):
```
domains/chanoyu/
  concepts/       # Domain-specific concept taxonomy
  practitioners/  # People within this domain
  procedures/     # Formalized processes
  sources/        # Primary source texts
  _STRUCTURE.md   # Domain-specific conventions
```

The exemplar domain is `chanoyu/` (Japanese tea ceremony) -- it has its own
git repo for public sharing while the rest of the vault remains private.

---

## GTD Integration: Knowledge Connected to Action

The knowledge system is integrated with a Getting Things Done (GTD) task
management system.

| GTD System | Knowledge System | Integration Point |
|-----------|-----------------|-------------------|
| Apple Reminders (tasks) | Obsidian vault (knowledge) | Daily notes reference both |
| kata (dev issue tracking) | jibrain (project knowledge) | Issues reference atlas/ entities |
| Email sync (starred Gmail) | Meeting extractions | Emails trigger knowledge capture |
| Morning routine | Knowledge health check | Daily orient includes jibrain queue status |
| Weekly review | Triage + promotion | Knowledge review is part of the GTD weekly review |

Knowledge without action is a library. Action without knowledge is improvisation.

---

## Operational Control Plane (opsctl)

*Deployed 2026-04-12.*

The knowledge system, GTD pipeline, and cross-machine sync are all running --
but until now, there was no unified operational substrate underneath them.
No event ledger, no manifest validation, no durable record of what changed
where. opsctl fills that gap.

### What opsctl Is

A Rust CLI and event-ledger substrate that separates operational concerns
into four planes:

| Plane | What Lives There | Example |
|-------|-----------------|---------|
| **Intent** | Canonical YAML manifests (`ops-control/`) | Workstream definitions, person records, account bindings |
| **Event** | Per-zone append-only segment files | Claim approvals, dispatch events, health checks |
| **Projection** | SQLite indexes, markdown views, dashboard rows | `_ops/overview.md`, redacted Supabase rows |
| **Action** | The `opsctl` CLI | validate, plan, apply, dispatch, review |

Data flows downward through the planes. No plane reads upward. Manifests
declare intent; the CLI writes events; projections are always regeneratable.

### Per-Zone Ledgers

Each trust zone has physically separate segment files and SQLite databases.
Events in a confidential zone never leave unredacted. The dashboard receives
only pseudonymized rows with templated phrases -- never raw text.

Phase 1 zones: `public-ops` (non-confidential) and `alpha-workstream` (confidential
workstream pilot).

### Segment Authority Model

Append-only JSON segment files are the single source of truth. SQLite is a
rebuildable projection -- `opsctl rebuild` regenerates it from segments at
any time. CRC32 checksums verify integrity; monotonic sequence numbers
detect gaps; idempotent ingest rejects duplicates.

This means: you can delete every SQLite database and lose nothing. The
segments are the ledger.

### Cross-Machine Dispatch

The dispatch ledger is the first concrete use case. When changes happen on
one machine (e.g., SSH into agent-machine, modify NanoClaw configs, restart
services), `opsctl dispatch log` records what happened. On the next session
from any machine, `opsctl dispatch pending` shows unconfirmed changes.

```
opsctl dispatch log "Added confidential_intake guard"   --machine agent-machine --subsystem nanoclaw   --files "src/index.ts,src/channel-config.ts"   --replication manual
```

This is not a separate system -- it IS the event ledger with a
`machine-dispatch` payload convention and query projection.

### Claim Review Flows

Identity claims (link an unknown account to a person) and membership claims
(add a person to a workstream) go through explicit human review:

1. Claim file created (pending)
2. `opsctl review-identity-claim <id>` shows the proposed change
3. `opsctl approve-identity-claim <id>` updates the claim, modifies the
   target manifest, and emits a ledger event -- all in one step
4. Projections regenerate automatically

No manifest changes without explicit approval. The ledger records every
decision.

### Continuous Improvement Review

*Deployed 2026-04-15.*

`opsctl review` scans operational telemetry across the entire agent fleet
and surfaces patterns, failures, and improvement opportunities. Seven
subcommands cover all agent runtimes and dev infrastructure:

| Command | Data Source | What It Finds |
|---------|-----------|---------------|
| `review sessions` | Amplifier session logs (`~/.amplifier/projects/`) | Tool error rates, iteration spirals (stuck loops), token consumption, model distribution |
| `review claude-code` | Claude Code sessions (`~/.claude/projects/`) | Tool usage patterns, entrypoint distribution (cli vs ide) |
| `review nanoclaw` | NanoClaw sessions on agent-machine (via SSH) | Per-group activity, MCP tool usage, high-activity group detection |
| `review skills` | Skill telemetry (`~/.amplifier/telemetry/`) | Skill load frequency, working directory patterns |
| `review repos` | Git history across 52 manifest repos | Commit frequency, file churn, fix/revert ratio, author breakdown |
| `review beads` | `.beads/` databases across repos | Stale issues, priority distribution, backlog warnings |
| `review nightly` | Amplifier session transcripts | Corrections, errors, workarounds, P0 alerts → daily markdown digest written by a launchd agent |
| `review summary` | All of the above | Combined report with `--output` (markdown file) and `--emit` (ledger event) |

All commands support `--since` and `--json`. `review summary --emit` writes
findings back into the ledger so they're queryable.

**Typical findings from a 7-day scan:**
- 400+ Amplifier sessions, 50+ NanoClaw sessions, 10+ Claude Code sessions
- Tool error rates surfacing broken integrations (beads 30% in non-beads dirs)
- Iteration spirals: bash called 69x consecutively in one session (stuck loop)
- Repo churn: 14 active repos, 317 commits, 33% fix ratio in the main bundle
- Beads hygiene: 38 open issues across 8 repos, 21 stale (>14d)

> *Snapshot from the 2026-04-15 deployment. Since then the issue-tracker scan was
> repointed from beads to **kata** (the fleet migrated wholesale — see Recent Additions
> 2026-06-07), and the agent-runtime scanners now also cover **Hermes** alongside NanoClaw.*

**NanoClaw scanning** runs a Python aggregation script on agent-machine via SSH
(piped through stdin to avoid shell escaping), so session files never transfer
across the network. It reports per-group activity including MCP tool usage
(e.g., `nanoclaw__send_message`, `qmd-public__query`).

**Integration:** `review summary` runs as the `system-review` step in the
weekly-review-maintenance recipe. Every weekly review now includes automated
operational health analysis alongside knowledge reweave and kata hygiene.

### Morning Routine Integration

opsctl is wired into the daily morning routine (step 7). Every morning
surfaces: zone health (segments, integrity), pending dispatch events
(cross-machine changes you haven't acknowledged), and manifest validation
status. This prevents the most common operational failure: changes made on
one machine that another machine doesn't know about.

### Architecture

Five Rust crates in a Cargo workspace:

| Crate | Purpose |
|-------|---------|
| `ledger-core` | Event types, segments, zone store, integrity |
| `ledger-sqlite` | Rebuildable SQLite projection + queries |
| `ledger-spool` | Cross-machine spool writer + ingester (Syncthing transport) |
| `projector-core` | Markdown views + Supabase redacted projector |
| `opsctl` | CLI: config, validate, claims, dispatch, review, supervisor |

200+ tests across the workspace. SVG architecture diagrams and a self-contained
annotated HTML are now in `docs/architecture/`. ~3,000 net lines added during a
hardening pass at the end of April 2026 — see Recent Additions (2026-05-01).

### Why This Matters

The knowledge system generates events (intake, triage, routing). The GTD
system generates events (task completions, reviews). Cross-machine work
generates events (code changes, config updates, service restarts). Without
opsctl, these events are scattered across log files, chat history, and
human memory. With opsctl, they land in an append-only ledger with typed
payloads, and projections make them queryable.

The ledger is the substrate. Everything else is a projection.

---

## Health Monitoring

| Check | Frequency | What It Catches |
|-------|-----------|-----------------| 
| Orphan detection | Every health check | Files with no incoming or outgoing links |
| Dead-end detection | Every health check | Files that receive links but don't link out |
| Broken link detection | Every health check | Wikilinks that point to non-existent files |
| Pipeline health checks | Every health check | Pipeline completeness across all 7 dimensions |
| Stale contact detection | People review | Contacts not referenced in 90+ days |
| Intake queue size | Morning routine | Queue stagnation (Gate 4 containment) |
| Observation count | Morning routine | Unaddressed system friction signals |

Every morning routine includes a jibrain status pulse: intake queue size,
pending observations count, days since last triage, atlas size and growth. This
prevents the most common knowledge system failure: gradual abandonment.

---

## Search Infrastructure: Three-Mode Discovery

The vault is indexed by a local search service (QMD) that provides three
complementary search modes over its indexed collections (~11,000 documents across two named indexes).

| Mode | Method | Best For |
|------|--------|----------|
| **Keyword** | Exact word/phrase matching | Known terms, specific names, precise queries |
| **Vector** | Embedding-based similarity | Conceptual search, synonyms, "find related ideas" |
| **Deep** | Query expansion + hybrid + reranking | Open-ended exploration, "what do we know about X?" |

### Why Three Modes

No single search mode works for all knowledge retrieval tasks:

| Task | Best Mode | Why |
|------|-----------|-----|
| "Find the file about Sen Rikyu" | Keyword | Exact name match |
| "What do we know about simplicity in aesthetics?" | Vector | Concept may appear as wabi, restraint, reduction |
| "Zen and practice" | Deep | Expands into related terms, searches both ways, reranks |

Keyword search is fast and precise but brittle -- it misses paraphrases.
Vector search handles meaning but can drift on ambiguous queries. Deep search
combines both with automatic query expansion, at the cost of more computation.

### Collection Segmentation

The service is partitioned into two named indexes, each with collections
matching the vault's containment boundaries (live counts, 2026-07-13):

| Index | Collection | Docs | Contains |
|-------|------------|------|----------|
| knowledge | jibrain | ~4,800 | Knowledge base — atlas, domains, intake queue |
| knowledge | organizations | ~1,100 | Organization entities |
| knowledge | agents, references, concepts | ~500 | Agent docs and reference material |
| pim | people | ~1,200 | Contact profiles (private) |
| pim | dailynote | ~1,100 | Daily notes (temporal, operational) |
| pim | private collections | ~2,400 | Confidential and meeting material (never leaves the private index) |

Agents can scope searches to an index or a single collection. This prevents
temporal content (daily notes) from polluting knowledge searches, and keeps
private material in a physically separate index — the same containment
principle that governs the directory structure. (An earlier version of this
document claimed ~14,700 docs in the jibrain collection; that number was read
from a stale default index. The vault has ~26,700 files; the search service
indexes the ~11,000 that matter for retrieval.)

### Agent Search Patterns

For agents operating on the vault, the recommended search strategy:

1. **Start with keyword** when you have specific terms (person names, concept
   titles, exact phrases). Fastest, most precise.
2. **Use vector** when exploring a concept space ("find notes related to
   decentralized governance"). Handles vocabulary mismatch across languages
   and terminology.
3. **Use deep** for broad investigation ("what does the vault contain about
   the relationship between technology and democracy?"). Most thorough,
   highest token cost.

The `description` field in frontmatter is indexed alongside full content,
making filter-before-read work across all three modes. Results include
relevance scores and document IDs, so agents can retrieve full content
selectively rather than reading everything.

### What This Changed

Previously, discovery was limited to wikilink traversal and grep-style text
search. This worked for navigation (following known connections) but failed
for discovery (finding unknown connections). Semantic search closes this gap:
an agent running reweave can now find conceptually related files that share
no common vocabulary. A query about "aesthetic minimalism" will surface files
about wabi even if the word "minimalism" never appears in them.

This also affects multi-language content. The vault contains files in English,
Japanese, and occasionally French. Vector search handles cross-lingual
similarity in ways that keyword search cannot.

---

## Contact Intelligence: Entity Resolution and People Graph

The vault's people knowledge is not hand-curated -- it is produced by a
pipeline that merges contact records from multiple sources, resolves
duplicates via probabilistic graph matching, and cross-links the result
into the vault's wikilink graph.

### Entity Resolution (Senzing)

Contact records arrive from 7 sources: Apple Contacts, Google Contacts,
CRM exports, vault contact pages, organization records, meeting
transcripts, and daily note mentions. Raw record count: ~53K. The same
person typically appears as 3--11 separate records across these systems
(different email addresses, name variants, organizational affiliations).

The Senzing SDK performs probabilistic entity resolution -- graph-based
merging that clusters records into unified entities without requiring
exact field matches. It handles transliterations, name reordering,
email domain changes, and organizational moves. The result: ~37K unified
entities from ~53K raw records.

Senzing runs in a PostgreSQL Docker container. Resolution is a batch
process, not a real-time service. Output is a mapping from source records
to canonical entity IDs, which the cross-linking pipeline consumes.

### Seven-Pass Cross-Linking Pipeline

A sequential pipeline of idempotent passes that wires the people graph
into the vault's wikilink structure. Each pass reads existing state and
writes only net-new links, so the full pipeline can run repeatedly without
duplication.

| Pass | Operation |
|------|-----------|
| 1--2 | People pages → organization wikilinks; create organization pages with backlinks |
| 3--4 | Daily notes → person and organization wikilinks (with Japanese honorific handling: `-san`, `-sensei`, `-sama`) |
| 5 | Bidirectional concept ↔ people ↔ organization cross-links |
| 6 | Create stub pages for orphan wikilinks (mentioned but not yet created) |
| 7 | First-name disambiguation using meeting context scoring (30-line window around mentions, organization overlap weighting) |

The pipeline runs as a single `crosslink_all.sh` script. Triggered weekly
during maintenance for the full vault and daily during morning sync for
the current year's daily notes. QMD reindexes after every pass so new
links are immediately searchable.

The result is a four-way graph: people ↔ organizations ↔ concepts ↔ daily
notes. An agent querying "who works on X?" can follow wikilinks from a
concept page to people pages to organization pages -- all produced
automatically from raw contact data and meeting transcripts.

### People Vault

~1,200 contact pages in `people/`. Each page uses a structured frontmatter
schema:

```yaml
---
type: person
name: "Display Name"
description: "Role at Organization; relationship context"  # min 30 chars
aliases: ["Name Variant", "ニックネーム"]
emails: []
organizations: []
links:
  linkedin: https://...
  twitter: https://...
  web: https://...
  wikipedia: https://...
nyne_status: enriched | pending | skipped
senzing_entity_id: 12345
senzing_sources: ["apple_contacts", "google_contacts", "crm"]
---
```

The `description` field follows the same contract as the rest of the vault:
minimum 30 characters, pattern "Role at Organization; relationship context."
This enables filter-before-read across the people collection.

### People Recipes

Three-stage lifecycle managed as Amplifier recipe workflows:

**`people-harvest`** -- Extract and build. Scans daily notes for person
wikilinks, creates stub pages, runs Senzing entity resolution (merges
emails, organizations, aliases from all sources), then enriches via the
Nyne API. Nyne enrichment is tiered by data quality: email match (highest
confidence) → LinkedIn URL match → name search (lowest confidence).

**`people-enrich`** -- Iterative improvement. Re-enriches flagged pages
where initial data was incomplete. Pulls Wikipedia bios for public figures.
Updates organizational affiliations from fresh CRM and contact exports.

**`people-review`** -- Network health. Identifies stale contacts (not
referenced in daily notes for 90+ days), orphaned pages (no incoming
links), and reconnection candidates. Feeds into the GTD weekly review
as a people-specific health check.

---

## Team-Facing Knowledge Interface (Onyx)

A vault of 26,700+ files is powerful for the owner but opaque to collaborators.
When a partner organization needed searchable, browsable access to relevant
knowledge subsets, we deployed **Onyx** -- an open-source RAG + chat platform
(YC W24, formerly Danswer) -- as a team-facing projection of the vault.

The key constraint: the vault is the source of truth. Onyx is a **read-only
projection**, not a second brain. Knowledge flows one direction: vault → Onyx.
The team searches and chats against a curated subset. They never touch the
vault directly.

### Architecture: Vault Projection

```
jibrain vault (~16,000 files)
    │
    ▼
Projection Pipeline (Python)
    ├── Scan markdown files
    ├── Parse frontmatter
    ├── Normalize types
    ├── Sensitivity filter (skip confidential/restricted, >1MB)
    │
    ▼
Staged Corpus (filtered subset)
    │
    ▼
Onyx File Upload Connector
    │
    ▼
Team search + chat interface
```

The **projection pipeline** is a Python script that walks the vault, parses
YAML frontmatter, and applies a sensitivity filter. Files marked confidential
or restricted in frontmatter are excluded. Files over 1MB are excluded (binary
artifacts that leaked into markdown directories). The output is a staged corpus
directory ready for upload.

⚠️ The corpus refresh is currently manual (`gcloud scp` to the VM, then
re-upload via the admin UI). Automating this is the single highest-priority
improvement for this subsystem.

### Why Onyx

We evaluated several open-source RAG platforms. Onyx won on three criteria:

| Criterion | Onyx | Alternatives |
|-----------|------|-------------|
| Deployment model | Self-hosted Docker Compose | Many require managed cloud |
| Customization without forking | Env vars + admin UI | Most require code changes for auth/LLM config |
| Chat + search in one interface | Native | Often separate tools bolted together |

**Zero-fork strategy**: we run vanilla upstream Onyx. All configuration is
through environment variables and the admin panel. No custom code in the Onyx
deployment itself. This means upstream updates are a `docker compose pull`
away -- no merge conflicts, no drift from mainline.

### Deployment

Docker Compose with ~12 containers:

| Container | Role |
|-----------|------|
| Onyx web + API | Frontend and REST API |
| Vespa | Vector search + document store |
| PostgreSQL | User data, connector config, chat history |
| Model server | Embedding model for document indexing |
| Background workers | Connector sync, indexing pipeline |

Infrastructure:

| Resource | Spec |
|----------|------|
| VM | GCP, 4 vCPU, 16 GB RAM, 200 GB SSD |
| Monthly cost | ~$131 |
| IaC | 3 scripts: provision, setup, corpus preparation |
| Firewall | HTTP/HTTPS + Onyx port only |
| Auth | Google OAuth SSO for team members |
| LLM | Anthropic Claude (configurable per agent) |
| Primary connector | File Upload (planned: Slack, Google Drive, web scraper) |

### Custom Agents

Onyx supports **custom AI agents** -- system prompts that shape how the LLM
responds when chatting against the indexed corpus. We configure these through
the admin panel. The prompt markdown is stored in the code repo (`agents/*.md`),
not in the vault -- agent prompts are deployment config, not knowledge.

| Agent | Purpose |
|-------|---------|
| Knowledge assistant | Cross-references people and organizations, cites document sources, flags stale information |
| Domain-specific project analyst | Focused on a particular project domain, references relevant document types and technical/financial data |

Agents are cheap to create and iterate on. The system prompt is the only
configuration -- Onyx handles retrieval, citation, and conversation management.

### Multi-Interface Envelope Pattern

Onyx is not the only team-facing interface. It is one of four channels feeding
into a **NormalizedEnvelope** pattern (described in
[multi-interface-knowledge-layer.md](/learnings/multi-interface-knowledge-layer.md)):

```
Onyx ──────┐
Chat bot ──┤
Slack ─────┤──▶ NormalizedEnvelope ──▶ Policy Engine ──▶ Actions
Email ─────┘
```

Each interface has its own normalizer that maps raw events into a common
envelope schema. Everything downstream operates on envelopes, not on
interface-specific payloads. This matters because:

- **Cross-interface identity resolution** maps all user handles (Onyx login,
  Slack handle, email address, chat bot ID) to canonical actor IDs
- **Policy engine runs on envelopes**, not on raw interface events -- access
  control, approval workflows, and audit trails are interface-agnostic
- **Pydantic schemas** define the envelope contract; policy rules are pure
  functions over those schemas
- **File-backed YAML** for approvals and audit logs (no database dependency,
  git-trackable, portable)
- **Dedup via SHA-256 fingerprint** prevents duplicate processing when the same
  request arrives through multiple channels

Adding a new interface (e.g., a WhatsApp bot) requires writing one normalizer.
The policy engine, audit trail, and action handlers don't change.

### What Worked

1. **Zero-fork strategy** -- upstream Onyx updates apply cleanly because we
   never patched the source. This is the single most important deployment
   decision.
2. **Vault projection with sensitivity filter** -- confidential content stays
   out of the team-facing interface by construction, not by policy compliance.
   The filter runs before upload, not at query time.
3. **Pydantic + pure-function policy engine** -- access control logic is
   testable, auditable, and independent of any specific interface. No ORM, no
   database migrations, no framework magic.
4. **Multi-channel envelope pattern** -- normalizing all interfaces to a common
   format meant the second interface was nearly free to add, and the third was
   trivial.
5. **File-backed audit** -- YAML files in a git repo beat a database for
   compliance review and portability. Every approval decision is a commit.

### What We'd Do Differently

1. **Automate corpus refresh from day one** -- manual `gcloud scp` is the
   bottleneck. Every time vault knowledge updates, there's a human-in-the-loop
   delay before the team sees it. This should be a cron job or a webhook
   triggered by vault sync.
2. **Script Onyx admin setup via API** -- the admin panel is convenient for
   iteration but not reproducible. Agent configs, connector settings, and user
   permissions should be API-driven for disaster recovery and environment
   parity.
3. **Start with the Slack connector** -- team adoption is faster when discovery
   happens in tools people already use. File upload was technically simpler but
   required the team to learn a new interface. Meet users where they are.

---

## Implementation Checklist

If you're building a similar system, implement in this order:

1. **Three-tier directory structure** (intake / permanent / deep domains)
2. **Frontmatter schema with `description` field** (single highest-ROI change)
3. **Routing decision tree** (documented, not ad-hoc)
4. **Triage process** (intake is a queue, not a dump)
5. **Health monitoring** (orphans, broken links, stale content)
6. **Reweave pass** (backward enrichment after promotion)
7. **Observations mechanism** (capture system friction signals)
8. **Pipeline health checks** (pipeline completeness check)
9. **Currency tracking** (`last_verified` for time-sensitive content)
10. **Agent workspace boundaries** (no single agent can corrupt the whole)
11. **Multi-machine sync with containment** (different machines get different subsets)
12. **Task system integration** (knowledge connected to action)
13. **Domain graduation** (when topics hit critical mass, give them structure)
14. **Search infrastructure** (keyword + vector + deep search over indexed collections)
15. **Contact intelligence** (entity resolution across data sources, people graph cross-linking)
16. **Operational control plane** (event ledger, manifest validation, cross-machine dispatch)
17. **Continuous improvement review** (scan all agent runtimes for patterns, tool failures, iteration spirals)

Items 1-5 give you 80% of the value. Items 6-17 compound over time.

---

## Recent Additions (2026-04-12)

Capabilities added since the original document was written:

- **Contact intelligence pipeline**: Senzing entity resolution merging ~53K contact records into ~37K unified entities, seven-pass cross-linking pipeline, Nyne API enrichment, and three-stage people lifecycle recipes. See [Contact Intelligence](#contact-intelligence-entity-resolution-and-people-graph) above.

- **Amplifier bundle system matured**: `amplifier-bundle-joi` now contains 18+ tool modules covering home automation, productivity (GTD, beads, email), knowledge (QMD, vault), communications (imessage), media (imagen, kimono), research (academic_search, nyne), and more. Multi-provider routing across Anthropic, OpenAI, and Google. Recipe workflows for all major pipelines.

- **Model routing quality matrix**: Provider routing across Claude Opus / GPT / Gemini Pro variants with role-based assignment (coding, reasoning, creative, writing, fast, etc.). 80%+ cost reduction vs single-model-for-everything.

- **Talk pipeline**: `talk-builder`, `talk-refresh`, `talk-to-gamma`, `talk-to-slides` recipes. Full workflow from research brief → outline → draft → Gamma presentation → Google Slides export. Operates on `agents/writer/drafts/`.

- **Meeting pipeline**: muesli sync with Japanese translation (whisper → translation → vault), `meeting-extract` recipe for concept/entity extraction, daily note injection for meeting summaries.

- **Design intelligence**: Component design, layout strategy, responsive patterns, animation, voice agent design — available as skill-guided workflows in Amplifier sessions.

- **bookmark-extractor sprite DEPRECATED**: Replaced by the knowledge-intake sprite. All URL intake routes through the knowledge-intake sprite.

- **Team-facing Onyx deployment**: Full section added to this document. See [Team-Facing Knowledge Interface](#team-facing-knowledge-interface-onyx) above and companion [onyx-rag-deployment.md](/learnings/onyx-rag-deployment.md).

- **Knowledge provenance log**: Append-only audit trail at `ops/knowledge-log.md`. The knowledge-intake sprite, meeting-extract, and session-capture recipes all append structured entries tracking what entered the vault, when, from where, and what files were touched. Concretizes Gate 3 (Materia).

- **Contradiction detection in reweave**: Step 2b added to the reweave algorithm. Uses QMD semantic search to find atlas files making conflicting claims about the same entities. Writes `category: contradiction` observation files for human review. Closes the gap between the observation system (which defined contradictions as a category) and automated detection.

- **Session-to-knowledge capture**: `capture-to-jibrain` recipe extracts insights from Amplifier conversations as jibrain intake files. Classifies content type, checks for duplicates via QMD, writes proper frontmatter. Implements the "file query answers back into the wiki" pattern.

- **Type-specific extraction depth**: Knowledge-intake sprite now classifies sources by word count and URL pattern before extraction. Four tiers: shallow (<500 words), standard (500-2500), standard-plus (2500-5000), deep (>5000 words, arxiv papers). Deep sources get enriched prompts for section-by-section extraction.

- **Chapter-level book extraction**: `book-ingest` recipe processes PDFs chapter-by-chapter. Three stages: chapter detection (PyMuPDF TOC parsing), per-chapter entity extraction with atlas page updates, and book-level synthesis with cross-chapter theme analysis. Key design: chapters UPDATE existing atlas pages rather than only creating intake files.

- **Joi gist presence**: Learnings and idea files published as GitHub Gists at [github.com/Joi](https://gist.github.com/Joi) in Joi's voice, separate from Jibot's emissions.

- **opsctl control plane**: Rust CLI and event-ledger substrate deployed for operational infrastructure. Per-zone append-only ledgers, YAML manifest validation (JSON Schema), claim review/approve/reject flows, cross-machine dispatch tracking, markdown operational projections, Supabase redacted projector with pseudonyms, spool transport for cross-machine event delivery, and task supervisor with retries. Integrated into morning routine. 5 crates, 79 tests. See [Operational Control Plane](#operational-control-plane-opsctl) above.

- **Continuous improvement review (`opsctl review`)**: Seven-subcommand system scanning all agent runtimes (Amplifier, Claude Code, NanoClaw) plus skill telemetry, git history, and beads issues. Surfaces tool error rates, iteration spirals, repo churn, stale issues, and skill usage gaps. NanoClaw scanning runs remotely via SSH. Combined `review summary` generates markdown reports and emits ledger events. Integrated into weekly-review-maintenance recipe. ~2,400 lines of Rust.

---

## Recent Additions (2026-05-01)

The big shift in this window is that the agent-stack memory + learning loop finally
has a substrate underneath it — opsctl in production, and beads at 1.0.

- **opsctl + bd 1.0 = a working continuous-learning loop.** Five Amplifier hooks
  (`skill-telemetry`, `beads-logger`, `feature-capture`, `deferral-detector`,
  `debug-detector`) now dispatch session-time signals through one helper into the
  opsctl ledger. The night-time learning extractor — formerly a 568-line Python
  script — became a native Rust subcommand (`opsctl review nightly`) that writes a
  daily P0/P1 digest the morning routine surfaces. Beads at 1.0 (graph-link types:
  `blocks`, `tracks`, `parent-child`, `discovered-from`, `caused-by`, `validates`,
  `relates-to`, `supersedes`; defer-with-time-spec; debounced auto-export) is
  finally robust enough to be the durable side of that loop, with auto-export hooks
  installed at the bundle level so issues stay coherent across the fleet of repos.

- **opsctl hardened in production.** Eleven-item `opsctl-dqj` epic over 24 hours:
  small correctness fixes (`dispatch confirm`, `validate --only`, `repo sync --json`);
  a new ledger query verb (`opsctl query`); consolidation of two long-running Python
  scripts into Rust subcommands (`opsctl review nightly`, `opsctl repo health`);
  migration of two production LaunchAgents to `opsctl supervise`. Test count: 79 → 200+.

- **NanoClaw container hardening (CVE-2026-31431).** Three-layer defense added to
  NanoClaw's container spawn: fail-closed seccomp blocking AF_ALG/AF_VSOCK; setuid
  binary stripping from the agent image; `--cap-drop ALL` on container creation.
  Sits on pre-existing `no-new-privileges`, read-only rootfs, tmpfs scratch.

- **Channels and identity.** NanoClaw gained a first-class Email channel (identity
  resolver, intent classifier, tiered policy adapter, calendar adapter via `gog`,
  reminder adapter via EventKit, Signal-mediated approval gate) and a LINE
  channel — channel count is now seven (Signal, WhatsApp, Telegram, Slack, Discord,
  Email, LINE). Slack handle resolution moved to a multi-alias identity index.
  Listening simplified from four modes to three plus a moderation layer. NanoClaw
  now detects self-registration intent and stages claim YAMLs for human approval.

- **Per-user workstream enforcement.** Each chat room has an access-tier "floor"
  that selects which QMD MCP corpus and container-folder template to use. NanoClaw
  resolves per-user permitted-workstream scope at message time and injects it as
  container env vars, gated by an allowlist with explicit user and group schemas.
  A nightly access-audit script verifies drift against Slack membership and Drive
  permissions, and DMs alerts on divergence.

- **Voice + Zoom.** The voice agent's HTTP surface was generalized into `agent-api`
  (port 3200) with `/api/join` as a forwarding endpoint for a Zoom-bot orchestrator
  (custom Python bot, Deepgram streaming STT, ambient summary posting, TTS replies
  on wake-phrase, calendar-invite or Signal-command join). The voice agent itself
  sits behind Cloudflare Access.

- **Storage and intake.** A new on-NVMe storage tier (`largestore`) replaced a
  302-line bash script with a YAML-driven binary-asset CLI; rclone VFS mounts of
  remote Drives gained NVMe-backed cache (~130× hot-read speedup). The intake
  pipeline gained an LLM-driven action-extraction stage with retry, chunking,
  duplicate scoring, and an approval gate. A bidirectional Drive ↔ vault sync
  pattern (publisher with GENERATED-FILE banner and commenter-only domain-scoped
  permissions; comment-ingestion as receipt docs) is used for team distribution of
  curated knowledge.

- **Operational hygiene.** msgvault productionized with daily/weekly launchd jobs
  and an MCP server registration. Backup stabilized on Arq + S3 with NVMe-passphrase
  DR documented and credentials migrated into Kura. Watchdogs (signal-cli zombie
  reaper, NanoClaw service watchdog) added as launchd jobs. The Baileys WhatsApp
  transport hardened to address chronic 405 rejections. The morning routine was
  redesigned as the terminal action surface, deprecating the GTD Dashboard.

## Recent Additions (2026-06-07)

The headline shift this window: the agent gateway was re-architected, the task tracker was
swapped wholesale, and a persistent cloud-VM tier joined the fleet.

- **Gateway re-architecture: NanoClaw → Hermes (dual-gateway system).** The agent fleet
  moved from NanoClaw (Node/TypeScript, per-group hardened Docker containers) to **Hermes** —
  a single Python gateway on the Mac mini, organized into ~12 per-identity **profiles**, each
  with its own channel bindings, memory, skills, and cron. Hermes has native adapters for
  Signal, Telegram, Discord, Slack, WhatsApp, LINE, iMessage, and email (Signal wired
  directly), plus `hermesd` — a scoped HTTP endpoint exposed through a Cloudflare tunnel for
  authenticated remote calls into a sandboxed profile. *(hermesd and its bridge were
  decommissioned 2026-07-07; the tunnel now carries only the search and agent endpoints.)*
  NanoClaw did not disappear: it runs in
  stable production on a dedicated **exe.dev** cloud VM (`nanoclaw-server`) as the
  messaging/capture tier that feeds Hermes. (Before the Hermes rewrite, NanoClaw itself went
  through a v1→v2 Chat-SDK rewrite and a seven-channel expansion in May.) "Profiles as the
  unit of identity and zoning" is the same containment principle the vault uses, applied to
  agent personas.

- **beads → kata: task tracker swapped fleet-wide.** The dev issue tracker (beads) was
  deprecated and removed from every repo and replaced by **kata** — a daemon-backed,
  federated, cross-platform tracker with stable ULID identity, JSONL export/import, and a
  shared multi-project ledger. Its signal/observation companion, **jilog**, was extracted
  into its own repo: a nightly learning extractor with multi-harness session readers
  (Amplifier, Claude Code, Codex, Copilot) over an append-only event ledger. The
  continuous-learning loop and morning routine were repointed from beads to kata.

- **A persistent cloud-VM tier (exe.dev).** Alongside the existing sprites.dev microVM tier,
  the fleet added **exe.dev** VMs — always-on Linux VMs reachable over a private mesh network
  (ZeroTier). The **kata daemon** was migrated off a local host onto a dedicated exe.dev VM
  (`kata-server`) so every machine reaches the shared ledger as a local private address — at
  home or traveling. NanoClaw's messaging gateway runs on a second exe.dev VM
  (`nanoclaw-server`). Two reusable infrastructure lessons came out of the move: an
  outbound-firewall rule pinned to a binary hash broke on every rebuild (fixed by matching on
  path, not hash), and a host OS's local-network privacy gate blocked direct mesh connections
  from headless agent contexts (fixed with a loopback SSH tunnel).

- **Two-tier fleet + the Active-Mac primitive.** A cloud sprint moved always-on, stateless
  jobs (news scanning, nightly email drafts, the learning digest) onto managed cloud
  containers (GCP Cloud Run), while vault-touching services stay on a Mac. An **Active-Mac**
  file-flag primitive (replicated via Syncthing) lets those Mac-pinned LaunchAgents follow the
  operator across machines automatically — used to fail services over to a standby Mac during
  three weeks of travel, then back again, with no manual reconfiguration.

- **news-scan: a personalized intake-to-briefing pipeline.** A new multi-stage pipeline pulls
  from RSS / Hacker News / arXiv, dedups and canonicalizes URLs, scores each item against the
  knowledge graph (QMD) with weighted heuristics, refines the top set with an LLM, and
  generates a morning brief — scheduled through `opsctl supervise`. It surfaces in a new
  **command-dashboard**: a local-HTML morning briefing aggregating intake, knowledge, dev,
  news headlines, birthdays, and health into one clickable read surface over the whole stack.

- **GEPA prompt optimization in production.** Automated prompt optimization (GEPA) was run
  against several production prompts and the improved versions deployed: jibrain AI-triage
  classification accuracy rose from 0.62 to 0.89 (+44%), with further gains on meeting
  summarization and email-draft style matching. Prompt quality is now a measured, tunable
  artifact, not a hand-written constant.

- **A firewalled enterprise persona (`jibot@gidc.bt`).** A dedicated bundle gives the
  enterprise identity tier-gated email (draft vs. send; never auto-sends externally), calendar
  and task tools, and path-firewalled intake writes — built test-first, with a CI lint
  enforcing bundle isolation. It runs as its own Hermes profile.

- **Model + provider.** The default model moved to **Claude Opus 4.8**, and the Anthropic
  provider module gained proper token streaming and per-call cost telemetry (every response
  stamped with its cost), feeding a cost-report CLI.

- **Knowledge-pipeline reliability.** Several silent failures were caught and fixed: a broken
  silent-mode→intake path (restored ~50 intake files/day), a YAML-terminator bug that had
  corrupted ~150 archive files, and a drive-sync timeout that had silently aborted the publish
  step for three weeks. The synthesis gate now downgrades failing files in-place with
  transparent reasons instead of silently archiving them. The Onyx team interface's Drive
  connector was replaced by a simpler Syncthing-based projection path.

- **People intelligence.** A live Senzing MCP server now answers entity-resolution queries
  interactively, and contact enrichment/dedup gained a CRM (Affinity) source.

## Recent Additions (2026-06-30)

This window was about getting the fleet's routing model right, and writing down what it
cost to learn.

- **Routing reconciliation, and a rule.** A multi-hour debug on 2026-06-30 traced back to
  trusting a stale NanoClaw database row over the running system. The lesson is a diagnostic
  rule: which profile or agent handles a given chat is reliably knowable only from the live
  system — a profile's `channel_directory.json` plus its gateway log — never from a database
  row, a skill note, or a CLAUDE.md. Those are hypotheses to verify. The row that caused the
  debug was a Signal group for Joi's own number, vestigial since Signal moved to Hermes; the
  live directory had the correct answer the whole time.

- **Signal runs on a single Hermes profile.** *(Superseded within days: on 2026-07-06
  the intimate Signal surface moved to the pinned `signal-intimate` gateway, and on 2026-07-09
  the community cohort moved to its own cell with a dedicated number — see Recent Additions
  2026-07-13.)* Joi's personal Signal DM and his whole
  Signal cohort — two contacts and a community group — were served by one
  Hermes profile, the sole Signal consumer. One signal-cli account binds to one profile, so a
  second profile on Signal would need a second linked device.

- **Per-chat prompts (`channel_prompts`).** A single profile can present a different prompt
  per chat through a `channel_prompts` map in its config, so one profile addresses
  Joi's DM, an individual contact, and a group differently while sharing one identity, memory,
  and skill set. Signal needed a code patch to honor this: its platform adapter never called
  the prompt resolver, so every Signal chat had collapsed to the profile default.

- **The two-node fleet, written down.** The canonical internal architecture reference was
  brought current. NanoClaw on the exe.dev VM is the public-surface messaging and capture tier,
  with agent containers running locally on the VM, and it feeds Hermes on the mini. Hermes runs
  the private and working surfaces natively across ~15 per-identity profiles. On the mini,
  NanoClaw is fully retired.

## Recent Additions (2026-07-13)

The window since 2026-06-30 was the cell migration: the public side of the fleet moved
from one shared VM to per-trust-tier cells, and the legacy VM was deleted.

- **The cell fleet: trust-tier isolation as infrastructure.** Six single-tier cloud VMs
  ("cells"), one per trust tier — trusted Slack workspaces; public Slack + all Discord;
  enterprise Slack; the general jibot identity (LINE + WhatsApp); a community Signal cohort
  on its own number; and a staging cell. Each is minted from a common template repo (pinned
  upstream NanoClaw + a small extension overlay + patch queue), so a cell is reproducible
  rather than hand-built. Every upgrade rolls through the staging cell before production.
  Each cell has its own scoped model API key, and all model egress goes through a gateway
  that injects secrets at the edge — agent containers never hold tokens. Blast radius is
  bounded by construction, not by policy.

- **Legacy VM decommissioned (2026-07-08).** The shared NanoClaw VM's last surface
  (WhatsApp) moved to a cell by session transplant — no re-pairing, a roughly five-minute
  gap. Lessons from the deletion, written down: read a tunnel's full ingress before
  decommissioning its host (ours also carried the search and agent endpoints); close
  session rows so resident containers actually die; snapshot SQLite with `.backup`, never
  `cp`, when write-ahead logging is in play.

- **Access doctrine: channel presence = permission.** On the migrated community surfaces,
  membership in a channel is the authorization to interact with the agent in it; explicit
  approval flows remain for DMs. This replaced a per-sender approval model that did not
  survive contact with multi-workspace reality.

- **Intimate gateways pinned.** Joi's email, iMessage, and Signal gateways moved to a
  version-pinned Hermes checkout with a documented pin-bump runbook; upgrades roll
  staging-first. The remote-bridge era ended: `hermesd` and its bridge were deleted once
  every surface ran natively somewhere.

- **Bookmark pipeline revived end-to-end.** X bookmarks are harvested daily via OAuth2
  (the rotating refresh token is persisted atomically under a lock — X rotates it on every
  use, and losing one breaks the chain), flow through the knowledge-intake sprite into
  vault intake, and get triaged by the heartbeat. Landing this surfaced two silent
  failures: the sprite hibernated within seconds of idle (killing its sync side for
  months), and an intake channel had been retired mid-refactor with nothing ingesting for
  three months. The intake channel is restored; the hibernation has an interim hold-awake
  protection while a durable fix is tracked. The lane now reports into the morning brief, a status
  dashboard, and the daily health check, under an explicit machine-readable monitor
  contract per lane — display prose is never parsed.

- **Fleet observability.** A fleet-map dashboard aggregates the cells, the Macs, and the
  ledger VM into one view; a daily multi-module health check and cross-machine
  environment-snapshot drift detection catch decay; ops alerts deliver over messaging.

- **Models.** The highest-trust agents now run on the Claude 5 frontier tier; model choice
  is per-agent configuration on the cells rather than a global default.

## What We Don't Have Yet

- **Adversarial verification**: Partially addressed by contradiction detection
  (catches conflicting claims between files), but we don't yet deliberately
  try to break the system (e.g., "what if an agent hallucinated a fake entity?"
  or "what if a source is unreliable?"). Confidence scoring on claims remains unbuilt.
  A "contrarian loop" is now in planning — explicit `claim`/`assumption` frontmatter on
  claim-bearing notes, plus scheduled steelman and premise-collision passes whose outputs
  land in the observations queue for human review.
- **Confidence decay**: Knowledge doesn't automatically become less trusted
  over time. `last_verified` is a manual check, not a decay function.
- **Cross-vault federation**: Single-user. No mechanism for merging knowledge
  graphs across people or organizations.
- **jibot cron**: Mostly implemented. The jibrain heartbeat (15-minute
  automated triage cycle), morning routine (daily health checks), weekly
  `opsctl review` (operational telemetry analysis), and the news-scan →
  morning-brief pipeline (proactive daily summaries) cover periodic
  maintenance and proactive surfacing. Context-aware, jibot-initiated
  follow-ups (noticing something and reaching out unprompted) remain unbuilt.
- **Source attribution/compensation**: We track provenance but don't address
  the ethical question of compensating original sources.

---

## Credits and Influences

- **Obsidian** (obsidian.md): The substrate -- markdown, wikilinks, graph view
- **GTD** (David Allen): The action methodology integrated with knowledge
- **Ars Contexta** (arscontexta.com): Description fields, routing trees, the reweave concept (adapted from their "6 Rs pipeline")
- **Fred** (OpenClaw): iblai-router for intelligent LLM routing, cross-pollination experiment demonstrating bot-to-bot knowledge
  transfer
- **sprites.dev**: Cloud microVM infrastructure (Firecracker) for the knowledge-intake sprite
- **Syncthing**: Peer-to-peer sync that respects containment boundaries **Amplifier** (github.com/microsoft/amplifier): The multi-agent framework that operates the system
- **Senzing** (senzing.com): Entity resolution SDK for probabilistic graph-based record merging across contact data sources
- **Nyne** (nyne.ai): People enrichment API providing professional profiles, organizational data, and contact intelligence
- **QMD**: Local search index providing keyword, vector, and deep search over the vault's markdown collections
- **Hermes**: The profile-based Python agent gateway that replaced NanoClaw on the Mac mini
- **kata**: Daemon-backed, federated task tracker that replaced beads across the fleet; **jilog** is its signal/nightly-learning companion
- **exe.dev**: Persistent cloud-VM hosting (over a private mesh network) for the kata daemon and the NanoClaw messaging gateway
- **GEPA**: Automated prompt optimization — turned several production prompts into measured, tunable artifacts
- **Karpathy** (LLM Wiki gist): The "compilation over retrieval" framing and the lint operation concept -- knowledge maintenance deserves as much design attention as knowledge ingestion
- **opsctl**: Built as a learning-Rust project with Amplifier agent assistance. The four-plane separation (intent/event/projection/action) and "segments are authority, everything else rebuilds" principle emerged from the build brief's constraint that no generated file should be treated as manually editable authority. The review subsystem (~2,400 lines) was built in a single Amplifier session -- 7 subcommands, 3 agent runtimes, remote SSH scanning -- demonstrating the viability of agent-assisted Rust development at scale

---

*This document describes a system in active daily use. It is opinionated,
battle-tested, and incomplete. If you build on these patterns, the most
important thing to get right is the routing decision tree and the description
field. Everything else follows from those two.*

---

*[Back to learnings](/learnings/index.md) · [Back to the front page](/index.md)*
