# @grackle-ai/runtime-claude-code

<p align="center">
  <a href="https://www.npmjs.com/package/@grackle-ai/runtime-claude-code"><img src="https://img.shields.io/npm/v/@grackle-ai/runtime-claude-code.svg" alt="npm version" /></a>
  <a href="https://github.com/nick-pape/grackle/actions/workflows/ci.yml"><img src="https://github.com/nick-pape/grackle/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI" /></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a>
</p>

<p align="center">
  <img src="https://raw.githubusercontent.com/nick-pape/grackle/main/apps/docs-site/static/img/grackle-logo.png" alt="Grackle" width="200" />
</p>

Grackle runtime that drives Anthropic's Claude Code agent via the Claude Agent SDK.

## Overview

This package implements the `@grackle-ai/runtime-sdk` `AgentRuntime` interface for Claude Code. It exports `ClaudeCodeRuntime`, which extends `BaseAgentRuntime` and is registered with the PowerLine process under the runtime name `claude-code`. When a session is spawned, the runtime drives a Claude Code conversation through the [`@anthropic-ai/claude-agent-sdk`](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) `query()` API, maps the SDK's streaming messages onto Grackle `AgentEvent`s (text, tool use, tool results, system, errors, usage), and reports token/cost usage back to the server.

The Claude Agent SDK is **not** a direct dependency. It is installed lazily at spawn time into an isolated per-runtime directory and imported dynamically (falling back to the legacy `@anthropic-ai/claude-code` package if present), so the package stays lightweight until a Claude Code session actually runs.

## Models

The model is chosen per session — Grackle passes the model selected for the task (via the spawn request) straight through to the SDK as the `model` option. This package does not hardcode or restrict the model list; any model the installed Claude Agent SDK accepts can be used.

## Credentials

The runtime authenticates using whatever credentials the Claude Agent SDK finds in its environment. Either path works:

| Credential          | How it's provided                          | Notes                                            |
| ------------------- | ------------------------------------------ | ------------------------------------------------ |
| Anthropic API key   | `ANTHROPIC_API_KEY` environment variable   | Console / pay-per-use access                     |
| Claude subscription | `~/.claude/.credentials.json` (OAuth file) | Generated by signing in with the Claude Code CLI |

Grackle delivers the credential to the PowerLine at task start, so nothing needs to be baked into the environment ahead of time. If `~/.claude` is read-only (common with bind-mounted host config in Docker), the runtime redirects session storage to a writable fallback directory and copies the credential/settings files so multi-turn conversations can still resume.

## Behavior

- **Persistent process mode** — keeps a single `query()` alive across turns using the SDK's async-iterable prompt mode, falling back to resume-per-input when persistence is unavailable.
- **Tools** — enables Claude Code's built-in tools (Bash, Read, Write, Edit, Glob, Grep, WebSearch, WebFetch, Task, Agent, NotebookEdit) and any MCP servers configured for the session, including the injected Grackle MCP server.
- **Usage tracking** — converts the SDK's cumulative token and cost totals into per-turn deltas before reporting them.
- **System context** — injected via the SDK-native `systemPrompt` (appended to Claude Code's built-in prompt), and caller-supplied hooks (e.g. Stop hooks) are passed through unchanged.

## Requirements

- Node.js >= 22
- `@anthropic-ai/claude-agent-sdk` (installed automatically at spawn time)
- An Anthropic API key (`ANTHROPIC_API_KEY`) **or** Claude subscription credentials (`~/.claude/.credentials.json`)

## License

MIT
