avenor

module
v0.28.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: MIT

README

Avenor

Most agent harnesses will only let you call a single layer of sub-agents. That's normally all you need. For large projects, you may want to reach for more advanced orchestration models. (I did.)

Avenor allows any given top-level agent (the one you're chatting with) to kick off an entirely separate process that is no longer bound by the single-level sub-agent restriction. Now your sub-agents can call sub-agents. Let your horses run wild!

The way I have this organized personally is to have a "jockey" agent that is write-restricted, forcing it to spawn "horse" or "mule" sub-agents to do write-oriented work for it. An amusing pattern, and keeps implementing agents from getting confused and doing the wrong thing. Each agent above keeps focusing the prompts so that the implementors don't get distracted and start doing things they aren't supposed to.

Avenor supports eight backends: opencode-acp (default), opencode-http, codex-app-server, agy, gemini-acp, cursor-acp, pi, and claude-channel (experimental). For MCP-compatible clients, avenor mcp is the canonical Go-native MCP server — no Node/Bun required. The Node.js packages (@dougbots/avenor-mcp, @dougbots/avenor-opencode) remain for OpenCode integration. See docs/mcp.md for MCP setup and tool details, or install the MCP server with bundled orchestration instructions via the Claude Code plugin guide or the Codex plugin guide. Get your agent to check the docs to ensure it uses the CLI correctly. (Hilariously, this CLI is intended for your agent to use, not you as a human.)

A template pack in templates/ covers the full dispatch matrix: Claude Code dispatching to OpenCode jockey, Claude Code dispatching to Codex, and Codex dispatching to OpenCode jockey. Each folder has agent prompts, permission boundaries, and dispatch skills ready to adapt to your own setup. For the full CLI reference and common orchestration patterns, start at docs/cli.md.

Installation

curl -fsSL https://avenor.douggo.com/install.sh | sh

Or with Go: go install github.com/sdougbrown/avenor/cmd/avenor@latest

Binaries for all platforms on GitHub Releases.

Development

This repo is Go-first, with a small JS workspace for package integrations. mise is the convenience layer for common local tasks; it wraps the underlying go and bun CLI commands rather than replacing them.

mise run build      # Go binary + JS packages
mise run test       # Go tests + JS package tests

mise run go-build   # Go binary only
mise run go-test    # Go tests only
mise run js-build   # JS packages only
mise run js-test    # JS tests only

The direct equivalents are still ordinary commands such as go build -o avenor ./cmd/avenor, go test ./..., bun run build, and bun run test.

Permission handling

Permission handling matters because a backend can ask for approval mid-run, and Avenor's job is to broker that request without turning the harness into a blocking human-in-the-loop primitive. When your backend forwards tool approval through ACP session/request_permission, point --permission-handler at a file path:

--permission-handler file:<path>

Avenor writes the request there; avenor answer <path> --option <id> writes the response back atomically. See docs/permission-handler.md for the request and response JSON shapes.

Control sockets

Avenor can expose a Unix-domain control socket so another process can inspect status, tail live events, answer permissions, cancel work, and send follow-up prompts while a run is active:

avenor run \
  --control-socket /tmp/avenor.sock \
  --prompt "List the files in this directory and exit." \
  --on-event /tmp/events.ndjson \
  --sentinel-file /tmp/done.env

avenor control --socket /tmp/avenor.sock status
avenor control --socket /tmp/avenor.sock tail
avenor control --socket /tmp/avenor.sock prompt "Continue with the next step"
avenor control --socket /tmp/avenor.sock cancel

For long-lived orchestration, avenor stable starts a supervisor that can spawn and manage multiple child runtimes:

avenor stable --control-socket /tmp/avenor-stable.sock

avenor control --socket /tmp/avenor-stable.sock spawn \
  --prompt "Review PR #42" \
  --dir /repo/A \
  --label review-42

avenor control --socket /tmp/avenor-stable.sock list
avenor control --socket /tmp/avenor-stable.sock prompt "Continue" rt_1
avenor control --socket /tmp/avenor-stable.sock cancel rt_1
avenor control --socket /tmp/avenor-stable.sock shutdown graceful

The socket also speaks newline-delimited JSON-RPC 2.0 directly, and --http-debug can expose loopback-only HTTP/SSE endpoints for debugging. See docs/control-protocol.md and docs/stable.md for the full method list, event stream, ownership rules, and stable supervisor reference.

Phase loops

When a single prompt isn't enough — build once, then test → review → fix until clean — define a loop config and let Avenor run the phases:

avenor run --loop-file loop.json --auto-approve --sentinel-file run.done

Phases emit <|workflow: exit | label|> to finish clean or <|workflow: abort | reason|> to escalate. Pre phases run once. Loop phases repeat until exit, abort, or max_iterations. See docs/loop.md for the full config reference, prompt templates, lifecycle events, and abort mechanics.

Event monitoring

Every run writes a structured NDJSON event log. Tail and classify it while a run is active:

avenor watch --follow --classify /tmp/events.ndjson

Events are typed (agent.message_chunk, tool.call, permission.request, session.end, etc.) and carry enough context to drive automated handling — permission responses, downstream triggers, or log aggregation. See docs/events.md and docs/watch.md.

Name

Avenor is the chief stable officer of a king, a nod to the horse/mule/groom/jockey vocabulary already used in agent orchestration frameworks.

Someone still has to clean out the stables, but at least the naming keeps the chore list from bolting.

Directories

Path Synopsis
cmd
avenor command
internal
admission
Package admission implements a tree-scoped execution-admission controller for stable supervisor trees.
Package admission implements a tree-scoped execution-admission controller for stable supervisor trees.
brokertools
Package brokertools holds small helpers shared by the agent-facing MCP servers (claude-channel sidecar and channeltools) for interacting with the in-process broker.
Package brokertools holds small helpers shared by the agent-facing MCP servers (claude-channel sidecar and channeltools) for interacting with the in-process broker.
channelwrap
Package channelwrap provides helpers for channel-wrapped prompt injection used by non-Claude backends.
Package channelwrap provides helpers for channel-wrapped prompt injection used by non-Claude backends.
cli
Package cli handles command-line argument parsing and event streaming.
Package cli handles command-line argument parsing and event streaming.
configfile
Package configfile reads structured configuration files (Team, Loop, Roster, and future Workflow/Controller definitions) and decodes them into caller-supplied Go values.
Package configfile reads structured configuration files (Team, Loop, Roster, and future Workflow/Controller definitions) and decodes them into caller-supplied Go values.
permission
Package permission handles session/request_permission round-trip.
Package permission handles session/request_permission round-trip.
rosterconfig
Package rosterconfig loads and resolves backend/agent/model roster entries.
Package rosterconfig loads and resolves backend/agent/model roster entries.
runstate
Package runstate normalizes supervisor lifecycle status for consumers.
Package runstate normalizes supervisor lifecycle status for consumers.
runtime/broker
Package broker provides a harness-agnostic run broker for agent communication.
Package broker provides a harness-agnostic run broker for agent communication.
runtime/claude
Package claude implements a channel-less runtime.Provider for Claude Code.
Package claude implements a channel-less runtime.Provider for Claude Code.
runtime/claudechannel
Package claudechannel implements a runtime.Provider for Claude Code via channels + tmux.
Package claudechannel implements a runtime.Provider for Claude Code via channels + tmux.
runtime/claudecore/terminal
Package terminal provides an abstraction for interactive terminal sessions.
Package terminal provides an abstraction for interactive terminal sessions.
runtime/claudeutil
Package claudeutil contains shared Claude Code startup helpers.
Package claudeutil contains shared Claude Code startup helpers.
runtime/factory
Package factory constructs runtime.Provider instances by backend name.
Package factory constructs runtime.Provider instances by backend name.
runtime/opencodehttp
Package opencodehttp implements a runtime.Provider that communicates with opencode serve over its HTTP API (SSE event stream + REST endpoints).
Package opencodehttp implements a runtime.Provider that communicates with opencode serve over its HTTP API (SSE event stream + REST endpoints).
spawnselection
Package spawnselection validates direct and roster spawn selectors.
Package spawnselection validates direct and roster spawn selectors.
thinkingpolicy
Package thinkingpolicy validates the canonical thinking-value contract and the per-backend thinking policy from a portable Umpire schema shared with the TypeScript packages.
Package thinkingpolicy validates the canonical thinking-value contract and the per-backend thinking policy from a portable Umpire schema shared with the TypeScript packages.
workflow
Package workflow owns Avenor's durable workflow state machine.
Package workflow owns Avenor's durable workflow state machine.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL