Skip to content
Conduit

mcp server

agentware

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.

coccinella-labs/agentwarecommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 22, 2026

agentware

A C++20 AI coding agent that runs in your terminal. It talks to hosted model providers, reads and edits files through its own commands, runs an autonomous tool-call loop, and works offline against local models.

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/bin/agentware-agent

On first run it prints a welcome screen and asks for a mode: online against a hosted provider, or offline against a local model.

Providers

Nine agent modes, one per provider or model family: Together, Llama 3B, Cerebras, Llama Latest, Llama 3.1, Fireworks, Groq, DeepSeek, and OpenAI. Each hosted mode needs its API key in the environment; see .env.example for the list. The three Llama modes and Offline run against a local Ollama server and need no key.

An experimental adapter can route local Ollama requests through xoi. Enabling it fetches a public, pinned xoi commit during CMake configuration:

cmake -S . -B build -DAGENTWARE_USE_XOI_OLLAMA=ON

The option is off by default, so normal builds do not fetch xoi and hosted providers are unchanged. The adapter uses xoi commit d04fde073f43d30bdb32813eedb930611658e069. Agentware continues to own its prompt, text-based tool loop, permissions, and safety checks. The adapter preserves the existing request timeout, disables xoi retries so Agentware owns the loop retry budget, bypasses proxies for local Ollama, and leaves num_predict to Ollama as before. xoi rejects responses larger than 8 MiB. Native provider tool-call requests and other providers are not part of this spike. This is an experimental first-provider integration, not a production-readiness claim.

What it does

Around 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.

A central tool registry classifies every tool by capability (read-only or mutating), model-surface availability, and interactive consent requirements, providing case-insensitive prefix resolution and canonical tool-call parsing.

Codebase search shells out to rg and fd when they are on PATH and falls back to a built-in scanner when they are not, so search works either way. github:threads:owner/repo:pr reads inline review threads without the GraphQL API.

Model Context Protocol server entries are configured in data/mcp_servers.json, and two are pre-populated by default: a filesystem server and a git server, both declared as npx commands. The MCP transport is not implemented, so no server process is started and no MCP tool is called; the /mcp commands report their own configuration and say so.

Model-driven tool loop (autonomous mode)

Set AGENTWARE_TOOL_CALL_LOOP=1 to allow the model to autonomously invoke tools across multiple turns. By default the loop is off (0), where the agent operates as a direct conversational assistant executing user-typed commands.

When enabled, assistant responses are parsed for JSON tool calls (e.g. {"tool": "read", "arguments": {"filename": "src/main.cpp"}}). The runtime validates each call through an execution gate before running it, captures the output, and feeds truncated observations back to the model until it outputs a final text answer or reaches turn bounds.

Strict safety invariants are enforced on the model surface:

  • Read-only execution: Mutating tools (cmd:, write:, replace:, remember:, clear, forget) are strictly refused on the model surface.
  • Model-disabled tools: Heavy tools (todos:, analyze:, git:diff) are refused on the model surface.
  • CWD containment: Paths that escape the current working directory via parent traversal (..), absolute paths, or external symlinks are refused.
  • Secrets filtering: Sensitive paths (.env, .ssh, tokens, secret keys) are blocked from reads and filtered out of search results.
  • Consent gates: Outbound network tools (fetch:, github:) require interactive TTY confirmation and fail with consent denied: no TTY in unattended or non-interactive environments.
VariableDefaultDescription
AGENTWARE_TOOL_CALL_LOOP0Set to 1 or true to enable the autonomous tool loop
AGENTWARE_TOOL_TURN_CAP8Maximum autonomous turns before returning control to the user
AGENTWARE_TOOL_TIMEOUT_SEC30Per-tool execution timeout in seconds
AGENTWARE_NET_TIMEOUT_SEC10Network timeout for model requests during tool loop turns (30s elsewhere)

Modal line editing (optional)

Set AGENTWARE_VIM_MODE=1 to edit the REPL prompt with Vim-style keys instead of plain std::getline. The default is off, so nothing changes until you opt in. Piped and redirected stdin always uses plain line input, so scripts and CI are unaffected even with the variable set.

Insert mode is the usual one: characters insert, Backspace deletes. These keys work in normal mode, reached with i:

KeyAction
iback to insert mode
hcursor left
lcursor right
0cursor to start of line
$cursor to end of line
xdelete the character under the cursor

Enter submits through the existing REPL flow. Anything else in normal mode is a silent no-op rather than an error.

Two limits worth knowing before you enable it:

  • Arrow keys, function keys, Home and End do nothing. Escape sequences are consumed and ignored in this version, so there is no j/k movement and no history navigation.
  • Windows key identity is unverified. The console mapping handles the unmapped keys that arrows and function keys produce, but nothing distinguishes one special key from another on that platform.

Scope

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.

Releases

Merging to main bumps the version, tags it, and creates a GitHub release automatically. Binaries are attached by a separate build workflow that runs on the tag push.

That separation has one requirement worth knowing: tags and releases created with GITHUB_TOKEN do not trigger new workflow runs, so the build never sees them and the release stays empty. The version-bump job therefore prefers a RELEASE_TOKEN secret (a personal access token with contents write access) and falls back to GITHUB_TOKEN with a warning. Without that secret, every automated release ships with no binaries, which is what happened to the releases that prompted this note.

To backfill a release, run the Release workflow by hand against its tag from the Actions tab.

Tests

cmake --build build --target test

ctest runs these targets:

  • basic_tests: Google Test suite with 130 cases across 42 suites. Covers command dispatch and redaction, file-access policy, project-root discovery, MCP and GitHub availability, review threads, sandbox construction, bounded execution, safety denylists, memory persistence, input validation, search backends, the central tool registry and snapshot verification, tool execution gating, and process timeout utilities.
  • remediation_probes: A POSIX shell harness driving the built binary against known-bad input and asserting refusal. It is POSIX-only and is not run on the Windows CI job.
  • routing_golden: A 35-case shell harness pinning command dispatch and routing contracts through the built binary in a hermetic workspace with zero outbound requests.
  • tool_loop_golden: A 131-case shell harness exercising the model-driven tool-call loop against a hermetic mock provider (mock_tool_provider.py). Verifies JSON parsing, turn caps, mutating tool refusals, model-disabled commands, path containment, secrets protection, variant sweeps, and consent denials.
  • provider_readiness: The wait the suite above uses to decide that a mock provider is up. Pins prompt readiness, that the server does not resolve its own bind address, that a bind error is still a bind error, and that a provider which genuinely fails to start fails fast with a reason instead of spending a deadline in silence.

Sandbox Tests

Seven sandbox test areas exercise Docker-isolated command execution:

Test SuiteDescription
SandboxCommandTestShell argument parsing and hostile value handling
SandboxSpawnTestProcess spawn, exit codes, missing binary handling
SandboxBoundedTestTimeout enforcement, hang detection, bounded execution
SandboxSafetyTestDenylist filtering (. substring), dangerous command blocking
SandboxConfigTestConfig validation: sane configs accepted, hostile rejected
SandboxResultTestResult formatting: success, empty, failure, timeout
SandboxDockerTestEnd-to-end fake-docker routing: success, daemon failure, hang timeout

CI additionally runs a build matrix (Ubuntu, macOS, Windows), coverage, linting, Docker end-to-end, and release jobs. The e2e job needs Docker; the coverage job needs its toolchain installed.

Contributing

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.

License

MIT. See LICENSE.

↑↓ navigate openesc close