Skip to content

nevescloud/claude-agent-driver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

claude-agent-driver

A tiny, transport-agnostic kernel for driving the local Claude CLI on your subscription through the Claude Agent SDK's query() — no API key. You bring the transport (an HTTP server, a WebSocket, a CLI) and the turn-control (session pooling, single-shot); this owns the two pieces every integration ends up rewriting:

  • buildOptions(fields) → assemble the query() Options: the Claude Code preset prompt with your system as an append (or a fully custom systemPrompt), mcpServers, allowedTools / disallowedTools, permissionMode, includePartialMessages.

  • mapMessage(msg, state) → normalize the SDK's message stream into a flat event stream:

    event from fields
    session system/init sessionId
    text streamed text_delta (or non-streaming fallback) text
    tool_use assistant id, name, input
    tool_result user id, name, result, isError
    result result text, subtype, isError, sessionId, costUsd, numTurns, usage, durationMs, errors

That's it — pooling, resume, streaming-input queues, and abort/interrupt stay in your app, where they differ per transport.

Install

npm i @nevescloud/claude-agent-driver

Requires the claude CLI installed and logged in (claude runs on your subscription; the SDK reads the same credentials).

Use

Single-turn (string prompt, no pooling) — streamTurn:

import { streamTurn } from '@nevescloud/claude-agent-driver';

let answer = '';
for await (const ev of streamTurn({
  prompt: 'Summarize the repo README.',
  system: 'Be concise.',                 // appended to the Claude Code preset
  permissionMode: 'dontAsk',             // run pre-approved tools, deny the rest, never prompt
  mcpServers: { mytools: { type: 'http', url: 'http://127.0.0.1:8771/mcp' } },
  allowedTools: ['mcp__mytools'],
})) {
  if (ev.type === 'text') process.stdout.write(ev.text);   // live typing
  else if (ev.type === 'tool_result') console.log('\n[tool]', ev.name, ev.result);
  else if (ev.type === 'result') answer = ev.text;         // durable final text
}

Pooled / streaming-input — assemble options and map messages around your own long-lived query() loop:

import { query, buildOptions, mapMessage, newState, userMessage } from '@nevescloud/claude-agent-driver';

const q = query({ prompt: myStreamingInput, options: buildOptions({ system, permissionMode: 'bypassPermissions' }) });
const state = newState();
for await (const msg of q) {
  for (const ev of mapMessage(msg, state)) { /* ... */ }
}

resolveClaudeBin() resolves the operator's own claude for version parity (pass to pathToClaudeCodeExecutable).

API

export what
streamTurn({ prompt, ...optionFields, queryFn? }) single-turn async generator of normalized events
buildOptions(fields) build the query() Options object
mapMessage(msg, state) generator: one SDK message → zero or more flat events
newState() per-turn state for mapMessage
userMessage(text) the streaming-input user message shape
resolveClaudeBin(envOverride?) resolve the claude binary path
query re-export of the Agent SDK's query

License

MIT

About

Transport-agnostic kernel for driving local Claude via the Claude Agent SDK query() — option-builder + message→event normalizer

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors