SDK

Node / generic

The stillrunningpackage monitors any async job, agent, or script. Wrap a function and StillRunning gets a ping on success or failure with the run's duration, plus optional cost, tokens, and model. Framework-agnostic, works with Claude Code scripts, LangChain, CrewAI, cron jobs, queue workers, anything.

On the Vercel AI SDK? Use stillrunning-vercel-ai-sdk instead, it auto-extracts tokens and cost for you.

Install

terminal
npm install stillrunning

30-second quickstart

1. Create a workflow at stillrunning.ai/app/new and copy its token. 2. Set STILLRUNNING_TOKEN. 3. Wrap your work:

job.ts
import { stillrunning } from 'stillrunning'

const sr = stillrunning() // reads STILLRUNNING_TOKEN

await sr.run(() => runNightlyImport())

run times the function, pings success when it resolves, pings failwith the error message if it throws (then rethrows it untouched), and returns the function's result.

Attaching AI metrics

Pass meta, statically or derived from the result. Give model plus token counts and cost is estimated automatically from a built-in pricing table:

agent.ts
const answer = await sr.run(() => callMyAgent(prompt), {
  meta: (result) => ({
    tokensIn: result.usage.inputTokens,
    tokensOut: result.usage.outputTokens,
    model: result.model,      // -> costUsd estimated automatically
    toolCalls: result.steps.length,
  }),
})

Wrapping a function

wrap returns a monitored version with the same signature:

wrap.ts
const syncCustomer = sr.wrap(rawSyncCustomer)
await syncCustomer('acme') // every call is monitored

Heartbeats and manual pings

For a cron job that just needs to say "I ran", or when the work can't be wrapped in one function:

manual.ts
await sr.heartbeat()                        // bare success ping
await sr.ping({ event: 'start', traceId }) // low-level: success | fail | start | log

Grouping multi-step runs

Wrap several runs in withTrace so they share one traceId and stitch into a single outcome chain:

trace.ts
import { stillrunning, withTrace } from 'stillrunning'
const sr = stillrunning()

await withTrace(async () => {
  await sr.run(() => stepOne())
  await sr.run(() => stepTwo())
}) // both pings share one traceId

Configuration

options.ts
stillrunning({
  token,         // ping token; defaults to process.env.STILLRUNNING_TOKEN
  baseUrl,       // defaults to https://stillrunning.ai
  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 job.

Requirements

Node 18+ (or any runtime with fetch and AsyncLocalStorage).

You're set

Open your dashboard to watch runs land with duration, cost, and anomaly alerts.

Open dashboard
stillrunning

Heartbeat monitoring for AI workflows and agent scripts.

Product

Company

Legal

© 2026 StillRunning. All rights reserved.
hello@stillrunning.ai