Skip to content

Quickstart

The fastest path through this guide is the rax workflow (Rax = Reactive Agents Executable).

Using the CLI:

Terminal window
bunx rax init my-agent-app --template standard
cd my-agent-app
bun install

rax init --template standard scaffolds:

  • Directorymy-agent-app/
    • Directorysrc/
      • agent.ts Your first agent — runnable with bun run src/agent.ts
      • Directorytools/ Drop custom tools here; auto-discovered when wired into builder
    • .env Provider API keys (gitignored by default)
    • package.json reactive-agents dependency + bun run agent script
    • tsconfig.json strict mode + Bun-aware module resolution
    • README.md

Or manually:

Terminal window
mkdir my-agent-app && cd my-agent-app
bun init -y
bun add reactive-agents

Set at least one provider key. Pick whichever you have access to:

Terminal window
# Pick at least one
echo 'ANTHROPIC_API_KEY=sk-ant-...' > .env # Recommended for first agent
echo 'OPENAI_API_KEY=sk-...' >> .env
echo 'GOOGLE_API_KEY=...' >> .env
# Or run fully local — no key needed
ollama pull qwen3:4b

Optional keys for built-in tools (web search, etc.) — add them later when you call .withTools():

Terminal window
echo 'TAVILY_API_KEY=tvly-...' >> .env # Web search (Tavily backend)
echo 'SERPER_API_KEY=...' >> .env # Web search (Serper.dev backend)

Create src/agent.ts:

src/agent.ts
import { ReactiveAgents } from "reactive-agents";
const agent = await ReactiveAgents.create()
.withProvider("anthropic")
.build();
const result = await agent.run("What are the three laws of thermodynamics?");
console.log(result.output);

That’s the minimum. .withProvider() picks the default model for the provider automatically (claude-sonnet-4-6 for Anthropic). Set ANTHROPIC_API_KEY in your environment before running.

To pin a specific model or add a name:

src/agent.ts
const agent = await ReactiveAgents.create()
.withName("my-first-agent")
.withProvider("anthropic")
.withModel("claude-sonnet-4-6")
.build();
const result = await agent.run("What are the three laws of thermodynamics?");
console.log("Output:", result.output);
console.log("Duration:", result.metadata.duration, "ms");
console.log("Steps:", result.metadata.stepsCount);
Terminal window
bun run src/agent.ts

The canonical composition path is a HarnessProfile preset — lean(), balanced(), or intelligent(). Presets compose the registry’s default-on capability set so you don’t pile up redundant .withX() calls.

src/agent.ts
import { ReactiveAgents, HarnessProfile } from "reactive-agents";
const agent = await ReactiveAgents.create()
.withName("research-agent")
.withProvider("anthropic")
.withModel("claude-sonnet-4-6")
.withProfile(HarnessProfile.balanced()) // memory + RI + verifier + strategy switching
.build();

Pick the preset that matches the workload:

  • HarnessProfile.lean() — model + nothing else. Latency- and cost-sensitive paths; benchmark ablations.
  • HarnessProfile.balanced() — today’s production defaults (memory + reactive intelligence + verifier + strategy switching).
  • HarnessProfile.intelligent() — balanced + skill persistence for cross-session compounding learning.

Override one capability after the preset — order matters; later calls win:

const agent = await ReactiveAgents.create()
.withName("research-agent")
.withProvider("anthropic")
.withModel("claude-sonnet-4-6")
.withProfile(HarnessProfile.balanced())
.withMemory({ tier: "enhanced" }) // upgrade memory to vector embeddings
.compose((h) => h.before("act", logFn)) // canonical chokepoint composition
.build();

Individual .withX() methods still work for backward compatibility, but most are now @deprecated aliases for either a HarnessProfile preset or a .compose(...) chokepoint. Check the JSDoc on a method to see which preset / compose primitive it routes to.