← All chapters

Skills, plugins and servers

Three different things an agent can be handed, each at a route of its own name.

The vocabulary, once, so it is never confusing again

A SKILL is a markdown playbook an agent loads and follows; the API stores it at /skills, under a name like write-release-notes. A PLUGIN is code an agent runs; the API stores it at /plugins.

MCP servers

A server your agent calls mid-run, with a key you bring yourself. Assignment is a real table, addressed by the agent's label.

Writing your own

A skill is markdown: POST /skills with its name and content_md, plus the keys it needs (required_keys). A plugin is code (Python, bash or JavaScript) plus a manifest: POST /plugins with code, lang, parameters and required_keys. auth_modes, optional, lists the alternative ways to authenticate, each a set of keys; every key a mode names must also be in required_keys.

Installing what other people published

POST /skills/:id/install and POST /plugins/:id/install copy a public one into your library: a private row of yours, whose version 1 is the original's newest version, keeping its author and licence. A revoked one is not copied. The copy is yours: deleting it is the undo, and the original is not touched.

Answer engines for GEO research

Seven platform plugins in the answer_engines category ask an AI answer engine a question the way a user would and report what it answered and which sources it cited: chatgpt_answer (OPENAI_API_KEY), claude_answer (ANTHROPIC_API_KEY), gemini_answer (GEMINI_API_KEY), grok_answer (XAI_API_KEY), perplexity_answer (PERPLEXITY_API_KEY), google_ai_overview and google_ai_mode (both SERPAPI_API_KEY). They take the same arguments (question, country, region, city, timezone, language, model, max_sources) and return the same shape: engine, surface (api or serp), model, answer, sources with position and cited (cited or only consulted), search_queries, location_requested, location_applied, fidelity_note, usage. The question is sent unchanged. The location goes to the engine only where it accepts one: OpenAI, Anthropic and Perplexity take it as the search's user location, the two Google plugins as Google's own parameters; Gemini and Grok document none, and say so in location_applied. The API plugins are close to, not identical to, the consumer apps; the Google ones read the live results page, and an AI Overview that Google does not show comes back as answer null with reason no_ai_overview. perplexity_answer has two actions: answer (the default) returns Perplexity's written answer and its citations, search returns only the pages Perplexity's Search API finds, with surface search and answer null.

Long tool outputs and errors

From runtime 0.31.0 a tool result is never cut silently. Up to 50,000 characters it reaches the agent whole; a longer one is saved in full to /workspace/.tool-outputs/<session>/ and the agent receives truncated: true, total_chars, saved_to, the first 40,000 and the last 2,000 characters, and reads the rest with read_file(path, offset, limit). The limit can be set per agent (tool_output_inline_chars, 5,000 to 500,000) and a plugin can raise it for itself with max_result_chars in its manifest. The saved files are not team files: they do not appear in Files and go away with the session or after 24 hours. When a plugin or a skill script fails, the agent receives error, exit_code, stdout and stderr (up to 20,000 characters each, with the cut declared); error is the message of a JSON error written on either channel. The values of the keys given to that plugin never appear: they become ***. A timeout says what the tool had written before it was stopped. The platform reading plugins (read_url, http_request, firecrawl_scrape, scrapingbee_fetch, playwright_render, google_drive, pdf_extract, docx_read_write, epub_read_build, pptx_read_write) return what they read whole: max_chars is only an explicit choice, and then the result says truncated, total_chars and next_offset, to pass as offset for the rest. xlsx_read_write and csv_excel_analyze return every row (max_rows and row_offset to read a part), and the run_* code runners return stdout and stderr whole.