ReAgent is a small Go framework for building local agent runtimes. It gives you the protocol types, runtime loop, model and tool ports, state stores, and built-in local tools needed to assemble a CLI or TUI agent without committing the core to one provider or interface.
The first intended use case is a local coding agent: a program that can keep session state, stream model output, call workspace-bounded tools, and emit events that a terminal UI, logger, or replay system can consume.
ReAgent is still early. The public shape is useful for experiments and internal tools, but the module currently uses the local import path reagent; if you consume it from another module, use a local replace directive until the module is published under a stable path.
- Provider-neutral message, content, tool-call, tool-result, event, record, and error types.
- A runtime that loads state, builds model context, streams model output, executes tool calls, appends records, and emits ordered events.
- A streaming model port, plus an OpenAI-compatible Chat Completions adapter.
- A tool port with JSON Schema-backed validation and immutable static registration.
- Built-in
read,write,edit, andbashtools scoped to a workspace root. - In-memory state for tests and local experiments.
- JSONL-backed durable state with append-only records and snapshots.
- Policy hooks for allowing, denying, or marking tool calls as requiring approval.
- A minimal example CLI that wires the runtime, OpenAI adapter, built-in tools, durable state, and terminal event output.
Use ReAgent when you want to build an agent application and keep these pieces separate:
- model provider integration,
- tool registration and execution,
- policy decisions,
- state persistence,
- context construction,
- UI or logging event handling.
Do not use ReAgent if you need a complete hosted agent product, browser automation runtime, multi-agent planner, vector memory system, MCP stack, or prebuilt TUI. Those are intentionally outside the current core.
Inside this repository, import packages with the current module path:
import "reagent/runtime"From another local module, point Go at this checkout:
require reagent v0.0.0
replace reagent => ../ReAgentAfter ReAgent is published under a stable module path, replace these imports with the published path.
This example uses the deterministic fake model, so it does not call an external provider.
package main
import (
stdctx "context"
"fmt"
"reagent/agent"
contextport "reagent/context"
"reagent/model"
"reagent/model/fake"
runtimeport "reagent/runtime"
"reagent/state/memory"
)
func main() {
modelPort := fake.New(fake.Turn{Events: []model.Event{
{Type: model.EventMessageDelta, DeltaText: "Hello from ReAgent."},
{Type: model.EventMessageEnd},
}})
rt := runtimeport.Runtime{
Model: modelPort,
State: memory.NewStore(),
Context: contextport.NewMessageHistory(),
}
err := rt.Run(stdctx.Background(), runtimeport.RunRequest{
SessionID: "demo",
Input: []agent.Message{{
Role: agent.RoleUser,
Content: []agent.ContentBlock{{
Type: agent.ContentText,
Text: "Say hello.",
}},
}},
}, func(ctx stdctx.Context, event agent.Event) error {
if event.Type == agent.EventMessageDelta {
fmt.Print(event.DeltaText)
}
return nil
})
if err != nil {
panic(err)
}
}A real runtime replaces the fake model with a provider adapter, adds a tool registry, and usually persists state with the JSONL store.
The runtime owns one agent turn. It loads the session snapshot, appends the new user input, builds model context, streams assistant output, executes requested tools, appends tool results, and either continues or completes the run.
The runtime requires three ports:
- a model port,
- a state store,
- a context manager.
Tools and policy are optional. If tools are present, assistant tool calls are validated, checked by policy, executed, recorded, and fed back to the model.
A model port streams provider-neutral model events. Adapters translate provider APIs into ReAgent message deltas, tool-call deltas, final messages, usage events, and structured errors.
The included OpenAI-compatible adapter targets streaming Chat Completions. It supports text and JSON content blocks. File and image content blocks are part of the protocol, but the current Chat Completions adapter rejects them because it does not translate them yet.
A tool advertises a ToolSpec and executes a ToolCall. Tool parameters are JSON Schema objects. The runtime validates arguments before execution.
Built-in tools are local-agent focused:
readreads files inside the workspace and can slice by line range.writeatomically creates or overwrites UTF-8 text files.editatomically applies exact replacements, insertions, or unified-patch-style edits.bashruns bounded shell commands inside the workspace.
Filesystem and shell tools enforce workspace containment. Write and edit operations support hash guards for stale-write protection.
ReAgent stores append-only records, not only chat messages. A session can contain model-facing messages, emitted events, and custom application records such as approval decisions, checkpoints, or UI state changes.
The default context manager exposes only persisted message records to the model. Event and custom records remain available for diagnostics, replay, and application-specific context managers.
Every run can emit ordered events for UIs, logs, persistence, or replay. Important event types include run start/end, turn start/end, message start/delta/end, tool start/update/end, usage, state saved, and error.
Emitter errors are significant: if the caller depends on ordered delivery or persistence, returning an error from the emitter stops the run.
Policy is a synchronous decision point. A policy can allow, deny, or request approval for a tool call. The current runtime treats ask as a model-visible denial unless the application supplies its own approval flow around the policy decision.
The repository includes an example CLI agent that wires together:
- the OpenAI-compatible model adapter,
- durable JSONL state,
- message-history context,
- built-in filesystem and bash tools,
- an allow-all policy,
- terminal event output.
Run it from a configured checkout:
go run ./cmd/example-agent \
-prompt "Read go.mod and summarize this module." \
-model "$OPENAI_MODEL" \
-workspace . \
-state .reagent-state \
-session defaultSet OPENAI_API_KEY for providers that require bearer-token authentication. Set OPENAI_BASE_URL when using an OpenAI-compatible gateway or local server with a different API root.
- Usage Guide explains how to assemble a runtime, register tools, use durable state, connect the OpenAI adapter, write custom tools, and handle events.
spec.mdcaptures the broader design intent and deferred work. Treat this README and the usage guide as the current user-facing docs.
- The module path is not yet a published import path.
- The OpenAI adapter currently targets Chat Completions streaming, not the Responses API.
- The built-in
readtool refuses directory listings. - Policy approval is a synchronous hook; a full interactive approval workflow belongs in the host application.
- There is no bundled planner, MCP integration, browser runtime, vector memory, multi-agent orchestration, or opinionated TUI.
Run the test suite with:
go test ./...