Skip to content

Instantly share code, notes, and snippets.

@twilson63
Created February 15, 2026 13:49
Show Gist options
  • Select an option

  • Save twilson63/a6431dfffb17115d518c2e3b8bb6b42c to your computer and use it in GitHub Desktop.

Select an option

Save twilson63/a6431dfffb17115d518c2e3b8bb6b42c to your computer and use it in GitHub Desktop.
OpenClaw Scout Atoms API Skill

API Schema Reference

Full JSON Schema for the AtomRequest, CacheDirective, and AgentConfig objects.

AtomRequest

{
  "type": "object",
  "required": ["atoms", "instructions"],
  "properties": {
    "atoms": {
      "type": "object",
      "description": "Schema definitions for each atom type. Keys are atom type names. Values are JSON Schema objects.",
      "additionalProperties": {
        "type": "object",
        "additionalProperties": true
      }
    },
    "instructions": {
      "type": "string",
      "description": "Free-form text instructions for the agent. Can include markdown, code blocks, structured examples."
    },
    "context": {
      "type": "object",
      "description": "Product-defined context for cache granularity. Platform injects org_id and user_id from session.",
      "additionalProperties": true
    },
    "cache": {
      "$ref": "#/$defs/CacheDirective",
      "description": "Client-controlled caching directives"
    },
    "tools": {
      "type": "array",
      "items": { "type": "string" },
      "description": "DEPRECATED: Use agent.tools instead."
    },
    "agent": {
      "$ref": "#/$defs/AgentConfig",
      "description": "Agent configuration overrides"
    }
  }
}

AgentConfig

{
  "type": "object",
  "properties": {
    "model": {
      "anyOf": [
        { "type": "string" },
        { "type": "array", "items": { "type": "string" } },
        { "type": "null" }
      ],
      "default": null,
      "description": "LLM model name or ordered list of model names. First is primary, rest are fallbacks. Provider derived from name. Default: 'claude-sonnet-4-5'."
    },
    "temperature": {
      "anyOf": [{ "type": "number" }, { "type": "null" }],
      "default": null,
      "description": "LLM temperature. Default: 0.3."
    },
    "max_tokens": {
      "anyOf": [{ "type": "integer" }, { "type": "null" }],
      "default": null,
      "description": "Maximum output tokens per LLM call. Default: 32000."
    },
    "tools": {
      "anyOf": [
        { "type": "array", "items": { "type": "string" } },
        { "type": "null" }
      ],
      "default": null,
      "description": "Tool names to enable for the agent. Default: []."
    }
  }
}

CacheDirective

{
  "type": "object",
  "properties": {
    "read": {
      "type": "boolean",
      "default": true,
      "description": "Read from cache if available and fresh"
    },
    "write": {
      "type": "boolean",
      "default": true,
      "description": "Write generated atoms to cache"
    },
    "maxStale": {
      "type": "integer",
      "default": 86400,
      "description": "Maximum staleness in seconds (default: 86400 = 24h)"
    },
    "revalidate": {
      "type": "boolean",
      "default": false,
      "description": "Serve cached then stream refresh (SWR mode)"
    }
  }
}

Model Providers

Model provider is derived from the model name:

Model Prefix Provider
claude-* Anthropic
gpt-* OpenAI
gemini-* Google

Default Values

  • model: "claude-sonnet-4-5"
  • temperature: 0.3
  • max_tokens: 32000
  • tools: []
  • cache.read: true
  • cache.write: true
  • cache.revalidate: false
  • cache.maxStale: 86400 (24 hours)

Basic Atom Generation

Simple request to generate summaries from context.

curl Example

curl -X POST https://api.scoutos.com/atoms \
  -H "Authorization: Bearer $SCOUTOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "atoms": {
      "task": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "description": "Unique task ID" },
          "title": { "type": "string", "description": "Task title" },
          "priority": { "type": "string", "enum": ["high", "medium", "low"] },
          "due": { "type": "string", "description": "ISO 8601 due date" }
        },
        "required": ["id", "title", "priority", "due"]
      }
    },
    "instructions": "Generate 3-5 example tasks for a software engineer's daily standup.",
    "context": {
      "page": "standup",
      "date": "2026-02-15"
    }
  }'

