{"id":"2dce23fe-7aaf-4360-b3db-05de1a0371b5","slug":"agentware","kind":"mcp","name":"agentware","summary":"A C++20 AI coding agent for the terminal. Talks to hosted and local models, reads and edits code through MCP filesystem and git servers, and works offline.","owner":"coccinella-labs","repoUrl":"https://github.com/coccinella-labs/agentware","license":"Apache-2.0","licenseTier":"permissive","trust":"community","stars":0,"match":null,"fewStars":true,"format":"mcp","createdAt":"2025-06-23T22:46:58.000Z","addedAt":"2026-10-21T07:58:53.545Z","logoUrl":"https://avatars.githubusercontent.com/u/283287531?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["developer-tools","files-documents"],"tags":["ai","coding-agent","cpp","ollama"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-22T15:56:03.808Z","sample":false,"url":"https://conduits.dev/tools/agentware","language":"C++","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/coccinella-labs/agentware/main/.github/assets/thumbnail.png\" alt=\"agentware\" width=\"100%\">\n</p>\n\n# agentware\n\nA C++20 AI coding agent that runs in your terminal. It talks to hosted model\nproviders, reads and edits files through its own commands, runs an autonomous\ntool-call loop, and works offline against local models.\n\n```bash\ncmake -S . -B build -DCMAKE_BUILD_TYPE=Release\ncmake --build build\n./build/bin/agentware-agent\n```\n\nOn first run it prints a welcome screen and asks for a mode: online against a hosted provider, or offline against a local model.\n\n## Providers\n\nNine agent modes, one per provider or model family: Together, Llama 3B,\nCerebras, Llama Latest, Llama 3.1, Fireworks, Groq, DeepSeek, and OpenAI.\nEach hosted mode needs its API key in the environment; see `.env.example` for\nthe list. The three Llama modes and Offline run against a local Ollama server\nand need no key.\n\nAn experimental adapter can route local Ollama requests through xoi. Enabling\nit fetches a public, pinned xoi commit during CMake configuration:\n\n```bash\ncmake -S . -B build -DAGENTWARE_USE_XOI_OLLAMA=ON\n```\n\nThe option is off by default, so normal builds do not fetch xoi and hosted\nproviders are unchanged. The adapter uses xoi commit\n`d04fde073f43d30bdb32813eedb930611658e069`. Agentware continues to own its\nprompt, text-based tool loop, permissions, and safety checks. The adapter\npreserves the existing request timeout, disables xoi retries so Agentware owns\nthe loop retry budget, bypasses proxies for local Ollama, and leaves\n`num_predict` to Ollama as before. xoi rejects responses larger than 8 MiB.\nNative provider tool-call requests and other providers are not part of this\nspike. This is an experimental first-provider integration, not a\nproduction-readiness claim.\n\n## What it does\n\nAround twenty services behind one binary: agent orchestration, AI provider calls, auth, checkpoints, codebase search, command execution, configuration, context tracking, a database layer, file and multi-file operations, git and GitHub integration, an MCP client module, memory management, sandboxing, theming, input validation, and a web service.\n\nA central tool registry classifies every tool by capability (read-only or\nmutating), model-surface availability, and interactive consent requirements,\nproviding case-insensitive prefix resolution and canonical tool-call parsing.\n\nCodebase search shells out to `rg` and `fd` when they are on `PATH` and falls\nback to a built-in scanner when they are not, so search works either way.\n`github:threads:owner/repo:pr` reads inline review threads without the GraphQL\nAPI.\n\nModel Context Protocol server entries are configured in\n`data/mcp_servers.json`, and two are pre-populated by default: a filesystem\nserver and a git server, both declared as `npx` commands. The MCP transport is\nnot implemented, so no server process is started and no MCP tool is called;\nthe `/mcp` commands report their own configuration and say so.\n\n## Model-driven tool loop (autonomous mode)\n\nSet `AGENTWARE_TOOL_CALL_LOOP=1` to allow the model to autonomously invoke\ntools across multiple turns. By default the loop is off (`0`), where the\nagent operates as a direct conversational assistant executing user-typed\ncommands.\n\nWhen enabled, assistant responses are parsed for JSON tool calls (e.g.\n`{\"tool\": \"read\", \"arguments\": {\"filename\": \"src/main.cpp\"}}`). The runtime\nvalidates each call through an execution gate before running it, captures the\noutput, and feeds truncated observations back to the model until it outputs a\nfinal text answer or reaches turn bounds.\n\nStrict safety invariants are enforced on the model surface:\n\n- **Read-only execution:** Mutating tools (`cmd:`, `write:`, `replace:`,\n  `remember:`, `clear`, `forget`) are strictly refused on the model surface.\n- **Model-disabled tools:** Heavy tools (`todos:`, `analyze:`, `git:diff`) are\n  refused on the model surface.\n- **CWD containment:** Paths that escape the current working directory via\n  parent traversal (`..`), absolute paths, or external symlinks are refused.\n- **Secrets filtering:** Sensitive paths (`.env`, `.ssh`, tokens, secret keys)\n  are blocked from reads and filtered out of search results.\n- **Consent gates:** Outbound network tools (`fetch:`, `github:`) require\n  interactive TTY confirmation and fail with `consent denied: no TTY` in\n  unattended or non-interactive environments.\n\n| Variable | Default | Description |\n|---|---|---|\n| `AGENTWARE_TOOL_CALL_LOOP` | `0` | Set to `1` or `true` to enable the autonomous tool loop |\n| `AGENTWARE_TOOL_TURN_CAP` | `8` | Maximum autonomous turns before returning control to the user |\n| `AGENTWARE_TOOL_TIMEOUT_SEC` | `30` | Per-tool execution timeout in seconds |\n| `AGENTWARE_NET_TIMEOUT_SEC` | `10` | Network timeout for model requests during tool loop turns (30s elsewhere) |\n\n## Modal line editing (optional)\n\nSet `AGENTWARE_VIM_MODE=1` to edit the REPL prompt with Vim-style keys\ninstead of plain `std::getline`. The default is off, so nothing changes until\nyou opt in. Piped and redirected stdin always uses plain line input, so\nscripts and CI are unaffected even with the variable set.\n\nInsert mode is the usual one: characters insert, Backspace deletes. These\nkeys work in **normal** mode, reached with `i`:\n\n| Key | Action |\n|---|---|\n| `i` | back to insert mode |\n| `h` | cursor left |\n| `l` | cursor right |\n| `0` | cursor to start of line |\n| `$` | cursor to end of line |\n| `x` | delete the character under the cursor |\n\nEnter submits through the existing REPL flow. Anything else in normal mode is\na silent no-op rather than an error.\n\nTwo limits worth knowing before you enable it:\n\n- **Arrow keys, function keys, Home and End do nothing.** Escape sequences\n  are consumed and ignored in this version, so there is no `j`/`k` movement\n  and no history navigation.\n- **Windows key identity is unverified.** The console mapping handles the\n  unmapped keys that arrows and function keys produce, but nothing\n  distinguishes one special key from another on that platform.\n\n## Scope\n\n`src/` holds the implementation, public headers under `src/include/`, tests under `src/tests/`, and automation under `src/scripts/`. `CMakeLists.txt` and `Makefile` both build the same targets; `make` wraps the CMake invocation.\n\n## Releases\n\nMerging to `main` bumps the version, tags it, and creates a GitHub release\nautomatically. Binaries are attached by a separate build workflow that runs on\nthe tag push.\n\nThat separation has one requirement worth knowing: tags and releases created\nwith `GITHUB_TOKEN` do not trigger new workflow runs, so the build never sees\nthem and the release stays empty. The version-bump job therefore prefers a\n`RELEASE_TOKEN` secret (a personal access token with contents write access)\nand falls back to `GITHUB_TOKEN` with a warning. Without that secret, every\nautomated release ships with no binaries, which is what happened to the\nreleases that prompted this note.\n\nTo backfill a release, run the Release workflow by hand against its tag from\nthe Actions tab.\n\n## Tests\n\n```bash\ncmake --build build --target test\n```\n\n`ctest` runs these targets:\n\n- **`basic_tests`**: Google Test suite with 130 cases across 42 suites. Covers\n  command dispatch and redaction, file-access policy, project-root discovery,\n  MCP and GitHub availability, review threads, sandbox construction, bounded\n  execution, safety denylists, memory persistence, input validation, search\n  backends, the central tool registry and snapshot verification, tool execution\n  gating, and process timeout utilities.\n- **`remediation_probes`**: A POSIX shell harness driving the built binary\n  against known-bad input and asserting refusal. It is POSIX-only and is not\n  run on the Windows CI job.\n- **`routing_golden`**: A 35-case shell harness pinning command dispatch and\n  routing contracts through the built binary in a hermetic workspace with zero\n  outbound requests.\n- **`tool_loop_golden`**: A 131-case shell harness exercising the model-driven\n  tool-call loop against a hermetic mock provider (`mock_tool_provider.py`).\n  Verifies JSON parsing, turn caps, mutating tool refusals, model-disabled\n  commands, path containment, secrets protection, variant sweeps, and consent\n  denials.\n- **`provider_readiness`**: The wait the suite above uses to decide that a mock\n  provider is up. Pins prompt readiness, that the server does not resolve its\n  own bind address, that a bind error is still a bind error, and that a\n  provider which genuinely fails to start fails fast with a reason instead of\n  spending a deadline in silence.\n\n### Sandbox Tests\n\nSeven sandbox test areas exercise Docker-isolated command execution:\n\n| Test Suite | Description |\n| --- | --- |\n| `SandboxCommandTest` | Shell argument parsing and hostile value handling |\n| `SandboxSpawnTest` | Process spawn, exit codes, missing binary handling |\n| `SandboxBoundedTest` | Timeout enforcement, hang detection, bounded execution |\n| `SandboxSafetyTest` | Denylist filtering (`.` substring), dangerous command blocking |\n| `SandboxConfigTest` | Config validation: sane configs accepted, hostile rejected |\n| `SandboxResultTest` | Result formatting: success, empty, failure, timeout |\n| `SandboxDockerTest` | End-to-end fake-docker routing: success, daemon failure, hang timeout |\n\nCI additionally runs a build matrix (Ubuntu, macOS, Windows), coverage, linting,\nDocker end-to-end, and release jobs. The `e2e` job needs Docker; the `coverage`\njob needs its toolchain installed.\n\n## Contributing\n\n`CONTRIBUTING.md` is the authority, not this file. External contributions are not accepted at this time; the project is maintained by collaborators. If that changes, the contributing guide will say so first.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n"}