[{"localId": "https://terraphim.ai/releases/", "https://atomicdata.dev/properties/name" : "Releases", "https://terraphim.ai/properties/url" : "https://terraphim.ai/releases/", "https://atomicdata.dev/properties/description" : "

Releases

\n

Stay up-to-date with the latest Terraphim AI releases.

\n

Latest Release: v1.21.22

\n

Released: 15 October 2026

\n

GitHub Releases | Release Notes

\n

Self-Update (recommended)

\n

If you already have a Terraphim client installed, update it with a single command — no GitHub credentials, no rate limiting:

\n
terraphim-agent update\nterraphim-grep update\n
\n

The self-update backend is served from our R2 bucket (downloads.terraphim.ai) with Ed25519 signature verification. GitHub Releases is an automatic fallback if R2 is unreachable.

\n

Quick Install

\n
curl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n
\n

Direct Downloads

\n

Binaries are distributed via Cloudflare R2 with zero-egress CDN. Browse the manifests:

\n\n

The stable-v2.json manifests carry the version, release date and a SHA-256\ndigest plus size for every published archive. The older stable.json pointers\nare still served for pre-1.21.15 clients.

\n

Download the latest archive for your platform directly:

\n
curl -fsSLO "https://downloads.terraphim.ai/terraphim-agent/terraphim-agent-1.21.22-x86_64-unknown-linux-gnu.tar.gz"\ntar -xzf terraphim-agent-1.21.22-*.tar.gz\nsudo mv terraphim-agent /usr/local/bin/\n
\n

Available Binaries

\n

v1.21.22 ships across three client tools:

\n\n

Platforms:

\n\n\n\n\n\n\n\n\n
PlatformAgentGrepCLI
Linux x86_64 (GNU)✓✓✓
Linux x86_64 (MUSL)✓✓✓
Linux ARM64 (MUSL)✓✓✓
macOS Apple Silicon✓✓✓
macOS Intel✓✓✓
macOS Universal✓✓—
Windows x64———
\n

Native Windows archives are unavailable on the current stable channel. Use WSL\nor build from source.

\n

All Linux and macOS archives are Ed25519-signed and verified on install by the self-updater. macOS universal binaries are additionally notarised by Apple.

\n

Installation and release integrity

\n

Public install path corrected

\n\n

Version reporting and exit codes

\n\n

Release integrity

\n\n

Installation

\n

Self-update

\n
# Already have terraphim-agent?  Update in-place.\nterraphim-agent update\nterraphim-grep update\n
\n

Universal installer

\n
curl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n
\n

Cargo

\n
cargo install terraphim_agent --features repl-full\n
\n

Homebrew

\n
brew tap terraphim/terraphim && brew install terraphim-agent\n
\n

Installation Guide

\n

All Releases

\n

View complete release history on GitHub Releases (terraphim-clients).

\n

Release Channels

\n

Stable

\n

Stable releases are recommended for production use. They are thoroughly tested and signed. The self-updater fetches signed archives from downloads.terraphim.ai by default.

\n

Latest Stable: v1.21.22

\n

Development

\n

Development releases contain the latest features and improvements. Use these for testing.

\n

Check the main branch for development builds.

\n

Upgrade Guide

\n

From Any Version to Latest

\n
# Self-update (recommended, no GitHub token needed)\nterraphim-agent update\n\n# Or via the universal installer\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n
\n

Configuration Compatibility

\n

Terraphim maintains backward compatibility for configuration files across minor versions. Major version bumps may require configuration updates.

\n

Verify Your Installation

\n
terraphim-agent --version\nterraphim-agent check-update\n
\n

Security & Integrity

\n\n

Beta Testing

\n

Want to test new features before they're released?

\n

Join our Discord server and look for #beta-testing channel. Beta testers get early access to new features and help shape the product.

\n

Need Help?

\n

If you encounter issues with a release:

\n
    \n
  1. Search existing issues
  2. \n
  3. Create a new issue
  4. \n
  5. Join Discord community for support
  6. \n
\n

Previous Release: v1.20.5

\n

Released: 14 June 2026

\n

The final release distributed exclusively through GitHub Releases before the R2 migration. v1.20.5 binaries remain available on GitHub and will continue to be served as the GitHub fallback. From v1.21.9 onward, all releases are published to both GitHub and R2.

\n", "https://terraphim.ai/properties/date" : "2026-07-08", "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/how-tos/synonym-search/", "https://atomicdata.dev/properties/name" : "Different words. The same idea.", "https://terraphim.ai/properties/url" : "https://terraphim.ai/how-tos/synonym-search/", "https://atomicdata.dev/properties/description" : "

Your project brief says risk. Later, you search for concern. Terraphim connects the two so a change of wording does not hide the decisions you need.

\n

The inspiration came from Jason Fried’s original Write_On video and its idea of “alternative control”. It prompted Alex Mikhalev to return to Terraphim Editor, a Rust/WebAssembly project he had abandoned two years earlier, with a clear purpose: connect wording alternatives to a reusable knowledge graph and carry that meaning into search.

\n

\n

Try Terraphim Editor · Install for VS Code · Read the narration

\n

Choose the words that fit

\n

In our community garden brief, timber might arrive late. The team has decided to keep a backup supplier. Add Concern as an alternative to Risk, then swap between them. The other wording stays attached to the document.

\n

Share what those words mean

\n

Open Knowledge graph from the Markdown export menu. The editor shows Risk ↔ Concern and its actual definition:

\n
synonyms:: Risk, Concern\n
\n

Download the graph and the clean text. This explicitly shares the document's authored synonym groups as a Terraphim thesaurus; it does not silently change your active role. The saved example contains Risk, with no literal occurrence of Concern.

\n

Find the decisions using either word

\n

Use the graph downloaded from that editing session:

\n
terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --search-only --json\n
\n

The actual result contains three risk passages and their related decisions, with file and line locations. No generated answer is requested.

\n

Replace --search-only with --answer for synthesis:

\n
terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --json --answer\n
\n

The video shows the generated summary and its references to the same three passages. Decisions remain decisions: the source does not establish whether they have been carried out. Check the evidence alongside any generated answer.

\n

Editing and local search use your local data. Optional synthesis sends the retrieved passages to your configured model provider.

\n

See the same workflow in Kilo

\n

This supplier brief says Risk. Search for Concern using its exported graph, and both retrieval and synthesis find the same three passages. The generated answer points back to the brief's decisions and actions.

\n

\n

A 44-second replay of saved tool results in Kilo, with captions and no audio. It shows the saved Risk/Concern alternative, source lines and cited summary. The Kilo skills are under marketplace review; this is a configured integration.

\n

Download the brief, graph and actual results · Kilo setup guide · Recorded versions and checksums

\n

Try it with an Obsidian vault

\n

Keep the words that describe a concept in the note that owns it. In this example, Risk.md contains the actual synonyms:: Risk, Concern property and embeds the community garden brief. The separate brief still says risk, never concern. The search-results note contains saved passages, with no synonym definition.

\n
\"Obsidian
Captured in Obsidian 1.14.4. The knowledge note owns the synonyms; Obsidian displays saved CLI results.
\n

Download the Obsidian demo vault ZIP. Extract it, open the included obsidian-demo/vault folder as an Obsidian vault, and open Notes/Risk.md. Open Search results/Concern search.md alongside it to inspect the saved output. No community plugins are required.

\n

To reproduce the retrieval, install terraphim-grep v1.21.19, open a terminal in the extracted vault directory, and run:

\n
terraphim-grep concern --thesaurus "Knowledge graph/baseline-role.json" --paths "Notes/Projects" -C 2 --json --search-only\nterraphim-grep concern --thesaurus "Knowledge graph/knowledge-graph.json" --paths "Notes/Projects" -C 2 --json --search-only\n
\n

The released binary returned zero passages with the baseline graph and three exact risk-and-decision passages with the exported graph, at lines 7, 10 and 13. The commands search only the project brief directory, excluding the concept definition and saved results. Inspect the baseline output, synonym output, execution receipt and file checksums.

\n

Terraphim’s synonyms:: convention uses Logseq-compatible Markdown property syntax. Obsidian’s native aliases use YAML aliases. This example supplies the same graph exported by the editor explicitly: saving a note does not automatically rebuild the graph or synchronise the vault. Search runs in the CLI; Obsidian displays the notes and saved results. The capture reruns local retrieval only; the video above shows the separate synthesis comparison.

\n

Try it with a Logseq graph

\n

Prefer linked blocks? Open the same garden project in Logseq. The Risk concept page owns the wording relationship and embeds the project brief. Its properties are:

\n
alias:: Concern\nsynonyms:: Risk, Concern\n
\n

alias:: gives the page another name inside Logseq. Terraphim’s synonyms:: property records the words connected by the exported search graph.

\n
\"Logseq
The imported graph in Logseq 2.0.2: wording belongs to the concept page; the sidebar shows saved CLI passages.
\n
\"The
Explore the garden brief’s connections in Logseq’s graph view. The arrows show page links; the Risk note holds the synonym definition used by the supplied Terraphim search graph.
\n
    \n
  1. Download the Logseq example ZIP and extract it.
  2. \n
  3. In Logseq 2.0, choose Import existing notes → File to DB graph, then select the included graph folder. If you use a Logseq version with file graphs, open that folder directly.
  4. \n
  5. Open Start here, then Risk. Search for Concern search and choose Open in sidebar to compare the saved results with the project note.
  6. \n
\n

From a terminal in the extracted graph folder, run:

\n
terraphim-grep concern --thesaurus baseline-role.json --paths pages/Projects -C 2 --json --search-only\nterraphim-grep concern --thesaurus knowledge-graph.json --paths pages/Projects -C 2 --json --search-only\n
\n

The first search returns zero passages. The shared synonym graph brings back three decisions: keep a backup supplier, reserve a covered area and keep a volunteer reserve list. The commands search only the project notes, leaving concept definitions and saved results outside the search.

\n

Compare the baseline and synonym search output, or follow the download instructions. The CLI reads the included Markdown files; Logseq 2.0 imports a copy into its database. Use the extracted folder for these commands. File checksums are included.

\n

Try it yourself

\n
    \n
  1. Download the complete example ZIP. It includes the project brief, synonym graph and a step-by-step README.
  2. \n
  3. Install terraphim-grep for macOS or Linux.
  4. \n
  5. Extract the ZIP and follow the README to search the brief, first without the synonym relationship and then with it. Add --answer when you want a summary alongside the source passages.
  6. \n
\n

Searching for concern returns no passages before the graph is shared. With the graph, it finds all three risk passages and their related decisions. Compare the saved results before sharing, with the synonym graph, and with a generated summary.

\n

Then try the same steps with a pair of words from your own project notes.

\n

Explore the files

\n\n

The video uses a sample project brief and synthetic British English narration. The graph and search results are saved outputs from the demonstrated workflow. Recording details and versions, commands and file checksums are available with the downloads.

\n

Explore more editor walkthroughs.

\n", "https://terraphim.ai/properties/date" : "2026-10-11", "https://terraphim.ai/properties/tags" : {"tags":["editor","knowledge-graph","search"],"categories":["How-tos"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/how-tos/command-rewriting-howto/", "https://atomicdata.dev/properties/name" : "A failed command, a saved correction, and the next run", "https://terraphim.ai/properties/url" : "https://terraphim.ai/how-tos/command-rewriting-howto/", "https://atomicdata.dev/properties/description" : "

A coding agent uses the wrong flag. You explain the correction, and the command works. The useful question is what happens when another session makes the same mistake.

\n

This walkthrough follows one harmless error from failure to saved correction to actual execution. Each execution now has one record linking the model’s request, the matching rewrite rule, the command the tool ran and its saved result. It uses the Harbour project brief from the memory walkthrough, a released Terraphim agent, and an OpenCode adapter included in the download.

\n\n

Download the Harbour hooks example · Read the transcript

\n

Start with the command that fails

\n

Harbour's validator checks that its brief contains a decision, a risk and an owner. The correct command ends with --check. In the baseline run, OpenCode actually attempts:

\n
python3 validate-brief.py --chek\n
\n

The argument is misspelled. Python's argument parser reports that --check is required and exits with status 2. No validation.json is created. The downloadable trace contains the host's actual tool result, including that output and exit status.

\n

That distinction matters: the coding host itself can finish normally after reporting a failed tool. Its overall process exit code is not evidence that the validator succeeded. Here we inspect the shell tool's result and the expected output file.

\n

Capture the failure that really happened

\n

The included project-local adapter receives OpenCode's after-tool event. It translates the real command, combined output and exit status into Terraphim's learning-hook schema, then calls the released agent.

\n

The saved Markdown learning contains the command, exit code 2 and the parser's actual error. A new CLI process can list it again. This gives the correction a concrete source: an observed failure, with a saved record that can be inspected.

\n

The adapter is part of this example. In the tested release, passing a native OpenCode event directly with --format opencode does not by itself establish that a learning was captured. The script checks the resulting file and later readback.

\n

Review and promote the correction

\n

We add the intended command to the failure record with learn correct. That records a proposed correction. It does not automatically make it a replacement rule: compiling the failure record alone produces zero correction entries in this release.

\n

The next step is explicit human review and promotion to a tool preference. Here, “review” means checking the intended correction; it is not a built-in approval gate. The reproduction script runs this command inside its isolated store:

\n
terraphim-agent learn correction add \\\n  --correction-type tool-preference \\\n  --original 'python3 validate-brief.py --chek' \\\n  --corrected 'python3 validate-brief.py --check' \\\n  --context 'Manually reviewed correction from the captured failure'\nterraphim-agent learn compile --output compiled-corrections.json\nterraphim-agent learn export-kg --output kg\n
\n

Compilation now reports one correction. The selected Harbour Validator role loads that compiled JSON. The exported Markdown makes the relationship readable:

\n
# python3 validate-brief.py --check\nsynonyms:: python3 validate-brief.py --chek\n
\n

This uses the same explicit synonyms:: idea as the editor-to-search flow. The correction says which command this project prefers. In this walkthrough the hook reads the compiled JSON; exporting a Markdown file alone is not the activation step.

\n

Inspect the hook before involving execution

\n

First we call the pre-tool hook on a saved input. Without --rewrite, the returned command keeps --chek and includes a warning about a replaceable match. With --rewrite, the returned JSON contains:

\n
{\n  "tool_input": {"command": "python3 validate-brief.py --check"},\n  "tool_name": "Bash"\n}\n
\n

That is a hook result. It has not executed Python. The example retains both results so you can compare the disabled and enabled behavior. An unrelated command and a role without this correction remain unchanged.

\n

\"The

\n

Verify what the coding host actually runs

\n

Now start a fresh OpenCode process and ask it to try the same misspelled command. Its before-tool event reaches the adapter. The adapter calls Terraphim with rewriting enabled, then applies the returned command through OpenCode V2's mutable tool input.

\n

The after-tool event records python3 validate-brief.py --check. Its exit status is 0. The validator prints a valid Harbour result and writes evidence/executions/<execution_id>/validation.json:

\n
{\n  "execution_id": "19578f09-a59a-4e80-be31-7d319b0c9368",\n  "project": "Harbour",\n  "status": "valid",\n  "fields": ["Decision", "Risk", "Owner"]\n}\n
\n

The host transcript can still display the model's original requested input. The hook changes the command; OpenCode executes it. Inspect the actual after-tool event to establish what ran.

\n

Keep one execution’s evidence together

\n

The included adapter records an execution ID alongside the host’s session and tool-call IDs. Its receipt.json links:

\n\n

The validator embeds the same execution ID in its printed result and saved file. The verifier checks those values against the native host events and rehashes the graph and output. A stale file, mismatched command, unmatched host call, missing artifact or altered bytes fails verification. A blocked call is retained without being labelled executed.

\n

Inspect the execution receipt, saved result and run verification.

\n

\"The

\n

This recorder covers the example’s sequential, whole-command mapping. It rejects overlapping fixture calls and unsupported rule attribution; it is not a general multi-rule provenance system.

\n

\"The

\n

Reproduce it in a new folder

\n

The example was verified with terraphim-agent v1.21.19 and OpenCode 2.0.20. The download includes the new adapter source, version 2.0.0; it is separate from the earlier binary release. Follow the ZIP's README to check the release archive, choose your already authenticated coding model and run from the extracted folder:

\n
python3 reproduction/reproduce.py \\\n  --agent /absolute/path/to/terraphim-agent \\\n  --model kimi-code-plan-global/k3 \\\n  --output /absolute/path/to/a-new-harbour-run\n
\n

Use your configured model identifier if it differs. The script uses a new folder for the fixture, settings, learning store and project-local adapter. It does not install global hooks or select a paid fallback. The recorded run used the existing Kimi coding-plan route.

\n

Run node reproduction/verify.mjs /absolute/path/to/a-new-harbour-run to check the saved evidence. Read evidence/verification.json, the host events and each execution’s receipt.json and validation.json. The ZIP also includes 22 regression tests, runnable with node --test tests/*.test.mjs. The script fails if the host does not perform the expected command or the saved outputs do not match. You can inspect the source before running it; only the two local validator commands are permitted by the fixture's host configuration.

\n

Keep the scope of the example visible

\n

This demonstrates one reviewed correction with one tested host adapter. It does not prove every coding host applies the same JSON, or that failure capture should automatically approve arbitrary substitutions. The earlier memory example and this learning store also remain separate; neither silently copies into the other.

\n

Use public sample data for this release's learning capture. Tests with deliberately fake secret-shaped values found redaction gaps in saved command and working-directory fields, and in some hook passthrough values. The example makes no blanket secret-redaction claim. The coding host uses its configured online model; Terraphim's demonstrated correction lookup uses the local compiled graph.

\n

Download the example and saved outputs to follow the whole chain: a failure that happened, a correction someone reviewed, and a later command whose result can be checked.

\n

Earlier 75-second walkthrough · Original example.

\n

Updated 13 October 2026. The new video is 66 seconds. The video uses synthetic British female narration and readable excerpts from actual released-binary and host outputs. The Harbour project is fictional public sample data.

\n", "https://terraphim.ai/properties/date" : "2026-04-15", "https://terraphim.ai/properties/tags" : {"categories":["Tutorials"],"tags":["Terraphim","hooks","OpenCode","knowledge-graph","developer-tools"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/how-tos/knowledge-work-editor/", "https://atomicdata.dev/properties/name" : "Write and search with the same knowledge graph", "https://terraphim.ai/properties/url" : "https://terraphim.ai/how-tos/knowledge-work-editor/", "https://atomicdata.dev/properties/description" : "

Watch the new 80-second story: create a synonym, share it, then search

\n

These earlier host recordings remain available as versioned evidence. The new story above follows the current alternative-to-search flow.

\n

Try Terraphim Editor

\n

Keep alternatives attached to words, sentences and paragraphs. Ghost a passage without losing it, stash notes in Overflow, and use the Lab to inspect possible cuts. The editor runs as WebAssembly in your browser with a bundled local knowledge graph.

\n

Grammarly for knowledge work

\n

Follow a public project brief from editing to search using the same knowledge graph. The 77-second captioned overview shows the browser editor, explicitly hands off to the clean file exported from Safari, then compares real terraphim-grep executions with and without --answer.

\n

\n

Recorded host walkthroughs

\n\n

The browser recordings produced identical saved annotated files. A separately checked Safari clean-export file supplies the grep corpus; the Safari walkthrough does not show that export gesture. Newly authored Assessment registers as a document-scoped synonym; it does not update the shared KG used by the CLI. Zed demonstrates existing extension capabilities; the Zed fork is separate. The brief's Trim preview produced zero cuts, so this recording does not demonstrate text reduction. The generated synthesis overstates a review policy as observed practice; compare that statement with the returned evidence rather than treating it as verified fact.

\n

All six videos now have explanatory on-screen captions. Idle intervals are cut, actions are accelerated by 1.5–3× where disclosed, and the long terminal end hold is removed. Captions sit outside the application image. Safari setup is cut and the Zed avatar remains masked. Chronological source ranges and speed changes are recorded in the manifest; original captures are retained. These are finite walkthroughs, not complete acceptance of all 41 requirements. Build identities, media hashes and edit disclosures identify the recorded candidate. The current editor preview includes the Unicode normalization repair: canonically equivalent accents, Terraphim Unicode lowercase and Greek sigma equivalence protect exact original spellings during Trim. The videos retain their earlier recorded build identity; they do not demonstrate this later repair.

\n

This is a preview. The complete source-video requirements are still being qualified; Safari dragging and some visual/native cases remain unresolved. Keyboard pull from Overflow is available. The browser demo does not imply full custom visual parity in the stock Zed extension.

\n

Start with a public brief

\n

Paste this supplied example into the editor. It is sample input, not generated output:

\n
# Public research workspace\n\nDecision: launch a local-first research workspace for the delivery team.\n\nThe decision owner will review the brief before the pilot begins.\n\nRisk: inconsistent terminology makes prior decisions hard to locate.\n\nUse the project brief to align the team and keep the decision record clear.\n
\n

Turn on Write_On using the word counter. Explore alternatives for “decision”, add your own wording, and compare it in context. Ghost/revive a passage, stash a note in Overflow and inspect the Lab. Save the result and reopen the actual file to check the choices and annotations.

\n

Save your work and use it in search

\n

Save keeps the Markdown, alternatives, ghosts and Overflow together. Clean Markdown export includes active text and omits ghosts, Overflow and the annotation block. Chrome can offer a file handle; Firefox and Safari use a download. Check the actual browser dialog and downloaded file.

\n

Download the same bundled KG and inspect the editor build identity. Newly authored alternatives register as document-scoped synonyms; they do not silently change this shared KG.

\n

Move the chosen saved or clean-exported file into a dedicated local corpus folder. Keep evidence logs and other copies outside that folder. With terraphim-grep installed, set paths for that public corpus and downloaded KG:

\n
terraphim-grep "decision" --thesaurus ./default.json --paths ./public-corpus --json\nterraphim-grep "decision" --thesaurus ./default.json --paths ./public-corpus --json --answer\n
\n

The first command returns search evidence without enabling synthesis. The second asks for an answer when sufficient evidence and a configured provider are available. Keep the query, corpus and KG unchanged to compare them. Add the same --role-config path to both commands if configuring a provider through a role. Check the generated answer against the returned source lines; a missing answer or provider error is not a successful synthesis.

\n

Writing and local search do not require sending your document to an LLM. Synthesis may send retrieved content to the configured provider. Use public sample content for the demo and inspect the provider configuration before enabling --answer.

\n", "https://terraphim.ai/properties/date" : "2026-10-11", "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/graph-embeddings-interactive/", "https://atomicdata.dev/properties/name" : "Graph Embeddings, Explained Interactively", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/graph-embeddings-interactive/", "https://atomicdata.dev/properties/description" : "

Most pages about embeddings show you a picture of some dots and ask you to trust the maths.\nThis one is different: the Terraphim side of every demo below runs the real algorithm —\nthe actual terraphim_rolegraph Rust crate, compiled to WebAssembly and executing in your\nbrowser — on a real thesaurus and corpus. Nothing is staged or ported: the counters you watch\nincrement are the same code paths the Rust tests exercise.

\n
\nHow to read this page. Each scene has controls. Press buttons, type queries,\nindex your own sentence. If a number is on screen, it was computed in your browser a moment\nago. Where the comparison side is simulated rather than real, it says so on the panel.\nEsc clears highlights and ledgers; your indexed data stays.\n
\n

Two retrieval worlds, one question

\n

The same eight documents, two retrieval systems. On the left, the classic picture: every\ndocument is a point in a high-dimensional space; a query lands as another point; similarity\nis distance. On the right, the Terraphim graph: every concept is a node; documents feed\nco-occurrence counters; a query lights up a path.

\n

Run a query — including byzantine fault tolerance, which is deliberately absent from the\nthesaurus — and watch what each side does with it.

\n
\n
\n \n \n \n \n \n \n
\n
\n
\n

Dense vectors illustrative

\n \n

Every dot is a document. The ring is a cosine-similarity radius.\n You get a score — 0.98, 0.87, 0.76 — and nothing else. There is no answer to\n why this document matched.

\n
\n
\n

Terraphim RoleGraph real algorithm

\n \n

Nodes are concepts; numbers inside are node.rank —\n co-occurrence counts. Lit nodes and edges are the ones the query actually traversed.

\n
\n
\n
\n
\n

Scene one: how the text is read

\n

Before anything is a graph, there is a dictionary. The role's thesaurus maps synonyms to\nnormalised concepts — leader election and election are the same node, id 3. At startup the\nthesaurus compiles into an Aho-Corasick automaton: a finite-state machine that scans text in a\nsingle pass, regardless of how many patterns it holds.

\n

Watch it read. The matcher runs leftmost-longest, case-insensitive: at each position it\ntakes the longest pattern that fits, then jumps past it. Type anything — the highlights and the\nconcept sequence update live.

\n
\n

Aho-Corasick matching real algorithm

\n
\n \n
\n
\n
\n

Try a consensus algorithm vs\n a consensus: consensus algorithm wins as one match,\n not two. That is LeftmostLongest. Overlapping terms collapse into a single concept id —\n and that ordered sequence of ids is all the indexer sees.

\n
\n

Scene two: indexing — where the \"embedding\" is built

\n

Here is the whole trick, and it is smaller than you expect. When a document is indexed:

\n
    \n
  1. The automaton scans it once, producing the matched concept sequence you saw above.\n(The crate matches title + body — Document::to_string() — which is why \"Raft notes\"\nadds a raft → raft self-loop: the title itself matches.)
  2. \n
  3. Each consecutive pair (a, b) becomes a directed edge magic_pair(a, b) — an integer\nkey computed by a Cantor-style pairing function, so (raft → consensus) and\n(consensus → raft) are different edges.
  4. \n
  5. node.rank += 1 for both endpoints; edge.doc_hash[doc] += 1 counts how often that pair\nappeared in that document.
  6. \n
\n

That is the embedding. What a concept \"is\" here: a node plus its edges in conceptual\nspace — the synonyms that map to it and the concepts that appear next to it — not a point\nin a vector space. Press \"Index next\" a few times and watch the graph accrete; then index\nyour own sentence (only thesaurus terms count).

\n
\n

Build the graph real algorithm

\n
\n \n \n \n \n
\n
\n
\n
\n \n \n
\n \n

Edge thickness ∝ total document count on that pair. Loops are real:\n partition tolerance → partition tolerance and leader → leader appear\n when the same concept is matched twice in a row. Re-indexing removes a document's\n contributions before re-counting — replace semantics. Honest caveat: removal decrements\n node rank once per edge, while insertion counts once per pair occurrence,\n so a document that repeats the same directed pair leaves a small rank residual on re-index.\n That is the Rust implementation's real behaviour, running live — not smoothed over.

\n
\n

Scene three: asking a question

\n

Querying is the mirror image. The automaton matches the query terms to node ids; for each\nmatched node, the engine walks its edges; for every document on each edge it adds:

\n
score += node.rank + edge.rank + doc_hash[doc]
\n

Documents are sorted by the sum. And because every point of the sum comes from a named node,\na named edge and a count you can inspect, the ranking is auditable — click a query and read\nthe ledger. This is the part a cosine score cannot give you.

\n
\n

Query the graph real algorithm

\n
\n \n \n \n \n \n \n \n
\n
\n
\n

Scene four: when does the work happen?

\n

The deepest difference is not the data structure — it is where computation lives.

\n

Traditional graph embeddings — DeepWalk, node2vec, GraphSAGE, TransE, Cleora — front-load\neverything: random walks or message passing produce dense vectors once, then queries are cheap\nANN lookups. Adding a term means re-walking and re-training. Terraphim inverts this: all the\nwork is tiny counters at index time; a query is a lookup and a sum.

\n

Add a synonym right now. The Terraphim column measures the real rebuild time in your browser.

\n
\n

Cost of change

\n
\n \n \n
\n
\n
\n
\n
Terraphim RoleGraph
\n
Edit thesaurus → rebuild automaton~ms
\n
Index doc: one AC scan + counter incrementsµs
\n
Query: match + traverse + integer sumsub-ms
\n
Answer to \"why?\": full provenancefree
\n
\n
\n
Learned graph embeddings node2vec / GCN / TransE / Cleora
\n
Random walks / message passingcorpus pass
\n
Skip-gram / gradient trainingminutes–hours
\n
Query: cosine vs ANN indexms
\n
New term → re-embed affected subgraphretrain
\n
\n
\n
Dense text embeddings API + vector DB
\n
Embed every document via API50–500 ms/doc
\n
Build ANN index (HNSW)build pass
\n
Query: embed query + ANN scan5–50 ms + API
\n
New vocabulary → re-embed corpusretrain/index
\n
\n
\n

Timings on the Terraphim column are measured live in this page; the other\n columns are indicative ranges consistent with published measurements, shown for comparison.

\n
\n

The honest comparison

\n\n\n\n\n\n\n\n\n\n\n
AspectLearned graph embeddings (node2vec, GCN, TransE, Cleora)Dense text embeddings (API + vector DB)Terraphim graph embeddings
What a concept \"is\"A point in ℝᵈ learned from walks/adjacencyA point in ℝᵈ learned from textA node + its edges + integer counters
TrainingWalks + SGD / iterative propagationPre-trained model; per-doc embed callNone — counters at index time
Query mechanismVector → ANN cosineVector → ANN cosineAC match → traverse → integer sum
Multi-hop semanticsYes — walks/message passingIndirectNeighbourhood only (1 hop)
Unseen vocabularyDegrades silentlyGeneralises (that's the point)Returns nothing — honestly
Update costRe-embed affected subgraphRe-embed documentEdit thesaurus, ~ms rebuild
ExplainabilityVector distance onlyVector distance onlyEvery contribution named and countable
Memory / hardwareFloat32 × nodes × dimsANN index + APIints; 15–20 MB typical; runs on a Pi
DeterminismSeed-dependentModel/version dependentSame input → same output, always
\n

Where the graph loses — honestly

\n\n

From page to code

\n

Every label above maps to a real symbol:

\n\n

One honest detail the prose docs gloss over: edge.rank is currently always 1 — the real\nper-document count lives in edge.doc_hash, which is why the ledger above shows the\ndocument count rather than an edge rank. This page shows the code, not the approximation.

\n

The reference text lives at Graph Embeddings; the short version of\nwhy it matters is in Why Graph Embeddings Matter.

\n", "https://terraphim.ai/properties/date" : "2026-10-20", "https://terraphim.ai/properties/tags" : {"categories":["Documentation"],"tags":["graph-embeddings","knowledge-graph","aho-corasick","interactive","explainer"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/crates/", "https://atomicdata.dev/properties/name" : "Crate Reference", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/crates/", "https://atomicdata.dev/properties/description" : "

Crate Reference

\n

Terraphim AI is a modular Rust workspace comprising 54 crates. Each crate has a single responsibility and can be used independently or composed into larger systems. All crates are available in the terraphim-ai monorepo.

\n

Core Engine

\n

The foundational crates that power Terraphim's deterministic knowledge graph search.

\n\n\n\n\n\n\n\n\n\n\n\n\n
CrateDescription
terraphim_automataAho-Corasick automata for searching and processing knowledge graphs. The core matching engine.
terraphim_rolegraphRole-based knowledge graph module. Maps search roles to domain-specific graph views.
terraphim_typesCore types crate shared across the entire workspace.
terraphim_configConfiguration loading and management for all Terraphim components.
terraphim_settingsSettings handling library for runtime preferences and defaults.
terraphim_serviceService layer handling user requests and responses for the Terraphim core.
terraphim_middlewareMiddleware for searching haystacks (pluggable data source backends).
terraphim-markdown-parserMarkdown parser for extracting structured content from knowledge base files.
terraphim_persistencePersistence layer with Persistable trait and DeviceStorage backends (memory, SQLite, redb).
terraphim_build_argsBuild argument management for compile-time feature configuration.
terraphim_test_utilsShared test utilities and fixtures for all Terraphim crates.
\n

Binaries and CLIs

\n

User-facing executables and command-line tools.

\n\n\n\n\n\n\n
CrateDescription
terraphim_agentTerraphim AI Agent CLI with interactive REPL, session search, learning capture, and ASCII graph visualisation.
terraphim-cliCLI tool for semantic knowledge graph search with JSON output for automation and scripting.
terraphim_serverHTTP server handling the core logic of Terraphim AI. Provides REST API and knowledge graph backend.
terraphim_updateShared auto-update functionality for all Terraphim AI binaries.
terraphim_validationRelease validation system ensuring binary and asset integrity before publishing.
\n

Agent Orchestration (AI Dark Factory)

\n

OTP-inspired agent management system for running autonomous AI coding agents.

\n\n\n\n\n\n\n\n\n\n\n\n
CrateDescription
terraphim_orchestratorAI Dark Factory orchestrator wiring spawner, router, and supervisor into a reconciliation loop.
terraphim_spawnerAgent spawner with health checking, output capture, and lifecycle management.
terraphim_routerUnified routing engine for LLM and agent providers (keyword routing, tier selection).
terraphim_agent_supervisorOTP-inspired supervision trees for fault-tolerant AI agent management.
terraphim_agent_applicationOTP-style application behaviour for the Terraphim agent system.
terraphim_agent_messagingErlang-style asynchronous message passing system for AI agents.
terraphim_agent_registryKnowledge graph-based agent registry for intelligent agent discovery and capability matching.
terraphim_agent_evolutionAgent evolution and self-improvement tracking.
terraphim_workspaceWorkspace management for agent execution including lifecycle, hooks, and isolation.
terraphim_multi_agentMulti-agent system built on roles with rust-genai integration.
\n

Knowledge Graph Intelligence

\n

Advanced crates for KG-powered reasoning, task planning, and goal management.

\n\n\n\n\n\n\n\n\n\n\n\n
CrateDescription
terraphim_kg_orchestrationKnowledge graph-based agent orchestration engine for coordinating multi-agent workflows.
terraphim_kg_agentsSpecialised knowledge graph-based agent implementations.
terraphim_kg_linterLinter for markdown-based Terraphim KG schemas (commands, types, permissions).
terraphim_goal_alignmentKnowledge graph-based goal alignment system for multi-level goal management and conflict resolution.
terraphim_task_decompositionKnowledge graph-based task decomposition for intelligent task analysis and execution planning.
terraphim_rlmRecursive Language Model (RLM) orchestration for structured reasoning chains.
terraphim_hooksUnified hooks infrastructure for knowledge graph-based text replacement and validation.
terraphim_file_searchKnowledge-graph scored file search integration.
terraphim_codebase_evalCodebase evaluation system with manifest types and metrics aggregation.
terraphim_negative_contributionNegative contribution analysis for identifying anti-patterns and risks.
\n

Haystack Integrations

\n

Pluggable data source connectors for searching external systems.

\n\n\n\n\n\n\n
CrateDescription
haystack_coreCore traits and types for all Terraphim haystack integrations.
haystack_atlassianAtlassian (Confluence, Jira) integration for searching enterprise knowledge bases.
haystack_discourseDiscourse forum integration for fetching posts and messages.
haystack_grepappGrep.app integration for searching code across GitHub repositories.
haystack_jmapJMAP email protocol integration for searching email (Fastmail, etc.).
\n

Session and Usage Analytics

\n

Tools for analysing AI coding assistant sessions and tracking usage.

\n\n\n\n\n\n
CrateDescription
terraphim_sessionsSession management for AI coding assistant history. Search across Claude Code, Cursor, and Aider sessions.
terraphim-session-analyzerAnalyse AI coding assistant session logs to identify agent usage patterns.
terraphim_ccusageClaude Code usage tracking and cost analysis.
terraphim_usageGeneral usage telemetry and analytics.
\n

DevOps and Infrastructure

\n

Deployment, CI/CD, and infrastructure management.

\n\n\n\n\n\n\n\n\n\n
CrateDescription
terraphim_symphonySymphony orchestration service. Reads issues from trackers and dispatches coding agent sessions.
terraphim_trackerIssue tracker abstraction for Gitea and Linear with PageRank-based prioritisation.
terraphim_github_runnerGitHub Actions runner with Firecracker sandbox integration.
terraphim_github_runner_serverHTTP server for the GitHub Actions runner service.
terraphim-firecrackerSub-2-second VM boot optimisation system for sandboxed agent execution.
terraphim_mcp_serverModel Context Protocol (MCP) server exposing Terraphim tools to AI assistants.
terraphim_onepassword_cli1Password CLI integration for secret management.
terraphim_atomic_clientAtomic Data Server client for managing stores and agents.
\n

Chat and Assistants

\n

Multi-channel AI assistant interfaces.

\n\n\n
CrateDescription
terraphim_tinyclawMulti-channel AI assistant for Telegram, Discord, and CLI.
\n

Language Bindings

\n

Cross-language bindings for using Terraphim from Python, Node.js, and WebAssembly.

\n\n\n\n\n\n
CrateDescription
terraphim_automata_pyPython (PyO3) bindings for terraphim_automata. Fast autocomplete and text processing for knowledge graphs.
terraphim_rolegraph_pyPython bindings for terraphim_rolegraph. Knowledge graph operations for AI agents.
terraphim-automata-node-rsNode.js (NAPI) bindings for Terraphim's Aho-Corasick matcher.
terraphim-automata-wasmWebAssembly bindings for terraphim_automata. Runs in the browser.
\n

Browser Extensions

\n\n\n
CrateDescription
terrraphim-automata-wasm (extension)WASM core for the Terraphim browser extensions (Sidebar and Autocomplete).
\n
\n

Quick Install

\n
# Install the agent (interactive REPL + session search)\ncargo install terraphim_agent --features repl-full\n\n# Install the CLI (JSON output for automation)\ncargo install terraphim_cli\n
\n

Or use the universal installer:

\n
curl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n
\n

Architecture

\n

The crate dependency graph follows a layered architecture:

\n
    \n
  1. Types and Config (bottom): terraphim_types, terraphim_config, terraphim_settings
  2. \n
  3. Core Engine: terraphim_automata, terraphim_rolegraph, terraphim_persistence
  4. \n
  5. Service Layer: terraphim_service, terraphim_middleware, haystack integrations
  6. \n
  7. Agent System: terraphim_spawner, terraphim_router, terraphim_agent_supervisor
  8. \n
  9. Orchestration: terraphim_orchestrator, terraphim_kg_orchestration, terraphim_symphony
  10. \n
  11. User Interfaces (top): terraphim_agent, terraphim-cli, terraphim_server, terraphim_tinyclaw
  12. \n
\n

Contributing

\n

Each crate has its own README.md with specific build instructions and examples. See the Contribution Guide for the overall workflow.

\n

Source: github.com/terraphim/terraphim-ai

\n", "https://terraphim.ai/properties/date" : "2026-04-12", "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/graph-embeddings/", "https://atomicdata.dev/properties/name" : "Graph Embeddings", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/graph-embeddings/", "https://atomicdata.dev/properties/description" : "

Graph Embeddings

\n
\n

Try it live: Graph Embeddings, Explained Interactively runs the actual terraphim_rolegraph Rust crate compiled to WebAssembly in your browser — matching, indexing and scoring with no server round-trips.

\n
\n

Terraphim uses a fundamentally different approach to semantic search compared to traditional vector embeddings. Instead of dense numerical vectors, Terraphim leverages graph structure embeddings where ranking is determined by the number of synonyms and related concepts connected to a query term in the knowledge graph.

\n

What are Graph Embeddings in Terraphim?

\n

Unlike vector embeddings that represent concepts as points in a high-dimensional semantic space, Terraphim represents concepts as nodes in a knowledge graph. Each node is a normalized term, and edges represent co-occurrence relationships between terms found in documents.

\n

The key insight is that rank is defined by the number of synonyms connected to a concept. When you search for a term, Terraphim expands your query to include all synonyms and related concepts from the knowledge graph, then traverses the graph to find documents that mention these connected concepts.

\n

Graph Structure

\n
    "raft" ----(edge)---- "consensus"\n       |                    |\n    (edge)               (edge)\n       |                    |\n    "leader" ----(edge)---- "election"\n
\n

When you search for \"consensus algorithms\", the graph traverses from the matched node to connected nodes, finding documents that mention related concepts like \"raft\", \"leader election\", and so on.

\n

How It Works

\n

The Terraphim Graph (scorer) uses unique graph embeddings with the following ranking algorithm:

\n
total_rank = node.rank + edge.rank + document_rank\n
\n

Where:

\n\n

Query Expansion

\n

When you search, Terraphim:

\n
    \n
  1. Matches your query terms against the thesaurus (normalized terms and synonyms)
  2. \n
  3. Expands the query to include all connected synonyms and related concepts
  4. \n
  5. Traverses the graph to find documents containing these terms
  6. \n
  7. Ranks documents by aggregating scores from multiple graph paths
  8. \n
  9. Returns results with explainable match reasons
  10. \n
\n

Technical Details

\n

Core Implementation

\n

The graph embedding system is implemented in crates/terraphim_rolegraph/src/lib.rs:

\n\n

Symbolic Embeddings

\n

For domain-specific embeddings (e.g., medical), the SymbolicEmbeddingIndex in crates/terraphim_rolegraph/src/medical.rs builds embeddings from IS-A hierarchies, allowing for hierarchical concept relationships.

\n

Configuration

\n

The system is configured via config/atomic_graph_embeddings_config.json:

\n
{\n  "roles": {\n    "Atomic Graph Embeddings": {\n      "relevance_function": "terraphim-graph"\n    }\n  }\n}\n
\n

The terraphim-graph relevance function enables graph-based ranking.

\n

Use Cases

\n

Semantic Search with Relationship Awareness

\n

Graph embeddings excel when content relationships matter more than simple keyword matching:

\n\n

Example: Learning Assistant

\n

With a learning knowledge graph:

\n\n

Comparison with Vector Embeddings

\n

Why Graph Embeddings?

\n\n\n\n\n\n\n
FeatureVector EmbeddingsGraph Embeddings
RepresentationDense vectorsGraph structure
ExplainabilityBlack boxFull traceability
Queries expandImplicit via distanceExplicit via synonyms
Relationship captureLearns patternsEncodes relationships
Domain adaptationRequires retrainingAdd to thesaurus
\n

The Transparency Advantage

\n

Unlike vector embeddings where you don't know WHY a document matched, Terraphim's graph embeddings show:

\n
    \n
  1. Which terms matched: The exact thesaurus entries that triggered
  2. \n
  3. Graph paths: The path from query term through the graph to the document
  4. \n
  5. Ranking breakdown: How node.rank + edge.rank + document_rank was computed
  6. \n
\n

This makes results fully auditable and debuggable.

\n

Example Usage

\n

CLI Search

\n
# Search with the Engineer role\nterraphim-agent search "graph embeddings" --role engineer\n
\n

This returns results for:

\n\n

Programmatic Usage

\n
use terraphim_rolegraph::RoleGraph;\nuse terraphim_types::{Thesaurus, RoleName};\n\n// Create rolegraph with domain knowledge\nlet thesaurus = build_domain_thesaurus();\nlet role_name = RoleName::new("Engineer");\nlet mut graph = RoleGraph::new(role_name, thesaurus).await?;\n\n// Index documents\nfor doc in documents {\n    graph.insert_document(&doc.id, doc);\n}\n\n// Query - automatically expands to synonyms\nlet results = graph.query_graph("distributed systems", None, Some(10))?;\n
\n

Configuration

\n

Enable graph embeddings in your config:

\n
{\n  "roles": {\n    "Your Role": {\n      "relevance_function": "terraphim-graph",\n      "kg": {\n        "knowledge_graph_local": {\n          "path": "./docs/your-domain"\n        }\n      }\n    }\n  }\n}\n
\n

Next Steps

\n\n", "https://terraphim.ai/properties/date" : "2026-04-04", "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/installation/", "https://atomicdata.dev/properties/name" : "Installation", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/installation/", "https://atomicdata.dev/properties/description" : "

Installation

\n

Choose the installation method that best suits your needs and platform.

\n

Quick Install (Recommended)

\n

The universal installer detects your platform, resolves the current release\nfrom the release channel, verifies the download's SHA-256, and unpacks it into\n~/.local/bin.

\n
curl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n
\n

Options:

\n
# Also install the CLI and grep tools\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash --with-cli --with-grep\n\n# Install somewhere else\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash --install-dir /usr/local/bin\n\n# Require a specific version (fails if the channel serves a different one)\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash --version 1.21.22\n
\n

The installer publishes these exit codes: 0 success, 1 usage error,\n2 manifest unreachable, 3 requested version unavailable, 4 download\nfailed, 5 checksum mismatch, 6 installation failed.

\n

Package Managers

\n

Homebrew (macOS/Linux)

\n
brew tap terraphim/terraphim && brew install terraphim-agent\n
\n

The tap also carries terraphim-grep. There is no terraphim-ai formula.

\n

Cargo (Rust)

\n
# Install agent with interactive REPL and full features\ncargo install terraphim_agent --features repl-full\n
\n

Platform-Specific Guides

\n

Linux

\n

Binary Download

\n

Archives are served from downloads.terraphim.ai. Substitute the release you\nwant for 1.21.22, or read the current version from the\nmanifest.

\n
VERSION=1.21.22\n\n# x86_64 (GNU)\ncurl -fsSLO "https://downloads.terraphim.ai/terraphim-agent/terraphim-agent-${VERSION}-x86_64-unknown-linux-gnu.tar.gz"\ntar -xzf "terraphim-agent-${VERSION}-x86_64-unknown-linux-gnu.tar.gz"\nsudo mv terraphim-agent /usr/local/bin/\n\n# x86_64 (MUSL / static)\ncurl -fsSLO "https://downloads.terraphim.ai/terraphim-agent/terraphim-agent-${VERSION}-x86_64-unknown-linux-musl.tar.gz"\n\n# ARM64 (MUSL)\ncurl -fsSLO "https://downloads.terraphim.ai/terraphim-agent/terraphim-agent-${VERSION}-aarch64-unknown-linux-musl.tar.gz"\n
\n

Verify the download against the digest in the manifest before installing:

\n
curl -fsSL https://downloads.terraphim.ai/terraphim-agent/stable-v2.json \\\n  | python3 -c 'import json,sys; m=json.load(sys.stdin); print(m["version"]); print(m["assets"]["x86_64-unknown-linux-gnu"]["sha256"])'\nsha256sum "terraphim-agent-${VERSION}-x86_64-unknown-linux-gnu.tar.gz"\n
\n

Build from Source

\n
git clone https://github.com/terraphim/terraphim-clients.git\ncd terraphim-clients\n\ncargo build --release -p terraphim_agent --bin terraphim-agent\n\nsudo cp target/release/terraphim-agent /usr/local/bin/\n
\n

macOS

\n

Binary Download

\n
VERSION=1.21.22\n\n# Apple Silicon (ARM64)\ncurl -fsSLO "https://downloads.terraphim.ai/terraphim-agent/terraphim-agent-${VERSION}-aarch64-apple-darwin.tar.gz"\ntar -xzf "terraphim-agent-${VERSION}-aarch64-apple-darwin.tar.gz"\nsudo mv terraphim-agent /usr/local/bin/\n\n# Intel (x86_64)\ncurl -fsSLO "https://downloads.terraphim.ai/terraphim-agent/terraphim-agent-${VERSION}-x86_64-apple-darwin.tar.gz"\n\n# Universal (runs on both)\ncurl -fsSLO "https://downloads.terraphim.ai/terraphim-agent/terraphim-agent-${VERSION}-universal-apple-darwin.tar.gz"\n
\n

macOS builds are signed and notarised by Apple; the self-updater verifies an\nEd25519 signature over every archive before installing it.

\n

Build from Source

\n

Requires Xcode command line tools.

\n
git clone https://github.com/terraphim/terraphim-clients.git\ncd terraphim-clients\ncargo build --release -p terraphim_agent --bin terraphim-agent\nsudo cp target/release/terraphim-agent /usr/local/bin/\n
\n

Windows

\n

WSL installation

\n

Native Windows archives are unavailable on the current stable channel. Use the Linux instructions inside WSL, or build from source below.

\n

Build from Source

\n

Requires Rust for Windows.

\n
git clone https://github.com/terraphim/terraphim-clients.git\ncd terraphim-clients\ncargo build --release -p terraphim_agent --bin terraphim-agent\n# Binary will be in target\\release\\\n
\n

Server and Library Bindings

\n

The commands above install the client tools (terraphim-agent,\nterraphim-grep, terraphim-cli). The server and the language bindings have\ntheir own release paths:

\n

Terraphim server

\n

The server is built and released from\nterraphim-ai. Build it from\nsource, or use the container images published to the GitHub Container\nRegistry.

\n

npm (Node.js / Bun)

\n

The @terraphim/autocomplete package provides NAPI bindings for autocomplete and knowledge graph functions.

\n
npm install @terraphim/autocomplete\n
\n

Python (PyPI)

\n

The terraphim-automata package provides PyO3 bindings for text matching and autocomplete.

\n
pip install terraphim-automata\n
\n

Browser Extensions

\n

Two browser extensions are available for developer-mode installation:

\n\n

Install from source:

\n
git clone https://github.com/terraphim/terraphim-ai.git\ncd terraphim-ai/browser_extensions\n
\n

Then load unpacked in Chrome at chrome://extensions (enable Developer Mode). Coming to the Chrome Web Store soon.

\n

See browser_extensions/INSTALL.md for detailed instructions.

\n

Verification

\n

After installation, verify that Terraphim is working:

\n
# Check version\nterraphim-agent --version\n# terraphim-agent 1.21.22\n\n# Confirm the updater can see the channel\nterraphim-agent check-update\n\n# Start the REPL\nterraphim-agent repl\n
\n

Troubleshooting

\n

Permission Denied

\n

If you get a permission denied error, make the binary executable:

\n
chmod +x /usr/local/bin/terraphim-agent\n
\n

Command Not Found

\n

Ensure that the installation directory is in your PATH. The universal\ninstaller adds ~/.local/bin to your shell profile:

\n
# For bash\necho 'export PATH=$PATH:$HOME/.local/bin' >> ~/.bashrc\nsource ~/.bashrc\n\n# For zsh\necho 'export PATH=$PATH:$HOME/.local/bin' >> ~/.zshrc\nsource ~/.zshrc\n
\n

Checksum Mismatch

\n

The installer exits with code 5 if the downloaded archive does not match the\ndigest in the release manifest. Re-run the install; if it fails again, please\nopen an issue rather than using --skip-verify.

\n

Rust Version Issues

\n

Ensure that you have a recent Rust version:

\n
rustc --version  # Should be 1.85.0 or later\nrustup update stable\n
\n

Next Steps

\n\n", "https://terraphim.ai/properties/date" : "2026-01-27", "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/quickstart/", "https://atomicdata.dev/properties/name" : "Quickstart", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/quickstart/", "https://atomicdata.dev/properties/description" : "

Quickstart Guide

\n

Get up and running with Terraphim AI in just 5 minutes. The agent works offline by default -- no server required.

\n

Step 1: Install

\n

Choose your preferred installation method:

\n

Option A: Universal Installer (Recommended)

\n
curl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n
\n

Option B: Homebrew (macOS/Linux)

\n
brew tap terraphim/terraphim && brew install terraphim-agent\n
\n

Option C: Cargo

\n
cargo install terraphim_agent --features repl-full\n
\n

More installation options

\n

Step 2: Launch the REPL

\n
terraphim-agent repl\n
\n

You will see:

\n
============================================================\nTerraphim TUI REPL\n============================================================\nType /help for help, /quit to exit\nMode: Offline Mode | Current Role: AI Engineer\n\nAI Engineer>\n
\n

The REPL runs offline by default. No server or network connection required.

\n

Step 3: First Search

\n

Search your knowledge graph:

\n
AI Engineer> /search knowledge graph\n
\n

Results are displayed in a ranked table with title and file path.

\n

Step 4: Explore REPL Commands

\n

Here are the most useful commands to get started:

\n\n\n\n\n\n\n\n\n\n\n\n\n\n
CommandDescription
/search \"query\"Search knowledge graph with role context
/autocomplete \"query\"Autocomplete terms from the thesaurus
/extract \"text\"Extract matching paragraphs
/find \"text\"Find exact matches in indexed documents
/replace \"text\"Replace matches using thesaurus mappings
/thesaurusShow loaded thesaurus entries
/graphVisualise knowledge graph (ASCII)
/role listList available roles
/role select <name>Switch to a different role
/config showDisplay current configuration
/helpShow all available commands
/quitExit the REPL
\n

CLI Subcommands

\n

For scripting and automation, use subcommands directly:

\n
# Search from the command line\nterraphim-agent search "knowledge graph" --limit 5\n\n# List roles\nterraphim-agent roles list\n\n# Show configuration\nterraphim-agent config show\n\n# Visualise knowledge graph (ASCII)\nterraphim-agent graph --top-k 10\n
\n

Session Search

\n

Import and search your AI coding assistant history (Claude Code, Cursor, Aider):

\n
# Check available sources\nterraphim-agent sessions sources\n\n# Import sessions\nterraphim-agent sessions import\n\n# Search across sessions\nterraphim-agent sessions search "rust async error"\n
\n

Learning Capture

\n

Terraphim captures failed commands and their corrections for future reference:

\n
# List captured learnings\nterraphim-agent learn list\n\n# Query by pattern\nterraphim-agent learn query "npm"\n\n# Compile corrections into a thesaurus\nterraphim-agent learn compile\n
\n

See the blog post Teaching AI Agents to Learn from Their Mistakes for a worked example.

\n

Onboarding Wizard

\n

On first run, the interactive wizard helps you configure:

\n
    \n
  1. Role selection -- choose a role (AI Engineer, Log Analyst, etc.)
  2. \n
  3. Haystack path -- where your documents live
  4. \n
  5. Knowledge graph -- remote automata or local markdown files
  6. \n
  7. LLM provider -- Ollama (local) or OpenRouter (cloud)
  8. \n
\n

You can re-run the wizard at any time with terraphim-agent onboard.

\n

Next Steps

\n\n

Getting Help

\n

If you run into issues:

\n
    \n
  1. Search existing GitHub issues
  2. \n
  3. Create a new issue
  4. \n
  5. Join Discord community for support
  6. \n
  7. Visit Discourse forum for discussions
  8. \n
\n", "https://terraphim.ai/properties/date" : "2026-01-27", "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/terraphim-config/", "https://atomicdata.dev/properties/name" : "Terraphim Config structure", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/terraphim-config/", "https://atomicdata.dev/properties/description" : "

Terraphim config structure

\n

Most of the functionality is driven from the config file.

\n

[global]

\n

section for global parameters - like global shortcuts

\n

Roles

\n
[[roles]]\n
\n

For example I can be engineer, architect, father or gamer. In each of those roles I will have a different concens which are driving different relevance/scoring and UX requirements.

\n

Roles are the separate abstract layers and define behaviour of the search for particular role. It's roughly following roles definition from ISO 42010 and other systems engineering materials and at different point in time one can wear diferent heat (different role).

\n

Each role have a

\n\n

The powers roughly follows:

\n\n

Terraphim powers - skills

\n
[[Skill]]\n
\n

Parameters:

\n\n

Haystack is a source, can be PubMed, Github, Coda.io, Notion.so etc.\nHaystack arguments

\n", "https://terraphim.ai/properties/date" : "2022-02-21", "https://terraphim.ai/properties/tags" : {"tags":["terraphim","config","plugins"],"categories":["Documentation"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/contribution/", "https://atomicdata.dev/properties/name" : "Contribution Guidelines", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/contribution/", "https://atomicdata.dev/properties/description" : "

General guidelines for contributing to the project.

\n

Main goals

\n

Be data driven

\n\n

Engineering approach

\n

Even for conceptual topics such as ethics or enterprise architecture, there should be path to be implemented in real would: student's head or software working in production considered to be real world.

\n", "https://terraphim.ai/properties/date" : "2021-12-15", "https://terraphim.ai/properties/tags" : {"categories":["Documentation"],"tags":["contribute","zola"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/docs/donate/", "https://atomicdata.dev/properties/name" : "Support project by contributing", "https://terraphim.ai/properties/url" : "https://terraphim.ai/docs/donate/", "https://atomicdata.dev/properties/description" : "

This is the beginning of an exciting great new journey: support open-source projects by donating or contributing.

\n

Terraphim AI is partially supported by Innovate UK via the Eureka funding program up to 60% of costs, under grant 600594, \"ATOMIC\", jointly with our collaborators Ontola - the team behind Atomic Data Server and Protocol.\nBut for the rest of the costs, we need your help.

\n

Introducing a Donation-driven roadmap

\n

After several months of agonising over which license to release Terraphim AI under, I created a new repository with the two most liberal licenses open source MIT and APACHE2.\nWe may build a commercial service on top of Terraphim Core(Cortex), but the core and our promise that it is open-sourced to allow you all to build on top of Terraphim AI, with a privacy-first, building AI tooling right way around: you don't need to move your data. You codify and move your knowledge where it needs to be and helps you to get things done the most.

\n

Donation-driven roadmap

\n

To support the project's development, we introduce a \"donation-driven roadmap\": if you want a feature, vote for it not only with your thumb but with your money.\nIn exchange:

\n\n

Sponsor the features on our GitHub page or propose a new idea in GitHub discussions

\n", "https://terraphim.ai/properties/date" : "2020-08-31", "https://terraphim.ai/properties/tags" : {"tags":["donate","support"],"categories":["donations","open-source"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/kg-concepts-code-checklists/", "https://atomicdata.dev/properties/name" : "KG Concepts Before Code, Checklists After", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/kg-concepts-code-checklists/", "https://atomicdata.dev/properties/description" : "

The Graph Embeddings for Checklists article\nshows how a knowledge graph acts as an enumerable checklist around an LLM call:\nterraphim-grep before it, terraphim-agent hook and learning after it. This\nhow-to applies the same loop to terraphim-agent code — the bounded coding loop —\non the simplest possible concept: npm install must become bun add.

\n

Every command below was run while writing this article; the outputs are real.

\n

TL;DR

\n

Declare the concept once (kg/*.md or .terraphim/rewrite/*.md with\nsynonyms::), let the hook find npm install in a proposed tool call and\nprescribe bun add, run code inside the policy gate, then validate the\nproduced work with validate --checklist. The checklist guards the write and\njudges the result — the model is never trusted to police itself.

\n

Declare the Concept

\n

One file, written once, compiled into the role's automaton. From this site's own\n.terraphim/rewrite/bun install.md:

\n
# bun add\n\nInstall dependencies using Bun package manager.\n\nsynonyms:: npm install, yarn install, pnpm install, npm i, yarn add, pnpm add\n
\n

Before code: The Hook Checks the Action

\n

An agent proposing npm install hits the checklist first — pre-tool-use with\n--rewrite (opt-in so a stray substring can't silently mutate a destructive\ncommand):

\n
echo '{"tool_name":"Bash","tool_input":{"command":"npm install react"}}' \\\n  | terraphim-agent hook --hook-type pre-tool-use --rewrite \\\n      --role "Terraphim Engineer" --json\n
\n
{\n    "tool_input": {\n        "command": "bun install react"\n    },\n    "tool_name": "Bash"\n}\n
\n

The concept fired: npm install in, bun install out — a checklist line\nexecuted before the tool call runs, with a named edge (bun install.md) to\naudit.

\n

Inside code: The Loop Is Gated

\n

code run puts the model inside a bounded loop — every tool call is\npolicy-decided, audited to JSONL, and the run is exit-coded for callers:

\n
TERRAPHIM_CODE_MODEL=auto \\\n  terraphim-agent code run "Create a Cargo.toml and src/main.rs that prints Hello from terraphim"\n
\n
- **Cargo.toml** — package `terraphim` v0.1.0, edition 2021, no dependencies\n- **src/main.rs** — `fn main()` printing `Hello from terraphim`\n\nVerified with `cargo run`, which compiled cleanly and output:\n\n    Hello from terraphim\n
\n

The hook and the gate compose: the KG checklist shapes what commands the agent\nmay propose, the deny-first policy decides whether a call runs at all, and the\naudit JSONL records both decisions. Sessions persist as transcripts plus\nTurnStep checkpoints, so code resume replays context and reads persisted\nsteps back.

\n

After code: The Checklist Judges the Result

\n

The same graph that prescribed bun judges the output — code_review is a KG\nchecklist, not a prompt suggestion:

\n
echo "no tests, unwrap() everywhere" \\\n  | terraphim-agent validate --checklist code_review\n
\n
Checklist 'code_review' Validation for role 'AI Dark Factory Author':\n  Passed: false\n  Score: 0/5\n  Missing items:\n    ✗ tests\n    ✗ documentation\n    ✗ error_handling\n    ✗ security\n    ✗ performance\n
\n

Zero-inflated honesty applies here too: if the produced work mentions none of\nthe checklist items, the report says so with the missing set enumerated — the\nsame \"honest empty case\" property terraphim-grep shows on retrieval.

\n

The Loop

\n
declare kg/*.md ──► hook pre-tool-use (npm install → bun add)\n                              │\n                    code run — gated, audited, resumable\n                              │\n            validate --checklist code_review — the verdict\n                              │\n              learn/correct — feed misses back into synonyms\n
\n

Honest Notes

\n\n

The Demo

\n

Two fframes renders of real captures back this article — every terminal\nline is a real command output captured while writing it.

\n\n

The joined storyline (spec → graph → gate → surface → code → checklist): a\nreal spec.md, terraphim-grep firing validation gate on the context, the\ngate denying two shell calls by rule name, the tools/commands/policy surface,\na verified cargo run output, and the 0/5 checklist verdict on\nspec-violating code.

\n\n

The disciplined-engineering cut (issue → research → design → impl → verify → validate): real issue #431\nthrough the disciplined-* phases — the rg finding, the design decision,\nreal commits, fmt/blaze verification, and the checklist verdict.

\n", "https://terraphim.ai/properties/date" : "2026-10-28", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","coding-agent","knowledge-graph","checklists","hooks"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/zero-token-routing-vs-cloudflare/", "https://atomicdata.dev/properties/name" : "The cheapest routing decision is the one that costs no tokens", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/zero-token-routing-vs-cloudflare/", "https://atomicdata.dev/properties/description" : "

Cloudflare published an excellent post this week: Cutting our inference bill by 68% by being obsessive about optimization. Their AI code reviewer went from $2.43 to $0.77 per review, and the median review time fell from 4m 09s to 1m 32s. It is a masterclass in squeezing the token economics of a single provider: shared prompt-cache prefixes, fewer LLM calls per session, and relentless model/effort A/B tests.

\n

It is also a study in what optimisation inside the call cannot reach. Every one of their levers operates after the request has already been committed to a provider, a model, and an effort level. Their architecture answered the question of which lane each request deserves by experiment rather than by a decision mechanism. That layer is what terraphim-llm-proxy exists for, and the interesting part is that its answer costs zero tokens.

\n

Two different cost stacks

\n

Cloudflare's optimisations and Terraphim's routing operate on disjoint parts of the spend. Neither substitutes for the other, but only one of them requires a Cloudflare-scale engineering team and production traffic to discover.

\n\n\n\n\n\n\n\n
LeverLayerWhat it costs to make the decision
Shared cache prefixes (14–26% → 91–99.5% first-request hits)Inside the callEngineering time; nothing per request once landed
Fewer LLM calls per session (16.6 → ~fewer; index into prompt)Inside the callEngineering time
Model + effort A/B splits (Sonnet 5 vs 5.5, medium vs high)Across callsReal production traffic and real dollars for days per split
Keyword/synonym routing to provider lanesBefore the callZero tokens, sub-millisecond, deterministic
Latency-probed \"fastest\" policyBefore the callProbe requests; zero tokens on the routed request
Runtime fallback on outage/rate-limit/credit exhaustionBefore the callZero; the fallback is a failover rather than a retry of the same lane
\n

Cloudflare's answer to \"which model should handle this\" was a 50/50 production split run for two and a half days, read off dashboards, then rolled out. That is the honest way to do it when your router is a human. A deterministic router answers the same question per-request, for free, in microseconds, and it can change its mind the moment a lane degrades.

\n

A worked example on the live proxy

\n

These are real requests through the Terraphim Proxy desktop app (v0.1.45) running on 127.0.0.1:17890 with five configured provider lanes: z.ai GLM-5.3, MiniMax-M3, OpenAI Codex gpt-5.6-sol, xAI Grok-4.3, and a free OpenRouter lane (nvidia/nemotron-3.5-lightning:free). The route policy was fastest, which is latency-probed rather than keyword-pinned.

\n
$ curl -X POST http://127.0.0.1:17890/v1/messages \\\n    -H "Authorization: Bearer <caller-key>" \\\n    -d '{"model":"auto","max_tokens":32,\n         "messages":[{"role":"user","content":"Reply with exactly: ok"}]}'\n
\n\n\n\n\n\n
RequestRoute decisionProvider that served itWall timeDecision cost
\"deep security code review…\"auto → fastest laneMiniMax-M31.28s0 tokens
\"Reply with exactly: ok\"auto → fastest laneMiniMax-M30.92s0 tokens
openrouter:nvidia/...:free pinnedexplicit pinnemotron-3.5-lightning:free1.09s0 tokens
xai:grok-4.3 pinnedexplicit pingrok-4.39.73s0 tokens
\n

Read the last two rows together. At the moment of measurement, Grok-4.3's lane was roughly 10× slower than MiniMax's; transient congestion is exactly the condition a human-picked \"best model\" cannot react to. The fastest policy had already steered automatic traffic away from it. No alert fired, no dashboard was watched, no incident was declared: the probe data just ranked the lanes and auto avoided the slow one. Pinning is still available for when you want a specific lane; the point is that the default behaviour absorbs provider badness for free.

\n

And the free lane is not decorative. nvidia/nemotron-3.5-lightning:free answered correctly at 1.09s. A $0 lane exists precisely so that traffic which does not need a frontier model never pays for one.

\n

Where the decision actually happens

\n

The routing decision is deterministic string matching, not a model call:

\n
    \n
  1. Capability keywords are extracted from the request content using word-boundary matching over the canonical KeywordRouter table, where \"review\", \"plan\", \"security\", \"think\" and friends map to scenario routes.
  2. \n
  3. Keyword remaps and user synonyms are resolved against the rolegraph-backed probe table before routing. Your synonym (\"audit\" → \"review\") is a first-class graph probe rather than a bolted-on regex.
  4. \n
  5. Route policies (auto, fastest, deep-think, code-review, cheapest) select the lane; FillFirst chains order fallbacks across providers, not just models.
  6. \n
  7. If the chosen lane 429s, 5xxs, or runs out of credit, the request fails over to the next lane in the chain, so the caller sees one response instead of an outage.
  8. \n
\n

Total inference tokens spent deciding: zero. The decision is a lookup, not a completion.

\n

Compare the alternative that is currently fashionable: a model-based \"decision layer\" or classifier that reads each request and predicts which model should handle it. That decision itself costs tokens on every single request, plus a serialization round-trip of added latency. It is inference spent so you can spend inference. For a single workload the overhead is trivial; at agent-fleet scale you have built a second inference bill whose only product is billing decisions.

\n

Honest limits: where Cloudflare's approach still wins

\n

The two levers stack; pretending otherwise would be dishonest:

\n\n

The arithmetic that matters

\n

Cloudflare's reviewer makes ~10 LLM calls per review and spends $0.77. If a model-based router spent even 500 tokens triaging each of those calls, that is 5k extra tokens per review. Small per request, but it buys nothing a deterministic probe doesn't already know. Multiply by agent-fleet volume and the decision layer becomes a line item.

\n

The inverse is the actual saving: the free OpenRouter lane answered the trivial request for $0.00 where a frontier lane would have billed input + output. At Cloudflare's scale of thousands of reviews, \"which requests genuinely need the expensive model\" is the question worth more than \"how do we cache better\", and it is a question that costs zero tokens to ask when the answer is a keyword rather than a completion.

\n

Obsessive optimisation inside the call is necessary. It is not sufficient. The cheapest token is still the one you never spend, including the ones you would have spent deciding.

\n

How to get the proxy

\n

Two routes, depending on whether you want the binary or the source:

\n\n

The arithmetic from above applies directly: if a $10/month tier saves you frontier-model tokens on routing decisions, or lands one free-lane fallback during an outage, it pays for itself in the first bad week.

\n
\n

FSL-1.1-MIT licensed. Sponsors: github.com/sponsors/terraphim. App: notarised DMG now, App Store in review.

\n", "https://terraphim.ai/properties/date" : "2026-10-23", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","LLM","proxy","cost","routing","tokens","comparison"],"categories":["Engineering"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/graph-embeddings-checklists/", "https://atomicdata.dev/properties/name" : "Graph Embeddings for Checklists", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/graph-embeddings-checklists/", "https://atomicdata.dev/properties/description" : "

A checklist is an enumerated set of terms that must be checked. That is the whole problem, and it is the reason vector embeddings are the wrong tool for it: a nearest-neighbour index returns fuzzy neighbours, it cannot enumerate a fixed set and report which members fired. A knowledge graph can. Write the checklist once as synonyms under a normalised term, compile it into an Aho-Corasick automaton, and every check becomes a deterministic match with a named edge you can audit.

\n

This post shows that machinery applied to the two places a checklist earns its keep around an LLM call: terraphim-grep with a role thesaurus before the call, and terraphim-agent hooks plus learning after it. Every command below was run while writing this article; the outputs are real.

\n

The Checklist Is an Automaton, Not a Promise

\n

The usual pattern for \"checklists\" in agent workflows is a paragraph in a system prompt that the model promises to honour. That is a probabilistic check enforced by the thing being checked. Terraphim inverts it: the checklist lives outside the model, in the same structure that powers graph embeddings elsewhere on this site.

\n

A checklist item set looks like this in the knowledge graph. This is bun install.md from the rewrite graph on this machine (committed verbatim at .terraphim/rewrite/bun install.md in this site's repository):

\n
# bun add\n\nInstall dependencies using Bun package manager.\n\nsynonyms:: npm install, yarn install, pnpm install, npm i, yarn add, pnpm add\n
\n

The filename gives the normalised term the hook reports back (the suggestion in the findings output below is bun install, matching bun install.md), while the heading names the approved form inside the file. The synonyms:: line is the checklist itself: every surface form that must be recognised and dealt with. Compile the directory of such files into thesaurus.json and you get the \"Terraphim Engineer\" role used below, currently 219 entries. Rebuilding the automaton after an edit takes about 20 ms, a figure we verified in Why Graph Embeddings Matter, so the checklist is cheap to change and free to consult.

\n

Before the LLM Call: Retrieval as Checklist Execution

\n

The first job of a checklist is deciding what goes into the prompt. \"Gather relevant context\" is vague; \"which of the enumerated terms in this role's graph appear in the repository, and what do they pull in\" is a check.

\n

Here is the query I ran over this site's own source while preparing this article, using the Terraphim Engineer thesaurus:

\n
terraphim-grep "quality gate" --haystack all --paths . \\\n  --thesaurus ~/.config/terraphim/thesaurus.json -n 8 -C 1 --json\n
\n

The result, abridged:

\n
"stats": {\n  "search_latency_ms": 53,\n  "chunks_returned": 8,\n  "kg_hits": 8\n},\n"concepts": [\n  {"name": "accept"}, {"name": "accepted"}, {"name": "escalate"},\n  {"name": "fail"}, {"name": "improve"}, {"name": "judge-verdicts"},\n  {"name": "needs improvement"}, {"name": "pass"}\n]\n
\n

Two things worth pausing on. First, the concepts list is the checklist executing: the graph expanded \"quality gate\" into its item set (accept, fail, escalate, pass, judge-verdicts and friends) and matched those terms across the tree. Second, the chunks it returned came from .github/workflows/*.yml and campaigns/skills-2026/*, files that contain none of the words \"quality\" or \"gate\". They matched on fail, curl --fail, accepted: items on the checklist, not words in the query. Fifty-three milliseconds, no embedding model, and every hit can name the edge that produced it.

\n

The honest empty case

\n

A checklist that cannot say \"not covered\" is useless, so here is the control run against the same thesaurus:

\n
terraphim-grep "checklist" --haystack all --paths . \\\n  --thesaurus ~/.config/terraphim/thesaurus.json -n 8 -C 2 --json\n
\n
"kg_hits": 0,\n"sufficiency": "SearchOnly",\n"sufficiency_explanation": "Found 4 chunks but KG confidence 0.00 < 0.50,\n  diversity 1 < 2; returning search results only (pass --answer or\n  --force-rlm to synthesise)."\n
\n

Zero KG hits, four plain lexical chunks, and an explicit admission that graph confidence was too low to claim concept coverage. The tool does not pretend the checklist applied. If you want \"checklist\" to be a graph concept, you write it into a kg/*.md file with a synonyms:: line and rebuild; the gap is a text edit, not a retraining run. The project-local variant of this workflow (a .terraphim/ directory in your repo with its own role thesaurus) is documented in the terraphim-grep offline setup and the concepts can be enriched with code anchors mined by ast-grep.

\n

Reproduce it

\n

The artefacts behind these outputs are committed. This site's repository carries a .terraphim/ directory: kg/ holds the concept files used above (validation gate, judge-verdicts, hook, grounding gate and friends), rewrite/ holds the hook checklist, and thesaurus.json is the compiled 39-entry public subset of the working role. Run the same command against it:

\n
terraphim-grep "quality gate" --haystack all --paths . \\\n  --thesaurus .terraphim/thesaurus.json -n 8 -C 1 --json\n
\n

Same eight concepts, same honest kg_hits: 0 on the \"checklist\" control. For larger published checklist graphs, docs/src/kg/checklists/ in the terraphim-ai repository carries the code review and security concepts.

\n

After the LLM Call: The Hook Is a Findings Checklist

\n

The second job of a checklist is gating what comes back. In current releases, terraphim-agent hook does not silently rewrite the agent's proposed action; it returns a machine-readable findings list. That distinction matters: the hook's job is to check, and a check that mutates silently is a check you cannot audit.

\n

Run from the directory holding the rewrite config, against a tool call an agent might propose:

\n
echo '{"tool_name":"Bash","tool_input":{"command":"npm install react"}}' \\\n  | terraphim-agent hook --hook-type pre-tool-use --json\n
\n
{"tool_input":{"command":"npm install react"},"tool_name":"Bash",\n "validations":{"findings":[{"matched_term":"npm install",\n "suggested_replacement":"bun install"}],"has_findings":true}}\n
\n

Read that output as a completed checklist line: item \"npm install\" found, prescribed action \"bun install\", flag raised. The hook types cover the lifecycle (pre-tool-use, post-tool-use, pre-commit, prepare-commit-msg), and --with-guard is on by default for pre-tool-use so destructive commands get intercepted in the same pass. We covered the git-hook end of this in Teaching AI Coding Agents with Knowledge Graph Hooks and the end-to-end verified flow in Native Hook Support.

\n

When the checklist itself fails

\n

Checklists also cover the checking tool. Two honest notes from this session:

\n\n

The Loop, Closed

\n

Put the phases together and the checklist lifecycle is:

\n
    \n
  1. Declare: write kg/*.md files; heading = normalised item, synonyms:: = surface forms to catch.
  2. \n
  3. Compile: generate thesaurus.json; ~20 ms per role.
  4. \n
  5. Retrieve (pre-LLM): terraphim-grep with the role thesaurus expands queries into concept terms and pulls grounded chunks — or honestly reports kg_hits: 0.
  6. \n
  7. Draft: the LLM call runs with checklist-shaped context instead of a vibes-based prompt.
  8. \n
  9. Gate (post-LLM): terraphim-agent hook emits findings; guards intercept destructive commands; failed commands are captured by the learning hook.
  10. \n
  11. Correct: learn correct / learn correction add turn observed failures into reviewed rules; memory capture stores authored lessons; the synonyms grow and the automaton recompiles.
  12. \n
\n

Step 6 is what makes this different from a static lint list. Corrections feed back into the graph, so the checklist the next session runs against is the checklist this session finished — a property the learn/memory subcommands exist to provide, described in the learning capture spotlight.

\n

Why This Is Not a Vector Problem

\n

A vector index answers \"what is near this?\" A checklist asks \"which of these exact items occurred, and what was the prescribed response?\" Those are different questions with different audit requirements. Graph embeddings give you the second in tens of milliseconds on a laptop, with an explainable edge for every match and no network call. The full performance case, including the 1.4-million-pattern sub-millisecond figure, is in Why Graph Embeddings Matter and Sub-Millisecond Context with Knowledge Graphs; the mechanism is on the Graph Embeddings reference page.

\n

If you want the wiring for your own agent setup, the command rewriting how-to walks through where the synonym files live, how the role graph is built, and how host hooks call the matcher. Write the checklist once; let the automaton enforce it on both sides of the call.

\n", "https://terraphim.ai/properties/date" : "2026-10-20", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","graph-embeddings","knowledge-graph","checklists","ai-agents","context-engineering"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/context-engineering-book-announcement/", "https://atomicdata.dev/properties/name" : "Context Engineering: the book is out", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/context-engineering-book-announcement/", "https://atomicdata.dev/properties/description" : "

\"Context

\n

Most AI systems don't fail because the model is wrong.

\n

They fail because the context is.

\n

But here's the uncomfortable part: context engineering isn't a new activity. We've been doing it for decades under different names:

\n\n

That's the argument in my book, Context Engineering: Designing AI That Understands, Remembers, Acts, and Learns.

\n

It isn't a new invention. It's an old discipline applied to a new kind of system — one where the \"software\" is partly prompts, partly knowledge, partly retrieval, partly policy, and partly the model's emergent behaviour.

\n

Inside, 25 chapters cover:

\n\n

It's written for senior developers, engineering managers and architects who need AI to be dependable in production, not just impressive in a demo.

\n

The book is out now on Kindle: amazon.com and amazon.co.uk.

\n

Which older discipline do you think AI teams have forgotten most?

\n", "https://terraphim.ai/properties/date" : "2026-10-19", "https://terraphim.ai/properties/tags" : {"tags":["context-engineering","book","Terraphim","knowledge-graphs","AI"],"categories":["Announcements"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/save-money-tokens-ai-agents/", "https://atomicdata.dev/properties/name" : "3 Ways to Save Money on Tokens for Your AI Agents", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/save-money-tokens-ai-agents/", "https://atomicdata.dev/properties/description" : "

Your agent bill is mostly input tokens. Not the clever parts: the re-reading.

\n\n

Three levers we run in production: let a cheap model summarise the evidence, put expensive reasoning only where it earns its keep, and route every request through a proxy that knows the price of each lane.

\n

Every turn, a coding agent replays its entire transcript to the provider. Add a repository to explore and a handful of tool outputs, and a single session can carry a hundred thousand tokens of context that the model reads over and over at full price. The frontier model you are paying for spends most of its expensive attention budget on text it has already seen, or text a much cheaper model could have filtered first.

\n

We run a fleet of overnight coding agents on a single machine, so we feel this directly. Over the past few months we have landed on three levers that cut token spend without cutting output quality. Each one is running in production today, and each one comes with a caveat we will not hide: we have measured the mechanisms, not the end-to-end savings. The arithmetic below uses published prices and our own logs; treat it as illustrative, not invoiced.

\n

1. Search first, let a cheap model summarise

\n

The most expensive way to give a frontier model context is to hand it raw search results. The cheapest way is to let a small model read them first.

\n

The pattern looks like this. A local search tool retrieves candidate chunks from your codebase or knowledge base. Before those chunks reach your GPT-6 or Fable-class session, a lower-cost model synthesises them into a compact answer, with deterministic references back to the source. The expensive model receives the synthesis and the few references it may need to reopen, not ten near-duplicate excerpts.

\n

We do this with terraphim-grep (part of the open-source terraphim-clients repository), which resolves query terms through a curated knowledge-graph thesaurus before ranking local matches:

\n
export OPENROUTER_MODEL='deepseek/deepseek-v4-flash-0731'\n\nterraphim-grep provider \\\n  --thesaurus docs/src/thesaurus.json \\\n  --haystack code --paths crates -n 10 \\\n  --answer --force-rlm --json\n
\n

--answer requests an answer when the sufficiency check calls for one; --force-rlm forces the synthesis path. Only the selected excerpts leave the machine, through OpenRouter to a DeepSeek-flash-class model. There is also --search-only, which hard-disables synthesis and skips building the LLM client entirely, so a stray API key in the environment cannot cost a single network call.

\n

In our verified run, the raw chunk contents measured 505 characters, the evidence with source locations 1,108 characters, and the synthesised answer text 440 characters: the frontier model received about 40% of the context it would otherwise have been fed, with references it could reopen on demand.

\n

Two honest caveats. First, we measured characters, not tokens: the CLI does not expose token usage, so treat the ratio as directional. Second, the win is conditional on the handoff shape. The full answer object with all ten references measured 1,918 characters; forward that wholesale and the saving evaporates. Pass the synthesis plus the references needed for verification, nothing more.

\n

2. Put expensive reasoning at the edges of the V, not in the middle

\n

The second lever is not a tool but a lifecycle decision: match the model's price to the phase of work.

\n

We structure agent work as a V-model. The left side asks \"what should we build\" (research, design, specification); the right side asks \"did we build it correctly\" (review, validation, judge panels). The long middle (implementation, test-writing, mechanical verification loops) is where most of the tokens burn, and it is precisely the part that needs the least reasoning depth.

\n

So we split the model placement:

\n\n

The arithmetic is worth doing once. At published API prices, an illustrative workload of 100 million input and 20 million output tokens costs $800 if everything runs on a frontier model. Route 80% of it to a mid-tier model and the same token volume costs $480: 40% less, with the model count unchanged. That is a counterfactual at published prices, not a measured bill, but the shape of the saving is real: you are not paying for fewer tokens, you are paying less per token for the phases that do not need frontier reasoning.

\n

The catch is discipline. Left to itself, an agent uses whatever model it started on for everything. The phases have to be explicit, which is why this lever only works inside a structured lifecycle rather than a free-running session.

\n

3. Put a proxy in front of the providers

\n

The third lever makes the cheap route the default: an LLM proxy between the agent and every provider, routing each request by what it contains or how fast each lane currently is.

\n

Ours is terraphim-llm-proxy, shared with our GitHub Sponsors supporters. It sits on localhost, exposes OpenAI and Anthropic compatible endpoints, and decides where each request goes:

\n\n

One caveat that took us by surprise: prompt caches are per model, not per session. Measured across real coding sessions, 82% of mid-session model switches collapsed the cache read below 10% of its previous value: a warm 107,000-token prefix became 110,000 tokens of uncached input, roughly ten times the cached price for the same text. The saving pattern is therefore to route the session or the scenario, not each turn at random. Pick a lane for the job and stay on it.

\n

What we do not claim

\n

Token savings are not measured end-to-end. The synthesis example is measured in characters, not tokens; the model-mix example is arithmetic at published prices, not an invoice; the 82% cache-collapse figure comes from one operator's session logs, not a fleet benchmark. The honest metric is quality-adjusted cost per accepted task, and we are still building the instrumentation to report it.

\n

What we can claim is mechanism: retrieval that filters before the expensive model reads, a lifecycle that spends reasoning budget where judgement lives, and a proxy that prices the lanes before it forwards the request. None of these require trusting a benchmark. All three are running today.

\n

Related posts

\n\n

The grep tooling is in terraphim-clients. The routing proxy from section 3 is terraphim-llm-proxy, shared with GitHub Sponsors supporters. If you want this running inside your team rather than as homework, we do it as part of our consulting work at zestic.ai.

\n", "https://terraphim.ai/properties/date" : "2026-10-19", "https://terraphim.ai/properties/tags" : {"tags":["AI-agents","cost","LLM","tokens","Terraphim","proxy"],"categories":["Engineering"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/cold-start-tax-agentic-memory/", "https://atomicdata.dev/properties/name" : "A project lesson your coding agent can find next time", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/cold-start-tax-agentic-memory/", "https://atomicdata.dev/properties/description" : "

You explain the project's validation command. The session ends. Next time, the agent needs the same explanation. Keeping the instruction somewhere is useful only if the next run can find the right instruction again.

\n

This walkthrough saves one lesson from a fictional project, opens it in a new process, and retrieves it through a small knowledge graph. You can inspect the exact saved text and repeat the same checks with the downloadable example.

\n\n

Download the Harbour example · Read the transcript

\n

Start with an instruction worth keeping

\n

Harbour is a small public project brief. It records a decision, a risk and an owner. Before publication, its validator checks that all three fields are present. The instruction we want the next session to remember is deliberately specific:

\n
Validate the Harbour project brief with python3 validate-brief.py --check.\nKeep the source decisions in brief.md intact.\n
\n

That gives a future agent an action and a boundary. “Remember to be careful” would be much harder to use. The example also includes the brief and validator, so the instruction has something concrete to refer to.

\n

The first step is to save this actual text. Download and extract the example, then install terraphim-agent v1.21.20. From the example folder, prepare a new, isolated run before entering the manual commands below:

\n
python3 reproduce.py --agent /path/to/terraphim-agent \\\n  --output ./harbour-run --prepare-only\ncd harbour-run/fixture\nexport TERRAPHIM_DEFAULT_DATA_PATH="$(cd .. && pwd)/data"\nexport TERRAPHIM_SETTINGS_PATH="$(cd .. && pwd)/settings"\n
\n

Use your actual binary path in the first command and put that same verified binary on your PATH for the remaining commands. Preparation creates the role configuration, settings and lesson.md; it has not captured anything yet. To run all checks automatically instead, omit --prepare-only and choose a fresh output folder.

\n
terraphim-agent --format json memory capture \\\n  --file lesson.md \\\n  --provenance-tag harbour-public-brief-v1\n
\n

Capture returns a memory identifier. We use that identifier to inspect the saved item, rather than treating a successful exit code as the whole result. The saved content is the lesson itself, and the provenance tag identifies which public example supplied it.

\n

--content accepts a short instruction directly. --file is convenient for a multiline note. Both preserve the supplied text. Missing, blank, unreadable or conflicting inputs fail without creating a substitute placeholder.

\n

End the process, then open the memory

\n

Each command in the demonstration starts a new process. After capture exits, memory show opens the saved identifier. memory list finds the item, and memory export includes the same instruction in JSON.

\n
terraphim-agent --format json memory show MEMORY_ID\nterraphim-agent --format json memory list\nterraphim-agent memory export --format json --output memories.json\n
\n

Replace MEMORY_ID with the identifier returned by capture. The reproduction script does this automatically and checks that the reopened and exported text exactly matches lesson.md.

\n

\"A

\n

The store has an explicit location. The example sets TERRAPHIM_DEFAULT_DATA_PATH to a new folder for that run; the evolution file lives beneath terraphim/evolution/cli-agent.json. A second empty folder supplies the independent-store check. This keeps the demonstration separate from your existing memory files.

\n

Without an explicit data root, the agent retains its usual platform configuration-directory location. Changing the root selects another store; it does not silently migrate or merge your previous one.

\n

Teach the role the words used by the project

\n

Knowing an identifier is useful for inspection. Day to day, you are more likely to ask a question such as “validate brief”. The Brief Reviewer role supplies the terminology for that question.

\n

Its small graph has a Brief validation concept:

\n
# Brief validation\nsynonyms:: validate brief, brief validation, --check\n
\n

A second concept describes the Project brief, including brief.md. Both definitions are ordinary Markdown in the download. The saved instruction mentions these concepts, connecting an action with the document it applies to.

\n

The synonyms:: property makes the relationship visible: “validate brief” and --check are labels for the same concept in this project. You can review or change that relationship. Saving a memory does not invent new terminology or update every other role automatically.

\n

This is the same explicit-knowledge principle used in the editor-to-search example: record the relationship, then use the configured graph to find relevant work. Here the searched material is an authored memory item.

\n

Retrieve the instruction, then check the empty cases

\n

With the example's role configuration loaded, this query retrieves the stored lesson:

\n
terraphim-agent --config ../config.json memory retrieve 'validate brief' \\\n  --role 'Brief Reviewer' --format json\n
\n

The result includes the original text, its memory identifier, the provenance tag and a matched concept. It is a retrieved instruction, not a generated paraphrase. The viewer can compare it directly with the file that was captured.

\n

\"The

\n

The accompanying controls matter just as much. “Volcanic eruption” returns no memory. The Finance Reviewer role, which has budget and grant concepts, does not match the validation query. The same useful query against a separate empty store also returns nothing.

\n

Those observations distinguish useful retrieval from a command that always prints the latest note. Roles shape which concepts are recognised. They are not an access-control system: use separate stores and ordinary filesystem permissions where separation is required.

\n

What happens inside the CLI

\n

The agent stores the lesson using Terraphim's existing evolution types. During retrieval, the role's thesaurus matches terms, and the role graph ranks memory items by their concept relationships. There is no lexical fallback when a question matches none of the configured concepts.

\n

This graph uses co-occurrence edges, so the example intentionally connects validation with the project brief. A single isolated concept is not enough to assume the same retrieval behavior. Keep the graph and the note inspectable, and test the questions people will actually ask.

\n

memory apply can preview proposed context for a prompt. That preview does not execute a command or prove a coding host consumed it. The separate hooks walkthrough will follow the instruction into actual execution. Captured memories and reviewed learning corrections also use different stores; neither is an automatic copy of the other.

\n

Try the next run yourself

\n

The ZIP contains the public brief, validator, lesson, Markdown concepts, reproduction script and saved outputs. Follow its README to verify the released binary, create an isolated run and compare the positive and negative results. The script checks the saved content, rather than relying on expected screenshots.

\n

Download and reproduce the memory example. You can also inspect the saved outputs and verification manifest.

\n

The useful result here is modest and concrete: an instruction survives the process that captured it, and the intended project terminology can find it again. Measuring whether that saves tokens or improves later decisions needs a separate experiment.

\n

Updated 13 October 2026 with a reproducible walkthrough. The broader memory-lifecycle vocabulary was inspired by memco.ai's field guide. The video uses synthetic British female narration and readable views of actual CLI outputs. The Harbour fixture is public sample data.

\n", "https://terraphim.ai/properties/date" : "2026-07-01", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","ai","agentic-engineering","memory","knowledge-graph","developer-tools"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/terraphim-forge-public-demo/", "https://atomicdata.dev/properties/name" : "Try Terraphim Forge: public demo open at demo.terraphim-forge.com", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/terraphim-forge-public-demo/", "https://atomicdata.dev/properties/description" : "

We just opened the public demo of Terraphim Forge at demo.terraphim-forge.com. It is a free, anonymous, self-serve instance of our Gitea fork running on Firecracker microVMs. Sign up, push code, publish a Cargo crate, run our PageRank-based issue triage tool. Everything resets at 04:00 UTC daily, so bring nothing irreplaceable.

\n

What it is

\n

Terraphim Forge is a pay-first SaaS that hands a paying customer their own Gitea-on-Firecracker microVM at <their-id>.terraphim-forge.com within ~30 seconds of completing checkout. The persistent paid tiers will go on the price page later this week; the public demo is what you can try right now without paying anything.

\n

The demo is one VM, public-facing, with anonymous registration enabled. Four canonical repositories are seeded on every refresh:

\n\n

You can fork any of them into your demo account, push to your forks, and use the platform exactly as a paying customer would.

\n

What you can actually do on it

\n

Push code, including LFS

\n
# Sign up at https://demo.terraphim-forge.com/user/sign_up first.\ngit clone https://demo.terraphim-forge.com/<you>/<repo>\ncd <repo>\ngit lfs track '*.bin'\ngit add .gitattributes some.bin && git commit -m "with LFS"\ngit push\n
\n

LFS objects land in our SeaweedFS-backed S3 store; the demo bucket gets wiped at 04:00 UTC along with the VM, so do not use this for anything you care about.

\n

Publish a Cargo crate to the per-user registry

\n

Every demo user gets their own Cargo registry endpoint at /api/packages/<your-user>/cargo. Generate a Personal Access Token in the Gitea UI (Settings -> Applications, scopes read:package, write:package), then:

\n
mkdir my-crate && cd my-crate\ncargo init --lib\n# minimal Cargo.toml: name, version, edition, license\ncargo publish --registry-url \\\n    "https://demo.terraphim-forge.com/api/packages/<you>/cargo" \\\n    --token "Bearer <your-pat>"\n
\n

The .crate lands in SeaweedFS, becomes downloadable from the sparse index. We verified the round-trip end-to-end (publish, sparse-index lookup, presigned-URL download, sha256 match) on a freshly-provisioned VM the day we opened the demo.

\n

Run gitea-robot against the demo

\n

gtr is our PageRank-based issue triage tool. It scores issues by how many other issues they unblock, so you fix the high-leverage ones first.

\n
git clone https://demo.terraphim-forge.com/terraphim/gitea-robot\ncd gitea-robot\nbun install\nexport GITEA_URL=https://demo.terraphim-forge.com\nexport GITEA_TOKEN=<your-pat>\n./bin/gtr triage --owner <you> --repo <your-repo>\n./bin/gtr ready --owner <you> --repo <your-repo>\n./bin/gtr graph --owner <you> --repo <your-repo>\n
\n

Read-only browsing of terraphim/gitea-robot works without a login.

\n

The catch

\n
\n

The demo resets every day at 04:00 UTC. Your repos, your packages, your account, the admin password -- all gone, all replaced. We rebuild from a known-good golden rootfs, re-mirror the four seeded repos from canonical Gitea, and rotate the admin password from 1Password.

\n
\n

This is deliberate. Twenty-four-hour lifetime makes the demo a poor target for spam, persistence-style abuse, or content-takedown drama. It also keeps the surface honest: you can never end up trusting a piece of state that turns out to have been there for six months by accident.

\n

If you want a Forge that does not reset, that is the paid tier; the price page goes up later this week.

\n

How it is built

\n

Each demo session and each paying customer gets their own Firecracker microVM. Boot time is ~330 ms total (network configure, drive attach, kernel boot, instance start). The full pay-first chain -- landing -> Stripe checkout -> webhook -> microVM provisioned -> admin user created -> Caddy route added -> customer logged in and pushing code -- runs in ~30 seconds end-to-end.

\n

A few of the load-bearing engineering decisions:

\n

Per-VM rootfs (copy-on-write). Firecracker exposes the host file as a raw virtio-blk device with no isolation. Two VMs sharing the same path with is_read_only: false will silently corrupt each other's ext4+SQLite. We copy the golden image to /var/lib/firecracker/images/instances/<vm_id>.rootfs before add_drive so each VM gets its own private writable disk. Cleanup happens automatically on stop.

\n

forge.fqdn= kernel arg. Each VM boots with forge.fqdn=<user>.terraphim-forge.com in /proc/cmdline. A systemd ExecStartPre hook in the rootfs reads it and patches app.ini so Gitea's DOMAIN and ROOT_URL are right before the daemon starts. Without it, every public URL would be https://localhost/ and the customer experience would be broken in ways that take a while to track down.

\n

Stable demo password from 1Password. The refresh job reads op://TerraphimPlatform/forge-demo/password every cycle and applies it to the freshly-provisioned admin user via gitea admin user change-password. No more lost demo creds.

\n

Caddy on-demand TLS. Each customer subdomain gets its own ACME cert on first request; Caddy reuses it across daily refreshes since the SAN does not change.

\n

SeaweedFS for everything that is not git. LFS, packages (Cargo registry, generic uploads), and repo archives all go to a SeaweedFS S3 bucket. Same bucket survives demo refreshes (we wipe per-user namespaces, not the whole bucket).

\n

The VM image build (gitea-vm-image) and the control plane (firecracker-rust) are both Rust. The control plane is fcctl-web + fcctl-core, the latter is the Firecracker driver and the former is the Stripe-aware web service that wires customer signup to VM provisioning.

\n

Where it is going

\n

Short term:

\n\n

Medium term:

\n\n

If you want a particular integration, ping us on the demo (open an issue in any repo there) or send us a note on social — we will be opening a public Forge tracker as the source repos go public.

\n

Source code

\n

The Rust control plane is being prepared for public release; the source repository will be opened up alongside this demo over the next few days. The four canonical repositories are currently visible on the demo itself (see the links earlier in this post), and a fork of our Gitea fork is one of them, so you can already read the patches we run by signing up on the demo and browsing terraphim/gitea.

\n

When the public release lands, the URLs will be:

\n\n

Follow @terraphim_ai for the public-release announcement.

\n

Try it

\n

demo.terraphim-forge.com

\n

If you break it, we will see it in the next refresh and fix it. If you build something cool on it, tag @terraphim_ai and we will boost it.

\n", "https://terraphim.ai/properties/date" : "2026-05-03", "https://terraphim.ai/properties/tags" : {"categories":["Product"],"tags":["terraphim-forge","gitea","firecracker","cargo-registry","demo","self-hosted"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/experiment-results-opencode-terraphim-2026-05-02/", "https://atomicdata.dev/properties/name" : "OpenCode + Terraphim Experiment Results", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/experiment-results-opencode-terraphim-2026-05-02/", "https://atomicdata.dev/properties/description" : "

OpenCode + Terraphim Experiment Results

\n

Date: 2026-05-02\nTask: Build accessible navigation component in SvelteKit\nProject: ~/projects/frontend-test (fresh SvelteKit project)

\n

Hypothesis

\n

OpenCode with terraphim-agent (KG-boosted search) produces better results faster than OpenCode without terraphim.

\n

Setup

\n\n\n\n\n\n
ComponentVersion
OpenCode1.14.31
terraphim-agent1.17.0
terraphim_mcp_serverbuilt from source
SvelteKit2.57.0 + Svelte 5.55.2
\n

Flow A: OpenCode WITH terraphim

\n\n

Flow B: OpenCode WITHOUT terraphim (control)

\n\n

Results

\n\n\n\n\n\n\n\n
MetricFlow A (+terraphim)Flow B (control)Difference
Steps1116-31%
Total tokens500,749686,995-27%
Tool calls1517-12%
Final tokens50,59550,510+0.2%
Cache read428,544613,819-30%
Cache write55,41455,910-1%
\n

Analysis

\n

Efficiency Gains

\n

Flow A (with terraphim) was 27% more token-efficient and completed in 31% fewer steps. This suggests:

\n
    \n
  1. KG-boosted search helped - The Frontend Developer role KG contains accessibility patterns that OpenCode used
  2. \n
  3. Better initial understanding - terraphim search found relevant Svelte/accessibility examples faster
  4. \n
  5. Reduced exploration - OpenCode didn't need to explore as many files to understand the project
  6. \n
\n

Code Quality

\n

Both flows produced working components with:

\n\n

Flow A additionally identified and fixed:

\n\n

Cache Efficiency

\n

Flow A had 30% less cache read - the KG records likely provided more relevant context upfront, reducing redundant lookups.

\n

Session IDs

\n\n

Raw Data

\n

Full JSON logs available at:

\n\n

Conclusion

\n

Hypothesis confirmed: OpenCode with terraphim-agent produces results 27% faster (token efficiency) with 31% fewer steps for accessibility-focused frontend tasks.

\n

The KG records for Frontend Developer provide targeted patterns for:

\n\n

This supports the value of role-based knowledge graphs for AI coding assistants.

\n", "https://terraphim.ai/properties/date" : "2026-05-02", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","OpenCode","AI","experiment","knowledge-graph"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/fff-vs-ripgrep/", "https://atomicdata.dev/properties/name" : "FFF vs Ripgrep: Understanding the Difference", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/fff-vs-ripgrep/", "https://atomicdata.dev/properties/description" : "

A common point of confusion in Terraphim is understanding the difference between FFF (fzf-like fuzzy file finder) and Ripgrep haystack. This post clarifies what each does and how they complement each other.

\n

TL;DR

\n

FFF is NOT a haystack. FFF provides MCP tools for fuzzy file finding and content grep. Ripgrep is a haystack ServiceType for exhaustive content search. They serve different purposes and can be used together.

\n

Haystack Architecture

\n

In Terraphim, a haystack is a searchable data source configured in your role definition:

\n
{\n  "haystacks": [\n    {\n      "location": "/path/to/project",\n      "service": "Ripgrep",\n      "read_only": true\n    }\n  ]\n}\n
\n

Available haystack ServiceTypes:

\n\n\n\n\n\n\n\n
ServiceTypePurposeKG Ranking
RipgrepLocal content searchVia relevance function
GrepAppGitHub code searchVia relevance function
AtomicAtomic ServerVia relevance function
QueryRsRust API docsVia relevance function
QuickwitLog searchVia relevance function
JmapEmail searchVia relevance function
\n

FFF: MCP Tools, Not a Haystack

\n

FFF (Fast File Finder) is a separate system that provides MCP tools for AI coding agents. It's not a haystack and cannot be configured as one.

\n

FFF MCP Tools

\n\n\n\n\n
ToolPurposeOutput
terraphim_find_filesFuzzy file path searchRanked list of file paths
terraphim_grepContent grep with KG orderingLines with matches
terraphim_multi_grepMulti-pattern Aho-Corasick grepLines matching any pattern
\n

FFF Architecture

\n
Query → FilePicker (scan files) → fuzzy_search → KG scorer (path boost) → ranked results\nQuery → File list → KG scorer (sort by path score) → grep_search → matches\n
\n

Key features:

\n\n

Comparison Table

\n\n\n\n\n\n\n\n\n
AspectRipgrep HaystackFFF Tools
TypeHaystack (configured in role)MCP tools
Content searchYes (regex, exhaustive)Yes (fff grep engine)
File path searchNoYes (fuzzy)
FrecencyNoYes
KG integrationRelevance functionkg_scorer (path boost)
Output formatRanked documentsFiles + content lines
PaginationNoCursor-based
\n

How They Work Together

\n

Ripgrep Haystack Flow

\n
Query → terraphim search → role relevance function → Ripgrep → KG concept match → ranked docs\n
\n
    \n
  1. Query hits terraphim search command
  2. \n
  3. Role's relevance function (e.g., terraphim-graph) scores documents
  4. \n
  5. Ripgrep searches content
  6. \n
  7. KG concept matching boosts conceptually relevant docs
  8. \n
\n

FFF MCP Tool Flow

\n
Query → terraphim_find_files → fuzzy path match → KG scorer (path) → ranked paths\nQuery → terraphim_grep → KG scorer (sort files) → grep → matches\n
\n
    \n
  1. AI agent calls terraphim_find_files or terraphim_grep directly
  2. \n
  3. FFF scans files and applies fuzzy matching
  4. \n
  5. KG scorer boosts files with KG concept matches in path
  6. \n
  7. Results returned directly to AI agent
  8. \n
\n

When to Use Each

\n

Use Ripgrep Haystack When:

\n\n

Use FFF Tools When:

\n\n

Use Both When:

\n\n

Configuration Example

\n

Role with Ripgrep Haystack

\n
{\n  "roles": {\n    "Frontend Developer": {\n      "relevance_function": "terraphim-graph",\n      "haystacks": [\n        {\n          "location": "/path/to/project",\n          "service": "Ripgrep"\n        }\n      ]\n    }\n  }\n}\n
\n

FFF MCP Tools

\n

FFR tools are registered separately in OpenCode:

\n
{\n  "mcp": {\n    "terraphim": {\n      "type": "local",\n      "command": ["/path/to/terraphim_mcp_server"]\n    }\n  }\n}\n
\n

Tools available: terraphim_find_files, terraphim_grep, terraphim_multi_grep

\n

Key Takeaway

\n

FFF and Ripgrep are complementary, not competing:

\n\n

Both integrate with the knowledge graph but in different ways. Use Ripgrep haystack for thorough content search. Use FFF for quick file finding and when AI agents need direct tool access.

\n", "https://terraphim.ai/properties/date" : "2026-05-02", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","FFF","Ripgrep","knowledge-graph","haystack"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/frontend-developer-role-setup-v2/", "https://atomicdata.dev/properties/name" : "Setting Up a Frontend Developer Role in Terraphim", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/frontend-developer-role-setup-v2/", "https://atomicdata.dev/properties/description" : "

This guide documents the step-by-step process for setting up a Frontend Developer role in Terraphim, including knowledge graph validation, MCP server configuration, and integration with OpenCode.

\n

Prerequisites

\n\n

Step 1: Validate the Frontend Knowledge Graph

\n

Before deploying the knowledge graph, validate each concept file to ensure proper structure:

\n
# Knowledge graph source location\nKG_SOURCE="/home/alex/projects/terraphim/terraphim-ai/data/kg/frontend"\n\n# Validate each file has required structure\nfor f in "$KG_SOURCE"/*.md; do\n  echo "=== $(basename "$f") ==="\n  head -5 "$f"\n  echo\ndone\n
\n

Validation criteria:

\n\n

The frontend KG ships with 18 concept files covering:

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
DomainFiles
Svelte/SvelteKitsvelte-patterns.md, component-design.md
CSScss-layout.md, css-custom-properties.md, visual-design.md
TypeScripttypescript.md
Accessibilityaccessibility.md
Performanceperformance.md
Testingtesting-frontend.md
State Managementstate-management.md
Formsforms-validation.md
APIsapi-integration.md
Browser APIsbrowser-apis.md
Build Toolsbuild-tools.md
DXdeveloper-experience.md
Package Managementpackage-management.md
Responsive Designresponsive-design.md
Interactioninteraction-patterns.md
\n

Total: 316 synonyms across 18 concepts

\n

Step 2: Copy Knowledge Graph to User Config

\n
# Create directory\nmkdir -p ~/.config/terraphim/kg/frontend\n\n# Copy validated KG\ncp -r /home/alex/projects/terraphim/terraphim-ai/data/kg/frontend/* \\\n  ~/.config/terraphim/kg/frontend/\n\n# Verify\nls ~/.config/terraphim/kg/frontend/\n
\n

Step 3: Configure Settings

\n

Add role configuration path to settings.toml:

\n
# ~/.config/terraphim/settings.toml\nserver_hostname = "127.0.0.1:8000"\napi_endpoint = "http://localhost:8000/api"\ninitialized = "${TERRAPHIM_INITIALIZED:-false}"\ndefault_data_path = "${TERRAPHIM_DATA_PATH:-${HOME}/.terraphim}"\ndefault_role = "AI Engineer"\nrole_config = "/home/alex/.config/terraphim/embedded_config.json"\n
\n

Step 4: Configure the Frontend Developer Role

\n

Add the role to embedded_config.json:

\n
{\n  "roles": {\n    "Frontend Developer": {\n      "shortname": "fedev",\n      "name": "Frontend Developer",\n      "relevance_function": "terraphim-graph",\n      "terraphim_it": true,\n      "theme": "yeti",\n      "kg": {\n        "automata_path": null,\n        "knowledge_graph_local": {\n          "input_type": "markdown",\n          "path": "/home/alex/.config/terraphim/kg/frontend"\n        },\n        "public": false,\n        "publish": false\n      },\n      "haystacks": [\n        {\n          "location": "/home/alex/projects/frontend-test",\n          "service": "Ripgrep",\n          "read_only": true,\n          "fetch_content": false,\n          "extra_parameters": {}\n        }\n      ],\n      "llm_enabled": false\n    }\n  }\n}\n
\n

Key configuration choices:

\n\n\n\n\n\n
SettingValueRationale
relevance_functionterraphim-graphHybrid KG + TF-IDF scoring
terraphim_ittrueEnables text replacement via synonyms
llm_enabledfalseDeterministic search only
haystacks[0]RipgrepLocal project file search
\n

Step 5: Build terraphim_mcp_server

\n

For FFF-based file finding (fuzzy path + content search with KG scoring):

\n
cd ~/projects/terraphim/terraphim-ai\ncargo build --release -p terraphim_mcp_server\ncp target/release/terraphim_mcp_server ~/.cargo/bin/\n
\n

For GrepApp support (GitHub code search):

\n
cargo build --release -p terraphim_middleware --features grepapp\ncargo build --release -p terraphim_mcp_server\n
\n

Step 6: Register MCP in OpenCode

\n

Add to ~/.config/opencode/opencode.json:

\n
{\n  "mcp": {\n    "terraphim": {\n      "type": "local",\n      "command": ["/home/alex/.cargo/bin/terraphim_mcp_server"],\n      "environment": {\n        "TERRAPHIM_DATA_PATH": "~/.terraphim"\n      }\n    }\n  }\n}\n
\n

Step 7: Create Fresh Svelte Project

\n
cd ~/projects\nbunx sv create frontend-test --template minimal --types ts --no-install\n\ncd frontend-test\nbun install\nbun run build\n
\n

Step 8: Verify Integration

\n
# Reload config\nterraphim-agent config reload\n\n# List roles\nterraphim-agent roles list\n\n# Test search\nterraphim-agent search --role "Frontend Developer" --limit 5 "aria"\n
\n

Expected output:

\n
[103] README\n    /home/alex/projects/frontend-test/node_modules/aria-query/README.md\n    # ARIA Query\n...\n
\n

Understanding Haystack Types

\n

Ripgrep Haystack

\n

Standard content search using ripgrep:

\n
{\n  "location": "/path/to/project",\n  "service": "Ripgrep",\n  "read_only": true,\n  "extra_parameters": {}\n}\n
\n

Pros: Fast, exhaustive content search, regex support\nCons: No concept understanding, no frecency

\n

FFF (Fuzzy File Finder)

\n

Not a haystack - provides MCP tools for fuzzy file finding and KG-scored content search:

\n
# MCP tools provided by terraphim_mcp_server:\n# - terraphim_find_files: Fuzzy path search with KG boost\n# - terraphim_grep: Content search with KG-ordered files\n# - terraphim_multi_grep: Multi-pattern Aho-Corasick search\n
\n

Pros: Frecency (frequency + recency), KG path scoring\nCons: Different interface than haystack search

\n

GrepApp Haystack

\n

GitHub code search via grep.app API:

\n
{\n  "location": "https://grep.app",\n  "service": "GrepApp",\n  "extra_parameters": { "language": "typescript" }\n}\n
\n

Pros: Searches millions of public GitHub repos\nCons: Requires --features grepapp build, rate limits

\n

Architecture: Flow A vs Flow B

\n

Flow A: Ripgrep Haystack

\n
Query → terraphim search → Ripgrep haystack → KG-boosted ranking\n
\n

Flow B: FFF Tools

\n
Query → terraphim_find_files/grep → FFF (fuzzy + frecency) → KG path scoring\n
\n

Next Steps

\n
    \n
  1. Create navigation component: Use terraphim search to find accessibility patterns
  2. \n
  3. Iterate with WCAG audit: Find missing aria-label, fix, re-audit
  4. \n
  5. Add GrepApp: Build with --features grepapp for GitHub code search
  6. \n
\n

Troubleshooting

\n

\"Role not found\"

\n
terraphim-agent config reload\nterraphim-agent roles list\n
\n

\"GrepApp haystack support not enabled\"

\n

GrepApp requires building terraphim_middleware with --features grepapp:

\n
cargo build --release -p terraphim_middleware --features grepapp\ncargo build --release -p terraphim_mcp_server\n
\n

Search returns no results

\n

Check haystack location exists:

\n
ls -la /home/alex/projects/frontend-test\n
\n

Related Documentation

\n\n", "https://terraphim.ai/properties/date" : "2026-05-02", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","walkthrough","knowledge-graph","frontend","Svelte","TypeScript","agent"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/sentrux-vs-terraphim-eval-comparison/", "https://atomicdata.dev/properties/name" : "Sentrux vs Terraphim: Two Approaches to AI Code Quality Evaluation", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/sentrux-vs-terraphim-eval-comparison/", "https://atomicdata.dev/properties/description" : "

As AI agents write more and more production code, the question shifts from \"can the agent write code?\" to \"can we verify the code is good?\" Two tools tackle this from opposite ends: Sentrux measures structural health, Terraphim measures semantic completeness. Neither is complete without the other.

\n

The Problem They Both Solve

\n

An AI agent that generates 500 lines of syntactically correct Rust can still degrade a codebase. It might introduce tight coupling, leave behind unimplemented stubs, create circular dependencies, or raise the cyclomatic complexity past any reasonable threshold. Standard CI pipelines catch compilation errors and failing tests. They do not catch architectural erosion.

\n

Both Sentrux and the Terraphim evaluation toolkit are designed to close that gap. They just do so from fundamentally different perspectives.

\n
\n

Sentrux: Structural Analysis

\n

Sentrux (v0.5.7, MIT, 27.7k lines of Rust) is a real-time structural analysis engine. It parses source code into an AST using tree-sitter, builds a dependency graph, and computes a quality signal from 0 to 10,000.

\n

Five Root Cause Metrics

\n

Sentrux computes a geometric mean across five orthogonal dimensions:

\n\n\n\n\n\n\n
MetricWhat it captures
ModularityFan-in and fan-out between modules; god file detection
AcyclicityCircular dependency count and which files participate
DepthMaximum dependency chain length; instability score
EqualityCyclomatic complexity distribution (Gini coefficient); large files
RedundancyDead functions; duplicate code groups
\n

These are structural facts derived from the AST and dependency graph, not text patterns. Sentrux does not care what the code says; it cares how it connects.

\n

How It Works with Agents

\n

Sentrux ships a native MCP server with nine tools. The intended agent workflow is:

\n
sentrux.scan("/path/to/project")\n  -> { quality_signal: 7342, files: 139, bottleneck: "modularity" }\n\nsentrux.session_start()\n  -> baseline saved\n\n... agent writes code ...\n\nsentrux.session_end()\n  -> { pass: false, signal_before: 7342, signal_after: 6891,\n       summary: "Quality degraded during this session" }\n
\n

The agent gets a precise numeric verdict with a named bottleneck. It can iterate: check the bottleneck, fix it, call rescan, repeat.

\n

The GUI

\n

Sentrux includes a live treemap built with egui and wgpu. Files are sized by metric contribution and glow when modified. Dependency edges are drawn between coupled files. A file system watcher (notify) feeds changes over crossbeam-channel to the renderer in real time. The same process that runs the GUI hosts the MCP server, so you can watch architectural changes happen as the agent works.

\n

Language Support

\n

52 languages via tree-sitter plugins. Each plugin is a plugin.toml and a tags.scm query file. No Rust required to add a language.

\n
\n

Terraphim Evaluation Toolkit: Semantic Completeness

\n

The Terraphim approach lives across two production crates in terraphim-ai: terraphim_codebase_eval and terraphim_negative_contribution. These are not a conceptual framework or a shell script wrapper; they are typed Rust libraries integrated into the agent review pipeline.

\n

The Manifest System (terraphim_codebase_eval)

\n

The evaluation manifest is a TOML file that describes a before/after comparison at the git SHA level:

\n
[[haystacks]]\nid = "baseline"\npath = "/srv/repo"\ncommit_sha = "abc123"\nstate = "baseline"\n\n[[haystacks]]\nid = "candidate"\npath = "/srv/repo"\ncommit_sha = "def456"\nstate = "candidate"\n\n[[roles]]\nrole_id = "code-reviewer"\ndescription = "Reviews for bugs and maintainability"\nterm_sets = ["bug-patterns", "code-smells"]\n\n[roles.scoring_weights]\nsearch_score = 1.0\ngraph_density = 0.8\nentity_count = 1.0\n\n[[queries]]\nquery_text = "highlight potential bugs"\nrole_id = "code-reviewer"\nexpected_signal = "increase"\nconfidence_threshold = 0.6\n\n[thresholds]\nimproved_pct = 10.0\ndegraded_pct = 5.0\ncritical_test_failures = 0\n
\n

Roles define the evaluation perspective. Each role carries named term sets (Aho-Corasick dictionaries built from domain knowledge graphs) and per-dimension scoring weights. Queries specify what to search for and in which direction the score should move. The manifest is validated for referential integrity before execution: any query that references a non-existent role is rejected at load time, not at runtime.

\n

The verdict logic is explicit: if the weighted score increases by more than improved_pct, the contribution is classified as Improved; if it drops by more than degraded_pct, it is Degraded; any new test failure triggers immediate Degraded regardless of scores.

\n

The EDM Scanner (terraphim_negative_contribution)

\n

The Explicit Deferral Marker (EDM) scanner answers a specific and critical question: did the agent ship stubs as production code?

\n

It uses the Aho-Corasick automata to detect markers in Rust source that indicate deferred implementation:

\n\n

The scanner is production-only by design. It automatically skips:

\n\n

Suppression is available per-line: // terraphim: allow(stub) silences the finding on that line only. Every finding carries a file path, line number, severity, category, confidence (0.95), and a suggestion drawn from the thesaurus URL metadata.

\n

The scanner outputs a ReviewAgentOutput struct consumed directly by the Terraphim review pipeline. An agent that ships one todo!() in production code fails the gate.

\n
\n

Side-by-Side Comparison

\n\n\n\n\n\n\n\n\n\n\n
DimensionSentruxTerraphim EDM ScannerTerraphim Manifest Eval
Core mechanismtree-sitter AST + dependency graphAho-Corasick on EDM pattern thesaurusAho-Corasick on domain KG + weighted scoring
What it measuresArchitecture: coupling, cycles, complexityIncomplete implementations in production codeSemantic quality delta between two git SHAs
Language scope52 languagesRust only (production files)Any language with KG term sets
Unit of comparisonQuality signal delta within a sessionPass/fail per fileBefore/after manifest with role-weighted scores
Agent integrationMCP server (9 tools, session lifecycle)ReviewAgentOutput struct in review pipelineEvaluationManifest loaded per evaluation run
False positive riskLow (graph-structural, not text)Very low (exact stub patterns, test exclusions)Medium (depends on KG quality)
Customisationrules.toml (layer boundaries, thresholds)// terraphim: allow(stub) suppressionKG term sets, role weights, query direction
Live feedbackYes (file watcher, treemap, MCP)No (batch scan)No (batch manifest)
Verdict granularityNamed bottleneck + per-metric breakdownFinding list with file:line and suggestionImproved / Degraded / Neutral with percentage
\n
\n

Where They Complement Each Other

\n

These tools are not alternatives. They operate at different layers of the quality stack:

\n

Sentrux answers: Is the architecture getting worse?

\n

Terraphim EDM Scanner answers: Did the agent leave stubs in production code?

\n

Terraphim Manifest Eval answers: Did the agent improve or degrade domain-specific semantic quality across these two commits?

\n

A complete agent quality gate combines all three:

\n
    \n
  1. sentrux session_start before the agent begins work
  2. \n
  3. Agent writes code
  4. \n
  5. sentrux session_end to verify no structural degradation
  6. \n
  7. Terraphim EDM scan to verify no stubs shipped to production
  8. \n
  9. Terraphim manifest eval (optional, for domain-specific semantic coverage) comparing the baseline and candidate SHAs
  10. \n
\n

If any gate fails, the contribution is blocked. The agent gets specific, actionable feedback: a named structural bottleneck from Sentrux, a file and line number from the EDM scanner, or a percentage degradation from the manifest evaluator.

\n
\n

Choosing Your Starting Point

\n

If you are instrumenting an AI agent pipeline today, start with the Terraphim EDM scanner. It requires no configuration beyond pointing it at your Rust source. It has a binary pass/fail verdict, zero false positives on well-written production code, and integrates directly into the existing ReviewAgentOutput pipeline.

\n

Add Sentrux when you want continuous architectural visibility. The MCP integration means the agent can self-correct in real time rather than discovering structural problems only at gate check.

\n

Add the Terraphim manifest evaluation when you have a domain knowledge graph and want to verify that the agent's changes improve semantic coverage in your specific domain, not just compile and pass tests.

\n

Together, they give you three independent quality signals that a capable agent must satisfy simultaneously: structural soundness, implementation completeness, and semantic improvement.

\n
\n

Further Reading

\n\n", "https://terraphim.ai/properties/date" : "2026-04-29", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","code-quality","AI-agents","evaluation","comparison","sentrux"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/sub-millisecond-context-knowledge-graphs/", "https://atomicdata.dev/properties/name" : "Sub-Millisecond Context: How Aho-Corasick Automata Replace Embedding Calls", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/sub-millisecond-context-knowledge-graphs/", "https://atomicdata.dev/properties/description" : "

Vector embedding calls are the hidden tax on every RAG pipeline. You pay latency, you pay API cost, you get probabilistic results that vary run to run. There is a class of problem where none of that is acceptable. This post shows how Terraphim replaces embedding calls with Aho-Corasick finite-state automata -- deterministic, auditable, and under one millisecond for 1.4 million patterns.

\n

The Problem with Embedding-Based Context

\n

When you call an embedding API to retrieve context for an LLM prompt, three things happen:

\n
    \n
  1. You pay latency. Even fast embedding models add 20-100ms per call. At scale, this compounds.
  2. \n
  3. You get probabilistic results. Two runs on the same input may return different top-k documents depending on float precision and index state.
  4. \n
  5. You lose auditability. A cosine similarity score tells you nothing about why a document was retrieved.
  6. \n
\n

For general-purpose assistants, these tradeoffs are acceptable. For domain-specific systems -- medical, legal, engineering -- they are not. A system that cannot explain its retrieval decisions cannot be trusted.

\n

The Aho-Corasick Alternative

\n

Aho-Corasick is a classical multi-pattern string matching algorithm. Given a dictionary of N patterns, it builds a finite-state automaton at construction time and then scans any input text in O(n) time regardless of how many patterns are in the dictionary.

\n

Terraphim builds knowledge graph automata on top of this: each node in the automaton is a domain concept, edges encode synonyms and related terms, and matching returns not just a span but a structured entity with graph position.

\n
Input text: "patient presents with BRAF V600E mutation"\n                                    |\n                            Aho-Corasick scan\n                                    |\n         Match: "BRAF V600E" -> node: Gene:BRAF, variant: V600E\n                                    |\n                            Graph traversal\n                                    |\n         Edges: BRAF -> Treats <- Vemurafenib\n                BRAF -> TestedBy <- Cobas 4800 assay\n                BRAF -> Contraindicated <- Sorafenib (paradoxical activation)\n
\n

The match is deterministic. The traversal is deterministic. The context injected into the prompt is always the same for the same input.

\n

Architecture

\n
┌─────────────────────────────────────────────────────┐\n│                   Input Text                        │\n└───────────────────────┬─────────────────────────────┘\n                        │\n              ┌─────────▼──────────┐\n              │  Aho-Corasick FSM  │  < 1ms for 1.4M patterns\n              │  (terraphim_automata│\n              └─────────┬──────────┘\n                        │ matched spans + normalized terms\n              ┌─────────▼──────────┐\n              │   Thesaurus Layer  │  synonym expansion,\n              │  (terraphim_types) │  canonical form resolution\n              └─────────┬──────────┘\n                        │ NormalizedTerm { url, rank, ... }\n              ┌─────────▼──────────┐\n              │   Role Graph       │  27 node types, 65 edge types\n              │  (terraphim_       │  Jaccard + path distance scoring\n              │   rolegraph)       │\n              └─────────┬──────────┘\n                        │ ranked context passages\n              ┌─────────▼──────────┐\n              │   Prompt Builder   │  inject into LLM prompt\n              └────────────────────┘\n
\n

Each stage is a Rust crate with a stable public API. You can use any layer independently.

\n

Getting Started

\n

Install

\n
cargo add terraphim_automata terraphim_types terraphim_rolegraph\n
\n

For Python (via PyO3 bindings):

\n
pip install terraphim-automata\n
\n

For JavaScript/TypeScript (via WASM):

\n
npm install @terraphim/automata\n
\n

Build an Automaton from a Thesaurus

\n

The thesaurus is a JSON file mapping term strings to NormalizedTerm records. Terraphim ships pre-built thesauri for SNOMED CT, UMLS, and software engineering domains. You can also build your own from markdown knowledge graph files.

\n
use terraphim_automata::{load_thesaurus_from_json, find_matches};\n\nlet thesaurus_json = std::fs::read_to_string("snomed-tier1.json")?;\nlet thesaurus = load_thesaurus_from_json(&thesaurus_json)?;\n\nlet text = "Patient presents with BRAF V600E mutation and melanoma stage IV.";\nlet matches = find_matches(text, thesaurus, true)?; // true = leftmost-longest\n\nfor m in &matches {\n    println!("{:?} at {:?}", m.term, m.pos);\n}\n
\n

find_matches is O(n) in the input length. On an M2 MacBook Pro, matching 1.4 million SNOMED patterns against a 500-word clinical note completes in 0.3ms.

\n

Add Knowledge Graph Traversal

\n

Once you have matched entities, traverse the role graph to collect supporting context:

\n
use terraphim_rolegraph::RoleGraph;\n\nlet graph = RoleGraph::from_kg_path("~/.config/terraphim/kg/medical/")?;\n\nfor m in &matches {\n    let context = graph.traverse(&m.normalized_term, depth: 2)?;\n    // context contains related concepts, evidence paths, ranked passages\n}\n
\n

The traversal depth controls how far to expand from each matched entity. Depth 1 gives direct neighbours (synonyms, treatments, contraindications). Depth 2 adds second-degree connections (clinical trials, guidelines, variants).

\n

Measured Impact: MedGemma with and without KG Context

\n

We ran identical clinical cases through Google's MedGemma model with and without Terraphim knowledge graph grounding:

\n\n\n\n\n
CaseRaw MedGemma (no KG)With Terraphim KG Grounding
BRAF V600E Melanoma\"BRAF inhibitor (e.g., Dabrafenib + Trametinib)\" -- vague class suggestionVemurafenib 450mg orally once daily -- specific drug and dose
CYP2D6 Codeine SensitivityOxycodone 5 mg/mL -- wrong drug entirelyCodeine 60mg every 6h -- correct drug from KG context
EGFR NSCLCOsimertinib 80mg (correct on this run; prior run hallucinated 800mg -- a 10x overdose)Osimertinib 80mg -- consistently correct per FLAURA trial
\n

Without graph grounding, the LLM gives vague class-level suggestions, recommends the wrong drug, or produces dosing errors that vary between runs. With Terraphim KG grounding, every recommendation is specific, correct, and reproducible.

\n

Evaluation results across 36 real inference runs

\n\n\n\n\n
RunPass RateSafety GateKG GroundingAvg Latency
CPU18/18 (100%)100%83.3%165.3s
GPU #118/18 (100%)100%77.8%23.5s
GPU #218/18 (100%)100%83.3%24.8s
\n

36 total inference calls. Zero safety failures. No mocked responses.

\n

The LLM latency dominates (23-165 seconds depending on hardware). The Terraphim matching and graph traversal contributes under 1ms to each call.

\n

Why This Matters Beyond Medical

\n

The medical case is the hardest version of the problem: the stakes are high, the domain is large (1.4M SNOMED terms), and incorrect context causes real harm. The same architecture applies anywhere you need deterministic, auditable retrieval:

\n\n

System Footprint

\n

The full stack -- MedGemma 4B + SNOMED automata + role graph -- runs on a single machine in under 4GB RAM. There is no vector database daemon to operate, no embedding API to call, and no GPU required for the retrieval layer.

\n
terraphim_automata (Aho-Corasick FSM, 1.4M patterns): ~800MB RAM\nMedGemma 4B (quantised):                             ~2.8GB RAM\nRole graph (27 node types, 65 edge types):            ~120MB RAM\nTotal:                                                ~3.7GB\n
\n

Compare this to a typical embedding-based RAG stack: embedding model (~500MB) + vector database process (~1-2GB) + embedding API latency per call.

\n

Key Numbers

\n\n

Further Reading

\n\n

The theory behind automata-based context injection, when to use it versus embeddings, and how to compose it with LLM routing is the subject of Chapters 5-7 of Context Engineering with Knowledge Graphs (launching 2026).

\n

Source: github.com/terraphim/terraphim-ai -- 42 Rust crates, WASM-ready, MCP-native, Apache 2.0.

\n", "https://terraphim.ai/properties/date" : "2026-04-29", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","knowledge-graph","Aho-Corasick","FST","context-engineering","tutorial"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/frontend-developer-agent-walkthrough/", "https://atomicdata.dev/properties/name" : "Building a Front-End Developer Agent with Knowledge Graphs and Code Search", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/frontend-developer-agent-walkthrough/", "https://atomicdata.dev/properties/description" : "

We have published a comprehensive walkthrough showing how to build a specialised front-end developer agent using Terraphim's knowledge graph system, dual haystacks, and deterministic search. This post walks through the key concepts and links to the full guide.

\n

Why a Front-End Developer Agent?

\n

Front-end development spans a vast surface area: CSS layout, accessibility, TypeScript types, Svelte reactivity, build tooling, performance, testing, and more. When you search for \"how do I make this accessible?\" or \"what's the SvelteKit pattern for form validation?\", you want answers that understand your domain -- not generic web search results.

\n

Terraphim's deterministic knowledge graph approach means every search result is grounded in concepts you define, ranked by relevance, and fully reproducible. No hallucination, no non-deterministic LLM output.

\n

What the Agent Does

\n

The front-end developer agent combines three capabilities:

\n
    \n
  1. \n

    Knowledge Graph: 18 concept files covering responsive design, accessibility, Svelte/SvelteKit patterns, TypeScript, CSS layout, state management, build tools, testing, performance, and more. Each concept has synonyms that resolve deterministically via Aho-Corasick matching.

    \n
  2. \n
  3. \n

    Local Search (Ripgrep): Searches your project files -- .svelte, .ts, .css, .md -- using the knowledge graph to boost conceptually relevant files.

    \n
  4. \n
  5. \n

    Global Code Search (GrepApp): Searches millions of public GitHub repositories for TypeScript code patterns via the grep.app API, filtered to TypeScript for modern front-end relevance.

    \n
  6. \n
\n

Results from both haystacks are merged and ranked using TerraphimGraph, a hybrid scoring algorithm that combines knowledge graph concept matching with TF-IDF rescoring. In testing, a query for \"svelte component\" returned 13 results with TerraphimGraph versus 1 result with the simpler BM25Plus scorer. The 18 concept files with 358 synonyms actively influence ranking, not just display.

\n

The Knowledge Graph

\n

Each concept is a Markdown file with a heading, description, and synonym list:

\n
# Svelte Patterns\n\nSvelte-specific patterns for building reactive, compiled frontend\napplications using runes, stores, and SvelteKit conventions.\n\nsynonyms:: Svelte, SvelteKit, rune, $state, $derived, $effect,\n$props, bind, each block, await block, load function, +page.svelte\n
\n

When you search for $derived or +page.svelte, the Aho-Corasick automaton matches it to the \"Svelte Patterns\" concept in O(n+m) time. The matching is case-insensitive and leftmost-longest, so \"CSS grid\" matches as one term rather than two separate words.

\n

If no exact match exists, a TF-IDF fallback kicks in using trigger:: directives for semantic similarity.

\n

Hybrid Scoring: Why TerraphimGraph

\n

Terraphim offers multiple relevance functions. For a knowledge-graph-backed agent, terraphim-graph is strictly superior to the simpler bm25plus:

\n\n\n\n\n\n
AspectBM25PlusTerraphimGraph
KG concepts affect rankingNo (display only)Yes (graph + TF-IDF hybrid)
Term co-occurrenceNot usedBoosts related documents
KG link insertionDisabledEnabled in results
TF-IDF rescoringNot applied30% weight boost
\n

TerraphimGraph uses a two-pass scoring system. Pass 1 builds a co-occurrence graph from Aho-Corasick matches and ranks documents by total_rank = node_rank + edge_rank + document_rank. Pass 2 applies TF-IDF rescoring at 30% weight. Documents containing co-occurring concepts (e.g., \"svelte\" + \"component\" + \"state management\") score higher than those matching only one term.

\n

Svelte and SvelteKit Focus

\n

The knowledge graph is tuned for Svelte/SvelteKit development with TypeScript:

\n\n

The GrepApp haystack is filtered to language: \"typescript\" rather than JavaScript, reflecting the modern Svelte/SvelteKit ecosystem.

\n

Quick Start

\n
# Build the agent\ngit clone https://github.com/terraphim/terraphim-ai.git\ncd terraphim-ai\ncargo build --release\n# Enable GrepApp haystack support\ncargo build --release -p terraphim_middleware --features grepapp\ncargo install --path crates/terraphim_agent\n\n# Set up the front-end developer role\nterraphim-agent setup --template frontend-engineer --path ~/projects\n\n# Search across local files and GitHub\nterraphim-agent search "flexbox responsive layout"\n
\n

Architecture in Brief

\n
Query: "flexbox responsive layout"\n    |\n    v\n[Auto-route] -> Front-End Developer role\n    |\n    v\n[Aho-Corasick] -> CSS Layout + Responsive Design concepts\n    |\n    v\n[Ripgrep]       [GrepApp (TypeScript)]\n    |                |\n    v                v\n[TerraphimGraph hybrid scoring:\n  Pass 1: KG graph ranking (node + edge co-occurrence)\n  Pass 2: TF-IDF rescoring (30% weight boost)]\n              |\n              v\n      Ranked results\n
\n

MCP Integration with AI Coding Agents

\n

The terraphim_mcp_server binary exposes all knowledge graph tools via the Model Context Protocol, so any MCP-compatible AI coding agent can use your front-end developer KG during coding sessions.

\n

opencode (~/.config/opencode/opencode.json):

\n
{\n  "mcp": {\n    "terraphim": {\n      "type": "local",\n      "command": ["~/.cargo/bin/terraphim_mcp_server"],\n      "environment": { "TERRAPHIM_DATA_PATH": "~/.terraphim" }\n    }\n  }\n}\n
\n

Claude Code (~/.claude.json):

\n
{\n  "mcpServers": {\n    "terraphim": {\n      "type": "stdio",\n      "command": "~/.cargo/bin/terraphim_mcp_server",\n      "env": { "RUST_LOG": "error" }\n    }\n  }\n}\n
\n

After configuration, the AI agent gains access to 18 MCP tools: search, autocomplete_terms, replace_matches, terraphim_find_files, terraphim_grep, and more. Queries auto-route to the Front-End Developer role when front-end terms are detected.

\n

For Cursor, Windsurf, or any HTTP-based MCP client, start the SSE server: terraphim_mcp_server --sse --bind 127.0.0.1:8000.

\n

Read the Full Walkthrough

\n

The complete step-by-step guide covers:

\n\n

Read it at: docs/walkthroughs/frontend-developer-agent.md

\n

What Comes Next

\n

This walkthrough demonstrates the deterministic, KG-first approach. Natural extensions include:

\n\n

The knowledge graph pattern is universal: define concepts, add synonyms, point at haystacks, and search. No training, no fine-tuning, no API keys for the deterministic path.

\n", "https://terraphim.ai/properties/date" : "2026-04-23", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","walkthrough","knowledge-graph","grepapp","Svelte","SvelteKit","TypeScript","agent"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/why-graph-embeddings-matter/", "https://atomicdata.dev/properties/name" : "Why Graph Embeddings Matter", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/why-graph-embeddings-matter/", "https://atomicdata.dev/properties/description" : "

Vector databases are probabilistic and slow. Graph embeddings are deterministic and sub-millisecond. If you are building context for an AI coding agent — or any system where you need to know why a result came back — the difference is not academic. It changes what your application is allowed to promise.

\n

The Pitch in One Paragraph

\n

Terraphim represents concepts as nodes in a knowledge graph and ranks them by how many synonyms and edges connect them. There is no embedding model, no GPU, no per-query distance computation in a 1024-dimensional space. There is an Aho-Corasick automaton built once, queried in O(n+m+z) time over the input length plus the number of matches. The mechanism is described in detail on the Graph Embeddings reference page; this post is about why it matters.

\n

The Numbers

\n

Three numbers carry the argument. Each is reproducible on a laptop.

\n\n

For comparison, a typical vector-DB nearest-neighbour query lands in the 5–50 ms range after you have paid the embedding API call (50–500 ms) and the network round-trip. We are not in the same regime.

\n

Three Consequences

\n

The numbers are interesting on their own. The reason they matter is what they let you build.

\n

1. Full Explainability

\n

Every match in Terraphim traces back to a specific edge in the knowledge graph and a specific synonym in a specific role. There is no \"the model said so.\" When a search returns a document, you can show the user exactly which terms matched, which role's graph supplied the synonym, and which edges connected them. That is not a debugging nicety — it is a regulatory requirement in any domain where you have to defend a decision after the fact. Healthcare, legal, finance, government. Vector search by construction cannot do this.

\n

2. No Training, No Retraining, No Fine-Tuning

\n

Adding a new concept is a text edit. You write the synonym down, you point Terraphim at the file, the graph rebuilds in 20 ms. There is no training run, no GPU bill, no \"we need to schedule a retrain on the new corpus.\" This collapses the loop between noticing a gap and fixing the gap from days or weeks to seconds. For an AI coding agent that needs to learn a project's vocabulary as you onboard, this is the difference between a working tool and a stalled rollout.

\n

3. Language-Agnostic Without Language Detection

\n

Because matching is done on normalised terms — synonyms you supply explicitly — the same node in the graph can carry English, French, Russian, and Mandarin labels at no extra cost. There is no language-detection step, no per-language embedding model, no separate index. The query \"consensus\" and the query \"консенсус\" both reach the same node if you have told the graph they are synonyms. Stop-word lists become irrelevant: if a word is not in the graph, it does not match, full stop.

\n

What This Lets You Do

\n

The pieces above are infrastructure. The story arc continues:

\n\n

How to Apply

\n

If you want to wire this into your own project, the Command Rewriting How-to walks through the moving parts: where to put your synonyms, how the role graph is built, how hooks call the matcher.

\n

The mechanism — automata, ranking formula, ASCII walk-through — is on the Graph Embeddings reference page. Read that next if you want the data structures.

\n

Why Bother Saying This Out Loud

\n

The current default in the AI tooling ecosystem is to reach for a vector database the moment anyone mentions \"semantic search.\" It is the path of least resistance because the tools are well-marketed and the API surface is familiar. But for a large class of problems — explainability-first systems, on-device agents, anywhere you need a hard latency budget or a hard explainability guarantee — graph embeddings are the better-engineered answer. Not the only answer; the better one for that class.

\n

The promotion campaign over the next few weeks goes deeper: a sub-millisecond context article walks through the FST/Aho-Corasick implementation, and the Context Engineering with Knowledge Graphs book (launching in May) puts it in the wider context of moving from RAG to context graphs.

\n

Until then: read the reference, try the how-to, and let us know in Discourse what you build with it.

\n", "https://terraphim.ai/properties/date" : "2026-04-22", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","graph-embeddings","knowledge-graph","aho-corasick","context-engineering"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/terraphim-search-in-claude-code-and-opencode/", "https://atomicdata.dev/properties/name" : "Plug Terraphim Search into Claude Code and opencode (CLI First, MCP When You Need It)", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/terraphim-search-in-claude-code-and-opencode/", "https://atomicdata.dev/properties/description" : "

Your AI coding agent already has a knowledge graph. It is just not yours yet. The model knows GitHub, Stack Overflow, and the public training corpus -- it has no idea that in your project npm should be bun, that RFP is shorthand for acquisition need, or that the email about the Stripe receipt for the Obsidian licence lives in your Fastmail mailbox. This post shows the smallest path to fixing that for both Claude Code and opencode, using Terraphim and the three roles we have published over the last week (Terraphim Engineer, Personal Assistant, System Operator).

\n

Two paths. CLI first.

\n

What \"integrate\" means here

\n

The host -- Claude Code or opencode -- needs a way to ask your role-aware Terraphim setup a question and get back ranked, source-attributed results. The model decides when to ask. The role decides which haystacks to search. Terraphim's terraphim-graph ranker decides which results come back first.

\n

Concrete example. You are working in opencode and you type:

\n
/tsearch "System Operator" RFP\n
\n

The slash command runs against the System Operator role. The role's knowledge graph normalises RFP to its INCOSE-canonical form acquisition need. The Aho-Corasick matcher walks the role's haystack (1,347 Logseq pages from the terraphim/system-operator repository). The top hit comes back ranked 13 -- Acquisition need.md -- with the synonyms:: line that mapped your query to it visible in the snippet. The model now has the right page in its context window and can answer your follow-up without a hallucinated INCOSE handbook reference.

\n

This works in both hosts because both speak the same two integration languages: shell-out slash commands and MCP servers. We are going to use both.

\n

Path A -- CLI via slash command

\n\n

terraphim-agent already exists, takes --role and --limit, and writes ranked results to stdout. There is nothing to build. Both Claude Code and opencode let slash commands shell out via Bash. So a two-line command file is the entire integration.

\n

One file, two hosts

\n

Drop this at ~/.claude/commands/tsearch.md (and an identical copy at ~/.config/opencode/command/tsearch.md -- both hosts read the same frontmatter shape):

\n
---\ndescription: Terraphim search across configured roles. Usage: /tsearch [role] <query>\nallowed-tools: Bash(terraphim-agent search:*), Bash(terraphim-agent-pa search:*)\n---\nRun `terraphim-agent search --role "<role>" --limit 5 "<query>"` (or\n`terraphim-agent-pa search ...` if the role is "Personal Assistant" and\nthe query needs the JMAP haystack). Return the top results as a numbered\nlist with title, source path/URL, and a 120-char snippet.\n
\n

That is it. The allowed-tools line auto-approves the two CLI invocations so the model does not have to ask permission per call. Restart the host (or reload commands) and /tsearch is live.

\n

Why fast enough

\n

terraphim-agent reads its persisted role state at start (low milliseconds), runs the query against the role's haystacks, and returns. For a typical knowledge-graph query against the Terraphim Engineer role on a laptop, the round trip from slash command to formatted output is well under a second. The agent already has the typed CLI -- --role, --limit, --format json -- so there is nothing the MCP layer adds for the search-only flow.

\n

Three example queries

\n
/tsearch "Terraphim Engineer" rolegraph\n/tsearch "System Operator" RFP\n/tsearch "Personal Assistant" invoice    # uses terraphim-agent-pa wrapper for JMAP\n
\n

The Personal Assistant case is the most interesting because it crosses surfaces -- Obsidian notes interleave with jmap:///email/<id> URLs from your Fastmail mailbox, ranked by the same terraphim-graph scoring. The wrapper script injects JMAP_ACCESS_TOKEN from 1Password at call time so the secret never lands on disk; the bare terraphim-agent continues to work for the other five roles without paying the unlock cost.

\n

Path B -- MCP server (when you want typed tools)

\n

The CLI path is enough for search. If you want the model to call search as a first-class tool with structured JSON parameters -- alongside autocomplete_terms, autocomplete_with_snippets, four flavours of fuzzy autocomplete, build_autocomplete_index, and update_config_tool -- that is what terraphim_mcp_server exposes. It reads the same ~/.config/terraphim/embedded_config.json, so the role list is identical.

\n

Build and install

\n
cd ~/projects/terraphim/terraphim-ai\ncargo build --release -p terraphim_mcp_server --features jmap\ncp target/release/terraphim_mcp_server ~/.cargo/bin/terraphim_mcp_server\n
\n

For the Personal Assistant role, mirror the existing terraphim-agent-pa wrapper at ~/bin/terraphim_mcp_server-pa so the JMAP token flows through op run instead of being baked into config.

\n

Register

\n

opencode -- add to ~/.config/opencode/opencode.json under mcp:

\n
"terraphim":    { "type": "local", "command": ["/Users/alex/.cargo/bin/terraphim_mcp_server"] },\n"terraphim-pa": { "type": "local", "command": ["/Users/alex/bin/terraphim_mcp_server-pa"] }\n
\n

Claude Code -- one shell command per server:

\n
claude mcp add terraphim    /Users/alex/.cargo/bin/terraphim_mcp_server\nclaude mcp add terraphim-pa /Users/alex/bin/terraphim_mcp_server-pa\nclaude mcp list      # both should show as Connected\n
\n

The model now sees mcp__terraphim__search and mcp__terraphim_pa__search (plus the autocomplete tools) in its tool list.

\n

SessionStart primer (both paths)

\n

Slash commands and MCP tools are useless if the model does not know the roles exist. Extend the SessionStart hook in ~/.claude/settings.json to print a one-screen role index when each session starts:

\n
printf '\\n--- Terraphim search via /tsearch [role] <query> ---\\n'\nprintf '  Terraphim Engineer  (Rust/agent KG)\\n'\nprintf '  Personal Assistant  (Obsidian + Fastmail JMAP, use terraphim-agent-pa for email)\\n'\nprintf '  System Operator     (INCOSE/MBSE Logseq KG)\\n'\nprintf '  Context Engineering Author, Rust Engineer, Default\\n'\n
\n

Equivalent hook in opencode. Cost: one screen of context per session. Benefit: the model picks the right role on the first try instead of guessing.

\n

When to pick which path

\n\n\n\n\n\n\n
CLI (Path A)MCP (Path B)
New binariesNoneterraphim_mcp_server plus wrapper
Cold start~50-200 ms per call~10-50 ms per call (long-lived process)
Tools exposedsearch onlysearch + 4 autocomplete + build_autocomplete_index + update_config_tool
Works in any hostYes -- anything that runs a slash commandOnly hosts that speak MCP
Token handlingterraphim-agent-pa wrapperterraphim_mcp_server-pa wrapper
\n

For the search-across-roles flow, CLI is enough. Add MCP when the model needs autocomplete-as-you-type, when you want it to manage role configuration without leaving the conversation, or when you are using a host where the typed-tool surface matters more than the cold-start cost.

\n

You do not have to choose. Wire both. The slash command above defaults to CLI and falls back to MCP if the binary is missing -- the two paths coexist cleanly because they read the same role config.

\n

Why this is the right shape

\n

Most \"AI assistant + knowledge base\" integrations end up tightly coupled to a specific host. Vendor X's plugin marketplace, Vendor Y's tool format. Terraphim takes the opposite stance: the role configuration lives in your filesystem, the haystacks live in your filesystem (or your mailbox), the ranker runs in a process you own, and the integration with the AI host is the thinnest possible shim -- a slash command or an MCP server, both of which are commodity surfaces.

\n

Yesterday the Personal Assistant role was a private setup on one laptop. Today it is callable from inside two different AI coding hosts via a one-file slash command. Tomorrow you can add Cursor or Aider with the same two-line wrapper because the integration surface is terraphim-agent search, not vendor-specific-tool-protocol-v3.

\n

The expensive part of context engineering is not the ranker. It is the vocabulary in the knowledge graph and the haystacks the role can reach. The integration layer should not be allowed to compete for that budget. CLI-first keeps it small.

\n

Try it

\n
# Build (or install the published crate when JMAP feature lands on crates.io)\ncd ~/projects/terraphim/terraphim-ai\ncargo install --path crates/terraphim_agent --features jmap\n\n# Configure roles -- copy the snippets from the how-tos linked below\n$EDITOR ~/.config/terraphim/embedded_config.json\n\n# Install the slash command\nmkdir -p ~/.claude/commands ~/.config/opencode/command\ncp ~/projects/terraphim/terraphim-ai/docs/src/howto/mcp-integration-claude-opencode.md \\\n   /tmp/tsearch.md  # adapt to your slash command file shape\n\n# Reload roles\nterraphim-agent config reload\n\n# Try\nterraphim-agent search --role "Terraphim Engineer" --limit 3 "rolegraph"\n
\n

Step-by-step in the docs: Plug Terraphim Search into Claude Code and opencode.

\n

For the underlying engine, start with Why Graph Embeddings Matter. For the two roles this integration most cleanly exposes, see Personal Assistant and System Operator.

\n", "https://terraphim.ai/properties/date" : "2026-04-18", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","claude-code","opencode","mcp","knowledge-graph","developer-tools","integration"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/disciplined-engineering-ai-systems/", "https://atomicdata.dev/properties/name" : "Disciplined Engineering: How We Build AI Systems That Actually Work", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/disciplined-engineering-ai-systems/", "https://atomicdata.dev/properties/description" : "

AI coding agents are making us worse engineers, unless we add discipline back. Here is what we do instead of vibe coding, and how you can do it too in 30 seconds.

\n

Update, May 2026: this repository is now private

\n

Up until last week, terraphim-skills was open source. You could install the whole set with one command via skills.sh. Then I ran a comparison: our skills against Andrej Karpathy's, against derivatives of Karpathy's, and against a no-skills control. For the first time in my life I clicked \"Make private\" on a public repository.

\n

Even on the first batch of tests, our approach beat both Karpathy's and the control:

\n\n

We control the flow and we control the cost, because we are not an AI lab and we are not a VC-funded startup burning tokens to chase a leaderboard. We are a consultancy getting things done with AI and building AI.

\n

The results speak for themselves. A few weeks ago I read a story about an autoresearch agent that achieved a speedup on the Liquid (Rails) parser. I had a slow markdown parser inside this very project. I ran our disciplined loop on it. Twice. Result: a 400x to 900x speedup in parsing.

\n

Here is how.

\n

The Vibe Coding Problem

\n

Every AI-generated pull request we review has the same pattern:

\n\n

The agent shipped code. It even passed the tests. But the tests were written by the same agent that wrote the code, optimising for the metric rather than understanding the problem.

\n

The missing piece is not better models. It is engineering discipline. AI agents need the same rigour humans use: understand the problem before coding, verify against the design, validate against requirements. We encoded this as executable skills that any AI coding agent can follow.

\n
\n

The research evidence behind this framework, including language-specific scaling laws and the 30% adoption gap between code intelligence research and production harnesses, is the subject of our next article.

\n
\n

The V-Model: Adding Discipline Back

\n

We built a V-model for AI agents. The left side asks \"what should we build?\" The right side asks \"did we build it correctly?\"

\n

\"The

\n

Phase 1: Research

\n

Before writing any code, the agent must understand the problem space:

\n\n

Phase 2: Design

\n

Create a specification before implementation:

\n\n

Phase 3: Implementation

\n

Write code with tests from the start:

\n\n

Phase 4: Verification

\n

Verify against the design, not just tests:

\n\n

Phase 5: Validation

\n

Validate against the original requirements:

\n\n

terraphim-skills: 32+ Executable Disciplines

\n

We packaged the V-model as executable skills for any AI coding agent. As of May 2026 the repository is private (see the update at the top of this post) and the skills.sh installer has been retired. The framework is now deployed as part of our consulting engagements at zestic.ai.

\n

The skills enforce:

\n\n

Each skill is a self-contained prompt that guides the agent through the phase's inputs, outputs, and quality gates.

\n

Quality Gates: The Judge System

\n

Our judge system (Kimi K2.5) catches what humans miss:

\n\n

Automated quality gates, zero manual overhead. Every PR reviewed before it merges.

\n

Guard Rails in Practice

\n

AI agents do not type commands into a terminal. They invoke tools programmatically, and they do not always get it right. \"Cleaning up build artefacts\" becomes rm -rf ./src (one-character typo). \"Resetting to last commit\" becomes git reset --hard (uncommitted work gone). You need a safety net that operates between the agent and your shell.

\n

We use two layers of guard rails:

\n

Layer 1: git-safety-guard (a terraphim-skill that runs as a PreToolUse hook):

\n\n

**Layer 2: Destructive Command Guard (DCG) by Jeff Emanuel, integrated via tool hooks:

\n\n

The architecture is simple: the agent calls a bash tool, the hook pipes the command to DCG as JSON, DCG pattern-matches against known destructive commands, and blocks execution before damage occurs. The agent receives an error explaining why, and can adjust its approach.

\n

Real Example: AI Dark Factory

\n

We run 12+ AI agents overnight on a single machine, coordinated by a Rust orchestrator. Each agent follows the V-model:

\n\n

Every agent's output passes through the judge system before merge. The morning routine is reviewing verdicts, not debugging overnight chaos. When an agent produces a NO-GO verdict, the PR is flagged with the specific issues: missing test coverage, undocumented API changes, or security concerns.

\n

This is disciplined engineering at scale: not process overhead, but automated quality gates that catch problems before they compound.

\n

Conclusion

\n

The gap between what AI agents can do and what they should do is real. It is not a technology gap: it is a discipline gap. The V-model and the 32+ executable skills we built are now part of our consulting work rather than an open repository.

\n

Add discipline back. If you want it inside your team, get in touch at zestic.ai.

\n
\n

Deeper dive: The V-model and quality gates we use are detailed in Chapters 3-4 of \"Context Engineering with Knowledge Graphs\". Coming soon.

\n

Related posts:

\n\n", "https://terraphim.ai/properties/date" : "2026-04-17", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","ai","engineering","v-model","developer-tools","coding-agents","discipline"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/guarding-opencode-with-dcg/", "https://atomicdata.dev/properties/name" : "Guarding OpenCode with Destructive Command Guard", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/guarding-opencode-with-dcg/", "https://atomicdata.dev/properties/description" : "

AI coding assistants are fast, productive, and occasionally catastrophic. One misplaced rm -rf, one accidental git reset --hard, and hours of uncommitted work vanish.

\n

Jeffrey Emanuel (@Dicklesworthstone) built Destructive Command Guard (dcg): a Rust binary with SIMD-accelerated pattern matching, 49+ security packs, and a fail-open design. It is one of the best tools to come out of the AI agent safety space, and it solved a problem we had been fighting with regex hacks.

\n

This post shows how we integrated dcg with OpenCode using its plugin hook system, so destructive commands are intercepted before they run.

\n

The Problem

\n

AI agents do not type commands into a terminal. They invoke tools programmatically, and they do not always get it right:

\n\n

You need a safety net that operates between the agent and your shell.

\n

The Architecture

\n

OpenCode v1.4+ exposes a plugin hook system. Hooks are top-level keys on the Hooks interface:

\n
interface Hooks {\n  "tool.execute.before"?: (input, output) => Promise<void>;\n  "tool.execute.after"?:  (input, output) => Promise<void>;\n}\n
\n

The \"tool.execute.before\" hook fires before every tool call. It receives the tool name and arguments, and can throw an error to abort execution. This is exactly where a command guard belongs.

\n

DCG is Jeffrey's Rust binary that reads a JSON payload from stdin and exits 0 (allow) or 2 (block). Our contribution was the plugin that wires dcg into OpenCode's hook system:

\n
OpenCode agent\n    |\n    | calls bash tool: "rm -rf ./build"\n    v\n"tool.execute.before" hook\n    |\n    | spawns: echo '{"tool":"bash","args":{"command":"rm -rf ./build"}}' | dcg\n    v\ndcg (Rust, SIMD-accelerated pattern matching)\n    |\n    | exit code 2 + reason on stderr\n    v\nhook throws Error --> command never executes\n
\n

The Plugin

\n

The complete plugin is roughly 60 lines:

\n
import { spawn } from 'child_process';\n\nconst callDcgHook = (toolCall) => {\n  return new Promise((resolve, reject) => {\n    const dcg = spawn('dcg', [], {\n      env: { ...process.env, DCG_FORMAT: 'json' }\n    });\n\n    let stdout = '';\n    let stderr = '';\n\n    dcg.stdout.on('data', (data) => { stdout += data.toString(); });\n    dcg.stderr.on('data', (data) => { stderr += data.toString(); });\n\n    dcg.on('close', (code) => {\n      if (code === 0) {\n        try { resolve(JSON.parse(stdout)); }\n        catch { resolve({ allowed: true }); }\n      } else {\n        reject(new Error(stderr || 'dcg blocked command'));\n      }\n    });\n\n    dcg.stdin.write(JSON.stringify(toolCall));\n    dcg.stdin.end();\n  });\n};\n\nexport const DcgGuard = async ({ client }) => {\n  return {\n    "tool.execute.before": async (input, output) => {\n      if (input.tool !== 'bash') return;\n\n      const toolCall = {\n        tool: 'bash',\n        args: { command: output.args.command }\n      };\n\n      try {\n        await callDcgHook(toolCall);\n      } catch (error) {\n        throw new Error(\n          `dcg blocked destructive command: ${output.args.command}\\n\\n` +\n          `${error.message}\\n\\n` +\n          `This command was blocked to protect your system.`\n        );\n      }\n    }\n  };\n};\n
\n

What Got Fixed: A Subtle API Mismatch

\n

The original plugin used a nested structure:

\n
return {\n  tool: {\n    execute: {\n      before: async (input, output) => { ... }\n    }\n  }\n};\n
\n

This looks intuitive but is wrong. In OpenCode's plugin API, tool is reserved for registering new tools (each needing a description, args, and execute function). The hook \"tool.execute.before\" is a top-level dotted key on the Hooks object, not a nested path.

\n

The fix:

\n
return {\n  "tool.execute.before": async (input, output) => { ... }\n};\n
\n

This distinction matters. OpenCode iterates over tool entries expecting ToolDefinition objects. When it found { before: ... } instead, it called .execute(args, ctx) on it, which was undefined. Hence the error: def.execute is not a function.

\n

What DCG Blocks

\n\n\n\n\n\n\n\n\n
CategoryExamples
Git history destructiongit reset --hard, git push --force, git branch -D
Uncommitted work lossgit checkout — ., git restore file, git clean -f
Stash destructiongit stash drop, git stash clear
Filesystem damagerm -rf outside /tmp
Database operationsDROP TABLE, FLUSHALL (via packs)
Container destructiondocker system prune, docker-compose down --volumes
Infrastructureterraform destroy, kubectl delete namespace
\n

Safe operations pass through silently: git status, git add, git commit, git push (without --force), git stash, git checkout -b, and all non-destructive commands.

\n

Key Design Decisions

\n

Default-allow. Unrecognised commands pass through. DCG blocks only known dangerous patterns. This prevents false positives from blocking legitimate work.

\n

Whitelist-first. Safe patterns (like git checkout -b) are checked before destructive patterns. Explicitly safe commands are never accidentally blocked.

\n

Sub-millisecond latency. Jeffrey's implementation uses SIMD-accelerated substring search via Rust's memchr crate. Commands without \"git\" or \"rm\" bypass regex matching entirely. The guard adds no perceptible delay.

\n

Fail-open. If dcg crashes or produces unexpected output, the plugin catches the error and defaults to allowing the command. A broken guard should never break your workflow. A safety system that slows down the developer will be disabled by the third day. A safety system that is invisible will run forever.

\n

Extending with Packs

\n

DCG ships with a modular pack system. Enable additional protection categories in ~/.config/dcg/config.toml:

\n
[packs]\nenabled = [\n    "database.postgresql",\n    "containers.docker",\n    "kubernetes",\n    "cloud.aws",\n]\n
\n

Or via environment variable:

\n
export DCG_PACKS="containers.docker,kubernetes"\n
\n

Installation

\n
# 1. Install dcg\ncurl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/master/install.sh" | bash\n\n# 2. Install the plugin\nmkdir -p ~/.config/opencode/plugin\ncurl -fsSL https://raw.githubusercontent.com/jms830/opencode-dcg-plugin/main/plugin/dcg-guard.js \\\n  -o ~/.config/opencode/plugin/dcg-guard.js\n\n# 3. Restart OpenCode\n
\n

Conclusion

\n

The OpenCode plugin API's \"tool.execute.before\" hook is a clean interception point for safety guards. Combined with Jeffrey Emanuel's dcg and its fast pattern matching, you get protection against destructive commands with zero workflow friction. The plugin is small, the guard is fast, and the safety net catches the mistakes that matter.

\n

Instructions are suggestions. Guards are guarantees.

\n
\n

DCG is built by Jeffrey Emanuel — see his destructive_command_guard repository and the broader agentic coding flywheel ecosystem for more agent safety tooling.

\n

This post is part of the Disciplined Engineering series. See also: Teaching AI Agents with Knowledge Graph Hooks and Teaching AI Agents to Learn from Their Mistakes.

\n

Source: DCG plugin gist and opencode-dcg-plugin repository

\n", "https://terraphim.ai/properties/date" : "2026-04-17", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","ai","opencode","developer-tools","rust","safety","coding-agents"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/personal-assistant-role-jmap-obsidian/", "https://atomicdata.dev/properties/name" : "Personal Assistant Role: One Search Across Email and Notes", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/personal-assistant-role-jmap-obsidian/", "https://atomicdata.dev/properties/description" : "

Most \"personal AI\" tools split your context across silos: one search box for email, another for notes, a third for your chat history. Terraphim treats every source as a haystack on the same role, so a single query crosses all of them. This post shows how to wire up the two most common personal sources -- email via JMAP and notes in an Obsidian vault -- under a new Personal Assistant role.

\n

Why a unified role matters

\n

The mental tax of personal search is not the typing. It is the deciding. \"Did I read that in an email or write it in a note?\" Each silo you skip is a context switch with no useful payload. Once Terraphim is the front door for both surfaces, the question collapses to \"where is the thing about X\" and the role's terraphim-graph ranking serves whichever source actually has the strongest signal.

\n

The Personal Assistant role uses two haystacks under one role:

\n\n

Ranking is the same terraphim-graph scoring as every other Terraphim role: an Aho-Corasick automaton built from the Obsidian vault contributes synonyms specific to your project vocabulary, then both haystacks share the same rank ladder. Notes and email interleave by relevance, not by source.

\n

What you get

\n\n

A 4 GB process on your laptop holds the whole working set; queries return in single-digit milliseconds for the local side and a few hundred for the remote JMAP round trip.

\n

Wiring sketch

\n

The role config is roughly thirty lines of JSON: two haystacks, one knowledge-graph pointer, no LLM. The Fastmail token is not in the config -- it is injected at runtime via op run from 1Password into the JMAP_ACCESS_TOKEN environment variable, so the secret never lands on disk:

\n
exec op run --account my.1password.com \\\n  --env-file=<(echo 'JMAP_ACCESS_TOKEN=op://VAULT/ITEM/credential') \\\n  -- /Users/alex/.cargo/bin/terraphim-agent "$@"\n
\n

Wrap that in ~/bin/terraphim-agent-pa, chmod +x, and the JMAP haystack lights up only for queries that ask for it. The other roles keep using the bare terraphim-agent and never pay for the 1Password unlock.

\n

Why graph embeddings make this practical

\n

The reason a unified role works at all -- not just for two haystacks but for any reasonable number -- is that Terraphim's graph-embeddings layer is sub-millisecond and deterministic. There is no per-query embedding API call to amortise across sources, no vector database to keep in sync, no opaque ranker that has to be retrained when you add a new haystack. The matching is byte-level Aho-Corasick traversal of an automaton built once at role-load time. We wrote up the engine in detail at Why Graph Embeddings Matter; this Personal Assistant role is one application of that engine.

\n

Try it

\n

The end-to-end how-to is in the docs: install the prerequisites, add the JSON snippet, write the wrapper, run three verification queries.

\n

Read the how-to: Personal Assistant Role on docs.terraphim.ai

\n

One caveat worth surfacing up front: the published terraphim-agent on crates.io does not yet ship with the JMAP haystack (the haystack_jmap dependency is not published either). For email search you need to build from local source with cargo build --release -p terraphim_agent --features jmap. The how-to walks through the two Cargo.toml edits required.

\n

What is next

\n

Personal Assistant is the smallest useful instance of \"Terraphim as the front door for everything I read.\" Calendar (CalDAV), contacts (CardDAV), browser bookmarks, RSS, and AI session logs are all natural follow-ups -- each is a single haystack entry on the same role. The pattern composes; the cost stays linear in haystacks, not quadratic in cross-source queries.

\n

If you want the underlying engine, start with Why Graph Embeddings Matter. If you want to wire knowledge-graph hooks into your AI coding agent on the same machine, Teaching AI Coding Agents with Knowledge Graph Hooks covers that side of the same engine.

\n", "https://terraphim.ai/properties/date" : "2026-04-17", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","personal-assistant","jmap","obsidian","knowledge-graph","fastmail"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/system-operator-logseq-knowledge-graph/", "https://atomicdata.dev/properties/name" : "System Operator Demo: A Logseq Knowledge Graph Drives Enterprise MBSE Search", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/system-operator-logseq-knowledge-graph/", "https://atomicdata.dev/properties/description" : "

Terraphim's System Operator role is the demo we point people at when they want to see a real Logseq knowledge graph drive search. 1,347 Logseq pages, 52 of them carrying explicit synonyms:: lines, covering Model-Based Systems Engineering vocabulary -- requirements, architecture, verification, validation, life cycle concepts. This post walks the demo end-to-end and shows the piece people miss: the KG is doing real work, not just re-ranking text matches.

\n

What the demo is

\n

The terraphim/system-operator repository on GitHub is a Logseq vault -- flat folder of markdown files under pages/, one page per concept, with Logseq's bullet-tree syntax for structure and Terraphim-format synonyms:: lines for the knowledge-graph layer. Two things make it a useful demo rather than a toy:

\n
    \n
  1. Real MBSE vocabulary. The synonyms are not invented; they track the INCOSE Systems Engineering Handbook v.4, the V-Model, and SEMP conventions. When you type RFP, the automaton normalises it to acquisition need because that is what the handbook calls it.
  2. \n
  3. Real scale. 1,347 markdown files is enough to expose cold-start behaviour (~5-10 seconds to index on a laptop) without being so large it obscures the ranking signal.
  4. \n
\n

Run it

\n

There is an automated setup script in the repo. As of today it clones to a durable path under ~/.config/terraphim/system_operator instead of /tmp, so the vault survives a reboot:

\n
./scripts/setup_system_operator.sh\n
\n

Then either drive the role via the server --

\n
cargo run --bin terraphim_server -- \\\n  --config terraphim_server/default/system_operator_config.json\ncurl "http://127.0.0.1:8000/documents/search?q=RFP&role=System%20Operator&limit=5"\n
\n

-- or via the terraphim-agent CLI after adding the role entry to ~/.config/terraphim/embedded_config.json:

\n
terraphim-agent config reload\nterraphim-agent search --role "System Operator" --limit 5 "RFP"\n
\n

The full config snippet and the embedded_config.json entry are in the README_SYSTEM_OPERATOR.md.

\n

The piece people miss

\n

Search-over-notes tools usually describe ranking in terms of \"it uses a knowledge graph\". That sentence hides a lot. Is the graph actually consulted at query time? Is it just a post-hoc re-ranker on top of BM25? Does it expand synonyms? On what vocabulary?

\n

Terraphim exposes the answer directly. validate --connectivity prints which words in your query the automaton matched and what canonical terms they normalised to:

\n
$ terraphim-agent validate --role "System Operator" --connectivity \\\n    "RFP business analysis life cycle model business requirements documentation tree"\n\nConnectivity Check for role 'System Operator':\n  Connected: false\n  Matched terms: ["acquisition need", "business or mission analysis",\n                  "business requirements", "documentation tree",\n                  "life cycle concepts"]\n
\n

Five query fragments, five canonical matches. RFP collapsed to acquisition need (its synonym, from Acquisition need.md in the vault). business analysis collapsed to business or mission analysis (INCOSE terminology). life cycle model collapsed to life cycle concepts. None of this is text matching -- the word RFP does not appear in the canonical page body; it lives in the synonyms:: line.

\n

Once a query is normalised, the ranker walks the graph. A document that mentions acquisition need directly outranks one that mentions it through three synonym hops, and both outrank a document that mentions none of the canonical terms at all. Ranks come back with concrete integer scores -- [13] on a top result, not an opaque 0.87 cosine.

\n

How it compares to the Personal Assistant role

\n

We wrote up the Personal Assistant role yesterday: a private per-user role that indexes a Fastmail mailbox plus an Obsidian vault. Same engine, same ranker, different haystacks. The knowledge graph there is a small kg/ folder inside the user's vault with 14 synonym files covering personal vocabulary (bun with npm/yarn/pnpm synonyms, odilo, invoice, meeting).

\n

The two roles expose the same pattern at two scales:

\n\n\n\n\n\n\n
System OperatorPersonal Assistant
KG size52 synonym files, 1,300-concept vocabulary14 synonym files, ~30-concept personal vocabulary
Haystacks1 (Logseq repo)2 (Obsidian vault + Fastmail JMAP)
SourcePublic GitHub repoPrivate user files and mailbox
AudienceDemos, onboarding, public showcaseOne user
LifetimeFrozen per releaseEdited daily, rebuilt in 20 ms per edit
\n

Both use terraphim-graph ranking. Both build an Aho-Corasick automaton once at role-load time. Both run in a 4 GB process on a laptop with no cloud round-trip. The only interesting difference is the vocabulary, which is exactly the separation of concerns a knowledge-graph-first design is supposed to deliver.

\n

Why this matters for teams evaluating MBSE tooling

\n

If you are evaluating Terraphim for a systems engineering group, the System Operator role is the honest starting point. It runs on a laptop against a public vault; you can check that every synonym mapping traces back to a concrete page; you can diff the pages/ folder against the INCOSE handbook and argue about terminology. When your team's own vocabulary diverges (every organisation's does), you clone the repo, edit synonyms:: lines, and the graph rebuilds in 20 milliseconds without a retraining step.

\n

The expensive part of enterprise search is not the ranker. It is the vocabulary. A deterministic graph makes the vocabulary an asset you curate, not a black box you tune.

\n

Try it

\n
git clone https://github.com/terraphim/terraphim-ai\ncd terraphim-ai\n./scripts/setup_system_operator.sh\ncargo run --bin terraphim_server -- \\\n  --config terraphim_server/default/system_operator_config.json\n
\n

Or cut to the CLI if you already have terraphim-agent installed -- the embedded_config.json snippet is in the README.

\n

For the underlying engine, start with Why Graph Embeddings Matter. For the personal-productivity analogue, see the Personal Assistant role post.

\n", "https://terraphim.ai/properties/date" : "2026-04-17", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","system-operator","logseq","knowledge-graph","mbse","systems-engineering"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/teaching-ai-agents-to-learn-from-mistakes/", "https://atomicdata.dev/properties/name" : "Teaching AI Agents to Learn from Their Mistakes", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/teaching-ai-agents-to-learn-from-mistakes/", "https://atomicdata.dev/properties/description" : "

AI coding agents make the same mistakes over and over. We built a learning system that captures failures, stores corrections, and feeds them back into future sessions — turning every error into institutional memory.

\n
\n

Builds on Why Graph Embeddings Matter — the deterministic engine that makes \"remember this correction forever\" cheap. Apply the pattern in your own project via the Command Rewriting How-to.

\n
\n

The Problem: Groundhog Day for AI Agents

\n

Every AI coding agent session starts from zero. Claude Code runs npm install, gets corrected, switches to bun — and tomorrow does it again. A force-push to main gets blocked, the agent learns why, then forgets by next session.

\n

In our previous post on Knowledge Graph Hooks, we showed how Aho-Corasick automata can intercept and transform agent commands in real time. But interception is reactive. What if the agent could remember its past failures and avoid repeating them?

\n

The Solution: Terraphim Learning Capture

\n

Terraphim's learning system operates as a closed loop with three stages:

\n
Failed Command --> PostToolUse Hook --> Learning Store --> Query at Session Start\n
\n

Stage 1: Automatic Capture

\n

A PostToolUse hook fires after every tool execution in Claude Code. When a command exits with a non-zero status, the hook calls terraphim-agent learn hook, which persists the failure as a structured markdown file:

\n
---\nid: 6b99a8924fad4f2aaeadf5450e76730c\ncommand: npm install react\nexit_code: 127\nsource: Global\ncaptured_at: 2026-04-04T18:43:07+00:00\n---\n
\n

The hook is fail-open — if terraphim-agent is unavailable, it exits silently. Development is never blocked.

\n

Stage 2: Human Corrections

\n

Raw failures are useful, but corrections make them actionable. Any developer (or the agent itself) can attach a correction:

\n
$ terraphim-agent learn correct <id> --correction "Use 'bun add react' instead"\n
\n

The learning file is updated in place:

\n
---\nid: 6b99a8924fad4f2aaeadf5450e76730c\ncommand: npm install react\nexit_code: 127\ncorrection: "Use 'bun add react' instead"\n---\n
\n

Stage 3: Query Before Repeating

\n

At the start of a session, or when encountering a familiar error, the agent queries the learning store:

\n
$ terraphim-agent learn query "npm"\n\nLearnings matching 'npm'.\n  [G] [cmd] npm install lodash (exit: 1)\n     Correction: Use 'bun add lodash' instead. Terraphim hooks enforce bun over npm.\n  [G] [cmd] npm install react (exit: 127)\n     Correction: Use bun instead of npm/yarn/pnpm. 'bun add react' or 'bun install'.\n
\n

The agent sees past mistakes with their corrections before taking action. No more Groundhog Day.

\n

How the Hook Works

\n

The PostToolUse hook is a shell script that receives JSON from Claude Code on stdin after every Bash tool call:

\n
#!/bin/bash\nset -euo pipefail\n\n# Find terraphim-agent binary\nAGENT="$HOME/.cargo/bin/terraphim-agent"\n[ -x "$AGENT" ] || exit 0  # Fail-open\n\n# Read tool result from stdin\nINPUT=$(cat)\n\n# Capture failures as learnings\n$AGENT learn hook --format claude <<< "$INPUT" 2>/dev/null || true\n
\n

The learn hook subcommand parses the Claude Code tool result format, extracts the command and exit code, and writes a learning file only when the exit code is non-zero.

\n

What Gets Captured

\n\n\n\n\n\n\n
SignalCaptured?Example
Non-zero exit codeYesnpm install (exit 127)
Force push attemptsYesgit push --force origin main (exit 1)
Compilation errorsYescargo build (exit 101)
Successful commandsNoOnly failures are stored
Duplicate failuresDeduplicatedSame command + exit code within a session
\n

Real Evidence: What Our Agents Have Learnt

\n

Here is actual data from our production learning store, accumulated across weeks of development sessions:

\n

Package manager enforcement — 3 npm entries, all corrected to bun:

\n
[G] [cmd] npm install lodash (exit: 1)\n   Correction: Use 'bun add lodash' instead.\n[G] [cmd] npm install react (exit: 127)\n   Correction: Use bun instead of npm/yarn/pnpm.\n
\n

Git safety — 29 push failures captured, including one critical correction:

\n
[G] [cmd] git push --force origin main (exit: 1)\n   Correction: NEVER force push to main. Use feature branches and PRs.\n
\n

These corrections are not just documentation. They are queryable institutional memory that agents consult before repeating the same mistakes.

\n

Integration with Knowledge Graph Hooks

\n

The learning system complements the Knowledge Graph Hooks we described previously. Together they form two layers of defence:

\n\n\n\n
LayerMechanismTiming
PreventionKG hooks intercept npm install and replace with bun installBefore execution
LearningPostToolUse hook captures failures that slip throughAfter execution
\n

If a new pattern appears that the knowledge graph does not cover, the learning system captures it. A developer adds a correction. Optionally, the pattern gets promoted to a knowledge graph entry for permanent interception.

\n
New failure captured --> Correction added --> Pattern promoted to KG --> Hook intercepts automatically\n
\n

The Learning Store

\n

Learning files are stored as markdown in ~/Library/Application Support/terraphim/learnings/ (macOS) or ~/.local/share/terraphim/learnings/ (Linux). Each file is a standalone document:

\n
---\nid: 1c8a4548-1434-a346-cd641131202a\ncommand: git push --force origin main\nexit_code: 1\nsource: Global\ncaptured_at: 2026-04-02T15:31:20+00:00\ncorrection: NEVER force push to main. Use feature branches and PRs.\n---\n\n## Command\n\n`git push --force origin main`\n\n## Error Output\n\n
\n

rejected

\n
\n## Suggested Correction\n\n`NEVER force push to main. Use feature branches and PRs.`\n
\n

Being plain markdown, these files are:

\n\n

CLI Reference

\n
# List recent learnings\nterraphim-agent learn list\n\n# Query by pattern (full-text search)\nterraphim-agent learn query "pattern"\n\n# Add correction to a learning\nterraphim-agent learn correct <id> --correction "what to do instead"\n\n# Hook mode (called by PostToolUse, reads JSON from stdin)\nterraphim-agent learn hook --format claude\n
\n

Setting It Up

\n

1. Install the PostToolUse hook

\n

Create ~/.claude/hooks/post_tool_use.sh:

\n
#!/bin/bash\nset -euo pipefail\nAGENT="$HOME/.cargo/bin/terraphim-agent"\n[ -x "$AGENT" ] || exit 0\nINPUT=$(cat)\n$AGENT learn hook --format claude <<< "$INPUT" 2>/dev/null || true\n
\n

2. Register in Claude Code settings

\n

Add to .claude/settings.json:

\n
{\n  "hooks": {\n    "PostToolUse": [{\n      "matcher": "Bash",\n      "hooks": [{\n        "type": "command",\n        "command": "~/.claude/hooks/post_tool_use.sh"\n      }]\n    }]\n  }\n}\n
\n

3. Start using it

\n

Failed commands are captured automatically. Query them with terraphim-agent learn query.

\n

What Comes Next

\n

The learning system is the foundation for richer agent memory:

\n\n

The goal is not to make agents perfect on the first try. It is to make them incapable of making the same mistake twice.

\n

Conclusion

\n

AI coding agents are powerful but amnesiac. Every session starts fresh, every mistake is rediscovered. Terraphim's learning capture system closes this gap with a simple, fail-open hook that turns failures into institutional memory.

\n

The pattern is straightforward: capture failures automatically, attach corrections manually, query before acting. No training required, no model fine-tuning, no prompt engineering beyond what you already do.

\n

Your agents will still make mistakes. They just will not make the same mistakes.

\n

Resources

\n\n", "https://terraphim.ai/properties/date" : "2026-04-05", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","ai","learning","hooks","knowledge-graph","claude-code","developer-tools"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/learning-via-negativa/", "https://atomicdata.dev/properties/name" : "Learning via Negativa: How Terraphim Remembers What You Keep Getting Wrong", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/learning-via-negativa/", "https://atomicdata.dev/properties/description" : "

You know what is embarrassing? Making the same mistake for the tenth time. Last week, I typed docker-compose up instead of docker compose up. The command failed. I sighed. I corrected it. Three days later? Same thing. Same sigh. Same correction.

\n
\n

Builds on Why Graph Embeddings Matter — the deterministic engine that lets Terraphim store and replay corrections in microseconds. Apply the pattern in your own project via the Command Rewriting How-to.

\n
\n

The Problem Nobody Talks About

\n

This is not just about typos. Developers repeat the same failed patterns constantly:

\n\n

The AI agents we use? They are even worse. Claude Code, Codex, Cursor: they all make the same mistakes, over and over, because they have no long-term memory of what went wrong.

\n

We are not learning from our failures. We are just repeating them.

\n

The Solution: Learning via Negativa

\n

What if your terminal learned from every failed command?

\n

That is exactly what Terraphim's Learning via Negativa system does. It captures every failed command, extracts the mistake pattern, and builds a knowledge graph that corrects you in real-time.

\n

The name comes from the Latin \"per negativa\": learning by knowing what is wrong. It is the pedagogical equivalent of \"do not touch the hot stove\" after you have already touched it.

\n

Here is how it works:

\n
You type "docker-compose up"\n        |\nCommand fails (docker-compose is deprecated)\n        |\nHook captures: command + error + context\n        |\nKnowledge graph maps: "docker-compose" -> "docker compose"\n        |\nNext time: Terraphim auto-replaces and suggests the correct command\n
\n

The Technical Implementation

\n

This is not a wrapper script or a hack. It is a native Rust system built into terraphim-agent that captures, stores, and corrects command mistakes.

\n

1. The Capture Hook

\n

The hook intercepts failed commands from your AI agent:

\n
// crates/terraphim_agent/src/learnings/capture.rs\n\nuse serde::{Deserialize, Serialize};\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct FailedCommand {\n    pub command: String,\n    pub exit_code: i32,\n    pub stderr: String,\n    pub working_directory: String,\n    pub timestamp: DateTime<Utc>,\n    pub tags: Vec<String>,\n}\n\n/// Capture a failed command and extract the mistake pattern\npub async fn capture_failed_command(\n    command: &str,\n    exit_code: i32,\n    stderr: &str,\n    context: &CommandContext,\n) -> Result<FailedCommand, CaptureError> {\n    // Only capture non-zero exit codes (actual failures)\n    if exit_code == 0 {\n        return Err(CaptureError::CommandSucceeded);\n    }\n\n    // Filter out test commands: we do not learn from intentional failures\n    if is_test_command(command) {\n        return Err(CaptureError::TestCommand);\n    }\n\n    // Extract mistake patterns from the command\n    let tags = extract_mistake_tags(command, stderr);\n\n    let failed = FailedCommand {\n        command: redact_secrets(command),\n        exit_code,\n        stderr: stderr.clone(),\n        working_directory: context.cwd.clone(),\n        timestamp: Utc::now(),\n        tags,\n    };\n\n    // Store as markdown for human readability\n    store_learning(&failed).await?;\n\n    Ok(failed)\n}\n
\n

The hook is fail-open by design: never blocks your workflow if capture fails.

\n

2. Building the Correction Knowledge Graph

\n

Once captured, mistakes become nodes in a knowledge graph that maps wrong to correct:

\n
// crates/terraphim_rolegraph/examples/learning_via_negativa.rs\n\nuse terraphim_rolegraph::RoleGraph;\nuse terraphim_types::{NormalizedTerm, NormalizedTermValue, Thesaurus};\n\n/// Build knowledge graph for command corrections\nfn build_correction_thesaurus() -> Thesaurus {\n    let mut thesaurus = Thesaurus::new("Command Corrections".to_string());\n\n    // Docker corrections\n    thesaurus.insert(\n        NormalizedTermValue::new("docker-compose up".to_string()),\n        NormalizedTerm::new(1, NormalizedTermValue::new(\n            "docker compose up".to_string()\n        )),\n    );\n\n    // Git corrections\n    thesaurus.insert(\n        NormalizedTermValue::new("git push -f".to_string()),\n        NormalizedTerm::new(2, NormalizedTermValue::new(\n            "git push --force-with-lease".to_string()\n        )),\n    );\n\n    // Cargo corrections\n    thesaurus.insert(\n        NormalizedTermValue::new("cargo buid".to_string()),\n        NormalizedTerm::new(3, NormalizedTermValue::new(\n            "cargo build".to_string()\n        )),\n    );\n\n    thesaurus\n}\n
\n

3. Real-Time Correction

\n

The correction happens automatically via Terraphim's replace tool:

\n
# Without Learning via Negativa (old workflow)\n$ docker-compose up\ndocker-compose: command not found\n# You: sigh, retype, move on\n\n# With Learning via Negativa\n$ docker-compose up\n# Terraphim intercepts, corrects, and shows:\nSuggestion: Did you mean 'docker compose up'? (y/n)\n# You: y, command executes correctly\n
\n

Demo Results

\n

We tested Learning via Negativa with common developer mistakes over a 30-day period:

\n

Correction Examples

\n\n\n\n\n\n\n\n
Wrong CommandErrorCorrection Learned
docker-compose upcommand not founddocker compose up
git push -fremote: denied by protection policygit push --force-with-lease
cargo buiderror: no such subcommandcargo build
npm isntallcommand not foundnpm install
apt updatePermission deniedsudo apt update
git psuhgit: 'psuh' is not a git commandgit push
\n

Knowledge Graph Growth

\n
Week 1:  12 corrections captured\nWeek 2:  34 corrections captured (cumulative)\nWeek 3:  58 corrections captured (cumulative)\nWeek 4:  89 corrections captured (cumulative)\n\nTop mistake categories:\n  - Docker commands: 28%\n  - Git commands: 24%\n  - Cargo/Rust: 18%\n  - npm/yarn: 15%\n  - System commands: 15%\n
\n

Why This Matters

\n

Most AI tools have no memory. Claude Code is brilliant but stateless. Cursor remembers your files, not your mistakes. GitHub Copilot suggests code but forgets that docker-compose has been deprecated for two years.

\n

Learning via Negativa gives your AI agent a memory for failure.

\n

It transforms every error from a one-time annoyance into a permanent lesson. The more you use it, the smarter it gets. And because it is built on the knowledge graph architecture, it does not just match strings: it understands context.

\n

You typed git push -f in a repo with protected branches? It learns that -f is wrong in that context. You use docker-compose in a project with a compose.yaml file? It learns the new syntax applies here.

\n

Getting Started

\n
# Install terraphim-agent\ncargo install terraphim_agent --features repl-full\n\n# Install the learning hook for Claude Code\nterraphim-agent learn install-hook claude\n\n# Verify it is working\nterraphim-agent learn list\n\n# Query your mistakes anytime\nterraphim-agent learn query "your mistake"\n\n# Or use the replace tool for real-time corrections\necho "docker-compose up" | terraphim-agent replace\n
\n

The Bigger Picture

\n

Learning via Negativa is more than a feature: it is a philosophy. Every failure contains information. Every error message is feedback. The trick is capturing that signal instead of just ignoring the noise.

\n

We have spent decades building systems that celebrate successes. It is time we built systems that learn from failures too.

\n

Your terminal should remember what you keep getting wrong. That is not just smart: that is how humans actually learn.

\n
\n

Links

\n\n
\n

Terraphim: Your AI agent's memory for mistakes.

\n", "https://terraphim.ai/properties/date" : "2026-02-20", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","rust","cli","ai-agents","developer-tools","learning","knowledge-graph"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/multi-haystack-roles-grepapp/", "https://atomicdata.dev/properties/name" : "Introducing Multi-Haystack Roles: Local + Global Code Search", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/multi-haystack-roles-grepapp/", "https://atomicdata.dev/properties/description" : "

Today we are announcing a significant enhancement to Terraphim's engineer roles: multi-haystack support. FrontEnd Engineers and Python Engineers now have access to both local code search (via Ripgrep) and global GitHub search (via GrepApp) in a single query.

\n

The Problem: Siloed Search

\n

Traditionally, developers face a frustrating choice when searching for code:

\n
    \n
  1. Search locally - Fast, but limited to your own codebase
  2. \n
  3. Search GitHub - Broad, but requires leaving your workflow
  4. \n
\n

When you are stuck on \"how do I use this library?\" or \"what's the idiomatic way to solve this?\", you need both: your local context for project-specific code, and global examples from the broader community.

\n

The Solution: Dual Haystacks

\n

Starting with Terraphim v1.8.1, select engineer roles now come with dual haystacks:

\n

FrontEnd Engineer

\n\n

Python Engineer

\n\n

Rust Engineer v2 (already available)

\n\n

How It Works

\n

When you search as a FrontEnd or Python Engineer, Terraphim queries both sources simultaneously:

\n
Your Query: "how to use useEffect"\n    |\n+-------------------+     +--------------------+\n|  Local Ripgrep    |     |  GrepApp           |\n|  (your code)      |     |  (GitHub repos)    |\n+---------+---------+     +---------+----------+\n          |                         |\n          +-----------+-------------+\n                      |\n           Combined Results\n           (ranked by relevance)\n
\n

The results are merged and ranked according to your role's relevance function:

\n\n

This means you get the best of both worlds: your project's specific implementations AND real-world examples from popular repositories.

\n

Real-World Use Cases

\n

Learning a New Library

\n

You are trying to use react-query for the first time. A single search shows:

\n\n

Debugging Common Patterns

\n

You are debugging a Python asyncio issue. Your search returns:

\n\n

Discovering Idioms

\n

You want to know the \"Pythonic\" way to do something. Instead of reading docs, you can see:

\n\n

Technical Implementation

\n

Under the hood, this uses our existing GrepApp integration:

\n
Haystack {\n    location: "https://grep.app".to_string(),\n    service: ServiceType::GrepApp,\n    read_only: true,\n    fetch_content: false,\n    extra_parameters: {\n        let mut params = HashMap::new();\n        params.insert("language".to_string(), "python".to_string());\n        params\n    },\n}\n
\n

The extra_parameters field allows language-specific filtering:

\n\n

GrepApp returns structured results from millions of GitHub repositories, complete with:

\n\n

Graceful Degradation

\n

We know network availability is not guaranteed. If GrepApp is unreachable:

\n\n

This follows our philosophy: local-first, enhance with global.

\n

What's Next

\n

This is just the beginning. We are planning:

\n
    \n
  1. \n

    More roles with dual haystacks:

    \n\n
  2. \n
  3. \n

    Configurable filters:

    \n\n
  4. \n
  5. \n

    Enhanced ranking:

    \n\n
  6. \n
\n

Try It Now

\n

If you are already using Terraphim v1.8.1+, you can try the new roles immediately:

\n
# Switch to FrontEnd Engineer (with dual haystack)\nterraphim-agent onboard --role frontend-engineer\n\n# Switch to Python Engineer (with dual haystack)\nterraphim-agent onboard --role python-engineer\n\n# Search as usual: both local and global results appear\nterraphim-agent search "async def"\n
\n

The Bigger Picture

\n

Multi-haystack roles represent a fundamental shift in how we think about code search:

\n

Old model: One haystack per role, choose your scope\nNew model: Multiple haystacks per role, get comprehensive results

\n

This aligns with how developers actually work: they do not want to choose between \"my code\" and \"the world's code\" — they want both, intelligently combined.

\n

As we expand this pattern to more roles and add more haystack types (MCP servers, Atomic Data, AI assistants), Terraphim becomes not just a search tool, but a knowledge synthesis engine for developers.

\n

Feedback Welcome

\n

Have ideas for other haystack combinations? Want to see this pattern applied to other roles? Let us know:

\n\n
\n

Related Reading:

\n\n

Terraphim: Search your world.

\n", "https://terraphim.ai/properties/date" : "2026-02-16", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","release","features","grepapp","haystack","code-search"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/native-hook-support/", "https://atomicdata.dev/properties/name" : "Native Hook Support: terraphim-agent Now Learns from Your Mistakes", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/native-hook-support/", "https://atomicdata.dev/properties/description" : "
\n

This is the February 2026 announcement for v1.8.1. For the tested failure → reviewed correction → execution flow, follow the current command-rewriting guide.

\n
\n

We are announcing native hook support for terraphim-agent v1.8.1. This feature captures failed commands from AI agents (Claude Code, Codex, OpenCode) and learns from them, creating a personal knowledge base of mistakes and corrections. No more jq dependency, no more bash wrappers: just terraphim-agent learn hook.

\n

The Problem

\n

If you are using AI agents like Claude Code, you have probably experienced this:

\n
    \n
  1. Agent suggests: cargo buid (typo)
  2. \n
  3. Command fails with error
  4. \n
  5. You fix it: cargo build
  6. \n
  7. The mistake is forgotten
  8. \n
  9. Next session: Same typo, same failure
  10. \n
\n

Every developer has their own \"greatest hits\" of mistakes:

\n\n

These mistakes are personal, contextual, and valuable: if only we could remember them.

\n

The Solution: Native Hook Support

\n

With terraphim-agent v1.8.1, we have introduced a complete learning system:

\n
# One-command setup\nterraphim-agent learn install-hook claude\n\n# That's it. Every failed command is now captured automatically.\n
\n

How It Works

\n
Claude Code executes Bash command\n        |\nCommand fails (exit code != 0)\n        |\nHook captures: command + error + context\n        |\nStored as Markdown: ~/.local/share/terraphim/learnings/\n        |\nQuery anytime: terraphim-agent learn query "cargo buid"\n
\n

Key Features

\n

1. Native Implementation

\n\n

2. Universal Support\nWorks with Claude Code, Codex, and OpenCode:

\n
terraphim-agent learn install-hook claude\nterraphim-agent learn install-hook codex\nterraphim-agent learn install-hook opencode\n
\n

3. Fail-Open Design\nNever blocks your workflow. If capture fails, the command still executes.

\n

4. Smart Filtering

\n\n

5. Rich Context\nEach learning includes:

\n\n

Live Demonstration

\n

Let us prove it works with a realistic scenario:

\n

Step 1: Set Role

\n
$ terraphim-agent setup --template rust-engineer-v2\nConfiguration set to role 'Rust Engineer v2'\n
\n

Step 2: Capture Mistake

\n
# Simulate Claude Code making a typo\necho '{"tool_name":"Bash","tool_input":{"command":"cargo buid"},...}' \\\n  | ~/.config/claude/terraphim-hook.sh\n
\n

Step 3: Verify Capture

\n
$ terraphim-agent learn list\nRecent learnings:\n  1. [G] cargo buid (exit: 101)\n
\n

Step 4: Query Mistake

\n
$ terraphim-agent learn query "cargo buid"\nLearnings matching 'cargo buid':\n  [G] cargo buid (exit: 101)\n
\n

Multi-Role Engineering

\n

We have also added 4 new engineer role templates, each with different ranking methods:

\n\n\n\n\n\n
RoleRankingUse Case
FrontEnd EngineerBM25PlusJavaScript/TypeScript development
Python EngineerBM25FPython with field-weighted ranking
Rust Engineer v2TitleScorerDual haystack (docs.rs + local)
Terraphim Engineer v2TerraphimGraphGraph embeddings + hybrid KG
\n

Each role learns differently and optimises search for its domain.

\n

The Complete Learning Cycle

\n
+-------------------------------------------------------------+\n|  1. LEARN                                                    |\n|     Command fails -> Hook captures -> Markdown stored        |\n|     Works with Claude, Codex, OpenCode                       |\n+-------------------------------------------------------------+\n|  2. QUERY                                                    |\n|     Search patterns -> Find similar mistakes                 |\n|     Pattern matching on command + error                      |\n+-------------------------------------------------------------+\n|  3. CORRECT                                                  |\n|     Add corrections: learn correct <id> --correction         |\n|     Future: Auto-suggest from knowledge graph                |\n+-------------------------------------------------------------+\n|  4. REPLACE                                                  |\n|     Real-time suggestions via replace --role <role>          |\n|     Uses thesaurus for context-aware corrections             |\n+-------------------------------------------------------------+\n
\n

Installation

\n
# Install latest terraphim-agent\ncargo install terraphim_agent --features repl-full\n\n# Install hook for your AI agent\nterraphim-agent learn install-hook claude\n\n# Verify installation\nterraphim-agent learn --help\n
\n

Verification and Validation

\n

This release passed rigorous quality gates:

\n\n

What's Next

\n
    \n
  1. Auto-suggest: Query learnings in real-time during command entry
  2. \n
  3. Learning insights: Analytics on most common mistakes per role
  4. \n
  5. Team sharing: Optional sync of learnings across team members
  6. \n
  7. IDE integration: VS Code extension for inline suggestions
  8. \n
\n

Get Started

\n
# Install\ncargo install terraphim_agent --features repl-full\n\n# Set up your role\nterraphim-agent setup --template rust-engineer-v2\n\n# Install hook\nterraphim-agent learn install-hook claude\n\n# Start learning from your mistakes\n
\n

Links

\n\n
\n

Terraphim: Your AI agent's memory for mistakes.

\n", "https://terraphim.ai/properties/date" : "2026-02-16", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","rust","cli","ai-agents","developer-tools","learning"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/zvec-vs-terraphim-comparison/", "https://atomicdata.dev/properties/name" : "zvec vs Terraphim: Two Paths to Semantic Search", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/zvec-vs-terraphim-comparison/", "https://atomicdata.dev/properties/description" : "

When it comes to semantic search, there are fundamentally different architectural approaches. Alibaba's zvec and Terraphim represent two distinct philosophies: neural embeddings vs. knowledge graphs, scale vs. interpretability, dense vectors vs. co-occurrence relationships.

\n

The Core Philosophy

\n

zvec: Neural Embeddings at Scale

\n

zvec is a lightweight, in-process vector database built on Alibaba's battle-tested Proxima engine. It transforms documents into high-dimensional vectors using neural embedding models (BERT, OpenAI, etc.), then uses Approximate Nearest Neighbour (ANN) algorithms like HNSW to find similar documents.

\n

Key Characteristics:

\n\n

Terraphim: Knowledge Graphs for Understanding

\n

Terraphim takes a radically different approach. Instead of converting documents to opaque vectors, it builds a knowledge graph from term co-occurrences. Each concept becomes a node, relationships become edges, and relevance is calculated by traversing this graph structure.

\n

Key Characteristics:

\n\n

Architectural Comparison

\n
+-------------------------------------------------------------+\n|                         zvec                                 |\n+-------------------------------------------------------------+\n|  Document -> Neural Encoder -> Dense Vector -> HNSW Index    |\n|                                                    |         |\n|  Query -> Neural Encoder -> Query Vector -> ANN Search -> K  |\n+-------------------------------------------------------------+\n                              vs\n+-------------------------------------------------------------+\n|                       Terraphim                              |\n+-------------------------------------------------------------+\n|  Document -> Term Extraction -> Co-occurrence -> Graph       |\n|                                                   |          |\n|  Query -> Aho-Corasick Match -> Graph Traversal -> Ranked    |\n+-------------------------------------------------------------+\n
\n

Data Structures

\n\n\n\n\n\n\n
ComponentzvecTerraphim
Storage UnitCollection (table-like)RoleGraph (knowledge graph)
Document IDStringString
RepresentationsDense/Sparse vectors (768-dim+)Nodes, Edges, Thesaurus
Index TypesHNSW, IVF, Flat, InvertedHash maps + Aho-Corasick
PersistenceDisk-based collectionsJSON serialisation
\n

Query Semantics

\n

zvec Query:

\n
import zvec\n\n# Semantic similarity via vector comparison\nresults = collection.query(\n    zvec.VectorQuery("embedding", vector=[0.1, -0.3, ...]),\n    topk=10,\n    filter="category == 'tech'"\n)\n# Returns: documents with similar vectors (cosine similarity)\n
\n

Terraphim Query:

\n
// Graph traversal with term expansion\nlet results = role_graph.query_graph(\n    "async programming",\n    Some(0),  // offset\n    Some(10)  // limit\n);\n// Returns: documents ranked by graph connectivity\n// Matched nodes: "async", "programming", "concurrency", "tokio"\n
\n

Feature Matrix

\n\n\n\n\n\n\n\n\n\n\n\n\n\n
FeaturezvecTerraphim
Dense EmbeddingsNativeNot used
Sparse VectorsBM25 supportedBM25/BM25F/BM25Plus
Knowledge GraphNoCore architecture
ANN SearchHNSW/IVF/FlatNot applicable
SQL-like FiltersSQL engineGraph-based filtering
ExplainabilityLow (black box)High (show path)
Synonym ExpansionVia embedding modelVia thesaurus
Role/Persona SupportNoRoleGraphs
Multi-HaystackSingle collectionMultiple sources
Built-in RerankersRRF, WeightedGraph ranks directly
QuantisationINT8/FP16Not needed
Hybrid SearchVectors + FiltersGraph + Haystacks
\n

Performance Characteristics

\n

zvec (Benchmarks from 10M vector dataset)

\n\n

Terraphim (Observed Performance)

\n\n

When to Use Which

\n

Choose zvec When:

\n
    \n
  1. \n

    You need to search billions of documents

    \n\n
  2. \n
  3. \n

    You are building RAG systems with LLMs

    \n\n
  4. \n
  5. \n

    You need image/audio similarity search

    \n\n
  6. \n
  7. \n

    Exact semantic similarity matters

    \n\n
  8. \n
\n

Choose Terraphim When:

\n
    \n
  1. \n

    You need explainable results

    \n\n
  2. \n
  3. \n

    You have domain-specific knowledge

    \n\n
  4. \n
  5. \n

    You are building personal knowledge management

    \n\n
  6. \n
  7. \n

    You need role-based search

    \n\n
  8. \n
\n

Code Comparison

\n

Document Indexing

\n

zvec (Python):

\n
import zvec\n\nschema = zvec.CollectionSchema(\n    name="docs",\n    vectors=zvec.VectorSchema("emb", zvec.DataType.VECTOR_FP32, 768),\n)\n\ncollection = zvec.create_and_open(path="./data", schema=schema)\n\n# Documents must have pre-computed embeddings\ncollection.insert([\n    zvec.Doc(\n        id="doc1",\n        vectors={"emb": embedding_model.encode("Rust async programming")},\n        fields={"title": "Async in Rust"}\n    ),\n])\n
\n

Terraphim (Rust):

\n
use terraphim_rolegraph::RoleGraph;\nuse terraphim_types::{Document, RoleName};\n\nlet mut graph = RoleGraph::new(\n    RoleName::new("engineer"),\n    thesaurus\n).await?;\n\n// Documents are indexed into the graph\ngraph.index_documents(vec![\n    Document {\n        id: "doc1".into(),\n        title: "Async in Rust".into(),\n        body: "Rust's async/await syntax...".into(),\n        // Graph extracts terms automatically\n        ..Default::default()\n    },\n]).await?;\n
\n

Searching

\n

zvec:

\n
# Vector similarity search\nquery_vec = embedding_model.encode("how to write async code")\nresults = collection.query(\n    zvec.VectorQuery("emb", vector=query_vec),\n    topk=5\n)\n# Results ranked by cosine similarity\n
\n

Terraphim:

\n
// Graph-based search\nlet results = graph.query_graph("async code", None, Some(5))?;\n// Results ranked by:\n// 1. Node rank (concept frequency)\n// 2. Edge rank (relationship strength)\n// 3. Document rank (occurrence count)\n
\n

Can They Work Together?

\n

Absolutely. Here are some integration patterns:

\n

1. Hybrid Retrieval

\n

Use zvec for initial broad retrieval, Terraphim for reranking:

\n
# Step 1: zvec ANN for candidate retrieval\ncandidates = zvec_collection.query(query_vector, topk=100)\n\n# Step 2: Terraphim graph reranking\n# Load candidates into temporary graph\n# Re-rank based on knowledge graph connectivity\n
\n

2. Explainable Vector Search

\n

Use Terraphim's graph to explain zvec results:

\n
User: "Why did this document match?"\nSystem:\n  - zvec: "Vector similarity: 0.92"\n  - Terraphim: "Matched via concepts: async -> tokio -> concurrency"\n
\n

Conclusion

\n

zvec and Terraphim solve semantic search with fundamentally different approaches:

\n\n

The exciting possibility is combining both: zvec's scale with Terraphim's explainability. The future of semantic search might just be hybrid.

\n

References

\n\n
\n

Have you used zvec or Terraphim? We would love to hear about your experiences on GitHub Issues.

\n", "https://terraphim.ai/properties/date" : "2026-02-16", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","vector-search","knowledge-graph","semantic-search","comparison"],"categories":["Technical"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/teaching-ai-agents-with-knowledge-graphs/", "https://atomicdata.dev/properties/name" : "Teaching AI Coding Agents with Knowledge Graph Hooks", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/teaching-ai-agents-with-knowledge-graphs/", "https://atomicdata.dev/properties/description" : "

How we use Aho-Corasick automata and knowledge graphs to automatically enforce coding standards across AI coding agents like Claude Code, Cursor, and Aider.

\n
\n

New: see Why Graph Embeddings Matter for the underlying engine that makes these hooks possible — sub-millisecond, deterministic, fully explainable.

\n
\n

Anthropic Bought Bun. Claude Still Outputs npm install.

\n

On December 3, 2025, Anthropic announced its first-ever acquisition: Bun, the blazing-fast JavaScript runtime. This came alongside Claude Code reaching $1 billion in run-rate revenue just six months after public launch.

\n

As Mike Krieger, Anthropic's Chief Product Officer, put it:

\n
\n

\"Bun represents exactly the kind of technical excellence we want to bring into Anthropic... bringing the Bun team into Anthropic means we can build the infrastructure to compound that momentum.\"

\n
\n

Claude Code ships as a Bun executable to millions of developers. Anthropic now owns the runtime their flagship coding tool depends on.

\n

And yet...

\n

Ask Claude to set up a Node.js project, and what do you get?

\n
npm install express\nyarn add lodash\npnpm install --save-dev jest\n
\n

Yet Anthropic's own models still default to npm, yarn, and pnpm in their outputs. The training data predates the acquisition, and old habits die hard.

\n

So how do you teach your AI coding tools to consistently use Bun, regardless of what the underlying LLM insists on?

\n

The Problem: LLMs Don't Know Your Preferences

\n

AI coding agents are powerful, but they're trained on the internet's collective habits—which means npm everywhere. Your team might have standardized on Bun for its speed (25% monthly growth, 7.2 million downloads in October 2025), but every AI agent keeps suggesting the old ways.

\n

Manually fixing these inconsistencies is tedious. What if your knowledge graph could automatically intercept and transform AI outputs?

\n

The Solution: Knowledge Graph Hooks

\n

Terraphim provides a hook system that intercepts AI agent actions and applies knowledge graph-based transformations. The system uses:

\n
    \n
  1. Aho-Corasick automata for efficient multi-pattern matching
  2. \n
  3. LeftmostLongest strategy ensuring specific patterns match before general ones
  4. \n
  5. Markdown-based knowledge graph files that are human-readable and version-controlled
  6. \n
\n

How It Works

\n
Input Text → Aho-Corasick Automata → Pattern Match → Knowledge Graph Lookup → Transformed Output\n
\n

The knowledge graph is built from simple markdown files:

\n
# bun install\n\nFast package installation with Bun.\n\nsynonyms:: pnpm install, npm install, yarn install\n
\n

When the automata encounter any synonym, they replace it with the canonical term (the heading).

\n

Real-World Example: npm → bun

\n

Let's prove it works. Here's a live test:

\n
$ echo "npm install" | terraphim-agent replace\nbun install\n\n$ echo "yarn install lodash" | terraphim-agent replace\nbun install lodash\n\n$ echo "pnpm install --save-dev jest" | terraphim-agent replace\nbun install --save-dev jest\n
\n

The LeftmostLongest matching ensures npm install matches the more specific pattern before standalone npm could match.

\n

Hook Integration Points

\n

Terraphim hooks integrate at multiple points in the development workflow:

\n

1. Claude Code PreToolUse Hooks

\n

Intercept Bash commands before execution:

\n
{\n  "hooks": {\n    "PreToolUse": [{\n      "matcher": "Bash",\n      "hooks": [{\n        "type": "command",\n        "command": "terraphim-agent replace"\n      }]\n    }]\n  }\n}\n
\n

When Claude Code tries to run npm install express, the hook transforms it to bun install express before execution.

\n

2. Git prepare-commit-msg Hooks

\n

Enforce attribution standards in commits:

\n
#!/bin/bash\nCOMMIT_MSG_FILE=$1\nORIGINAL=$(cat "$COMMIT_MSG_FILE")\nTRANSFORMED=$(echo "$ORIGINAL" | terraphim-agent replace)\necho "$TRANSFORMED" > "$COMMIT_MSG_FILE"\n
\n

With a knowledge graph entry:

\n
# Terraphim AI\n\nAttribution for AI-assisted development.\n\nsynonyms:: Claude Code, Claude, Anthropic Claude\n
\n

Every commit message mentioning \"Claude Code\" becomes \"Terraphim AI\".

\n

3. MCP Tools

\n

The replace_matches MCP tool exposes the same functionality to any MCP-compatible client:

\n
{\n  "tool": "replace_matches",\n  "arguments": {\n    "text": "Run npm install to setup"\n  }\n}\n
\n

Architecture

\n

The hook system is built on three crates:

\n\n\n\n\n
CratePurpose
terraphim_automataAho-Corasick pattern matching, thesaurus building
terraphim_hooksReplacementService, HookResult, binary discovery
terraphim_agentCLI with replace subcommand
\n

Performance

\n\n

Extending the Knowledge Graph

\n

Adding new patterns is simple. Create a markdown file in the mdBook source tree under docs/src/kg/ (published at https://docs.terraphim.ai/src/kg/).

\n
# pytest\n\nPython testing framework.\n\nsynonyms:: python -m unittest, unittest, nose\n
\n

The system automatically rebuilds the automata on startup.

\n

Pattern Priority

\n

The LeftmostLongest strategy means:

\n\n

Installation

\n

Quick Setup

\n
# Install all hooks\n./scripts/install-terraphim-hooks.sh --easy-mode\n\n# Test the replacement\necho "npm install" | ./target/release/terraphim-agent replace\n
\n

Manual Setup

\n
    \n
  1. Build the agent:
  2. \n
\n
cargo build -p terraphim_agent --features repl-full --release\n
\n
    \n
  1. \n

    Configure Claude Code hooks in .claude/settings.local.json

    \n
  2. \n
  3. \n

    Install Git hooks:

    \n
  4. \n
\n
cp scripts/hooks/prepare-commit-msg .git/hooks/\nchmod +x .git/hooks/prepare-commit-msg\n
\n

Use Cases

\n\n\n\n\n\n\n
Use CasePatternReplacement
Package manager standardizationnpm, yarn, pnpmbun
AI attributionClaude Code, ClaudeTerraphim AI
Framework migrationReact.ComponentReact functional components
API versioning/api/v1/api/v2
Deprecated function replacementmoment()dayjs()
\n

Claude Code Skills Plugin

\n

For AI agents that support skills, we provide a dedicated plugin:

\n
claude plugin install terraphim-engineering-skills@terraphim-ai\n
\n

The terraphim-hooks skill teaches agents how to:

\n\n

Conclusion

\n

Knowledge graph hooks provide a powerful, declarative way to enforce coding standards across AI agents. By defining patterns in simple markdown files, you can:

\n\n

The Aho-Corasick automata ensure efficient matching regardless of pattern count, making this approach scale to large knowledge graphs.

\n

Next Steps

\n

To wire knowledge-graph hooks into your own project, the Command Rewriting How-to walks through the configuration end to end. To understand why the matching is sub-millisecond and deterministic — and what that lets you promise to your users — read Why Graph Embeddings Matter.

\n

Resources

\n\n", "https://terraphim.ai/properties/date" : "2025-12-28", "https://terraphim.ai/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","ai","hooks","knowledge-graph","claude-code","developer-tools","bun","anthropic"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/posts/post-0/", "https://atomicdata.dev/properties/name" : "Announcing Terraphim AI", "https://terraphim.ai/properties/url" : "https://terraphim.ai/posts/post-0/", "https://atomicdata.dev/properties/description" : "

We have a few end-to-end demos and user journeys to discuss with early adopters of Terraphim - Privacy Preserving AI assistant.

\n", "https://terraphim.ai/properties/date" : "2023-08-12", "https://terraphim.ai/properties/tags" : {"tags":["Terraphim","ai","announcement"],"categories":["Announcements"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/local-first/", "https://atomicdata.dev/properties/name" : "Local-First Architecture", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/local-first/", "https://atomicdata.dev/properties/description" : "

Privacy by Architecture, Not by Policy

\n

Terraphim AI is not \"privacy-respecting\" because of a terms-of-service promise. It is private because the architecture makes data exfiltration structurally impossible. All indexing, searching, and knowledge graph traversal happens entirely on your device. There is no cloud dependency, no telemetry, no analytics phone-home.

\n

Design Principles

\n

The search architecture is deliberately non-neural and offline-first:

\n\n\n\n\n\n\n
PrincipleWhat It Means
Offline-firstNo network calls or LLM inference required at search time
DeterministicSame query plus same corpus equals same results, always
ExplainableEvery score decomposes into frequency counts, field weights, or set overlaps
Low footprintApproximately 15-20 MB RAM for a typical knowledge graph; no GPU, no float vectors
Graph-nativeExplicit edges and nodes encode domain relationships, not latent geometry
\n

No Account Required

\n

There is no sign-up, no API key, no subscription. You install Terraphim and it works. Your search history, your knowledge graphs, your indexed documents — all of it stays on your machine under your control.

\n

How It Compares

\n

Traditional enterprise search tools upload your data to cloud servers, process it with proprietary models, and return results through APIs that require authentication and ongoing payment. Terraphim inverts this model entirely:

\n\n

Deployment Options

\n

Terraphim runs wherever you need it: as a native desktop application, a WebAssembly module in your browser, a CLI tool, or a TUI (terminal user interface). For teams that need shared access, Terraphim Private Cloud uses AWS Firecracker microVMs to give each user a dedicated virtual machine with their own TLS certificate — keeping data isolated even in multi-tenant deployments.

\n

Learn More

\n\n", "https://terraphim.ai/properties/date" : "2026-04-05", "https://terraphim.ai/properties/tags" : {"tags":["privacy","local-first","offline","architecture"],"categories":["Capabilities"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/knowledge-graph/", "https://atomicdata.dev/properties/name" : "Knowledge Graph Engine", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/knowledge-graph/", "https://atomicdata.dev/properties/description" : "

Thousands of Patterns in a Single Pass

\n

At the heart of Terraphim is a knowledge graph engine that uses Aho-Corasick finite state automata for multi-pattern matching. Unlike traditional keyword search, Aho-Corasick matches thousands of patterns simultaneously in O(n) time relative to the text length — regardless of how many patterns are in the graph.

\n

How It Works

\n

The search pipeline operates in stages:

\n
    \n
  1. Lexical Extraction — Aho-Corasick automaton matches all thesaurus terms simultaneously, with case-insensitive, leftmost-longest matching
  2. \n
  3. Graph Traversal — Matched nodes are traversed through the RoleGraph, accumulating node rank, edge rank, and document rank
  4. \n
  5. Statistical Ranking — Pluggable scorers (BM25, BM25F, BM25+, TF-IDF, Jaccard, QueryRatio) rank results
  6. \n
  7. Similarity Re-ranking — Optional fuzzy matching via Levenshtein, Jaro, or Jaro-Winkler distance
  8. \n
\n

Role-Based Knowledge Graphs

\n

Each Terraphim role has its own separate knowledge graph containing concepts relevant to that domain, with all synonyms. A systems engineer, a project manager, and a quality analyst each see the same documents ranked differently based on their role's knowledge graph.

\n

Knowledge graphs are built from industry standards, reference process models, handbooks, and curated taxonomies. Terraphim imports these sources and produces a graph following the SIPOC pattern — concepts at the input and output of processes, with activity names linking them.

\n

Dynamic Ontology

\n

Terraphim's Dynamic Ontology enables schema-first knowledge graph construction:

\n\n

Synonym Control and Multilingual Matching

\n

Users specify synonyms manually and rebuild graph embeddings within 20 milliseconds. This allows matching terms in different languages to the same concept without running language detection. There is no need for a stop-word dictionary — \"The Pattern\" matches exactly as a project name, even though \"The\" would normally be filtered as a stop word.

\n

Learn More

\n\n", "https://terraphim.ai/properties/date" : "2026-04-05", "https://terraphim.ai/properties/tags" : {"categories":["Capabilities"],"tags":["knowledge-graph","aho-corasick","ontology","semantic-search"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/mcp-server/", "https://atomicdata.dev/properties/name" : "MCP Server Integration", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/mcp-server/", "https://atomicdata.dev/properties/description" : "

Connect Your AI Assistant to Local Knowledge

\n

Terraphim includes a native Model Context Protocol (MCP) server that exposes your local knowledge graphs to AI coding assistants like Claude Code, Claude Desktop, and other MCP-compatible tools. Your AI assistant gains domain-specific context without your data leaving your machine.

\n

Available MCP Tools

\n

Paragraph Extraction

\n

Extract paragraphs from text starting at matched terms, with precise line numbers. Useful for referencing function definitions, getting context around specific patterns, or building documentation with accurate line references.

\n

Knowledge Graph Search

\n

Semantic search that returns full document context with file paths. Unlike plain text search, this leverages your role-based knowledge graph to find documents by their conceptual relationship to your query, not just keyword overlap.

\n

Token Tracking

\n

Monitor token usage across your AI assistant sessions. Track how much context is being consumed and optimise your prompts based on actual usage data.

\n

Role-Based Context Enrichment

\n

Different roles need different context. A systems engineer asking about \"requirements\" needs different search results from a quality analyst asking the same word. Terraphim's MCP server routes queries through the active role's knowledge graph, ensuring your AI assistant receives context that matches your current domain.

\n

How It Differs from Cloud Solutions

\n

Typical AI assistant integrations send your files and context to cloud APIs. Terraphim's MCP server runs locally:

\n\n

Integration with Claude Code

\n

Terraphim works as a Claude Code MCP server, providing knowledge-graph-boosted file search, concept extraction, and role-based context enrichment directly within your development workflow.

\n

Learn More

\n\n", "https://terraphim.ai/properties/date" : "2026-04-05", "https://terraphim.ai/properties/tags" : {"tags":["mcp","ai-assistant","claude","context-engineering"],"categories":["Capabilities"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/rust-wasm/", "https://atomicdata.dev/properties/name" : "Rust/WASM Performance", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/rust-wasm/", "https://atomicdata.dev/properties/description" : "

Near-Native Speed, Everywhere

\n

Terraphim AI is written in Rust and compiles to WebAssembly. This is not a marketing choice — it is a performance requirement. Knowledge graph inference runs in 5 to 10 nanoseconds. Pipeline processing completes in hundreds of milliseconds. Search queries resolve in sub-millisecond time.

\n

Why Rust

\n

Rust provides memory safety without garbage collection, zero-cost abstractions, and thread safety guaranteed at compile time. For a system that builds and traverses knowledge graphs with thousands of nodes and edges, these guarantees translate directly into reliable performance without unexpected pauses or memory leaks.

\n

Why WebAssembly

\n

WebAssembly allows the same Rust codebase to run:

\n\n

One codebase, compiled to multiple targets, with no performance compromise.

\n

Performance Numbers

\n

The journey from The Pattern to Terraphim AI tells the performance story:

\n\n\n\n\n\n
MetricTraditional ML PipelineThe PatternTerraphim AI
Data processing for training6 days6 hoursHundreds of milliseconds
Inference latencySecondsUnder 2 ms5-10 nanoseconds
RAM footprintGigabytesHundreds of MB15-20 MB
GPU requiredYesNoNo
\n

Benchmarking

\n

Terraphim includes a comprehensive benchmarking framework covering:

\n\n

All benchmarks run on standard hardware — no GPU, no specialised accelerator.

\n

Low Footprint

\n

A typical Terraphim knowledge graph occupies approximately 15-20 MB of RAM. There are no float vectors, no dense embeddings, no GPU memory allocation. This means Terraphim runs comfortably on a laptop, a Raspberry Pi, or a modest cloud instance.

\n

Learn More

\n\n", "https://terraphim.ai/properties/date" : "2026-04-05", "https://terraphim.ai/properties/tags" : {"categories":["Capabilities"],"tags":["rust","wasm","performance","benchmarks"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/hooks/", "https://atomicdata.dev/properties/name" : "Hooks System", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/hooks/", "https://atomicdata.dev/properties/description" : "

Two-Stage Runtime Validation

\n

Terraphim implements a two-stage runtime validation system for AI-assisted development workflows. Every tool execution and LLM generation passes through hooks that provide both safety and intelligence enhancement.

\n

Stage 1: Guard Stage

\n

The guard stage prevents dangerous operations before any processing occurs:

\n\n

Stage 2: Replacement Stage

\n

The replacement stage enhances text using knowledge graph patterns:

\n\n

Learning from Mistakes

\n

Failed commands are automatically captured by post-tool-use hooks. When a bash command fails, Terraphim records the failure for later review. Over time, you build a searchable history of what went wrong and how it was corrected.

\n
# Review captured learnings\nterraphim-agent learn list\n\n# Query by pattern\nterraphim-agent learn query "npm"\n\n# Add a correction\nterraphim-agent learn correct <id> "use bun instead"\n
\n

This turns individual debugging sessions into institutional knowledge that persists across conversations and team members.

\n

Hook Types

\n

Terraphim supports hooks at four points in the AI workflow:

\n\n\n\n\n\n
HookPurpose
Pre-LLMValidate prompts before generation; block, modify, or require human confirmation
Post-LLMValidate responses; catch harmful content, enforce formatting
Pre-ToolValidate commands before execution; security checks, injection prevention
Post-ToolMonitor results; track performance, capture failures for learning
\n

Configuration

\n

Hooks are configured via TOML and environment variables, with sensible defaults:

\n\n

Deep Dives

\n\n", "https://terraphim.ai/properties/date" : "2026-04-05", "https://terraphim.ai/properties/tags" : {"categories":["Capabilities"],"tags":["hooks","ai-assistant","learning","security","claude-code"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/kg-file-search/", "https://atomicdata.dev/properties/name" : "KG-Boosted File Search", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/kg-file-search/", "https://atomicdata.dev/properties/description" : "

Beyond Keyword Matching

\n

Traditional file search finds files by name or by text content. Terraphim's KG-boosted file search finds files by their semantic relationship to your domain concepts and role-specific vocabulary.

\n

When you search for \"requirements validation\", Terraphim does not just grep for those words. It traverses your knowledge graph to find documents connected to those concepts through synonyms, co-occurrence edges, and domain relationships. A document titled \"acceptance criteria review\" surfaces because the knowledge graph knows these concepts are related in a systems engineering context.

\n

Multi-Source Search

\n

Terraphim searches across multiple sources simultaneously:

\n\n

Results from all sources are unified, deduplicated, and ranked using a single knowledge graph.

\n

Intelligent Deduplication

\n

When searching across multiple haystacks, the same document often appears in different sources. Terraphim handles duplicates intelligently, merging results and preserving the highest-ranked version rather than showing the same content multiple times.

\n

Role-Specific Relevance

\n

The same search query produces different rankings for different roles:

\n\n

Each role's knowledge graph contains domain-specific concepts and synonyms that reshape how results are scored and ordered.

\n

Context Collections

\n

Terraphim organises searchable content into context collections — curated sets of documents, taxonomies, and vocabulary that define a domain. Collections can be shared across a team or customised per user, providing consistent search relevance without centralised configuration.

\n

Integration with AI Assistants

\n

Through the MCP server, KG-boosted file search is available directly in your AI coding assistant. When Claude Code searches for files, it uses your knowledge graph to find semantically relevant results, not just filename matches.

\n

Learn More

\n\n", "https://terraphim.ai/properties/date" : "2026-04-05", "https://terraphim.ai/properties/tags" : {"tags":["search","knowledge-graph","semantic","role-based"],"categories":["Capabilities"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/origin-story/", "https://atomicdata.dev/properties/name" : "Origin Story", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/origin-story/", "https://atomicdata.dev/properties/description" : "

Inspired by Science Fiction

\n

The name Terraphim comes from the concept of an artificial intelligence as superposition of quantum fields that lives inside a spacesuit — part of an exocortex — or inside your house or vehicle, designed to help you with your tasks. You carry it with you.

\n

Similar companions are now familiar across modern science fiction. Destiny 2 has Ghost, a small floating AI bound to its Guardian. Star Wars Jedi: Survivor has BD-1, a droid riding on Cal Kestis's back. Same pattern: a compact, mobile, personal intelligence that augments rather than replaces.

\n

That image — small, local, loyal, always with you — drives the engineering choices in the rest of this page. Terraphim runs on your hardware, codifies knowledge as compact graphs rather than heavyweight models, and never ships your data across a boundary. The sci-fi premise is the brief; what follows is how we built it.

\n

From Kaggle to Nanosecond Inference

\n

Terraphim AI did not start as a product. It started as a frustration with how slowly machine learning pipelines process data.

\n

The project's predecessor, The Pattern, grew out of participation in two Kaggle data science competitions. The original ML pipeline could not finish processing data in six days. The Pattern processed the same data for training in six hours and achieved under two-millisecond inference. That hundredfold improvement was not a hardware upgrade — it was a fundamental rethinking of how search and retrieval should work.

\n

Redis Hackathon Platinum Winner

\n

The Pattern was awarded Platinum Winner at the Redis Hackathon, outperforming Nvidia's ML pipeline for BERT QA inference on CPU. The prize confirmed that external experts recognised the approach as genuinely innovative, not merely a clever optimisation.

\n

The results were presented and discussed at a public lecture at Oxford University, Green Templeton College, bringing academic scrutiny to the architecture that would become Terraphim AI.

\n

The Breakthrough: Graph Embeddings Without Attention

\n

Traditional search systems rely on dense vector embeddings and attention mechanisms that are expensive, opaque, and non-deterministic. Terraphim took a different path.

\n

Terraphim Graph Embeddings maintain the position of terms in a sentence without requiring traditional training techniques like attention. Users can specify synonyms manually and rebuild graph embeddings for a role within 20 milliseconds. This allows matching terms in different languages to the same concept without running language detection, and eliminates the need for stop-word dictionaries entirely.

\n

By rethinking from the ground up, Terraphim AI achieves pipeline processing in hundreds of milliseconds and knowledge-graph-based inference in 5 to 10 nanoseconds.

\n

Validated by INCOSE

\n

The methodology has been validated within the INCOSE (International Council on Systems Engineering) community for the Systems Engineering Handbook v.4 and the Systems Engineering Digital Process Model v.1. It was recognised as a valid low-effort substitution for formal model-based systems engineering — particularly valuable for brownfield systems engineering, reverse-engineering, and professional certification.

\n

Why Search is Broken

\n

Research consistently shows the problem Terraphim exists to solve:

\n\n

Terraphim's answer: deterministic, privacy-first, knowledge-graph-powered search that runs entirely on your hardware.

\n

Three Differentiators

\n
    \n
  1. Privacy-first: Rather than transferring data across boundaries, Terraphim codifies and moves knowledge graphs. Runs in your browser via WebAssembly.
  2. \n
  3. Action-oriented ontologies: Focused on required outcomes, not exhaustive recognition. Compact knowledge representations following YAGNI principles.
  4. \n
  5. Role-based knowledge lenses: Separate knowledge graphs per role, with user control over modifications.
  6. \n
\n

Learn More

\n\n", "https://terraphim.ai/properties/date" : "2026-04-17", "https://terraphim.ai/properties/tags" : {"tags":["history","the-pattern","redis","kaggle","oxford","incose","science-fiction"],"categories":["Capabilities"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/graph-embeddings/", "https://atomicdata.dev/properties/name" : "Graph Embeddings", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/graph-embeddings/", "https://atomicdata.dev/properties/description" : "

Terraphim uses graph embeddings instead of neural vector embeddings. Terms and concepts\nare represented as nodes in a role-specific knowledge graph, with relationships encoded as\nedges. Matching a query against a graph is deterministic, auditable, and fast.

\n

See the full design note for how RoleGraph composes\nAho-Corasick matching with PageRank ordering to produce ranked results in\nsub-millisecond time, without any floating-point vector math.

\n

Why graph embeddings

\n\n

This is a fundamentally different model from dense vector retrieval. It is what makes\nTerraphim run on a laptop, a Raspberry Pi, or inside a browser extension.

\n", "https://terraphim.ai/properties/date" : "2026-04-15", "https://terraphim.ai/properties/tags" : {"categories":["Capability"],"tags":["graph-embeddings","aho-corasick","knowledge-graph","search"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/multi-haystack/", "https://atomicdata.dev/properties/name" : "Multi-Haystack Search", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/multi-haystack/", "https://atomicdata.dev/properties/description" : "

Terraphim roles can be configured with multiple haystacks — named sources of content.\nA single query fans out across every haystack attached to the role and the results come\nback ranked by the role's knowledge graph.

\n

Haystack adapters available today:

\n\n

See the release post Introducing Multi-Haystack Roles: Local + Global Code Search\nfor a walkthrough of combining a local haystack with grepapp to search both your code and\nthe world's code in one query.

\n", "https://terraphim.ai/properties/date" : "2026-04-15", "https://terraphim.ai/properties/tags" : {"tags":["haystack","search","grepapp","code-search"],"categories":["Capability"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/terraphim-agent/", "https://atomicdata.dev/properties/name" : "terraphim-agent CLI", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/terraphim-agent/", "https://atomicdata.dev/properties/description" : "

terraphim-agent is a command-line AI agent that searches before it answers. It runs\nlocal knowledge graph queries, imports session history from Claude Code and Cursor,\ncaptures failed commands via post-tool-use hooks, and surfaces past corrections when\nyou encounter a recurring error.

\n

Install it with one command:

\n
cargo install terraphim_agent --features repl-full\n
\n

What it does

\n\n

See the command rewriting how-to and the blog post\nTeaching AI Agents to Learn from Their Mistakes\nfor worked examples.

\n", "https://terraphim.ai/properties/date" : "2026-04-15", "https://terraphim.ai/properties/tags" : {"tags":["agent","cli","ai-agents","learning"],"categories":["Capability"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/terraphim-editor/", "https://atomicdata.dev/properties/name" : "Terraphim Editor", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/terraphim-editor/", "https://atomicdata.dev/properties/description" : "

Intelligent editing with your knowledge graph

\n

Terraphim Editor brings knowledge-graph alternative suggestions into your writing. Use role-specific concepts and synonyms to compare wording in context, choose an alternative, and keep other options attached to the text. Roles provide the vocabulary for your domain; the online preview starts with a bundled local knowledge graph.

\n

Try the intelligent editor preview

\n

Keep your decisions and alternatives

\n

Attach alternatives to words, sentences and paragraphs. Save an annotated Markdown document and reopen it with those choices preserved. Newly authored alternatives register as document-scoped synonyms using synonyms:: syntax; download them through Knowledge graph to use that exact vocabulary in terraphim-grep. Sharing is explicit and does not silently alter your active role.

\n

Ghost passages to retain them outside clean export, set notes aside in Overflow, and inspect possible cuts in the Lab. KG-protected Trim preserves matched concepts and their original spelling, including supported Unicode normalization.

\n

The editor runs as WebAssembly in your browser. Editing with the bundled graph does not require an LLM or sending your document to a provider.

\n

See actual saved outputs

\n

Watch the 80-second alternative-to-search story: create Concern as an alternative to Risk, share the graph and find related decisions, with and without synthesis.

\n

Earlier captioned browser and extension walkthroughs: Chrome, Safari, Firefox and the existing Zed extension, followed by search with the same shared KG, with and without synthesis. Each video identifies its recorded scope; the current browser build includes the later Unicode normalization repair.

\n

This is a preview. Complete acceptance against all 41 source-video requirements remains open, including Safari dragging and some visual/native cases. The existing Zed extension demonstrates its supported capabilities; the separate Zed fork is outside this publication.

\n\n\n", "https://terraphim.ai/properties/date" : "2026-10-11", "https://terraphim.ai/properties/tags" : {"categories":["Capabilities"],"tags":["editor","knowledge-graph","role-based","wasm"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/evaluation/", "https://atomicdata.dev/properties/name" : "Automata Evaluation", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/evaluation/", "https://atomicdata.dev/properties/description" : "

The evaluation framework measures how accurately the Aho-Corasick automata classify terms in\nreal documents. Give it a JSON file of hand-labeled documents and it returns micro-averaged\nprecision, recall, and F1, a per-term breakdown, and a list of terms that consistently\nproduce false positives.

\n

When to use it

\n\n

Ground-truth file format

\n
[\n  {\n    "id": "doc1",\n    "text": "tokio powers async rust applications",\n    "expected_terms": [\n      { "term": "tokio",  "category": null },\n      { "term": "rust",   "category": null },\n      { "term": "async",  "category": null }\n    ]\n  }\n]\n
\n

Each term must match the normalized term value (nterm) stored in the thesaurus.

\n

Running an evaluation

\n
use terraphim_automata::evaluation::{evaluate, load_ground_truth};\n\nlet docs = load_ground_truth(Path::new("ground_truth.json"))?;\nlet result = evaluate(&docs, thesaurus);\n\nprintln!("F1: {:.2}", result.overall.f1);\nfor report in &result.per_term {\n    println!("  {} precision={:.2} recall={:.2}",\n        report.term, report.metrics.precision, report.metrics.recall);\n}\nfor err in &result.systematic_errors {\n    println!("  SYSTEMATIC FP: {} in {} documents", err.term, err.false_positive_count);\n}\n
\n

How metrics are computed

\n

Metrics are micro-averaged: true positives, false positives, and false negatives are\nsummed across all documents before dividing.

\n

A term is flagged as a SystematicError when it appears as a false positive in 2 or more\ndocuments. Matching is case-insensitive; each term is counted at most once per document.

\n

Source: crates/terraphim_automata/src/evaluation.rs

\n", "https://terraphim.ai/properties/date" : "2026-04-16", "https://terraphim.ai/properties/tags" : {"categories":["Capabilities"],"tags":["evaluation","automata","testing","quality"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/capabilities/listener-dispatch/", "https://atomicdata.dev/properties/name" : "Gitea Agent Dispatch", "https://terraphim.ai/properties/url" : "https://terraphim.ai/capabilities/listener-dispatch/", "https://atomicdata.dev/properties/description" : "

The listener dispatch feature lets you run terraphim-agent subcommands by mentioning the\nagent in a Gitea issue or comment. The result is posted back as a formatted markdown comment.

\n

Triggering a command

\n

Mention the agent in a Gitea comment with a subcommand and arguments:

\n
@adf:worker search "knowledge graph" --role engineer\n@adf:worker evaluate --role engineer\n@adf:worker learn list\n
\n

The listener parses the text after @adf:, validates it through three security layers, runs\nthe command, and posts the output back to the same issue.

\n

Security

\n

Three checks must all pass before the process is spawned:

\n

1. Shell metacharacter rejection — Input containing |, ;, &, `, $, (,\n), <, or > is rejected immediately. No shell is involved in execution, but this\nprevents confusion if the input is ever logged or replayed.

\n

2. Subcommand allowlist / denylist — Only known safe subcommands are permitted.\nDenied subcommands (listen, repl, interactive, setup, update, sessions)\nare blocked even if added to extra_allowed_subcommands.

\n

3. CommandGuard — A pattern-based guard runs on the full command string before\nprocess spawn. It blocks destructive patterns such as git reset --hard.

\n

Configuration

\n

Enable dispatch in your listener config JSON:

\n
{\n  "identity": { "agent_name": "worker" },\n  "gitea": {\n    "base_url": "https://git.terraphim.cloud",\n    "owner": "terraphim",\n    "repo": "terraphim-ai"\n  },\n  "dispatch": {\n    "timeout_secs": 300,\n    "max_output_bytes": 48000,\n    "specialist_routes": {\n      "evaluate": "eval-bot"\n    }\n  }\n}\n
\n

specialist_routes routes specific subcommands to a named agent rather than running locally.

\n

Output

\n

The comment posted back to Gitea includes the exit code, elapsed time, stdout in a code\nblock, and stderr in a collapsible section. Output is capped at 48 KB. Commands that exceed\n5 minutes are killed and marked **TIMED OUT**.

\n

The --robot flag is always appended, so output is machine-readable JSON regardless of the\nuser's default format.

\n

Source: crates/terraphim_agent/src/shell_dispatch.rs, crates/terraphim_agent/src/listener.rs

\n", "https://terraphim.ai/properties/date" : "2026-04-16", "https://terraphim.ai/properties/tags" : {"categories":["Capabilities"],"tags":["gitea","agent","dispatch","security","automation"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/how-tos/knowledge-work-editor/", "https://atomicdata.dev/properties/name" : "Write and search with the same knowledge graph", "https://terraphim.ai/properties/url" : "https://terraphim.ai/how-tos/knowledge-work-editor/", "https://atomicdata.dev/properties/description" : "

Watch the new 80-second story: create a synonym, share it, then search

\n

These earlier host recordings remain available as versioned evidence. The new story above follows the current alternative-to-search flow.

\n

Try Terraphim Editor

\n

Keep alternatives attached to words, sentences and paragraphs. Ghost a passage without losing it, stash notes in Overflow, and use the Lab to inspect possible cuts. The editor runs as WebAssembly in your browser with a bundled local knowledge graph.

\n

Grammarly for knowledge work

\n

Follow a public project brief from editing to search using the same knowledge graph. The 77-second captioned overview shows the browser editor, explicitly hands off to the clean file exported from Safari, then compares real terraphim-grep executions with and without --answer.

\n

\n

Recorded host walkthroughs

\n\n

The browser recordings produced identical saved annotated files. A separately checked Safari clean-export file supplies the grep corpus; the Safari walkthrough does not show that export gesture. Newly authored Assessment registers as a document-scoped synonym; it does not update the shared KG used by the CLI. Zed demonstrates existing extension capabilities; the Zed fork is separate. The brief's Trim preview produced zero cuts, so this recording does not demonstrate text reduction. The generated synthesis overstates a review policy as observed practice; compare that statement with the returned evidence rather than treating it as verified fact.

\n

All six videos now have explanatory on-screen captions. Idle intervals are cut, actions are accelerated by 1.5–3× where disclosed, and the long terminal end hold is removed. Captions sit outside the application image. Safari setup is cut and the Zed avatar remains masked. Chronological source ranges and speed changes are recorded in the manifest; original captures are retained. These are finite walkthroughs, not complete acceptance of all 41 requirements. Build identities, media hashes and edit disclosures identify the recorded candidate. The current editor preview includes the Unicode normalization repair: canonically equivalent accents, Terraphim Unicode lowercase and Greek sigma equivalence protect exact original spellings during Trim. The videos retain their earlier recorded build identity; they do not demonstrate this later repair.

\n

This is a preview. The complete source-video requirements are still being qualified; Safari dragging and some visual/native cases remain unresolved. Keyboard pull from Overflow is available. The browser demo does not imply full custom visual parity in the stock Zed extension.

\n

Start with a public brief

\n

Paste this supplied example into the editor. It is sample input, not generated output:

\n
# Public research workspace\n\nDecision: launch a local-first research workspace for the delivery team.\n\nThe decision owner will review the brief before the pilot begins.\n\nRisk: inconsistent terminology makes prior decisions hard to locate.\n\nUse the project brief to align the team and keep the decision record clear.\n
\n

Turn on Write_On using the word counter. Explore alternatives for “decision”, add your own wording, and compare it in context. Ghost/revive a passage, stash a note in Overflow and inspect the Lab. Save the result and reopen the actual file to check the choices and annotations.

\n

Save your work and use it in search

\n

Save keeps the Markdown, alternatives, ghosts and Overflow together. Clean Markdown export includes active text and omits ghosts, Overflow and the annotation block. Chrome can offer a file handle; Firefox and Safari use a download. Check the actual browser dialog and downloaded file.

\n

Download the same bundled KG and inspect the editor build identity. Newly authored alternatives register as document-scoped synonyms; they do not silently change this shared KG.

\n

Move the chosen saved or clean-exported file into a dedicated local corpus folder. Keep evidence logs and other copies outside that folder. With terraphim-grep installed, set paths for that public corpus and downloaded KG:

\n
terraphim-grep "decision" --thesaurus ./default.json --paths ./public-corpus --json\nterraphim-grep "decision" --thesaurus ./default.json --paths ./public-corpus --json --answer\n
\n

The first command returns search evidence without enabling synthesis. The second asks for an answer when sufficient evidence and a configured provider are available. Keep the query, corpus and KG unchanged to compare them. Add the same --role-config path to both commands if configuring a provider through a role. Check the generated answer against the returned source lines; a missing answer or provider error is not a successful synthesis.

\n

Writing and local search do not require sending your document to an LLM. Synthesis may send retrieved content to the configured provider. Use public sample content for the demo and inspect the provider configuration before enabling --answer.

\n", "https://terraphim.ai/properties/date" : "2026-10-11", "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/how-tos/synonym-search/", "https://atomicdata.dev/properties/name" : "Different words. The same idea.", "https://terraphim.ai/properties/url" : "https://terraphim.ai/how-tos/synonym-search/", "https://atomicdata.dev/properties/description" : "

Your project brief says risk. Later, you search for concern. Terraphim connects the two so a change of wording does not hide the decisions you need.

\n

The inspiration came from Jason Fried’s original Write_On video and its idea of “alternative control”. It prompted Alex Mikhalev to return to Terraphim Editor, a Rust/WebAssembly project he had abandoned two years earlier, with a clear purpose: connect wording alternatives to a reusable knowledge graph and carry that meaning into search.

\n

\n

Try Terraphim Editor · Install for VS Code · Read the narration

\n

Choose the words that fit

\n

In our community garden brief, timber might arrive late. The team has decided to keep a backup supplier. Add Concern as an alternative to Risk, then swap between them. The other wording stays attached to the document.

\n

Share what those words mean

\n

Open Knowledge graph from the Markdown export menu. The editor shows Risk ↔ Concern and its actual definition:

\n
synonyms:: Risk, Concern\n
\n

Download the graph and the clean text. This explicitly shares the document's authored synonym groups as a Terraphim thesaurus; it does not silently change your active role. The saved example contains Risk, with no literal occurrence of Concern.

\n

Find the decisions using either word

\n

Use the graph downloaded from that editing session:

\n
terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --search-only --json\n
\n

The actual result contains three risk passages and their related decisions, with file and line locations. No generated answer is requested.

\n

Replace --search-only with --answer for synthesis:

\n
terraphim-grep concern --thesaurus knowledge-graph.json --paths corpus -C 2 --json --answer\n
\n

The video shows the generated summary and its references to the same three passages. Decisions remain decisions: the source does not establish whether they have been carried out. Check the evidence alongside any generated answer.

\n

Editing and local search use your local data. Optional synthesis sends the retrieved passages to your configured model provider.

\n

See the same workflow in Kilo

\n

This supplier brief says Risk. Search for Concern using its exported graph, and both retrieval and synthesis find the same three passages. The generated answer points back to the brief's decisions and actions.

\n

\n

A 44-second replay of saved tool results in Kilo, with captions and no audio. It shows the saved Risk/Concern alternative, source lines and cited summary. The Kilo skills are under marketplace review; this is a configured integration.

\n

Download the brief, graph and actual results · Kilo setup guide · Recorded versions and checksums

\n

Try it with an Obsidian vault

\n

Keep the words that describe a concept in the note that owns it. In this example, Risk.md contains the actual synonyms:: Risk, Concern property and embeds the community garden brief. The separate brief still says risk, never concern. The search-results note contains saved passages, with no synonym definition.

\n
\"Obsidian
Captured in Obsidian 1.14.4. The knowledge note owns the synonyms; Obsidian displays saved CLI results.
\n

Download the Obsidian demo vault ZIP. Extract it, open the included obsidian-demo/vault folder as an Obsidian vault, and open Notes/Risk.md. Open Search results/Concern search.md alongside it to inspect the saved output. No community plugins are required.

\n

To reproduce the retrieval, install terraphim-grep v1.21.19, open a terminal in the extracted vault directory, and run:

\n
terraphim-grep concern --thesaurus "Knowledge graph/baseline-role.json" --paths "Notes/Projects" -C 2 --json --search-only\nterraphim-grep concern --thesaurus "Knowledge graph/knowledge-graph.json" --paths "Notes/Projects" -C 2 --json --search-only\n
\n

The released binary returned zero passages with the baseline graph and three exact risk-and-decision passages with the exported graph, at lines 7, 10 and 13. The commands search only the project brief directory, excluding the concept definition and saved results. Inspect the baseline output, synonym output, execution receipt and file checksums.

\n

Terraphim’s synonyms:: convention uses Logseq-compatible Markdown property syntax. Obsidian’s native aliases use YAML aliases. This example supplies the same graph exported by the editor explicitly: saving a note does not automatically rebuild the graph or synchronise the vault. Search runs in the CLI; Obsidian displays the notes and saved results. The capture reruns local retrieval only; the video above shows the separate synthesis comparison.

\n

Try it with a Logseq graph

\n

Prefer linked blocks? Open the same garden project in Logseq. The Risk concept page owns the wording relationship and embeds the project brief. Its properties are:

\n
alias:: Concern\nsynonyms:: Risk, Concern\n
\n

alias:: gives the page another name inside Logseq. Terraphim’s synonyms:: property records the words connected by the exported search graph.

\n
\"Logseq
The imported graph in Logseq 2.0.2: wording belongs to the concept page; the sidebar shows saved CLI passages.
\n
\"The
Explore the garden brief’s connections in Logseq’s graph view. The arrows show page links; the Risk note holds the synonym definition used by the supplied Terraphim search graph.
\n
    \n
  1. Download the Logseq example ZIP and extract it.
  2. \n
  3. In Logseq 2.0, choose Import existing notes → File to DB graph, then select the included graph folder. If you use a Logseq version with file graphs, open that folder directly.
  4. \n
  5. Open Start here, then Risk. Search for Concern search and choose Open in sidebar to compare the saved results with the project note.
  6. \n
\n

From a terminal in the extracted graph folder, run:

\n
terraphim-grep concern --thesaurus baseline-role.json --paths pages/Projects -C 2 --json --search-only\nterraphim-grep concern --thesaurus knowledge-graph.json --paths pages/Projects -C 2 --json --search-only\n
\n

The first search returns zero passages. The shared synonym graph brings back three decisions: keep a backup supplier, reserve a covered area and keep a volunteer reserve list. The commands search only the project notes, leaving concept definitions and saved results outside the search.

\n

Compare the baseline and synonym search output, or follow the download instructions. The CLI reads the included Markdown files; Logseq 2.0 imports a copy into its database. Use the extracted folder for these commands. File checksums are included.

\n

Try it yourself

\n
    \n
  1. Download the complete example ZIP. It includes the project brief, synonym graph and a step-by-step README.
  2. \n
  3. Install terraphim-grep for macOS or Linux.
  4. \n
  5. Extract the ZIP and follow the README to search the brief, first without the synonym relationship and then with it. Add --answer when you want a summary alongside the source passages.
  6. \n
\n

Searching for concern returns no passages before the graph is shared. With the graph, it finds all three risk passages and their related decisions. Compare the saved results before sharing, with the synonym graph, and with a generated summary.

\n

Then try the same steps with a pair of words from your own project notes.

\n

Explore the files

\n\n

The video uses a sample project brief and synthetic British English narration. The graph and search results are saved outputs from the demonstrated workflow. Recording details and versions, commands and file checksums are available with the downloads.

\n

Explore more editor walkthroughs.

\n", "https://terraphim.ai/properties/date" : "2026-10-11", "https://terraphim.ai/properties/tags" : {"tags":["editor","knowledge-graph","search"],"categories":["How-tos"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/how-tos/command-rewriting-howto/", "https://atomicdata.dev/properties/name" : "A failed command, a saved correction, and the next run", "https://terraphim.ai/properties/url" : "https://terraphim.ai/how-tos/command-rewriting-howto/", "https://atomicdata.dev/properties/description" : "

A coding agent uses the wrong flag. You explain the correction, and the command works. The useful question is what happens when another session makes the same mistake.

\n

This walkthrough follows one harmless error from failure to saved correction to actual execution. Each execution now has one record linking the model’s request, the matching rewrite rule, the command the tool ran and its saved result. It uses the Harbour project brief from the memory walkthrough, a released Terraphim agent, and an OpenCode adapter included in the download.

\n\n

Download the Harbour hooks example · Read the transcript

\n

Start with the command that fails

\n

Harbour's validator checks that its brief contains a decision, a risk and an owner. The correct command ends with --check. In the baseline run, OpenCode actually attempts:

\n
python3 validate-brief.py --chek\n
\n

The argument is misspelled. Python's argument parser reports that --check is required and exits with status 2. No validation.json is created. The downloadable trace contains the host's actual tool result, including that output and exit status.

\n

That distinction matters: the coding host itself can finish normally after reporting a failed tool. Its overall process exit code is not evidence that the validator succeeded. Here we inspect the shell tool's result and the expected output file.

\n

Capture the failure that really happened

\n

The included project-local adapter receives OpenCode's after-tool event. It translates the real command, combined output and exit status into Terraphim's learning-hook schema, then calls the released agent.

\n

The saved Markdown learning contains the command, exit code 2 and the parser's actual error. A new CLI process can list it again. This gives the correction a concrete source: an observed failure, with a saved record that can be inspected.

\n

The adapter is part of this example. In the tested release, passing a native OpenCode event directly with --format opencode does not by itself establish that a learning was captured. The script checks the resulting file and later readback.

\n

Review and promote the correction

\n

We add the intended command to the failure record with learn correct. That records a proposed correction. It does not automatically make it a replacement rule: compiling the failure record alone produces zero correction entries in this release.

\n

The next step is explicit human review and promotion to a tool preference. Here, “review” means checking the intended correction; it is not a built-in approval gate. The reproduction script runs this command inside its isolated store:

\n
terraphim-agent learn correction add \\\n  --correction-type tool-preference \\\n  --original 'python3 validate-brief.py --chek' \\\n  --corrected 'python3 validate-brief.py --check' \\\n  --context 'Manually reviewed correction from the captured failure'\nterraphim-agent learn compile --output compiled-corrections.json\nterraphim-agent learn export-kg --output kg\n
\n

Compilation now reports one correction. The selected Harbour Validator role loads that compiled JSON. The exported Markdown makes the relationship readable:

\n
# python3 validate-brief.py --check\nsynonyms:: python3 validate-brief.py --chek\n
\n

This uses the same explicit synonyms:: idea as the editor-to-search flow. The correction says which command this project prefers. In this walkthrough the hook reads the compiled JSON; exporting a Markdown file alone is not the activation step.

\n

Inspect the hook before involving execution

\n

First we call the pre-tool hook on a saved input. Without --rewrite, the returned command keeps --chek and includes a warning about a replaceable match. With --rewrite, the returned JSON contains:

\n
{\n  "tool_input": {"command": "python3 validate-brief.py --check"},\n  "tool_name": "Bash"\n}\n
\n

That is a hook result. It has not executed Python. The example retains both results so you can compare the disabled and enabled behavior. An unrelated command and a role without this correction remain unchanged.

\n

\"The

\n

Verify what the coding host actually runs

\n

Now start a fresh OpenCode process and ask it to try the same misspelled command. Its before-tool event reaches the adapter. The adapter calls Terraphim with rewriting enabled, then applies the returned command through OpenCode V2's mutable tool input.

\n

The after-tool event records python3 validate-brief.py --check. Its exit status is 0. The validator prints a valid Harbour result and writes evidence/executions/<execution_id>/validation.json:

\n
{\n  "execution_id": "19578f09-a59a-4e80-be31-7d319b0c9368",\n  "project": "Harbour",\n  "status": "valid",\n  "fields": ["Decision", "Risk", "Owner"]\n}\n
\n

The host transcript can still display the model's original requested input. The hook changes the command; OpenCode executes it. Inspect the actual after-tool event to establish what ran.

\n

Keep one execution’s evidence together

\n

The included adapter records an execution ID alongside the host’s session and tool-call IDs. Its receipt.json links:

\n\n

The validator embeds the same execution ID in its printed result and saved file. The verifier checks those values against the native host events and rehashes the graph and output. A stale file, mismatched command, unmatched host call, missing artifact or altered bytes fails verification. A blocked call is retained without being labelled executed.

\n

Inspect the execution receipt, saved result and run verification.

\n

\"The

\n

This recorder covers the example’s sequential, whole-command mapping. It rejects overlapping fixture calls and unsupported rule attribution; it is not a general multi-rule provenance system.

\n

\"The

\n

Reproduce it in a new folder

\n

The example was verified with terraphim-agent v1.21.19 and OpenCode 2.0.20. The download includes the new adapter source, version 2.0.0; it is separate from the earlier binary release. Follow the ZIP's README to check the release archive, choose your already authenticated coding model and run from the extracted folder:

\n
python3 reproduction/reproduce.py \\\n  --agent /absolute/path/to/terraphim-agent \\\n  --model kimi-code-plan-global/k3 \\\n  --output /absolute/path/to/a-new-harbour-run\n
\n

Use your configured model identifier if it differs. The script uses a new folder for the fixture, settings, learning store and project-local adapter. It does not install global hooks or select a paid fallback. The recorded run used the existing Kimi coding-plan route.

\n

Run node reproduction/verify.mjs /absolute/path/to/a-new-harbour-run to check the saved evidence. Read evidence/verification.json, the host events and each execution’s receipt.json and validation.json. The ZIP also includes 22 regression tests, runnable with node --test tests/*.test.mjs. The script fails if the host does not perform the expected command or the saved outputs do not match. You can inspect the source before running it; only the two local validator commands are permitted by the fixture's host configuration.

\n

Keep the scope of the example visible

\n

This demonstrates one reviewed correction with one tested host adapter. It does not prove every coding host applies the same JSON, or that failure capture should automatically approve arbitrary substitutions. The earlier memory example and this learning store also remain separate; neither silently copies into the other.

\n

Use public sample data for this release's learning capture. Tests with deliberately fake secret-shaped values found redaction gaps in saved command and working-directory fields, and in some hook passthrough values. The example makes no blanket secret-redaction claim. The coding host uses its configured online model; Terraphim's demonstrated correction lookup uses the local compiled graph.

\n

Download the example and saved outputs to follow the whole chain: a failure that happened, a correction someone reviewed, and a later command whose result can be checked.

\n

Earlier 75-second walkthrough · Original example.

\n

Updated 13 October 2026. The new video is 66 seconds. The video uses synthetic British female narration and readable excerpts from actual released-binary and host outputs. The Harbour project is fictional public sample data.

\n", "https://terraphim.ai/properties/date" : "2026-04-15", "https://terraphim.ai/properties/tags" : {"categories":["Tutorials"],"tags":["Terraphim","hooks","OpenCode","knowledge-graph","developer-tools"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/terraphim-llm-proxy/privacy/", "https://atomicdata.dev/properties/name" : "Terraphim Proxy — Privacy Policy", "https://terraphim.ai/properties/url" : "https://terraphim.ai/terraphim-llm-proxy/privacy/", "https://atomicdata.dev/properties/description" : "

Effective date: 24 October 2026. Applies to the Terraphim Proxy macOS\napplication (cloud.terraphim.desktop), distributed via the Mac App\nStore and direct download.

\n

The short version

\n

The Terraphim Proxy application collects no data whatsoever. There\nis no account system, no telemetry, no analytics, no crash reporting, and\nno third-party tracking SDK in the app. Your credentials never leave your\nMac except inside the requests you deliberately send to the LLM providers\nyou configured.

\n

Buying a direct download does create a small server-side record — kept by\nthe Terraphim Skills marketplace, not by the app — described under\nPurchases below.

\n

What stays on your device

\n\n

What leaves your device

\n

Only the requests you send through the proxy, to the LLM providers you\nchose — over TLS, bearing the credentials those providers issued to\nyou. Their handling of that traffic is governed by their own privacy\npolicies (z.ai, OpenRouter, Groq, Cerebras, Kimi, MiniMax, DeepSeek,\nOpenAI, xAI, or any other provider you configure).

\n

Purchases

\n

Mac App Store. The app is a one-time purchase processed entirely by\nApple's App Store. Apple — not Terraphim Proxy — receives and processes\nyour payment information. The app contains no in-app purchases, no\nsubscription checks and no licence servers.

\n

Direct download. Direct-download purchases are processed by Stripe\nvia the Terraphim Skills marketplace (api.terraphim-skills.md). Stripe\n— not Terraphim — receives and processes your payment information. The\nmarketplace stores the email address on your account, the fact of the\npurchase, and which release downloads it has served to your account;\nthose records are used solely for entitlement checks and refund\nadjudication, as described in\nthe Refund policy. The application\nitself still collects nothing — this record lives entirely on the\nmarketplace side.

\n

Permissions the app requests

\n\n\n\n\n\n
EntitlementWhy
app-sandboxThe app runs sandboxed.
files.user-selected.read-writeOnly files you explicitly choose (e.g. settings export).
network.clientOutbound calls to your configured LLM providers.
network.serverLoopback-only listeners for the local proxy endpoint and the dashboard's metrics feed.
\n

Contact

\n

Questions, corrections or requests: open an issue on\nGitHub or write to\nthe maintainers via the repository.

\n

If this policy changes, the updated version is published at this URL\nbefore the change ships.

\n", "https://terraphim.ai/properties/date" : "2026-10-24", "https://terraphim.ai/properties/tags" : {"categories":["Legal"]}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/terraphim-llm-proxy/refunds/", "https://atomicdata.dev/properties/name" : "Terraphim Proxy — Refund Policy", "https://terraphim.ai/properties/url" : "https://terraphim.ai/terraphim-llm-proxy/refunds/", "https://atomicdata.dev/properties/description" : "

Effective upon launch of direct-download sales.

\n

This policy covers direct downloads purchased on terraphim.ai.\nPurchases made through the Mac App Store are refunded by Apple under the\nApple Media Services Terms and Conditions; Apple,\nnot Terraphim, decides those refunds.

\n

The short version

\n

Within 14 days of purchase you can get a full refund provided no\nrelease has been downloaded. Once your account has downloaded a release,\nthe sale is final — unless the proxy does not function.

\n

This is the same shape as Steam's rule for games: a refund is available\nwhile the product is untouched, and the usage measurement is what makes\nthe rule fair to enforce. Steam measures playtime; we measure the moment\nour service first serves the download.

\n

Why we do it this way

\n

A signed application bundle cannot be returned once it is copied to your\nMac — there is no undo. The download is the honest line between\n\"bought but not taken\" and \"taken\", and it is a line we can measure: the\nservice records the first time it serves a release download request to\nyour account, and that record is the only thing the refund rule\nconsults.

\n

We considered the alternative — a blanket 14-day window — and rejected\nit, because it would let anyone buy, download every release, and refund.\nThat pattern subsidises itself out of the purchase price of everyone\nelse.

\n

What you get back

\n\n\n\n\n\n
SituationOutcome
Within 14 days of purchase, no release downloadedFull refund, no questions asked
Any release downloaded, proxy functioning as documentedFinal sale — no refund
Any release downloaded, proxy does not functionFull refund — see When the proxy does not function below
More than 14 days after purchase, no downloadNot automatic. Ask anyway — see Outside the rules below.
\n

\"Downloaded\" is counted when our service begins delivering the release\nto your account — the request is recorded when delivery starts, not when\nthe bytes finish. A failed or interrupted delivery does not count as a\ncompleted download for refund purposes (see Downloads were broken\nbelow), and where the record is ambiguous we treat it in your favour.

\n

Refunds go back to the original payment method through Stripe. Card\nrefunds usually appear within 5–10 business days, depending on your bank\n— that part is outside our control.

\n

When a refund is issued, download access ends: the entitlement is\nrevoked and release downloads stop working.

\n

When the proxy does not function

\n

\"Not functioning\" means the software itself is defective — for example:

\n\n

It does not cover upstream problems outside our control: a provider\noutage, an exhausted provider quota, a network block on your side, or a\nmodel behaving unexpectedly. Those are the provider's service, not ours.

\n

Because the app collects no telemetry, we cannot see the failure\nourselves — when you report a defect we may ask for the app version, your\nmacOS version, and the error or behaviour you see. If the software\ngenuinely does not work, we will refund it. You should not have to argue\nthe point.

\n

How to ask

\n

Email engineering@terraphim.ai\nwith the email address on the account you purchased with. For a defect\nclaim, include the app version and macOS version.

\n

We aim to process refund requests within 3 business days.

\n

Outside the rules

\n

Outside the automatic cases a refund is at our discretion, but the door\nis not closed. We will look seriously at:

\n\n

What we record

\n

To make this policy enforceable we keep a server-side record, tied to\nyour purchase account, of when our service first serves a release\ndownload request to you — the version, the asset and the time. That is\nthe entire record — the app itself collects no telemetry and reports\nnothing back. Purchase and download records are covered in the\nPrivacy policy.

\n

Your statutory rights

\n

If you are a consumer in the UK or EU you have a legal right to cancel a\ndistance contract within 14 days. For digital content that right is lost\nonce downloading begins if you asked for immediate access and\nacknowledged losing the right — which is why checkout asks you to\nconfirm exactly that before a download becomes available.

\n

Nothing in this policy affects your statutory rights.

\n

Fair use

\n

We will refuse refunds where the pattern is clearly abusive — for\nexample repeatedly purchasing, downloading, and refunding, or\nredistributing downloaded releases. Because downloads are recorded we\ncan see this pattern; purchase of a licence does not transfer\nredistribution rights.

\n

Changes

\n

We may change this policy. Any change applies to purchases made after\nthe change, never retrospectively. Material changes will be notified by\nemail or through the site.

\n", "https://terraphim.ai/properties/date" : null, "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] },{"localId": "https://terraphim.ai/terraphim-llm-proxy/download/", "https://atomicdata.dev/properties/name" : "Terraphim Proxy — Downloads", "https://terraphim.ai/properties/url" : "https://terraphim.ai/terraphim-llm-proxy/download/", "https://atomicdata.dev/properties/description" : "

Signed macOS builds of Terraphim Proxy, served from the Terraphim Skills\nmarketplace. Downloads are tied to the account you purchased with — sign\nin below with that account, then pick a release. Every artefact is listed\nwith its SHA-256 so you can verify the download before opening it.

\n
\n \n
\n
\n

Loading releases…

\n
\n
\n\n\n\n", "https://terraphim.ai/properties/date" : null, "https://terraphim.ai/properties/tags" : {}, "https://atomicdata.dev/properties/isA": [ "https://atomicdata.dev/classes/Article" ] }]