MCP App Store
by KeenEthics
Developer Tools
Outside Agent icon

Outside Agent

by Outside Agent

Overview

Outside Agent turns a plain-language brief into a hosted AI agent you can publish to SMS, voice, and web without leaving your coding agent. Describe what the agent should do and it composes the full configuration, grounds it in your own content, runs a safety review, and ships it. Create agents, seed a knowledge base, preview replies before publishing, issue a phone number, and manage everything you’ve built, all through natural conversation.

Tools

addAllowedNumber

ChatGPT
Add an E.164 phone number to a PRIVATE agent's allow-list — the texters/callers (and signed-in web phone identities) allowed to reach it. The OWNER is always allowed and need not be listed. Idempotent (a duplicate returns the existing entry). label is an optional owner-facing note (e.g. "Spouse"). No effect on a public agent.

addCapabilityEval

ChatGPT
Add a re-runnable unit test for ONE capability step — a persisted { input -> expected } case, scored 0..1 when run. Pass agentId and eval: { capabilityInstanceId, name, input, expected }. capabilityInstanceId comes from listEvalTargets. input is the step's input — a command payload (e.g. an enum-classifier's { variables: {...} }), a knowledge-base { query }, or a composer { message }. expected is one of: { kind: 'deterministic', matcher: { mode: 'equals'|'contains'|'regex', path?, value } } (exact/structural, scores 0 or 1); { kind: 'judge', modality: 'text'|'image', criteria } (a model grades the output 0..1 against the prose criterion); or { kind: 'tool-selection', expect: [tools], forbid: [tools] } (the composer must call expect and must not call forbid). moduleId and the kind are derived server-side; the input and expectation are validated against the capability. Ideal to seed several at once so a creator can verify a step keeps working across edits. Pass the OPTIONAL intentId to LINK this eval to the behaviorIntents[].id it verifies (it must name a real intent on the agent): a must intent with a linked, passing eval is treated by the publish review as behaviorally covered, and a change that makes that eval fail is BLOCKED as a regression (ADR 0006) — the durable way to keep a requirement working across sessions. Seed a linked eval from the intent's examples (situation → expectedBehavior).

addScenarioEval

ChatGPT
Add a SCENARIO eval — a re-runnable conversation test against the WHOLE agent, not one capability instance. eval.script.turns is a short STATIC script of end-user messages (1..12 { message } turns) dispatched in order on ONE conversation, so later turns see earlier ones as real history; keep each message meaningful regardless of the agent's exact wording in between. eval.expected scores the resulting transcript: { kind: 'judge', modality: 'text', criteria } grades the WHOLE conversation 0..1 against prose criteria (the usual choice), { kind: 'deterministic', matcher } structurally matches the agent's FINAL reply, { kind: 'tool-selection', expect, forbid } set-matches every tool called across ALL turns. Scenario evals are what make persona rules ('never give medical advice') and multi-step flows ('collect name then phone') testable — free-text behavior no capability eval can target. Link eval.intentId to the behaviorIntent the case VERIFIES (validated against the draft) so the Quality report and the ADR-0006 publish gate count it; tag eval.caseTag ('happy' | 'edge' | 'adversarial') so the requirement's RIGOR is honest — a requirement only shows VERIFIED once it has ≥2 tests including an edge or adversarial probe. Returns the persisted eval. Run it with runCapabilityEval (pass the returned id) or as part of runQualitySuite.

askCreator

ChatGPT
Put ONE question straight to the creator and wait for their answer — the live 'grill' step. Pass question and, when the answers are few and known, options (2–6) for a pick list; always recommend an answer in the question text. Use it when you need the creator's decision and can't infer it from the catalog or what they've told you — one question at a time. Returns { elicited: true, answer } when they reply. A live prompt needs a client that supports elicitation on a session-backed connection; when that isn't available the tool returns { elicited: false, note, question } for you to ask the creator directly in chat instead — that is NOT an error. Either way, never answer on the creator's behalf for a decision that's theirs.

builderHealth

ChatGPT
Report this build server's health and WHICH publish-gate judge it runs: { ok, judge: "gemini" | "fake" | "unknown", knowledgeTextSeeding: "available" | "unavailable-no-embedder", server }. gemini is the real Vertex safety/alignment review; fake is the deterministic stand-in (fine for non-LLM work, but not a real safety verdict). knowledgeTextSeeding reports whether the seedKnowledgeText tool is wired — it needs an embedding indexer (Gemini/Vertex), so when it's unavailable-no-embedder a knowledge-grounded agent CANNOT be seeded or exercised over MCP on this server (check this BEFORE building a KB scenario). Read-only; takes no input.

checkEmailDomain

ChatGPT
Re-check a domain's live DNS/verification status — call this after the creator says they've published the DNS records connectEmailDomain returned. Pass domain. Returns { domain, connected: false } when the creator has never connected this domain (not an error — call connectEmailDomain first, and only when they ask), or { domain, connected: true, status, dnsRecords } with the current status (pending/verifying/verified/failed) and any records still outstanding. For a "list/manage my domains" style ask, point the creator at the dashboard link connectEmailDomain returned rather than enumerating domains here. NOT read-only: it re-triggers provider verification and persists the refreshed status/records/verifiedAt on the domain.

compactAgent

ChatGPT
Read-only LEANNESS report for an already-built agent — coding agents treat every edit as ADDITIVE, so agents accrue dead weight (unreachable capabilities, tables nothing writes to, one-row demo lookups, hardcoded PII, over-declared intents, a near-cap soul) that nothing ever prunes. compactAgent compiles the config and runs the DETERMINISTIC bloat checks (no server LLM, no credit spend), returning { ok, headline, provenSafe, needsReview, proseCompaction, summary, note }. headline is an HONEST computed metric — movingParts, vestigialParts, movingPartsAfterProvenSafe, and promptSurfaceChars (the model-facing prose weight). STRUCTURAL bloat splits into two buckets: provenSafe is PROVABLY-DEAD items whose removal is behavior-neutral (bulk-approvable); needsReview is the judgment-call bucket (looks like bloat but may be intentional/roadmap) to approve one at a time. NOTE: bulk-approve is currently gated until the keep-intentional opt-out ships, so provenSafe is empty for now and every structural prune arrives in needsReview — approve each after confirming it isn't mid-build. Each proposal carries a code, the subjectId it targets, a human summary, and an applyInstruction. proseCompaction is the SEMANTIC pass: a worksheet of the model-facing prose (fields with char weights), the baselineCoveredIntents the baseline already covers, cross-field duplicationHints (near-duplicates by shared significant tokens, so REWORDED restatements are caught, not just byte-identical copies — each carries sharedTokens), and a rubric — YOU (this coding agent) reason over it, dedupe across fields, cut verbosity WITHOUT dropping any distinct instruction, and PROPOSE before→after rewrites to the human; the reasoning is yours, there is no second LLM. When every must-have intent is baseline-covered, note warns that dropping them ALL empties the requirement ledger (REQUIREMENT_LEDGER_THIN) — keep 2–3 terse musts backed by evals instead. compactAgent WRITES NOTHING: apply an approved prune/rewrite through patchAuthoredConfig/setAuthoredConfig (which gate removals behind acknowledgeDrops/acknowledgeRemovals), then ALWAYS re-run reviewAgent — an INTENT_REGRESSION or DROPPED_REQUIREMENT means you cut something load-bearing, so revert it. Run it after publish, or whenever an agent has grown across many edits.

connectEmailDomain

ChatGPT
OPT-IN — only call this when the creator EXPLICITLY asks to send their agents' outbound email FROM their own domain (e.g. "mail.acme.com") instead of the platform's default sending inbox. Do NOT proactively suggest it. Pass domain. Returns { domain, status, dnsRecords, dashboardUrl }: status is one of pending/verifying/verified/failed, dnsRecords are the TXT/CNAME/MX records the creator must publish at their DNS provider — relay them to the creator VERBATIM (type, name, value, and — for MX records — the priority, which DNS providers require as its own field) — and dashboardUrl is the Console page that tracks verification. For a "list/manage my domains" style ask, point the creator at dashboardUrl rather than trying to enumerate their domains here. Calling this again on an already-connected domain is IDEMPOTENT — it just re-checks the live verification state (same as checkEmailDomain). Once status is "verified", use setAgentFromEmail to point an agent's From address at an address on this domain.

convertFlagToEval

