Skills
A skill is a unit of capability the agent can invoke from inside a
think step. Two types ship today, authored as files under
tavora/agents/<id>/skills/:
For a hands-on walkthrough that pairs a module skill with an MCP server, see Extend the agent with a module skill — builds on the tasklist tutorial.
| Type | File | When |
|---|---|---|
| Prompt | .md | Domain instructions, templates, the “company tone” preamble. |
| JavaScript module | .js | First-class extension — composable, sandboxed, require()-able from any think step. |
For everything the agent should do against your domain (read
tickets, write invoices, query a database), an MCP server declared
in agent.jsonc → mcp is the right path. Module skills are for
in-sandbox composable logic.
Module skills — the canonical extension path
Section titled “Module skills — the canonical extension path”A module skill is a JS module the agent require()s by name from
inside a think step. The exported surface is whatever you make it —
helpers, transformations, light orchestration.
Inside the sandbox
Section titled “Inside the sandbox”Module skill code runs in a Goja sandbox with these primitives available:
search(query, opts?)/searchDocuments(query, opts?)— semantic search over the app’s indexes.fetch(url, opts?)— HTTP requests (whitelist enforced per app).ai(prompt, opts?)— LLM call through the platform’s provider router.listIndexes()/getDocument(id)— index + document accessors.log(message)— emits asandbox_eventto the trace.data— scratch object that persists for the duration of one agent run.require(name)— pull in another module skill or MCP server declared inagent.jsonc → mcp.
Example
Section titled “Example”A skill named summarize_search:
var results = search(args.query, { limit: args.top_k || 3 });if (results.length === 0) { return "No results found for: " + args.query;}var summaries = results.map(function (r) { return "- " + r.snippet.substring(0, 200);});return "Found " + results.length + " results:\n" + summaries.join("\n");The agent calls it inside its think step:
var out = require('summarize_search')({ query: 'refund policy', top_k: 5 });return out;Authoring constraints
Section titled “Authoring constraints”- ES5.1 only — Goja runtime: no arrow functions, no
let/const, no template literals. Usevar,function (...) { ... }, string concatenation. - 30-second timeout per step — long-running code is terminated.
- No direct network or filesystem access — use the
fetch()primitive, which goes through the app’s whitelist. - No subprocess, no
eval— the runtime is hardened by default.
Creating a module skill
Section titled “Creating a module skill”Drop a .js file under tavora/agents/<agent-id>/skills/ and
tavora dev syncs it as a draft:
var results = search(args.query, { limit: args.top_k || 3 });if (results.length === 0) { return "No results found for: " + args.query;}return results.map(function (r) { return r.snippet; }).join("\n");tavora dev # watch + sync on savetavora run support-bot "find the refund policy" # exercise the drafttavora deploy # ship as immutable version
# Pull the live authoring guide as input for an LLM authoring helper:tavora skills authoring-guide -o skill-authoring.mdThe skill name is the file basename (summarize_search.js →
require('summarize_search')). No SDK call required — tavora dev
upserts the skill row and the agent picks it up on next session.
Authoring guide — fetched from the live runtime
Section titled “Authoring guide — fetched from the live runtime”The runtime exposes its current sandbox primitives, reserved names,
and authoring rules as a Markdown document at /api/sdk/skills/ authoring-guide. Both SDKs return the live content via
getSkillAuthoringGuide — useful as input to an LLM that’s drafting a
module skill (Claude Code, Cursor, etc.):
tavora skills authoring-guide > skill-authoring.mdThis stays in sync with the runtime — when a new primitive lands, the guide picks it up automatically.
Binding skills to an agent
Section titled “Binding skills to an agent”The skills bound to an agent are the files present under that
agent’s skills/ folder at deploy time. Adding a .js or .md
file binds it on the next tavora dev sync; removing it unbinds.
Every tavora deploy snapshots the current skill set into an
immutable agent_versions row — agent_version_id on a session
resolves to that frozen snapshot, so old sessions keep seeing the
skill set they ran against even after you edit.