sturlese/stigmergy

A team's knowledge, captured where the work happens, filed by an agent, and answered with citations you can check.

9

stars

359

commits

Python

primary language

Aug 26, 2026

updated

ai-agents
claude
hybrid-search
knowledge-base
knowledge-management
llm
mcp
model-context-protocol
pgvector
postgres
python
rag
second-brain
slack
wiki

README

Stigmergy

CI License: Apache-2.0 Python 3.12+ MCP server and local bridge Specification

Stigmergy is the team version of the wiki in Karpathy's gist. Immutable source material enters one queue, one librarian agent keeps a small Git-and-Markdown wiki current, and every search and answer is scoped to what the caller may see.

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


Why

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

Capture where the work happensAgents through the MCP bridge, people through a :brain: reaction in Slack, the master through the backoffice.
Evidence you can trustExact bytes in a private store; one immutable source page per capture.
A librarian that filesCreates, rewrites, consolidates, and deletes pages without approval.
Answers with receiptsHybrid search and ask with citations verified by code.
Visibility on writes tooRestricted evidence never shapes a page a broader audience can read.
Honest contradictionsConflicting claims stay explicit, dated, and cited.
Self-healing corpusA scheduled gardener repairs through the same gates. No human to-do list.
Full auditOne operation, one commit, one change record with the exact patch.

How it works

Architecture

  1. Capture. Thin adapters authenticate and acquire bytes. Local files and private Google Drive documents stay on your machine until uploaded through a presigned URL.
  2. Queue. Every adapter produces the same kind-free CaptureEnvelope. The Postgres queue is durable, leased, and idempotent per actor and client key.
  3. Write. One serialized writer extracts text, renders the immutable source page, asks the librarian for a FilingPlan, and advances the branch only when every gate passes.
  4. Remember. The knowledge repository is plain Git and Markdown. Postgres is operational state and a rebuildable index, never a second wiki.
  5. Read. Five MCP tools for agents, @brain for people, one visibility policy. A webhook indexes incrementally; a nightly full rebuild guarantees convergence.

The write path

The write path

States are queued → processing → landed | failed. Nothing waits for a human: ambiguity becomes an explicit contradiction, technical failures retry within a bounded lease, and a terminal failure carries a typed error the master can retry. A crash after the commit is reconciled by commit SHA, never by a second commit.

The librarian may create or rewrite a note or concept, consolidate and delete a redundant page, propose an entity claim, add or resolve a contradiction, or file nothing — the source still lands. It never rewrites sources/ and never broadens an ACL. Deletion is a separate explicit operation (brain_delete) through the same writer and gates.

The knowledge model

The knowledge model

RoleLocationMutable by filing?Meaning
Notewiki/notes/yescontextual conclusion, decision, or event
Conceptwiki/concepts/yesdurable explanatory knowledge
Entity identitywiki/entities/ent_<uuid>.mdentity primitives onlyopaque ID and scoped name claims
Sourcesources/YYYY/MM/<capture-id>.mdnoimmutable evidence for one capture

A note or concept carries a maturity (seed, developing, mature, evergreen), an optional ACL, entity anchors, and its sources:

---
id: page_aurora_renewal
type: note
title: Aurora renewal
status: mature
created: 2026-08-10
updated: 2026-08-10
acl:
- sales
entity:
- ent_11111111-1111-4111-8111-111111111111
sources:
- sources/2026/08/20000000-0000-4000-8000-000000000002.md
---

# Aurora renewal

Aurora Systems agreed to an annual renewal with a budget of EUR 120,000. The renewed term starts
on 15 September 2026.

Entities are opaque IDs with scoped, sourced name claims; facts live in notes and concepts and describe_entity composes them at read time. Merging needs a shared external ID or an exact assertion in a source — resemblance does nothing.

When credible sources disagree, the librarian keeps both claims in a strict marker on the narrowest page whose readers may see both:

