JamJet
Open Source

Quickstart

See JamJet block an unsafe tool call in 60 seconds. No API key, no cloud account.

Quickstart

In 60 seconds, see JamJet block an unsafe tool call before execution.

pip install jamjet
jamjet demo unsafe-tool-call

You'll see the blocked tool, the matched policy rule, and an audit JSON file written under .jamjet-demo/runs/. No API key. No cloud account. The model is mocked; the enforcement path is real.

Three more demos:

jamjet demo approval        # pause for human approval
jamjet demo budget-cap      # $0.05 cost cap
jamjet demo mcp-tool-policy # MCP-shaped policy (preview)

Once the demos make sense, drop a policy beside your real agent code.

Looking for JamJet Cloud (governance, dashboard, audit trail)? See the Cloud Quickstart instead.

1. Install

pip install jamjet

The Java SDK is published on Maven Central as dev.jamjet:jamjet-sdk.

Prerequisites: Java 21+ and Maven 3.9+ or Gradle 8+.

Maven:

<dependency>
    <groupId>dev.jamjet</groupId>
    <artifactId>jamjet-sdk</artifactId>
    <version>0.5.0</version>
</dependency>

Gradle (Kotlin DSL):

implementation("dev.jamjet:jamjet-sdk:0.5.0")

Gradle (Groovy DSL):

implementation 'dev.jamjet:jamjet-sdk:0.5.0'

Make sure your project targets Java 21 or later. In Maven:

<properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
</properties>

2. Write a workflow

# agent.py
from jamjet import task, tool

@tool
async def web_search(query: str) -> str:
    """Search the web for current information."""
    # plug in your actual search implementation
    return f"Results for: {query}"

@task(model="claude-sonnet-4-6", tools=[web_search])
async def research(question: str) -> str:
    """You are a research assistant. Search first, then summarize clearly."""

import asyncio
result = asyncio.run(research("What is JamJet?"))
print(result)

The @tool decorator exposes any Python function to the agent. The @task docstring becomes the agent's instructions. Works with OpenAI, Anthropic, Ollama, Groq — any model.

tip: Using Ollama locally? No API key needed:

OPENAI_API_KEY=ollama OPENAI_BASE_URL=http://localhost:11434/v1 python agent.py

Change model= to any Ollama model (e.g. "llama3.2").

Define a tool — the bridge between your agent and the outside world:

import dev.jamjet.tool.Tool;
import dev.jamjet.tool.ToolCall;

@Tool(description = "Search the web for information about a topic")
record WebSearch(String query) implements ToolCall<String> {
    public String execute() {
        // In production, call your search API here
        return "Results for '" + query + "': JamJet is a safety layer "
                + "for AI agents.";
    }
}

Build an agent with a reasoning strategy and runtime-enforced limits:

import dev.jamjet.agent.Agent;

var agent = Agent.builder("researcher")
        .model("claude-haiku-4-5-20251001")
        .tools(WebSearch.class)
        .instructions("You are a helpful research assistant. "
                + "Always search first, then provide a thorough summary.")
        .strategy("react")
        .maxIterations(5)
        .build();

3. Run it

ANTHROPIC_API_KEY=sk-ant-... python agent.py
public static void main(String[] args) {
    var agent = Agent.builder("researcher")
            .model("claude-haiku-4-5-20251001")
            .tools(WebSearch.class)
            .instructions("You are a helpful research assistant. "
                    + "Always search first, then provide a thorough summary.")
            .strategy("react")
            .maxIterations(5)
            .build();

    var result = agent.run("What is JamJet?");

    System.out.println(result.output());
    System.out.printf("Duration: %.2f ms%n", result.durationUs() / 1000.0);
    System.out.printf("Tool calls: %d%n", result.toolCalls().size());
}
export OPENAI_API_KEY=sk-...
mvn compile exec:java -Dexec.mainClass=com.example.MyAgent

Next steps

On this page