{"slug": "show-hn-stigmergy-a-karpathy-style-llm-wiki-for-a-team-not-one-person", "title": "Show HN: Stigmergy, a Karpathy-style LLM wiki for a team, not one person", "summary": "Stigmergy, a team-oriented LLM wiki inspired by Andrej Karpathy's single-user wiki, uses a librarian agent to maintain a Git-and-Markdown knowledge base from immutable source captures via Slack, Claude Code, and MCP tools, with visibility scoping and full audit trails. The open-source project, built on Postgres and Git, targets organizations needing shared, evidence-backed documentation without human approval workflows.", "body_md": "**Stigmergy** is the team version of the wiki in\n[Karpathy's gist](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). Immutable\nsource material enters one queue, one librarian agent keeps a small Git-and-Markdown wiki current,\nand every search and answer is scoped to what the caller may see.\n\nAnts coordinate by leaving traces in the environment, not by talking to each other. Here every capture is a trace — a person reacting in Slack, an agent finishing a task in Claude Code — the librarian follows the traces, and the wiki emerges. Nobody approves a queue.\n\n[Why](#why)[How it works](#how-it-works)[The write path](#the-write-path)[The knowledge model](#the-knowledge-model)[Using it](#using-it)·[Claude Code / Codex](#from-claude-code-or-codex)·[Slack](#from-slack)·[Backoffice](#from-the-backoffice)·[MCP tools](#mcp-tools)[Visibility and security](#visibility-and-security)[Models](#models)[Quality and tests](#quality-and-tests)[Quick start](#quick-start)[Deployment](#deployment)[Repository layout](#repository-layout)[Design principles](#design-principles)[Documentation](#documentation)\n\nA one-person wiki works because the loop is tiny. Once several people and agents write to the same wiki, you need what a shared deployment forces on you: identity, visibility, concurrency, binary evidence, Slack, audit. Stigmergy adds exactly that and nothing that duplicates the loop.\n\nCapture where the work happens |\nAgents through the MCP bridge, people through a `:brain:` reaction in Slack, the master through the backoffice. |\nEvidence you can trust |\nExact bytes in a private store; one immutable source page per capture. |\nA librarian that files |\nCreates, rewrites, consolidates, and deletes pages without approval. |\nAnswers with receipts |\nHybrid search and `ask` with citations verified by code. |\nVisibility on writes too |\nRestricted evidence never shapes a page a broader audience can read. |\nHonest contradictions |\nConflicting claims stay explicit, dated, and cited. |\nSelf-healing corpus |\nA scheduled gardener repairs through the same gates. No human to-do list. |\nFull audit |\nOne operation, one commit, one change record with the exact patch. |\n\n**Capture.** Thin adapters authenticate and acquire bytes. Local files and private Google Drive documents stay on your machine until uploaded through a presigned URL.**Queue.** Every adapter produces the same kind-free`CaptureEnvelope`\n\n. The Postgres queue is durable, leased, and idempotent per actor and client key.**Write.** One serialized writer extracts text, renders the immutable source page, asks the librarian for a`FilingPlan`\n\n, and advances the branch only when every gate passes.**Remember.** The knowledge repository is plain Git and Markdown. Postgres is operational state and a rebuildable index, never a second wiki.**Read.** Five MCP tools for agents,`@brain`\n\nfor people, one visibility policy. A webhook indexes incrementally; a nightly full rebuild guarantees convergence.\n\nStates are `queued → processing → landed | failed`\n\n. Nothing waits for a human: ambiguity becomes\nan explicit contradiction, technical failures retry within a bounded lease, and a terminal failure\ncarries a typed error the master can retry. A crash after the commit is reconciled by commit SHA,\nnever by a second commit.\n\nThe librarian may create or rewrite a note or concept, consolidate and delete a redundant page,\npropose an entity claim, add or resolve a contradiction, or file nothing — the source still lands.\nIt never rewrites `sources/`\n\nand never broadens an ACL. Deletion is a separate explicit operation\n(`brain_delete`\n\n) through the same writer and gates.\n\n| Role | Location | Mutable by filing? | Meaning |\n|---|---|---|---|\n| Note | `wiki/notes/` |\nyes | contextual conclusion, decision, or event |\n| Concept | `wiki/concepts/` |\nyes | durable explanatory knowledge |\n| Entity identity | `wiki/entities/ent_<uuid>.md` |\nentity primitives only | opaque ID and scoped name claims |\n| Source | `sources/YYYY/MM/<capture-id>.md` |\nno | immutable evidence for one capture |\n\nA note or concept carries a maturity (`seed`\n\n, `developing`\n\n, `mature`\n\n, `evergreen`\n\n), an optional\nACL, entity anchors, and its sources:\n\n```\n---\nid: page_aurora_renewal\ntype: note\ntitle: Aurora renewal\nstatus: mature\ncreated: 2026-08-10\nupdated: 2026-08-10\nacl:\n- sales\nentity:\n- ent_11111111-1111-4111-8111-111111111111\nsources:\n- sources/2026/08/20000000-0000-4000-8000-000000000002.md\n---\n\n# Aurora renewal\n\nAurora Systems agreed to an annual renewal with a budget of EUR 120,000. The renewed term starts\non 15 September 2026.\n```\n\nEntities are opaque IDs with scoped, sourced name claims; facts live in notes and concepts and\n`describe_entity`\n\ncomposes them at read time. Merging needs a shared external ID or an exact\nassertion in a source — resemblance does nothing.\n\nWhen credible sources disagree, the librarian keeps both claims in a strict marker on the narrowest page whose readers may see both:\n\n```\n> [!WARNING] Unresolved contradiction `con_3f1c2b9a-6d4e-4a2b-9c1d-2f7e8a9b0c1d`\n> The two renewal sources disagree on the annual budget.\n> - **Claim:** The annual renewal budget is EUR 120,000\n>   **Date:** `2026-08-10`\n>   **Source:** `sources/2026/08/20000000-0000-4000-8000-000000000002.md`\n> - **Claim:** The annual renewal budget is EUR 95,000\n>   **Date:** `2026-08-18`\n>   **Source:** `sources/2026/08/40000000-0000-4000-8000-000000000004.md`\n```\n\nA master may later submit a resolution; it is an ordinary capture, and the marker goes away only when the new evidence actually resolves it.\n\nInstall the bridge once per machine and point it at your deployment. It proxies the read tools to the cloud and acquires local files, public URLs, and private Google Drive documents locally.\n\n```\nuv tool install git+https://github.com/sturlese/stigmergy.git\nexport STIGMERGY_TOKEN=\"<identity-token>\"\n```\n\nClaude Code, `.mcp.json`\n\n:\n\n```\n{\n  \"mcpServers\": {\n    \"stigmergy\": {\n      \"command\": \"stigmergy-bridge\",\n      \"args\": [\"--url\", \"https://stigmergy.example.com\"],\n      \"env\": {\n        \"STIGMERGY_TOKEN\": \"${STIGMERGY_TOKEN}\",\n        \"STIGMERGY_GOOGLE_CLIENT_SECRETS\": \"${STIGMERGY_GOOGLE_CLIENT_SECRETS:-}\"\n      }\n    }\n  }\n}\n```\n\nCodex, `.codex/config.toml`\n\n:\n\n```\n[mcp_servers.stigmergy]\ncommand = \"stigmergy-bridge\"\nargs = [\"--url\", \"https://stigmergy.example.com\"]\nenv_vars = [\"STIGMERGY_TOKEN\", \"STIGMERGY_GOOGLE_CLIENT_SECRETS\"]\nrequired = true\n```\n\n| You say | What happens |\n|---|---|\n\"Save the conclusions to the brain.\" |\n`brain_submit(text=…)` with a self-contained synthesis. |\n\"File ~/Downloads/board-deck.pdf.\" |\nThe bridge uploads the bytes; the worker extracts, OCRs scanned pages, files. |\n\"Capture\n|\nLocal Google OAuth, token in your keychain, DOCX export uploaded. |\n\"What did we decide about the Aurora renewal?\" |\n`ask` retrieves within your visibility and answers with verified citations. |\n\nThe same tools and the same token rules apply whether a person is driving the session or an\nagent runs on its own after a task. Private Drive needs\n`STIGMERGY_GOOGLE_CLIENT_SECRETS=/absolute/path/google-oauth-client.json`\n\n.\n\n**Ask:**`@brain what is the status of the Borealis rollout?`\n\nin a mapped channel. If you can see more than the channel, the extra follows up privately.**Capture:** react with`:brain:`\n\non a thread. Speakers, timestamps, permalinks, and attachments become one capture under the channel's audience. Unmapped channels and unauthorized reactors capture nothing.\n\nChannels map to audiences in `ops/slack-channels.json`\n\n; the app manifest is\n[ deploy/slack-app-manifest.json](/sturlese/stigmergy/blob/main/deploy/slack-app-manifest.json).\n\n`/admin`\n\non the `app`\n\nprocess, enabled by `STIGMERGY_ADMIN_TOKEN_HASH`\n\n, one master identity.\n\n| View | |\n|---|---|\n| Captures | paste, upload, public URL; provenance, extraction, retries, commit, change |\n| Changes | plain-language summary, per-path diff, exact Git patch on demand |\n| Contradictions | live list from current Markdown, resolution form |\n| Entities | scoped claims and provenance, evidence-backed merge and delete |\n| Gardener | run history and a manual trigger |\n| Index health | repository HEAD vs indexed commit, dirty flag, last full rebuild |\n\nThe cloud server and the local bridge expose the same surface:\n\n| Tool | |\n|---|---|\n`search_brain(query, filters?, max_results?)` |\nhybrid lexical + vector search |\n`read_page(path)` |\none visible page with links and citations |\n`ask(question)` |\na cited, verified answer — or an honest refusal |\n`list_entities()` |\nidentities with a name you may see |\n`describe_entity(entity)` |\nknowledge composed from visible pages |\n`brain_submit(text | path | url, title?, occurred_at?, audience?)` |\ncapture one input |\n`brain_submissions(limit?, status?)` |\ncapture progress |\n`brain_delete(paths, why)` |\nexplicit deletion with reference sweep |\n\nThere is no `kind`\n\n. `path`\n\nand private Drive exist only in the bridge. An omitted `audience`\n\nuses\nyour configured default, never organization-wide by accident.\n\n- Every identity — whoever or whatever holds the token — has groups and a default audience in the\nknowledge repository's\n`ops/identities.json`\n\n; a page's`acl`\n\nis`null`\n\nor a list of groups.`brain-admins`\n\nis unrestricted. - One policy for reads and writes:\n`server.acl.visible`\n\n,`kernel.acl.flows_into`\n\n, and the write guard. A restricted capture gets a restricted companion page; open pages are never rewritten from narrower evidence. - Unknown, hidden, and unauthorized pages, entities, and captures look identical from outside.\n- Per-user bearer tokens from\n`stigmergy-issue-token`\n\n; the server keeps only SHA-256 hashes. The cloud never sees Google credentials; clients never see the object store. - Captured content is data, never instructions. The answer verifier is pure code; adversarial tests keep it that way.\n- Public fetching blocks private and metadata destinations and revalidates every redirect. Parsers detect types from bytes and enforce size, page, and decompression limits.\n- Secrets, tokens, presigned URLs, bytes, and restricted titles never enter logs. CI runs\n`gitleaks`\n\n.\n\nReport vulnerabilities privately: [ SECURITY.md](/sturlese/stigmergy/blob/main/SECURITY.md).\n\nOne `OPENROUTER_API_KEY`\n\n, a closed allowlist in `kernel.llm`\n\n, no provider fallback, zero-data\nretention. Direct Anthropic, OpenAI, or Gemini credentials are rejected.\n\n| Purpose | Model |\n|---|---|\n| filing and semantic repair | `deepseek/deepseek-v4-flash` |\n| cited answers | `z-ai/glm-5.2` |\n| embeddings | `qwen/qwen3-embedding-8b` , 2560 dimensions |\n| OCR | `qwen/qwen3-vl-8b-instruct` |\n\nThe keyless suite — 1,100+ tests over real Postgres and Git, fake models, 75% coverage gate — is\nthe contract. Optional real-model evaluations run over a frozen corpus and append to\n[ evals/history.ndjson](/sturlese/stigmergy/blob/main/evals/history.ndjson). Latest run (2026-08-24):\n\n| Measure | Result | Bar |\n|---|---|---|\n| Retrieval Recall@5 (15 questions, 9 ACL-filtered) | 1.00 |\n≥ 0.80 |\n| Answer honesty | 1.00 |\n≥ 0.90 |\n| Answer groundedness | 1.00 |\n≥ 0.84 |\n| False-premise refutation | 1.00 |\n— |\n\n```\nmake retrieval-golden EMBEDDER=openrouter\nmake qa-golden EMBEDDER=openrouter LLM=openrouter\nmake gates\n```\n\nPython 3.12+, [ uv](https://docs.astral.sh/uv/), Docker.\n\n```\ngit clone https://github.com/sturlese/stigmergy.git && cd stigmergy\nmake venv\nmake db-up     # Postgres + pgvector, MinIO\nmake test\nmake lint\n```\n\nIndex a knowledge repository and serve it over stdio:\n\n```\nexport STIGMERGY_INDEX_DSN=postgresql://stigmergy:stigmergy@localhost:54321/stigmergy\nstigmergy-index --rebuild --repo ../stigmergy-brain --embedder fake\nstigmergy-server --transport stdio --repo ../stigmergy-brain \\\n  --identity you@example.com --embedder fake\n```\n\nOne image, three Fly process groups:\n\n| Process | Command | Role |\n|---|---|---|\n`app` |\n`stigmergy-server --transport http` |\nMCP over HTTP, uploads, index webhook, backoffice |\n`worker` |\n`stigmergy-librarian-boot` |\nthe only writer and the scheduled gardener |\n`slack` |\n`stigmergy-slack` |\nSocket Mode adapter, one active instance |\n\n```\nmake deploy-staging\nmake rebuild-staging\n```\n\n| Area | Variables |\n|---|---|\n| Models | `OPENROUTER_API_KEY` , `STIGMERGY_LIBRARIAN_MODEL` , `ANSWER_MODEL` , `STIGMERGY_OCR_MODEL` |\n| Database | `STIGMERGY_INDEX_DSN` |\n| Evidence store | `STIGMERGY_EVIDENCE_ENDPOINT` , `_BUCKET` , `_ACCESS_KEY_ID` , `_SECRET_ACCESS_KEY` |\n| Server | `STIGMERGY_PUBLIC_HOST` , `STIGMERGY_TOKEN_STORE` or `STIGMERGY_TOKEN_STORE_FILE` |\n| Backoffice | `STIGMERGY_ADMIN_TOKEN_HASH` , `STIGMERGY_ADMIN_ACTOR` |\n| Writer | `STIGMERGY_REPO` , `STIGMERGY_LIBRARIAN_REPO_URL` , `STIGMERGY_LIBRARIAN_APP_ID` , `_INSTALLATION_ID` , `_PRIVATE_KEY` , `STIGMERGY_LIBRARIAN_GARDEN_AT` |\n| Index webhook | `STIGMERGY_GITHUB_WEBHOOK_SECRET` , `STIGMERGY_GITHUB_REPO` , `STIGMERGY_GITHUB_BRANCH` |\n| Slack | `SLACK_APP_TOKEN` , `SLACK_BOT_TOKEN` , `SLACK_TEAM_ID` |\n\nYour team's knowledge is a separate private repository:\n\n```\nyour-brain/\n├── sources/YYYY/MM/<capture-id>.md\n├── wiki/\n│   ├── notes/\n│   ├── concepts/\n│   └── entities/ent_<uuid>.md\n├── ops/\n│   ├── identities.json            people, groups, default audience\n│   ├── slack-channels.json        channel id → audience\n│   └── entity-registry.json       derived, written by the platform\n├── .claude/skills/librarian/SKILL.md\n└── .github/workflows/             nightly index rebuild\n```\n\nOnly the writer's GitHub App identity commits to `wiki/`\n\n, `sources/`\n\n, and the registry. Runbook:\n[ docs/OPERATIONS.md](/sturlese/stigmergy/blob/main/docs/OPERATIONS.md); reset:\n\n[.](/sturlese/stigmergy/blob/main/docs/RESET.md)\n\n`docs/RESET.md`\n\n| Package | |\n|---|---|\n`kernel` |\nACL flow, deadlines, the model boundary, normalization |\n`capture` |\nenvelopes, evidence, uploads, extraction and OCR, queue, sources |\n`bridge` |\nthe local stdio MCP client |\n`knowledge` |\npage contracts, `FilingPlan` , writer, linter, repair, contradictions, write guard |\n`entities` |\nopaque identities, claims, registry, merge, rename, delete |\n`changes` |\nexact patches and the change ledger |\n`index` |\ncorpus selection, ranking, incremental updates, full rebuild, health |\n`server` · `answer` |\nMCP tools, HTTP transport, webhook, verified answers |\n`slack` |\nSocket Mode adapter |\n`admin` |\nthe master backoffice |\n`librarian` |\nthe writer process, bootstrap, Git and GitHub App transport, schedule |\n`ops` |\nthe guarded non-production reset |\n\n- Git and Markdown are current knowledge; Postgres is a rebuildable index.\n- Every adapter produces the same kind-free\n`CaptureEnvelope`\n\n. - Original bytes and source pages are immutable except through explicit deletion.\n- One serialized writer: one commit and one change record per operation.\n- Visibility is a write constraint.\n- The librarian owns notes and concepts; entity pages hold identity only.\n- No write waits for a human. Uncertainty is represented honestly.\n- A health finding is preventable or autonomously repairable, or it is not a finding.\n- Every capability is reachable through Slack, MCP, or the backoffice.\n\nRationale and acceptance criteria: [ specs/karpathy-team-wiki.md](/sturlese/stigmergy/blob/main/specs/karpathy-team-wiki.md).\n\n[Specification](/sturlese/stigmergy/blob/main/specs/karpathy-team-wiki.md)[Architecture](/sturlese/stigmergy/blob/main/docs/ARCHITECTURE.md)[Operations](/sturlese/stigmergy/blob/main/docs/OPERATIONS.md)[Clean reset](/sturlese/stigmergy/blob/main/docs/RESET.md)[Quality evaluations](/sturlese/stigmergy/blob/main/evals/README.md)[Changelog](/sturlese/stigmergy/blob/main/CHANGELOG.md)·[Contributing](/sturlese/stigmergy/blob/main/CONTRIBUTING.md)·[Security](/sturlese/stigmergy/blob/main/SECURITY.md)\n\nApache License 2.0.", "url": "https://wpnews.pro/news/show-hn-stigmergy-a-karpathy-style-llm-wiki-for-a-team-not-one-person", "canonical_source": "https://github.com/sturlese/stigmergy", "published_at": "2026-08-24 22:32:57+00:00", "updated_at": "2026-08-24 22:43:01.305696+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-agents", "ai-tools", "developer-tools"], "entities": ["Stigmergy", "Andrej Karpathy", "Slack", "Claude Code", "MCP", "Postgres", "Git"], "alternates": {"html": "https://wpnews.pro/news/show-hn-stigmergy-a-karpathy-style-llm-wiki-for-a-team-not-one-person", "markdown": "https://wpnews.pro/news/show-hn-stigmergy-a-karpathy-style-llm-wiki-for-a-team-not-one-person.md", "text": "https://wpnews.pro/news/show-hn-stigmergy-a-karpathy-style-llm-wiki-for-a-team-not-one-person.txt", "jsonld": "https://wpnews.pro/news/show-hn-stigmergy-a-karpathy-style-llm-wiki-for-a-team-not-one-person.jsonld"}}