Skip to content

mrazza/coma

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

97 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

COMA: Comptime Agent

An LLM agent architecture written entirely in native Zig.

screenshot

The 'Why'

First and foremost, this project was built as a hands-on way to learn Zig. I wanted a project where I couldn't just slide by on basic syntax but also wasn't so complex it would take forever to get working. Building an LLM agent framework fit the bill. An agent has to deal with nested dynamic JSON, HTTP connections, and complex memory lifetimes—forcing me to jump straight into the deep end of how Zig handles memory and compile-time evaluation.

Sure, writing LLM agent loops is a solved problem and it's completely unnecessary to do this in Zig... but it was fun to figure out and it runs incredibly fast.

Core Features

  • Type-safe Comptime Tool Registration: Register standard Zig functions as agent tools. The compiler checks that your function parameters match the tool's descriptor structure using Zig's compile-time reflection.
  • ACP Server Integration: Built-in JSON-RPC stdio server supporting the Agent Connection Protocol (ACP) for external client/IDE integration (--acp).
  • Context-Aware Tools & State Management: Support for custom user-data contexts (Tool.initWithContext), session state tracking, and dynamic context injections across turns.
  • Built-in Agent Tools: Standardized built-in tools (such as agent.Tool.BuiltIn.Todo for planning and tracking multi-step execution).
  • Incremental Streaming & Response Accumulator: Built-in support for streaming model responses chunk-by-chunk with ANSI terminal markdown formatting.
  • Asynchronous & Concurrent Tool Execution: Built on top of Zig's native non-blocking I/O event loop (std.Io). Tools run concurrently via Io.Select.
  • Async Zero-Dependency HTTP Client: Direct communication with LLM backends asynchronously using Zig's native std.http.Client.
  • Explicit Memory Control: Everything uses Zig's explicit allocator pattern with minimal memory footprint (~5MB overhead).

Tool Registration Example

COMA uses Zig's comptime capabilities to make tool registration type-safe and boilerplate-free:

// Define a standard Zig function
fn getWeather(allocator: std.mem.Allocator, zip_code: i64) ![]const u8 {
    return try std.fmt.allocPrint(allocator, "Weather in {d}: Sunny, 72°F", .{zip_code});
}

// Register it with the Agent
const weather_tool = Tool.init(.{
    .name = "get_weather",
    .description = "Get the current weather for a given zip code.",
    .parameters = &.{
        .{
            .name = "zip_code",
            .type = .integer,
            .required = true,
            .description = "The 5-digit zip code.",
        },
    },
}, getWeather);

You can also attach custom context to tools using Tool.initWithContext or include built-in tools like agent.Tool.BuiltIn.Todo.

Library Usage

To use COMA in your own project, initialize a provider and the agent loop:

var http_client: std.http.Client = .{ .allocator = allocator, .io = io };
var gemini_client = try provider.Gemini.init(allocator, &http_client, api_key);
var client = gemini_client.provider();

const session_config: types.SessionConfig = .{
    .model = selected_model,
    .system_prompt = "You are a helpful assistant.",
    .tools = &[_]Tool{ weather_tool, agent.Tool.BuiltIn.Todo },
};

var session = try Session.init(allocator, io, client, session_config);
defer session.deinit();

const result = try session.executeTurn(.{ .prompt = "What is the weather in 90210?" });

Project Structure

  • src/acp/: Implementation of the Agent Connection Protocol (ACP) JSON-RPC server and session storage.
  • src/agent/: Core agent logic, session state management, tool execution, and built-in tools.
  • src/llm/: Generic LLM provider interfaces and message schemas.
  • src/provider/: Concrete implementations for LLM services (e.g., Google Gemini).
  • src/testing/: Mocks and utilities for testing without network calls.
  • src/MarkdownRendering.zig: Dedicated module for ANSI-formatted streaming markdown output in the terminal.
  • src/main.zig: CLI entry point, supporting interactive chat and ACP server mode.

Setup

COMA is tested and built with Zig 0.16.0.

1. Configure the API Key

Get an API key from Google AI Studio. You can set it in your environment:

export GEMINI_API_KEY="your-api-key"

Or create a .env file in the root of the project:

GEMINI_API_KEY="your-api-key"

2. Run the Interactive Chat

To build and start the CLI agent interface:

zig build run

3. Run as an ACP Server

To run COMA as an ACP server over stdio for external client integrations:

zig build run -- --acp

You can test the ACP server with coma-acp-repl.

4. Run the Test Suite & Coverage

To compile and execute all tests:

zig build test

To generate a test coverage report (requires kcov):

zig build coverage

The Roadmap / Future Plans

  • ACP Server Integration: Build an ACP server into the agent for external client control.
  • Agents.md / SKILLS: Define agent behaviors in Markdown files and load them into context automatically.
  • More Providers: Support for Anthropic, OpenAI, Ollama, etc.
  • Vector DB Client: Persistent long-term memory.

License

Distributed under the Apache License 2.0. See LICENSE for more information.

About

COMA is an LLM agent harness written entirely in Zig.

Topics

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages