playbook/outfitter-agents/plugins/outfitter/skills/claude-commands/references/sdk-integration.md

8.0 KiB

SDK Integration Reference

Guide to using slash commands with the Claude Agent SDK.

Overview

Custom slash commands are fully accessible through the Claude Agent SDK, enabling programmatic invocation and integration into automated workflows.


Discovering Commands

Commands are listed in the system initialization message:

TypeScript

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Hello",
  options: { maxTurns: 1 }
})) {
  if (message.type === "system" && message.subtype === "init") {
    console.log("Available commands:", message.slash_commands);
    // Example: ["/compact", "/clear", "/help", "/review", "/deploy"]
  }
}

Python

import asyncio
from claude_agent_sdk import query

async def main():
    async for message in query(
        prompt="Hello",
        options={"max_turns": 1}
    ):
        if message.type == "system" and message.subtype == "init":
            print("Available commands:", message.slash_commands)

asyncio.run(main())

Invoking Commands

Send commands as prompt strings:

TypeScript

import { query } from "@anthropic-ai/claude-agent-sdk";

// Basic invocation
for await (const message of query({
  prompt: "/review",
  options: { maxTurns: 3 }
})) {
  if (message.type === "assistant") {
    console.log("Review:", message.message);
  }
}

// With arguments
for await (const message of query({
  prompt: "/fix-issue 123",
  options: { maxTurns: 5 }
})) {
  if (message.type === "result") {
    console.log("Fixed:", message.result);
  }
}

Python

async def main():
    # Basic invocation
    async for message in query(
        prompt="/review",
        options={"max_turns": 3}
    ):
        if message.type == "assistant":
            print("Review:", message.message)

    # With arguments
    async for message in query(
        prompt="/fix-issue 123",
        options={"max_turns": 5}
    ):
        if message.type == "result":
            print("Fixed:", message.result)

Enabling Filesystem Settings

By default, the SDK doesn't read filesystem settings. Enable them explicitly:

TypeScript

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "/my-custom-command",
  options: {
    maxTurns: 3,
    settingSources: ['user', 'project', 'local']  // Enable filesystem
  }
})) {
  // Process results
}

Python

async for message in query(
    prompt="/my-custom-command",
    options={
        "max_turns": 3,
        "setting_sources": ["user", "project", "local"]
    }
):
    # Process results

Setting Sources:

  • user - Personal settings (~/.claude/)
  • project - Project settings (.claude/)
  • local - Local overrides

Built-in Commands

/compact

Summarize conversation history to reduce context:

for await (const message of query({
  prompt: "/compact",
  options: { maxTurns: 1 }
})) {
  if (message.type === "system" && message.subtype === "compact_boundary") {
    console.log("Compacted");
    console.log("Pre-tokens:", message.compact_metadata.pre_tokens);
  }
}

/clear

Start fresh conversation:

for await (const message of query({
  prompt: "/clear",
  options: { maxTurns: 1 }
})) {
  if (message.type === "system" && message.subtype === "init") {
    console.log("Cleared, new session:", message.session_id);
  }
}

Workflow Automation

Sequential Commands

Chain commands for multi-step workflows:

async function developmentWorkflow(featureName: string) {
  // Step 1: Create branch
  for await (const msg of query({
    prompt: `/create-branch ${featureName}`,
    options: { maxTurns: 3 }
  })) {
    // Handle branch creation
  }

  // Step 2: Implement feature
  for await (const msg of query({
    prompt: `/implement ${featureName}`,
    options: { maxTurns: 10 }
  })) {
    // Handle implementation
  }

  // Step 3: Create PR
  for await (const msg of query({
    prompt: "/create-pr",
    options: { maxTurns: 3 }
  })) {
    // Handle PR creation
  }
}

Conditional Execution

Execute commands based on results:

async function deployIfTestsPass() {
  let testsPass = false;

  for await (const msg of query({
    prompt: "/run-tests",
    options: { maxTurns: 5 }
  })) {
    if (msg.type === "result" && msg.result.includes("All tests passed")) {
      testsPass = true;
    }
  }

  if (testsPass) {
    for await (const msg of query({
      prompt: "/deploy staging",
      options: { maxTurns: 5 }
    })) {
      // Handle deployment
    }
  }
}

Error Handling

Command Not Found

for await (const msg of query({
  prompt: "/nonexistent-command",
  options: { maxTurns: 1 }
})) {
  if (msg.type === "error") {
    console.error("Command error:", msg.error);
  }
}

Timeout Handling

import { query } from "@anthropic-ai/claude-agent-sdk";

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 60000);

try {
  for await (const msg of query({
    prompt: "/long-running-command",
    options: { maxTurns: 10 },
    signal: controller.signal
  })) {
    // Process messages
  }
} finally {
  clearTimeout(timeout);
}

SlashCommand Tool

Claude can programmatically invoke commands via the SlashCommand tool:

Enabling

Commands with description are automatically available to the SlashCommand tool.

Disabling

Prevent automatic invocation:

---
description: Interactive deployment (manual only)
disable-model-invocation: true
---

Character Budget

Control how many command descriptions fit in context:

export SLASH_COMMAND_TOOL_CHAR_BUDGET=30000  # Default: 15000

Integration Patterns

CI/CD Pipeline

// GitHub Actions integration
async function runCodeQuality() {
  const results = [];

  for await (const msg of query({
    prompt: "/lint && /test && /security-check",
    options: { maxTurns: 10 }
  })) {
    if (msg.type === "result") {
      results.push(msg.result);
    }
  }

  return results;
}

Chatbot Integration

// Slack/Discord bot
async function handleUserCommand(userMessage: string) {
  if (userMessage.startsWith("/")) {
    for await (const msg of query({
      prompt: userMessage,
      options: { maxTurns: 5 }
    })) {
      if (msg.type === "assistant") {
        await sendToChannel(msg.message);
      }
    }
  }
}

Batch Processing

// Process multiple items
async function batchReview(files: string[]) {
  for (const file of files) {
    for await (const msg of query({
      prompt: `/review-file ${file}`,
      options: { maxTurns: 3 }
    })) {
      if (msg.type === "result") {
        await saveReview(file, msg.result);
      }
    }
  }
}

Best Practices

1. Enable Settings Explicitly

Always specify which settings to load:

options: {
  settingSources: ['user', 'project', 'local']
}

2. Handle All Message Types

Check for various response types:

for await (const msg of query({ prompt: "/command" })) {
  switch (msg.type) {
    case "assistant":
      // Claude's response
      break;
    case "result":
      // Command result
      break;
    case "error":
      // Error occurred
      break;
    case "system":
      // System message
      break;
  }
}

3. Set Appropriate Timeouts

Long-running commands need timeout handling:

options: {
  maxTurns: 10,
  timeout: 120000  // 2 minutes
}

4. Use maxTurns Appropriately

Simple commands need fewer turns:

// Simple lookup
options: { maxTurns: 1 }

// Standard operation
options: { maxTurns: 3 }

// Complex workflow
options: { maxTurns: 10 }

Resources