Skip to content

jamjet-labs/jamjet

⚡ JamJet

The agent-native runtime — durable, composable, built for production.

jamjet MCP server CI PyPI License Rust Python Java Go Docs Discord

jamjet.dev · Quickstart · Concepts · API Reference · Examples · Blog · Discord

Open in GitHub Codespaces Open in Gitpod

jamjet MCP server

JamJet demo


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 executionpip install jamjet and run immediately

Quickstart

Requirements: Python 3.11+

Fastest path — pure Python, no server

pip install jamjet
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?")
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 dev

In another terminal:

jamjet run workflow.yaml --input '{"query": "What is JamJet?"}'

Full quickstart guide


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: end
jamjet 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: summarize

A2A delegation

nodes:
  delegate:
    type: a2a_task
    agent_url: "https://agents.example.com/research-agent"
    input:
      query: "{{ state.query }}"
    output_key: research
    next: end

Eval 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: end

Coordinator — 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 → process

Agentic 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 Agent with @task Simple prototypes, single-purpose tasks Chatbot, classifier
Sequential Pipeline WorkflowGraph with edges Ordered steps where each depends on the previous ETL, document processing
Parallel Fan-Out ParallelNode Independent tasks that can run concurrently Multi-source research, batch classification
Loop & Critic LoopNode + EvalNode Quality-critical tasks needing iterative refinement Code review, content generation
Coordinator (Dynamic Routing) CoordinatorNode Route to the best agent at runtime based on capability, cost, latency Support ticket routing, task delegation
Agent-as-Tool agent_tool() wrapper 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-Tool

Coordinator vs static routing

Static (ConditionalNode) Dynamic (CoordinatorNode)
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 (@task) ✅ 5 lines 6+ lines 10+ lines 8+ lines
In-process execution pip install + run ✅ native ✅ native ✅ native ✅ native
Durable execution ✅ event-sourced, crash-safe ❌ ephemeral ❌ ephemeral ❌ ephemeral ❌ ephemeral
Dynamic agent routing ✅ Coordinator with scoring + LLM tiebreaker transfer_to_agent()
Agent-as-Tool ✅ sync, streaming, conversational AgentTool (sync only)
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 @taskAgentWorkflow 🟡 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

Quickstart Get running in 10 minutes
Core Concepts Agents, workflows, nodes, state, durability
YAML Workflows All node types, retry policies, conditions
Python SDK Full Python SDK reference
Java SDK Builders, records, @Tool annotation, agents
REST API All endpoints, auth, request/response schemas
Enterprise Security Tenants, PII redaction, OAuth, mTLS federation
MCP Integration Connect to MCP servers, expose tools
A2A Integration Delegate to and serve external agents
Eval Harness Score quality, run regression suites, gate CI
Observability OTel traces, metrics, Prometheus
Deployment Docker, Kubernetes, PostgreSQL
CLI Reference 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 issue for easy entry points
  • For large changes, open an issue first to discuss the approach
  • Read CONTRIBUTING.md for setup instructions

Community


License

Apache 2.0 — see LICENSE.


Built by Sunil Prakash · © 2026 JamJet · jamjet.dev · Apache 2.0