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.
Generate a prioritized action report: high-value links to add
Bridge links: Connect previously unconnected clusters (highest value)
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):
agents/curator/extractions/andjibot-docs/outbox/tointake/intake/via Syncthing (no collection step needed)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:
~/scripts/jibrain-heartbeat.shโ collection and dispatch~/scripts/jibrain-triage.pyโ triage logic and auto-promote gatescom.amplifier.jibrain-heartbeat(every 900 seconds)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.
File-backed audit-- YAML files in a git repo beat a database for compliance review and portability. Every approval decision is a commit.
Automate corpus refresh from day one-- manual- gcloud scpis 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.
If you're building a similar system, implement in this order:
descriptionfieldlast_verifiedfor time-sensitive content)Items 1-5 give you 80% of the value. Items 6-14 compound over time.
Capabilities added since the original document was written:
amplifier-bundle-joinow 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.talk-builder,talk-refresh,talk-to-gamma,talk-to-slidesrecipes. Full workflow from research brief โ outline โ draft โ Gamma presentation โ Google Slides export. Operates onagents/writer/drafts/.people-harvest(extract contacts from daily notes),people-enrich(Nyne API enrichment),people-review(network health review). People profiles inatlas/people/are now systematically maintained.meeting-extractrecipe for concept/entity extraction, daily note injection for meeting summaries.intake-XXXXX.sprites.example). The bookmark-extractor FastAPI sprite on sprites.app is no longer active. All URL intake routes through the knowledge-intake sprite.Team-facing Onyx deployment: Deployed Onyx (open-source RAG platform) as a read-only projection of the vault for a partner organization. Zero-fork strategy (vanilla upstream, all config via env vars + admin UI). Vault projection pipeline with sensitivity filter, multi-channel envelope pattern (Onyx + chat bot + Slack + email), file-backed governance (approvals, audit, revisions). See the new section in this document and the companion onyx-rag-deployment.md.
Agent identity persistence: Designed but not built. Agents currently start fresh each session. State files spec exists but no implementation.
last_verifiedis a manual check, not a decay function.Source attribution/compensation: We track provenance but don't address the ethical question of compensating original sources.
Obsidian(obsidian.md): The substrate -- markdown, wikilinks, graph view
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.