
Plexus
io.github.pcas-ioPublished by GitHub account pcas-iov0.1.2Updated Oct 24, 2026
Typed on-prem knowledge graph for AI agents — read-only for humans, write-only for agents via MCP.
Overview
Plexus is a self-hosted, typed knowledge graph that gives an AI assistant persistent memory: it reads and writes entities and relations over MCP.
- What you can do
- Search, read and list typed entities, with BM25 full-text search and filters by kind, context and status, plus a session warm-up that loads recent entities and registries. Create, update and archive entities with optimistic locking, and link or unlink them with named, time-valid relations. Traverse the graph in either direction, including point-in-time queries as of a past date. Inspect the kind and relation registries and run a lint check for orphans and duplicate titles. Browse and load skills by name, trigger phrase or keyword search.
- When to use it
- Useful when an assistant should carry knowledge across sessions, agents or small teams instead of re-deriving it: decisions and ADRs, project and task tracking, incident and post-mortem records, research digests, or a private second brain. Best for people willing to run their own instance and let the agent do the curation.
- Requirements
- A self-hosted deployment (Docker Compose on your own hardware) with a SurrealDB backend, reachable at your own host over HTTPS at the MCP endpoint. Required environment variables include PLEXUS_ADMIN_TOKEN, PLEXUS_OAUTH_SECRET, PLEXUS_COOKIE_SECRET and PLEXUS_SURREAL_PASS. Agents authenticate with a personal token sent as an Authorization Bearer header, or through the built-in OAuth flow; humans sign in with passkeys.
Installation
In SourceWeft
- Open Plexus in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Web executable via Streamable HTTP. Remote servers run from the web runtime once configured in a workspace.
Other MCP clients
Follow the launch instructions in the repository.
README
plexus (_graph)
A typed, on-prem knowledge graph for AI agents. Read-only for humans, write-only for agents, spoken over the Model Context Protocol.
Part of the pcas.io product line.
[plexus graph view — Apollo-program demo graph]
TL;DR
Knowledge management has been a document sport for twenty years — folders, notes, wikis, editor wars. plexus inverts that.
In plexus, every piece of information is a typed entity — concept, decision, fact, project, task, document, skill, … — with hard, temporally-valid edges between them. No free-form text, no forgotten tags, no "I'll clean that up later." Writing and linking happen exclusively through MCP — from your agent. The dashboard shows you the graph; it has no edit buttons.
That gets you three things:
- Your agent doesn't have to ask you — it just builds, with strict kind-and-relation discipline.
- The graph never goes stale, because lint, supersede, and provenance are part of the workflow.
- You can share a single idea, not your graph — passkey-gated one-shot links that burn on first click.
Runs in Docker Compose on your own hardware. Apache-2.0 licensed.
Think of it as a wiki, but for LLMs
Traditional wikis are built for human readers: free-form prose, hand-curated links, a tree of pages that rots the moment you stop grooming it. Put an LLM in front of one and the first thing the LLM does is ask you to summarise it.
plexus reverses the audience. The LLM is the reader and the writer. Each page is a typed record instead of a paragraph, each link is a named relation instead of a hyperlink, and each edit is an atomic MCP call instead of a markdown diff. The UI shows you the same graph your agent sees — but your agent does the curation.
This is the same pattern Andrej Karpathy sketched in his "The LLM wiki" gist (April 2026, 5000+ stars): instead of stateless RAG against raw documents on every query, an LLM compiles knowledge into a structured, cross-referenced wiki once and keeps it up to date. plexus is that pattern on infrastructure:
Karpathy calls the gist an "idea file" — a vendor-neutral prompt pattern. plexus gives it a production backend: typed storage, optimistic locking, temporal edges, multi-user auth, audit log.
What that buys you:
- One source of truth across sessions. Your agent loads the context at the start of every conversation. You don't re-explain yourself.
- One source of truth across agents. Claude web, Claude Code, Claude Desktop, Le Chat, Gemini — whoever connects speaks the same graph.
- One source of truth across humans. Multi-user out of the box, scoped tokens per person, shared
projectcontainers, audit log.
Contents
Understand it
- Use cases — seven concrete scenarios plexus is built for
Run it
- Quickstart — Docker Compose up in under two minutes
- Create your admin user (first run) — the bootstrap walk-through, including where to find the admin token
Wire an agent to it
- Connecting an agent — Claude web / Code / Desktop snippets
- Agent system-prompt template — copy-paste block that makes an LLM use plexus correctly
- Example: ingesting a source — a Karpathy-style LLM-wiki ingest walked end-to-end against plexus
Reference
Operate it
Use cases
Persistent agent memory. Every conversation starts with context_load, so your assistant remembers which ADRs you've already made, which projects are live, and which tasks you finished yesterday. No "as you might recall…" prompt engineering.
Cross-agent handoff. Claude Code finishes a feature, writes a handoff-fact. Next morning Claude web picks up the same context, knows which commits shipped, what's still open. Zero re-briefing.
Team memory for small groups. Spin up one instance, issue scoped personal tokens per person, share a project container. Read-only dashboard for everybody, agents write for everybody. No Notion, no wiki, no Slack-archaeology.
Decision archaeology. Every ADR is a first-class decision entity with supersedes / derived_from edges. A year later you can trace why the F-1 engine stayed, what the Apollo 13 post-mortem triggered, and which design superseded which. Time-travel queries via get_related(as_of: "2026-01-01").
Incident → fix loop. A production incident becomes a fact with severity: high. The mitigation ADR links triggered_by that fact. The runbook documents the ADR. When you hire someone six months later, they read one graph walk instead of twelve Slack threads.
Literature / research digest. An agent ingests a paper, creates a note for the source, extracts concept and fact entities, attaches mentions edges. You query the graph by topic; every claim has provenance back to a derived_from note.
Private "second brain" that an agent actually uses. Capture with inbox_item, promote to task/concept/fact during a weekly review, archive with supersedes. Your notes are structured without you having to touch a form.
Quickstart
The admin token you'll need for the very first login is in .env:
Copy that hex value — the next section walks through the one-time bootstrap.
Full configuration reference is in .env.example. Deployment notes for Coolify, plain Docker, and Kubernetes are below.
Create your admin user (first run)
plexus boots on an empty database with no user. You'll use your PLEXUS_ADMIN_TOKEN once to create the first admin account, then it steps aside.
1. Find your admin token
The scripts/bootstrap_env.sh script you ran in the Quickstart wrote the token into your .env. Read it back:
Copy the hex value after the =. You'll paste it once into the dashboard; after the bootstrap, plexus rejects the admin token on MCP and on normal login.
2. Walk the flow
From here on, the admin token is only used for admin-plane endpoints (backup, reset). It's rejected on MCP and on normal dashboard login.
Why the rotation?
The initial tokens (admin + first pt_) are one-shot invitation codes. If anything intercepted them — mail, chat, a screen share — rotation makes that capture worthless the moment you sign in. For additional users you create via /users, the same admin→user handoff + first-enroll rotation protects them the same way.
Where to go next
The /help page inside the dashboard covers everything else: MCP integration, token scoping, passkey management, share links, graph view.
[plexus help page — first-run bootstrap documentation]
Connecting an agent
plexus speaks Model Context Protocol over POST /mcp. Any MCP-capable client can connect.
Claude.ai (web)
Settings → Integrations → Add Custom Integration → https://<your-plexus-host>/mcp. plexus handles OAuth automatically — you'll see a consent screen once.
Claude Code (CLI)
Claude Desktop
In ~/Library/Application Support/Claude/claude_desktop_config.json:
MCP tools
plexus exposes 15 tools.
Every tool enforces scope at the handler boundary: requireWrite(), checkContext(), checkKind(), and rejectSecret(). kind=secret is unreachable via MCP and filtered out of every read response.
[plexus dashboard home — projects, activity feed, context filter]
Agent system-prompt template
Paste this block into any MCP-capable agent (Claude web custom integration, Claude Code CLI, Claude Desktop, Le Chat, a custom SDK harness). It's written tight on purpose — every line earns its place. Model-agnostic; works with any LLM that supports MCP tool-calling.
Tighten per agent role. Issue distinct personal tokens with narrow scope instead of one all-powerful token:
- Writer agent (Claude Code CLI):
permission=write, all contexts, all kinds. - Reader widget (a dashboard, a monitoring job):
permission=read, singlecontexts: [dev], no secrets. - Domain-specific agent (e.g. a research summariser):
permission=write,kinds: [note, concept, fact]only.
The dashboard's /tokens page generates any of these in two clicks.
Example: ingesting a source
Here's what the Karpathy-style ingest loop looks like when an agent actually runs it against plexus. The user drops an article; the agent walks the five phases of the LLM-wiki pattern using only plexus tools, and leaves the graph richer in under a minute.
User: "Pull this in: https://example.com/engineering/feature-flags-at-scale"
1 — Classify & orient. The agent fetches the source, classifies it as article, and checks what already exists so it doesn't duplicate:
2 — Extract. For an article the agent pulls key claims, new facts, decisions, and anything that contradicts existing entities.
3 — Write typed entities. One kind per intent; update existing ones instead of creating duplicates.
4 — Anchor provenance. Every ingest creates exactly one note as the provenance anchor, and every extracted entity links back to it with derived_from:
5 — Dual output. Reply to the user and the graph update — both happen in the same turn, not as a chore for later.
Agent's reply:
Ingested Acme's feature-flag post. 2 new entities, 1 existing concept enriched, 3
derived_from/mentionsedges to the new source note (entities:ef56…). Shadow-flag pre-rollout doesn't contradict the existing rollout ADR — they're complementary.
Six months later, someone asks your agent "how did we end up on shadow flags?" Your agent does search_entities({ query: "shadow flag rollout" }), get_related on the hit to pull the source note and the ADR that cited it, and answers from the compiled graph instead of re-reading the raw HTML. No re-summarisation. No "as you might recall." The wiki already holds the answer.
What the graph knows
Kinds
Relations
contains / part_of · relates_to · depends_on / blocks · supersedes / superseded_by · documents / documented_by · implements · produces / produced_by · consumes · mentions · derived_from · triggered_by · has_version · variant_of · executed_by · owned_by
Every edge carries valid_from, valid_to, confidence, and source (manual / llm-inferred / computed / imported). unlink_entity sets valid_to = now; the edge survives as history. get_related(as_of: …) gives you the graph state at any point in the past.
[plexus entity detail — ADR with markdown body, attributes, and typed relations]
Authentication
For humans: passkeys
The dashboard is passkey-only. Token + passkey at first login rotates the token automatically — the initial token is a one-shot invitation code that dies on enrollment. Up to 3 passkeys per user (laptop, phone, hardware key); the last one cannot be deleted.
For agents: personal tokens and OAuth
Personal tokens (pt_…) are first-party, self-service tokens issued from the dashboard with an explicit scope: permission × contexts × kinds × expires_in_days. Use them for claude code, CLI automation, or any MCP client you trust with a long-lived credential.
OAuth 2.1 tokens (ot_…) are for third-party MCP clients. plexus ships a full authorization server:
- Discovery via RFC 8414 (Authorization Server Metadata) and RFC 9728 (Protected Resource Metadata).
- Dynamic Client Registration (RFC 7591).
- PKCE with
S256is mandatory;plainis rejected by schema and code. - Resource indicators (RFC 8707) on both authorize and token endpoints.
- Exact-match redirect-URI comparison in constant time.
- Token rotation on refresh — the old refresh token is revoked the moment a new one is issued, enabling compromise detection.
Admin tokens are rejected on /mcp with a hard 403. There is no "just use the admin token" escape hatch.
Sharing
You can share a single entity as a read-only one-shot link, without handing out your graph.
- Open the entity in the dashboard. Click Share.
- Step-up passkey prompt with purpose-binding (
stepup:share:<userId>) — a share challenge cannot be replayed as a reset challenge. - plexus issues a 32-byte
st_token. Only the SHA-256 hash is stored. The URL is shown once. - The recipient opens
GET /share/:token— no login required, rate-limited, read-only. - Second call returns
410 Gone. You can revoke at any time.
One share URL, three formats:
kind=secret entities cannot be shared — the check happens before token creation.
Search
search_entities runs on a SurrealDB BM25 index with a custom analyzer (plexus_text):
blank+classtokenizers,lowercase+asciifilters (Unicode-to-ASCII folding —ümatchesu,ßmatchesss).- Two indexes:
entities_title_searchandentities_body_search. - Ranking:
search::score(0) * 2 + search::score(1)— title weighs twice. - Optional highlighting wraps matches in
<mark>tags. - Optional
body_preview_chars(0–2000) to cap response size — recommended for wide queries.
[plexus entities browser — BM25 search with match highlighting]
Architecture
Source layout
File-size soft cap: ~700 lines. Files that grow past that get split by responsibility.
Configuration
All configuration is via environment variables. See .env.example for the full list with defaults.
Generate high-entropy secrets:
Self-hosting
Docker Compose (recommended)
The shipped docker-compose.yml brings up the plexus worker and SurrealDB together. The worker is published on 127.0.0.1:8787 — localhost only — so a typo in a public DNS record cannot accidentally expose the dashboard. Put a reverse proxy in front for anything beyond your own machine.
For Coolify hosts, stack the Coolify overlay on top to attach the external coolify Traefik network and pin the routing label:
Behind a reverse proxy
plexus expects TLS in production. The dashboard sets Secure cookies and will misbehave over plain HTTP outside of localhost. Use a proxy such as Caddy, Traefik, or nginx; a minimal Caddy config is in Caddyfile.
The CSP header pins cdn.jsdelivr.net for D3 (with an SRI hash). If you serve the dashboard behind a different CDN, update the CSP in src/index.ts accordingly.
Backups
The export contains entities, edges, kinds, relations, and users (without token hashes). It does not contain sessions, passkeys, OAuth tokens, personal tokens, or share tokens — credentials and session state are never backed up. Pass ?include_audit=1 to include the last 1000 activity-log rows under a separate filename (opt-in because those rows contain personal data).
Development
Quality gates:
See CONTRIBUTING.md for commit conventions, PR expectations, and design principles we enforce during review.
Security
- Markdown is rendered through an allow-listed URL parser; links carry
rel="noopener nofollow ugc". - Attribute payloads are capped at 64 KB and rejected at the Zod boundary; prototype keys (
__proto__,constructor,prototype) are stripped recursively. - Token generation uses rejection sampling over base62 to avoid modulo bias.
- WebAuthn challenges are stepped-up with purpose binding for sensitive operations.
- The login error path returns a uniform
LOGIN_FAILregardless of which of (user, passkey, rate-limit) failed — no user enumeration. kind=secretis unreachable via MCP, non-shareable, and admin-only in the dashboard with a step-up passkey.
Report vulnerabilities privately — see SECURITY.md. Do not open a public issue for security matters.
Licence
Apache License 2.0. See LICENSE.
plexus and pcas.io are trademarks of the pcas.io project. The Apache licence covers the code; it does not grant trademark rights.
Acknowledgements
plexus is built on SurrealDB, Hono, the Model Context Protocol SDK, SimpleWebAuthn, Zod, and D3.
Source: README.md at commit 833df34
Tools
0Version history
1- v0.1.2LatestSep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 daysRequired25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declaredRequired10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts