The JamJet server provides a comprehensive management interface for agent-native workflow runtimes, enabling you to run, monitor, and control durable AI agent workflows and multi-agent systems.
Run Workflows (
jamjet_run_workflow): Start a workflow execution with input data, workflow ID, and optional version parametersMonitor Executions (
jamjet_get_execution,jamjet_list_executions): Retrieve execution status/details and browse paginated execution history with filtering by status (running, paused, completed, failed)Get Event Logs (
jamjet_get_events): Retrieve the full event timeline/audit log for any execution, supporting observability and replayCancel Executions (
jamjet_cancel_execution): Terminate running workflow executionsHuman-in-the-Loop (
jamjet_approve): Approve or reject paused executions waiting for human intervention, with an optional commentList Agents (
jamjet_list_agents): Browse registered agents with filtering by skill, status, or protocolDiscover Remote Agents (
jamjet_discover_agent): Register new remote agents into the JamJet registry by URL, enabling dynamic agent discovery and routingMulti-tenancy: All operations support tenant isolation via
tenant_idparameters
Enables integrating Brave Search as an MCP tool within agent workflows to provide web search and information retrieval capabilities.
The agent-native runtime — durable, composable, built for production.
jamjet.dev · Quickstart · Concepts · API Reference · Examples · Blog · Discord

