Skip to main content
The Playbooks API lets you trigger playbook executions from your code and monitor their progress. This is useful for integrating NimbleBrain automations into your existing workflows, CI/CD pipelines, or custom applications.

Overview

Working with playbooks involves two main operations:
  1. Execute - Trigger a playbook to run
  2. Monitor - Check the execution status and get results
Playbook.execute() → Execution ID → Poll for status → Get result

Playbooks

List Playbooks

Retrieve all playbooks in your workspace:
const playbooks = await nb.playbooks.list();

for (const playbook of playbooks) {
  console.log(`${playbook.name} (${playbook.id})`);
  console.log(`  Description: ${playbook.description}`);
}
Response type:
interface Playbook {
  id: string;
  name: string;
  description?: string;
  createdAt?: string;
  updatedAt?: string;
}

Execute a Playbook

Trigger a playbook execution:
const { id: executionId } = await nb.playbooks.execute(playbookId);
console.log(`Execution started: ${executionId}`);
The execute() method returns immediately with an execution ID. The playbook runs asynchronously in the background. With parameters: If your playbook accepts input parameters:
const { id: executionId } = await nb.playbooks.execute(playbookId, {
  ticker: 'AAPL',
  period: 'weekly',
});
Response type:
interface ExecutePlaybookResponse {
  id: string;
  status: 'queued';
  message?: string;
}

Executions

Get Execution Status

Check the current status of an execution:
const execution = await nb.executions.get(executionId);

console.log(`Status: ${execution.status}`);
console.log(`Duration: ${execution.durationMs}ms`);

if (execution.status === 'completed') {
  console.log('Result:', execution.result);
}
Response type:
interface Execution {
  id: string;
  status: 'queued' | 'pending' | 'running' | 'completed' | 'completed_with_errors' | 'failed' | 'cancelled';
  targetType?: 'playbook' | 'agent';
  targetId?: string;
  targetName?: string;
  result?: string | Record<string, unknown> | null;
  startedAt?: string;
  completedAt?: string;
  durationMs?: number;
}

Execution Status Values

StatusDescription
queuedExecution is waiting to start
pendingExecution is being prepared
runningExecution is in progress
completedExecution finished successfully
completed_with_errorsExecution finished but encountered non-fatal errors
failedExecution failed
cancelledExecution was cancelled

Wait for Completion

The SDK provides a helper method that polls until the execution completes:
const execution = await nb.executions.waitForCompletion(executionId, {
  timeoutMs: 120000,     // Maximum wait time (2 minutes)
  pollIntervalMs: 2000,  // Check every 2 seconds
});

if (execution.status === 'completed') {
  console.log('Success! Result:', execution.result);
} else {
  console.log(`Execution ended with status: ${execution.status}`);
}
Options:
OptionTypeDefaultDescription
timeoutMsnumber60000Maximum time to wait in milliseconds
pollIntervalMsnumber1000Interval between status checks
If the execution doesn’t complete within timeoutMs, the method throws a timeout error. The execution continues running - only the waiting stops.

Complete Example: Playbook Runner

Here’s a complete script that runs a playbook and displays the result:
import { NimbleBrain } from '@nimblebrain/sdk';

async function runPlaybook(playbookName: string) {
  const nb = new NimbleBrain({
    apiKey: process.env.NIMBLEBRAIN_API_KEY!,
  });

  // Find the playbook by name
  const playbooks = await nb.playbooks.list();
  const playbook = playbooks.find((p) => p.name === playbookName);

  if (!playbook) {
    console.error(`Playbook not found: ${playbookName}`);
    console.log('Available playbooks:');
    playbooks.forEach((p) => console.log(`  - ${p.name}`));
    return;
  }

  console.log(`Executing: ${playbook.name}`);
  console.log(`ID: ${playbook.id}`);
  console.log('---');

  // Execute the playbook
  const { id: executionId } = await nb.playbooks.execute(playbook.id);
  console.log(`Execution ID: ${executionId}`);

  // Show progress while waiting
  const startTime = Date.now();
  let lastStatus = '';

  const checkStatus = async () => {
    const exec = await nb.executions.get(executionId);
    if (exec.status !== lastStatus) {
      const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
      console.log(`[${elapsed}s] Status: ${exec.status}`);
      lastStatus = exec.status;
    }
    return exec;
  };

  // Poll until complete
  let execution = await checkStatus();
  while (!['completed', 'completed_with_errors', 'failed', 'cancelled'].includes(execution.status)) {
    await new Promise((resolve) => setTimeout(resolve, 2000));
    execution = await checkStatus();
  }

  // Display result
  console.log('\n--- Result ---');
  console.log(`Final status: ${execution.status}`);
  console.log(`Duration: ${execution.durationMs}ms`);

  if (execution.result) {
    console.log('\nOutput:');
    if (typeof execution.result === 'string') {
      console.log(execution.result);
    } else {
      console.log(JSON.stringify(execution.result, null, 2));
    }
  }
}

// Run from command line: npx ts-node run-playbook.ts "My Playbook Name"
const playbookName = process.argv[2];
if (!playbookName) {
  console.error('Usage: npx ts-node run-playbook.ts "Playbook Name"');
  process.exit(1);
}

runPlaybook(playbookName);

CI/CD Integration Example

Run a playbook as part of your deployment pipeline:
import { NimbleBrain } from '@nimblebrain/sdk';

async function notifyDeployment(environment: string, version: string) {
  const nb = new NimbleBrain({ apiKey: process.env.NIMBLEBRAIN_API_KEY! });

  // Find the deployment notification playbook
  const playbooks = await nb.playbooks.list();
  const notifyPlaybook = playbooks.find((p) => p.name === 'Deployment Notification');

  if (!notifyPlaybook) {
    console.warn('Deployment notification playbook not found, skipping');
    return;
  }

  // Execute with deployment info
  const { id } = await nb.playbooks.execute(notifyPlaybook.id, {
    environment,
    version,
    timestamp: new Date().toISOString(),
  });

  // Wait for completion (with short timeout for CI)
  try {
    const result = await nb.executions.waitForCompletion(id, {
      timeoutMs: 30000,
      pollIntervalMs: 2000,
    });

    if (result.status === 'completed') {
      console.log('Deployment notification sent successfully');
    } else {
      console.warn(`Notification ended with status: ${result.status}`);
    }
  } catch (error) {
    console.warn('Notification timed out, continuing deployment');
  }
}

// Usage in deployment script
notifyDeployment('production', 'v1.2.3');

Error Handling

try {
  const { id } = await nb.playbooks.execute(playbookId);
  const result = await nb.executions.waitForCompletion(id);
} catch (error) {
  if (error instanceof Error) {
    if (error.message.includes('timed out')) {
      console.error('Playbook took too long to complete');
    } else if (error.message.includes('404')) {
      console.error('Playbook not found');
    } else {
      console.error('Execution failed:', error.message);
    }
  }
}

Best Practices

Set Appropriate Timeouts

Know how long your playbooks typically take and set timeouts accordingly

Handle All Statuses

Check for failed and completed_with_errors in addition to completed

Log Execution IDs

Always log execution IDs for debugging. You can look them up in Studio.

Don't Block Critical Paths

For non-critical notifications, use fire-and-forget pattern