---
title: Claude Agent SDK
description: "Use beliefs with the Anthropic Claude Agent SDK. Automatic belief extraction from agent turns."
---

## Hooks Adapter (recommended)

```bash
npm i beliefs
```

The adapter integrates with the Claude Agent SDK's hook system. It captures tool results via `PostToolUse` hooks and injects belief context at `SessionStart`:

```ts
import { query } from '@anthropic-ai/claude-agent-sdk'
import Beliefs from 'beliefs'
import { beliefsHooks } from 'beliefs/claude-agent-sdk'

const beliefs = new Beliefs({
  apiKey: process.env.BELIEFS_KEY,
  agent: 'research-agent',
  namespace: 'claude-sdk',
  writeScope: 'thread',
})

// Pass hooks to the Claude Agent SDK query options
const result = await query({
  prompt: 'Research the competitive landscape for AI dev tools',
  options: {
    hooks: beliefsHooks(beliefs),
  },
})
```

`beliefsHooks` registers:
- **`SessionStart`:** calls `beliefs.before()` and injects context via `additionalContext`
- **`PostToolUse`:** calls `beliefs.after(toolResult, {tool})` for each tool invocation

If the client is thread-scoped, `beliefsHooks()` resolves the thread automatically from Claude's `session_id` by default.

### Capture Modes

```ts
beliefsHooks(beliefs, { capture: 'tools' })    // each tool call result (default)
beliefsHooks(beliefs, { capture: 'all' })      // tool results + text responses
```

### Configuration

```ts
beliefsHooks(beliefs, {
  capture: 'all',
  includeContext: true,
  toolFilter: 'search|Read',  // regex to filter which tools trigger extraction
})
```

| Option | Default | Description |
|--------|---------|-------------|
| `capture` | `'tools'` | What to extract beliefs from |
| `includeContext` | `true` | Inject belief context at session start |
| `toolFilter` | — | Regex matched against tool names. Example: `'search\|Read'` extracts only from search and Read; internal tools like `Bash` would be skipped. |
| `resolveThreadId` | `input.session_id` | Override how thread IDs are derived. Pass a `(input) => threadId` function when your thread keying differs from Claude's session id (e.g., per-user threads). |

<Callout type="warning" title="Don't mix manual calls with hooks">
When you use `beliefsHooks(...)`, the adapter owns the lifecycle: `SessionStart` calls `before()`, `PostToolUse` calls `after()`. Calling `beliefs.before()` or `beliefs.after()` yourself in the same query produces duplicate extraction and double-counts evidence. Use one path or the other, not both.
</Callout>

<Callout type="info" title="Choosing a scope">
Use `writeScope: 'thread'` when each Claude session should keep its own memory. Use `writeScope: 'space'` when all sessions in a namespace should share one state.
</Callout>

---

## Without the adapter (manual `before`/`after`)

If you're not using the Claude Agent SDK's hook system (for example, you're using `@anthropic-ai/sdk` directly), wrap your calls manually:

```ts
import Anthropic from '@anthropic-ai/sdk'
import Beliefs from 'beliefs'

const client = new Anthropic()
const beliefs = new Beliefs({
  apiKey: process.env.BELIEFS_KEY,
  agent: 'research-agent',
  namespace: 'claude-sdk',
  writeScope: 'space',
})

async function research(question: string) {
  const context = await beliefs.before(question)

  const message = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 4096,
    system: context.prompt,
    messages: [{ role: 'user', content: question }],
  })

  const text = message.content
    .filter(b => b.type === 'text')
    .map(b => b.text)
    .join('')

  const delta = await beliefs.after(text)
  return { text, delta }
}
```

### With tool results

Feed each tool result separately so beliefs update mid-turn:

```ts
const context = await beliefs.before(question)

const message = await client.messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 4096,
  system: context.prompt,
  messages: [{ role: 'user', content: question }],
  tools: myTools,
})

for (const block of message.content) {
  if (block.type === 'tool_use') {
    const result = await executeTool(block.name, block.input)
    await beliefs.after(JSON.stringify(result), { tool: block.name })
  } else if (block.type === 'text') {
    await beliefs.after(block.text)
  }
}
```

### Multi-turn loop

Run multiple turns and let clarity drive when to stop:

```ts
async function deepResearch(question: string) {
  for (let turn = 0; turn < 10; turn++) {
    const context = await beliefs.before(question)

    if (context.clarity > 0.8) {
      return context.beliefs
    }

    const message = await client.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 4096,
      system: context.prompt,
      messages: [{ role: 'user', content: question }],
    })

    const text = message.content
      .filter(b => b.type === 'text')
      .map(b => b.text)
      .join('')

    await beliefs.after(text)
  }
}
```

<CardGroup cols={2}>
  <DocsCard title="Patterns" description="Common integration patterns with the core SDK." href="/dev/sdk/patterns" />
  <DocsCard title="Hack Guide" description="Quick framework recipes for hackathons." href="/dev/tutorial/hack-guide" />
</CardGroup>
