Skill Management#
Overview#
A skill is a packaged unit of agent behavior: a named Markdown body paired with optional bundled files (scripts, configs, references). Skills are defined in SKILL.md format, attached to an agent config, resolved server-side, materialized on disk by the runner, and discovered by Pi at execution time.
The skill system was introduced across the SDK, API, and runner in PR #4814 , with bundled file storage and runtime execution added in PR #4782 .
SKILL.md Format#
A SKILL.md file is a YAML frontmatter block followed by a Markdown body:
---
name: release-notes
description: Draft release notes from a changelog.
allowed-tools: Read, Bash
disable-model-invocation: false
---
Read the changelog, then write release notes...
Frontmatter fields :
| Field | Required | Description |
|---|---|---|
name | β | Lowercase alphanumeric + hyphens, β€64 chars |
description | β | Trigger text for model invocation (1β1024 chars) |
allowed-tools | β | Comma-separated tool list the skill may invoke |
disable-model-invocation | β | Hides skill from model prompt; invoke only via /skill:name |
user-invocable | β | Whether non-agents can trigger the skill directly |
The body (everything after ---) can be up to 50,000 chars. Skills can also declare auxiliary files with path, content, and an optional executable flag .
SDK Layer#
Python skill models live in sdks/python/agenta/sdk/agents/skills/ :
models.pyβSkillConfig(name, description, body, files, flags) andSkillFile(path, content, executable).SkillFile.pathrejects absolute paths, parent-directory escapes, and collisions withSKILL.md.parsing.pyβparse_skill_config()/parse_skill_configs()validate inputs and raiseSkillConfigurationErrorwith indexed diagnostics.wire.pyβskills_to_wire()serializesSkillConfigobjects to the camelCase wire format consumed by the runner.errors.pyβSkillConfigurationErrorwith message, optional index, and value.
Skills are added to AgentConfig and HarnessAgentConfig via a skills field. Inline skills can be written directly; @ag.embed references to is_skill workflows are resolved server-side by ResolverMiddleware before the runner receives them .
API Layer#
There are no dedicated skill endpoints. Skills flow through the existing workflow catalog and config APIs .
Platform/static skills are defined in api/oss/src/core/workflows/platform_catalog.py under the reserved _agenta.* slug namespace, with deterministic UUIDs for stable cross-instance identity. Three build-flow platform skills β __ag__build_your_first_app, __ag__discover_and_wire_tools, and __ag__set_up_triggers β use the reserved __ag__ slug prefix and were added in PR #4930 . A ReservedWorkflowSlugException (HTTP 400) prevents user workflows from shadowing these reserved prefixes.
Runner: Materialization and Execution#
Skills Engine (services/agent/src/engines/skills.ts)#
Introduced in PR #4814 , this TypeScript engine transforms resolved inline skill packages into on-disk directories:
- Creates a per-run temp root directory.
- For each skill: validates the name (rejects
../, non-alphanumeric), composesSKILL.mdwith YAML-escaped frontmatter (:,#,"are quoted), writes bundled files, and optionallychmod +xexecutable files. - Triple-gated executable policy: skill opt-in (
allowExecutableFiles=true) + file opt-in (executable=true) + caller policy (default deny). - Deduplicates by name (later duplicates are skipped); unsafe file paths are logged and skipped rather than aborting the run.
- Returns
{ name, dir }[]plus acleanup()callback called in afinallyblock.
Bundled ("Forced") Skills#
Bundled skills are static directories under services/runner/skills/ (volume-mounted in dev) . The resolveSkillDirs() function maps skill names to these directories; the root is overridable via AGENTA_AGENT_SKILLS_DIR .
The Agenta harness injects a fixed skill set into every pi_agenta run. Internally it maps agenta β pi for the rivet/ACP backend while preserving agenta as the user-facing identity in logs and traces .
Skill Path Stability on Cold Resume#
PR #5295 fixed cold-resume failures caused by skill paths changing after sandbox teardown.
Root cause: skills were copied into a random per-run directory deleted at teardown, leaving dangling paths on resume.
Fix: skills are now stored as content-addressed snapshots at a stable path:
<cwd>/agents/skills/<digest>/<skill-name>
The digest is computed from skill names, file paths, modes, and contents. Snapshots are published atomically via a staging directory + completion marker and are never deleted (append-only) until the session workspace itself is removed. pi-acp reads the path via PI_CODING_AGENT_SKILL_DIR .
Local Pi vs. Daytona Sandboxes#
| Aspect | Local Pi | Daytona |
|---|---|---|
| Skill deposit | Per-run throwaway PI_CODING_AGENT_DIR, seeded from login credentials | Uploaded via sandbox FS API (uploadSkillsToSandbox) |
| Isolation | Temp dir deleted in finally to prevent leakage to ~/.pi/agent | Built-in per-sandbox isolation |
| File types | Full tree with symlink dereferencing | UTF-8 text only (binary deferred) |
Frontend: Skill Upload UI#
The skill editor lives in web/packages/agenta-entity-ui/ β a separate package from the OSS web/oss/ app. It was introduced in PR #4850 and extended with drawer-based editing in PR #4881 .
Key components (all under web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/):
| File | Role |
|---|---|
SkillFormView.tsx | Full skill editor drawer: markdown editor, file uploads, metadata fields, Edit/Preview toggle |
SkillUploadZone.tsx | Drag-and-drop upload zone for bundled skill files |
skillUpload.ts | parseSkillMarkdown(), mergePastedSkill(), and upload utilities |
MarkdownEditor.tsx | Markdown editor with toolbar; toggle is "Source" / "Rich text" |
SkillTemplateControl.tsx | Config panel inline summary (renamed from SkillConfigControl in PR #4900 ) |
The skill editor mirrors the Tools and MCP section pattern: compact summary in the config panel, full editing in a right-hand drawer.
Paste-a-SKILL.md#
PR #5258 added drawer-wide paste support β the primary workaround for remote machines where drag-and-drop is unavailable:
- A document-level
pastelistener on the drawer ignores pastes when any text input is focused. - Detects a SKILL.md by a leading
---frontmatter delimiter; non-matching pastes fall through. - Calls
mergePastedSkill(), which runsparseSkillMarkdown()and updatesname,description, andbodyβ but never modifies bundledfiles. - Shows a toast: "Filled from the pasted skill." UI hint: "β¦or paste a SKILL.md anywhere here to fill the fields."
Key Source Locations#
| Layer | Path |
|---|---|
| SDK models & parsing | sdks/python/agenta/sdk/agents/skills/ |
| Platform skill catalog | api/oss/src/core/workflows/platform_catalog.py |
| Runner materialization engine | services/agent/src/engines/skills.ts |
| Bundled skill directories | services/runner/skills/ |
| Frontend skill editor | web/packages/agenta-entity-ui/src/DrillInView/SchemaControls/ |
| Example SKILL.md | .agents/skills/self-host-agenta/SKILL.md |
Related PRs#
| PR | Summary |
|---|---|
| #4782 | Bundled skill file storage and runner execution |
| #4814 | Full skill system: SDK models, runner materialization, API catalog |
| #4850 | Frontend skill form view and upload zone |
| #4881 | Agent config section drawers with skill editor |
| #4900 | Rename SkillConfig β SkillTemplate; fix schema normalization |
| #4930 | Build-flow platform skills (__ag__ slugs) |
| #5258 | Frontend paste-a-SKILL.md + toggle label fix |
| #5295 | Content-addressed skill snapshots for cold-resume stability |
| #5310 | Example self-host-agenta skill with SKILL.md and resource files |