Every production AI agent needs the same scaffolding: a run loop that drives LLM-tool-state cycles, typed tool dispatch, event streaming for observability, and a testing harness that works without calling a real LLM. AgentJeff ships all of it as composable TypeScript packages. You own the agent logic — not the plumbing.
AI Badgr is the default inference provider. Swap it out via the adapter interface.
- Working run loop —
executeRundrives infer → dispatch → update-state → repeat so you don't write it - Typed tools with Zod — input/output validated at definition time; schema errors surface before the LLM touches them
- Full event trace — every step emits a typed event (
tool.called,tool.succeeded,state.updated,run.completed) you can stream, log, or assert on - Swappable inference —
BadgrAdapterworks with any model key on AI Badgr; mock it entirely for tests - Pre-built packs — workspace assistant and structured extraction agents ready to use or fork
- Deterministic tests —
MockInferenceAdapter+runAndAssertlet you test agent behavior without an LLM - CLI — scaffold a project, run any agent, or stream events from the terminal
| Package | Description |
|---|---|
@agentjeff/sdk |
Main entry point — defineAgent, defineTool, run() |
@agentjeff/core |
Type definitions: Agent, Tool, Run, State, Adapter, Event, Policy |
@agentjeff/runtime |
Step-execution loop (executeRun) |
@agentjeff/adapters |
BadgrAdapter (AI Badgr inference) and LocalWorkspaceAdapter (file I/O) |
@agentjeff/workflow |
Step-based multi-stage workflow builder |
@agentjeff/packs |
Pre-built workspace assistant and structured extraction packs |
@agentjeff/testing |
MockInferenceAdapter, runAndAssert, scenario runner |
@agentjeff/cli |
agentjeff CLI binary |
@agentjeff/examples |
Reference agent implementations |
npx @agentjeff/cli init basic-agent
cd basic-agent
cp .env.example .env # add BADGR_API_KEY
npm install
npm startSee all templates:
npx @agentjeff/cli templatesnpm install @agentjeff/sdk zod openai
export BADGR_API_KEY=your_key_hereimport { z } from 'zod';
import { defineAgent, defineTool, run } from '@agentjeff/sdk';
const summarizeTool = defineTool({
name: 'summarize',
description: 'Summarize a block of text into bullet points',
inputSchema: z.object({ text: z.string() }),
outputSchema: z.object({ bullets: z.array(z.string()) }),
async execute({ text }) {
return { bullets: text.split('. ').map(s => s.trim()).filter(Boolean) };
},
});
const agent = defineAgent({
name: 'analyst',
instructions: 'Summarize the given content using the summarize tool.',
inputSchema: z.object({ content: z.string() }),
outputSchema: z.object({ summary: z.string() }),
tools: [summarizeTool],
});
const result = await run(
agent,
{ content: 'AgentJeff owns the loop. Your tool executes. State updates. Repeat.' },
{ onEvent: (event) => console.log(`[${event.type}]`, event.payload) },
);
console.log(result.result?.summary);defineAgent + defineTool
│
▼
executeRun()
│
┌────▼────┐
│ Loop │ up to maxSteps
│ ─────── │
│ 1. LLM infers (InferenceAdapter)
│ 2. Tool calls? → execute tools
│ 3. Emit events
│ 4. Final answer? → return Run
└─────────┘
│
Run { status, result, state, events }
Ready-to-run project starters. Scaffold with the CLI:
npx @agentjeff/cli init basic-agent # minimal single-tool agent
npx @agentjeff/cli init researcher # multi-step research + report
npx @agentjeff/cli init code-reviewer # reads a workspace, records issues
npx @agentjeff/cli init data-pipeline # fetch → validate → transform → storeOr copy from templates/ directly.
BadgrAdapter is the default. Bring your own model key on AI Badgr and pick any model:
import { BadgrAdapter } from '@agentjeff/sdk';
import { MockInferenceAdapter } from '@agentjeff/testing'; // for tests
new BadgrAdapter({ model: 'gpt-4o' })
new BadgrAdapter({ model: 'claude-opus-4-7' })See docs/adapters.md for options and how to write your own.
import { buildWorkspaceAgent } from '@agentjeff/packs';
import { executeRun, BadgrAdapter } from '@agentjeff/sdk';
const agent = buildWorkspaceAgent('./my-project');
const run = await executeRun({
agent,
input: { task: 'Summarize the project structure', path: '.' },
inferenceAdapter: new BadgrAdapter(),
});
console.log(run.result.summary);import { extractionAgent } from '@agentjeff/packs';
import { executeRun, BadgrAdapter } from '@agentjeff/sdk';
const run = await executeRun({
agent: extractionAgent,
input: { text: 'Login button broken on mobile Safari — users can\'t sign in.' },
inferenceAdapter: new BadgrAdapter(),
});
// { category: 'bug_report', priority: 'high', fields: {...}, summary: '...' }More examples in packages/examples/.
npx @agentjeff/cli run:workspace ./my-project "List all TypeScript files"
npx @agentjeff/cli run:extract "Payment fails at checkout for EU users"
npx @agentjeff/cli run:research "Rust ownership model"
# Scaffold a new project
npx @agentjeff/cli init basic-agent
npx @agentjeff/cli templates
# Stream all events
npx @agentjeff/cli run:workspace ./my-project --eventsimport { MockInferenceAdapter, runAndAssert } from '@agentjeff/testing';
await runAndAssert(
agent,
{ content: 'some input' },
new MockInferenceAdapter([
{ content: null, toolCalls: [{ id: 'tc1', name: 'my_tool', arguments: { foo: 'bar' } }] },
{ content: 'Done', toolCalls: [] },
]),
{
status: 'completed',
eventTypes: ['tool.called', 'tool.succeeded'],
}
);| Guide | Description |
|---|---|
| Quickstart | From zero to a running agent in 5 minutes |
| Debugging | Events, state, testing, common failures |
| Adapters | OpenAI, Anthropic, custom providers |
git clone https://github.com/michaelmanly/agentjeff.git
cd agentjeff
npm install
npm run build # build all packages
npm run build:watch # watch mode
npm test # run tests
npm run lint # type check| Variable | Description |
|---|---|
BADGR_API_KEY |
API key for AI Badgr |
BADGR_BASE_URL |
Override base URL (default: https://aibadgr.com/v1) |
Contributions are welcome. Please open an issue before submitting a pull request for significant changes.
- Fork the repo
- Create a feature branch (
git checkout -b feat/my-feature) - Make your changes and add tests
- Run
npm run lint && npm test - Open a pull request
MIT