hal9000 a64cc3075f issue 190: Add Windows signal handling support
Add platform-specific signal handling to enable Ctrl+C cancellation on Windows.
- Windows uses SetConsoleCtrlHandler with CTRL_C_EVENT
- Unix continues to use signal() with SIGINT
- Unified setup_signal_handler() function for both platforms
2026-08-05 23:33:48 +00:00
2026-05-05 09:22:41 -05:00
2026-08-05 18:25:53 -05:00
2026-05-08 14:38:49 -05:00
2026-05-06 13:04:30 -05:00
2026-06-06 09:53:43 -05:00

drharness

A C++23 LLM (Open AI Compatible) harness designed for agentic workflows, file manipulation, and task delegation. It implements a tool-use loop that allows a large language model to dynamically invoke shell commands, edit files, and delegate sub-tasks to other specialized agents. (I wouldn't use the agents feature yet as it is kind of half baked, and I'm not sure when I'll loop back to it)

🏗️ Architectural Overview

drharness is built as a modular C++ application consisting of several key components:

  • Harness: The core orchestrator. It manages the conversation history (stored as a JSON array), the active tool registry, and the main execution loop. It repeatedly pushes messages to the LLM, parses tool calls, executes them locally, and appends the results back into the history until the model indicates a final response.
  • ToolRegistry: A dynamic system for managing available tools. The LLM receives the list of available tools in JSON format and can invoke them dynamically. The registry includes a base set of tools (file reading, editing, grepping, shell execution) and supports nested agent delegation.
  • Agent Profiles: Configurable definitions for specialized sub-agents (e.g., shell_expert). These allow the main agent to offload complex multi-step tasks to a dedicated model/agent instance.
  • Client Layer:
    • OllamaClient: Handles the actual communication with an Ollama-compatible API server via HTTP (using libcurl).
    • DebugClient: A CLI-friendly mock client that reads a mock JSON response from stdin, allowing for deterministic testing of harness logic without relying on an external LLM.
  • State Management: Conversations are serialized to and deserialized from JSON files. This includes the full message history (history), the active tool registry (tools), and harness configuration (config).

🛠️ How to Build

The project requires CMake version 3.16 or newer, C++23 support, curl, and the nlohmann_json library.

# Configure the build
cmake -B build -DCMAKE_BUILD_TYPE=Release .

# Build the binary
cmake --build build

🧪 How to Run Tests

To run tests first you have to build the project. Then you can run ctest:

cd build
ctest

And it will run the entire test suite

💬 Starting & Continuing Conversations

The harness state is persisted in a JSON file specified by the -F flag.

Starting a New Conversation

To start fresh, use the -n flag. If you don't specify a chat file with -F, the harness will automatically generate a unique, ephemeral JSON file in your system's temporary directory. If you do specify a file with -F, it must be new or empty. The harness will refuse to start a new conversation if the specified file already contains data.

Auto-generated temp file

./build/drharness -n -m "Let's start a new project."

Using a specific file

./build/drharness -F conversation.json -n -m "Let's start a new project."

Continuing an Old Conversation

To continue a previous session, simply invoke the harness with the same -F file. It will automatically deserialize the saved history, tool registry, and configuration.

./build/drharness -F conversation.json -m "Can you now refactor the main loop?"

Other Useful Flags

  • -l: List all available tools.
  • -p <file>: Pretty-print a conversation JSON file without running the harness.
  • -t <tool>: Manually constrain the harness to a specific subset of tools (by default no tools are provided to the model)
  • -s <name>: Manually constrain the harness to a specific subset of skills (can be specified multiple times)
  • -i <path>: Image file to attach to the prompt (can be specified multiple times)
  • -m <prompt>: The user prompt to send to the agent.
  • -P <file>: Read the prompt from a file instead of the command line.
  • -M <model>: Override the Ollama model (e.g., mistral, llama3).

✍️ Editor Integration

This harness supports an interactive editor mode that allows you to write multi-line prompts or complex instructions using your preferred terminal or GUI editor.

Setup

To enable editor mode, simply set the VISUAL or EDITOR environment variable in your shell before running the harness:

export EDITOR=nvim  # or vscode, nano, vim, emacs, etc.

Usage

  1. When the harness launches the editor, it opens a temporary file in your configured editor.
  2. The file contains the current conversation context (or the last AI response) followed by a separator line: -- >8 --
  3. Type your new prompt below this separator line. You can write as much as you like!
  4. Save the file and exit the editor.
  5. The harness will automatically extract everything you typed after the separator as your prompt and continue the conversation.

Note: If neither VISUAL nor EDITOR is set, the harness will refuse to launch the editor and throw an error instead.

For detailed documentation on history editing, see docs/history-editing.md.

🐳 Docker Isolation

The harness can be compiled and run inside an isolated Alpine Linux container.

1. Build the Docker Image

Use the provided script to build the image. It passes your local Ollama auth token as a build-time argument.

./build_docker.sh

2. Run the Agent

Use the dockerdrh script. This script automatically maps the current working directory to /mnt inside the container and runs the container with the host user's UID/GID to preserve file permissions.

# Start a new conversation inside the container
./dockerdrh -F conversation.json -n -m "Initialize the project"

Note: Inside the container, the working directory is /mnt. Always pass your local JSON file relative to the mapped directory.

S
Description
No description provided
Readme 733 KiB
v0.3 Latest
2026-07-22 09:11:22 -05:00
Languages
Shell 55.6%
C++ 41.7%
CMake 2.5%
Dockerfile 0.2%