Skip to content

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.

TypeFileWhen
Prompt.mdDomain instructions, templates, the “company tone” preamble.
JavaScript module.jsFirst-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.

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 a sandbox_event to 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 in agent.jsonc → mcp.

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;
  • ES5.1 only — Goja runtime: no arrow functions, no let/const, no template literals. Use var, 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.

Drop a .js file under tavora/agents/<agent-id>/skills/ and tavora dev syncs it as a draft:

tavora/agents/support-bot/skills/summarize_search.js
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");
Terminal window
tavora dev # watch + sync on save
tavora run support-bot "find the refund policy" # exercise the draft
tavora deploy # ship as immutable version
# Pull the live authoring guide as input for an LLM authoring helper:
tavora skills authoring-guide -o skill-authoring.md

The skill name is the file basename (summarize_search.jsrequire('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.):

Terminal window
tavora skills authoring-guide > skill-authoring.md

This stays in sync with the runtime — when a new primitive lands, the guide picks it up automatically.

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.