JavaScript/TypeScript Example

const response = await fetch('https://api.scoutos.com/atoms', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.SCOUTOS_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    atoms: {
      task: {
        type: 'object',
        properties: {
          id: { type: 'string', description: 'Unique task ID' },
          title: { type: 'string', description: 'Task title' },
          priority: { type: 'string', enum: ['high', 'medium', 'low'] },
          due: { type: 'string', description: 'ISO 8601 due date' }
        },
        required: ['id', 'title', 'priority', 'due']
      }
    },
    instructions: 'Generate 3-5 example tasks for a software engineer.',
    context: { page: 'standup', date: '2026-02-15' }
  })
});

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  
  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split('\n');
  buffer = lines.pop()!;
  
  for (const line of lines) {
    if (line.startsWith('event: atom')) {
      // Next line will have data
    }
    if (line.startsWith('data: ')) {
      const atom = JSON.parse(line.slice(6));
      console.log('Received atom:', atom);
    }
  }
}

Expected Output

event: atom
data: {"atom_type":"task","data":{"id":"t-1","title":"Review PR #1234","priority":"high","due":"2026-02-15"}}

event: atom
data: {"atom_type":"task","data":{"id":"t-2","title":"Update API documentation","priority":"medium","due":"2026-02-16"}}

event: atom
data: {"atom_type":"task","data":{"id":"t-3","title":"Fix login bug from yesterday","priority":"high","due":"2026-02-15"}}

event: done
data: {"status":"complete","cached":0,"generated":3,"from_store":false}
name description
scout-atoms
Interact with the Scout Atoms API for real-time structured data generation via SSE streaming. Use when you need to generate structured data (atoms) with schemas and instructions, fetch real-time data from integrations (Salesforce, Google Calendar, web search), or implement streaming data feeds. Provides commands for discovering tools, generating atoms, and handling SSE streams with SWR caching support.

Scout Atoms

Product-agnostic atom generation engine. Send JSON schemas and instructions, receive structured data as a real-time SSE stream. The API doesn't know what product it powers — you define the shape, it fills it.

Quick Start

1. Set API Key

export SCOUTOS_API_KEY="secret_..."

Get your key from scoutos.com → Settings → API Keys.

2. Discover Available Tools

scout-atoms discover

Returns available integrations (Salesforce, Google Calendar, web search, etc.).

3. Generate Atoms

scout-atoms generate --instructions "Generate today's meetings" \
  --schema 'meeting: {"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"time":{"type":"string"}},"required":["id","title","time"]}'

Or use a request file:

scout-atoms generate --file request.json

Key Concepts

Atoms

Atoms are structured data objects emitted by an AI agent. You define the schema (JSON Schema), provide instructions, and the agent generates atoms matching your schema. Each atom MUST have an id field.

Schema-First Design

  • Frontend defines atom shapes as JSON Schema
  • Schemas sent in every request
  • No hardcoded types in backend
  • Change schemas without deploys

SSE Streaming

Response is text/event-stream format. Atoms arrive progressively:

event: atom
data: {"atom_type":"meeting","data":{"id":"m-1","title":"Team Sync","time":"10:00"}}

event: done
data: {"status":"complete","cached":0,"generated":1}

Event Types

Event When Key Fields
atom Per generated atom atom_type, data, source?, action?
cache_complete SWR cache phase ends count, max_stale
done Always last status, cached, generated
error On failure message

Caching Modes

Mode read write revalidate Behavior
Default true true false Serve cache if fresh, else generate
No-cache false false false Ephemeral, don't store
Force refresh false true false Generate fresh, cache result
SWR true true true Serve cached, then stream refresh

SWR (Stale-While-Revalidate)

Two-phase streaming:

  1. Cache phase: Atoms with source: "cache" — instant delivery
  2. cache_complete event marks transition
  3. Refresh phase: Atoms with source: "refresh" and action:
    • "add" — New atom
    • "update" — Changed atom (same id, new data)
    • "remove" — Deleted atom (only id in data)