JamJet is a performance-first, agent-native runtime for AI agents. It is not another prompt wrapper or thin agent SDK — it is a production-grade orchestration substrate for agents that need to work, not just demo.
The runtime core is Rust + Tokio for scheduling, state, and concurrency. The authoring surface is Python, Java, Go (planned), or YAML. All compile to the same IR graph and run on the same engine.
Why JamJet?
Problem | JamJet's answer |
Agent runs lose state on crash | Durable graph execution — event-sourced, crash-safe resume |
No way to pause for human approval | Human-in-the-loop as a first-class workflow primitive |
Agents siloed in their own framework | Native MCP + A2A — interoperate with any agent, any framework |
Slow Python orchestration at scale | Rust core — no GIL, real async parallelism |
Weak observability, no replay | Full event timeline, OTel GenAI traces, replay from any checkpoint |
No standard agent identity | Agent Cards — every agent is addressable and discoverable |
Hard-coded agent routing | Coordinator Node — dynamic routing with structured scoring + LLM tiebreaker |
Can't use agents as tools | Agent-as-Tool — wrap any agent as a callable tool (sync, streaming, conversational) |
No governance or guardrails | Policy engine — tool blocking, approvals, autonomy enforcement, audit log |
Agents with unchecked access | OAuth delegation — RFC 8693 token exchange, scope narrowing, per-step scoping |
PII leaking into logs | Data governance — PII redaction (mask/hash/remove), retention policies, auto-purge |
No tenant isolation | Multi-tenant — row-level partitioning, tenant-scoped state, isolated audit logs |
Locked into one language | Polyglot SDKs — Python, Java (JDK 21), Go (planned), YAML — same IR, same runtime |
Can't run without a server | In-process execution — |
Quickstart
Requirements: Python 3.11+
Fastest path — pure Python, no server
pip install jamjetfrom jamjet import task, tool
@tool
async def web_search(query: str) -> str:
return f"Search results for: {query}"
@task(model="claude-haiku-4-5-20251001", tools=[web_search])
async def research(question: str) -> str:
"""You are a research assistant. Search first, then summarize clearly."""
result = await research("What is JamJet?")
print(result)No server. No config. No YAML. Just pip install and run.
Full runtime path — durable execution
pip install jamjet
jamjet init my-first-agent
cd my-first-agent
jamjet devIn another terminal:
jamjet run workflow.yaml --input '{"query": "What is JamJet?"}'Hello World
YAML
# workflow.yaml
workflow:
id: hello-agent
version: 0.1.0
state_schema:
query: str
answer: str
start: think
nodes:
think:
type: model
model: claude-haiku-4-5-20251001
prompt: "Answer clearly and concisely: {{ state.query }}"
output_key: answer
next: end
end:
type: endjamjet validate workflow.yaml
jamjet run workflow.yaml --input '{"query": "What is JamJet?"}'Python — @task (simplest)
from jamjet import task, tool
@tool
async def web_search(query: str) -> str:
return f"Search results for: {query}"
@task(model="claude-haiku-4-5-20251001", tools=[web_search])
async def research(question: str) -> str:
"""You are a research assistant. Search first, then summarize clearly."""
result = await research("What is JamJet?")The docstring becomes the instruction. The function signature is the contract. That's it.
Python — Agent
from jamjet import Agent, tool
@tool
async def web_search(query: str) -> str:
return f"Search results for: {query}"
agent = Agent(
"researcher",
model="claude-haiku-4-5-20251001",
tools=[web_search],
instructions="You are a research assistant. Search first, then summarize.",
)
result = await agent.run("What is JamJet?")
print(result)Python — Workflow (full control)
from jamjet import Workflow, tool
from pydantic import BaseModel
@tool
async def web_search(query: str) -> str:
return f"Search results for: {query}"
workflow = Workflow("research")
@workflow.state
class State(BaseModel):
query: str
answer: str | None = None
@workflow.step
async def search(state: State) -> State:
result = await web_search(query=state.query)
return state.model_copy(update={"answer": result})All three levels compile to the same IR and run on the same durable Rust runtime.
Performance
JamJet's IR compilation is 88× faster than LangGraph's graph compilation:
Operation | JamJet | LangGraph |
Compile / graph build | ~0.006 ms | ~0.529 ms |
In-process invocation | ~0.015 ms | ~1.458 ms |
Measured with Python 3.11, single-tool workflows. JamJet compiles a lightweight IR dict; LangGraph builds a NetworkX graph.
MCP tool call
nodes:
search:
type: tool
server: brave-search # configured in jamjet.toml
tool: web_search
arguments:
query: "{{ state.query }}"
count: 10
output_key: results
next: summarizeA2A delegation
nodes:
delegate:
type: a2a_task
agent_url: "https://agents.example.com/research-agent"
input:
query: "{{ state.query }}"
output_key: research
next: endEval with self-improvement
nodes:
check:
type: eval
scorers:
- type: llm_judge
rubric: "Is the answer accurate and complete?"
min_score: 4
on_fail: retry_with_feedback # injects feedback into next model call
max_retries: 2
next: endCoordinator — dynamic agent routing
from jamjet.coordinator import DefaultCoordinatorStrategy
strategy = DefaultCoordinatorStrategy(registry=my_registry)
# Discover agents by skill, score them, route to the best fit
candidates, _ = await strategy.discover(
task="Analyze quarterly revenue data",
required_skills=["data-analysis", "finance"],
trust_domain="internal",
)
rankings, spread = await strategy.score(task, candidates, weights={})
decision = await strategy.decide(task, rankings, threshold=0.1)
# decision.selected_uri → "jamjet://org/finance-analyst"Agent-as-Tool — wrap agents as callable tools
from jamjet.agent_tool import agent_tool
# Sync: quick, stateless
classifier = agent_tool(agent="jamjet://org/classifier", mode="sync",
description="Classifies documents by topic")
# Streaming: long-running with early termination on budget
researcher = agent_tool(agent="jamjet://org/researcher", mode="streaming",
description="Deep research with progress", budget={"max_cost_usd": 2.00})
# Conversational: multi-turn iterative refinement
reviewer = agent_tool(agent="jamjet://org/reviewer", mode="conversational",
description="Peer review with feedback", max_turns=5)Auto-routing — compiler inserts Coordinator automatically
from jamjet.workflow.graph import WorkflowGraph
graph = WorkflowGraph("pipeline")
graph.add_agent_tool("process", agent="auto", mode="sync", output_key="result")
# ↑ "auto" expands at compile time into: Coordinator → AgentTool
ir = graph.compile()
# IR now has 2 nodes: _coordinator_process → processAgentic design patterns
JamJet supports the six major multi-agent orchestration patterns. Here's when to use each:
Pattern | JamJet primitive | When to use | Example |
Single Agent |
| Simple prototypes, single-purpose tasks | Chatbot, classifier |
Sequential Pipeline |
| Ordered steps where each depends on the previous | ETL, document processing |
Parallel Fan-Out |
| Independent tasks that can run concurrently | Multi-source research, batch classification |
Loop & Critic |
| Quality-critical tasks needing iterative refinement | Code review, content generation |
Coordinator (Dynamic Routing) |
| Route to the best agent at runtime based on capability, cost, latency | Support ticket routing, task delegation |
Agent-as-Tool |
| One agent needs to call another as a function | Orchestrator invoking specialists |
Choosing the right pattern
Is it a single task?
→ Single Agent
Does order matter?
→ Sequential Pipeline
Can tasks run independently?
→ Parallel Fan-Out
Does output need quality checks?
→ Loop & Critic
Do you need to pick the best agent at runtime?
→ Coordinator
Does one agent need to invoke another?
→ Agent-as-ToolCoordinator vs static routing
Static ( | Dynamic ( | |
Candidates | Declared in YAML | Discovered from registry at runtime |
Selection | Expression-based rules | Structured scoring + optional LLM tiebreaker |
When agents change | Redeploy workflow | Automatic — new agents discovered |
Observability | Branch taken logged | Full scoring breakdown + reasoning in event log |
Best for | Fixed, known routes | Dynamic environments, multi-tenant, research |
How JamJet compares
As of March 2026. All frameworks evolve — check their docs for the latest.
Capability | JamJet | Google ADK | LangChain | AutoGen | CrewAI |
Simple agent setup | ✅ 3 lines ( | ✅ 5 lines | 6+ lines | 10+ lines | 8+ lines |
In-process execution | ✅ | ✅ native | ✅ native | ✅ native | ✅ native |
Durable execution | ✅ event-sourced, crash-safe | ❌ ephemeral | ❌ ephemeral | ❌ ephemeral | ❌ ephemeral |
Dynamic agent routing | ✅ Coordinator with scoring + LLM tiebreaker | ✅ | ❌ | ❌ | ❌ |
Agent-as-Tool | ✅ sync, streaming, conversational | ✅ | ❌ | ❌ | ❌ |
Human-in-the-loop | ✅ first-class primitive | 🟡 callbacks | 🟡 callbacks | 🟡 conversational | 🟡 manual |
MCP support | ✅ client + server | ✅ client + server | 🟡 client only | 🟡 client only | 🟡 client only |
A2A protocol | ✅ client + server | 🟡 client only | ❌ | ❌ | ❌ |
Built-in eval | ✅ LLM judge, assertions, cost | ✅ 8 built-in criteria | ❌ | ❌ | ❌ |
Built-in observability | ✅ OTel GenAI, event replay | ✅ Cloud Trace | 🟡 LangSmith (external) | ❌ | ❌ |
Agent identity | ✅ Agent Cards, A2A discovery | ✅ Agent Cards | ❌ | ❌ | ❌ |
Policy & governance | ✅ policy engine, audit log | 🟡 Model Armor plugin | ❌ | ❌ | ❌ |
Multi-tenant isolation | ✅ row-level partitioning | ❌ | ❌ | ❌ | ❌ |
PII redaction | ✅ mask/hash/remove, retention | 🟡 plugin | ❌ | ❌ | ❌ |
Model independence | ✅ any model provider | 🟡 Gemini-first (LiteLLM escape) | ✅ any | ✅ any | ✅ any |
Progressive complexity | ✅ | 🟡 code or YAML | ❌ single API | ❌ | ❌ |
Managed deployment | 📋 Planned | ✅ Vertex AI Agent Engine | ❌ | ❌ | ❌ |
Runtime language | Rust core + Python/Java/Go | Python/TS/Go/Java | Python | Python | Python |
Best for | Production multi-agent systems | Google Cloud AI agents | Rapid prototyping | Conversational agents | Role-based crews |
Architecture
┌──────────────────────────────────────────────────────────┐
│ Authoring Layer │
│ Python SDK | Java SDK | Go SDK (planned) | YAML │
├──────────────────────────────────────────────────────────┤
│ Compilation / Validation │
│ Graph IR | Schema | Policy lint │
├────────────────────────────┬─────────────────────────────┤
│ Rust Runtime Core │ Protocol Layer │
│ Scheduler | State SM │ MCP Client | MCP Server │
│ Event log | Snapshots │ A2A Client | A2A Server │
│ Workers | Timers │ │
├────────────────────────────┴─────────────────────────────┤
│ Enterprise Services │
│ Policy | Audit | PII Redaction | OAuth | mTLS │
├──────────────────────────────────────────────────────────┤
│ Runtime Services │
│ Model Adapters | Tool Execution | Observability │
├──────────────────────────────────────────────────────────┤
│ Storage │
│ Postgres (production) | SQLite (local) │
└──────────────────────────────────────────────────────────┘Roadmap
Phase | Status | Goal |
0 — Architecture & RFCs | ✅ Complete | Design docs, RFCs, repo scaffolding |
1 — Minimal Viable Runtime | ✅ Complete | Local durable execution, MCP client, agent cards, Python CLI |
2 — Production Core | ✅ Complete | Distributed workers, MCP server, full A2A client + server |
3 — Developer Delight | ✅ Complete | Eval harness, trace debugging, templates, Java SDK |
4 — Enterprise | 🔄 In Progress | Policy engine, tenant isolation, PII redaction, OAuth delegation, A2A federation auth, mTLS |
5 — Scale & Ecosystem | 📋 Planned | Go SDK, TypeScript SDK, hosted plane, agent marketplace |
Documentation
Full documentation at jamjet.dev
Get running in 10 minutes | |
Agents, workflows, nodes, state, durability | |
All node types, retry policies, conditions | |
Full Python SDK reference | |
Builders, records, @Tool annotation, agents | |
All endpoints, auth, request/response schemas | |
Tenants, PII redaction, OAuth, mTLS federation | |
Connect to MCP servers, expose tools | |
Delegate to and serve external agents | |
Score quality, run regression suites, gate CI | |
OTel traces, metrics, Prometheus | |
Docker, Kubernetes, PostgreSQL | |
Full CLI reference |
Repository structure
jamjet/
├── runtime/ # Rust workspace (15 crates)
│ ├── core/ # Graph IR, node types, state machine
│ ├── ir/ # Canonical Intermediate Representation
│ ├── scheduler/ # Durable task scheduler
│ ├── state/ # Event-sourced state, snapshots
│ ├── workers/ # Node executors (model, tool, http, eval, …)
│ ├── api/ # REST API, OAuth delegation, secrets backends
│ ├── agents/ # Agent Cards, registry, lifecycle
│ ├── models/ # LLM provider adapter layer
│ ├── timers/ # Durable timers, Postgres-backed cron
│ ├── policy/ # Policy engine, PII redaction
│ ├── audit/ # Immutable audit log
│ ├── protocols/
│ │ ├── mcp/ # MCP client + server
│ │ └── a2a/ # A2A client + server + federation auth + mTLS
│ └── telemetry/ # OTel instrumentation
├── sdk/
│ ├── python/ # Python SDK + CLI
│ │ └── jamjet/
│ │ ├── cli/ # jamjet CLI (Typer)
│ │ ├── eval/ # Eval dataset, runner, scorers
│ │ ├── agents/ # Agent definitions + strategies
│ │ ├── templates/ # Project scaffolding templates
│ │ └── workflow/ # Python workflow builder
│ ├── java/ # Java SDK (JDK 21, virtual threads, records)
│ │ ├── jamjet-sdk/ # Core SDK module
│ │ └── jamjet-cli/ # CLI module
│ └── go/ # Go SDK (planned — Phase 5)Contributing
Contributions are welcome — bugs, features, docs, and code.
Open an issue for bugs or feature requests
Check issues tagged
good first issuefor easy entry pointsFor large changes, open an issue first to discuss the approach
Read CONTRIBUTING.md for setup instructions
Community
GitHub Discussions: github.com/jamjet-labs/jamjet/discussions
GitHub Issues: github.com/jamjet-labs/jamjet/issues
License
Apache 2.0 — see LICENSE.