stillrunning-claude-agent-sdk
v0.1.0
Published
One-line monitoring for the Claude Agent SDK. Wrap query() and auto-ping StillRunning on every agent run with duration, tokens, cost, model, and tool-call count.
Maintainers
Readme
stillrunning-claude-agent-sdk
One-line monitoring for the Claude Agent SDK. Wrap query() and every agent run auto-reports to StillRunning with its duration, tokens, cost, model, and tool-call count, and fires an alert the moment a run fails, runs too long, or costs too much.
import { query } from '@anthropic-ai/claude-agent-sdk'
import { stillrunning } from 'stillrunning-claude-agent-sdk'
const sr = stillrunning() // reads STILLRUNNING_TOKEN
const monitoredQuery = sr.wrap(query)
for await (const message of monitoredQuery({ prompt: 'fix the failing test' })) {
// use messages exactly as before , a ping fires automatically when the run completes
}That's the whole integration. monitoredQuery is a drop-in for query: same arguments, same message stream, same control methods (interrupt(), setPermissionMode(), …). It just watches the run go by.
Install
npm install stillrunning-claude-agent-sdkThe Claude Agent SDK is your dependency; this package wraps the query you already import, so there's nothing to keep in version lockstep.
Setup
- Create a workflow at stillrunning.ai/app/new and copy its ping token.
- Set
STILLRUNNING_TOKEN(or passstillrunning({ token })). - Wrap
queryonce and use it everywhere.
What it captures
On completion the wrapper reads the Claude Agent SDK's final result message and pings StillRunning with:
| Field | Source |
| --- | --- |
| success / fail | result.subtype (error_* or is_error → fail) |
| duration | result.duration_ms |
| cost | result.total_cost_usd (the SDK's own number) |
| tokens in / out | result.usage (input + cache reads/writes, and output) |
| model | the dominant model in result.modelUsage |
| tool calls | counted from the tool_use blocks in the run |
| turns, session id, terminal reason | sent as metadata |
A run that throws mid-stream pings fail with the error message, then the error rethrows untouched. A failed run still reports the tokens and cost it burned before failing.
Grouping multi-step agents
Wrap several runs in withTrace so they share one traceId and stitch into a single outcome chain in StillRunning:
import { stillrunning, withTrace } from 'stillrunning-claude-agent-sdk'
const sr = stillrunning()
const query = sr.wrap(baseQuery)
await withTrace(async () => {
for await (const _ of query({ prompt: 'plan the work' })) {}
for await (const _ of query({ prompt: 'execute step 1' })) {}
}) // both runs share one traceIdConfiguration
stillrunning({
token, // ping token; defaults to process.env.STILLRUNNING_TOKEN
baseUrl, // defaults to https://stillrunning.ai
computeCost, // ({ model, inputTokens, outputTokens }) => number , override the SDK's cost
awaitPing, // default true; false = fire-and-forget (lowest latency)
pingTimeoutMs, // default 3000
onError, // (err) => void , observe ping delivery failures
fetch, // custom fetch (testing / non-global-fetch runtimes)
})Monitoring never throws into your code: a failed ping routes to onError and is otherwise swallowed, bounded by pingTimeoutMs so a slow StillRunning never hangs your agent. Messages stream through unchanged.
Requirements
Node 18+. Claude Agent SDK as a peer (you already have it). Ships ESM + CJS with TypeScript types.
License
MIT