Request Structure

{
  "atoms": {
    "meeting": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "title": { "type": "string" },
        "time": { "type": "string" }
      },
      "required": ["id", "title", "time"]
    }
  },
  "instructions": "Generate today's meetings.",
  "context": {
    "page": "dashboard",
    "date": "2026-02-15"
  },
  "cache": {
    "read": true,
    "write": true,
    "revalidate": true,
    "maxStale": 86400
  },
  "agent": {
    "model": "claude-sonnet-4-5",
    "temperature": 0.3,
    "tools": ["google_calendar__read_events"]
  }
}

Required fields: atoms, instructions

Optional fields: context, cache, agent

Context & Cache Keys

The context dict controls cache granularity:

  • Platform injects org_id and user_id
  • Add fields like page, date, account_id to scope caching
  • More fields = more specific cache = fresher but fewer hits

Integration Tools

Discover with scout-atoms discover. Tool names follow {Toolbox}__{tool}:

Prefix Description
Salesforce__* CRM queries, record ops
scout_search_tools__* Web search, scrape
google_calendar__* Calendar events
scout_knowledge__* Knowledge base
scout_documents__* Document processing
deno__* Custom code execution

Include in agent.tools array. Platform always enables myla__emit_atoms.

Commands

scout-atoms discover

List available integration tools for your organization.

scout-atoms discover [--json]

scout-atoms generate

Generate atoms from schemas and instructions.

scout-atoms generate \
  --instructions "Generate today's tasks" \
  --schema 'task: {"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"priority":{"type":"string"}},"required":["id","name"]}' \
  [--tools "scout_search_tools__search_and_scrape"] \
  [--context '{"page":"tasks"}'] \
  [--cache '{"revalidate":true}'] \
  [--output atoms.json]

Or from a file:

scout-atoms generate --file request.json [--output atoms.json]

scout-atoms validate

Validate atom schemas against the AtomRequest schema.

scout-atoms validate --file request.json

Examples

See examples/ directory for complete examples:

  • basic-request.json — Simple atom generation
  • swr-request.json — Stale-while-revalidate
  • multi-tool-request.json — Using Salesforce + Calendar
  • streaming-client.js — JavaScript SSE client

API Reference

Authentication

All requests require Bearer token:

Authorization: Bearer $SCOUTOS_API_KEY

Endpoints

Method Path Description
GET /tools Discover available tools
POST /atoms Generate atoms (SSE stream)
GET /atoms/docs/schema.json AtomRequest JSON Schema

Base URL

https://api.scoutos.com

Error Handling

  • error event is terminal — stream ends after it
  • Invalid atoms are logged but still emitted (graceful degradation)
  • Tool connection status delivered at stream start

Key Principles

  1. Frontend owns schemas — Change shapes without backend deploys
  2. Backend is product-agnostic — No hardcoded atom types
  3. IDs are required — Every atom needs stable id for dedup/SWR
  4. Progressive rendering — Stream atoms as they arrive
  5. Validate but don't crash — Bad atoms logged, stream continues

Further Reading

SSE Parsing Pattern

Robust SSE stream parsing for the Atoms API.

Full SSE Parser Implementation

interface SSEEvent {
  event: string;
  data: any;
}

interface AtomEvent {
  atom_type: string;
  data: any;
  source?: 'cache' | 'refresh';
  action?: 'add' | 'update' | 'remove';
}

async function* parseAtomsStream(
  response: Response
): AsyncGenerator<SSEEvent> {
  const reader = response.body!.getReader();
  const decoder = new TextDecoder();
  let buffer = '';
  let pendingEvent = '';
  let pendingData = '';

  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      const lines = buffer.split('\n');
      buffer = lines.pop()!; // Keep incomplete line in buffer

      for (const line of lines) {
        if (line.startsWith('event:')) {
          pendingEvent = line.slice(6).trim();
        } else if (line.startsWith('data:')) {
          pendingData = line.slice(5).trim();
        } else if (line === '' && pendingData) {
          // Empty line dispatches accumulated event
          yield {
            event: pendingEvent,
            data: JSON.parse(pendingData)
          };
          pendingEvent = '';
          pendingData = '';
        }
      }
    }
  } finally {
    reader.releaseLock();
  }
}

