Documentation Index
Fetch the complete documentation index at: https://docs.orcbot.buzzchat.site/llms.txt
Use this file to discover all available pages before exploring further.
OrcBot’s skills system is the interface between the LLM’s reasoning and the outside world. Skills are executable functions that the agent can call to perform actions: search the web, send messages, run commands, manipulate files, and more.
Architecture
Skill Types
1. Core Skills
Purpose: Built-in tools registered at agent startup.
Implementation: Agent.ts (lines 908-2500+) — registerInternalSkills()
Registration:
this.skills.registerSkill({
name: 'web_search',
description: 'Search the web for information. Use this for current events, facts, or research.',
usage: 'web_search(query)',
handler: async (args) => {
const query = args.query;
const results = await this.browser.search(query);
return JSON.stringify(results, null, 2);
},
isResearch: true, // Higher repetition budget
isDeep: true // Counts as substantive progress
});
Categories:
| Category | Skills | Description |
|---|
| Research | web_search, browser_navigate, http_fetch, extract_article, download_file | Web browsing and data retrieval |
| Communication | send_telegram, send_whatsapp, send_discord, send_slack, send_email | Multi-channel messaging |
| Telegram Rich UI | telegram_send_buttons, telegram_send_poll, telegram_react, telegram_edit_message, telegram_pin_message | Interactive Telegram features |
| File Operations | read_file, write_file, send_file, send_voice_note | File I/O and delivery |
| System | run_command, get_system_info, system_check | Shell execution and diagnostics |
| Memory | recall_memory, update_user_profile, update_learning, update_journal | Long-term storage |
| RAG | rag_ingest, rag_search, rag_ingest_url, rag_list, rag_delete | Knowledge store operations |
| Orchestration | schedule_task, heartbeat_schedule, spawn_agent, delegate_task | Task scheduling and multi-agent |
| Configuration | manage_config | Runtime config modification |
| Reasoning | deep_reason, request_supporting_data | Extended reasoning and clarification |
| Skills Meta | manage_skills, create_custom_skill, self_repair_skill | Skill lifecycle |
Full list: See SKILLS.md
2. Dynamic Plugins
Purpose: Hot-reloadable TypeScript/JavaScript files for custom skills.
Location: ~/.orcbot/plugins/*.ts or ./plugins/*.ts
Format:
// ~/.orcbot/plugins/weather-api.ts
export default {
name: 'weather_api',
description: 'Get weather from OpenWeatherMap API. Use for weather queries.',
usage: 'weather_api(city)',
handler: async (args: any, context: any) => {
const apiKey = context.config.get('openWeatherApiKey');
const city = args.city;
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`;
const response = await fetch(url);
const data = await response.json();
return `Weather in ${city}: ${data.main.temp}°C, ${data.weather[0].description}`;
},
isDeep: true, // Resets communication cooldown
isParallelSafe: false // Can't run in parallel with other tools
};
Loading:
// Automatic at startup
skillsManager.loadPlugins();
// Manual hot reload
skillsManager.loadPlugins();
logger.info('Plugins reloaded');
Hot Reload: OrcBot clears the require cache before each load, so you can edit plugins without restarting:
# 1. Edit plugin
vim ~/.orcbot/plugins/weather-api.ts
# 2. Trigger reload (automatic on file change, or manual via TUI)
orcbot ui → Skills → Reload Plugins
Safety:
# orcbot.config.yaml
pluginAllowList: [weather_api, custom_tool] # Only these plugins load
pluginDenyList: [dangerous_plugin] # Block these plugins
safeMode: true # Disable all plugins
3. Agent Skills (SKILL.md)
Purpose: Declarative skill packages following the agentskills.io spec.
Location: ~/.orcbot/plugins/skills/*/SKILL.md
Format:
---
name: web-scraper
description: Advanced web scraping with Cheerio and Puppeteer. Use for extracting structured data from complex websites.
license: MIT
compatibility: orcbot >= 2.0
allowedTools:
- browser_navigate
- http_fetch
- run_command
orcbot:
autoActivate: false
requiredPackages:
- cheerio
- puppeteer
permissions:
- network
- browser
triggerPatterns:
- scrape.*website
- extract.*data.*from
---
# Web Scraper Skill
## When to Use
Use this skill when the user asks to:
- Extract structured data from a website (tables, lists, prices)
- Scrape multiple pages following pagination
- Parse complex HTML structures beyond simple article extraction
## Approach
1. First, use `browser_navigate` to inspect the page structure
2. If the page requires JavaScript, use the browser. Otherwise, use `http_fetch` + Cheerio for speed.
3. Identify CSS selectors for the target data
4. Extract and structure the data as JSON
5. Handle pagination by following "next" links
## Example Selectors
```javascript
// Extract product prices
const prices = $('span.price').map((i, el) => $(el).text()).get();
// Extract table rows
const rows = $('table tr').map((i, el) => {
return $(el).find('td').map((j, cell) => $(cell).text()).get();
}).get();
Error Handling
- If the page is protected by CAPTCHA, inform the user
- If selectors fail, try alternative patterns (XPath, data attributes)
- If rate-limited, suggest adding delays between requests
**Progressive Disclosure:**
Agent skills use a 2-level disclosure system:
**Level 1: Metadata only (always in prompt)**
```xml
<available_skills>
<skill>
<name>web-scraper</name>
<description>Advanced web scraping with Cheerio and Puppeteer...</description>
<scripts>scrape.ts, pagination.ts</scripts>
<references>cheerio-guide.md, puppeteer-tips.md</references>
</skill>
</available_skills>
Level 2: Full instructions (activated on-demand)
// Agent calls activate_skill("web-scraper")
const skill = skillsManager.activateAgentSkill('web-scraper');
// Now the full SKILL.md body is injected into the prompt
Installation:
# From npm package (follows agentskills.io spec)
orcbot skill install firecrawl/cli
# → Resolves to @firecrawl/cli or firecrawl-cli
# → Downloads via npm pack
# → Extracts and discovers SKILL.md files
# → Installs to ~/.orcbot/plugins/skills/
# From GitHub repo
orcbot skill install https://github.com/user/repo
# From local directory
orcbot skill install ./my-skill/
# From .skill (zip) file
orcbot skill install ./my-skill.skill
Skill matching (auto-activation):
// On action start, SkillsManager scans task description
const matched = await skills.classifySkillsWithLLM(taskDescription, llm);
// → Activates matched skills automatically
// Fallback to regex if LLM unavailable
const matched = skills.matchSkillsForTask(taskDescription);
Skill Interface
interface Skill {
name: string; // Unique identifier (lowercase, no spaces)
description: string; // What it does + when to use it
usage: string; // Example call: "web_search(query)"
handler: (args: any, context?: AgentContext) => Promise<any>;
// Optional metadata flags
pluginPath?: string; // Source file (for uninstallation)
sourceUrl?: string; // Original URL (if generated)
isResearch?: boolean; // Higher repetition budget
isSideEffect?: boolean; // Subject to deduplication
isDeep?: boolean; // Resets communication cooldown
isDangerous?: boolean; // Requires confirmation in autonomy
isElevated?: boolean; // Requires admin privileges
isParallelSafe?: boolean; // Can run in parallel
}
isResearch:
- Higher tool repetition budget (10 vs. 5)
- Used for: web_search, browser_navigate, http_fetch
- Prevents premature loop detection during research
isSideEffect:
- Subject to strict deduplication
- Used for: send_telegram, send_whatsapp, write_file
- Prevents duplicate messages/writes
isDeep:
- Resets transparency nudge timer
- Counts as “substantive progress”
- Used for: web_search, browser_navigate, run_command, deep_reason
- Tells termination review: “real work was done”
isDangerous:
- Requires explicit confirmation in autonomy mode
- Used for: run_command, delete_file, install_npm_dependency
- Blocks execution if user approval not granted
isElevated:
- Requires admin privileges
- Filtered out for non-admin tasks
- Used for: run_command, write_file, manage_config, browser_navigate
isParallelSafe:
- Can be executed in parallel with other parallel-safe tools
- Used for: read_file, http_fetch (read-only operations)
- Enables concurrent execution in multi-agent scenarios
Skill Execution Flow
// 1. LLM decides to call a tool
const decision = {
tools: [
{ name: 'web_search', metadata: { query: 'Paris weather' } }
]
};
// 2. Agent looks up skill
const skill = skills.getSkill('web_search');
if (!skill) {
throw new Error('Skill not found: web_search');
}
// 3. Validate arguments (basic checks)
if (!decision.tools[0].metadata.query) {
throw new Error('Missing required argument: query');
}
// 4. Execute handler
try {
const result = await skill.handler(
decision.tools[0].metadata,
{ browser, config, agent, logger }
);
// 5. Save observation to memory
memory.saveMemory({
id: `${actionId}-step-${step}`,
type: 'short',
content: `Observation: Tool ${skill.name} returned ${result}`,
metadata: { actionId, step, skill: skill.name }
});
} catch (error) {
// 6. Save error to memory
memory.saveMemory({
id: `${actionId}-step-${step}-error`,
type: 'short',
content: `Observation: Tool ${skill.name} FAILED: ${error.message}`,
metadata: { actionId, step, skill: skill.name, error: true }
});
}
For LLMs that support native function calling (OpenAI, Google), SkillsManager generates JSON schemas:
interface LLMToolDefinition {
type: 'function';
function: {
name: string;
description: string;
parameters: {
type: 'object';
properties: Record<string, any>;
required: string[];
};
};
}
// Generated from skill metadata
const toolDefs = skills.getToolDefinitions();
// [
// {
// type: 'function',
// function: {
// name: 'web_search',
// description: 'Search the web for information...',
// parameters: {
// type: 'object',
// properties: {
// query: { type: 'string', description: 'Search query' }
// },
// required: ['query']
// }
// }
// },
// ...
// ]
Passed to LLM:
const response = await llm.callWithTools(prompt, systemPrompt, toolDefs);
// Native response:
// {
// content: "I'll search for Paris weather.",
// toolCalls: [
// { name: 'web_search', arguments: { query: 'Paris weather' } }
// ]
// }
Skill Context (AgentContext)
All skill handlers receive a context object:
interface AgentContext {
browser: WebBrowser; // Playwright browser instance
config: ConfigManager; // Runtime configuration
agent: Agent; // Full agent instance
logger: Logger; // Winston logger
workerProfile?: WorkerProfileManager; // Multi-agent metadata
orchestrator?: AgentOrchestrator; // Worker spawn/coordination
[key: string]: any; // Custom extensions
}
// Usage in skill handler:
handler: async (args, context) => {
const apiKey = context.config.get('myApiKey');
const userAgent = await context.browser.getUserAgent();
context.logger.info('Executing custom skill');
// Access agent methods
await context.agent.pushTask('Follow-up task', 5);
return 'Result';
}
Prompt Injection
Compact mode (after step 1):
AVAILABLE SKILLS:
- web_search(query) — Search the web
- browser_navigate(url) — Visit a URL
- send_telegram(chatId, message) — Send Telegram message
[... 40+ more skills, name + usage only]
AGENT SKILLS:
- web-scraper — Advanced web scraping (use activate_skill to load)
- pdf-extractor — Extract text from PDFs (use activate_skill to load)
Activated skills (after activate_skill called):
AVAILABLE SKILLS:
[... same as above]
ACTIVATED SKILL INSTRUCTIONS:
<skill name="web-scraper">
# Web Scraper Skill
## When to Use
Use this skill when the user asks to:
- Extract structured data from a website
...
</skill>
Skill Discovery
List all skills:
orcbot skill list
# Core Skills (45):
# - web_search: Search the web for information
# - browser_navigate: Visit a URL and extract content
# ...
#
# Dynamic Plugins (2):
# - weather_api: Get weather from OpenWeatherMap
# - custom_tool: My custom tool
#
# Agent Skills (3):
# - web-scraper: Advanced web scraping [INACTIVE]
# - pdf-extractor: Extract text from PDFs [ACTIVE]
# - news-finder: Find latest news [INACTIVE]
Inspect skill:
orcbot skill info web-scraper
# Name: web-scraper
# Description: Advanced web scraping with Cheerio and Puppeteer...
# License: MIT
# Required packages: cheerio, puppeteer
# Permissions: network, browser
# Trigger patterns: scrape.*website, extract.*data.*from
#
# Bundled resources:
# - scripts/scrape.ts
# - scripts/pagination.ts
# - references/cheerio-guide.md
# - references/puppeteer-tips.md
Creating Skills
Option 1: Core Skill (Hardcoded)
Edit Agent.ts and register:
this.skills.registerSkill({
name: 'my_skill',
description: 'What it does and when to use it',
usage: 'my_skill(arg1, arg2)',
handler: async (args, context) => {
// Implementation
return 'Result';
},
isDeep: true
});
Option 2: Dynamic Plugin
Create ~/.orcbot/plugins/my-skill.ts:
export default {
name: 'my_skill',
description: 'What it does and when to use it',
usage: 'my_skill(arg1, arg2)',
handler: async (args: any, context: any) => {
// Implementation
return 'Result';
}
};
Reload plugins via TUI or restart agent.
Option 3: Agent Skill (SKILL.md)
Create directory structure:
~/.orcbot/plugins/skills/my-skill/
├── SKILL.md # Frontmatter + instructions
├── scripts/
│ └── helper.ts # Executable scripts
├── references/
│ └── guide.md # Documentation
└── assets/
└── example.png # Images/files
Write SKILL.md:
---
name: my-skill
description: Brief description of what this skill does and when to use it
license: MIT
allowedTools:
- browser_navigate
- http_fetch
orcbot:
autoActivate: false
triggerPatterns:
- my.*skill.*pattern
---
# My Skill
## When to Use
...
## Approach
...
Restart agent or use:
Option 4: Self-Generated Plugin (create_custom_skill)
Ask the agent:
User: Create a skill that fetches crypto prices from CoinGecko
Agent: [Uses create_custom_skill to generate ~/.orcbot/plugins/crypto-price.ts]
Agent: Skill created and loaded. You can now use crypto_price(symbol).
Self-Repair
When a plugin fails to load (syntax error, missing dependency), OrcBot auto-triggers repair:
// SkillsManager.ts:296-315
try {
const plugin = require(pluginPath);
this.registerSkill(plugin);
} catch (error) {
logger.error(`Failed to load plugin ${file}: ${error.message}`);
// Push repair task
agent.pushTask(
`System Alert: Plugin '${skillName}' failed to compile. Error: ${error.message}. Use self_repair_skill to fix it.`,
10, // High priority
{ source: 'system', error: error.message, skillName }
);
}
The self_repair_skill handler:
- Reads the broken plugin file
- Analyzes the error (syntax, type, import)
- Calls LLM to generate a fix
- Writes corrected code
- Reloads plugins
- Validates the fix
Skill Validation
For Agent Skills (SKILL.md), OrcBot validates against the spec:
orcbot skill validate ~/.orcbot/plugins/skills/my-skill
# ✓ SKILL.md found
# ✓ Name matches directory (my-skill)
# ✓ Description is descriptive (120 chars)
# ✗ ERROR: name contains uppercase letters (must be lowercase)
# ✗ ERROR: description exceeds 1024 chars
Validation rules:
- Name: lowercase, alphanumeric + hyphens, no consecutive hyphens, 1-64 chars
- Description: 10-1024 chars
- Compatibility: 500 chars max
- Body: < 500 lines (warning only, large skills are valid)
Parallel Execution
Skills marked isParallelSafe: true can run concurrently:
const tools = [
{ name: 'read_file', metadata: { path: 'file1.txt' } },
{ name: 'read_file', metadata: { path: 'file2.txt' } },
{ name: 'http_fetch', metadata: { url: 'https://api.example.com' } }
];
// All are parallel-safe → execute concurrently
const results = await Promise.all(
tools.map(t => skills.execute(t.name, t.metadata, context))
);
Unsafe for parallel execution:
- write_file (race conditions)
- send_telegram (message ordering)
- run_command (shared stdout)
Configuration
# Skills behavior
safeMode: false # Disable dangerous skills
pluginAllowList: [] # Empty = all plugins allowed
pluginDenyList: [] # Block specific plugins by name
compactSkillsPrompt: false # Use compact format (names only)
skipSimulationForSimpleTasks: true # Skip pre-task simulation
# Skill routing
skillRoutingRules:
- intent: search
preferSkills: [web_search, browser_navigate]
- intent: code
preferSkills: [run_command, read_file, write_file]
# Plugin paths
pluginsPath: ~/.orcbot/plugins
skillsPath: ./SKILLS.md
# Agent skill auto-activation
agentSkillAutoActivatePatterns:
- web-scraper: "scrape.*website"
- pdf-extractor: "extract.*pdf"
Further Reading