Documentation · v0.1.0

The portable AI worker runtime

AgentMug is a runtime and portable format for AI workers. A worker packages its job, tools, source requirements, permissions, schedules, and runtime behavior into a .agent file. The same definition can run locally, through the CLI, from an MCP host, or on AgentMug Cloud.

Worker is the product concept. .agent is the portable technical format. These docs, the APIs, the schemas, and the package names keep agent where it is technically accurate — both words refer to the same thing.

Multi-provider models, bring your own keys on desktop and CLI. The runtime is Apache-2.0. Host parity is partial: the engine, format, streaming, and pause/resume behave the same everywhere, but each host supplies its own tool executors, so tool catalogs differ.

Install

Three published packages — pick the ones that fit your shape.

bash
# Embed the runtime in your own app
npm install @agentmug/runtime

# Use the CLI (humans + agent-driven)
npm install -g @agentmug/cli

# Expose AgentMug agents to Claude Code / Cursor (configured, not installed)
# See "Use from Claude Code / Cursor" below

Hello agent

The 10-line minimum. Pass a parsed .agent file + a prompt + an Anthropic key. quickRun wires in-memory adapters so you don't need a database to get started.

typescript
import { quickRun, parseAgentFile } from "@agentmug/runtime";
import { readFileSync } from "node:fs";

const agentFile = parseAgentFile(JSON.parse(readFileSync("./hello.agent", "utf8")));

const result = await quickRun({
  agentFile,
  userInput: "Say hi in 5 words.",
  llm: { anthropicApiKey: process.env.ANTHROPIC_API_KEY! },
  onEvent: (e) => e.type === "token" && process.stdout.write(e.content),
});

console.log("\n→", result.totalTokens, "tokens");

Full runnable copy in examples/hello-agent.

.agent file format

A .agent file is a declarative JSON document: name, description, system prompt, model, tool list, input/output shapes, parameters. Portable. Version-controllable. Forkable.

json
{
  "$schema": "https://agentmug.com/schemas/agent.v1.json",
  "id": "email-triage",
  "name": "Email Triage",
  "description": "Sorts unread Gmail and drafts replies.",
  "blueprint": {
    "primaryModel": "claude-sonnet-4-6",
    "systemPrompt": "You triage emails...",
    "tools": ["gmail.send", "memory.save", "ask_user"]
  },
  "parameters": [{
    "name": "source_file_1",
    "label": "Source table 1",
    "type": "file",
    "required": true,
    "artifact": {
      "kind": "table",
      "accepts": [".csv", ".xlsx"],
      "structure": ["Sheet \"Invoices\" columns: invoice_id, amount, due_date"]
    }
  }],
  "inputs": { "accepts": ["text"] },
  "outputs": { "shape": "text" }
}

Load + validate via parseAgentFile(json). Pass the result to quickRun() or runAgent().

A type: "file" parameter carries only a secret-free format and structure contract. Each host binds its owner's private equivalent and can call checkArtifactCompatibility(parameter, candidate) before ingesting anything. Filenames, rows, prose, image bytes, credentials, memories, and bound values never belong in a shared file.

See the canonical spec page for the full schema with all optional fields.

Grounded source contracts

A source contract declares the evidence an agent requires. The .agent carries that secret-free requirement; each owner privately binds and verifies their own file, folder, provider item, or saved brain snapshot before the agent can run.

When you attach a .klypix in the web builder, AgentMug creates correction-aware grounding from that saved snapshot. It excludes Archive history and cards reversed by saved lifecycle edges or a valid KLYPIX correction overlay. Incomplete projections fail closed.

The authenticated browser hashes the exact selected file bytes; the receipt labels that raw revision owner-client. AgentMug Cloud independently hashes the indexed current-card projection, but does not upload or reparse the original archive bytes. The receipt records both the raw-file revision attestation and evidence digest, plus the card ids and actual read time.

Grounding only — not coordination. A KLYPIX snapshot binding does not call or join brain_sync coordination, peer presence, messages, or file-overlap detection. Saving the original brain again does not update the attachment; attach and verify the new saved revision.

Grounding is private, not local-only: selected card content, card ids, and revision evidence are sent to AgentMug's configured embedding/model processors for the run. They are not put in the shareable .agent or exposed as public source data.

For this source, stale means the snapshot/file revision drifted from its verification pin, or verification expired, before the first model request. It does not mean that a card is old, and it is not derived from brain_doctor.

Adapters — the universality lever

The runtime knows nothing about where it's running. Everything that touches the outside world is an adapter you pass to runAgent():

AdapterWhat it doesBundled implementations
LlmClientStreams messages, returns tokensAnthropicLlmClient · OpenAiLlmClient · GeminiLlmClient
PersistenceAdapterCreates / updates run recordsInMemoryPersistenceAdapter (quickstart) — or write your own (Postgres, SQLite, file)
TracingAdapterRecords LLM call telemetryInMemoryTracingAdapter (with optional hooks) — wrap your OpenTelemetry SDK here
TranscriptionAdapterAudio → textGeminiTranscriptionAdapter
RemindersAdapterWhere reminders landiCloud CalDAV · local .ics file · or your own

Swap any layer. The engine doesn't know the difference.

Tools

Tools are normal classes implementing ToolExecutor. Register them with an InMemoryToolRegistry + pass to runAgent() or quickRun().

typescript
import {
  InMemoryToolRegistry,
  gmailSendDefinition,
} from "@agentmug/runtime";

const tools = new InMemoryToolRegistry();
tools.register(gmailSendDefinition, new YourGmailExecutor());

The runtime ships built-in tool definitions for: Gmail send, Calendar create-event, Slack send, GitHub create-issue, code execute, web research, web browse, web.fetch_json (generic HTTP), ask_user (pause/resume), memory save/recall/forget, image.generate, invoke_agent, create_reminder, shell.execute (desktop-only), Skills importer.

The web.fetch_json tool is the catalog unlock: any HTTP API becomes a capability without writing a custom executor. See examples/web-research.

Scheduling

Enabled cloud schedules are accepted only when AgentMug can confirm its Redis producer and at least one fleet scheduler worker are ready. Disabled drafts can still be saved, but remain visibly paused instead of appearing active and silently missing their run.

Managed AgentMug

Contact your workspace administrator or AgentMug support. Existing schedule definitions remain saved and paused until service is restored.

Self-hosted

Set REDIS_URL for every API and background-worker replica, restart them, then verify GET /api/schedules/status returns localProducerReady: true and fleetWorkerReady: true before enabling schedules.

Plugins

External npm packages can ship coherent bundles of tools + adapters with the plugin API. definePlugin() builds the bundle; registry.loadPlugin() wires it.

typescript
// In your plugin package — e.g. @agentmug-plugins/hackernews
import { definePlugin } from "@agentmug/runtime";

export default definePlugin({
  name: "hackernews",
  version: "1.0.0",
  tools: [
    {
      definition: hnSearchDefinition,
      executor: new HnSearchExecutor(),
    },
  ],
});

// In the consumer
import { InMemoryToolRegistry } from "@agentmug/runtime";
import hnPlugin from "@agentmug-plugins/hackernews";

const tools = new InMemoryToolRegistry();
tools.loadPlugin(hnPlugin);
// every tool the plugin defines is now registered

Plugins can also ship adapter implementations (custom LlmClient, PersistenceAdapter, TracingAdapter) — see the OpenTelemetry adapter package below for the canonical example.

Observability (OpenTelemetry)

@agentmug/otel ships a TracingAdapter that emits LLM-call + transcription spans into your existing OTel pipeline — Honeycomb, Datadog, Tempo, Jaeger, Sentry, anything that consumes OTel.