> [!WARNING] Unresolved contradiction `con_3f1c2b9a-6d4e-4a2b-9c1d-2f7e8a9b0c1d`
> The two renewal sources disagree on the annual budget.
> - **Claim:** The annual renewal budget is EUR 120,000
>   **Date:** `2026-08-10`
>   **Source:** `sources/2026/08/20000000-0000-4000-8000-000000000002.md`
> - **Claim:** The annual renewal budget is EUR 95,000
>   **Date:** `2026-08-18`
>   **Source:** `sources/2026/08/40000000-0000-4000-8000-000000000004.md`

A master may later submit a resolution; it is an ordinary capture, and the marker goes away only when the new evidence actually resolves it. Direct and local MCP submissions use the optional resolution_of="con_<uuid>" argument. The writer accepts it only from the master, only for that exact visible marker, and only at a safe audience; an unauthorized attempt still archives its source but applies none of the librarian plan.

Using it

From Claude Code or Codex

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

uv tool install git+https://github.com/sturlese/stigmergy.git
export STIGMERGY_TOKEN="<identity-token>"

Claude Code, .mcp.json:

{
  "mcpServers": {
    "stigmergy": {
      "command": "stigmergy-bridge",
      "args": ["--url", "https://stigmergy.example.com"],
      "env": {
        "STIGMERGY_TOKEN": "${STIGMERGY_TOKEN}",
        "STIGMERGY_GOOGLE_CLIENT_SECRETS": "${STIGMERGY_GOOGLE_CLIENT_SECRETS:-}"
      }
    }
  }
}

Codex, .codex/config.toml:

[mcp_servers.stigmergy]
command = "stigmergy-bridge"
args = ["--url", "https://stigmergy.example.com"]
env_vars = ["STIGMERGY_TOKEN", "STIGMERGY_GOOGLE_CLIENT_SECRETS"]
required = true
You sayWhat happens
"Save the conclusions to the brain."brain_submit(text=…) with a self-contained synthesis.
"File ~/Downloads/board-deck.pdf."The bridge uploads the bytes; the worker extracts, OCRs scanned pages, files.
"Capture https://docs.google.com/document/d/…"Local Google OAuth, token in your keychain, DOCX export uploaded.
"What did we decide about the Aurora renewal?"ask retrieves within your visibility and answers with verified citations.

The same tools and the same token rules apply whether a person is driving the session or an agent runs on its own after a task. Private Drive needs STIGMERGY_GOOGLE_CLIENT_SECRETS=/absolute/path/google-oauth-client.json.

From Slack

  • Ask: @brain what is the status of the Borealis rollout? in a mapped channel. If you can see more than the channel, the extra follows up privately.
  • Capture: react with :brain: on a thread. Speakers, timestamps, permalinks, and attachments become one capture under the channel's audience. Unmapped channels and unauthorized reactors capture nothing.

Channels map to audiences in ops/slack-channels.json; the app manifest is deploy/slack-app-manifest.json.

From the backoffice

/admin on the app process, enabled by STIGMERGY_ADMIN_TOKEN_HASH, one master identity.

View
Capturespaste, upload, public URL; provenance, extraction, retries, commit, change
Changesplain-language summary, per-path diff, exact Git patch on demand
Contradictionslive list from current Markdown, resolution form
Entitiesscoped claims and provenance, evidence-backed merge and delete
Gardenerrun history and a manual trigger
Index healthrepository HEAD vs indexed commit, dirty flag, last full rebuild

MCP tools

The cloud server and the local bridge expose the same surface:

Tool
search_brain(query, filters?, max_results?)hybrid lexical + vector search
read_page(path)one visible page with links and citations
ask(question)a cited, verified answer — or an honest refusal
list_entities()identities with a name you may see
describe_entity(entity)knowledge composed from visible pages
brain_submit(text | path | url, title?, occurred_at?, audience?, resolution_of?)capture one input; the optional contradiction ID is master-only
brain_submissions(limit?, status?)capture progress
brain_delete(paths, why)explicit deletion with reference sweep

There is no kind. path and private Drive exist only in the bridge. An omitted audience uses your configured default, never organization-wide by accident.

