@getstackrun/sdk
v0.4.1
Published
Official JavaScript/TypeScript SDK for STACK - the runtime control plane for AI agents
Downloads
570
Maintainers
Readme
@getstackrun/sdk
Official JavaScript / TypeScript SDK for STACK - the runtime control plane for AI agents.
This package is also the target for our
@getstack/sdkscope claim (pending). Once settled,@getstackrun/sdkwill be deprecated with a pointer to the new name.
STACK sits between your agent and everything it touches. Short-lived, scoped passports replace long-lived API keys. Every outbound call routes through a proxy that enforces scope and parameter constraints. A hash-chained audit log records every decision. A single call kills any passport globally in under 60 seconds.
Install
npm install @getstackrun/sdkRequires Node.js 18 or newer. Works in Deno, Bun, and browsers via native fetch.
Quick start
Sign in once on your machine — the SDK reads credentials from ~/.stack/credentials.json automatically:
npx -y @getstackrun/cli auth loginimport { Stack } from '@getstackrun/sdk';
// No constructor args — reads ~/.stack/credentials.json (OAuth refresh token).
// Falls back to STACK_API_KEY env var or constructor { apiKey } for CI.
const stack = new Stack();
// 1. Register an agent (one-time)
const agent = await stack.agents.register({ name: 'support-bot' });
// 2. In your agent runtime, switch to per-agent keypair mode
const agentStack = new Stack({ agent_id: agent.id });
// First run: generates an Ed25519 keypair locally + enrolls the public
// half via /v1/agents/<id>/enroll. Persisted at ~/.stack/agents/<id>.json
// (mode 0600). Every subsequent call signs a fresh 60-second JWT.
// 3. Issue a short-lived scoped passport
const passport = await agentStack.passports.issue({
agent_id: agent.id,
intent: {
summary: 'Answer one customer ticket',
services: ['slack', 'github'],
estimated_duration_seconds: 900,
},
ttl_seconds: 900,
});
// 4. Every outbound call routes through the proxy
await agentStack.proxy.request({
service: 'slack',
method: 'POST',
url: 'https://slack.com/api/chat.postMessage',
body: { channel: 'C0123', text: 'Ticket resolved' },
passport_token: passport.token,
});
// 5. Revoke when done (or let the passport expire)
await agentStack.passports.revoke(passport.jti, 'mission complete');Authentication
Three sources, resolved in priority order:
- Explicit
apiKeyon the constructor orSTACK_API_KEYenv var (legacysk_live_*path, preserved for CI) agent_idoption (Phase 2) — every request signed with the agent's local keypair~/.stack/credentials.json— OAuth refresh token written bystack-cli auth login
See /docs/security/stack-auth for the full auth model and /docs/security/agent-keys for the per-agent keypair story.
Offline passport verification
Downstream services that only need cryptographic validity (no revocation awareness) can verify a passport using the public JWKS — no network round-trip to STACK per request.
import { verifyPassportOffline } from '@getstackrun/sdk';
// Mode 1: fetch JWKS once per process
const claims = await verifyPassportOffline(token, {
jwksUrl: 'https://api.getstack.run/v1/.well-known/jwks.json',
});
// Mode 2: fully air-gapped with a pre-fetched public key
const claims2 = await verifyPassportOffline(token, {
publicJwk: { kty: 'OKP', crv: 'Ed25519', x: '...', kid: 'stack-passport-v1', alg: 'EdDSA', use: 'sig' },
});For revocation-aware verdicts, combine with a short cache against POST /v1/passports/verify or subscribe to the stack:revoked Redis pub/sub channel.
What the SDK wraps
| Service | Typical use |
|---|---|
| stack.agents | Register, list, update, delete agents |
| stack.passports | Issue, verify, delegate, refresh, revoke |
| stack.services | Connect OAuth / custom credentials, grant agent access |
| stack.credentials | Retrieve decrypted credentials (agent-side) |
| stack.proxy | Make outbound HTTP calls; scope + constraints enforced server-side |
| stack.dropoffs | Schema-validated, encrypted agent-to-agent data transfer |
| stack.skills | Publish + invoke marketplace skills |
| stack.identity | Verification sessions, claims, providers |
| stack.team | Team members, roles, scoped API keys |
| stack.deliveryMethods | Email, SMS, webhook destinations |
| stack.notifications | Rules mapping events to destinations |
| stack.securityEvents | List, resolve real-time detector signals |
A handful of endpoints (audit export, chain-head, verify-chain, billing) are not yet wrapped — call them via fetch using the same API key. See docs/api.
Error handling
Every error is a StackError subclass with a stable machine code.
import { Stack, StackError, PassportRevokedError, InsufficientCreditsError } from '@getstackrun/sdk';
try {
await stack.passports.verify(token);
} catch (err) {
if (err instanceof PassportRevokedError) {
// issue a fresh passport
} else if (err instanceof StackError) {
console.error(err.code, err.statusCode, err.message);
}
}Full catalog: docs/reference/errors.
Documentation
- Getting started: https://getstack.run/docs/getting-started
- Concepts: https://getstack.run/docs/concepts/passports
- API reference: https://getstack.run/docs/api/passports
- MCP tools (alternative to the SDK): https://getstack.run/docs/mcp-tools
License
MIT
