We do not open a CRM, a research wiki, and a build console. We open one chat window and talk to a manager. Behind that manager is an org chart of AI agents: a CRM department, a geo-audit department, a coding department, a research department, each with its own memory, its own task queue, its own signed paper trail, and the ability to staff up temporary help for a busy afternoon. The whole thing lives in a git repo. Clone it, type one passphrase, run one command, and the company is standing again on a fresh laptop.
This post is the architecture and the how-to. Every command, path, and tool name below is real and lives in our repo.
You talk to one agent: the orchestrator. It is the manager. It plans, decomposes, delegates, reviews, and integrates, and it never edits domain code itself. That last rule is load-bearing: the manager stays a clean integrator, so responsibility for any given folder always has exactly one owner.
Under it sit four folder-scoped department heads, each owning one slice of the repo:
you
└─ orchestrator main session plans / delegates / integrates; never edits domain code
├─ crm-engineer L1 subagent owns projects/crm
├─ geo-audit-operator L1 owns projects/geo-audit (pipeline operator)
├─ coder L1 subagent horizontal code (repo minus the product folders)
└─ researcher L1 subagent owns research/, read-only on code
└─ worker L2 leaf one objective, isolated worktree, cannot fan out
These are not vibes. They are declared agent charters in .omp/agents/*.md. The orchestrator's front-matter says exactly what it is allowed to touch:
# .omp/agents/orchestrator.md
name: orchestrator
model: plan
tools: read,search,find,task,todo,bash
spawns: crm-engineer,geo-audit-operator,coder,researcher
Each role maps to a model. The orchestrator runs on a strong reasoning model, the heads on code-strong ones, and we run open weights for all of it.
nano-gpt. A clean way to serve those role models is nano-gpt: pay per prompt, no account, pay with crypto or card, and access to hundreds of models including the open weights we lean on (DeepSeek, Qwen, Kimi, GLM). Prompts are not stored by default, there is an in-browser TEE private mode with receipts you can verify yourself, and it ships a native MCP. It fits a privacy-first agent stack without a subscription.
Each head can fan out ephemeral workers for genuinely parallel work: one worker per rule module, say, each in an isolated worktree with a disjoint file scope. omp enforces a two-level depth cap and blocks self-recursion, so a worker is a leaf. It has no task tool, can read the department database but never write it, and returns a branch plus a short report before it yields. The head merges the worktrees and owns the single authoritative write. Fan-out is opt-in, never automatic, with a soft cap of about five workers. Small work the head just does itself.
Routing is one writer per folder. projects/crm goes to crm-engineer, projects/geo-audit to geo-audit-operator, general code to coder, and "find out or synthesize" to researcher. No two heads ever write the same folder.
Here is the constraint that shapes everything. We store each department in its own local Turso database (@tursodatabase/database, the embedded engine, local by design, no cloud, no sync). The embedded engine forbids multi-process access. If five agents each opened departments/crm.db, we would corrupt it.
So no agent ever opens a database file. Instead, one long-lived process, which we call the Records Office, the deptdb daemon, owns every departments/<dept>.db and is their sole writer. It exposes a streamable-HTTP MCP server on 127.0.0.1:8788, and every agent, whether on omp or anything else that speaks MCP, is just a client:
cd deptdb && KEYRING_PASSPHRASE=… bun src/server.ts # or: just -f deptdb/justfile deptdb
The daemon is a bun and TypeScript program with no build step. It keeps one connection per department and runs all of a department's operations through a per-department serial queue. That is the entire concurrency model. No MVCC, no secondary indexes (both experimental in the engine), just a single writer absorbing fan-out concurrency and guaranteeing that snapshots and task claims see consistent state.
Wiring it into the org is four lines. The repo's mcp.json points every agent at the loopback daemon:
{
"mcpServers": {
"deptdb": { "type": "http", "url": "http://127.0.0.1:8788/mcp" }
}
}
The orchestrator's first move every session is to call list_departments. If that fails, the daemon is not up, and nothing proceeds until it answers.
Each department database is four things at once.
Append-only knowledge with semantic search. A knowledge table stores title plus body plus an embedding BLOB. Search is brute-force cosine distance, vector_distance_cos(embedding, vector32(?)) ORDER BY dist LIMIT ?, which is plenty at department scale (target under about 10k rows). Embeddings come from a local Ollama model, nomic-embed-text (768-dimensional vectors), which we now run for real, with an offline deterministic hashed fallback (a smaller 256-dim vector) so the company still works with no model server at all. Note the split: embeddings stay local on Ollama, while the heavier reasoning roles run on the hosted open weights from the aside above.
Crucially, the embedder is pinned per department database. The first knowledge_write stamps the active embedder into a meta row, and every later read and write checks against it. If the daemon's embedder or its vector dimension no longer matches what a department was written with, the call fails closed instead of silently mixing incompatible vectors:
embedder mismatch for crm: db pinned to 'ollama:nomic-embed-text', daemon is 'deterministic:256'.
The operational rule is simple: keep Ollama up when the daemon boots, so every department pins to ollama:nomic-embed-text. If you would rather rule out a silent downgrade, set DEPTDB_EMBEDDER_FALLBACK=false, and a missing model server then becomes a hard boot failure instead of a quiet fall back to the deterministic embedder, which would otherwise mismatch every Ollama-pinned department on its next read.
Knowledge is never mutated. A new entry supersedes the old one (setting supersedes and deactivating the prior row), so the history of what the department believed is always recoverable.
A single-writer task queue. Tasks are opened, then atomically claimed with a time-boxed lease. Because the claim runs on the serial queue, two agents can never grab the same task, and a lease that expires lets the work be reclaimed.
Threaded discussion and a signed audit log: the durable record, covered next.
All of it is reachable through exactly 18 MCP tools, grouped:
Org chart (1):
list_departmentsKnowledge (3):
knowledge_write,knowledge_search,knowledge_getTasks (4):
task_open,task_claim,task_complete,task_listThreads (3):
thread_open,thread_post,thread_readAudit (1):
audit_tailPortability (2):
snapshot,rehydrateGEO-Audit extension (4):
audit_record,audit_recent,extractability_put,extractability_get
The last group is how a department earns extra tools without forking the daemon. geoaudit.db additionally carries audits, probe_cost, and extractability_cache tables, and its operator calls audit_recent(domain) to avoid re-spending a paid probe inside a freshness window.
metaend Grade. Checking how legible a site is to an AI agent is useful on its own, outside any audit pipeline. That is what metaend Grade does: point it at a domain and it scores how readable and usable your site is for AI agents, in the same spirit as the extractability layer this department caches.
The reason for threads is that delegation should be replayable, not lost in a chat scroll. Every objective produces a paper trail with a small, fixed protocol:
The orchestrator opens a
taskand athread, then posts adelegatemessage describing the objective.The routed head claims the task. It either posts a
questionand yields (never guesses), or does the work and posts areportwith its branch name.The orchestrator posts an
answerto unblock a question, or, after/reviewand integrating the branch, posts a signeddecision.
Those are the literal roles the thread_post tool accepts: delegate, question, answer, report, decision. When a head fans out, it opens a sub-thread for its workers with the same roles, so the tree is replayable all the way down to a single worker's contribution. The head merges and owns the one signed write, and workers stay keyless.
The effect is that "why did we ship this?" is always answerable. Knowledge is superseded, never overwritten. Decisions are appended, never edited. The company remembers.
Five of the agents, the orchestrator and the four heads, have a persistent Nostr identity, managed end to end with nak, the Nostr army knife. When a decision is posted, the daemon signs a kind:30078 event tagged with the department, task, and thread, stores the event JSON on the message row, and mirrors it into the audit_log. Anyone can check it later:
echo '<event-json>' | nak verify
Identities are generated once (just -f deptdb/justfile identities): nak key generate for the secret, nak encode npub for the public registry committed to identities.json, and nak key encrypt to store the NIP-49 ciphertext in the vault. At boot the daemon loads the encrypted keyring, decrypts it in memory with the keyring passphrase, and signs at runtime. Workers have no key and sign nothing.
An honest word on what this proves. On our single-user, loopback-only box, the daemon holds each role's key and signs on behalf of whatever author a local client claims. So a signature attests "the daemon, holding role R's key, recorded this decision." It is daemon-level provenance, not per-agent authentication. It does not cryptographically prove which process authored the call. That is a deliberate, documented trade-off for the local trust model (see deptdb/SECURITY.md), and it has a clean upgrade path: the moment the daemon leaves loopback, you add bearer-token auth on /mcp and per-caller-to-role binding so an attestation proves the authenticated caller. We say this plainly rather than overselling the crypto.
Live databases are disposable. departments/*.db is gitignored and rebuilt on demand. The committed source of truth is a textual SQL snapshot per department, snapshots/<dept>.sql: INSERT statements with embeddings emitted as x'<hex>' literals for an exact round-trip. Text instead of a binary .db means no WAL-sidecar corruption, no merge hell, and survival across a future engine change. The snapshot and rehydrate tools (and their CLIs) drive the loop, and snapshot runs on the serial queue so it always captures consistent state.
Three classes of state, three handling rules:
State | Lives in | Encryption | Committed? |
|---|---|---|---|
Code and config | repo | none (no secrets) | yes, plain |
Data (knowledge/tasks/threads/audit) |
| git-crypt | yes, encrypted |
Secrets (nak keyring, tokens) |
| git-crypt | yes, encrypted |
The git-crypt key itself |
| age passphrase (scrypt) | yes, encrypted |
Live databases |
| none | no, gitignored, rebuilt |
secrets/ and snapshots/ are transparently git-crypt-encrypted in the remote (AES-256) and plaintext only in your working tree. The git-crypt key that unlocks them is itself wrapped with an age passphrase as cowork.key.age and committed. So the repo is fully self-contained and the only secret you carry by hand is one passphrase, kept in a password manager plus one offline backup, never on disk in the clear. A one-time just -f deptdb/justfile vault-init (the only place git-crypt is initialized) sets all of this up.
Standing the whole company up on a new laptop is four steps:
git clone <repo> && cd cowork
age -d cowork.key.age > /dev/shm/cowork.key # enter the passphrase (tmpfs, not disk)
git-crypt unlock /dev/shm/cowork.key && shred -u /dev/shm/cowork.key
just -f deptdb/justfile rehydrate # rebuild live DBs from encrypted snapshots
just -f deptdb/justfile deptdb # daemon loads the keyring, signs, serves
Everything else, the encrypted git-crypt key, the nak keyring, and all department data, travels inside the repo. When you ever do get a hardware token, the only change is swapping age -p for an age-plugin-yubikey recipient. Nothing else in the design moves.
The daemon is bun and TypeScript, no build step, with the tool surface split into small modules under deptdb/src/tools/ (core, portability, geoaudit). It ships with 77 bun test cases across 11 test files, covering the embeddings round-trip, knowledge and semantic search, the task queue and serial-queue concurrency, threads and signed decisions, snapshot and rehydrate portability, the geo-audit extension, end-to-end HTTP MCP integration, and a dedicated security-hardening suite, all green, with bunx tsc --noEmit clean on top.
A security audit drove a concrete set of mitigations, each documented in deptdb/SECURITY.md:
Parameterized SQL everywhere. The single string-interpolation site is snapshot serialization, where a dedicated escaper emits
x'<hex>'for BLOBs. No tool input is ever concatenated into a live query.Prototype-safe department allowlist. Department names are checked with an own-property membership test against a fixed registry, so
__proto__,constructor, and../traversal are rejected before they can reach a filename or table.Shell-free nak. Signing and verification spawn
nakwith an explicit argument vector, never a shell string, so nothing can be injected via content, and stderr is suppressed so noise cannot leak around the event JSON.Hardened loopback transport. A Host and Origin allowlist plus DNS-rebinding protection keeps a browser or rebinding attacker off
/mcpeven if it resolves a name to127.0.0.1. Oversized POSTs are rejected with a413(a 4 MiB body cap), every tool argument carries a string-length cap, and early-error responses sendConnection: closeso a half-read socket is never reused.Fail-closed where it counts. The embedder pin refuses a model swap rather than corrupting vectors. A per-call embed timeout stops a hung Ollama from stalling a department's serial queue. Rehydrate is serialized against in-flight ops. Secrets never reach the logs (the keyring passphrase and decrypted keys stay inside the keyring module). And a commit-time vault guard (
scripts/sync-guard.sh) refuses to commit anything undersecrets/orsnapshots/that is not git-crypt-encrypted.
The doc is equally explicit about the residual risks it accepts under the local single-user model: daemon-level (not per-caller) provenance, no per-tool auth on the loopback port, and full-scan knowledge search, each with the exact upgrade to make if the deployment assumptions change. Honest numbers, honest limits.
Growth is a pattern, not a rewrite. A department is a row in the registry, a folder, a database, and an agent charter. The whole registry lives in deptdb/src/config.ts:
export const DEPARTMENTS: Record<string, DeptSpec> = {
crm: { db: "crm.db", kind: "default", role: "crm-engineer", folder: "projects/crm" },
geoaudit: { db: "geoaudit.db", kind: "geoaudit", role: "geo-audit-operator", folder: "projects/geo-audit" },
coding: { db: "coding.db", kind: "default", role: "coder", folder: "(repo minus product folders)" },
research: { db: "research.db", kind: "default", role: "researcher", folder: "research" },
};
Add an entry, drop in a charter under .omp/agents/, snapshot, and the new department is a first-class citizen with all 18 tools and its own signed memory. The full, repeatable runbook, including the geoaudit-style path for a department that needs extra tables and tools, lives in deptdb/ADDING-A-DEPARTMENT.md.
Put it together with one sentence to the orchestrator: "Refresh the geo-audit on-page checker for 2026, then re-audit a domain."
The orchestrator opens a
taskandthread, then delegates the research toresearcher.researcherrunsknowledge_searchon theresearchdepartment, fills the gaps withweb_search, and writes findings withknowledge_write, each with its source in theref. It returns the finding ulids and yields.The orchestrator delegates to
geo-audit-operator, which reads those findings, sees the change spans the checker plus three rule modules, and fans out oneworkerper module (disjoint scopes) while taking the checker itself.Workers return branches. The operator merges, runs a lite self-test, writes one consolidated knowledge entry, and posts a signed
decisiontogeoaudit.Before re-auditing, it calls
audit_recent(domain). Nothing fresh inside the window, so it runs the audit, then records the result withaudit_recordand caches the technical layer withextractability_put.The orchestrator runs
/review, integrates the branch, and posts the final signeddecision.just -f deptdb/justfile syncsnapshots every department, the vault guard confirmssnapshots/andsecrets/are git-crypt-encrypted, and it pushes.
You wrote one sentence. The company produced working code, a paper trail down to each worker, a nak verify-able decision, and an encrypted commit, and tomorrow on any machine, rehydrate brings it all back exactly as you left it.
We wanted a company that behaves like software: versioned, reproducible, and auditable, not a pile of SaaS tabs and tribal memory. What we got is exactly that. You talk to a manager that delegates to specialists who remember what they have learned, justify what they shipped, and sign the decisions that matter. The data is encrypted the moment it leaves the daemon, and the entire operation collapses into a git repo you can clone anywhere.
A company you can clone, unlock with one passphrase, and rehydrate on a fresh machine in under a minute. That is the whole point. The org chart is code. The memory is portable. The paper trail verifies. And the only thing you cannot lose is a single passphrase in your head.
I write about agent systems, privacy-first infrastructure, and the open-model stack as metaend. If you want to reach me, build on any of this, or tell me where it breaks, the door is here:
More writing lives at paragraph.com/@metaend. And if you are curious how legible your own site is to AI agents, run it through metaend Grade.
Written by metaend.

