Using Theurian with Serena
Theurian does not replace Serena, and it must never be built to. They answer different questions, and an agent that has both is meaningfully better than one with either.
The split
| Theurian | Serena |
|---|---|
| What did we decide, and why? | Where is this symbol defined? |
| Was this approach rejected before? | Who calls this function? |
| What does the specification require? | What is this type's hierarchy? |
| Which tests verify this spec? | What are this symbol's references? |
| What did review say about this pattern? | What is the current code shape? |
| Has the spec drifted from the code? | — |
| Which knowledge governs these files? | — |
Put another way: Serena knows what the code is. Theurian knows what the team decided. Serena reads the present through a language server. Theurian reads the accumulated record, with provenance and validity.
They never call each other
flowchart TB
subgraph CC["Claude Code"]
AGENT["Agent"]
end
AGENT -->|"MCP"| T["Theurian MCP<br/>http://127.0.0.1:7419/mcp"]
AGENT -->|"MCP"| S["Serena MCP<br/>(its own transport)"]
T --> TK[("Knowledge, specs,<br/>reviews, traceability")]
S --> SC[("Language server:<br/>symbols, references, types")]
T -.->|"never"| S
S -.->|"never"| T
Theurian must not call Serena internally, and Serena's capabilities must not be reimplemented inside Theurian Core. Two independent MCP servers, composed by the agent. That keeps each one replaceable: a team that prefers a different code intelligence tool swaps Serena out and Theurian is unaffected.
Configuring both
They are independent MCP servers. Theurian is HTTP (never stdio — see below); Serena is configured however Serena documents.
/theurian:setup writes only its own entry, merging into your existing
configuration and leaving every other server byte-for-byte unchanged. If Serena
is already configured, setup detects it and reports:
✓ Serena MCP detected
✓ Theurian and Serena can be used together
Resulting user-scope configuration:
{
"mcpServers": {
"theurian": {
"type": "http",
"url": "http://127.0.0.1:7419/mcp",
"headers": { "Authorization": "Bearer ${THEURIAN_MCP_TOKEN}" }
},
"serena": {
"command": "...",
"args": ["..."]
}
}
}
Serena being stdio is fine. Serena is stateless per client and holds no shared write-side state, so one process per client costs memory and nothing else.
Why Theurian is never stdio
Because Theurian is not stateless.
A stdio MCP server is spawned once per client. In Claude Code that means one per session and, in practice, one per subagent. For Theurian that would be:
- N processes opening write connections to one SQLite database;
- N independent index builders racing on the same files;
- N copies of every cache, with none of the benefit;
- no single publisher, so a partially built index could become visible.
The failure mode is not slowness — it is corruption. Every agent therefore shares one daemon over Streamable HTTP. (ADR-0002)
If you ever see a theurian entry with a command field, that is a bug. Run
/theurian:doctor.
All subagents use the same URL
Nothing special is required. Because the connection is an HTTP URL rather than a spawned process, every agent that inherits the MCP configuration — main agent and subagents alike — connects to the same daemon. Ten subagents produce ten connections to one process, and they share a warm index.
A workflow that uses both
flowchart TB
A["1. spec.get<br/>what are we supposed to build?"] --> B["2. knowledge.search<br/>what have we already decided?"]
B --> C["3. review.findSimilar<br/>has this come up in review?"]
C --> D["4. Serena: find_symbol<br/>where does this live?"]
D --> E["5. Serena: find_referencing_symbols<br/>what would break?"]
E --> F["6. Implement"]
F --> G["7. trace.findTests<br/>what verifies this?"]
G --> H["8. spec.getCoverage<br/>did we miss anything?"]
style A fill:#1f6f4a,color:#fff
style B fill:#1f6f4a,color:#fff
style C fill:#1f6f4a,color:#fff
style G fill:#1f6f4a,color:#fff
style H fill:#1f6f4a,color:#fff
style D fill:#5a3a7a,color:#fff
style E fill:#5a3a7a,color:#fff
Steps 1–3 are Theurian: understand the intent and the history before touching anything. Steps 4–5 are Serena: understand the code as it is now. Steps 7–8 are Theurian again: verify the change is traceable.
Skipping 1–3 is how an agent reimplements something the team rejected last quarter. Skipping 4–5 is how it edits the wrong call site.
Worked example
"Add a cancellation deadline check to the order service."
| Step | Call | What comes back |
|---|---|---|
| 1 | spec.get("spec.order-cancellation") |
preconditions, rules, outcomes — structured, not prose |
| 2 | knowledge.search("order cancellation deadline") |
ADR on transaction boundaries; a runbook noting cancellation is idempotent |
| 3 | review.findSimilar("deadline check") |
PR #431 thread: an earlier deadline check was rejected for running after the state mutation |
| 4 | Serena find_symbol("cancelOrder") |
src/orders/service.ts:142 |
| 5 | Serena find_referencing_symbols |
three call sites, one in a scheduled job |
| 6 | — | implement, with the ordering constraint from step 3 |
| 7 | trace.findTests("spec.order-cancellation") |
one integration test; no unit test for the deadline path |
| 8 | spec.getCoverage |
CANCELLATION_NOT_ALLOWED outcome is untested |
Step 3 is the one that is hard to get any other way, and it is the step that prevents shipping the same mistake twice.
Which tool for a given question
flowchart TD
Q["What are you asking?"] --> D1{"Is it about<br/>intent, history,<br/>or a decision?"}
D1 -->|yes| T["Theurian"]
D1 -->|no| D2{"Is it about<br/>the current code<br/>structure?"}
D2 -->|yes| S["Serena"]
D2 -->|no| D3{"Does it link<br/>a spec to code<br/>or tests?"}
D3 -->|yes| B["Both: Theurian for the link,<br/>Serena for the code"]
D3 -->|no| E["Probably neither"]
style T fill:#1f6f4a,color:#fff
style S fill:#5a3a7a,color:#fff
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Theurian tools missing | Setup not run | /theurian:setup |
| Theurian returns 401 | THEURIAN_MCP_TOKEN not in the environment — common when Claude Code is launched from a GUI rather than a shell |
/theurian:doctor explains the fix |
| Serena disappeared after setup | Would be a bug: setup merges, never replaces | Restore the timestamped backup and file an issue |
| Both configured, results conflict | They answer different questions | Trust Serena on code shape, Theurian on intent |
A theurian entry with command |
Misconfiguration | Remove it and re-run /theurian:setup |