ChatGPT
Convert one OPEN flag into a frozen scenario eval (origin: 'flagged') that the quality suite runs forever after (NOT for flags whose correlationId starts eval: — those dispute an existing test's rubric; fix that test and dismissFlag instead): the excerpt's user turns become the scripted conversation (the agent's side replays live each run), and the judge criteria encode the creator's correction. Returns { flag, eval, droppedUserTurns } with the flag resolved 'converted' (droppedUserTurns > 0 means the excerpt had more user turns than the 12-turn script cap and the OLDEST were dropped — tell the creator when that happens). The script replays only the USER side of the conversation; when a user turn was an answer to an agent question, target the BEHAVIOR in the criteria rather than expecting the identical dialogue shape. Inputs: agentId AND flagId (both required; the flag must belong to that agent); OPTIONAL criteria — REFINE THIS rather than accepting the default (the raw note wrapped in a template): state precisely what the agent MUST and MUST NOT have done so the judge scores the behavior, not the wording; OPTIONAL intentId — link the behaviorIntent this case verifies (add the intent first when the flag reveals a requirement the config never had; that closes the 'things I didn't consider' gap AND makes the case count toward the requirement's rigor); OPTIONAL name and caseTag (defaults to 'edge' — a real conversation the battery didn't anticipate). The new eval starts FAILING by construction (the agent just failed it for real) — after converting, fix the config and prove the fix with runQualitySuite. A concurrent conversion of the same flag loses cleanly (no duplicates).

createAgent

ChatGPT
Create a new draft agent for the creator. Provide a name. visibility defaults to public (anyone can chat over web or SMS); pass visibility: "private" to make it reachable ONLY by the owner and the E.164 numbers on its allow-list (a private web visitor must sign in; an un-listed SMS sender is ignored). You can also flip visibility later with setAgentVisibility, and manage access with addAllowedNumber. Returns the agent, including its id — pass that id to setAuthoredConfig and publishAgent. The result also echoes ownerId (the tenant the agent is filed under) and a manageUrl Console deep link, so you can confirm WHERE it landed.

createConversationalAgent

ChatGPT
ONE-CALL macro for a PURE conversational agent that answers the user in a persona, within a safety policy, on some channels. Do NOT use this as the finished shape when the creator provides a fixed list of questions, questionnaire, application, lead form, or intake: use createAgent, fetch the structured-intake recipe, and author the questions in top-level intakeForm so the compiler supplies deterministic extraction and completeness handling. For a plain conversational agent, give name, purpose (what it's for), optionally persona (its tone/voice) and safetyPolicy (boundaries), and channels (defaults to ["web"]). It creates the draft AND sets a complete authored config — you do NOT hand-wire the MessageReceived→ComposeReply→MessageGenerated→SendMessage chat chain or attach a messenger/composer capability; the platform's baseline supplies all of that for an agentic agent. Returns the created agent + the config it set; then simulateBuild / reviewAgent / publishAgent it like any draft. Use setAuthoredConfig or patchAuthoredConfig afterwards to add capabilities, connectors, or reactive rules. (For a NO-LLM fixed-script bot, use createAgent + setAuthoredConfig with replyMode "deterministic" instead.)

createTemplateUploadUrl

ChatGPT
STEP 1 of uploading a large Word (.docx) template for the docx-fill capability WITHOUT inlining its bytes. Prefer this over setting templateBase64 whenever the template is large or dense (a multi-page form, embedded images): a big base64 blob is unreliable to emit verbatim as tool args and bloats every config round-trip. Pass { agentId, filename? }; returns { uploadUrl, storagePath, contentType }. Then, IN YOUR SHELL (the bytes never pass through this tool), upload the local file directly: curl -X PUT -H "Content-Type: <contentType>" --upload-file <local.docx> "<uploadUrl>". The URL is short-lived — upload promptly. Then call registerDocumentTemplate with the returned storagePath to get the template's placeholders and finish wiring. (Small template, or a dev host with no storage bucket where this tool isn't available? Just set templateBase64 on the capability config instead.)

deleteCapabilityEval

ChatGPT
Delete one capability eval (and its run history) — pass evalId. Returns { ok: true }.

deleteKnowledgeSource

ChatGPT
Permanently remove ONE knowledge-base source — and its indexed chunks — from an agent's knowledge base. Pass { agentId, sourceId }, where sourceId is an id from getKnowledgeBase's sources (or a sourceId seedKnowledgeText returned). Use this to CORRECT the base when a fact is disproved or superseded — delete the stale source outright instead of seeding a 'disregard the above' document, which would leave contradictory passages competing in retrieval forever. (seedKnowledgeText already UPSERTS by exact title and gates near-duplicates; reach for delete when there's no clean replacement to re-seed, e.g. dropping a whole obsolete source.) Deleting a FILE source removes the WHOLE file's chunks, not one fact within it. Irreversible — re-seed to restore. No-op-safe: an unknown or already-deleted sourceId (or one on an agent you don't own) returns a not-found error. Returns { ok: true }.

disableConnector

ChatGPT
Remove a connector from the agent (by connectorId). The agent can no longer use that toolkit; existing end-user connections are left untouched.

disableDailySweep

ChatGPT
Delete ONE of this agent's daily sweeps by name (default "daily"). Idempotent — removed: false means no such sweep existed. The agent itself (its rules, connector, inboundHook) is untouched; only that daily wake-up stops. Use listDailySweeps to see the names.

dismissFlag

ChatGPT
Dismiss one OPEN flag without converting it — for a one-off the creator confirms needs no guard (a user typo, a transient outage, behavior that is actually correct). Pass agentId AND flagId (both required; the flag must belong to that agent); returns the resolved flag. Prefer convertFlagToEval when in doubt: a dismissed flag protects nothing, a converted one guards the behavior forever.

enableConnector

ChatGPT
Enable one external connector on the agent so it can act in that third-party app on behalf of the end user. connectorId MUST be a real toolkit id (from listConnectors / getConnector) — an id that doesn't exist in the provider's catalog is rejected, so discover it first instead of guessing. Optionally pass enabledTools (a subset of the connector's tool slugs) to narrow what the agent may call — recommended for large toolkits (check toolCount) so you don't load hundreds of tools into the model. To actually USE the connector in conversation you ALSO need to attach the connector-tool capability in setAuthoredConfig, PIN it to this connectorId, and choose the ownership scope on that instance: end-user (each user OAuths their own account at runtime — today's default) or creator (the agent uses the creator's single shared account, linked once from the agent config page; users can't override it). That per-connector ownership choice DRIVES connector-tool resolution and lives on the connector-tool INSTANCE (scope), so you rarely need bindingPolicy. (bindingPolicy — { default: 'creator'|'none', override: 'forbidden'|'allowed'|'required' } (ADR 0005) — remains only for native binding flows and is NOT what drives connector-tool resolution: default says whether the agent carries a creator-set account (creator) or none; override says whether an end user may bind their own; creator+forbidden LOCKS to the creator's one account, none+required makes every user connect their own, none+forbidden is invalid; omit it for normal toolkits.) CUSTOM HTTP CONNECTOR (no Composio toolkit needed): to call an API Composio does NOT cover — a carrier/AMS REST API, an internal service — OR to POST to a Zapier catch-hook, pass a manifest instead of relying on the catalog: { provider: 'http', baseUrl, auth: { type: 'none'|'bearer'|'header', header? }, tools: [{ name, method, path, params?, body?, responseMap? }] } (auth carries NO secret field — the key is set in the Console, never here). A manifest connector needs NO catalog entry and NO per-end-user OAuth — connectorId is YOUR OWN chosen slug (e.g. 'coastal-ams'), the existence check is SKIPPED, and it is callable as soon as enabled (still attach connector-tool + PIN the id, with scope: 'creator' since a manifest runs as the creator's own credential). In each tool, path may contain {param} placeholders filled from params (a map of name→'string'|'number'|'boolean'); body (write methods) is the JSON body fields; responseMap projects the raw JSON into clean fields for the agent as { outField: '$.json.path' } (tiny JSONPath — $.a.b, $.arr[0].c). CREDENTIAL — for bearer/header auth, DO NOT put a token here: LEAVE secretRef UNSET. A raw API key must NEVER pass through this tool — it would enter your context and the transcript. There is a dedicated WRITE-ONLY Console field for the key, so do NOT ask the creator for a secret NAME, do NOT tell them to set a server/env var, and do NOT hunt for an MCP tool to store the secret (there is none) — the creator types the actual key themselves in the Console (agent Configuration → "Connector API keys") AFTER you author the shape. During the interview just ask the auth TYPE (bearer vs a header name); never ask where the key is stored. Author only the SHAPE (auth: { type: 'bearer' }, or { type: 'header', header: 'X-Api-Key' }) with no secretRef; the connector is then in a PENDING-CREDENTIAL state, and this tool's response returns credentialRequired — RELAY it to the creator: they enter the real key in the Console on the agent's Configuration page, under "Connector API keys", which stores it encrypted and mints the handle. Publish is BLOCKED until the key is set. IMPORTANT — the baseUrl and each tool's catch-hook path ARE creator-specific: when a creator says "post to my Zapier" / "connect my API", ASK for the real hook URL and use it VERBATIM; NEVER invent, guess, or leave a placeholder like /hooks/catch/<id>/<key> — but the API KEY is the one thing you do NOT take here (it goes to the Co…

forceMigrateLiveConversations

ChatGPT
Force the agent's LIVE conversations onto a specific published build NOW — the opt-in override for an urgent or safety fix. By DEFAULT a re-publish does NOT touch conversations already in flight: each one stays pinned to the build it started on and only re-resolves to the latest at its own idle gap or continue-as-new boundary (and even then only if the change is compatible). This tool is the deliberate firehose for when you can't wait for that. Pass { agentId, buildId, mode? } where buildId is the TARGET build (the one you just published — read it from getAgent / the publish result). mode is "compatible-only" (the DEFAULT — safe): a conversation the target build is BREAKING for (it would strand that conversation's accumulated in-flight state) is SKIPPED and reported back, never migrated; only compatible conversations are swapped. mode: "all" is the explicit DATA-LOSS override: it migrates EVERY conversation including breaking ones, and lists each breaking one under dataLossOverrides so the loss is on record — use it only when the fix is more important than the in-flight state. Returns a compatibility report { buildId, total, migrated, skipped, endedOrIdle, skippedReasons: [{ correlationId, reasons }], dataLossOverrides? }: migrated got the swap, skipped were breaking (compatible-only), endedOrIdle had already ended (nothing to migrate — they pick up the latest on their next turn anyway), and skippedReasons explains WHY each was breaking. A migrated conversation swaps forward-only (its future turns use the new build; past events are never re-folded) and surfaces a DefinitionUpgraded event on its next turn.

generateEvalBattery

ChatGPT
Generate the STANDARD BATTERY for behavior intents that don't have one yet: for each intent, the platform writes three scenario evals — a 'happy' path, an 'edge' case, and an 'adversarial' probe (a user actively trying to make the agent violate the requirement) — each linked to its intent, tagged, and persisted with origin: 'generated'. Returns { generated, alreadyGeneratedIntentIds, unknownIntentIds } where generated is the created evals. The battery is FROZEN once COMPLETE: an intent whose generated cases already cover all three tags is SKIPPED (listed in alreadyGeneratedIntentIds), so every config version replays the identical suite and version-to-version score deltas mean the AGENT changed, not the tests. An INCOMPLETE battery (an earlier interrupted write) self-heals: its remnants are replaced with a fresh trio. Delete a generated case to force regeneration. Pass intentIds to scope generation; omit it to cover every intent without a battery. This is what gives every requirement a comparable rigor floor. NOTE: runQualitySuite runs this automatically for every uncovered intent before grading, so you rarely need to call it yourself — use it to write tests WITHOUT grading, or with intentIds to scope regeneration after deleting a case. This spends model credits, so it is credit-gated.

getAgent

ChatGPT
Read one of the creator's agents by id (name, status, slug, visibility). Read-only.

getAgentSpec

ChatGPT
Load an agent's REQUIREMENT LEDGER before you change it — read this FIRST when taking over or editing an existing agent, so you don't regenerate over requirements it already commits to. Returns { purpose, intents, ledgerStatus, unverifiedMustIntentIds, summary }. intents is every recorded behaviorIntent with its priority, its sourceQuote provenance, and a coverage roll-up (how many linked evals, and how many are passing/failing/never-run) — so you see what the agent must do AND which requirements are actually verified. ledgerStatus is healthy (records must-have requirements), thin (has behavior but NO must intent — nothing protects it across edits; call suggestBehaviorIntents to backfill), or empty (a fresh agent). unverifiedMustIntentIds are the must intents with no passing eval — add one with addCapabilityEval (intentId) so a later change can't silently break them. summary gives capability/rule counts + channels for orientation. Pair with getAuthoredConfig for the full config. Read-only.

getAgentTimeline

ChatGPT
Read what a PUBLISHED agent actually DID at runtime — the durable domain events it folded, newest first, across all of its conversations. The investigative companion to getAgent (which shows config): use THIS to see whether a side effect actually happened. Every capability outcome is here — EmailSent vs EmailFailed, CallFailed, PaymentCaptureFailed, etc. — so you can confirm e.g. that an email truly sent rather than trusting the agent's reply text. Input: { agentId, limit? (default 50, max 200), conversationId?, type? (exact, e.g. "EmailFailed"), failuresOnly? (only events whose type ends in "Failed"), since? (ISO instant) }. Returns { agentId, total, matched, returned, truncated, events: [{ id, type, at, source, conversationId, causationId?, failed, payload }] } — payloads are redacted (data: URIs dropped, long strings truncated). failed flags failure events at a glance; truncated means more matched than the page returned (raise limit or filter by conversationId/since). Read-only.

getAuthoredConfig

ChatGPT
Load the agent's COMPLETE current AuthoredConfig — read this BEFORE you edit an already-built agent, so you change it by read-modify-write instead of editing blind. Returns { agentId, name, status, config, instances? } where config is the whole authored document (purpose, audience, soul, capabilities, guidance, reactiveRules, signals, behaviorIntents, channels, escalation, branding, adminViews/adminForms, schedules, connectorTriggers, webWidget, and every other field) exactly as stored, or null for a fresh agent with nothing authored yet. instances maps each attached capability to its compiled instance id ({ id, instanceId }, the same GLOBAL 0-based scheme setAuthoredConfig/lintConfig return). TO EDIT COHERENTLY: (1) call this to get the current config; (2) modify the field(s) you want ON THE RETURNED OBJECT — change one element of an array, tweak one guidance line, add a capability — keeping everything else intact; (3) write it back. For a whole-document edit, pass the modified config to setAuthoredConfig (it OVERWRITES, so send the full object — omitting fields resets them to defaults, which is why you must start from this read, not from memory). For a single top-level field, pass just that field to patchAuthoredConfig (it shallow-replaces that one key and leaves the rest untouched — but since a top-level array is replaced wholesale, resend the WHOLE array you just read with your one element changed). Do NOT rebuild a config from memory: that silently drops capabilities, rules, guidance, and channels you can't see. This config can be LARGE; if you only need orientation (what the agent must do, ledger health, capability/rule counts), read getAgentSpec instead — call getAuthoredConfig when you are about to make a change and need the exact current values. Owner-scoped. Read-only — it authors nothing and costs no model spend.

getCatalog

ChatGPT
Return the BUILT-IN capability catalog (the palette of skills with their ids, config shapes, and examples) so you use real capability ids, not guesses. PREFER getCatalogSummary first — the FULL catalog serializes every module's JSON Schema plus the worked examples and is large enough to exceed an MCP client's per-result token cap. Pass moduleIds: ["<id>", …] to fetch the full JSON Schema for ONLY those modules (discover the ids with getCatalogSummary); omit it only when you truly need the whole palette. For EXTERNAL connectors (Google Calendar, Gmail, a CRM, …), use listConnectors instead — those are enabled separately with enableConnector. Each module also carries the FULL pitfalls it declares — its KNOWN failure modes (code, failureMode, guidance, severity): how the capability is commonly misused and how to avoid it, so you wire it right the first time (getCatalogSummary lists only code + severity; this is where the prose lives — the same pitfalls are re-checked at the end-of-build review).

getCatalogSummary

ChatGPT
Return the COMPACT capability catalog — per module, the config keys it needs, its commands (with required + accepted payload fields) and the events it emits (the fields a rule can read as event.<field>) — WITHOUT the full JSON Schemas. It also carries valueExprForms: the full vocabulary a then.payload leaf may take — {const}, {object}, {template} (interpolate {{name}} placeholders in a string with vars — each var itself a value-expr — for a personalized body/message), {select} (pick ONE element out of a prior-lookup array by matching a field and return one of its fields — e.g. resolve a user-named list into its real id from a connector's list result, so the model never authors the id and a fabricated one can't flow downstream; no match ⇒ the key is omitted), and every {ref} root (event., endUser.id — the trusted server-known identity of the person, bind durable keys like a data-table keyField or escalation id to it, state., settings., and chain.<EventType>.last.payload.<field> to pull a value from an event emitted EARLIER in the same reactive chain) — so you don't have to infer the ref forms from examples. An order of magnitude smaller than getCatalog: prefer this when you're wiring reactiveRules and just need the field names, and only fall back to getCatalog when you need a full schema. Each module also lists any pitfalls it declares — its KNOWN failure modes — but here as code + severity ONLY (no prose): enough to see THAT a capability has common misuses and how serious. Pull the full failureMode + guidance for the ones that matter with getCatalog({ moduleIds }) — the same modules you fetch full schemas for when wiring (the same pitfalls are re-checked at the end-of-build review). Read-only.

getConnector

ChatGPT
Look up one connector by its toolkit connectorId (e.g. from listConnectors, or one you already know like "gmail"). This is the RELIABLE exact-existence check (unlike listConnectors' page-limited substring search). Returns { connector, providerMode }: connector carries its title, description, categories, noAuth, and toolCount, OR is null when no such toolkit exists. A genuinely absent slug resolves to connector: null — it is NOT an error; an ok:false error means an ACTUAL provider failure (timeout/auth/5xx), so retry it rather than concluding the toolkit is missing. providerMode makes the null authoritative: connector: null proves absence only when providerMode is live-composio (the real credentialed catalog); on no-catalog (keyless dev) EVERY lookup is null and proves nothing. Use it to confirm an id and decide whether to scope enabledTools before enableConnector. Read-only.

getEvalCoverage

ChatGPT
Read the agent's EVAL COVERAGE at a glance — which capability steps have re-runnable unit tests, which steps are still UNTESTED, and which existing evals never ran, are failing, or are orphaned — so you close the gaps instead of re-deriving them from listEvalTargets + listCapabilityEvals. Compiles the DRAFT and returns { targets, orphanedEvals, summary }. Each target is an eval-able instance (same shape as listEvalTargets) plus its rolled-up cases: evalCount, neverRunCount (authored but never executed), failingCount (last score < 0.7), and evals (each case's id, name, lastScore, lastRunAt). An UNCOVERED target (evalCount: 0) carries a suggestion — a concrete first case to author for that step (the right input shape and expectation kind). orphanedEvals are cases whose target instance no longer exists in the current draft (left behind by a config edit) — delete them or re-add them against the new instance id. summary totals it: { targetCount, coveredCount, uncoveredCount, evalCount, neverRunCount, failingCount, orphanedCount }. Workflow to CLOSE a gap: getEvalCoverage → addCapabilityEval for each uncovered target (start from its suggestion) → runCapabilityEval to score each new case → getEvalCoverage again to confirm uncoveredCount: 0 and nothing failing. Read-only.

getKnowledgeBase

ChatGPT
Read the agent's knowledge base: how many sources it has and their processing status. You can add reference TEXT directly with seedKnowledgeText; FILE uploads still go through the Outside Agent Console (the manageUrl from setAuthoredConfig/publishAgent). Use THIS tool to check whether sources have finished indexing. Returns { total, counts: { ready, processing, pending, failed }, ready, sources: [{ id, title, sourceType, status, errorMessage }] }. ready is true once at least one source is embedded and searchable. After you seed text (or the creator uploads files) call this: if counts.processing or counts.pending is non-zero indexing is still running (call again shortly); once ready is true you can confirm the knowledge base was added successfully and continue. A failed source carries a friendly errorMessage. Read-only.

getPublishStatus

ChatGPT
Read the outcome of a publish started by publishAgent, by the agentId + buildId it returned. Use this ONLY when publishAgent (or a prior getPublishStatus) returned { pending: true, agentId, buildId } — the safety review is still running server-side. Pass BOTH the returned agentId and buildId (agentId scopes the poll to the right owner, which also lets a delegated editor resolve the run). While in flight it returns { pending: true, agentId, buildId } again (poll again in a few seconds); once done it returns the SAME shape publishAgent would have: the public link on success, or the blockers/failure to fix. Read-only — it does NOT start a new build (publishAgent does). notFound means the buildId is unknown for this creator.

getQualityReport

ChatGPT
Read the Quality report — the same single view the Console Quality page shows, in one call. Returns { understood, built, tested, flags, latestRun, runs }: understood is the requirement ledger (every behaviorIntent's intentId/statement — what the platform believes the agent must do; EVERY requirement weighs the same in the grade, the config's priority field is ignored by grading; if a requirement is wrong or missing, fix the config's behaviorIntents); built lists the compiled capability instances, channels, soulPresent, and replyMode (what actually got wired); tested describes the suite's shape (testCount, scenarioCount, generatedCount, authoredCount, intentsWithoutBattery — intents the next runQualitySuite will auto-cover — and testCountByIntent, live per-requirement test counts); gradeStale is true when the config or the test set changed since the latest completed run (e.g. a flag was just converted) — the standing grade doesn't cover the change until runQualitySuite runs again; flags.openCount says how many creator-flagged real interactions await processing (listFlaggedInteractions to read them); latestRun + runs carry the grade history (see runQualitySuite for the rollup shape). Use it to answer 'did the platform understand the ask, is it tested, and what is the grade' before and after changes. Read-only.

getRecipe

ChatGPT
Resolve one AuthoredConfig recipe by name (from listRecipes), returning { name, title, description, config } — a real, schema-valid config skeleton with the wiring already correct. The config is a SHAPE TO ADAPT, not a finished agent: replace the placeholder purpose/persona/message text and <…> markers, pick real capability ids (cross-check getCatalog) and connectors (listConnectors), then pass it to setAuthoredConfig. Returns null if no such recipe exists. Read-only.

getWidgetEmbedCode

ChatGPT
Get the <script> snippet and step-by-step install instructions to add this agent as a floating chat widget on a website. Requires the agent to be PUBLISHED and to have webWidget.enabled set (turn it on with setAuthoredConfig, then publish). Returns { enabled, slug, snippet, scriptUrl, previewUrl, appearance, instructions: { generic, byPlatform, selected? } }: paste snippet just before </body> on every page. Pass an optional platform (shopify | wix | wordpress | webflow | squarespace | html) to get tailored steps under instructions.selected. If the widget is off or the agent isn't published yet, snippet is null and instructions.generic says what to do first. Read-only.

grantEditor

ChatGPT
Owner-only. Grant a Firebase uid delegated authoring access to this agent; the owner keeps billing + control.

issueNumber

ChatGPT
Provision (or retry) the Twilio phone number for a PUBLISHED sms/voice agent, AND the way to READ an agent's number over this surface. Decoupled from publish: publishing kicks issuance off in the background, so call this to check/retry it explicitly — e.g. after publishAgent returned numberPending, or after a transient failure. IDEMPOTENT: if the agent already has an active number it is returned unchanged. AREA CODE: pass an optional areaCode (a 3-digit NANP code like "305") to bias the search to that area code — the number will be in it or issuance FAILS LOUDLY (no_inventory_in_area_code, nothing is bought); omit it to take whatever Twilio inventory is available. To make a FRESH agent auto-issue in a given area code the moment it publishes, set numberAreaCode on the authored config instead (setAuthoredConfig) — the background issuance reads it. Returns { ok: true, e164, status }, or { ok: false, reason } — no_inventory (no number available at all, try again later), no_inventory_in_area_code (the requested area code had none right now — retry later, or the creator can email illya@outsideagent.ai to have a specific DID bought and swapped on), provisioning_failed (transient infra, retry), not_configured (server is missing Twilio settings — NOT retryable, tell the operator), agent_not_published (publish first), already_has_number (it already has an active number — this tool NEVER swaps or releases a live number; to change or remove it the creator must email illya@outsideagent.ai). On already_has_number the result ALSO carries e164 + status for the existing number (so you can read and hand the creator the agent's number even when the background issuance already provisioned it before you called this); while it's still provisioning, e164 is null and status is provisioning — call again shortly.

lintConfig

ChatGPT
Validate a CANDIDATE authored config WITHOUT saving it — the read-only dual of setAuthoredConfig. Runs the SAME write-boundary checks (every capabilities[].id must be a real catalog id; every capabilities[].config must match its module's configSchema; every reactiveRules[].then.payload must satisfy its target command's required fields and types) and computes the same channelAdvisories and capabilityAdvisories, but persists NOTHING and RETURNS the problems instead of rejecting. Returns { valid, errors, channelAdvisories?, capabilityAdvisories? }: valid is true when setAuthoredConfig would accept the config, and errors lists each unknown capability id (with the valid ids), each capability config that fails its module configSchema (naming the field path), each invalid rule payload (naming the rule + field), and each unrooted reactive-rule condition.field (e.g. label instead of event.label). capabilityAdvisories carries each attached capability's KNOWN PITFALLS (common misuses + suggestedGuidance) — non-gating heads-up, the same ones setAuthoredConfig returns and the review re-checks. It ALSO returns instances — the compiled instance id ({ id, instanceId }) per attached capability, same GLOBAL 0-based index scheme setAuthoredConfig uses — so you can resolve a duplicate-capability then.target / adminForm capabilityId while still validating, before persisting. Use it to check a config you're still assembling — iterate against errors here, then commit the clean config with setAuthoredConfig. Pass the OPTIONAL agentId (the agent this config would OVERWRITE) to also get an impact preview: impact.droppedMustIntents lists the must-have behavior intents this candidate would drop or downgrade vs the stored config — the exact ids setAuthoredConfig would REJECT unless you pass acknowledgeRemovals (ADR 0006) — and impact.droppedCapabilities / impact.droppedChannels list the capabilities/channels it would drop (rejected unless you pass acknowledgeDrops). Check it before committing so you don't silently erase a requirement. TO LINT A PARTIAL PATCH: instead of a full config, pass set (the same top-level fields you'd give patchAuthoredConfig) plus agentId — lint MERGES the patch onto the stored config and validates the result, so impact reflects what the patch would really produce (a partial that omits behaviorIntents does NOT false-report every must intent as dropped — the merge inherits them). Provide config OR set, not both. Read-only.

listAgents

ChatGPT
List the creator's agents (id, name, status, slug). Read-only.

listAllowedNumbers

ChatGPT
List the E.164 numbers allowed to reach a PRIVATE agent (oldest first, each with its optional label). The owner is implicitly allowed and is NOT in this list. Read-only.

listCapabilityEvalRuns

ChatGPT
List the run history for one eval, newest first — pass agentId AND evalId (both required; the eval must belong to that agent). Each run is { id, score, output, rationale, judgeModality, configRef, ranAt }, where configRef identifies which config version was exercised (for spotting regressions across edits). Read-only.

listCapabilityEvals

ChatGPT
List the agent's capability evals with their latest result — pass agentId (optionally instanceId to scope to one capability). Each returns { id, capabilityInstanceId, moduleId, evalKind, name, input, expected, lastScore, lastRunAt, ... }; lastScore (0..1) and lastRunAt are null until the eval has been run. Read-only.

listConnectorTriggers

ChatGPT
Discover the TRIGGER types a connector can fire (the inbound/event side — e.g. "a new Google Task was added"). Pass connectorId (a real toolkit id from listConnectors). Returns each trigger's type (use it in setAuthoredConfig's connectorTriggers), name, and description. A trigger lets the agent ACT ON ITS OWN when something happens in the end user's connected account — distinct from connector tools, which the agent calls on demand. To use one: declare it in connectorTriggers AND add a reactive rule with when: { event: "ConnectorTriggerReceived" } that does something (notify, call a tool, …). Read-only.

listConnectors

ChatGPT
Search the provider's catalog of external connectors — thousands of third-party toolkits (Google Calendar, Gmail, Slack, HubSpot, GitHub, Notion, Stripe, …) the agent can use. Pass query to filter by name/keyword (e.g. "calendar", "crm", "github"), category to filter (e.g. "crm", "productivity"), and limit to cap results (the catalog is huge — results are always bounded). Returns { connectors, providerMode }: each connector carries its id (pass it to getConnector / enableConnector), title, description, categories, and toolCount. IMPORTANT: query is a SUBSTRING filter over a provider-RANKED PAGE, not a full search — an empty connectors list does NOT prove a toolkit is absent (it may just be off the fetched page); confirm a specific toolkit with getConnector(id) instead. providerMode is live-composio (the real credentialed catalog) or no-catalog (no provider wired in this environment, e.g. keyless dev — then EVERY result is empty and proves nothing about real availability; don't conclude a connector is missing). A connector lets the agent act in a third-party app ON BEHALF OF THE END USER, who authorizes it once at runtime via OAuth (the creator never supplies credentials). The results ALSO include the platform's NATIVE connectors (e.g. meta_lead_ads, Meta Lead Ads) — platform-owned integrations bound ONCE at build time to the creator's OWN asset (a Facebook Page), with NO per-end-user OAuth; a native connector delivers INBOUND events, so enable it and pair it with connectorTriggers + a ConnectorTriggerReceived reactive rule (not connector-tool). These are NOT the built-in capabilities from getCatalog. Search by need rather than listing everything.

listDailySweeps

ChatGPT
List every daily sweep configured on this agent — each with its name, kind, fire time (fireHour/fireMinute + timezone), connector-list fields (connectorId, listTool, listArgs, rowsPath, phonePath, contextPaths), instruction, pacing, and weekday setting. Read-only. Call BEFORE configureDailySweep when unsure what exists: configuring an existing name OVERWRITES it, and an agent holds at most 6 sweeps.

listEditors

ChatGPT
Owner-only. List the editors granted authoring access to this agent.

listEnabledConnectors

ChatGPT
List the connectors currently enabled on the agent (each with its connectorId and the enabledTools scope, if any). Read-only.

listEvalTargets

ChatGPT
List the agent's EVAL-able capability instances — the individual steps you can write re-runnable unit tests against. Compiles the DRAFT and returns one entry per instance: { instanceId, moduleId, evalKind, judge, supportsDeterministic }. Use instanceId as the capabilityInstanceId when you add an eval. evalKind is capability (feed it an input, score the output) or tool-selection (feed the composer a user message, assert which tools it calls). supportsDeterministic says whether an exact deterministic matcher is allowed; judge (text|image|null) says which model judge scores fuzzy outputs. Read-only.

listFlaggedInteractions

ChatGPT
List the interactions the creator FLAGGED while reviewing real conversations on the Console — the feedback inbox this loop drains. Returns the agent's flags newest-first, each { id, correlationId, excerpt, note, status, evalId }: excerpt is the transcript span frozen at flag time ({ role: 'user'|'agent', text }[] — what actually happened), note is the creator's correction (what SHOULD have happened — treat it as the requirement), DISPUTED TESTS: a correlationId starting eval: flags an EXISTING test from the Quality page's conversation view — the creator read the test's conversation and believes the RUBRIC is wrong, not the agent. For those, review the eval (the id follows eval:) and its criteria against the excerpt + note; if the creator is right, FIX THE TEST (replace it via deleteCapabilityEval + addScenarioEval with corrected criteria, or adjust the behaviorIntent) and then dismissFlag — do NOT convertFlagToEval (that would mint a duplicate test), status walks 'open' → 'converted' | 'dismissed' (default filter: 'open'; pass status: 'all' for history), and evalId points at the scenario eval a converted flag became. THE LOOP: a flag is a failing test the agent already failed for real. Process each open flag: (1) read the excerpt + note and decide whether it reveals a MISSING requirement — if so, add a behaviorIntent for it first (setAuthoredConfig/patchAuthoredConfig); (2) convertFlagToEval with sharpened judge criteria and the intent link; (3) fix the config so the behavior actually changes (guidance, soul, rules, or an intent example); (4) runQualitySuite and confirm the flag-derived eval passes AND nothing else regressed; (5) publish. Dismiss (dismissFlag) only what the creator confirms is a one-off. Read-only.

listRecipes

ChatGPT
List the canonical AuthoredConfig RECIPES — known-good starting shapes for common agent patterns (conversational, no-LLM deterministic bot, scheduled reminder, escalating reminder ladder that self-cancels, classify-and-branch routing, human escalation, RSVP/guest list, structured intake (a typed, ordered intakeForm that automatically compiles the proven whole-transcript extraction, per-conversation record, focused missing-field recovery, completeness gate, PDF, email, and truthful delivery confirmation), owner-uploaded roster/worklist, per-user scheduled recap, multi-step generate-then-deliver, knowledge-base grounded, connector-trigger reaction). Pass query with the task IN YOUR OWN WORDS (e.g. listRecipes({ query: "chase an overdue invoice until paid" }), "answer from our FAQ", or "ask callers these questions and submit their answers") and the best-fitting recipes are ranked first; omit it to skim the whole library. A creator-provided fixed question list, questionnaire, application, lead form, or intake MUST use structured-intake, not the generic conversational shape. Returns each recipe's name, title, description, and keywords. Fetch the full skeleton with getRecipe(name), adapt it (purpose, form fields/groups, verification, delivery, branding), then setAuthoredConfig it. Start here instead of composing a config from scratch. Read-only.

listTargets

ChatGPT
List the valid then.target instances for the agent's reactive rules — so you don't have to guess an instance id or probe with a bad rule to learn it. Compiles the DRAFT and returns { targets }, each { id, module, emits }: id is a compiled capability instance usable DIRECTLY as a rule's then.target, module is the capability it runs (for an ATTACHED capability the bare module id — e.g. "messenger" — is ALSO a valid target and additionally enables synchronous payload validation), and emits are the event types that instance can produce (wire another rule's when.event off one to chain behaviors). The list includes the auto-wired BASELINE instances (the agentic composer + replier) and the escalation instance when human-in-the-loop is on — targets that aren't in getCatalog and are otherwise undiscoverable. Read-only.

listTriggerEvents

ChatGPT
List the valid when.event values a reactive rule can fire on for this agent — so you don't have to hand-assemble them from getCatalog + the draft, or probe with a bad rule to learn them. Compiles the DRAFT and returns { triggerEvents }, each { event, source, emittedBy }: event is the type usable DIRECTLY as a rule's when.event; source is how it becomes fireable — builtin (MessageReceived, the universal external chat entry point, always present), capability (an event an ATTACHED capability instance emits — emittedBy lists the instance ids, so you can chain a rule off another rule's command), connector-trigger (ConnectorTriggerReceived, present ONLY when a connector trigger subscription is in the draft's connectorTriggers), or signal (a custom composer signal you declared). An event NOT in this list is unfireable for this draft: attach the capability/connector trigger or declare the signal first. This is the when.event companion to listTargets (which lists the valid then.target). Read-only.

patchAuthoredConfig

ChatGPT
Apply a PARTIAL update to an already-configured agent without resending the whole config — tightens the iterate loop when you only want to change one field. Pass agentId and set, an object of the top-level fields to change (e.g. { purpose: "…" }, { channels: ["web","sms"] }, { guidance: [...] }, { activityDisplay: "all" }). Each key in set REPLACES that field wholesale (arrays/objects are NOT deep-merged — predictable); fields you omit are left untouched. The merged config is re-validated exactly like setAuthoredConfig (capability ids + reactive-rule payloads are checked, so a bad patch is rejected with the same field-level errors), and the result returns the full merged config plus any channelAdvisories and capabilityAdvisories (the known pitfalls of the attached capabilities). The agent must already have a config (create it with createAgent/createConversationalAgent and setAuthoredConfig first). PROTECTED REQUIREMENTS: patching behaviorIntents to drop or downgrade a published priority: "must" intent is rejected unless you pass acknowledgeRemovals: [<the intent id>] — the same durable-requirement guard as setAuthoredConfig, so an incremental edit can't silently erase a hard requirement. QUALITY LOOP: after changing an agent's behavior (soul, behaviorIntents, capabilities, guidance), run runQualitySuite and read rollup.regressions — it diffs against the previous completed run and shows exactly which requirements your change made WORSE ('newly_failing', 'score_drop', 'requirement_dropped'). New behaviorIntents get their standard test battery written automatically by that same call. Don't publish a change that introduced regressions without either fixing it or telling the creator why it's acceptable.

previewSchedule

ChatGPT
Arm the draft's AGENT-WIDE standing schedules (declared on the scheduler capability's config.schedules: [{ label, spec }]) on the agent-level session and advance its clock, returning each firing's cascade — so you can confirm an agent-wide cadence (a weekly announcement, a daily digest) ARMS and drives its TimerFired rule WITHOUT hand-firing a TimerFired. Returns { correlationId, until, armed, firings, events, failures? }: armed is what was scheduled, firings are the occurrences that fell due (label + 0-based occurrence + firedAt), events is the produced cascade (look for the broadcast/digest each firing drove). Omit until for a deterministic default window (35 days past each schedule's anchor); pass an ISO until for a specific horizon. armed: [] means no standing schedules are configured. Read-only — nothing is persisted or sent.

publishAgent

ChatGPT
Compile the agent's guidance into runtime policies, run the full safety review, and publish it to the web. On success returns the public link (the creator can share it immediately). Phone numbers are DECOUPLED from publish: when the agent has an sms/voice channel, publishing KICKS OFF number issuance in the background and returns numberPending: true — it does NOT wait for or fail on the number. Call issueNumber to check/retry the number (it's idempotent), or read it later via getAgent. If the review blocks publishing, returns the blockers to fix — adjust the config and call again. PENDING RESULT: the safety review runs server-side; if it hasn't finished within the in-request window, this returns { pending: true, agentId, buildId } (NOT an error and NOT a timeout — the build keeps running). When you get that, call getPublishStatus with the returned agentId AND buildId to read the final outcome; do NOT re-call publishAgent (that starts a NEW build). AFTER PUBLISH: the platform re-grades the published agent automatically in the background (the same suite runQualitySuite runs); call getQualityReport a few minutes later to read the fresh grade and its regressions, and treat a post-publish regression as a bug to fix, not noise.

recordSourceRequirements

ChatGPT
Capture the RAW source you are building this agent from — BEFORE you reviewAgent/publishAgent — so the safety review can verify nothing was dropped. The review runs an advisory requirement_coverage pass that compares this source against the assembled agent and WARNS (it never blocks) about any requirement that did not make it in; those warnings come back in reviewAgent's findings for you to fix. Pass messages: the build conversation as role-tagged turns, oldest-first — role: "creator" for the human's own words (paste the dropped transcript or brief as one creator message; or each of their answers), and role: "builder" for YOUR questions and framing. CAPTURE BOTH SIDES, in order: a terse creator answer ("yes", "after two tries", "text my cell") is only a requirement together with the builder question it answered, so recording the answer WITHOUT its question loses the requirement. Recording the full back-and-forth also lets a later reversal ("actually, drop SMS") correctly cancel an earlier ask instead of looking like a dropped one. Appends (does not replace): call once with the whole exchange, or turn-by-turn as you interview — the messages accumulate in order. This does NOT change the agent's config; it only records what to check the config against. Owner-gated to your own agent.

registerDocumentTemplate

ChatGPT
STEP 2 after createTemplateUploadUrl + your curl PUT: confirm the uploaded Word (.docx) template and read its real fields. Pass { agentId, storagePath } (the storagePath from step 1); returns { storagePath, placeholders }, where placeholders are the template's actual {{token}} names. Set the capability's templateStoragePath to this storagePath (NOT templateBase64), and author your FillTemplateDocument field map against these exact placeholders so no field ships blank in the finished document. Errors (user-safe) if the upload is missing, isn't a valid .docx, or the path isn't a template you uploaded for this agent.

removeAllowedNumber

ChatGPT
Remove an E.164 number from a private agent's allow-list (matched exactly). The owner keeps access regardless. Owner-scoped.

reportBuilderFeedback

ChatGPT
Log an improvement, blocker, or opportunity you hit WHILE building — feedback for the platform team about the build surface itself, NOT a message to the creator. Call this whenever the tools or catalog get in your way: a capability the spec NEEDED that doesn't exist (kind: "blocker"); a limitation you had to work AROUND but shipped anyway (kind: "opportunity"); or a clunky/missing/confusing MCP tool, catalog gap, or unclear error (kind: "improvement"). Logging it is fire-and-forget: it stores a row for the team and DOES NOT change or block this build — keep building. Input: { kind, title, body, severity?, capabilityArea?, agentId?, context? }. Make title a one-line summary and body concrete — what you needed, why you couldn't do it with today's tools, and what would have helped (name the exact tool/capability id/field and quote the error or catalog absence). severity is blocks-build | degrades | nice-to-have; capabilityArea is a coarse tag (e.g. "scheduling", "communication", "knowledge"); pass the agentId you're building and any structured context (the failing call, ids) to help triage. Returns { id, status: "new", message }. Prefer ONE feedback row per distinct gap (don't spam duplicates). This is the right channel for 'the platform should be able to…' — use it instead of silently faking a required integration or abandoning a must behavior.

reviewAgent

ChatGPT
Run the SAME compile + safety/purpose review that publishAgent runs, but WITHOUT publishing — returns { canPublish, blockers, findings, validation, delta? }. simulateBuild only checks behavior (rules → events); this checks publish-readiness, so use it to iterate on review blockers cheaply before going live. canPublish: true with no blockers means publishAgent would succeed. blockers is the friendly human-facing list; each carries STRUCTURED targeting — subjectId (the exact rule/intent/capability id flagged), subjectKind, fieldPath, and a quote of the offending span — so you fix the right thing in one pass instead of guessing which item the review meant. findings is the FULL machine shape publishAgent's report carries (id, category, severity: info|warning|blocker, confidence 0..1, summary, evidence[], subjectId, fieldPath, suggestedRemediation, ...) for EVERY severity — so you can iterate blockers off reviewAgent ALONE with no publish round-trip and never under-count. Read verdict STABILITY from confidence: a deterministic gate emits confidence 1 (reproducible); a finding with severity "blocker" and confidence < 0.8 is a MARGINAL LLM-judge verdict that did NOT gate publish (it may shift run-to-run). validation is core's static validation block (errors/warnings). To track progress across iterations, pass priorBlockers (the blockers array you got from your LAST reviewAgent call); the result then includes a delta of { cleared, introduced, kept } so you can tell whether your last edit helped. The review also dry-runs the draft and promotes a runtime failure (a rule that fails on every message) to a distinct "a rule fails when it runs" blocker, separate from "a behavior has no rule". The result also carries a NON-GATING bloat nudge ({ count, message }, present only when > 0) counting the config's dead/redundant parts — call compactAgent for the full prune report; it never affects canPublish. Note the review depends on replyMode (a deterministic agent skips the AI judge — see setAuthoredConfig).

revokeEditor

ChatGPT
Owner-only. Revoke a Firebase uid's authoring access to this agent; the owner keeps billing + control.

runCapabilityEval

ChatGPT
Run ONE eval FOR REAL against the agent's current draft and score it 0..1 — pass agentId AND evalId (both required; the eval must belong to that agent). Executes the capability with live ports (real model / knowledge retrieval; side-effects captured, nothing sent), extracts the output, and scores it by the stored expectation (deterministic matcher, model judge, or tool-selection set). Records a run and updates the eval's last-run snapshot, returning { id, score, output, rationale, ... }. A tool-selection eval runs the message through a full composer turn and asserts which tools the model called. This spends model credits, so it is credit-gated.

runQualitySuite

ChatGPT
Execute EVERY eval on the agent (capability, tool-selection, and scenario cases) in one batch against the current DRAFT config and persist the rolled-up GRADE. Any behavior intent still missing its standard battery gets one WRITTEN AUTOMATICALLY first (same behavior as generateEvalBattery; best-effort — a generator failure grades the existing tests), so a bare runQualitySuite on a freshly authored agent is a complete grade, not a partial one. Returns the quality run: { id, status, configRef, rollup } where rollup is { requirements, totals, regressions, comparedToRunId } — per requirement its status ('verified' | 'failing' | 'unverified' | 'untested'), avgScore, rigor ({ level, testCount, tagsPresent, hasMultiTurn } — 'verified' needs ≥2 tests incl. an edge/adversarial probe), and each test's score + judge rationale (plus evalRunId — pass the test's evalId to listCapabilityEvalRuns and match that run id to read the RECORDED CONVERSATION behind the score: output.trials[].output.transcript, one entry per trial; single-trial runs store output.transcript directly); totals carries the headline numbers (verifiedCount/requirementCount, suite-wide avgScore); regressions diffs against the agent's PREVIOUS completed run ('newly_failing', 'score_drop' ≥0.15, 'requirement_dropped'). A test that cannot run scores null and keeps its requirement out of 'verified' — never silently dropped. The suite also refreshes each eval's last-run snapshot, and it re-runs automatically after every successful publish. Typical loop: runQualitySuite → fix what's failing → runQualitySuite again → publish. An UNCHANGED config + unchanged test set SHORT-CIRCUITS: the standing grade is returned instead of re-running (the agent and judges are nondeterministic, so a no-change re-run only measures model noise and spends credits doing it) — pass force: true to deliberately probe run-to-run variance. Judge scores are 3-sample medians. Because the agent is nondeterministic, one trial per test is a single sample — each test runs trials times (1..5, DEFAULT 3 — a plain call already runs every test 3×): the test's score is the MEAN across trials and each result carries a trials: { count, min, max } spread, so an agent that fails 1-in-3 times shows up instead of getting lucky. Cost scales with trials (the default spend is ~3× a single pass); pass trials: 1 only for a cheap smoke run whose grade is a single sample. This runs every case against live models, so it is credit-gated and can take a while on a large suite.

seedKnowledgeText

ChatGPT
Add one or more PLAIN-TEXT documents to an agent's knowledge base directly — no file upload, no Console round-trip — the way to seed reference material up front when you already have the text. Pass { agentId, documents: [{ title?, text, onConflict? }] }; each document is chunked, embedded, and stored, so it becomes searchable by the agent's search_knowledge tool right away. Returns each document's outcome: { sourceId, title, status, replacedSourceIds, conflicts }. UPDATING A FACT IN A LATER SESSION (a changed price, a new policy) — two guards stop you from stacking a stale duplicate that leaves the agent able to answer with the OLD value: (1) UPSERT BY TITLE — a document whose title EXACTLY matches an existing source replaces it (old chunks dropped first); reuse the prior title to update, use a fresh title to add. (2) SEMANTIC CONFLICT GATE — otherwise, before writing, the text is vector-searched against the existing knowledge; if it strongly OVERLAPS a source (same topic — e.g. a new card price vs a $40 one already in an uploaded PDF), the document is NOT written and comes back with status: "conflict" and conflicts: [{ sourceId, title, snippet, distance }]. This catches stale facts even under a different title or inside a PDF. When you get a conflict, CONFIRM WITH THE USER, then re-submit that document with onConflict: "append" to keep BOTH (they're genuinely different), or { replaceSourceId: "<the stale source>" } to drop the old source first, then add the new one (note: replacing a PDF source removes the WHOLE PDF, not just the one fact). onConflict defaults to "ask" (run the gate). An UNTITLED, non-overlapping document simply appends. SEED ONE FACT PER DOCUMENT (one price, one policy, one hours block) under its OWN title — do NOT bundle several facts in one document. Both guards depend on it: the upsert key is per-title, and the conflict gate compares whole-chunk embeddings, so a chunk that blends 3 facts dilutes each one's signal and a later single-fact correction can slip past the gate and silently append a contradiction. Granular, titled facts keep updates deterministic. Attach the knowledge-base capability so the agent USES the results. This is TEXT only — for files (PDFs, docs) hand the creator the Console manageUrl. An empty base is fine to publish; retrieval just finds nothing until you seed it.

setAgentFromEmail

ChatGPT
Point ONE agent's outbound email (the email capability's sends AND the HITL escalation notice) to go out FROM fromAddress (optionally with a display fromName) instead of the platform's default sending inbox. fromAddress's domain MUST already be a VERIFIED sending domain on the creator's account — connect it first with connectEmailDomain and poll checkEmailDomain until status is "verified"; calling this against an unverified or unregistered domain does nothing destructive, it just returns the reason. Returns { ok: true } on success (the agent's AuthoredConfig now carries email.fromAddress/fromName) or { ok: false, reason } with a human-readable reason (most commonly that the domain isn't verified yet) to relay to the creator rather than retrying blindly.

setAgentSlug

ChatGPT
Choose or change the agent's public link — the slug in /a/<slug> (e.g. /a/front-desk). Pass any text as slug; it is normalized to lowercase letters, numbers and hyphens ("Front Desk" → front-desk). The link is UNIQUE across the whole platform: if it is already taken you get a clear error — pick another. Works BEFORE or AFTER publishing. On a PUBLISHED agent this RENAMES the live link and the old /a/<old-slug> URL stops resolving immediately (there is no redirect). It never re-compiles or re-publishes the agent, so it takes effect at once. A published agent already gets a clean auto-slug from its name; use this to pick a nicer one, or to rename it later. Returns the final slug and its public url.

setAgentVisibility

ChatGPT
Flip an EXISTING agent between public and private. public: anyone can chat over web (no sign-in) or SMS. private: only the OWNER and E.164 numbers on the allow-list can reach it — a web visitor must sign in, an SMS from an un-listed number is ignored (silently). This is an OPERATIONAL change: it never re-compiles or re-publishes the agent, so it takes effect immediately. Manage who has access with addAllowedNumber / listAllowedNumbers / removeAllowedNumber.

setAuthoredConfig

ChatGPT
Set the agent's full behavior config in one call: purpose (required), plus optional audience, capabilities (each { id, config } where id is a getCatalog module id — there is NO module field on authored capabilities; the catalog's authoredExamples show this exact shape, distinct from the compiled examples), natural-language guidance (safety + handoff), and channels (use ["web"] for a shareable link). Overwrites any previous config. GUIDANCE SHAPE + SCOPE: each guidance item is { kind: "safety" | "handoff", text } (a bare string is accepted as kind: "safety"). A PROSE-only item is a DECLARATIVE BOUNDARY the agent respects ("never share pricing", "this agent respects opt-out") — it rides verbatim into the system prompt and needs NO runtime wiring; a pure prohibition with no matching command is fine and publishes clean (prompt-only). To ENFORCE a boundary — block / escalate / notify WHEN a condition holds — give the SAME item the structured { when, condition?, then } body a reactiveRules entry uses (a "safety" line IS a reactive rule on the reply event): e.g. { kind: "safety", text: "Never share billing before the caller is verified", when: { event: "MessageReceived" }, condition: { all: [{ field: "state.verified", op: "eq", value: false }] }, then: { command: "EscalateToHuman", target: "human-in-the-loop" } } (optional id names the compiled policy). A structured guidance line compiles DETERMINISTICALLY (no LLM), same grammar and same synchronous payload/target validation as a reactive rule. PROSE guidance is ALWAYS prompt-only — it is NEVER compiled into a policy, so a prose line can't block a publish no matter what it says. So express anything the agent must DO as a structured guidance body (for a safety/handoff boundary) or a reactiveRules + signals behavior — NOT as prose hoping it becomes an action. Add the structured body ONLY when the line names an action to TAKE; leave a plain boundary as prose. Every capabilities[].id MUST be a real catalog id — an unknown id is rejected immediately with the list of valid ids (in the error's JSON detail), so call getCatalog first instead of guessing. Each capability's config is ALSO validated against that module's configSchema at write time — a wrong-shaped config (e.g. a FLAT data-table config where source must be the object { event, keyField, fields }) is rejected with the failing field path, not deferred to a simulateBuild invalid instance config failure. For a NO-LLM agent (a fixed-script / rule-only bot — e.g. always reply the same line), set replyMode: "deterministic" and drive it entirely with reactiveRules (e.g. a rule when {event: "MessageReceived"} → then {command: "SendMessage", target: "messenger", payload: {message: {const: "…"}}}, with messenger in capabilities); the language model is then omitted everywhere. Reactive rules set through this tool are auto-confirmed (there is no separate confirm step on this surface), and reactiveRules[].intentIds is OPTIONAL — omit it for a self-contained rule and the compiler links it to a synthesized intent (no paraphrased behaviorIntents boilerplate needed). REVIEW DELTA by replyMode: deterministic runs only fast structural checks at publish (no AI judge), while agentic ALSO runs the LLM safety + purpose-alignment judge — so an agentic agent can surface safety/alignment blockers a deterministic one won't. Attaching knowledge-base only MARKS the agent as knowledge-backed — its documents are NOT set here. Add reference TEXT directly with the seedKnowledgeText tool (when it's available — it needs the embedding indexer); FILE documents (PDFs, docs) are uploaded by the creator in the Console via the returned knowledgeBase.manageUrl (with a note). An EMPTY knowledge base is fine — publishing still works; retrieval just finds nothing until documents are added. Attach the web-search capability (empty config) to give the agent a search_web tool for current, time-sensitive facts (weather, news, prices, scores) that it grounds in live web results with sources — atta…

simulateBuild

ChatGPT
Compile the draft and run it against generated scenarios WITHOUT publishing; returns the FULL event-cascade traces per scenario. This can be LARGE — prefer simulateBuildSummary for a compact pass/fail-at-a-glance read, and only call this when you need the full cascade to debug a specific scenario.

simulateBuildSummary

ChatGPT
Compile the draft and run it against generated scenarios WITHOUT publishing, returning a COMPACT summary instead of the full traces: { scenarioCount, repliedCount, failures, coverage }, where each failure is { scenario, command, target, code, reason }. This is the fast way to spot a payload/wiring bug — e.g. "every scenario fails on SendMessage because the message field is missing" — without paging through the full cascade. coverage is the INVERSE signal: coverage.rulesNeverFired lists reactive rules that fired in NO scenario (usually a wrong when.event, an unsatisfiable condition, or a dangling then.target) — treat a non-empty list as likely dead wiring, NOT a pass; coverage.intentsWithoutScenario lists behaviorIntents no scenario exercised (usually because the intent has no examples, so it was never tested — add one). Drill into simulateBuild only when you need the full trace for one scenario. Read-only.

suggestBehaviorIntents

ChatGPT
Derive candidate behaviorIntents from an agent's CURRENT config — a BACKFILL helper for an agent authored before the requirement ledger existed (or one that never recorded its requirements). Returns { existingIntentCount, candidates, guidance }: each candidate is { id, statement, suggestedPriority, source, relatedRuleId? } derived from a safety guidance line (→ must), a handoff guidance line, a CONFIRMED reactive rule (→ should, with the rule id to link via intentIds), or the purpose. These are PROPOSALS, not saved: walk them WITH the creator, confirm which are real requirements, set each must vs should, ASK about anything the config doesn't yet encode, then write the confirmed set with patchAuthoredConfig({ set: { behaviorIntents: [...] } }) and recordSourceRequirements the creator's words. Back each must with an eval (addCapabilityEval intentId). Recording a ledger is what lets later edits be checked for dropped/broken requirements — call this when reviewAgent surfaces REQUIREMENT_LEDGER_THIN, or whenever taking over an existing agent. Read-only.

testDrive

ChatGPT
Send a turn to one of YOUR agents and get back the events it produces — verify it actually behaves before (or after) publishing. By default (build: "auto") the turn runs the agent's PUBLISHED build if it has one, otherwise its current draft config. IMPORTANT when iterating on a PUBLISHED agent: your unpublished edits live in the DRAFT, so auto runs the STALE published build and your change 'looks broken' — pass build: "draft" to drive your unpublished config (or build: "published" to force the live build). The result echoes ranBuild (published | draft | fixture) and, for a published run, buildId — so you always KNOW which one ran instead of guessing. Pass message for a normal user chat turn (the common case), OR an event type + payload to fire a triggered/scheduled behavior without waiting on the real clock — e.g. type: "TimerFired" to check a scheduled reminder fires and is personalized. Reuse the same correlationId across calls to hold a multi-turn conversation (it defaults to a per-agent session). Turns at different modes are SEPARATE conversations (the fidelity is part of the conversation key), so a mocked turn never seeds a live-response one. Returns the produced events in order: the inbound trigger first, then the agent's reactive cascade (e.g. MessageSent). mode picks the fidelity: mocked (the DEFAULT — a deterministic stand-in model, every side-effect captured; free + byte-stable, best for asserting cascade SHAPE) or live-response (the agent's REAL model, so you see its genuine generated wording, with side-effects STILL captured — for evals / checking actual copy). On THIS service ALL side-effects (connector tool calls, email, texts) are captured, NEVER performed, in BOTH modes — mode: "live" (real performed effects) is NOT supported here and returns an error telling you to use live-response. Don't assert on exact generated wording in mocked (it's a stand-in); assert on the cascade SHAPE. To gate deterministically instead of eyeballing the trace, pass expect: producedTypes (event types that MUST fire), absentTypes (types that must NOT fire), target (an instance id at least one event must route to), and/or noFailures: true; the result then carries an assertion { pass, missing, unexpected, targetMissing?, failureCount } so you can loop until pass is true.

tryAgent

ChatGPT
Preview what the DRAFT would do with ONE user message, WITHOUT publishing and WITHOUT the scenario harness — pass agentId and message. Returns { reply, producedTypes, failures }: the reply the agent would send, the event cascade it triggered (so you can see which rules fired), and any command failures. NOTE: this is a DETERMINISTIC preview — the rule wiring and which capabilities fire are faithful, but the reply TEXT is a stand-in, not the live model's exact wording (that appears once published). Use it to catch a silent agent, a mis-wired rule, or a failing command far faster than a publish round-trip. Read-only.

Capabilities

Writes

Example Prompts

Click any prompt to copy it.

App Stats

71

Tools

3

Prompts

ChatGPT

Platforms

Works with

ChatGPT

Data refreshed daily