[{"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" : "
Stay up-to-date with the latest Terraphim AI releases.
\nReleased: 7 April 2026
\nDownload from GitHub | GitHub Releases
\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n\nv1.16.31 ships pre-built binaries for 7 platforms:
\nThree binaries in each release:
\nterraphim-agent — Interactive TUI/REPL with knowledge graph searchterraphim-cli — CLI for automation, scripting, and JSON outputterraphim_server — HTTP REST API serverChoose your preferred method:
\n# Universal installer (recommended)\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n\n# Homebrew\nbrew tap terraphim/terraphim && brew install terraphim-ai\n\n# Cargo\ncargo install terraphim-agent\ncargo install terraphim-cli\n\n\nView complete release history on GitHub Releases.
\nStable releases are recommended for production use. They have been thoroughly tested and are the most reliable version.
\nLatest Stable: v1.16.31
\nDevelopment releases contain the latest features and improvements but may have more bugs. Use these for testing new features.
\nCheck the main branch for development builds.
\n# Universal installer (recommended)\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n\n# Cargo\ncargo install terraphim-agent --force\ncargo install terraphim-cli --force\n\nTerraphim maintains backward compatibility for configuration files across minor versions. Major version bumps (e.g., 1.x to 2.0) may require configuration updates.
\nAfter installation or upgrade, verify your version:
\nterraphim-agent --version\nterraphim-cli --version\n\nWant to test new features before they're released?
\nJoin our Discord server and look for #beta-testing channel. Beta testers get early access to new features and help shape product.
\nSecurity updates are released as soon as they're available. Stay informed by:
\nIf you encounter issues with a release:
\nThis guide shows how to use terraphim-agent to rewrite shell commands before\nexecution — for example npm install -> bun add or pip install -> uv add — by plugging a knowledge-graph-backed thesaurus into your AI coding\nagent's tool-execution hook.
The mechanism composes three pieces that already exist in terraphim-agent:
\n~/.config/terraphim/docs/src/kg/ (or any role-configured path).terraphim-agent replace — Aho-Corasick replacement that rewrites text\nusing a role's compiled thesaurus.replace,\nand writes the result back into the tool's args.terraphim-agent on PATH (any recent release; 1.16.33 or later).Terraphim Engineer role pointing at ~/.config/terraphim/docs/src/kg/.tool.execute.before style plugin API\n(OpenCode has one; Claude Code exposes equivalent hooks via shell scripts).Each concept is one markdown file. The filename stem becomes the concept\nkey; the H1 heading provides the display name used as the replacement; the\nsynonyms:: line lists terms that should be rewritten to it.
Example ~/.config/terraphim/docs/src/kg/bun install.md:
# bun add\n\nInstall dependencies using Bun package manager.\n\nsynonyms:: npm install, yarn install, pnpm install, npm i, yarn add, pnpm add\n\nConventions that matter in practice:
\nbun install).python -m pip install is a valid\nsynonym and is matched as a whole phrase; the Aho-Corasick automaton uses\nLeftmostLongest, so the longer phrase wins when a shorter one would also\nmatch.uv.md and uv add.md\nclaim pip install, the behaviour becomes non-deterministic at rebuild\ntime. Keep single-token synonyms in the short file (pip -> uv) and\nmulti-token phrases in the specific file (pip install -> uv add).Terraphim Engineer role| File | Maps to | Covers |
|---|---|---|
bun.md | bun | npm, yarn, pnpm |
bun install.md | bun add | npm install, yarn install, pnpm install, npm i, yarn add, pnpm add |
bun run.md | bun run | npm run, yarn run, pnpm run |
bunx.md | bunx | npx, pnpx, yarn dlx |
uv.md | uv | pip, pip3, pipx |
uv add.md | uv add | pip install, pip3 install, pip add, pipx install, python -m pip install |
uv sync.md | uv sync | pip install -r requirements.txt |
printf "npm install express" \\\n | terraphim-agent replace --role "Terraphim Engineer" --fail-open --json\n\nExpected output:
\n{"result":"bun add express","original":"npm install express","replacements":1,"changed":true}\n\nFlags worth knowing:
\n--fail-open — on any error, emits the input unchanged. Mandatory in\nhooks so a misconfigured terraphim-agent never wedges the agent.--json — structured output with result, changed, replacements.\nUse this if the hook needs to branch on whether anything changed.--format plain|markdown|wiki|html — how the replacement is wrapped.\nHooks want plain.Terraphim caches compiled thesauri in a SQLite database at\n/tmp/terraphim_sqlite/terraphim.db (path configured by\ncrates/terraphim_settings/default/settings.toml). Editing a KG markdown\nfile does not invalidate this cache; replace keeps returning the old\nmapping until you flush it.
sqlite3 /tmp/terraphim_sqlite/terraphim.db \\\n "DELETE FROM terraphim_kv WHERE key LIKE 'thesaurus_%' OR key LIKE 'document_ripgrep_%';"\n\nBecause /tmp/ is wiped on reboot, a fresh boot always gives the\nup-to-date thesaurus.
OpenCode plugins expose tool.execute.before(input, output) where\noutput.args.command is the mutable shell command about to run. The same\npattern works in Claude Code via the PreToolUse hook script, just with\nshell-stdin instead of a JS closure.
// ~/.config/opencode/plugin/terraphim-hooks.js\nconst REWRITE_MODE = process.env.TERRAPHIM_REWRITE_MODE || "suggest"\nconst REWRITE_ROLE = process.env.TERRAPHIM_REWRITE_ROLE || "Terraphim Engineer"\nconst AUDIT_LOG = `${process.env.HOME}/Library/Application Support/terraphim/rewrites.log`\n\n// Narrow whitelist of commands whose argument grammar survives a synonym swap.\nconst REWRITEABLE_HEADS =\n /^\\s*(npm|yarn|pnpm|npx|pnpx|pip|pip3|pipx|python\\s+-m\\s+pip|python3\\s+-m\\s+pip)\\b/i\n\nexport const TerraphimHooks = async ({ $ }) => ({\n "tool.execute.before": async (input, output) => {\n if (input.tool !== "Bash" || !output.args?.command) return\n const command = output.args.command\n\n const agent = `${process.env.HOME}/.cargo/bin/terraphim-agent`\n\n // Always run the destructive-command guard first.\n const g = await $`${agent} guard ${command} --json --fail-open 2>/dev/null || echo '{"decision":"allow"}'`\n const guard = JSON.parse(g.stdout)\n if (guard.decision === "block") {\n throw new Error(`BLOCKED: ${guard.reason}`)\n }\n\n const isGitCommit = /git\\s+(-C\\s+\\S+\\s+)?commit/i.test(command)\n const isRewriteable = REWRITEABLE_HEADS.test(command)\n if (!isGitCommit && !isRewriteable) return\n\n const res = await $`echo ${command} | ${agent} replace --role ${REWRITE_ROLE} --fail-open --json 2>/dev/null`\n const parsed = JSON.parse(res.stdout)\n const rewrite = (parsed.result || "").trim()\n if (!parsed.changed || !rewrite || rewrite === command) return\n\n const line = [\n new Date().toISOString(), REWRITE_MODE,\n isGitCommit ? "git-commit" : "pkg-mgr",\n command.replace(/[\\t\\n\\r]/g, " "),\n rewrite.replace(/[\\t\\n\\r]/g, " "),\n ].join("\\t") + "\\n"\n await $`mkdir -p "$(dirname ${AUDIT_LOG})" < /dev/null && printf %s ${line} >> ${AUDIT_LOG}`\n\n if (REWRITE_MODE === "apply" || isGitCommit) {\n output.args.command = rewrite\n }\n },\n})\n\nDesign notes:
\nREWRITEABLE_HEADS are candidates.TERRAPHIM_REWRITE_MODE=apply once you\ntrust the diffs. Git commit rewriting always applies because commit\nmessages are prose, not syntax.~/Library/Application Support/terraphim/rewrites.log so you can diff\nbefore flipping modes.||\nfallbacks. If terraphim-agent is missing, commands pass through unchanged.With the hook installed and the cache flushed, open your agent, ask it to\nrun npm install express, and inspect the audit log:
tail -n 5 ~/Library/Application\\ Support/terraphim/rewrites.log\n\nYou should see a line like:
\n2026-04-15T11:32:51.129Z suggest pkg-mgr npm install express bun add express\n\nIn suggest mode the command still executes as npm install express; in\napply mode the agent actually runs bun add express.
terraphim-agent learn hook --format <claude|codex|opencode> has three\nmodes driven by --learn-hook-type:
post-tool-use — the default, captures failed Bash commands as\nlearnings. This is already wired into the OpenCode plugin's\ntool.execute.after callback.pre-tool-use — checks if the command matches a past failure pattern and\nstashes the hint to ~/.local/share/terraphim/session-hints.txt for LLM\nconsumption. Does not block and does not print to the user terminal.user-prompt-submit — scans the user's prompt for patterns like \"use X\ninstead of Y\" or \"prefer X over Y\" and records a ToolPreference\ncorrection under\n~/Library/Application Support/terraphim/learnings/correction-*.md.At present these corrections are stored but not yet fed back into the\nreplacement thesaurus. Closing that loop is tracked as future work — see\nthe accompanying GitHub issue \"Learning-driven command correction: Phase 2\n& 3\".
\nreplace returns the original unchanged.\nRun terraphim-agent search \"<synonym>\" --role \"<role>\" — if the concept\nappears, the KG is loaded but the synonym is not. Confirm the synonym is on\nthe synonyms:: line (case-insensitive; commas separate entries). Flush\nthe cache (section 3) and retry.
Failed to load thesaurus: NotFound(\"thesaurus_...\") in stderr.\nCosmetic. The agent looked for a pre-compiled JSON thesaurus first, didn't\nfind one, and fell back to building from markdown. Expected on first run.
Hook does nothing in OpenCode.\nCheck the plugin loaded: grep terraphim-hooks ~/.local/share/opencode/log/$(ls -t ~/.local/share/opencode/log/ | head -1).\nYou should see a line like service=plugin path=...terraphim-hooks.js loading plugin. If absent, the plugin file is in the wrong directory —\nOpenCode autoloads from ~/.config/opencode/plugin/ and\n~/.config/opencode/plugins/.
Commands get double-rewritten on retry.\nThe hook only touches tool.execute.before; the agent does not loop back\nthrough the hook on its own retries. If you see double rewrites, check\nwhether input.tool === \"Bash\" is spelt exactly — OpenCode passes\n\"Bash\", not \"bash\".
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.
\nThe foundational crates that power Terraphim's deterministic knowledge graph search.
\n| Crate | Description |
|---|---|
| terraphim_automata | Aho-Corasick automata for searching and processing knowledge graphs. The core matching engine. |
| terraphim_rolegraph | Role-based knowledge graph module. Maps search roles to domain-specific graph views. |
| terraphim_types | Core types crate shared across the entire workspace. |
| terraphim_config | Configuration loading and management for all Terraphim components. |
| terraphim_settings | Settings handling library for runtime preferences and defaults. |
| terraphim_service | Service layer handling user requests and responses for the Terraphim core. |
| terraphim_middleware | Middleware for searching haystacks (pluggable data source backends). |
| terraphim-markdown-parser | Markdown parser for extracting structured content from knowledge base files. |
| terraphim_persistence | Persistence layer with Persistable trait and DeviceStorage backends (memory, SQLite, redb). |
| terraphim_build_args | Build argument management for compile-time feature configuration. |
| terraphim_test_utils | Shared test utilities and fixtures for all Terraphim crates. |
User-facing executables and command-line tools.
\n| Crate | Description |
|---|---|
| terraphim_agent | Terraphim AI Agent CLI with interactive REPL, session search, learning capture, and ASCII graph visualisation. |
| terraphim-cli | CLI tool for semantic knowledge graph search with JSON output for automation and scripting. |
| terraphim_server | HTTP server handling the core logic of Terraphim AI. Provides REST API and knowledge graph backend. |
| terraphim_update | Shared auto-update functionality for all Terraphim AI binaries. |
| terraphim_validation | Release validation system ensuring binary and asset integrity before publishing. |
OTP-inspired agent management system for running autonomous AI coding agents.
\n| Crate | Description |
|---|---|
| terraphim_orchestrator | AI Dark Factory orchestrator wiring spawner, router, and supervisor into a reconciliation loop. |
| terraphim_spawner | Agent spawner with health checking, output capture, and lifecycle management. |
| terraphim_router | Unified routing engine for LLM and agent providers (keyword routing, tier selection). |
| terraphim_agent_supervisor | OTP-inspired supervision trees for fault-tolerant AI agent management. |
| terraphim_agent_application | OTP-style application behaviour for the Terraphim agent system. |
| terraphim_agent_messaging | Erlang-style asynchronous message passing system for AI agents. |
| terraphim_agent_registry | Knowledge graph-based agent registry for intelligent agent discovery and capability matching. |
| terraphim_agent_evolution | Agent evolution and self-improvement tracking. |
| terraphim_workspace | Workspace management for agent execution including lifecycle, hooks, and isolation. |
| terraphim_multi_agent | Multi-agent system built on roles with rust-genai integration. |
Advanced crates for KG-powered reasoning, task planning, and goal management.
\n| Crate | Description |
|---|---|
| terraphim_kg_orchestration | Knowledge graph-based agent orchestration engine for coordinating multi-agent workflows. |
| terraphim_kg_agents | Specialised knowledge graph-based agent implementations. |
| terraphim_kg_linter | Linter for markdown-based Terraphim KG schemas (commands, types, permissions). |
| terraphim_goal_alignment | Knowledge graph-based goal alignment system for multi-level goal management and conflict resolution. |
| terraphim_task_decomposition | Knowledge graph-based task decomposition for intelligent task analysis and execution planning. |
| terraphim_rlm | Recursive Language Model (RLM) orchestration for structured reasoning chains. |
| terraphim_hooks | Unified hooks infrastructure for knowledge graph-based text replacement and validation. |
| terraphim_file_search | Knowledge-graph scored file search integration. |
| terraphim_codebase_eval | Codebase evaluation system with manifest types and metrics aggregation. |
| terraphim_negative_contribution | Negative contribution analysis for identifying anti-patterns and risks. |
Pluggable data source connectors for searching external systems.
\n| Crate | Description |
|---|---|
| haystack_core | Core traits and types for all Terraphim haystack integrations. |
| haystack_atlassian | Atlassian (Confluence, Jira) integration for searching enterprise knowledge bases. |
| haystack_discourse | Discourse forum integration for fetching posts and messages. |
| haystack_grepapp | Grep.app integration for searching code across GitHub repositories. |
| haystack_jmap | JMAP email protocol integration for searching email (Fastmail, etc.). |
Tools for analysing AI coding assistant sessions and tracking usage.
\n| Crate | Description |
|---|---|
| terraphim_sessions | Session management for AI coding assistant history. Search across Claude Code, Cursor, and Aider sessions. |
| terraphim-session-analyzer | Analyse AI coding assistant session logs to identify agent usage patterns. |
| terraphim_ccusage | Claude Code usage tracking and cost analysis. |
| terraphim_usage | General usage telemetry and analytics. |
Deployment, CI/CD, and infrastructure management.
\n| Crate | Description |
|---|---|
| terraphim_symphony | Symphony orchestration service. Reads issues from trackers and dispatches coding agent sessions. |
| terraphim_tracker | Issue tracker abstraction for Gitea and Linear with PageRank-based prioritisation. |
| terraphim_github_runner | GitHub Actions runner with Firecracker sandbox integration. |
| terraphim_github_runner_server | HTTP server for the GitHub Actions runner service. |
| terraphim-firecracker | Sub-2-second VM boot optimisation system for sandboxed agent execution. |
| terraphim_mcp_server | Model Context Protocol (MCP) server exposing Terraphim tools to AI assistants. |
| terraphim_onepassword_cli | 1Password CLI integration for secret management. |
| terraphim_atomic_client | Atomic Data Server client for managing stores and agents. |
Multi-channel AI assistant interfaces.
\n| Crate | Description |
|---|---|
| terraphim_tinyclaw | Multi-channel AI assistant for Telegram, Discord, and CLI. |
Cross-language bindings for using Terraphim from Python, Node.js, and WebAssembly.
\n| Crate | Description |
|---|---|
| terraphim_automata_py | Python (PyO3) bindings for terraphim_automata. Fast autocomplete and text processing for knowledge graphs. |
| terraphim_rolegraph_py | Python bindings for terraphim_rolegraph. Knowledge graph operations for AI agents. |
| terraphim-automata-node-rs | Node.js (NAPI) bindings for Terraphim's Aho-Corasick matcher. |
| terraphim-automata-wasm | WebAssembly bindings for terraphim_automata. Runs in the browser. |
| Crate | Description |
|---|---|
| terrraphim-automata-wasm (extension) | WASM core for the Terraphim browser extensions (Sidebar and Autocomplete). |
# Install the agent (interactive REPL + session search)\ncargo install terraphim-agent\n\n# Install the CLI (JSON output for automation)\ncargo install terraphim-cli\n\nOr use the universal installer:
\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n\nThe crate dependency graph follows a layered architecture:
\nterraphim_types, terraphim_config, terraphim_settingsterraphim_automata, terraphim_rolegraph, terraphim_persistenceterraphim_service, terraphim_middleware, haystack integrationsterraphim_spawner, terraphim_router, terraphim_agent_supervisorterraphim_orchestrator, terraphim_kg_orchestration, terraphim_symphonyterraphim_agent, terraphim-cli, terraphim_server, terraphim_tinyclawEach crate has its own README.md with specific build instructions and examples. See the Contribution Guide for the overall workflow.
Source: github.com/terraphim/terraphim-ai
\n", "https://terraphim.ai/properties/date" : "2026-04-12", "https://atomicdata.dev/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" : "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.
\nUnlike 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.
\nThe 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 "raft" ----(edge)---- "consensus"\n | |\n (edge) (edge)\n | |\n "leader" ----(edge)---- "election"\n\nWhen 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.
\nThe Terraphim Graph (scorer) uses unique graph embeddings with the following ranking algorithm:
\ntotal_rank = node.rank + edge.rank + document_rank\n\nWhere:
\nWhen you search, Terraphim:
\nThe graph embedding system is implemented in crates/terraphim_rolegraph/src/lib.rs:
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.
The system is configured via config/atomic_graph_embeddings_config.json:
{\n "roles": {\n "Atomic Graph Embeddings": {\n "relevance_function": "terraphim-graph"\n }\n }\n}\n\nThe terraphim-graph relevance function enables graph-based ranking.
Graph embeddings excel when content relationships matter more than simple keyword matching:
\nWith a learning knowledge graph:
\n| Feature | Vector Embeddings | Graph Embeddings |
|---|---|---|
| Representation | Dense vectors | Graph structure |
| Explainability | Black box | Full traceability |
| Queries expand | Implicit via distance | Explicit via synonyms |
| Relationship capture | Learns patterns | Encodes relationships |
| Domain adaptation | Requires retraining | Add to thesaurus |
Unlike vector embeddings where you don't know WHY a document matched, Terraphim's graph embeddings show:
\nThis makes results fully auditable and debuggable.
\n# Search with the Engineer role\nterraphim-agent search "graph embeddings" --role engineer\n\nThis returns results for:
\nuse 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\nEnable 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\nChoose the installation method that best suits your needs and platform.
\nThe universal installer automatically detects your platform and installs the appropriate version.
\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n\nbrew tap terraphim/terraphim && brew install terraphim-ai\n\nThis installs terraphim-agent, terraphim-cli, and terraphim_server.
Install using Cargo, Rust's package manager.
\n# Install agent with interactive TUI\ncargo install terraphim-agent\n\n# Install CLI for automation\ncargo install terraphim-cli\n\nDownload the .deb package from the latest release:
curl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent_1.16.32-1_amd64.deb\nsudo dpkg -i terraphim-agent_1.16.32-1_amd64.deb\n\nDownload the latest release from GitHub:
\n# x86_64 (GNU)\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-x86_64-unknown-linux-gnu.tar.gz\ntar -xzf terraphim-agent-1.16.32-x86_64-unknown-linux-gnu.tar.gz\nsudo mv terraphim-agent terraphim-cli terraphim_server /usr/local/bin/\n\n# x86_64 (MUSL / static)\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-x86_64-unknown-linux-musl.tar.gz\n\n# ARM64 (MUSL)\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-aarch64-unknown-linux-musl.tar.gz\n\n# ARMv7 (MUSL)\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-armv7-unknown-linux-musleabihf.tar.gz\n\n# Clone the repository\ngit clone https://github.com/terraphim/terraphim-ai.git\ncd terraphim-ai\n\n# Build all binaries\ncargo build --release\n\n# Install\nsudo cp target/release/terraphim_server /usr/local/bin/\nsudo cp target/release/terraphim-agent /usr/local/bin/\nsudo cp target/release/terraphim-cli /usr/local/bin/\n\n# Apple Silicon (ARM64)\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-aarch64-apple-darwin.tar.gz\ntar -xzf terraphim-agent-1.16.32-aarch64-apple-darwin.tar.gz\nsudo mv terraphim-agent terraphim-cli terraphim_server /usr/local/bin/\n\n# Intel (x86_64)\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-x86_64-apple-darwin.tar.gz\n\n# Universal (Fat binary)\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-universal-apple-darwin.tar.gz\n\nRequires Xcode command line tools.
\ngit clone https://github.com/terraphim/terraphim-ai.git\ncd terraphim-ai\ncargo build --release\nsudo cp target/release/terraphim_server /usr/local/bin/\nsudo cp target/release/terraphim-agent /usr/local/bin/\nsudo cp target/release/terraphim-cli /usr/local/bin/\n\n# Download and extract\ncurl -LO https://github.com/terraphim/terraphim-ai/releases/latest/download/terraphim-agent-1.16.32-x86_64-pc-windows-msvc.zip\n\nExtract the zip and add the directory to your PATH.
\n\nRequires Rust for Windows.
\ngit clone https://github.com/terraphim/terraphim-ai.git\ncd terraphim-ai\ncargo build --release\n# Binaries will be in target\\release\\\n\nThe @terraphim/autocomplete package provides NAPI bindings for autocomplete and knowledge graph functions.
npm install @terraphim/autocomplete\n\nThe terraphim-automata package provides PyO3 bindings for text matching and autocomplete.
pip install terraphim-automata\n\nTwo browser extensions are available for developer-mode installation:
\nInstall from source:
\ngit clone https://github.com/terraphim/terraphim-ai.git\ncd terraphim-ai/browser_extensions\n\nThen load unpacked in Chrome at chrome://extensions (enable Developer Mode). Coming to the Chrome Web Store soon.
See browser_extensions/INSTALL.md for detailed instructions.
\nAfter installation, verify that Terraphim is working:
\n# Check version\nterraphim-agent --version\n# terraphim-agent 1.16.32\n\nterraphim-cli --version\n# terraphim-cli 1.16.32\n\n# Start the server\nterraphim_server\n\n# In another terminal, use the agent\nterraphim-agent\n\nIf you get a permission denied error, make the binary executable:
\nchmod +x /usr/local/bin/terraphim_server\nchmod +x /usr/local/bin/terraphim-agent\nchmod +x /usr/local/bin/terraphim-cli\n\nEnsure that the installation directory is in your PATH:
\n# For bash\necho 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc\nsource ~/.bashrc\n\n# For zsh\necho 'export PATH=$PATH:/usr/local/bin' >> ~/.zshrc\nsource ~/.zshrc\n\nEnsure that you have a recent Rust version:
\nrustc --version # Should be 1.75.0 or later\nrustup update stable\n\nGet up and running with Terraphim AI in just 5 minutes.
\nChoose your preferred installation method:
\n# Single command installation with platform detection\ncurl -fsSL https://raw.githubusercontent.com/terraphim/terraphim-ai/main/scripts/install.sh | bash\n\nbrew tap terraphim/terraphim && brew install terraphim-ai\n\n# Install agent with interactive TUI\ncargo install terraphim-agent\n\n# Install CLI for automation\ncargo install terraphim-cli\n\n\nTerraphim server provides HTTP API and knowledge graph backend.
\nterraphim_server\n\nBy default, server runs on http://localhost:8080.
You should see output like:
\n[INFO] Terraphim Server v1.16.32 starting...\n[INFO] Server listening on http://localhost:8080\n[INFO] Knowledge graph initialized\n\nIn a new terminal, start the interactive agent:
\nterraphim-agent\n\nYou'll see a welcome message and can start typing commands:
\nTerraphim AI Agent v1.16.32\nType 'help' for available commands\n\n> search rust async\nFound 12 results for 'rust async'\n\n> roles select engineer\nRole set to: Engineer (optimising for technical depth)\n\n> search patterns\nFound 8 results for 'patterns'\n\nHere are the most useful commands to get started:
\n> search <query> # Search knowledge graph\n> roles select <name> # Set search role (engineer, architect, etc.)\n> connect <term1> <term2> # Link two terms in knowledge graph\n> import <file> # Import markdown file into knowledge graph\n> export <format> # Export knowledge graph (json, csv)\n> status # Show server status and statistics\n> help # Show all available commands\n\nImport your markdown files or documentation:
\n# Import a single file\nimport ~/notes/project-a.md\n\n# Import entire directory\nimport ~/Documents/knowledge-base/\n\nConfigure Terraphim to search different sources:
\n# Search GitHub repositories\nsource add github https://github.com/terraphim/terraphim-ai\n\n# Search StackOverflow\nsource add stackoverflow rust tokio\n\n# Search local filesystem\nsource add filesystem ~/code/ --recursive\n\n> search how to implement async channels in rust\n\n> roles select architect\n> search system design patterns\n\n> connect tokio async\n> show tokio\n\nFor automation and scripting, use the CLI instead of REPL:
\n# Search and get JSON output\nterraphim-cli search "async patterns" --format json\n\n# Import files programmatically\nterraphim-cli import ~/notes/*.md --recursive\n\n# Set role and search\nterraphim-cli search "rust error handling" --role engineer\n\nHere's a complete example workflow:
\n# 1. Start the server (in one terminal)\nterraphim_server &\n\n# 2. Import your codebase (in another terminal)\nterraphim-agent\n> import ~/my-project/src/\n\n# 3. Search for information\n> search error handling patterns\n\n# 4. Set role for better results\n> roles select senior-engineer\n\n# 5. Search again with role context\n> search error handling patterns\n\n# 6. Export results\n> export json > search-results.json\n\nIf you run into issues:
\nMost of the functionality is driven from the config file.
\nsection for global parameters - like global shortcuts
\n[[roles]]\n\nFor 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.
\nRoles 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).
\nEach role have a
\nThe powers roughly follows:
\n[[Skill]]\n\nParameters:
\nHaystack is a source, can be PubMed, Github, Coda.io, Notion.so etc.\nHaystack arguments
\n", "https://terraphim.ai/properties/date" : "2022-02-21", "https://atomicdata.dev/properties/tags" : {"categories":["Documentation"],"tags":["terraphim","config","plugins"]}, "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.
\nEven 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://atomicdata.dev/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.
\nTerraphim 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.
\nAfter 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.
\nTo 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:
\nSponsor the features on our GitHub page or propose a new idea in GitHub discussions
\n", "https://terraphim.ai/properties/date" : "2020-08-31", "https://atomicdata.dev/properties/tags" : {"categories":["donations","open-source"],"tags":["donate","support"]}, "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.
\nAn 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.
\nBoth Sentrux and the Terraphim evaluation toolkit are designed to close that gap. They just do so from fundamentally different perspectives.
\nSentrux (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.
\nSentrux computes a geometric mean across five orthogonal dimensions:
\n| Metric | What it captures |
|---|---|
| Modularity | Fan-in and fan-out between modules; god file detection |
| Acyclicity | Circular dependency count and which files participate |
| Depth | Maximum dependency chain length; instability score |
| Equality | Cyclomatic complexity distribution (Gini coefficient); large files |
| Redundancy | Dead functions; duplicate code groups |
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.
\nSentrux ships a native MCP server with nine tools. The intended agent workflow is:
\nsentrux.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\nThe agent gets a precise numeric verdict with a named bottleneck. It can iterate: check the bottleneck, fix it, call rescan, repeat.
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.
\n52 languages via tree-sitter plugins. Each plugin is a plugin.toml and a tags.scm query file. No Rust required to add a language.
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.
terraphim_codebase_eval)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\nRoles 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.
\nThe 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.
terraphim_negative_contribution)The Explicit Deferral Marker (EDM) scanner answers a specific and critical question: did the agent ship stubs as production code?
\nIt uses the Aho-Corasick automata to detect markers in Rust source that indicate deferred implementation:
\ntodo!()unimplemented!()panic!(\"not implemented\")panic!(\"TODO\")The scanner is production-only by design. It automatically skips:
\ntests/, examples/, benches/ directoriesbuild.rs_test.rs#[test] or #[cfg(test)]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.
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.
| Dimension | Sentrux | Terraphim EDM Scanner | Terraphim Manifest Eval |
|---|---|---|---|
| Core mechanism | tree-sitter AST + dependency graph | Aho-Corasick on EDM pattern thesaurus | Aho-Corasick on domain KG + weighted scoring |
| What it measures | Architecture: coupling, cycles, complexity | Incomplete implementations in production code | Semantic quality delta between two git SHAs |
| Language scope | 52 languages | Rust only (production files) | Any language with KG term sets |
| Unit of comparison | Quality signal delta within a session | Pass/fail per file | Before/after manifest with role-weighted scores |
| Agent integration | MCP server (9 tools, session lifecycle) | ReviewAgentOutput struct in review pipeline | EvaluationManifest loaded per evaluation run |
| False positive risk | Low (graph-structural, not text) | Very low (exact stub patterns, test exclusions) | Medium (depends on KG quality) |
| Customisation | rules.toml (layer boundaries, thresholds) | // terraphim: allow(stub) suppression | KG term sets, role weights, query direction |
| Live feedback | Yes (file watcher, treemap, MCP) | No (batch scan) | No (batch manifest) |
| Verdict granularity | Named bottleneck + per-metric breakdown | Finding list with file:line and suggestion | Improved / Degraded / Neutral with percentage |
These tools are not alternatives. They operate at different layers of the quality stack:
\nSentrux answers: Is the architecture getting worse?
\nTerraphim EDM Scanner answers: Did the agent leave stubs in production code?
\nTerraphim Manifest Eval answers: Did the agent improve or degrade domain-specific semantic quality across these two commits?
\nA complete agent quality gate combines all three:
\nsentrux session_start before the agent begins worksentrux session_end to verify no structural degradationIf 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.
\nIf 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.
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.
\nAdd 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.
\nTogether, they give you three independent quality signals that a capable agent must satisfy simultaneously: structural soundness, implementation completeness, and semantic improvement.
\nVector 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.
\nWhen you call an embedding API to retrieve context for an LLM prompt, three things happen:
\nFor 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.
\nAho-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.
\nTerraphim 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.
\nInput 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\nThe match is deterministic. The traversal is deterministic. The context injected into the prompt is always the same for the same input.
\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\nEach stage is a Rust crate with a stable public API. You can use any layer independently.
\ncargo add terraphim_automata terraphim_types terraphim_rolegraph\n\nFor Python (via PyO3 bindings):
\npip install terraphim-automata\n\nFor JavaScript/TypeScript (via WASM):
\nnpm install @terraphim/automata\n\nThe 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.
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\nfind_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.
Once you have matched entities, traverse the role graph to collect supporting context:
\nuse 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\nThe 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).
\nWe ran identical clinical cases through Google's MedGemma model with and without Terraphim knowledge graph grounding:
\n| Case | Raw MedGemma (no KG) | With Terraphim KG Grounding |
|---|---|---|
| BRAF V600E Melanoma | \"BRAF inhibitor (e.g., Dabrafenib + Trametinib)\" -- vague class suggestion | Vemurafenib 450mg orally once daily -- specific drug and dose |
| CYP2D6 Codeine Sensitivity | Oxycodone 5 mg/mL -- wrong drug entirely | Codeine 60mg every 6h -- correct drug from KG context |
| EGFR NSCLC | Osimertinib 80mg (correct on this run; prior run hallucinated 800mg -- a 10x overdose) | Osimertinib 80mg -- consistently correct per FLAURA trial |
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| Run | Pass Rate | Safety Gate | KG Grounding | Avg Latency |
|---|---|---|---|---|
| CPU | 18/18 (100%) | 100% | 83.3% | 165.3s |
| GPU #1 | 18/18 (100%) | 100% | 77.8% | 23.5s |
| GPU #2 | 18/18 (100%) | 100% | 83.3% | 24.8s |
36 total inference calls. Zero safety failures. No mocked responses.
\nThe LLM latency dominates (23-165 seconds depending on hardware). The Terraphim matching and graph traversal contributes under 1ms to each call.
\nThe 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:
\nThe 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.
\nterraphim_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\nCompare this to a typical embedding-based RAG stack: embedding model (~500MB) + vector database process (~1-2GB) + embedding API latency per call.
\nThe 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).
\nSource: 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://atomicdata.dev/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","knowledge-graph","Aho-Corasick","FST","context-engineering","tutorial"]}, "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.
\nFront-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.
\nTerraphim'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.
\nThe front-end developer agent combines three capabilities:
\nKnowledge 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.
\nLocal Search (Ripgrep): Searches your project files -- .svelte, .ts, .css, .md -- using the knowledge graph to boost conceptually relevant files.
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.
\nResults 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.
\nEach 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\nWhen 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.
If no exact match exists, a TF-IDF fallback kicks in using trigger:: directives for semantic similarity.
Terraphim offers multiple relevance functions. For a knowledge-graph-backed agent, terraphim-graph is strictly superior to the simpler bm25plus:
| Aspect | BM25Plus | TerraphimGraph |
|---|---|---|
| KG concepts affect ranking | No (display only) | Yes (graph + TF-IDF hybrid) |
| Term co-occurrence | Not used | Boosts related documents |
| KG link insertion | Disabled | Enabled in results |
| TF-IDF rescoring | Not applied | 30% weight boost |
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.
The knowledge graph is tuned for Svelte/SvelteKit development with TypeScript:
\n$state, $derived, $effect), stores, components, transitions+page.svelte, +page.ts, +layout.svelte, form actions, load functionssatisfies operatorThe GrepApp haystack is filtered to language: \"typescript\" rather than JavaScript, reflecting the modern Svelte/SvelteKit ecosystem.
# 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\nQuery: "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\nThe 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.
opencode (~/.config/opencode/opencode.json):
{\n "mcp": {\n "terraphim": {\n "type": "local",\n "command": ["~/.cargo/bin/terraphim_mcp_server"],\n "environment": { "TERRAPHIM_DATA_PATH": "~/.terraphim" }\n }\n }\n}\n\nClaude Code (~/.claude.json):
{\n "mcpServers": {\n "terraphim": {\n "type": "stdio",\n "command": "~/.cargo/bin/terraphim_mcp_server",\n "env": { "RUST_LOG": "error" }\n }\n }\n}\n\nAfter 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.
For Cursor, Windsurf, or any HTTP-based MCP client, start the SSE server: terraphim_mcp_server --sse --bind 127.0.0.1:8000.
The complete step-by-step guide covers:
\nRead it at: docs/walkthroughs/frontend-developer-agent.md
This walkthrough demonstrates the deterministic, KG-first approach. Natural extensions include:
\nThe 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://atomicdata.dev/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.
\nTerraphim 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.
\nThree numbers carry the argument. Each is reproducible on a laptop.
\nFor 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.
\nThe numbers are interesting on their own. The reason they matter is what they let you build.
\nEvery 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.
\nAdding 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.
\nBecause 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.
\nThe pieces above are infrastructure. The story arc continues:
\nnpm install, intercept it via a graph-embeddings match and replace it with bun install. We wrote this up at Teaching AI Coding Agents with Knowledge Graph Hooks — that post is the demo of what this engine enables.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.
\nThe mechanism — automata, ranking formula, ASCII walk-through — is on the Graph Embeddings reference page. Read that next if you want the data structures.
\nThe 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.
\nThe 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.
\nUntil 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://atomicdata.dev/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","graph-embeddings","knowledge-graph","aho-corasick","context-engineering"]}, "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).
Two paths. CLI first.
\nThe 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.
Concrete example. You are working in opencode and you type:
\n/tsearch "System Operator" RFP\n\nThe 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.
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.
\nterraphim-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.
Drop this at ~/.claude/commands/tsearch.md (and an identical copy at ~/.config/opencode/command/tsearch.md -- both hosts read the same frontmatter shape):
---\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\nThat 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.
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.
/tsearch "Terraphim Engineer" rolegraph\n/tsearch "System Operator" RFP\n/tsearch "Personal Assistant" invoice # uses terraphim-agent-pa wrapper for JMAP\n\nThe 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.
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.
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\nFor 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.
opencode -- add to ~/.config/opencode/opencode.json under mcp:
"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\nClaude Code -- one shell command per server:
\nclaude 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\nThe model now sees mcp__terraphim__search and mcp__terraphim_pa__search (plus the autocomplete tools) in its tool list.
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:
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\nEquivalent 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| CLI (Path A) | MCP (Path B) | |
|---|---|---|
| New binaries | None | terraphim_mcp_server plus wrapper |
| Cold start | ~50-200 ms per call | ~10-50 ms per call (long-lived process) |
| Tools exposed | search only | search + 4 autocomplete + build_autocomplete_index + update_config_tool |
| Works in any host | Yes -- anything that runs a slash command | Only hosts that speak MCP |
| Token handling | terraphim-agent-pa wrapper | terraphim_mcp_server-pa wrapper |
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.
\nYou 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.
\nMost \"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.
\nYesterday 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.
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# 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\nStep-by-step in the docs: Plug Terraphim Search into Claude Code and opencode.
\nFor 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://atomicdata.dev/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.
\nEvery AI-generated pull request we review has the same pattern:
\nThe 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.
\nThe 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\nThe 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
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
Before writing any code, the agent must understand the problem space:
\nCreate a specification before implementation:
\nWrite code with tests from the start:
\nVerify against the design, not just tests:
\nValidate against the original requirements:
\nWe packaged the V-model as executable skills you can add to any AI agent:
\nnpx skills add terraphim/terraphim-skills\n\nThis installs skills that enforce:
\nEach skill is a self-contained prompt that guides the agent through the phase's inputs, outputs, and quality gates.
\nOur judge system (Kimi K2.5) catches what humans miss:
\nAutomated quality gates, zero manual overhead. Every PR reviewed before it merges.
\nAI 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.
We use two layers of guard rails:
\nLayer 1: git-safety-guard (a terraphim-skill that runs as a PreToolUse hook):
\ngit reset --hard, git push --force, rm -rf and similar destructive commands before they executeLayer 2: Destructive Command Guard (DCG) by Jeff Emanuel, integrated via tool hooks:
\nThe 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.
\nWe run 12+ AI agents overnight on a single machine, coordinated by a Rust orchestrator. Each agent follows the V-model:
\nEvery 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.
\nThis is disciplined engineering at scale: not process overhead, but automated quality gates that catch problems before they compound.
\nThe 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 32+ executable skills we built are available today:
\nnpx skills add terraphim/terraphim-skills\n\nAdd discipline back. Your future self will thank you.
\nDeeper dive: The V-model and quality gates we use are detailed in Chapters 3-4 of \"Context Engineering with Knowledge Graphs\". Coming soon.
\nRelated posts:
\nAI coding assistants are fast, productive, and occasionally catastrophic. One misplaced rm -rf, one accidental git reset --hard, and hours of uncommitted work vanish.
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.
\nThis post shows how we integrated dcg with OpenCode using its plugin hook system, so destructive commands are intercepted before they run.
\nAI agents do not type commands into a terminal. They invoke tools programmatically, and they do not always get it right:
\nrm -rf ./src (one-character typo)git reset --hard (uncommitted work gone)git push --force (team history destroyed)You need a safety net that operates between the agent and your shell.
\nOpenCode v1.4+ exposes a plugin hook system. Hooks are top-level keys on the Hooks interface:
interface Hooks {\n "tool.execute.before"?: (input, output) => Promise<void>;\n "tool.execute.after"?: (input, output) => Promise<void>;\n}\n\nThe \"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.
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:
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\nThe complete plugin is roughly 60 lines:
\nimport { 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\nThe original plugin used a nested structure:
\nreturn {\n tool: {\n execute: {\n before: async (input, output) => { ... }\n }\n }\n};\n\nThis 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.
The fix:
\nreturn {\n "tool.execute.before": async (input, output) => { ... }\n};\n\nThis 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.
| Category | Examples |
|---|---|
| Git history destruction | git reset --hard, git push --force, git branch -D |
| Uncommitted work loss | git checkout — ., git restore file, git clean -f |
| Stash destruction | git stash drop, git stash clear |
| Filesystem damage | rm -rf outside /tmp |
| Database operations | DROP TABLE, FLUSHALL (via packs) |
| Container destruction | docker system prune, docker-compose down --volumes |
| Infrastructure | terraform destroy, kubectl delete namespace |
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.
Default-allow. Unrecognised commands pass through. DCG blocks only known dangerous patterns. This prevents false positives from blocking legitimate work.
\nWhitelist-first. Safe patterns (like git checkout -b) are checked before destructive patterns. Explicitly safe commands are never accidentally blocked.
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.
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.
\nDCG ships with a modular pack system. Enable additional protection categories in ~/.config/dcg/config.toml:
[packs]\nenabled = [\n "database.postgresql",\n "containers.docker",\n "kubernetes",\n "cloud.aws",\n]\n\nOr via environment variable:
\nexport DCG_PACKS="containers.docker,kubernetes"\n\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\nThe 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.
Instructions are suggestions. Guards are guarantees.
\nDCG is built by Jeffrey Emanuel — see his destructive_command_guard repository and the broader agentic coding flywheel ecosystem for more agent safety tooling.
\nThis 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.
\nSource: DCG plugin gist and opencode-dcg-plugin repository
\n", "https://terraphim.ai/properties/date" : "2026-04-17", "https://atomicdata.dev/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","ai","opencode","developer-tools","rust","safety","coding-agents"]}, "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.
\nThe 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.
The Personal Assistant role uses two haystacks under one role:
\nRipgrep service. Plain markdown, sub-millisecond local search, no daemon.Jmap service (RFC 8620/8621). One HTTPS round trip per query, server-side full-text against your real mailbox, results returned with jmap:///email/<id> URLs you can paste back into a mail client.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.
terraphim-agent-pa search \"<query>\" returns mixed hits ordered by rank.~/.config/terraphim/embedded_config.json. Add another haystack tomorrow (calendar, contacts, browser history) and the same query sweeps it too.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.
\nThe 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:
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\nWrap 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.
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.
\nThe end-to-end how-to is in the docs: install the prerequisites, add the JSON snippet, write the wrapper, run three verification queries.
\nRead the how-to: Personal Assistant Role on docs.terraphim.ai
\nOne 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.
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.
\nIf 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://atomicdata.dev/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.
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:
RFP, the automaton normalises it to acquisition need because that is what the handbook calls it.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:
./scripts/setup_system_operator.sh\n\nThen either drive the role via the server --
\ncargo 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:
terraphim-agent config reload\nterraphim-agent search --role "System Operator" --limit 5 "RFP"\n\nThe full config snippet and the embedded_config.json entry are in the README_SYSTEM_OPERATOR.md.
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?
\nTerraphim exposes the answer directly. validate --connectivity prints which words in your query the automaton matched and what canonical terms they normalised to:
$ 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\nFive 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.
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.
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).
The two roles expose the same pattern at two scales:
\n| System Operator | Personal Assistant | |
|---|---|---|
| KG size | 52 synonym files, 1,300-concept vocabulary | 14 synonym files, ~30-concept personal vocabulary |
| Haystacks | 1 (Logseq repo) | 2 (Obsidian vault + Fastmail JMAP) |
| Source | Public GitHub repo | Private user files and mailbox |
| Audience | Demos, onboarding, public showcase | One user |
| Lifetime | Frozen per release | Edited daily, rebuilt in 20 ms per edit |
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.
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.
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.
\ngit 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\nOr cut to the CLI if you already have terraphim-agent installed -- the embedded_config.json snippet is in the README.
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://atomicdata.dev/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\nBuilds 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
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.
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?
\nTerraphim's learning system operates as a closed loop with three stages:
\nFailed Command --> PostToolUse Hook --> Learning Store --> Query at Session Start\n\nA 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:
---\nid: 6b99a8924fad4f2aaeadf5450e76730c\ncommand: npm install react\nexit_code: 127\nsource: Global\ncaptured_at: 2026-04-04T18:43:07+00:00\n---\n\nThe hook is fail-open — if terraphim-agent is unavailable, it exits silently. Development is never blocked.
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\nThe learning file is updated in place:
\n---\nid: 6b99a8924fad4f2aaeadf5450e76730c\ncommand: npm install react\nexit_code: 127\ncorrection: "Use 'bun add react' instead"\n---\n\nAt 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\nThe agent sees past mistakes with their corrections before taking action. No more Groundhog Day.
\nThe 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\nThe 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.
| Signal | Captured? | Example |
|---|---|---|
| Non-zero exit code | Yes | npm install (exit 127) |
| Force push attempts | Yes | git push --force origin main (exit 1) |
| Compilation errors | Yes | cargo build (exit 101) |
| Successful commands | No | Only failures are stored |
| Duplicate failures | Deduplicated | Same command + exit code within a session |
Here is actual data from our production learning store, accumulated across weeks of development sessions:
\nPackage 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\nGit 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\nThese corrections are not just documentation. They are queryable institutional memory that agents consult before repeating the same mistakes.
\nThe learning system complements the Knowledge Graph Hooks we described previously. Together they form two layers of defence:
\n| Layer | Mechanism | Timing |
|---|---|---|
| Prevention | KG hooks intercept npm install and replace with bun install | Before execution |
| Learning | PostToolUse hook captures failures that slip through | After execution |
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.
\nNew failure captured --> Correction added --> Pattern promoted to KG --> Hook intercepts automatically\n\nLearning files are stored as markdown in ~/Library/Application Support/terraphim/learnings/ (macOS) or ~/.local/share/terraphim/learnings/ (Linux). Each file is a standalone document:
---\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\nrejected
\n\n## Suggested Correction\n\n`NEVER force push to main. Use feature branches and PRs.`\n\nBeing plain markdown, these files are:
\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\nCreate ~/.claude/hooks/post_tool_use.sh:
#!/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\nAdd to .claude/settings.json:
{\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\nFailed commands are captured automatically. Query them with terraphim-agent learn query.
The learning system is the foundation for richer agent memory:
\nterraphim-agent sessions search already indexes learnings alongside session transcriptsThe goal is not to make agents perfect on the first try. It is to make them incapable of making the same mistake twice.
\nAI 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.
\nThe 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.
\nYour agents will still make mistakes. They just will not make the same mistakes.
\nYou 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\nBuilds 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
This is not just about typos. Developers repeat the same failed patterns constantly:
\ngit push -f when they should use git push --force-with-leasecargo run when cargo build would catch the error fasternpm install instead of yarn install (or vice versa, depending on your project)apt-get commands without sudops aux | grep returned too many resultsThe 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.
\nWe are not learning from our failures. We are just repeating them.
\nWhat if your terminal learned from every failed command?
\nThat 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.
\nThe 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.
\nHere is how it works:
\nYou 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\nThis 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.
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\nThe hook is fail-open by design: never blocks your workflow if capture fails.
\nOnce 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\nThe 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\nWe tested Learning via Negativa with common developer mistakes over a 30-day period:
\n| Wrong Command | Error | Correction Learned |
|---|---|---|
docker-compose up | command not found | docker compose up |
git push -f | remote: denied by protection policy | git push --force-with-lease |
cargo buid | error: no such subcommand | cargo build |
npm isntall | command not found | npm install |
apt update | Permission denied | sudo apt update |
git psuh | git: 'psuh' is not a git command | git push |
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\nMost 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.
Learning via Negativa gives your AI agent a memory for failure.
\nIt 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.
\nYou 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.
# Install terraphim-agent\ncargo install terraphim-agent\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\nLearning 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.
\nWe have spent decades building systems that celebrate successes. It is time we built systems that learn from failures too.
\nYour terminal should remember what you keep getting wrong. That is not just smart: that is how humans actually learn.
\ncrates/terraphim_agent/src/learnings/crates/terraphim_rolegraph/examples/learning_via_negativa.rsTerraphim: Your AI agent's memory for mistakes.
\n", "https://terraphim.ai/properties/date" : "2026-02-20", "https://atomicdata.dev/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.
\nTraditionally, developers face a frustrating choice when searching for code:
\nWhen 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.
\nStarting with Terraphim v1.8.1, select engineer roles now come with dual haystacks:
\n~/projects or custom path)~/projects or custom path)When you search as a FrontEnd or Python Engineer, Terraphim queries both sources simultaneously:
\nYour 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\nThe results are merged and ranked according to your role's relevance function:
\nThis means you get the best of both worlds: your project's specific implementations AND real-world examples from popular repositories.
\nYou are trying to use react-query for the first time. A single search shows:
You are debugging a Python asyncio issue. Your search returns:
\nYou want to know the \"Pythonic\" way to do something. Instead of reading docs, you can see:
\nUnder the hood, this uses our existing GrepApp integration:
\nHaystack {\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\nThe extra_parameters field allows language-specific filtering:
language=javascriptlanguage=pythonGrepApp returns structured results from millions of GitHub repositories, complete with:
\nWe know network availability is not guaranteed. If GrepApp is unreachable:
\nThis follows our philosophy: local-first, enhance with global.
\nThis is just the beginning. We are planning:
\nMore roles with dual haystacks:
\nConfigurable filters:
\nEnhanced ranking:
\nIf 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\nMulti-haystack roles represent a fundamental shift in how we think about code search:
\nOld model: One haystack per role, choose your scope\nNew model: Multiple haystacks per role, get comprehensive results
\nThis 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.
\nAs 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.
\nHave ideas for other haystack combinations? Want to see this pattern applied to other roles? Let us know:
\nRelated Reading:
\n\nTerraphim: Search your world.
\n", "https://terraphim.ai/properties/date" : "2026-02-16", "https://atomicdata.dev/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" : "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.
If you are using AI agents like Claude Code, you have probably experienced this:
\ncargo buid (typo)cargo buildEvery developer has their own \"greatest hits\" of mistakes:
\nnpm isntall instead of npm installgit psuh instead of git pushpip intall instead of pip installThese mistakes are personal, contextual, and valuable: if only we could remember them.
\nWith 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\nClaude 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\n1. Native Implementation
\n2. Universal Support\nWorks with Claude Code, Codex, and OpenCode:
\nterraphim-agent learn install-hook claude\nterraphim-agent learn install-hook codex\nterraphim-agent learn install-hook opencode\n\n3. Fail-Open Design\nNever blocks your workflow. If capture fails, the command still executes.
\n4. Smart Filtering
\ncargo test, npm test)5. Rich Context\nEach learning includes:
\nLet us prove it works with a realistic scenario:
\n$ terraphim-agent setup --template rust-engineer-v2\nConfiguration set to role 'Rust Engineer v2'\n\n# Simulate Claude Code making a typo\necho '{"tool_name":"Bash","tool_input":{"command":"cargo buid"},...}' \\\n | ~/.config/claude/terraphim-hook.sh\n\n$ terraphim-agent learn list\nRecent learnings:\n 1. [G] cargo buid (exit: 101)\n\n$ terraphim-agent learn query "cargo buid"\nLearnings matching 'cargo buid':\n [G] cargo buid (exit: 101)\n\nWe have also added 4 new engineer role templates, each with different ranking methods:
\n| Role | Ranking | Use Case |
|---|---|---|
| FrontEnd Engineer | BM25Plus | JavaScript/TypeScript development |
| Python Engineer | BM25F | Python with field-weighted ranking |
| Rust Engineer v2 | TitleScorer | Dual haystack (docs.rs + local) |
| Terraphim Engineer v2 | TerraphimGraph | Graph embeddings + hybrid KG |
Each role learns differently and optimises search for its domain.
\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# Install latest terraphim-agent\ncargo install terraphim-agent\n\n# Install hook for your AI agent\nterraphim-agent learn install-hook claude\n\n# Verify installation\nterraphim-agent learn --help\n\nThis release passed rigorous quality gates:
\n# Install\ncargo install terraphim-agent\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\nTerraphim: Your AI agent's memory for mistakes.
\n", "https://terraphim.ai/properties/date" : "2026-02-16", "https://atomicdata.dev/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","rust","cli","ai-agents","developer-tools","learning"]}, "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.
\nzvec 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.
\nKey Characteristics:
\nTerraphim 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.
\nKey Characteristics:
\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| Component | zvec | Terraphim |
|---|---|---|
| Storage Unit | Collection (table-like) | RoleGraph (knowledge graph) |
| Document ID | String | String |
| Representations | Dense/Sparse vectors (768-dim+) | Nodes, Edges, Thesaurus |
| Index Types | HNSW, IVF, Flat, Inverted | Hash maps + Aho-Corasick |
| Persistence | Disk-based collections | JSON serialisation |
zvec Query:
\nimport 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\nTerraphim 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 | zvec | Terraphim |
|---|---|---|
| Dense Embeddings | Native | Not used |
| Sparse Vectors | BM25 supported | BM25/BM25F/BM25Plus |
| Knowledge Graph | No | Core architecture |
| ANN Search | HNSW/IVF/Flat | Not applicable |
| SQL-like Filters | SQL engine | Graph-based filtering |
| Explainability | Low (black box) | High (show path) |
| Synonym Expansion | Via embedding model | Via thesaurus |
| Role/Persona Support | No | RoleGraphs |
| Multi-Haystack | Single collection | Multiple sources |
| Built-in Rerankers | RRF, Weighted | Graph ranks directly |
| Quantisation | INT8/FP16 | Not needed |
| Hybrid Search | Vectors + Filters | Graph + Haystacks |
You need to search billions of documents
\nYou are building RAG systems with LLMs
\nYou need image/audio similarity search
\nExact semantic similarity matters
\nYou need explainable results
\nYou have domain-specific knowledge
\nYou are building personal knowledge management
\nYou need role-based search
\nzvec (Python):
\nimport 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\nTerraphim (Rust):
\nuse 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\nzvec:
\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\nTerraphim:
\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\nAbsolutely. Here are some integration patterns:
\nUse 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\nUse Terraphim's graph to explain zvec results:
\nUser: "Why did this document match?"\nSystem:\n - zvec: "Vector similarity: 0.92"\n - Terraphim: "Matched via concepts: async -> tokio -> concurrency"\n\nzvec and Terraphim solve semantic search with fundamentally different approaches:
\nzvec scales neural embeddings to billions of documents using ANN algorithms. It is the right choice for large-scale RAG systems, e-commerce search, and any application requiring dense vector similarity.
\nTerraphim builds interpretable knowledge graphs from term relationships. It excels at personal knowledge management, domain-specific expert systems, and any application where understanding why a document matched is as important as finding it.
\nThe exciting possibility is combining both: zvec's scale with Terraphim's explainability. The future of semantic search might just be hybrid.
\nHave 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://atomicdata.dev/properties/tags" : {"categories":["Technical"],"tags":["Terraphim","vector-search","knowledge-graph","semantic-search","comparison"]}, "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\nNew: see Why Graph Embeddings Matter for the underlying engine that makes these hooks possible — sub-millisecond, deterministic, fully explainable.
\n
npm install.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.
\nAs Mike Krieger, Anthropic's Chief Product Officer, put it:
\n\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
Claude Code ships as a Bun executable to millions of developers. Anthropic now owns the runtime their flagship coding tool depends on.
\nAnd yet...
\nAsk Claude to set up a Node.js project, and what do you get?
\nnpm install express\nyarn add lodash\npnpm install --save-dev jest\n\nYet 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.
\nSo how do you teach your AI coding tools to consistently use Bun, regardless of what the underlying LLM insists on?
\nAI 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.
\nManually fixing these inconsistencies is tedious. What if your knowledge graph could automatically intercept and transform AI outputs?
\nTerraphim provides a hook system that intercepts AI agent actions and applies knowledge graph-based transformations. The system uses:
\nInput Text → Aho-Corasick Automata → Pattern Match → Knowledge Graph Lookup → Transformed Output\n\nThe 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\nWhen the automata encounter any synonym, they replace it with the canonical term (the heading).
\nLet'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\nThe LeftmostLongest matching ensures npm install matches the more specific pattern before standalone npm could match.
Terraphim hooks integrate at multiple points in the development workflow:
\nIntercept 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\nWhen Claude Code tries to run npm install express, the hook transforms it to bun install express before execution.
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\nWith a knowledge graph entry:
\n# Terraphim AI\n\nAttribution for AI-assisted development.\n\nsynonyms:: Claude Code, Claude, Anthropic Claude\n\nEvery commit message mentioning \"Claude Code\" becomes \"Terraphim AI\".
\nThe replace_matches MCP tool exposes the same functionality to any MCP-compatible client:
{\n "tool": "replace_matches",\n "arguments": {\n "text": "Run npm install to setup"\n }\n}\n\nThe hook system is built on three crates:
\n| Crate | Purpose |
|---|---|
terraphim_automata | Aho-Corasick pattern matching, thesaurus building |
terraphim_hooks | ReplacementService, HookResult, binary discovery |
terraphim_agent | CLI with replace subcommand |
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/).
# pytest\n\nPython testing framework.\n\nsynonyms:: python -m unittest, unittest, nose\n\nThe system automatically rebuilds the automata on startup.
\nThe LeftmostLongest strategy means:
\nnpm install matches before npmpython -m pytest matches before python# 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\ncargo build -p terraphim_agent --features repl-full --release\n\nConfigure Claude Code hooks in .claude/settings.local.json
Install Git hooks:
\ncp scripts/hooks/prepare-commit-msg .git/hooks/\nchmod +x .git/hooks/prepare-commit-msg\n\n| Use Case | Pattern | Replacement |
|---|---|---|
| Package manager standardization | npm, yarn, pnpm | bun |
| AI attribution | Claude Code, Claude | Terraphim AI |
| Framework migration | React.Component | React functional components |
| API versioning | /api/v1 | /api/v2 |
| Deprecated function replacement | moment() | dayjs() |
For AI agents that support skills, we provide a dedicated plugin:
\nclaude plugin install terraphim-engineering-skills@terraphim-ai\n\nThe terraphim-hooks skill teaches agents how to:
Knowledge graph hooks provide a powerful, declarative way to enforce coding standards across AI agents. By defining patterns in simple markdown files, you can:
\nThe Aho-Corasick automata ensure efficient matching regardless of pattern count, making this approach scale to large knowledge graphs.
\nTo 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.
\nWe 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://atomicdata.dev/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" : "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.
\nThe search architecture is deliberately non-neural and offline-first:
\n| Principle | What It Means |
|---|---|
| Offline-first | No network calls or LLM inference required at search time |
| Deterministic | Same query plus same corpus equals same results, always |
| Explainable | Every score decomposes into frequency counts, field weights, or set overlaps |
| Low footprint | Approximately 15-20 MB RAM for a typical knowledge graph; no GPU, no float vectors |
| Graph-native | Explicit edges and nodes encode domain relationships, not latent geometry |
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.
\nTraditional 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:
\nTerraphim 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.
\nAt 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.
\nThe search pipeline operates in stages:
\nEach 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.
\nKnowledge 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.
\nTerraphim's Dynamic Ontology enables schema-first knowledge graph construction:
\nUsers 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.
\nTerraphim 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.
\nExtract 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.
\nSemantic 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.
\nMonitor token usage across your AI assistant sessions. Track how much context is being consumed and optimise your prompts based on actual usage data.
\nDifferent 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.
\nTypical AI assistant integrations send your files and context to cloud APIs. Terraphim's MCP server runs locally:
\nTerraphim 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.
\nTerraphim 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.
\nRust 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.
\nWebAssembly allows the same Rust codebase to run:
\nOne codebase, compiled to multiple targets, with no performance compromise.
\nThe journey from The Pattern to Terraphim AI tells the performance story:
\n| Metric | Traditional ML Pipeline | The Pattern | Terraphim AI |
|---|---|---|---|
| Data processing for training | 6 days | 6 hours | Hundreds of milliseconds |
| Inference latency | Seconds | Under 2 ms | 5-10 nanoseconds |
| RAM footprint | Gigabytes | Hundreds of MB | 15-20 MB |
| GPU required | Yes | No | No |
Terraphim includes a comprehensive benchmarking framework covering:
\nAll benchmarks run on standard hardware — no GPU, no specialised accelerator.
\nA 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.
\nTerraphim 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.
\nThe guard stage prevents dangerous operations before any processing occurs:
\n--no-verify in git operationsThe replacement stage enhances text using knowledge graph patterns:
\nFailed 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\nThis turns individual debugging sessions into institutional knowledge that persists across conversations and team members.
\nTerraphim supports hooks at four points in the AI workflow:
\n| Hook | Purpose |
|---|---|
| Pre-LLM | Validate prompts before generation; block, modify, or require human confirmation |
| Post-LLM | Validate responses; catch harmful content, enforce formatting |
| Pre-Tool | Validate commands before execution; security checks, injection prevention |
| Post-Tool | Monitor results; track performance, capture failures for learning |
Hooks are configured via TOML and environment variables, with sensible defaults:
\nTraditional 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.
\nWhen 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.
\nTerraphim searches across multiple sources simultaneously:
\nResults from all sources are unified, deduplicated, and ranked using a single knowledge graph.
\nWhen 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.
\nThe same search query produces different rankings for different roles:
\nEach role's knowledge graph contains domain-specific concepts and synonyms that reshape how results are scored and ordered.
\nTerraphim 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.
\nThrough 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.
\nThe name Terraphim comes from the Relict series of science fiction novels by Vasiliy Golovachev. In Golovachev's universe a Terraphim is an artificial intelligence 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.
\nSimilar 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.
\nThat 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.
\nTerraphim AI did not start as a product. It started as a frustration with how slowly machine learning pipelines process data.
\nThe 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.
\nThe 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.
\nThe 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.
\nTraditional search systems rely on dense vector embeddings and attention mechanisms that are expensive, opaque, and non-deterministic. Terraphim took a different path.
\nTerraphim 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.
\nBy rethinking from the ground up, Terraphim AI achieves pipeline processing in hundreds of milliseconds and knowledge-graph-based inference in 5 to 10 nanoseconds.
\nThe 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.
\nResearch consistently shows the problem Terraphim exists to solve:
\nTerraphim's answer: deterministic, privacy-first, knowledge-graph-powered search that runs entirely on your hardware.
\nTerraphim 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.
\nSee 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.
\nThis 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://atomicdata.dev/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.
\nHaystack adapters available today:
\nSee 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://atomicdata.dev/properties/tags" : {"categories":["Capability"],"tags":["haystack","search","grepapp","code-search"]}, "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.
Install it with one command:
\ncargo install terraphim-agent\n\nlearn subcommand records failed commands and their corrections.npm install to bun add,\npip install to uv add, etc. via a thesaurus.learn compile converts captured ToolPreference corrections into a\nthesaurus JSON that the replace command loads directly, closing the feedback loop from\nfailure to live rewrite.evaluate measures automata classification accuracy with\nprecision, recall, and F1 against a ground-truth JSON file, and flags terms that\nconsistently produce false positives.terraphim-agent subcommands triggered by\n@adf:<agent-name> Gitea mentions, with three security layers (allowlist, metachar\nrejection, CommandGuard), and posts results back as markdown comments.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://atomicdata.dev/properties/tags" : {"categories":["Capability"],"tags":["agent","cli","ai-agents","learning"]}, "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[\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\nEach term must match the normalized term value (nterm) stored in the thesaurus.
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\nMetrics are micro-averaged: true positives, false positives, and false negatives are\nsummed across all documents before dividing.
\nA 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.
Source: crates/terraphim_automata/src/evaluation.rs
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.
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\nThe listener parses the text after @adf:, validates it through three security layers, runs\nthe command, and posts the output back to the same issue.
Three checks must all pass before the process is spawned:
\n1. 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.
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.
3. CommandGuard — A pattern-based guard runs on the full command string before\nprocess spawn. It blocks destructive patterns such as git reset --hard.
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\nspecialist_routes routes specific subcommands to a named agent rather than running locally.
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**.
The --robot flag is always appended, so output is machine-readable JSON regardless of the\nuser's default format.
Source: crates/terraphim_agent/src/shell_dispatch.rs, crates/terraphim_agent/src/listener.rs
This guide shows how to use terraphim-agent to rewrite shell commands before\nexecution — for example npm install -> bun add or pip install -> uv add — by plugging a knowledge-graph-backed thesaurus into your AI coding\nagent's tool-execution hook.
The mechanism composes three pieces that already exist in terraphim-agent:
\n~/.config/terraphim/docs/src/kg/ (or any role-configured path).terraphim-agent replace — Aho-Corasick replacement that rewrites text\nusing a role's compiled thesaurus.replace,\nand writes the result back into the tool's args.terraphim-agent on PATH (any recent release; 1.16.33 or later).Terraphim Engineer role pointing at ~/.config/terraphim/docs/src/kg/.tool.execute.before style plugin API\n(OpenCode has one; Claude Code exposes equivalent hooks via shell scripts).Each concept is one markdown file. The filename stem becomes the concept\nkey; the H1 heading provides the display name used as the replacement; the\nsynonyms:: line lists terms that should be rewritten to it.
Example ~/.config/terraphim/docs/src/kg/bun install.md:
# bun add\n\nInstall dependencies using Bun package manager.\n\nsynonyms:: npm install, yarn install, pnpm install, npm i, yarn add, pnpm add\n\nConventions that matter in practice:
\nbun install).python -m pip install is a valid\nsynonym and is matched as a whole phrase; the Aho-Corasick automaton uses\nLeftmostLongest, so the longer phrase wins when a shorter one would also\nmatch.uv.md and uv add.md\nclaim pip install, the behaviour becomes non-deterministic at rebuild\ntime. Keep single-token synonyms in the short file (pip -> uv) and\nmulti-token phrases in the specific file (pip install -> uv add).Terraphim Engineer role| File | Maps to | Covers |
|---|---|---|
bun.md | bun | npm, yarn, pnpm |
bun install.md | bun add | npm install, yarn install, pnpm install, npm i, yarn add, pnpm add |
bun run.md | bun run | npm run, yarn run, pnpm run |
bunx.md | bunx | npx, pnpx, yarn dlx |
uv.md | uv | pip, pip3, pipx |
uv add.md | uv add | pip install, pip3 install, pip add, pipx install, python -m pip install |
uv sync.md | uv sync | pip install -r requirements.txt |
printf "npm install express" \\\n | terraphim-agent replace --role "Terraphim Engineer" --fail-open --json\n\nExpected output:
\n{"result":"bun add express","original":"npm install express","replacements":1,"changed":true}\n\nFlags worth knowing:
\n--fail-open — on any error, emits the input unchanged. Mandatory in\nhooks so a misconfigured terraphim-agent never wedges the agent.--json — structured output with result, changed, replacements.\nUse this if the hook needs to branch on whether anything changed.--format plain|markdown|wiki|html — how the replacement is wrapped.\nHooks want plain.Terraphim caches compiled thesauri in a SQLite database at\n/tmp/terraphim_sqlite/terraphim.db (path configured by\ncrates/terraphim_settings/default/settings.toml). Editing a KG markdown\nfile does not invalidate this cache; replace keeps returning the old\nmapping until you flush it.
sqlite3 /tmp/terraphim_sqlite/terraphim.db \\\n "DELETE FROM terraphim_kv WHERE key LIKE 'thesaurus_%' OR key LIKE 'document_ripgrep_%';"\n\nBecause /tmp/ is wiped on reboot, a fresh boot always gives the\nup-to-date thesaurus.
OpenCode plugins expose tool.execute.before(input, output) where\noutput.args.command is the mutable shell command about to run. The same\npattern works in Claude Code via the PreToolUse hook script, just with\nshell-stdin instead of a JS closure.
// ~/.config/opencode/plugin/terraphim-hooks.js\nconst REWRITE_MODE = process.env.TERRAPHIM_REWRITE_MODE || "suggest"\nconst REWRITE_ROLE = process.env.TERRAPHIM_REWRITE_ROLE || "Terraphim Engineer"\nconst AUDIT_LOG = `${process.env.HOME}/Library/Application Support/terraphim/rewrites.log`\n\n// Narrow whitelist of commands whose argument grammar survives a synonym swap.\nconst REWRITEABLE_HEADS =\n /^\\s*(npm|yarn|pnpm|npx|pnpx|pip|pip3|pipx|python\\s+-m\\s+pip|python3\\s+-m\\s+pip)\\b/i\n\nexport const TerraphimHooks = async ({ $ }) => ({\n "tool.execute.before": async (input, output) => {\n if (input.tool !== "Bash" || !output.args?.command) return\n const command = output.args.command\n\n const agent = `${process.env.HOME}/.cargo/bin/terraphim-agent`\n\n // Always run the destructive-command guard first.\n const g = await $`${agent} guard ${command} --json --fail-open 2>/dev/null || echo '{"decision":"allow"}'`\n const guard = JSON.parse(g.stdout)\n if (guard.decision === "block") {\n throw new Error(`BLOCKED: ${guard.reason}`)\n }\n\n const isGitCommit = /git\\s+(-C\\s+\\S+\\s+)?commit/i.test(command)\n const isRewriteable = REWRITEABLE_HEADS.test(command)\n if (!isGitCommit && !isRewriteable) return\n\n const res = await $`echo ${command} | ${agent} replace --role ${REWRITE_ROLE} --fail-open --json 2>/dev/null`\n const parsed = JSON.parse(res.stdout)\n const rewrite = (parsed.result || "").trim()\n if (!parsed.changed || !rewrite || rewrite === command) return\n\n const line = [\n new Date().toISOString(), REWRITE_MODE,\n isGitCommit ? "git-commit" : "pkg-mgr",\n command.replace(/[\\t\\n\\r]/g, " "),\n rewrite.replace(/[\\t\\n\\r]/g, " "),\n ].join("\\t") + "\\n"\n await $`mkdir -p "$(dirname ${AUDIT_LOG})" < /dev/null && printf %s ${line} >> ${AUDIT_LOG}`\n\n if (REWRITE_MODE === "apply" || isGitCommit) {\n output.args.command = rewrite\n }\n },\n})\n\nDesign notes:
\nREWRITEABLE_HEADS are candidates.TERRAPHIM_REWRITE_MODE=apply once you\ntrust the diffs. Git commit rewriting always applies because commit\nmessages are prose, not syntax.~/Library/Application Support/terraphim/rewrites.log so you can diff\nbefore flipping modes.||\nfallbacks. If terraphim-agent is missing, commands pass through unchanged.With the hook installed and the cache flushed, open your agent, ask it to\nrun npm install express, and inspect the audit log:
tail -n 5 ~/Library/Application\\ Support/terraphim/rewrites.log\n\nYou should see a line like:
\n2026-04-15T11:32:51.129Z suggest pkg-mgr npm install express bun add express\n\nIn suggest mode the command still executes as npm install express; in\napply mode the agent actually runs bun add express.
terraphim-agent learn hook --format <claude|codex|opencode> has three\nmodes driven by --learn-hook-type:
post-tool-use — the default, captures failed Bash commands as\nlearnings. This is already wired into the OpenCode plugin's\ntool.execute.after callback.pre-tool-use — checks if the command matches a past failure pattern and\nstashes the hint to ~/.local/share/terraphim/session-hints.txt for LLM\nconsumption. Does not block and does not print to the user terminal.user-prompt-submit — scans the user's prompt for patterns like \"use X\ninstead of Y\" or \"prefer X over Y\" and records a ToolPreference\ncorrection under\n~/Library/Application Support/terraphim/learnings/correction-*.md.At present these corrections are stored but not yet fed back into the\nreplacement thesaurus. Closing that loop is tracked as future work — see\nthe accompanying GitHub issue \"Learning-driven command correction: Phase 2\n& 3\".
\nreplace returns the original unchanged.\nRun terraphim-agent search \"<synonym>\" --role \"<role>\" — if the concept\nappears, the KG is loaded but the synonym is not. Confirm the synonym is on\nthe synonyms:: line (case-insensitive; commas separate entries). Flush\nthe cache (section 3) and retry.
Failed to load thesaurus: NotFound(\"thesaurus_...\") in stderr.\nCosmetic. The agent looked for a pre-compiled JSON thesaurus first, didn't\nfind one, and fell back to building from markdown. Expected on first run.
Hook does nothing in OpenCode.\nCheck the plugin loaded: grep terraphim-hooks ~/.local/share/opencode/log/$(ls -t ~/.local/share/opencode/log/ | head -1).\nYou should see a line like service=plugin path=...terraphim-hooks.js loading plugin. If absent, the plugin file is in the wrong directory —\nOpenCode autoloads from ~/.config/opencode/plugin/ and\n~/.config/opencode/plugins/.
Commands get double-rewritten on retry.\nThe hook only touches tool.execute.before; the agent does not loop back\nthrough the hook on its own retries. If you see double rewrites, check\nwhether input.tool === \"Bash\" is spelt exactly — OpenCode passes\n\"Bash\", not \"bash\".