Visibility and security

  • Every identity — whoever or whatever holds the token — has groups and a default audience in the knowledge repository's ops/identities.json; a page's acl is null or a list of groups. brain-admins is unrestricted.
  • One policy for reads and writes: server.acl.visible, kernel.acl.flows_into, 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.
  • Per-user bearer tokens from stigmergy-issue-token; 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.
  • Public fetching blocks private and metadata destinations and revalidates every redirect. Parsers detect types from bytes and enforce size, page, and decompression limits.
  • Secrets, tokens, presigned URLs, bytes, and restricted titles never enter logs. CI runs gitleaks.

Report vulnerabilities privately: SECURITY.md.

Models

One OPENROUTER_API_KEY, a closed allowlist in kernel.llm, same-model provider failover only, no model fallback or direct alternate-provider credentials, zero-data retention. Direct Anthropic, OpenAI, or Gemini credentials are rejected. The librarian's structured plans are routed to a host verified to return tool-call arguments intact, with the hosts known to corrupt them excluded from failover.

PurposeModel
filing and semantic repairdeepseek/deepseek-v4-flash
cited answersz-ai/glm-5.2
embeddingsqwen/qwen3-embedding-8b, 2560 dimensions
OCRqwen/qwen3-vl-8b-instruct

Query embeddings are bounded. A provider timeout degrades that request to ACL-scoped lexical ranking; indexing remains strict and never accepts an incomplete vector build. Serving connections — HTTP requests and the Slack adapter — bound every Postgres statement; workers and rebuilds keep the database default.

Quality and tests

The keyless suite — 1,100+ tests over real Postgres and Git, fake models, 75% coverage gate — is the contract. Optional real-model evaluations run over a frozen corpus and append to evals/history.ndjson. Latest run (2026-08-24):

MeasureResultBar
Retrieval Recall@5 (15 questions, 9 ACL-filtered)1.00≥ 0.80
Answer honesty1.00≥ 0.90
Answer groundedness1.00≥ 0.84
False-premise refutation1.00
make retrieval-golden EMBEDDER=openrouter
make qa-golden EMBEDDER=openrouter LLM=openrouter
make gates

Quick start

Python 3.12+, uv, Docker.

git clone https://github.com/sturlese/stigmergy.git && cd stigmergy
make venv
make db-up     # Postgres + pgvector, MinIO
make test
make lint

Index a knowledge repository and serve it over stdio:

export STIGMERGY_INDEX_DSN=postgresql://stigmergy:stigmergy@localhost:54321/stigmergy
stigmergy-index --rebuild --repo ../stigmergy-brain --embedder fake
stigmergy-server --transport stdio --repo ../stigmergy-brain \
  --identity you@example.com --embedder fake

Deployment

One image, three Fly process groups:

ProcessCommandRole
appstigmergy-server --transport httpMCP over HTTP, uploads, index webhook, backoffice
workerstigmergy-librarian-bootthe only writer and the scheduled gardener
slackstigmergy-slackSocket Mode adapter, one active instance
make deploy-staging
make rebuild-staging
AreaVariables
ModelsOPENROUTER_API_KEY, STIGMERGY_LIBRARIAN_MODEL, ANSWER_MODEL, STIGMERGY_OCR_MODEL
DatabaseSTIGMERGY_INDEX_DSN
Evidence storeSTIGMERGY_EVIDENCE_ENDPOINT, _BUCKET, _ACCESS_KEY_ID, _SECRET_ACCESS_KEY
ServerSTIGMERGY_PUBLIC_HOST, STIGMERGY_TOKEN_STORE or STIGMERGY_TOKEN_STORE_FILE
BackofficeSTIGMERGY_ADMIN_TOKEN_HASH, STIGMERGY_ADMIN_ACTOR
WriterSTIGMERGY_REPO, STIGMERGY_LIBRARIAN_REPO_URL, STIGMERGY_LIBRARIAN_APP_ID, _INSTALLATION_ID, _PRIVATE_KEY, STIGMERGY_LIBRARIAN_GARDEN_AT
Index webhookSTIGMERGY_GITHUB_WEBHOOK_SECRET, STIGMERGY_GITHUB_REPO, STIGMERGY_GITHUB_BRANCH
SlackSLACK_APP_TOKEN, SLACK_BOT_TOKEN, SLACK_TEAM_ID

Your team's knowledge is a separate private repository:

