drover
A declarative, strongly-typed, Effect-native agent harness library for TypeScript.
drover is a declarative, strongly-typed, Effect-native agent harness library
for TypeScript. Define agents as JSON-serialisable specs. The API surface is
Effect-first, with a Promise/AsyncIterable facade as a fallback for
non-Effect consumers.
Features
- Declarative agent specs —
defineAgent({...})returns a JSON-serialisable, TypeBox-typedAgentSpec; dynamic agents use the same shape. - Effect-first API — internals and public surface speak
Effect;Promise/AsyncIterablefacade kept as a fallback. - Schemaed agent loop — typed input/output, output retry budget on schema-decode failures.
- Streaming events — normalised
HarnessEventstream as anAsyncIterable. - Plugin hooks —
HarnessPluginbundles:beforeToolCall/afterToolCall/wrapTool/onEvent/onError/onRunStart/onRunEnd. - Built-in plugins — loop-detect, step-tracer, bash-blocklist, circuit-breaker, write-policy, phase-recorder, confirm-gate, output-validate.
- Built-in tools — bash, read, write, edit, grep, …
- Subagents —
taskToolfactory; depth ≤ 2, fan-out ≤ 3 caps; child lifecycle events on the parent stream. - Skills —
SKILL.mdloader +skill_loadtool, progressive disclosure. - Commands & lifecycle — markdown prompt macros (host-pushed) run as deterministic
init/postSuccesssteps around the loop. - Instruction files —
AGENTS.md/CLAUDE.mdloaders. - MCP — stdio + HTTP transports, tool-name prefixing, per-agent allowlist.
- Model layer — pi-ai wrapper, alias resolver, routing interface, circuit breaker.
- Pause / resume — durable checkpoints; resume validates run id / status / agent id / spec hash before replay.
- Storage — libsql default +
StorageAdapter; in-memory adapter for tests. - Sandbox —
SandboxAdapterinterface; just-bash virtual sandbox by default (isolated, docker-style mounts,bash-safe), plus in-processnone. - Runtime (opt-in) — worker pool, lease queue,
RunApi, crash recovery. - Evals —
ScenarioRunner,Scorer,Reporter, plus the eval-viewer app.
drover is a small library that hosts LLM agents. You give it an agent spec (prompt, schemas, tools, model), and it runs the loop: validate input, call the model, dispatch tools, decode the output against your schema, retry on schema failures, persist everything if you wire storage, pause / resume durably if you ask it to.
What it ships
Schemaed input + output, pi-agent-core driving the model, output retry budget for schema failures.
beforeToolCall / afterToolCall / onEvent / wrapTool bundles. Ship
your safety + observability as plugins.
taskTool factory. Parent agent spawns scoped children with depth and
fan-out caps. Lifecycle events surface on the parent stream.
Runs / events / checkpoints in libsql. Memory adapter for tests; libsql for durability. Pluggable interface — bring your own.
handle.pause() checkpoints + suspends. resumeAgent continues from
the saved messages via pi’s runAgentLoopContinue.
SKILL.md allowlists, progressive disclosure. MCP stdio + HTTP via
@modelcontextprotocol/sdk, tool-name prefixing, per-agent allowlist.
Worker pool + lease queue + crash recovery. Programmatic RunApi. Point
multiple processes at the same libsql queue for horizontal scaling.
Normalised HarnessEvent stream. Step tracer plugin projects it into a
flat list. Eval-viewer renders the timeline.
Design principles
- Effect-first, Promise/AsyncIterable facade as fallback. The public
surface speaks
Effect<RunResult, HarnessError, R>. The facade gives non-Effect consumers a Promise that never rejects and anAsyncIterable<HarnessEvent>— adopt without rewriting. - Capability flags over docstrings. Sandbox capabilities are typed.
Want
bash? PassallowShell: true. Documenting an escape in prose is not a safety boundary. - Resume validates everything before replaying. Run id, status, agent
id, spec hash. Drift =
ResumeError, not a silent replay under a changed policy. - Plugins ship only what’s wired.
ToolDecisionisallow | denyfor v0.rewriteandrequire_confirmcome back when storage-backed confirmation lands.
Where it sits
drover wraps @mariozechner/pi-agent-core
for the model loop, adds TypeBox-schemaed agent specs + tools, and layers
storage / pause-resume / plugin / MCP / skills primitives on top. Effect
provides the error channel and composition.