Agent-readable docs index: /llms.txt. Full docs in one file: /llms-full.txt. Download /docs.zip to grep all markdown files locally.

Read-only code mode

Code mode gives an AI client one extra tool, stackyapper_run_code. Instead of calling tools one at a time and reading every response, the client writes a short JavaScript script. The script calls your connected apps, filters and combines the results, and returns only the summary. One code-mode run can replace a dozen tool calls, and the model reads kilobytes instead of megabytes.
Code mode is a beta. Stackyapper enrolls workspaces individually; it is not a self-service setting. To ask for access, contact support. After enrollment, refresh or reconnect your AI client so it sees the new tool.

When to use it

Use code mode when a question needs several reads or more data than you want in the conversation:
  • Across apps: "Which companies have open Priority 1 tickets and offline servers?"
  • Paging: count or group every alert, not just the first page.
  • Filtering and summarizing: return totals by status instead of 300 raw records.
For a single lookup, such as one ticket or one user, call the tool directly. It is simpler and just as fast.

What it can and cannot do

Code mode is read-only. Scripts can only discover tools and call read tools, through the same authorization, app connections, and audit trail as direct calls:
  • The script runs as the person using the AI client, with exactly their permissions in the current workspace.
  • Create, update, delete, and execute tools are rejected before they reach the app.
  • Every call the script makes is checked, audited, and counted like the same call made directly.
  • Scripts have no network access, credentials, files, packages, timers, or storage. They see only the results Stackyapper returns to them.
  • Reads that need confirmation can't be confirmed from a script. Run those directly.
Access is checked again on every call. If a workspace admin turns off an app or tool while a script runs, the next call to it returns ok: false. If code mode access is removed, the run stops and its result is withheld.

Writing a script

A script is the body of an async function. Use await and end with return. The returned value, converted to JSON, is the result. A script pasted inside a single Markdown code fence is accepted as-is.
Scripts use a tools object:
CallWhat it does
tools.search({ query })Find tools by describing the task.
tools.schemas({ tool_names })Get the exact arguments for tools you found. Each schema includes a TypeScript-style signature.
tools.connections({ service })List connections for an app when there is more than one.
tools.call({ tool_name, arguments, connection_id })Run a read tool. connection_id is only needed when an app has several connections.
Every call resolves to one of two shapes. Branch on ok:
const result = await tools.call({ tool_name: 'cw_get_ticket', arguments: { ticketId: 42 } }); if (!result.ok) { // result.error = { code, message, retryable } return { ticket: null, unavailable: result.error.message }; } return { summary: result.data.summary, status: result.data.status?.name };
  • { ok: true, data }: data is the tool's result.
  • { ok: false, error: { code, message, retryable } }: the call failed, but the script keeps running. Treat that source as unavailable, not empty.
Common error codes include tool_unavailable (the tool doesn't exist or isn't available to you), tool_call_timeout (the app didn't answer in time), and the app's own error codes.

Signatures

tools.schemas returns each tool's JSON Schema plus a compact signature, for example:
(args: { after?: string; pageSize?: number; sourceType?: string }) => { alerts: unknown[]; pagination: { next_page_token: string | null; complete: boolean; upstream_count: number; returned_count: number } }
Optional arguments end in ?. Don't invent tool names or arguments. Search, then read the schema.

Logging

console.log, info, warn, error, and debug work. Output is returned with the result, including when a script fails, which makes a failed script easy to fix. It is never stored.

Examples

Page through every result

Tools that page their results return a pagination object. Keep calling with next_page_token until it is null, and say whether you got everything:
const alerts = []; let after; do { const page = await tools.call({ tool_name: 'ninja_list_alerts', arguments: after ? { pageSize: 100, after } : { pageSize: 100 }, }); if (!page.ok) return { counted: alerts.length, complete: false, error: page.error.message }; alerts.push(...page.data.alerts); after = page.data.pagination.next_page_token; } while (after); const bySource = {}; for (const alert of alerts) bySource[alert.sourceType] = (bySource[alert.sourceType] ?? 0) + 1; return { total: alerts.length, complete: true, bySource };

Combine two apps and report partial results

const [tickets, alerts] = await Promise.all([ tools.call({ tool_name: 'cw_search_tickets', arguments: { conditions: 'closedFlag=false AND priority/name contains "Priority 1"', pageSize: 50 }, }), tools.call({ tool_name: 'ninja_list_alerts', arguments: { pageSize: 100 } }), ]); return { openP1Tickets: tickets.ok ? tickets.data.length : null, activeAlerts: alerts.ok ? alerts.data.pagination.upstream_count : null, unavailable: [tickets, alerts].filter((r) => !r.ok).map((r) => r.error.message), };
Calls run one at a time, even inside Promise.all, and every call must be awaited before the script returns. Matching records across apps needs a shared identifier. Names that look alike are not proof that two records are the same company or device.

Limits

LimitValue
Script size16 KiB
Tool calls per run12 (including search and schema calls)
Time per tool call20 seconds, always leaving 2 seconds for the script to finish
Time per run30 seconds
Tool results read per run1 MiB in total
Returned result64 KiB. Larger results are truncated and marked truncated.
Memory16 MiB
Runs at the same time2 per workspace
Runs per day500 per workspace, resetting at midnight UTC
Return summaries, not raw records. If a result is truncated, the response includes the beginning of the JSON as result_preview and says it is incomplete.

When a run stops

A run stops early only when it hits a limit, access changes, or the script itself fails. The error says why, gives the run ID, and includes any console output. Calls that already finished may have happened; nothing is retried automatically.
ReasonWhat to do
The script failed at line NFix the error shown. Syntax errors are reported the same way.
More than 12 tool callsUse larger pages or fewer searches.
Passed the 30-second limitMake fewer or faster calls, or split the work into two runs.
Tool results passed 1 MiBRequest smaller pages or fewer fields.
Used its work budget or memorySimplify loops over large results, or keep fewer values.
Returned before awaiting every callawait every tools call, or await Promise.all(...).
Code mode is busy in this workspaceTwo runs are already in progress. Try again shortly.
Today's limit reachedThe workspace has used its 500 runs for today (UTC).

Usage and privacy

For each run, Stackyapper records operational details: when it ran, whether it completed or why it stopped, how many calls it made, how long they took, how many bytes were read and returned, the names of the tools called, and the CPU time it used. Stackyapper does not store your script, its arguments, the data it read, its logs, or its result. These records are kept for up to 90 days, and a workspace's run records are deleted with the workspace.
The tool calls a script makes are recorded in your workspace's audit log like direct calls. Code mode has no separate charge.