your-brain/
├── sources/YYYY/MM/<capture-id>.md
├── wiki/
│   ├── notes/
│   ├── concepts/
│   └── entities/ent_<uuid>.md
├── ops/
│   ├── identities.json            people, groups, default audience
│   ├── slack-channels.json        channel id → audience
│   └── entity-registry.json       derived, written by the platform
├── .claude/skills/librarian/SKILL.md
└── .github/workflows/             nightly index rebuild

Only the writer's GitHub App identity commits to wiki/, sources/, and the registry. Runbook: docs/OPERATIONS.md; reset: docs/RESET.md.

Repository layout

Package
kernelACL flow, deadlines, the model boundary, normalization
captureenvelopes, evidence, uploads, extraction and OCR, queue, sources
bridgethe local stdio MCP client
knowledgepage contracts, FilingPlan, writer, linter, repair, contradictions, write guard
entitiesopaque identities, claims, registry, merge, rename, delete
changesexact patches and the change ledger
indexcorpus selection, ranking, incremental updates, full rebuild, health
server · answerMCP tools, HTTP transport, webhook, verified answers
slackSocket Mode adapter
adminthe master backoffice
librarianthe writer process, bootstrap, Git and GitHub App transport, schedule
opsthe guarded non-production reset

Design principles

  1. Git and Markdown are current knowledge; Postgres is a rebuildable index.
  2. Every adapter produces the same kind-free CaptureEnvelope.
  3. Original bytes and source pages are immutable except through explicit deletion.
  4. One serialized writer: one commit and one change record per operation.
  5. Visibility is a write constraint.
  6. The librarian owns notes and concepts; entity pages hold identity only.
  7. No write waits for a human. Uncertainty is represented honestly.
  8. A health finding is preventable or autonomously repairable, or it is not a finding.
  9. Every capability is reachable through Slack, MCP, or the backoffice.

Rationale and acceptance criteria: specs/karpathy-team-wiki.md.

Documentation

Apache License 2.0.

Contributors

sturlese

359 commits

sturlese/stigmergy

A team's knowledge, captured where the work happens, filed by an agent, and answered with citations you can check.

9

stars

359

commits

Python

primary language

Aug 26, 2026

updated

ai-agents
claude
hybrid-search
knowledge-base
knowledge-management
llm
mcp
model-context-protocol
pgvector
postgres
python
rag
second-brain
slack
wiki

README

Stigmergy

CI License: Apache-2.0 Python 3.12+ MCP server and local bridge Specification

Stigmergy is the team version of the wiki in Karpathy's gist. Immutable source material enters one queue, one librarian agent keeps a small Git-and-Markdown wiki current, and every search and answer is scoped to what the caller may see.

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


Why

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

Capture where the work happensAgents through the MCP bridge, people through a :brain: reaction in Slack, the master through the backoffice.
Evidence you can trustExact bytes in a private store; one immutable source page per capture.
A librarian that filesCreates, rewrites, consolidates, and deletes pages without approval.
Answers with receiptsHybrid search and ask with citations verified by code.
Visibility on writes tooRestricted evidence never shapes a page a broader audience can read.
Honest contradictionsConflicting claims stay explicit, dated, and cited.
Self-healing corpusA scheduled gardener repairs through the same gates. No human to-do list.
Full auditOne operation, one commit, one change record with the exact patch.

How it works

Architecture

  1. Capture. Thin adapters authenticate and acquire bytes. Local files and private Google Drive documents stay on your machine until uploaded through a presigned URL.
  2. Queue. Every adapter produces the same kind-free CaptureEnvelope. The Postgres queue is durable, leased, and idempotent per actor and client key.
  3. Write. One serialized writer extracts text, renders the immutable source page, asks the librarian for a FilingPlan, and advances the branch only when every gate passes.
  4. Remember. The knowledge repository is plain Git and Markdown. Postgres is operational state and a rebuildable index, never a second wiki.
  5. Read. Five MCP tools for agents, @brain for people, one visibility policy. A webhook indexes incrementally; a nightly full rebuild guarantees convergence.

The write path

The write path

States are queued → processing → landed | failed. Nothing waits for a human: ambiguity becomes an explicit contradiction, technical failures retry within a bounded lease, and a terminal failure carries a typed error the master can retry. A crash after the commit is reconciled by commit SHA, never by a second commit.

The librarian may create or rewrite a note or concept, consolidate and delete a redundant page, propose an entity claim, add or resolve a contradiction, or file nothing — the source still lands. It never rewrites sources/ and never broadens an ACL. Deletion is a separate explicit operation (brain_delete) through the same writer and gates.

The knowledge model

The knowledge model

RoleLocationMutable by filing?Meaning
Notewiki/notes/yescontextual conclusion, decision, or event
Conceptwiki/concepts/yesdurable explanatory knowledge
Entity identitywiki/entities/ent_<uuid>.mdentity primitives onlyopaque ID and scoped name claims
Sourcesources/YYYY/MM/<capture-id>.mdnoimmutable evidence for one capture

A note or concept carries a maturity (seed, developing, mature, evergreen), an optional ACL, entity anchors, and its sources:

---
id: page_aurora_renewal
type: note
title: Aurora renewal
status: mature
created: 2026-08-10
updated: 2026-08-10
acl:
- sales
entity:
- ent_11111111-1111-4111-8111-111111111111
sources:
- sources/2026/08/20000000-0000-4000-8000-000000000002.md
---

# Aurora renewal

Aurora Systems agreed to an annual renewal with a budget of EUR 120,000. The renewed term starts
on 15 September 2026.

Entities are opaque IDs with scoped, sourced name claims; facts live in notes and concepts and describe_entity composes them at read time. Merging needs a shared external ID or an exact assertion in a source — resemblance does nothing.

When credible sources disagree, the librarian keeps both claims in a strict marker on the narrowest page whose readers may see both:

> [!WARNING] Unresolved contradiction `con_3f1c2b9a-6d4e-4a2b-9c1d-2f7e8a9b0c1d`
> The two renewal sources disagree on the annual budget.
> - **Claim:** The annual renewal budget is EUR 120,000
>   **Date:** `2026-08-10`
>   **Source:** `sources/2026/08/20000000-0000-4000-8000-000000000002.md`
> - **Claim:** The annual renewal budget is EUR 95,000
>   **Date:** `2026-08-18`
>   **Source:** `sources/2026/08/40000000-0000-4000-8000-000000000004.md`

A master may later submit a resolution; it is an ordinary capture, and the marker goes away only when the new evidence actually resolves it. Direct and local MCP submissions use the optional resolution_of="con_<uuid>" argument. The writer accepts it only from the master, only for that exact visible marker, and only at a safe audience; an unauthorized attempt still archives its source but applies none of the librarian plan.

Using it

From Claude Code or Codex

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

uv tool install git+https://github.com/sturlese/stigmergy.git
export STIGMERGY_TOKEN="<identity-token>"

Claude Code, .mcp.json:

{
  "mcpServers": {
    "stigmergy": {
      "command": "stigmergy-bridge",
      "args": ["--url", "https://stigmergy.example.com"],
      "env": {
        "STIGMERGY_TOKEN": "${STIGMERGY_TOKEN}",
        "STIGMERGY_GOOGLE_CLIENT_SECRETS": "${STIGMERGY_GOOGLE_CLIENT_SECRETS:-}"
      }
    }
  }
}

Codex, .codex/config.toml:

[mcp_servers.stigmergy]
command = "stigmergy-bridge"
args = ["--url", "https://stigmergy.example.com"]
env_vars = ["STIGMERGY_TOKEN", "STIGMERGY_GOOGLE_CLIENT_SECRETS"]
required = true
You sayWhat happens
"Save the conclusions to the brain."brain_submit(text=…) with a self-contained synthesis.
"File ~/Downloads/board-deck.pdf."The bridge uploads the bytes; the worker extracts, OCRs scanned pages, files.
"Capture https://docs.google.com/document/d/…"Local Google OAuth, token in your keychain, DOCX export uploaded.
"What did we decide about the Aurora renewal?"ask retrieves within your visibility and answers with verified citations.

The same tools and the same token rules apply whether a person is driving the session or an agent runs on its own after a task. Private Drive needs STIGMERGY_GOOGLE_CLIENT_SECRETS=/absolute/path/google-oauth-client.json.

From Slack

  • Ask: @brain what is the status of the Borealis rollout? in a mapped channel. If you can see more than the channel, the extra follows up privately.
  • Capture: react with :brain: on a thread. Speakers, timestamps, permalinks, and attachments become one capture under the channel's audience. Unmapped channels and unauthorized reactors capture nothing.

Channels map to audiences in ops/slack-channels.json; the app manifest is deploy/slack-app-manifest.json.

From the backoffice

/admin on the app process, enabled by STIGMERGY_ADMIN_TOKEN_HASH, one master identity.

View
Capturespaste, upload, public URL; provenance, extraction, retries, commit, change
Changesplain-language summary, per-path diff, exact Git patch on demand
Contradictionslive list from current Markdown, resolution form
Entitiesscoped claims and provenance, evidence-backed merge and delete
Gardenerrun history and a manual trigger
Index healthrepository HEAD vs indexed commit, dirty flag, last full rebuild

MCP tools

The cloud server and the local bridge expose the same surface:

Tool
search_brain(query, filters?, max_results?)hybrid lexical + vector search
read_page(path)one visible page with links and citations
ask(question)a cited, verified answer — or an honest refusal
list_entities()identities with a name you may see
describe_entity(entity)knowledge composed from visible pages
brain_submit(text | path | url, title?, occurred_at?, audience?, resolution_of?)capture one input; the optional contradiction ID is master-only
brain_submissions(limit?, status?)capture progress
brain_delete(paths, why)explicit deletion with reference sweep

There is no kind. path and private Drive exist only in the bridge. An omitted audience uses your configured default, never organization-wide by accident.

Visibility and security

  • Every identity — whoever or whatever holds the token — has groups and a default audience in the knowledge repository's ops/identities.json; a page's acl is null or a list of groups. brain-admins is unrestricted.
  • One policy for reads and writes: server.acl.visible, kernel.acl.flows_into, 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.
  • Per-user bearer tokens from stigmergy-issue-token; 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.
  • Public fetching blocks private and metadata destinations and revalidates every redirect. Parsers detect types from bytes and enforce size, page, and decompression limits.
  • Secrets, tokens, presigned URLs, bytes, and restricted titles never enter logs. CI runs gitleaks.

Report vulnerabilities privately: SECURITY.md.

Models

One OPENROUTER_API_KEY, a closed allowlist in kernel.llm, same-model provider failover only, no model fallback or direct alternate-provider credentials, zero-data retention. Direct Anthropic, OpenAI, or Gemini credentials are rejected. The librarian's structured plans are routed to a host verified to return tool-call arguments intact, with the hosts known to corrupt them excluded from failover.

PurposeModel
filing and semantic repairdeepseek/deepseek-v4-flash
cited answersz-ai/glm-5.2
embeddingsqwen/qwen3-embedding-8b, 2560 dimensions
OCRqwen/qwen3-vl-8b-instruct

Query embeddings are bounded. A provider timeout degrades that request to ACL-scoped lexical ranking; indexing remains strict and never accepts an incomplete vector build. Serving connections — HTTP requests and the Slack adapter — bound every Postgres statement; workers and rebuilds keep the database default.

Quality and tests

The keyless suite — 1,100+ tests over real Postgres and Git, fake models, 75% coverage gate — is the contract. Optional real-model evaluations run over a frozen corpus and append to evals/history.ndjson. Latest run (2026-08-24):

MeasureResultBar
Retrieval Recall@5 (15 questions, 9 ACL-filtered)1.00≥ 0.80
Answer honesty1.00≥ 0.90
Answer groundedness1.00≥ 0.84
False-premise refutation1.00
make retrieval-golden EMBEDDER=openrouter
make qa-golden EMBEDDER=openrouter LLM=openrouter
make gates

Quick start

Python 3.12+, uv, Docker.

git clone https://github.com/sturlese/stigmergy.git && cd stigmergy
make venv
make db-up     # Postgres + pgvector, MinIO
make test
make lint

Index a knowledge repository and serve it over stdio:

export STIGMERGY_INDEX_DSN=postgresql://stigmergy:stigmergy@localhost:54321/stigmergy
stigmergy-index --rebuild --repo ../stigmergy-brain --embedder fake
stigmergy-server --transport stdio --repo ../stigmergy-brain \
  --identity you@example.com --embedder fake

Deployment

One image, three Fly process groups:

ProcessCommandRole
appstigmergy-server --transport httpMCP over HTTP, uploads, index webhook, backoffice
workerstigmergy-librarian-bootthe only writer and the scheduled gardener
slackstigmergy-slackSocket Mode adapter, one active instance
make deploy-staging
make rebuild-staging
AreaVariables
ModelsOPENROUTER_API_KEY, STIGMERGY_LIBRARIAN_MODEL, ANSWER_MODEL, STIGMERGY_OCR_MODEL
DatabaseSTIGMERGY_INDEX_DSN
Evidence storeSTIGMERGY_EVIDENCE_ENDPOINT, _BUCKET, _ACCESS_KEY_ID, _SECRET_ACCESS_KEY
ServerSTIGMERGY_PUBLIC_HOST, STIGMERGY_TOKEN_STORE or STIGMERGY_TOKEN_STORE_FILE
BackofficeSTIGMERGY_ADMIN_TOKEN_HASH, STIGMERGY_ADMIN_ACTOR
WriterSTIGMERGY_REPO, STIGMERGY_LIBRARIAN_REPO_URL, STIGMERGY_LIBRARIAN_APP_ID, _INSTALLATION_ID, _PRIVATE_KEY, STIGMERGY_LIBRARIAN_GARDEN_AT
Index webhookSTIGMERGY_GITHUB_WEBHOOK_SECRET, STIGMERGY_GITHUB_REPO, STIGMERGY_GITHUB_BRANCH
SlackSLACK_APP_TOKEN, SLACK_BOT_TOKEN, SLACK_TEAM_ID

Your team's knowledge is a separate private repository:

your-brain/
├── sources/YYYY/MM/<capture-id>.md
├── wiki/
│   ├── notes/
│   ├── concepts/
│   └── entities/ent_<uuid>.md
├── ops/
│   ├── identities.json            people, groups, default audience
│   ├── slack-channels.json        channel id → audience
│   └── entity-registry.json       derived, written by the platform
├── .claude/skills/librarian/SKILL.md
└── .github/workflows/             nightly index rebuild

Only the writer's GitHub App identity commits to wiki/, sources/, and the registry. Runbook: docs/OPERATIONS.md; reset: docs/RESET.md.

Repository layout

Package
kernelACL flow, deadlines, the model boundary, normalization
captureenvelopes, evidence, uploads, extraction and OCR, queue, sources
bridgethe local stdio MCP client
knowledgepage contracts, FilingPlan, writer, linter, repair, contradictions, write guard
entitiesopaque identities, claims, registry, merge, rename, delete
changesexact patches and the change ledger
indexcorpus selection, ranking, incremental updates, full rebuild, health
server · answerMCP tools, HTTP transport, webhook, verified answers
slackSocket Mode adapter
adminthe master backoffice
librarianthe writer process, bootstrap, Git and GitHub App transport, schedule
opsthe guarded non-production reset

Design principles

  1. Git and Markdown are current knowledge; Postgres is a rebuildable index.
  2. Every adapter produces the same kind-free CaptureEnvelope.
  3. Original bytes and source pages are immutable except through explicit deletion.
  4. One serialized writer: one commit and one change record per operation.
  5. Visibility is a write constraint.
  6. The librarian owns notes and concepts; entity pages hold identity only.
  7. No write waits for a human. Uncertainty is represented honestly.
  8. A health finding is preventable or autonomously repairable, or it is not a finding.
  9. Every capability is reachable through Slack, MCP, or the backoffice.

Rationale and acceptance criteria: specs/karpathy-team-wiki.md.

Documentation

Apache License 2.0.

Contributors

sturlese

359 commits

Languages

Python

97.8%

JavaScript

1.3%