Home / Docs / Skills

Skills

Skills are user-created tools that extend Zubo's capabilities. Each skill is a single TypeScript file that the agent can invoke during conversations to perform actions, fetch data, or interact with external services. Skills are hot-loaded — you can add, edit, or remove them without restarting Zubo. User-installed skills run in sandboxed subprocesses for security, ensuring they cannot access Zubo's internal state or database.

Copy-Paste Task Cards

Secure API Access

Enable API auth and create a key before exposing ports beyond localhost.

zubo config set auth.enabled true
zubo auth create-key my-app

Set Local Model Fallback

Keep responses available during provider outages or API quota issues.

zubo config set failover '["openai","ollama"]'
zubo config set providers.ollama.model llama3.3

Common Errors

401 Unauthorized / Missing Bearer token

If auth.enabled is true, all /api/* calls require Authorization: Bearer <key>. Create a new key if needed.

curl -H "Authorization: Bearer YOUR_KEY" http://localhost:3000/api/dashboard/status
Provider Timeout / Upstream unavailable

Use failover and switch temporarily to a responsive provider or smaller model. Check logs for repeated timeout patterns.

zubo model openai/gpt-4o-mini
zubo logs --follow
Missing local model (Ollama/LM Studio)

If local providers fail, ensure the runtime is running and a model is installed.

ollama serve
ollama pull llama3.3

Quick Start

The fastest way to create a skill is with the built-in scaffolding command:

zubo skills new

This interactive wizard walks you through choosing a name, writing a description, and defining parameters. It generates a ready-to-use handler.ts file in your skills directory.

Even easier — just tell Zubo what you need in plain language:

"Build a skill that checks the weather for a location"

Zubo will generate the entire skill file for you, including parameter definitions, error handling, and a working implementation. You can then refine it by chatting: "Add a units parameter that accepts celsius or fahrenheit."

Single-File Format

Every skill is a single TypeScript file with two exports: a skill configuration object and a default handler function. Here is a complete example:

export const skill = {
  name: "weather",
  description: "Get current weather for a location",
  params: {
    location: { type: "string", description: "City or coordinates", required: true },
    units: { type: "string", description: "celsius or fahrenheit" }
  }
};

export default async function (input: Record<string, unknown>): Promise<string> {
  const location = input.location as string;
  const units = (input.units as string) || "metric";
  const res = await fetch(`https://api.example.com/weather?q=${location}&units=${units}`);
  return JSON.stringify(await res.json());
}

The skill object tells the AI what this tool does and what parameters it accepts. The default export is the function that runs when the skill is invoked. This is all you need — no boilerplate, no build step, no configuration files.

Skill Config

The exported skill object defines metadata that Zubo uses to register the tool with the LLM:

FieldRequiredDescription
nameYesUnique identifier. Lowercase letters, numbers, and underscores only ([a-z0-9_]+). This is how the AI references your skill internally.
descriptionYesA natural-language explanation shown to the AI. The LLM uses this to decide when to invoke your skill, so be specific and descriptive.
paramsNoAn object mapping parameter names to their definitions (see Params Format below). If omitted, the skill accepts no parameters.

Params Format

Each key in the params object is a parameter name. The value is an object with the following fields:

FieldTypeDescription
typestringThe data type: "string", "number", or "boolean". Determines how the LLM formats the argument.
descriptionstringExplains what this parameter does. Shown to the AI to help it provide the correct value.
requiredbooleanWhether the parameter must be provided. Defaults to false if omitted.

The params are automatically converted to JSON Schema and passed to the LLM as part of the tool definition. You do not need to write JSON Schema yourself — Zubo handles the conversion.

Handler Function

The handler is the default export of your skill file. It is the function that executes when the AI decides to use your skill.

Accessing API Keys

Skills often need API keys or credentials to call external services. Zubo provides a secure way to pass secrets to skill handlers via environment variables:

export default async function (input: Record<string, unknown>): Promise<string> {
  const apiKey = process.env.ZUBO_SECRET_WEATHER_API_KEY;
  if (!apiKey) return JSON.stringify({ error: "Weather API key not configured" });

  const location = input.location as string;
  const res = await fetch(
    `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${location}`
  );
  return JSON.stringify(await res.json());
}

Secrets referenced in the handler code are automatically passed to the sandboxed subprocess as environment variables with the ZUBO_SECRET_ prefix. Only the secrets that your handler actually references are injected — other secrets are not exposed.

Set secrets via the dashboard or by telling Zubo in chat:

"Store my weather API key: abc123"

You can also use the CLI: zubo secrets set WEATHER_API_KEY abc123

Skill Directory Structure

All skills live under the Zubo workspace directory. Each skill gets its own folder containing a handler.ts file:

~/.zubo/workspace/skills/
├── weather/
│   └── handler.ts      # Single-file skill
├── calculator/
│   ├── SKILL.md         # Legacy format (still supported)
│   └── handler.ts
├── email_sender/
│   └── handler.ts
└── stock_price/
    └── handler.ts

When Zubo starts (or when a skill is added/modified), it scans this directory and hot-loads all valid skills. You can manually place files here or use zubo skills new to scaffold them.

Sandbox Behavior

Security is a core concern when running user-authored code. Zubo enforces the following sandbox rules for user-installed skills:

Community Skill Registry

The Zubo Skill Registry is a centralized community marketplace at zubo.bot/skills where you can discover, install, star, and publish skills. It features:

You can also browse and install skills by chatting with Zubo: "Search for a skill that sends emails" or "Install the github_issues skill."

Publishing a Skill

To publish a skill to the community registry:

  1. Create your skill locally in ~/.zubo/workspace/skills/my-skill/handler.ts.
  2. Authenticate by visiting zubo.bot/skills and signing in with GitHub.
  3. Publish via the CLI: zubo publish my-skill.
  4. Or publish via the web form on the skills page at zubo.bot/skills.
  5. The auto-review scanner runs automatically. Clean code is approved immediately. Medium-risk code is flagged for manual review. High-risk code is rejected with detailed findings.
  6. Both the CLI and web form display the auto-review results after submission.

Registry CLI Commands

zubo search <query>     # Search the registry
zubo install <name>     # Install a skill from the registry
zubo publish <name>     # Publish your local skill to the registry

The agent can also perform these actions via the skill_registry built-in tool, which supports search, install, and publish actions. All registry-installed skills are sandboxed by default, just like locally created skills.

Managing Skills

Use the CLI to manage your installed skills:

zubo skills list          # List all installed skills
zubo skills new           # Create a new skill interactively
zubo skills remove        # Remove an installed skill
zubo install weather      # Install a skill from the registry
zubo search "email"       # Search the registry for skills
zubo publish my_skill     # Publish your skill to the registry

Or manage skills conversationally by telling Zubo:

Built-in Tools Reference

Zubo ships with a comprehensive set of built-in tools that are always available. These are not sandboxed — they run in the main process and have full access to Zubo's internals.

ToolDescriptionPermission
get_current_datetimeGet current date and time with timezoneauto
memory_writeSave a fact or note to persistent memoryauto
memory_searchSearch memory using semantic and full-text searchauto
kg_queryQuery the knowledge graph for entities and relationshipsauto
kg_updateAdd or update entities and relationships in the knowledge graphauto
manage_skillsCreate, list, or remove user skillsauto
secret_setStore a secret (API key, token, etc.)auto
secret_listList all stored secret namesauto
secret_deleteDelete a stored secretconfirm
cron_createCreate a scheduled task (cron job or one-shot reminder)auto
cron_listList all scheduled tasks and remindersauto
cron_deleteDelete a scheduled task or reminderauto
reminder_setSet a one-time reminder that fires after a delay and auto-deletesauto
config_updateRead or update Zubo's own configuration at runtimeauto
connect_serviceConnect an external integration (GitHub, Google, etc.)auto
delegateDelegate a task to a sub-agentauto
delegate_taskDelegate a task to an ad-hoc sub-agentauto
manage_agentsCreate, list, or remove sub-agentsauto
diagnoseCheck recent errors and system healthauto
manage_workflowsCreate and manage multi-step workflowsauto
manage_teamsManage agent teams and coordinationauto
manage_triggersManage proactive triggers and alertsauto
run_workflowExecute a defined workflowauto
skill_registrySearch and install skills from the registryauto
shellExecute shell commands on the host systemconfirm
file_readRead the contents of a fileauto
file_writeWrite or append content to a fileconfirm
code_interpreterExecute Python, JavaScript, or TypeScript codeconfirm
web_searchSearch the web via DuckDuckGoauto
url_fetchFetch and extract content from a web pageauto
http_requestMake a generic HTTP request (GET, POST, etc.)auto
image_generateGenerate images using AI (DALL-E, etc.)auto
webhook_manageCreate, list, or remove incoming webhooksauto
oauth_manageManage OAuth provider connectionsauto
todosAdd, list, complete, update, and remove tasks with priorities, due dates, and tagsauto
notesSave, search (FTS5), list, update, delete, and pin notes with tagsauto
preferencesSet, get, list, and remove user preferences (injected into system prompt)auto
topicsCreate, switch, list, and archive conversation topicsauto
follow_upsSchedule, list, and cancel proactive follow-up messagesauto

Tools marked confirm require user confirmation before execution. Tools marked auto run immediately without prompting.

Personal Features

Built-in tools for personal productivity — todos, notes, preferences, conversation topics, and scheduled follow-ups. These run in the main process (not sandboxed) and store data in your local SQLite database.

todos

A full task manager built into your agent. Add tasks, set priorities and due dates, tag them for organization, and check them off when done.

ActionDescription
addCreate a new task with an optional priority (low, medium, high), due date, and tags.
listList tasks, optionally filtered by status, priority, tag, or due date.
completeMark a task as done by ID.
updateUpdate a task's text, priority, due date, or tags.
removeDelete a task by ID.

Key parameters: text (string), priority ("low" | "medium" | "high"), due (date string), tags (comma-separated), id (task ID for update/complete/remove).

Example:

"Add a todo: finish the API docs, high priority, due Friday, tag: work"
"Show my todos tagged work"
"Complete todo #3"

notes

Save, search, and organize notes with full-text search (FTS5). Pin important notes so they surface first.

ActionDescription
saveCreate a new note with optional title, tags, and pinned status.
searchFull-text search across all notes using FTS5.
listList all notes, optionally filtered by tag or pinned status.
updateUpdate a note's content, title, tags, or pinned status.
deleteDelete a note by ID.
pinToggle the pinned status of a note.

Key parameters: title (string), content (string), tags (comma-separated), pinned (boolean), query (search string), id (note ID).

Example:

"Save a note: meeting with design team moved to Thursday 2pm, tag: meetings"
"Search my notes for API design"
"Pin note #5"

preferences

Store user preferences as category/key/value pairs. Preferences are automatically injected into the system prompt so the agent always knows your settings.

ActionDescription
setSet a preference value for a given category and key.
getRetrieve a specific preference by category and key.
listList all preferences, optionally filtered by category.
removeDelete a preference by category and key.

Key parameters: category (string, e.g. "display", "communication", "coding"), key (string), value (string).

Example:

"Set my preference: coding/language = TypeScript"
"What are my communication preferences?"
"Remove preference coding/editor"

topics

Organize conversations into named topics. Each topic scopes a separate session, so context stays focused and you can switch between projects easily.

ActionDescription
createCreate a new topic with a name and optional description.
switchSwitch the active conversation to a different topic.
listList all topics, including archived ones.
archiveArchive a topic to keep things tidy without deleting history.

Key parameters: name (string), description (string), id (topic ID for switch/archive).

Example:

"Create a topic called 'Website Redesign'"
"Switch to the API project topic"
"List my topics"
"Archive the old marketing topic"

follow_ups

Schedule proactive follow-up messages that Zubo sends to you at a specified time. Uses one-shot cron jobs under the hood — the job fires once and auto-deletes.

ActionDescription
scheduleSchedule a follow-up message for a specific time or delay.
listList all pending follow-ups.
cancelCancel a scheduled follow-up by ID.

Key parameters: message (string — what Zubo should say), time (date/time string or natural language like "in 2 hours", "tomorrow at 9am"), id (follow-up ID for cancel).

Example:

"Follow up with me tomorrow at 10am about the deployment"
"List my pending follow-ups"
"Cancel follow-up #2"

Legacy Format (SKILL.md)

Earlier versions of Zubo used a Markdown-based skill definition file called SKILL.md. This format is still fully supported for backward compatibility:

# weather
Get current weather for a location.

## Input Schema
```json
{
  "type": "object",
  "properties": {
    "location": { "type": "string", "description": "City or coordinates" }
  },
  "required": ["location"]
}
```

If both a SKILL.md file and an exported skill configuration object exist in the same skill directory, the SKILL.md definition takes precedence. For new skills, the inline export const skill format is recommended as it keeps everything in a single file.

Best Practices