Skills
Skills are modular extensions to the AI agent. A skill can provide:
- Domain knowledge — documentation, conventions, or constraints injected into the agent’s system prompt
- Runnable scripts — tools the agent can call during a task (shell scripts, Python scripts, TypeScript, executables)
- Reference files — documentation the agent can query mid-task
Skills allow you to give the agent specialised expertise for specific frameworks, internal APIs, company conventions, or complex workflows without modifying Tarsk itself.
How Skills Work
Section titled “How Skills Work”When you send a message, Tarsk scans all available skills and automatically activates those whose descriptions match keywords in your message. Activated skills are appended to the system prompt under an # Available Skills section before the agent processes your request.
You can also explicitly enable or disable specific skills per thread (see below).
Skill Structure
Section titled “Skill Structure”A skill is a directory containing a SKILL.md file. The minimum structure is:
my-skill/ SKILL.mdThe SKILL.md file uses YAML frontmatter followed by content injected into the system prompt:
---name: My Skilldescription: Provides guidance for working with internal payments API.license: MITcompatibility: Node.js 18+, Python 3.9+---
## Payments API
Always use `PaymentService` class from `src/services/payment.ts`.Never call Stripe API directly — use abstraction layer....Frontmatter Fields
Section titled “Frontmatter Fields”| Field | Required | Description |
|---|---|---|
name | Yes | Display name for skill (must match directory name, 1-64 chars, lowercase alphanumeric, hyphens only) |
description | Yes | Used for auto-activation keyword matching (1-1024 chars) |
license | No | License identifier (e.g. MIT) |
compatibility | No | System requirements or dependencies |
allowed-tools | No | Restrict which agent tools this skill can invoke |
Optional Subfolders
Section titled “Optional Subfolders”my-skill/ SKILL.md scripts/ ← runnable tools exposed to agent generate.sh validate.py scaffold.ts references/ ← documentation agent can read on demand api-spec.md schema.json assets/ ← static files, images, data templates/ output.jsonscripts/ — Any executable file here becomes an agent tool. The agent can call it with arguments. Supported types:
.sh,.bash→bash.py→python3.js→node.ts→bun run- Other extensions → Direct execution if executable
references/ — Files agent can read via read_skill_reference. Useful for large specifications or schemas you don’t want injected into every prompt automatically.
assets/ — Static files the skill can reference, such as templates, configuration files, or data files.
Skill Discovery Locations
Section titled “Skill Discovery Locations”Tarsk looks for skills in two locations:
| Location | Scope |
|---|---|
~/.tarsk/skills/ | Global — available to all projects and threads |
<threadPath>/.tarsk/skills/ | Project-level — only available within that project |
Project-level skills take precedence over global skills with the same name. This lets you override a global skill’s behaviour for a specific project.
Enabling and Disabling Skills Per Thread
Section titled “Enabling and Disabling Skills Per Thread”By default, skills are auto-activated based on keyword matching. To override this behaviour for a thread:
- Click the Skills section in the thread’s sidebar panel.
- Toggle individual skills on (always enabled) or off (always disabled) regardless of keyword matching.
This is useful when a skill is relevant to a project but not to a specific thread, or when you want to force a skill to always be active.
Creating a Skill
Section titled “Creating a Skill”- Create a directory in
~/.agents/skills/(global) or<threadPath>/.agents/skills/(project-level):Terminal window mkdir -p ~/.agents/skills/my-skill - Create
SKILL.mdwith the frontmatter and instructions. - Optionally add
scripts/andreferences/subdirectories. - Start a new conversation — the skill is available immediately.
Example: Framework Conventions Skill
Section titled “Example: Framework Conventions Skill”---name: React Query Conventionsdescription: Conventions for using React Query and TanStack Query in this project.---
## Query Keys
Always define query keys as constants in `src/query-keys.ts`.Never inline query key strings.
## Mutations
Use `useMutation` hook from `@tanstack/react-query`:
```typescriptconst createUser = useMutation({ mutationFn: (userData: CreateUserInput) => api.post("/users", userData), onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.users }); toast.success("User created successfully"); }, onError: (error) => { toast.error(`Failed to create user: ${error.message}`); },});```Always invalidate related queries in onSuccess.
Queries
Section titled “Queries”Use useQuery with proper error handling:
const { data: users, isLoading, error } = useQuery({ queryKey: queryKeys.users, queryFn: () => api.get('/users'), staleTime: 5 * 60 * 1000, // 5 minutes retry: 3});
if (isLoading) return <LoadingSpinner />;if (error) return <ErrorMessage error={error} />;return <UserList users={users} />;This skill activates automatically when user's message mentions "query", "fetch", "mutation", or similar terms.
## Script Examples
### PDF Text Extractor Script
**File:** `~/.tarsk/skills/pdf-processing/scripts/extract-text.py`
```python#!/usr/bin/env python3import sysimport jsonimport PyPDF2
def main(): if len(sys.argv) < 2: print(json.dumps({"error": "No PDF path provided"}), file=sys.stderr) sys.exit(1)
pdf_path = sys.argv[1]
try: with open(pdf_path, 'rb') as file: reader = PyPDF2.PdfReader(file) text = "" for page in reader.pages: text += page.extract_text()
print(json.dumps({ "success": True, "text": text, "pages": len(reader.pages) })) except Exception as e: print(json.dumps({"error": str(e)}), file=sys.stderr) sys.exit(1)
if __name__ == "__main__": main()Make it executable:
chmod +x ~/.tarsk/skills/pdf-processing/scripts/extract-text.pyDatabase Query Script
Section titled “Database Query Script”File: database-queries/scripts/explain-query.sh
#!/bin/bashQUERY="$1"DB_NAME="${2:-postgres}"
if [ -z "$QUERY" ]; then echo "Error: No query provided" >&2 exit 1fi
echo "Analyzing query execution plan..."psql -d "$DB_NAME" -c "EXPLAIN ANALYZE $QUERY"Script Best Practices
Section titled “Script Best Practices”- Accept arguments: Use command line arguments for input
- Output JSON: Return structured data for easy parsing
- Error handling: Send errors to stderr, exit with non-zero status
- Dependencies: Check for required tools/libraries
- Timeouts: Keep operations under 30 seconds
# Good: Accept input as argumentsINPUT_FILE = sys.argv[1] if len(sys.argv) > 1 else None
# Good: Output structured dataprint(json.dumps({"result": data, "success": True}))
# Good: Errors to stderrprint("Error processing file", file=sys.stderr)Reference Files
Section titled “Reference Files”API Documentation
Section titled “API Documentation”File: stripe-api/references/api-reference.md
# Stripe API Reference
## Authentication
All API requests require authentication using your secret key:
```bashcurl https://api.stripe.com/v1/charges \ -u sk_test_your_key:```Create a Payment Intent
Section titled “Create a Payment Intent”Endpoint: POST /v1/payment_intents
Parameters:
amount(required): Amount in centscurrency(required): Three-letter ISO codepayment_method_types(required): Array of payment methods
Example:
curl https://api.stripe.com/v1/payment_intents \ -u sk_test_your_key: \ -d amount=1000 \ -d currency=usd \ -d "payment_method_types[]"=card### Referencing in Skills
Tell the agent about reference files:
```markdown---name: stripe-apidescription: Work with Stripe payment APIs---
## Reference Documentation
For detailed API documentation, use the `read_skill_reference` tool with:- skillName: "stripe-api"- referencePath: "api-reference.md"
For authentication examples, use:- referencePath: "guides/authentication.md"## Naming and Validation
### Valid Skill Names
✅ **Good names:**- `pdf-processing`- `web-scraping`- `database-tools`- `api-testing`- `code-review`
❌ **Invalid names:**- `PDF-Processing` (uppercase not allowed)- `pdf_processing` (underscores not allowed)- `pdf processing` (spaces not allowed)- `-pdf` (cannot start with hyphen)- `pdf-` (cannot end with hyphen)- `pdf--processing` (consecutive hyphens not allowed)
**Rules:**- 1-64 characters- Lowercase letters, numbers, and hyphens only- Must not start or end with hyphen- No consecutive hyphens
## Skill Activation
### Auto-Discovery
Tarsk matches your task to relevant skills:
**Your task:**> "Extract the table data from this PDF file"
**Activated skills:**- `pdf-processing` (matches "PDF")- `data-extraction` (matches "extract" and "table data")
**How it works:**1. Tarsk extracts keywords from your task2. Compares keywords to skill descriptions3. Activates top 5 most relevant skills (threshold: 10% keyword match)
### Manual Override
Control which skills are active for a thread:
**Enable specific skills only:**```javascript// In thread metadata{ "enabledSkills": ["pdf-processing", "ocr-helper"]}Disable specific skills:
{ "disabledSkills": ["web-scraping"]}Advanced Features
Section titled “Advanced Features”Progressive Disclosure
Section titled “Progressive Disclosure”Skills use progressive disclosure to minimize context usage:
1. Startup (always loaded):
- Skill name and description
- ~100 tokens per skill
2. Activation (when skill matches):
- Full SKILL.md instructions
- <5000 tokens per skill
3. On-demand (when agent requests):
- Reference files via
read_skill_reference - Loaded only when needed
Script Timeouts
Section titled “Script Timeouts”Scripts have a 30-second timeout by default. For longer operations:
Option 1: Stream progress
import sys
for i in range(100): process_chunk(i) print(f"Progress: {i}%", file=sys.stderr) sys.stderr.flush()Option 2: Background processing
#!/bin/bashnohup long-running-process.sh > output.log 2>&1 &PID=$!echo "Started process: $PID"echo "Check output: tail -f output.log"Troubleshooting
Section titled “Troubleshooting”Skill Isn’t Activating
Section titled “Skill Isn’t Activating”Check the skill name:
- Must match directory name exactly
- Lowercase, alphanumeric, hyphens only
Check frontmatter:
# ❌ Missing closing delimitername: my-skilldescription: My skill
# ❌ Name mismatchDirectory: my-skill/Frontmatter: name: different-name
# ✅ Correct---name: my-skilldescription: My skill---Check description keywords: Make sure your skill description includes keywords related to your task.
Script Isn’t Executing
Section titled “Script Isn’t Executing”Check permissions:
chmod +x ~/.tarsk/skills/my-skill/scripts/my-script.shCheck dependencies:
try: import PyPDF2except ImportError: print("Error: PyPDF2 not installed. Run: pip install PyPDF2", file=sys.stderr) sys.exit(1)Getting Started Checklist
Section titled “Getting Started Checklist”- Create skills folder:
mkdir -p ~/.tarsk/skills - Create your first skill (e.g.,
code-review) - Write clear instructions in SKILL.md
- Test activation with a relevant task
- Add scripts for specialized tools (optional)
- Add reference docs for detailed info (optional)
- Create project-specific skills in
.tarsk/skills/ - Commit project skills to git for your team
Skills transform Tarsk from a general-purpose AI assistant into a specialized tool tailored to your specific technologies, workflows, and requirements.