bash
npm install @agentmug/otel @opentelemetry/api
typescript
import { runAgent, noSourcePlan } from "@agentmug/runtime";
import { OtelTracingAdapter } from "@agentmug/otel";

const result = await runAgent({
  agentId: "...", userId: "...", userInput: "...",
  adapters: {
    persistence: yourPersistence,
    llm: yourLlmClient,
    tracing: new OtelTracingAdapter(),   // ← that's it
  },
  onEvent: () => {},
});

Every LLM call becomes a span with attributes like agentmug.llm.provider, agentmug.llm.model, agentmug.llm.tokens, agentmug.llm.cost_cents, agentmug.llm.latency_ms. Wire your existing OTel SDK + exporter as you normally would and runs show up in your dashboards.

Use AgentMug agents from Claude Code / Cursor

@agentmug/mcp-bridge exposes any agent (hosted on agentmug.com or your own backend) as a Model Context Protocol server. Drop into your MCP client config:

json
{
  "mcpServers": {
    "email-assistant": {
      "command": "npx",
      "args": [
        "-y",
        "@agentmug/mcp-bridge",
        "https://agentmug.com/api/external/agents/<AGENT_ID>"
      ],
      "env": { "AGENTMUG_API_KEY": "am_agent_..." }
    }
  }
}

Generate the agent ID + API key from the agent's Deploy → External access tab. Works in Claude Desktop, Claude Code, Cursor (command mode), Continue, Cline.

CLI (agent-controllable)

The agentmug CLI runs .agent files locally AND talks to agentmug.com to create, fork, and invoke agents remotely. Designed to be driven by humans OR by other agents (an LLM with shell access can use it).

bash
# Local — uses your Anthropic key
export ANTHROPIC_API_KEY=sk-ant-...
agentmug run path/to/my.agent --input "Hello"

# Cloud — uses your AgentMug user key
export AGENTMUG_API_KEY=am_user_...    # mint at /settings/api-keys
agentmug create --prompt "Triage my Gmail and draft replies"
agentmug list
agentmug invoke email-triage --input "Summarize unread" --stream
agentmug fork email-triage --as personal-email
agentmug key new --agent email-triage

The cloud subcommands hit /api/agents/* and /api/external/agents/:id/invoke. Authenticated via the AGENTMUG_API_KEY env var (a user-levelam_user_… token).

Migrate from raw Anthropic SDK

If you're calling Claude directly from @anthropic-ai/sdk with a system prompt + tool loop, AgentMug is mostly a refactor. The engine + tool registry replace your hand-rolled message loop; your existing tool implementations become ToolExecutor classes.

typescript
// Before — raw SDK
const anthropic = new Anthropic({ apiKey });
const messages = [{ role: "user", content: input }];
while (true) {
  const r = await anthropic.messages.create({
    model, system, messages, tools, max_tokens: 4096,
  });
  // hand-write: tool_use detection, executor dispatch,
  // tool_result formatting, stop_reason loop, etc.
}

// After — @agentmug/runtime
const tools = new InMemoryToolRegistry();
tools.register(gmailSendDefinition, new MyGmailExecutor());

const result = await quickRun({
  agentFile: parseAgentFile(myAgentJson),
  userInput: input,
  llm: { anthropicApiKey: apiKey },
  tools,
  onEvent: (e) => { /* streaming tokens + tool events */ },
});

What you gain by migrating:

  • Tool loop with pause/resume, abort, streaming events.
  • Provider-agnostic — same code paths against Anthropic, OpenAI, or Gemini by changing the LLM client.
  • Portable .agent JSON files so an agent definition can be version-controlled, forked, or shipped to another runtime (cloud / desktop / CLI / MCP).
  • Built-in tool catalog you don't have to maintain.
  • MCP server adapter so your agents become invocable from any MCP-compatible client without extra code.

Examples

Try it without writing any code

Sign up, pick a goal in onboarding, and connect your accounts inline. You get a working agent, then point Claude Code at it with one config file.