Live package

@stacksona/sdk

Gate one exact action without rebuilding the request, review, revision, proof, and execution loop yourself.

Fast path

  1. 1
    Install.

    npm install @stacksona/sdk

  2. 2
    Create a client.

    Use your Gate URL and sg_ agent API key.

  3. 3
    Wrap the real side effect.

    runGatedAction calls it only after Gate allows or approves the exact request.

Gate an action

ts
import { StacksonaGateClient } from '@stacksona/sdk';

const gate = new StacksonaGateClient({
  baseUrl: process.env.STACKSONA_GATE_URL!,
  apiKey: process.env.STACKSONA_API_KEY!,
});

const { decision, executed, result } = await gate.runGatedAction(
  'refund-order-8821',
  {
    tool_name: 'issue_refund',
    subject: 'Refund order #8821',
    risk_level: 'high',
    payload: { order_id: '8821', amount: 500, currency: 'usd' },
  },
  async (_decision, request) => issueRefund(request.payload),
);

if (!executed) console.log(`Action stopped: ${decision.status}`);
What the SDK handles

It sends the Gate request, follows the exact review thread, returns requested changes as actionable state, fails closed on unexpected states, and only invokes your callback after allow or approved. The request payload is snapshotted so the callback receives the JSON Gate evaluated.

Reviewer requests changes

Add reviseAction when your runtime can revise a proposal. The revision is submitted on the same thread_id and the SDK continues following that review.

ts
await gate.runGatedAction(taskId, request, executeTool, {
  reviseAction: async ({ decision, request }) => ({
    tool_name: request.tool_name,
    subject: request.subject ?? 'Revised action',
    request_payload: await reviseWithAgent(
      request.payload,
      decision.modification?.requested_changes,
    ),
  }),
});

Signed approval proof

ts
await gate.runGatedAction(
  taskId,
  { tool_name: 'deploy_production', payload: deployArgs },
  async (_decision, request) => deploy(request.payload),
  { validateSignedApprovalToken: true },
);

An approved review without required proof, or token validation with valid: false, fails closed.

Methods

MethodPurpose
resolveTools(tools)Resolve registered names, descriptions, and input schemas.
logEvent(taskId, event)Append timeline evidence.
requestDecision(taskId, input)Evaluate one exact proposed tool call.
getDecision(query)Read a review by thread or task.
listDecisions(query)List recent pending or completed reviews.
pollDecision(query, options)Wait for approved, rejected, or changes requested.
requestDecisionAndPoll(taskId, input, options)Request and automatically wait on human review.
submitRevision(taskId, threadId, revision)Submit requested changes on the same review thread.
validateApprovalToken(input)Validate and consume one-time approval proof.
runGatedAction(taskId, input, action, options)Own the normal Gate lifecycle for one action.

Dynamic tools

ts
const { tools, unregistered } = await gate.resolveTools([
  'issue_refund',
  'send_customer_email',
]);

Use the returned exact tool contracts when the runtime builds its model tool list dynamically.

Manual durable flow

When your app already has a queue or durable resume mechanism, use requestDecision and persist the returned thread_id, then resume with getDecision or pollDecision.

Package version

@stacksona/sdk 0.3.0 · Node.js 18+