diff --git a/Cargo.toml b/Cargo.toml index d852470..97fdaf3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ ] [workspace.package] -version = "1.20.3" +version = "1.20.4" edition = "2024" authors = ["Terraphim Team "] documentation = "https://terraphim.ai" diff --git a/crates/terraphim_agent/CHANGELOG.md b/crates/terraphim_agent/CHANGELOG.md new file mode 100644 index 0000000..dd6b362 --- /dev/null +++ b/crates/terraphim_agent/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +All notable changes to terraphim_agent are documented here. + +## [1.20.4] - 2026-06-13 + +### Fixed +- Hermetic integration tests now bootstrap `Terraphim Engineer` via `role_config` in + test settings instead of a missing `terraphim_server/` path from the polyrepo split. + +### Added +- Crate-specific `README.md` with install instructions, feature flags, and quick start. \ No newline at end of file diff --git a/crates/terraphim_agent/Cargo.toml b/crates/terraphim_agent/Cargo.toml index e856ff2..f7bec7f 100644 --- a/crates/terraphim_agent/Cargo.toml +++ b/crates/terraphim_agent/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://terraphim.ai" repository = "https://github.com/terraphim/terraphim-ai" keywords = ["cli", "ai", "agent", "search", "repl"] license = "Apache-2.0" -readme = "../../README.md" +readme = "README.md" [features] default = ["repl-interactive", "llm", "repl-sessions"] diff --git a/crates/terraphim_agent/README.md b/crates/terraphim_agent/README.md new file mode 100644 index 0000000..a50fc46 --- /dev/null +++ b/crates/terraphim_agent/README.md @@ -0,0 +1,140 @@ +# terraphim_agent + +Terraphim AI Agent CLI — semantic search, knowledge-graph exploration, and an interactive REPL for AI coding workflows. + +## Overview + +`terraphim_agent` is the primary command-line interface for Terraphim. It combines offline-capable local search with optional server-backed fullscreen TUI mode, knowledge-graph validation, hook integration for AI coding assistants, and operational learning capture. + +Install the binary as `terraphim-agent`. + +## Features + +- **Semantic search** across configured haystacks with KG-aware ranking +- **Interactive REPL** with markdown-defined commands and autocomplete +- **Knowledge graph tools** — validate, replace, extract, and visualize concepts +- **Session search** — import and query AI coding assistant session history +- **Operational learning** — capture corrections, query learnings, replay procedures +- **Safety guards** — block destructive git/filesystem commands before execution +- **Robot mode** — structured JSON output for automation and agent orchestration + +## Installation + +### From crates.io + +```bash +cargo install terraphim_agent +``` + +### From source + +```bash +git clone https://git.terraphim.cloud/terraphim/terraphim-clients.git +cd terraphim-clients +cargo build -p terraphim_agent --release --bin terraphim-agent +``` + +The release binary is at `target/release/terraphim-agent`. + +### Feature Flags + +| Feature | Default | Description | +|---------|---------|-------------| +| `repl-interactive` | Yes | Interactive REPL with rustyline | +| `llm` | Yes | Ollama and LLM router integration | +| `repl-sessions` | Yes | Session import and search | +| `server` | No | HTTP client for server-backed TUI | +| `repl-full` | No | All REPL sub-features (chat, MCP, web, file) | +| `shared-learning` | No | Cross-agent learning store and wiki sync | +| `enrichment` | No | Concept enrichment for session search | + +Build with extra features: + +```bash +cargo build -p terraphim_agent --release --features repl-full,server +``` + +## Quick Start + +```bash +# Show available commands +terraphim-agent --help + +# Semantic search (offline) +terraphim-agent search "async error handling" + +# List and select roles +terraphim-agent roles list +terraphim-agent roles select "Terraphim Engineer" + +# Validate text against the knowledge graph +terraphim-agent validate --connectivity "haystack service uses automata" + +# Start the REPL +terraphim-agent repl + +# First-time setup wizard +terraphim-agent setup +``` + +### Server-backed TUI + +When a Terraphim server is running: + +```bash +terraphim-agent --server --server-url http://127.0.0.1:8000 interactive +``` + +### Robot / automation output + +```bash +terraphim-agent search "retry policy" --robot --format json +``` + +## Configuration + +On first run, the agent reads `settings.toml` from the platform config directory +(`~/.config/terraphim/` on Linux). Point `role_config` at a JSON role definition +to bootstrap roles and haystacks: + +```toml +role_config = "/path/to/terraphim_engineer_config.json" +default_data_path = "~/.local/share/terraphim" +``` + +Use `terraphim-agent config show` to inspect the active configuration and +`terraphim-agent config validate` to check role definitions. + +## Key Commands + +| Command | Purpose | +|---------|---------| +| `search` | Semantic document search | +| `graph` | ASCII knowledge-graph visualization | +| `validate` | KG connectivity and checklist validation | +| `replace` | Thesaurus-based text replacement | +| `hook` | Pre/post-tool-use hook handler for AI assistants | +| `guard` | Safety pattern check for shell commands | +| `learn` | Operational learning capture and query | +| `sessions` | Import and search AI coding sessions | + +## Testing + +```bash +# Unit tests +cargo test -p terraphim_agent --lib + +# Integration tests (hermetic, no server required) +cargo test -p terraphim_agent --test offline_mode_tests +cargo test -p terraphim_agent --test exit_codes +``` + +## Related Crates + +- [`terraphim-cli`](https://crates.io/crates/terraphim-cli) — lightweight CLI for scripted search +- [`terraphim_grep`](https://crates.io/crates/terraphim_grep) — hybrid grep with KG boost and LLM fallback +- [`terraphim_mcp_server`](https://crates.io/crates/terraphim_mcp_server) — MCP tools for editor integration + +## License + +Apache-2.0 \ No newline at end of file diff --git a/crates/terraphim_agent/tests/exit_codes.rs b/crates/terraphim_agent/tests/exit_codes.rs index 15b1cf5..a5478b9 100644 --- a/crates/terraphim_agent/tests/exit_codes.rs +++ b/crates/terraphim_agent/tests/exit_codes.rs @@ -71,14 +71,17 @@ fn search_succeeds_exits_0() { #[test] fn validate_with_no_kg_exits_3() { - // Load a fixture config where the role has kg: null so the service layer - // returns "Knowledge graph not configured", which classify_error maps to - // ErrorIndexMissing (3). This avoids relying on the developer's local KG. - let fixture = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/no_kg_config.json"); + // Embed the fixture content at compile time so this test works even when + // compiled from a git worktree that is later deleted (shared target dir). + // Writing to a temp file avoids a runtime path dependency on CARGO_MANIFEST_DIR. + let fixture_content = include_str!("no_kg_config.json"); + let dir = tempfile::tempdir().expect("temp dir"); + let fixture_path = dir.path().join("no_kg_config.json"); + std::fs::write(&fixture_path, fixture_content).expect("write fixture"); cmd() .args([ "--config", - fixture, + fixture_path.to_str().expect("valid path"), "validate", "xyzzy_f1_2_exit_code_test_sentinel", ]) diff --git a/crates/terraphim_agent/tests/fixtures/terraphim_engineer_config.json b/crates/terraphim_agent/tests/fixtures/terraphim_engineer_config.json new file mode 100644 index 0000000..9ae1bb9 --- /dev/null +++ b/crates/terraphim_agent/tests/fixtures/terraphim_engineer_config.json @@ -0,0 +1,58 @@ +{ + "id": "Server", + "global_shortcut": "Ctrl+Shift+T", + "roles": { + "Terraphim Engineer": { + "shortname": "TerraEng", + "name": "Terraphim Engineer", + "relevance_function": "terraphim-graph", + "terraphim_it": true, + "theme": "lumen", + "kg": { + "automata_path": null, + "knowledge_graph_local": { + "input_type": "markdown", + "path": "crates/terraphim_agent/tests/test_kg" + }, + "public": true, + "publish": true + }, + "haystacks": [ + { + "location": "crates/terraphim_agent/docs/src/kg", + "service": "Ripgrep", + "read_only": true, + "atomic_server_secret": null, + "extra_parameters": {} + } + ], + "llm_provider": null, + "llm_auto_summarize": false, + "llm_system_prompt": "You are a Terraphim Engineer assistant.", + "extra": {} + }, + "Default": { + "shortname": "Default", + "name": "Default", + "relevance_function": "title-scorer", + "terraphim_it": false, + "theme": "spacelab", + "kg": null, + "haystacks": [ + { + "location": "crates/terraphim_agent/docs/src/kg", + "service": "Ripgrep", + "read_only": true, + "atomic_server_secret": null, + "extra_parameters": {} + } + ], + "llm_provider": null, + "llm_auto_summarize": false, + "llm_system_prompt": "You are a helpful assistant.", + "extra": {} + } + }, + "default_role": "Terraphim Engineer", + "selected_role": "Terraphim Engineer" +} \ No newline at end of file diff --git a/crates/terraphim_agent/tests/support/cli_test_env.rs b/crates/terraphim_agent/tests/support/cli_test_env.rs index 07a4670..742400b 100644 --- a/crates/terraphim_agent/tests/support/cli_test_env.rs +++ b/crates/terraphim_agent/tests/support/cli_test_env.rs @@ -49,13 +49,14 @@ fn create_unique_test_root() -> Result { pub fn apply_hermetic_env(cmd: &mut Command) -> Result<()> { let root = create_unique_test_root()?; let home_dir = root.join("home"); - let xdg_config_home = root.join("xdg-config"); + let xdg_config_home = home_dir.join(".config"); + let terraphim_config_dir = xdg_config_home.join("terraphim"); let data_dir = root.join("data"); let dashmap_dir = root.join("dashmap"); let sqlite_dir = root.join("sqlite"); fs::create_dir_all(&home_dir)?; - fs::create_dir_all(&xdg_config_home)?; + fs::create_dir_all(&terraphim_config_dir)?; fs::create_dir_all(&data_dir)?; fs::create_dir_all(&dashmap_dir)?; fs::create_dir_all(&sqlite_dir)?; @@ -75,12 +76,16 @@ pub fn apply_hermetic_env(cmd: &mut Command) -> Result<()> { // Write to all three under the hermetic HOME so whichever runs first // finds our settings. let sqlite_db = sqlite_dir.join("terraphim.db"); + let role_config = workspace_root()? + .join("crates/terraphim_agent/tests/fixtures/terraphim_engineer_config.json"); + let settings_toml = format!( r#" server_hostname = "127.0.0.1:8000" api_endpoint = "http://localhost:8000/api" initialized = "false" default_data_path = "{data}" +role_config = "{role_config}" [profiles.dashmap] type = "dashmap" @@ -96,9 +101,10 @@ table = "terraphim_kv" dashmap = dashmap_dir.display(), sqlite = sqlite_dir.display(), db = sqlite_db.display(), + role_config = role_config.display(), ); let settings_dirs = [ - home_dir.join(".config").join("terraphim"), + terraphim_config_dir.clone(), home_dir .join("Library") .join("Application Support") @@ -110,13 +116,12 @@ table = "terraphim_kv" } let workspace = workspace_root()?; - let role_config = workspace.join("terraphim_server/default/terraphim_engineer_config.json"); cmd.current_dir(&workspace) .env("HOME", &home_dir) .env("XDG_CONFIG_HOME", &xdg_config_home) - .env("TERRAPHIM_DEFAULT_DATA_PATH", &data_dir) - .env("TERRAPHIM_ROLE_CONFIG", &role_config); + .env("TERRAPHIM_SETTINGS_PATH", &terraphim_config_dir) + .env("TERRAPHIM_DEFAULT_DATA_PATH", &data_dir); Ok(()) }