Raw capture โ€” raw/jibrain-knowledge-architecture.md


url: https://github.com/Joi/ai-agent-learnings/blob/main/architecture.md date_fetched: 2026-07-05 backfilled: true


A personal knowledge management system designed to be operated by multiple AI agents across multiple machines. Built on Obsidian (markdown + wikilinks), synced via Syncthing, with ~4,300 indexed files across 3 languages in daily production use 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.

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)

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: draftvsstatus: 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.

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

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.

---
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
agent: curator | meeting-extractor | meeting-prep | manual
---
---
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 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:

Bad:

A vault of 2,400 files is too large to read exhaustively. The description field is the index.

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 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 .stignoreper machine
Queue vs archive Unprocessed intake from processed knowledge Age monitoring (>90 days = stagnation)
Agent workspace Each agent's write boundary Convention + audit
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.

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.

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.

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

---
type: observation
category: gap | contradiction | connection | friction | structural
observed: 2026-02-26
agent: curator
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"

Most knowledge systems only capture what you deliberately put in. Observations capture what the system itself is telling you -- gaps, contradictions, structural decay. These signals are generated as a byproduct of normal agent work and would otherwise be lost.

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

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 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_verifiedfor 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.

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.

Multiple specialized agents operate on the vault, each with explicit workspace boundaries:

Agent Writes To Reads From Purpose
Curator intake/ URLs, web content Extract structured knowledge from bookmarks
Meeting Extractor intake/ Daily notes Pull concepts/entities from meeting summaries
Meeting Prep intake/ atlas/, people/ Generate entity profiles for upcoming meetings
Triage _review/ intake/, atlas/ Review intake queue, generate promotion recommendations
Context Advisor Various Everything Reweave, orient, health checks

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

Agents are session-scoped but can maintain continuity via state files:

---
type: agent-state
agent: curator
last_active: 2026-02-26
session_count: 47
status: active
---

Content includes: last session summary, active investigations, learned patterns (e.g., "news articles produce low-value extractions"), cumulative stats, and open questions. Read at session start, write at session end.

This is not implemented yet -- it's a design we intend to build. Currently agents start fresh each session.

A persistent extraction service runs on a cloud VM (Firecracker microVM via sprites.dev). The knowledge-intake sprite (FastAPI, server.py v0.2.0) 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 Ethoswarm Curator Mind, external agents

Data flow (URL extraction):

Data flow (structured intake):

Knowledge capture happens 24/7, not just during active conversations.

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):

Triage triggers:

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 agent Agent is in trusted list

Trusted agents: deep-meeting-process, meeting-prep, bookmark-extractor, curator

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

Implementation:

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-mac(primary) Full vault, Amplifier, heartbeat Everything Bidirectional
agent-mac(Mac mini) NanoClaw host, jibot agents jibrain/ only Bidirectional
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.

The Ethoswarm persistent agent protocol provides an always-on intake channel via a Switchboard Curator Mind running on Telegram.

Component Status
Curator Mind LIVE โ€”
Intake route POST /intake/structured on knowledge-intake sprite
Sync Syncthing โ†’ intake/ โ†’ heartbeat triage
Daily usage ~1,500 credits/day, ~$0.01/day in SWARM tokens

Phase 1 (basic intake) is operational: Mind receives URLs and text via Telegram, extracts structured knowledge, routes through the sprite, and content appears in intake/ for automated triage.

Phase 2 (bidirectional sync) is in progress: the /intake/structured endpoint is live, but the vault search endpoint (enabling the Mind to check for duplicates before creating intake) is not yet built.

See ethoswarm-switchboard-bridge.md for the full integration specification.

Deployed on NanoClaw 2026-03-04. Origin: built by Colin Raney's bot Fred for OpenClaw, adapted for NanoClaw.

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.

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.

Fred (Colin Raney's 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

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.

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
Beads (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.

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
Seven Gates audit 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.

The vault is indexed by a local search service (QMD) that provides three complementary search modes over the full document collection (~4,300 files).

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?"

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.

The index is partitioned into collections matching the vault's containment boundaries:

Collection Docs Contains
jibrain ~2,400 Knowledge base (intake, atlas, domains)
dailynote ~1,000 Daily notes (temporal, operational)
people ~900 Contact profiles (private)

Agents can scope searches to a single collection. This prevents temporal content (daily notes) from polluting knowledge searches, reinforcing the same containment principle that governs the directory structure.

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

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.

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.

A vault of 4,300+ 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.

jibrain vault (4,300+ 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.

gcloud scp to the VM, then re-upload via the admin UI). Automating this is the single highest-priority improvement for this subsystem.

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.

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)

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.

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):

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:

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

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

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

Capabilities added since the original document was written:

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.