// Usage
async function subscribe(
  request: AtomRequest,
  onAtom: (atom: AtomEvent) => void,
  onDone: (stats: { cached: number; generated: number }) => void,
  onError: (message: string) => void
): Promise<void> {
  const controller = new AbortController();
  
  const response = await fetch('https://api.scoutos.com/atoms', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.SCOUTOS_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(request),
    signal: controller.signal
  });

  if (!response.ok) {
    const error = await response.text();
    onError(error);
    return;
  }

  for await (const { event, data } of parseAtomsStream(response)) {
    switch (event) {
      case 'atom':
        onAtom(data);
        break;
      case 'cache_complete':
        console.log(`Cache delivered ${data.count} atoms`);
        break;
      case 'done':
        onDone(data);
        break;
      case 'error':
        onError(data.message);
        break;
    }
  }
}

React Hook Example

function useAtoms<T extends Record<string, any>>(
  request: AtomRequest | null
) {
  const [state, setState] = useState<T>({} as T);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const abortRef = useRef<AbortController | null>(null);

  useEffect(() => {
    if (!request) return;

    const controller = new AbortController();
    abortRef.current = controller;
    setIsLoading(true);
    setError(null);

    (async () => {
      try {
        const response = await fetch('https://api.scoutos.com/atoms', {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${process.env.SCOUTOS_API_KEY}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(request),
          signal: controller.signal
        });

        for await (const { event, data } of parseAtomsStream(response)) {
          if (event === 'atom') {
            setState(prev => ({
              ...prev,
              [data.atom_type]: [...(prev[data.atom_type] || []), data.data]
            }));
          }
          if (event === 'done') {
            setIsLoading(false);
          }
          if (event === 'error') {
            setError(data.message);
            setIsLoading(false);
          }
        }
      } catch (err) {
        if (err instanceof Error && err.name !== 'AbortError') {
          setError(err.message);
          setIsLoading(false);
        }
      }
    })();

    return () => controller.abort();
  }, [request]);

  const refetch = useCallback(() => {
    abortRef.current?.abort();
    setState({} as T);
    setIsLoading(true);
  }, []);

  return { state, isLoading, error, refetch };
}

Cancellation

Always support abort for cleanup:

const controller = new AbortController();

// On unmount or refetch:
controller.abort();

// This terminates the SSE stream and releases resources

SWR Implementation

Stale-While-Revalidate pattern with SSE parsing.

Request with SWR

{
  "atoms": {
    "meeting": {
      "type": "object",
      "properties": {
        "id": { "type": "string", "description": "Meeting ID" },
        "title": { "type": "string", "description": "Meeting subject" },
        "start_time": { "type": "string", "description": "ISO 8601 start" },
        "end_time": { "type": "string", "description": "ISO 8601 end" },
        "attendees": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "email": { "type": ["string", "null"] }
            },
            "required": ["name"]
          }
        }
      },
      "required": ["id", "title", "start_time", "end_time", "attendees"]
    }
  },
  "instructions": "Generate today's meetings from the calendar.",
  "context": { "page": "schedule", "date": "2026-02-15" },
  "cache": {
    "read": true,
    "write": true,
    "revalidate": true,
    "maxStale": 86400
  },
  "agent": {
    "tools": ["google_calendar__read_events"]
  }
}

SWR State Handler

interface AtomState {
  meetings: Map<string, Meeting>;
  isRefreshing: boolean;
  isComplete: boolean;
}

function handleAtom(state: AtomState, event: string, data: any): AtomState {
  if (event === 'atom') {
    const { atom_type, data: atom, source, action } = data;
    
    if (atom_type === 'meeting') {
      const meetings = new Map(state.meetings);
      
      // Default action is "add" for non-SWR or cache phase
      const effectiveAction = action ?? 'add';
      
      switch (effectiveAction) {
        case 'add':
        case 'update':
          meetings.set(atom.id, atom);
          break;
        case 'remove':
          meetings.delete(atom.id);
          break;
      }
      
      return { ...state, meetings, isRefreshing: source === 'refresh' };
    }
  }
  
  if (event === 'cache_complete') {
    // Cache phase done, refresh phase starting
    return { ...state, isRefreshing: true };
  }
  
  if (event === 'done') {
    return { ...state, isRefreshing: false, isComplete: true };
  }
  
  return state;
}

SSE Stream Phases

Phase 1: Cache (instant)

event: atom
data: {"atom_type":"meeting","data":{"id":"m-1",...},"source":"cache"}

event: atom
data: {"atom_type":"meeting","data":{"id":"m-2",...},"source":"cache"}

event: cache_complete
data: {"count":2,"max_stale":86400}

UI shows cached meetings immediately (0 latency).

Phase 2: Refresh (background)

event: atom
data: {"atom_type":"meeting","data":{"id":"m-3",...},"source":"refresh","action":"add"}

event: atom
data: {"atom_type":"meeting","data":{"id":"m-1","title":"Updated Title",...},"source":"refresh","action":"update"}

event: atom
data: {"atom_type":"meeting","data":{"id":"m-2"},"source":"refresh","action":"remove"}

event: done
data: {"status":"complete","cached":2,"generated":1,"from_store":true}

UI updates progressively as refresh arrives.

Client-Side Cache Layer (Optional)

// On page mount: hydrate from localStorage
function loadClientCache(context: object): AtomState | null {
  const key = JSON.stringify(context);
  const stored = localStorage.getItem(`atoms:${key}`);
  return stored ? JSON.parse(stored) : null;
}

// On stream complete: persist state
function saveClientCache(context: object, state: AtomState) {
  const key = JSON.stringify(context);
  localStorage.setItem(`atoms:${key}`, JSON.stringify(state));
}

Tool Discovery and Selection

Find and use integration tools dynamically.

Discover Available Tools

curl -s -H "Authorization: Bearer $SCOUTOS_API_KEY" \
  https://api.scoutos.com/tools | jq '.available[] | {name: .tool_name, desc: .description}'

Output

{
  "name": "scout_search_tools__search_and_scrape",
  "desc": "Search the web and retrieve page content"
}
{
  "name": "Salesforce__salesforce_query",
  "desc": "Query Salesforce objects and fields"
}
{
  "name": "google_calendar__read_events",
  "desc": "Read events from Google Calendar"
}

Tool Selection Pattern

Match tools to use case:

interface UseCase {
  page: string;
  suggestedTools: string[];
}

const USE_CASE_MAP: Record<string, UseCase> = {
  'pipeline-dashboard': {
    page: 'pipeline',
    suggestedTools: ['Salesforce__salesforce_query']
  },
  'daily-briefing': {
    page: 'briefing',
    suggestedTools: [
      'google_calendar__read_events',
      'scout_search_tools__search_and_scrape'
    ]
  },
  'research-assistant': {
    page: 'research',
    suggestedTools: [
      'scout_search_tools__search_and_scrape',
      'scout_knowledge__search'
    ]
  }
};

async function selectTools(useCase: string): Promise<string[]> {
  const response = await fetch('https://api.scoutos.com/tools', {
    headers: { 'Authorization': `Bearer ${process.env.SCOUTOS_API_KEY}` }
  });
  const { available, unavailable } = await response.json();
  
  const suggested = USE_CASE_MAP[useCase]?.suggestedTools ?? [];
  const availableNames = available.map(t => t.tool_name);
  
  // Filter to only available tools
  return suggested.filter(t => availableNames.includes(t));
}

Request with Tools

{
  "atoms": {
    "opportunity": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "name": { "type": "string" },
        "amount": { "type": "number" },
        "stage": { "type": "string" },
        "close_date": { "type": "string" }
      },
      "required": ["id", "name", "amount", "stage", "close_date"]
    }
  },
  "instructions": "Query Salesforce for open opportunities in the pipeline. Group by stage. Show deals likely to close this quarter.",
  "context": { "page": "pipeline", "quarter": "Q1-2026" },
  "agent": {
    "tools": ["Salesforce__salesforce_query"]
  }
}

Handling Unavailable Tools

function buildRequest(
  discoveredTools: { available: Tool[]; unavailable: Tool[] },
  useCase: string
): AtomRequest {
  const requested = USE_CASE_MAP[useCase]?.suggestedTools ?? [];
  const availableNames = discoveredTools.available.map(t => t.tool_name);
  
  const missing = requested.filter(t => !availableNames.includes(t));
  
  if (missing.length > 0) {
    console.warn(`Tools not connected: ${missing.join(', ')}`);
    // Note in instructions that some data sources are unavailable
  }
  
  return {
    atoms: { /* schemas */ },
    instructions: `Generate pipeline data. Note: ${missing.length > 0 ? `Data from ${missing.join(', ')} not available.` : 'All data sources connected.'}`,
    agent: {
      tools: requested.filter(t => availableNames.includes(t))
    }
  };
}

Toolbox Integration Guide

Detailed reference for working with integration tools.

Available Toolboxes

Toolbox Prefix Capabilities
Salesforce Salesforce__* CRM queries, field discovery, record operations
Search Tools scout_search_tools__* Web search and page scraping
Google Calendar google_calendar__* Read events, availability
Knowledge scout_knowledge__* Knowledge base search and retrieval
Collections scout_collections__* Data collection operations
Documents scout_documents__* Document processing and extraction
Deno deno__* Custom code execution

Tool Discovery Flow

1. GET /tools → List all tools
2. Filter by toolbox prefix for relevant capabilities
3. Read input_schema for each tool → Understand parameters
4. Check authorization status → Know what's connected
5. Select tools for use case → Request in agent.tools

Tool Schema Structure

Each tool from GET /tools includes:

{
  "tool_name": "Salesforce__salesforce_query",
  "tool_cname": "Salesforce Query",
  "description": "Query Salesforce objects and fields",
  "input_schema": {
    "type": "object",
    "properties": {
      "object": { "type": "string", "description": "Object type (e.g., 'Opportunity')" },
      "fields": { "type": "array", "items": { "type": "string" } },
      "where": { "type": "string", "description": "SOQL WHERE clause" }
    },
    "required": ["object", "fields"]
  },
  "labels": ["crm", "sales"],
  "authorization": "connected"
}

Common Tool Patterns

Web Search

{
  "agent": {
    "tools": ["scout_search_tools__search_and_scrape"]
  },
  "instructions": "Search for recent news about the company and summarize key developments."
}

CRM Data

{
  "agent": {
    "tools": [
      "Salesforce__salesforce_query",
      "Salesforce__salesforce_describe"
    ]
  },
  "instructions": "Query Salesforce for open opportunities closing this quarter."
}

Calendar Integration

{
  "agent": {
    "tools": ["google_calendar__read_events"]
  },
  "instructions": "Generate today's meeting schedule from the user's calendar."
}

Multi-Source

{
  "agent": {
    "tools": [
      "Salesforce__salesforce_query",
      "google_calendar__read_events",
      "scout_search_tools__search_and_scrape"
    ]
  },
  "instructions": "Build a daily briefing: calendar events, pipeline update, and relevant news."
}

Authorization Status

When requesting tools, the agent startup includes status messages:

  • connected – Tool ready to use
  • not_connected – Integration not set up (user needs to connect in Settings → Integrations)

Always handle unavailable tools gracefully:

  • Skip that data source
  • Fall back to alternatives
  • Note the limitation in output

Platform Tool: emit_atoms

The platform always enables myla__emit_atoms (or similar internal name) — this is how agents output atoms. You never need to request it explicitly.

Tool Naming Convention

{Toolbox}__{tool_name}

Examples:
- Salesforce__salesforce_query
- scout_search_tools__search_and_scrape
- google_calendar__read_events

The toolbox prefix indicates the integration source. Use it to filter related capabilities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment