@botbotgo/agent-harness
v0.0.53
Published
Workspace runtime for multi-agent applications
Downloads
2,861
Readme
@botbotgo/agent-harness
Product Overview
@botbotgo/agent-harness is a workspace-shaped application runtime for real agent products.
It is not a new agent framework. It is the runtime layer around LangChain v1 and DeepAgents that turns one workspace into one operable application runtime.
The boundary is strict:
- LangChain v1 and DeepAgents own agent execution semantics
agent-harnessowns application-level orchestration and lifecycle management
That means:
- public API stays small
- complex setup and operating policy live in YAML
- application-level orchestration and lifecycle management stays in the harness
- runtime lifecycle stays stable even if backend implementations change
What the runtime provides:
createAgentHarness(...),run(...),subscribe(...), inspection methods, andstop(...)- YAML-defined workspace assembly for routing, models, tools, stores, backends, MCP, recovery, and maintenance
- backend-adapted execution with current LangChain v1 and DeepAgents adapters
- local
resources/tools/andresources/skills/discovery - persisted threads, runs, approvals, events, queue state, and recovery metadata
Quick Start
Install:
npm install @botbotgo/agent-harnessWorkspace layout:
your-workspace/
config/
workspace.yaml
agent-context.md
models.yaml
embedding-models.yaml
vector-stores.yaml
stores.yaml
backends.yaml
tools.yaml
mcp.yaml
agents/
direct.yaml
orchestra.yaml
resources/
package.json
tools/
skills/Minimal usage:
import { createAgentHarness, run, stop } from "@botbotgo/agent-harness";
const runtime = await createAgentHarness("/absolute/path/to/workspace");
try {
const result = await run(runtime, {
agentId: "auto",
input: "Explain what this workspace is for.",
});
console.log(result.output);
} finally {
await stop(runtime);
}Feature List
- Workspace runtime for multi-agent applications
- Small public runtime contract
- YAML-defined host routing and runtime policy
- LangChain v1 and DeepAgents backend adaptation
- Auto-discovered local tools and SKILL packages
- provider-native tools, MCP tools, and workspace-local tool modules
- persisted threads, runs, approvals, lifecycle events, and queued runs
- runtime-managed recovery and checkpoint maintenance
- structured output and multimodal content preservation in run results
- MCP bridge support for agent-declared MCP servers
- MCP server support for exposing harness tools outward
How To Use
Create A Runtime
import { AgentHarnessRuntime, createAgentHarness } from "@botbotgo/agent-harness";
const runtime: AgentHarnessRuntime = await createAgentHarness("/absolute/path/to/workspace");createAgentHarness(...) loads one workspace, resolves resources/, initializes persistence under runRoot, and starts runtime maintenance.
Run A Request
import { run } from "@botbotgo/agent-harness";
const result = await run(runtime, {
agentId: "orchestra",
input: "Summarize the runtime design.",
invocation: {
context: {
requestId: "req-123",
},
inputs: {
visitCount: 1,
},
attachments: {
"/tmp/spec.md": { content: "draft" },
},
},
});run(runtime, { ... }) creates or continues a persisted thread and returns threadId, runId, state, and a simple text output. When upstream returns richer output, the runtime also preserves outputContent, contentBlocks, and structuredResponse without making the basic API larger.
Use invocation as the runtime-facing request envelope:
invocation.contextfor request-scoped execution contextinvocation.inputsfor additional structured runtime inputsinvocation.attachmentsfor attachment-like payloads that the active backend can interpret
Let The Runtime Route
const result = await run(runtime, {
agentId: "auto",
input: "Inspect the repository and explain the release flow.",
});agentId: "auto" evaluates ordered routing.rules, then routing.defaultAgentId, and only falls back to model routing when routing.modelRouting: true.
Stream Output And Events
const result = await run(runtime, {
agentId: "orchestra",
input: "Inspect the workspace and explain the available tools.",
listeners: {
onChunk(chunk) {
process.stdout.write(chunk);
},
onContentBlocks(blocks) {
console.log(blocks);
},
onEvent(event) {
console.log(event.eventType, event.payload);
},
},
});subscribe(...) is a read-only observer surface over stored lifecycle events.
The runtime event stream includes:
run.createdrun.queuedrun.dequeuedrun.state.changedapproval.requestedapproval.resolvedoutput.delta
Inspect Threads And Approvals
import {
getApproval,
getThread,
listApprovals,
listThreads,
} from "@botbotgo/agent-harness";
const threads = await listThreads(runtime);
const thread = await getThread(runtime, threads[0]!.threadId);
const approvals = await listApprovals(runtime, { status: "pending" });
const approval = approvals[0] ? await getApproval(runtime, approvals[0].approvalId) : null;These methods return runtime-facing records, not raw persistence or backend checkpoint objects.
Bridge MCP Servers Into Agents
apiVersion: agent-harness/v1alpha1
kind: Agent
metadata:
name: orchestra
spec:
execution:
backend: deepagent
modelRef: model/default
mcpServers:
- name: browser
command: node
args: ["./mcp-browser-server.mjs"]The runtime discovers MCP tools, filters them through agent configuration, and exposes them like other tools.
Expose Runtime Tools As An MCP Server
import { createToolMcpServer, serveToolsOverStdio } from "@botbotgo/agent-harness";
const server = await createToolMcpServer(runtime, { agentId: "orchestra" });
await serveToolsOverStdio(runtime, { agentId: "orchestra" });Stop The Runtime
import { stop } from "@botbotgo/agent-harness";
await stop(runtime);How To Configure
Use Kubernetes-style YAML:
- collection files use
apiVersion, pluralkind, andspec: [] - single-object files use
apiVersion, singularkind,metadata, andspec
Core workspace files:
config/workspace.yamlconfig/agent-context.mdconfig/models.yamlconfig/embedding-models.yamlconfig/vector-stores.yamlconfig/stores.yamlconfig/backends.yamlconfig/tools.yamlconfig/mcp.yamlconfig/agents/direct.yamlconfig/agents/orchestra.yamlresources/tools/resources/skills/
There are three configuration layers:
- runtime policy in
config/workspace.yaml - reusable object catalogs in
config/*.yaml - agent assembly in
config/agents/*.yaml
The repository-owned default config layer is intentionally full-shaped. The shipped YAML keeps explicit default values for the main runtime knobs so teams can start from concrete config instead of reconstructing adapter defaults from code.
config/workspace.yaml
Use this file for runtime-level policy shared by the whole workspace.
Primary fields:
runRootconcurrency.maxConcurrentRunsrouting.defaultAgentIdrouting.rulesrouting.systemPromptrouting.modelRoutingmaintenance.checkpointsrecovery.enabledrecovery.resumeResumingRunsOnStartuprecovery.maxRecoveryAttempts
If runRoot is omitted, the runtime defaults to <workspace-root>/run-data.
Queued runs are persisted under runRoot and continue after process restart. running runs are only replayed on startup when the bound tools are retryable.
config/agent-context.md
Use this file for shared bootstrap context loaded into agents at construction time.
Put stable project context here. Do not use it as mutable long-term memory.
config/models.yaml
Use named chat-model presets:
apiVersion: agent-harness/v1alpha1
kind: Models
spec:
- name: default
provider: openai
model: gpt-4.1
temperature: 0.2These load as model/<name>.
config/embedding-models.yaml
Use named embedding-model presets for retrieval-oriented tools.
config/vector-stores.yaml
Use named vector-store presets referenced by retrieval tools.
config/stores.yaml
Use reusable store and checkpointer presets:
apiVersion: agent-harness/v1alpha1
kind: Stores
spec:
- kind: Store
name: default
storeKind: FileStore
path: store.json
- kind: Checkpointer
name: default
checkpointerKind: MemorySaver
- kind: Checkpointer
name: sqlite
checkpointerKind: SqliteSaver
path: checkpoints.sqliteBuilt-in store kinds today:
FileStoreInMemoryStore
Built-in checkpointer kinds today:
MemorySaverFileCheckpointerSqliteSaver
If you need other store or checkpointer implementations, inject them through runtime resolvers instead of treating them as built-in harness features.
config/backends.yaml
Use reusable DeepAgent backend presets so filesystem and long-term memory topology stays in YAML instead of application code:
apiVersion: agent-harness/v1alpha1
kind: Backends
spec:
- kind: Backend
name: default
backendKind: CompositeBackend
state:
kind: VfsSandbox
rootDir: .
virtualMode: true
timeout: 600
routes:
/memories/:
kind: StoreBackendconfig/tools.yaml
Use this file for reusable tool objects.
Supported tool families in the built-in runtime include:
- function tools
- backend tools
- MCP tools
- provider-native tools
- bundles
Provider-native tools are declared in YAML and resolved directly to upstream provider tool factories such as OpenAI and Anthropic tool objects.
Use retryable carefully. Mark a tool retryable only when repeated execution is safe or intentionally idempotent.
config/mcp.yaml
Use this file for named MCP server presets.
config/agents/*.yaml
Agents are always declared with kind: Agent and spec.execution.backend.
Use two nested sections inside each agent:
spec.runtimefor harness-owned runtime placement such asspec.runtime.runRootspec.executionfor upstream execution semantics and adapter-facing config
This keeps the public product model small while letting LangChain v1 and DeepAgents concepts pass through with minimal translation.
Example lightweight host:
apiVersion: agent-harness/v1alpha1
kind: Agent
metadata:
name: direct
spec:
runtime:
runRoot: ./.agent
execution:
backend: langchain-v1
modelRef: model/default
tools: []
skills: []
memory: []
subagents: []
mcpServers: []
config:
checkpointer:
ref: checkpointer/default
store:
ref: store/default
interruptOn: {}
middleware: []
systemPrompt: Answer simple requests directly.Example main execution host:
apiVersion: agent-harness/v1alpha1
kind: Agent
metadata:
name: orchestra
spec:
runtime:
runRoot: ./.agent
execution:
backend: deepagent
modelRef: model/default
memory:
- path: config/agent-context.md
tools: []
skills: []
subagents: []
mcpServers: []
config:
store:
ref: store/default
checkpointer:
ref: checkpointer/default
backend:
ref: backend/default
interruptOn: {}
middleware: []
generalPurposeAgent: true
taskDescription: Complete delegated sidecar work and return concise results.Client-configurable agent fields include:
metadata.namemetadata.descriptionspec.execution.backendspec.runtime.runRootspec.execution.modelRefspec.execution.toolsspec.execution.skillsspec.execution.memoryspec.execution.subagentsspec.execution.mcpServersspec.execution.config.systemPromptspec.execution.config.checkpointerspec.execution.config.storespec.execution.config.backendspec.execution.config.middlewarespec.execution.config.responseFormatspec.execution.config.contextSchemaspec.execution.config.stateSchemaspec.execution.config.interruptOnspec.execution.config.filesystemspec.execution.config.taskDescriptionspec.execution.config.generalPurposeAgentspec.execution.config.includeAgentNamespec.execution.config.version
For backend-specific agent options, prefer passing the upstream concept directly inside spec.execution.config. The loader keeps a small stable product shape, but it also preserves adapter-facing passthrough fields so new LangChain v1 or DeepAgents parameters can flow into adapters without expanding the public API surface.
Upstream feature coverage is tracked in docs/upstream-feature-matrix.md.
resources/
Use resources/ for executable local extensions:
resources/tools/for tool modulesresources/skills/for SKILL packages
Tool modules are discovered from resources/tools/*.js, resources/tools/*.mjs, and resources/tools/*.cjs.
The preferred tool module format is exporting tool({...}).
SKILL packages are discovered from resources/skills/ and attached to agents through YAML.
Design Notes
- public runtime contract stays generic and small
- application-level orchestration and lifecycle management stays in the harness
- upstream LangChain v1 and DeepAgents concepts should be expressed as directly as possible in YAML
- recovery, approvals, threads, runs, and events are runtime concepts, not backend-specific escape hatches
- backend implementation details should stay internal unless product requirements force exposure
- new LangChain v1 or DeepAgents public config should land in YAML passthrough and compatibility tests before adding new public runtime APIs
In short: agent-harness is a public runtime contract generic enough to survive backend changes, while the deep execution semantics stay upstream.
API Summary
Primary exports:
createAgentHarnessrunsubscribelistThreadsgetThreaddeleteThreadlistApprovalsgetApprovalcreateToolMcpServerserveToolsOverStdiostop
