> ## Documentation Index
> Fetch the complete documentation index at: https://user-docs.olyrosstudios.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Skills

> Skills let your team teach an agent a repeatable procedure once and reuse it everywhere the agent chats.

A skill is a `SKILL.md` document, optionally bundled with reference files and Python or
Node scripts, that a company keeps in its library and attaches to its chat agents. The
agent sees a catalog of its skills, loads one when a request matches, and can run a
skill's script in a disposable sandbox in Olyros's cloud or on one of the company's own
OHO machines. Skills live in the client app under the **Agents** sidebar group as
**Skills** (`/settings/skills`): a list, a three-column editor (`/settings/skills/new`,
`/settings/skills/:id/edit`) and a **Skills** tab on each agent (`/agents/:id/skills`).
Agents, [cloud tasks](https://user-docs.olyrosstudios.com/cloud-tasks-and-executors.md) and [sandboxes](https://user-docs.olyrosstudios.com/sandboxes.md) have
their own pages; see [Agents](https://user-docs.olyrosstudios.com/agents.md) for the agent itself.

## What it does

**A company library of versioned skills.** A skill is created from `SKILL.md` text in
the editor (`createSkill`, `updateSkill`) or from a zip upload
(`POST /api/v1/skills/bundles`). The frontmatter follows the Agent Skills format:
`name` (lowercase kebab-case, at most 64 characters, the `olyros-` prefix is reserved),
`description` (at most 1024 characters), optional `license`, `compatibility`,
`metadata`, `allowed-tools`, plus the Claude Code extensions `argument-hint`,
`user-invocable`, `disable-model-invocation` and `when_to_use`. Every save of changed
content writes an immutable version (`skillVersions`, `skillVersion`); an identical save
is a no-op; a save from a stale editor is rejected when `expectedLatestVersionId` no
longer matches. Any version can be restored as a new version (`restoreSkillVersion`,
with or without its files) and downloaded as a zip
(`GET /api/v1/skills/{skill_id}/versions/{version_id}/bundle.zip`). Validation errors
block a save; warnings are stored on the version and shown in the editor
(`validateSkill` dry-runs the editor text).

**Bundles with files.** A zip holds `SKILL.md` plus text files under `references/`,
`scripts/`, `assets/` or any folder (kinds `reference`, `script`, `asset`, `other`).
The pipeline rejects binary files, symlinks, duplicate paths, paths deeper than 4
segments and file names that hold secrets by convention (`.env*`, `*.pem`, `*.key`,
`id_rsa*`); it ignores `__MACOSX`, `.git`, `.DS_Store` and `Thumbs.db`. A browser save
of `SKILL.md` on a bundled skill carries the latest version's files forward, so every
version is a complete snapshot. The validator warns about unreferenced or oversized
files, scripts that call the network, read environment variables or import from outside
the skill, packages the sandbox image lacks (`DEPENDENCY_NOT_IN_IMAGE`), unsupported
script extensions, and hidden characters or secrets in any file.

**Bound to agents, per environment.** A company admin binds a skill to an agent
(`bindSkillToAgent`, `updateSkillBinding`, `unbindSkillFromAgent`) with an optional
pinned version (null follows the skill's current version), `environmentOverrides`
limited to `web_chat` and/or `slack`, and `invocationOverride` of `model`, `user` or
`both`. An inactive skill (`isActive = false`) is hidden from every agent; unbinding is
soft. `agentSkills` and `skillBindings` list bindings with `missingTools` (tools the
skill text references that the agent lacks) and `bridgeTools` (what its code may call).

**In chat: a catalog, a read tool and `/skill` commands.** Each turn the agent's active
skills (at most 20 per agent) are rendered into its system prompt as
`<available_skills>`. The built-in tool `olyros_skill_read(name, path?)` returns the full
`SKILL.md` or one bundle file, truncated at 32 KiB. Users invoke skills directly:
`/skill` or `/skills` shows a pick card, `/skill list all` lists names, `/skill help`,
`/skill info <name>`, `/skill <name> [arguments]` invokes one, and `/<name> [arguments]`
is a shorthand when the name resolves. `!` works wherever `/` does (Slack refuses DMs
that start with `/`). Arguments are capped at 2000 characters, stand in for
`$ARGUMENTS` in the body, and are presented to the model as data, not instructions.

**Code skills run in a sandbox.** A bundle with `scripts/*.py` (runtime `python3.12`)
or `scripts/*.js|.mjs|.cjs` (runtime `node22`) is a code skill. The built-in tool
`olyros_skill_run(name, command, input_files?, stdin?)` takes one command such as
`node scripts/generate-flyer.js in/content.json out/Flyer.pdf`. The command is split
POSIX-style and never handed to a shell: the interpreter must be `python`, `python3` or
`node`, the script must be one of the skill's own `scripts/` files and match the
interpreter, and arguments may only name paths under `/work` or the skill mount. Input
files land under `/work/in`; whatever the script writes to `/work/out` comes back as
temporary files offered as links that expire after 7 days (web chat shows them in the
reply and a `skill_output_files` event; Slack attaches them natively). A non-zero exit
returns stdout and stderr to the model so it can fix its input and retry.

**Where code runs: the execution plan.** Two backend kinds exist, `cloud` (the
`olyros-skill-exec` Cloud Run sandbox service) and `oho` (a one-shot Docker container on
one of the company's OHOs). The effective order is the skill's `executionOrder`
(`updateSkillExecutionOrder`), else the company's `skillExecutionOrder`, else `cloud`;
allowed values are `cloud`, `oho,cloud`, `oho` and `cloud,oho`. `cloud` is usable only
when a platform admin enabled cloud skill execution for the company and a cloud backend
is configured. `oho` is usable only when a company admin turned on **Run skill code on
our OHOs** (`updateCompanySettings(ohoSkillExecutionEnabled)`), the server carries the
runtime image definition, and at least one OHO that an admin allowed
(`setOhoSkillExecutionAllowed`) is online and advertises the `skill_exec` feature. The
OHO picked is the agent's sandbox host, else the OHO behind the company's default
backend, else the one with the fewest running skill runs. When the first backend refuses
before anything ran (OHO offline, busy or still building its image; cloud unreachable),
the next one in the order gets the run once, and the chat run row says which backend ran
and why the first did not. `skillExecutionCapabilities(skillId)` returns the effective
order with each backend's availability and reason; `skillExecOhos` lists the company's
OHOs with their allow state.

**The cloud sandbox.** Every call gets a fresh sandbox on a read-only root filesystem
with the skill mounted read-only at `/skills/<name>` and a writable `/work`. The image
holds Python 3.12 with pandas, numpy, openpyxl, python-docx, python-pptx, pypdf,
matplotlib, reportlab, pillow, pyyaml, jinja2 and tabulate, and Node 22 with pdf-lib,
googleapis, @databricks/sql, xlsx, date-fns, csv-parse, csv-stringify, dayjs, lodash,
yargs and marked. There is no pip, npm, npx, curl, wget, git or compiler, only six fixed
environment variables, and no network egress unless the run carries a tool bridge
session. **The OHO runtime** is built on each OHO from the same five-file definition
(first build 5 to 10 minutes and about 1.2 GB; needs PyPI, npm, nodejs.org and Docker
Hub reachable), runs with `--network none` unless a bridge session is present, and
rebuilds when the definition changes. Inputs and outputs travel through signed URLs in
the temporary bucket; only control messages cross the OHO link.

**Trust profile and the tool bridge.** Skill code can call the agent's tools (HTTP
tools, MCP servers, built-ins) through a server-side broker using the `olyros` client
package mounted in the sandbox. Each skill has an admin-edited trust profile
(`updateSkillTrustProfile`): `toolAccess` is `none`, `declared` (only what the bundle's
`olyros.yaml` declares) or `agent` (everything the agent has); `writes` is `deny`, `ask`
or `allow`; `network` is `none`, `bridge` or `internet`; `secrets` is reserved and never
honoured. Each company tool and MCP server carries an admin gate for skill code
(`setToolSkillCodeEnabled`, `setMcpServerSkillCodeEnabled`), and the bridge as a whole
is exposed by the platform and allowed by the company (`toolBridgeAllowed`). Under
`writes = ask`, and for tools of per-user OAuth MCP servers, the run pauses on a consent
card (**Allow for this run**, **Always allow for me on this agent**, **Deny**) before it
starts; consents are listed and revoked with `skillToolConsents` and
`revokeSkillToolConsent`, and every call appears in `toolCallAudit`. A declared tool the
agent does not have refuses the run (`SKILL_RUN_REQUIRES_UNMET`).

## Who can use it

* Reading the library, versions, files, bindings, consents, capabilities and the OHO
  list: **any company member** (membership only).
* Every write (create, edit, restore, delete, bundle upload and download, validate,
  bind, trust profile, execution order, the skill-code gates on tools and MCP servers,
  consent revocation), the tool-call audit, OHO execution and order, the tool bridge
  switch and allowing a specific OHO: **company admin**. The gates name class-scoped
  abilities whose minimum role is admin: `skill.manage` for skill writes, bindings,
  trust profile, execution order, consent revocation, `validateSkill` and the bundle
  REST routes (403 `ADMIN_REQUIRED`); `tool.manage_restricted` and `mcp.manage` for the
  skill-code gates; `tool.audit` for `toolCallAudit`; `company.manage` for the company
  settings; `oho.manage` for allowing an OHO. Settings -> Roles (`/settings/roles`)
  lists them, as does [Company settings](https://user-docs.olyrosstudios.com/company-settings.md).
* Enabling cloud skill execution per company, the budget ceilings and tool bridge
  exposure: **platform admin** in the admin app
  (`PUT /api/platform/execution/companies/{company_id}/skill-execution`).
* No plan or tier gate exists for skills.

## How to configure it

1. **Create the skill** (Skills -> New): write `SKILL.md` and save
   (`createSkill(input{skillMd, displayName, isActive})`), or upload a zip
   (`POST /api/v1/skills/bundles`, multipart `file`, optional `dry_run` and
   `display_name`). Errors such as `NAME_INVALID`, `DESCRIPTION_MISSING`,
   `FILE_TOO_LARGE` or `BINARY_FILE` must be fixed before the save succeeds.
2. **Iterate**: edit the text (`updateSkill`), upload a new bundle version
   (`POST /api/v1/skills/{skill_id}/bundles` with an optional `change_note`), compare
   versions and restore one (`restoreSkillVersion(skillId, versionId, withFiles)`).
3. **Bind it to an agent** on the agent's Skills tab:
   `bindSkillToAgent(agentId, skillId, input{pinnedVersionId, environmentOverrides,
   invocationOverride})`.
4. **For code skills, choose where it runs.** Ask a platform admin to enable cloud
   execution, or turn on **Run skill code on our OHOs** in Settings -> General and allow
   one OHO on its host page (Execution -> OHO host). Pick the company order
   (`updateCompanySettings(skillExecutionOrder)`) and, if needed, a per-skill order on
   the editor's Tools tab (`updateSkillExecutionOrder`).
5. **Set the trust profile** on the Tools tab (`updateSkillTrustProfile`), open the
   per-tool skill-code gates the skill needs (declare them in `olyros.yaml` to narrow
   access to `declared`), and tune the agent's budgets (`skillCallTimeoutS`,
   `skillTurnBudgetS`; bounds from `agentRuntimeLimits`).
6. **Test in the editor's Chat tab**, which runs a real conversation with a chosen agent.
7. **From a coding agent.** With an agent connection that holds `skills:write`
   ([Agent access](https://user-docs.olyrosstudios.com/agent-access.md)), `upload_skill_bundle(files, dry_run)` validates and
   uploads the same bundle the zip route takes and `download_skill_bundle` returns one; the
   walk-throughs are on [Olyros for agents](https://user-docs.olyrosstudios.com/olyros-for-agents.md).

## Limits and defaults

| Setting | Default | Where enforced |
| - | - | - |
| `SKILL.md` size | 64 KiB | parser (`FILE_TOO_LARGE`) |
| Body length | warning over 500 lines, error over 2000 | parser |
| Zip upload / bundle / files | 2 MiB zip, 4 MiB bundle, 64 files, 256 KiB per file, path depth 4 | bundle pipeline, REST body cap (413) |
| Uploads and downloads | 60 per company per hour (shared by the zip routes and the agent connection tools) | REST rate limiter |
| `validateSkill` | 60 per company per minute | GraphQL rate limiter |
| Skills in an agent's catalog | 20 | `active_skills_for_agent` |
| `/skill` arguments | 2000 characters | runtime |
| `olyros_skill_read` file | truncated at 32 KiB | runtime |
| Command | interpreter `python`/`python3`/`node`, at most 32 extra arguments of 512 characters | `run_command` |
| Inputs | 8 files, 1 MiB each, 8 MiB total, stdin 64 KiB | `run_command`, backend |
| Outputs | 16 MiB and 25 files per run; each file also under the platform temp-file cap (8 MB default) | backend, `temp_files` |
| Output links | signed URLs valid 7 days | `temp_files` |
| Per-call timeout | agent `skill_call_timeout_s` 90 s, platform ceiling 120 s, hard max 300 s | `limits.resolve_skill_budgets` |
| Per-turn script budget | agent `skill_turn_budget_s` 240 s, platform ceiling 270 s, hard max 600 s | same; under 5 s left is refused |
| Effective run timeout | min(call timeout, turn budget left, about 270 s minus elapsed) | `run_common.run_timeout` |
| Concurrent runs | 4 per company in flight; 4 per cloud instance; 2 per OHO | `run_common`, service, OHO |
| OHO container | 1 GiB memory, 1 CPU, 256 pids | OHO runner |
| `skill_execution_enabled` (cloud) | off | platform admin per company |
| `oho_skill_execution_enabled` | off | company admin |
| `skill_execution_order` | `cloud` | company admin; CHECK constraint |
| `skill_exec_allowed` per OHO | off | company admin |
| Trust profile defaults | `tool_access` `declared` with `olyros.yaml` else `agent`; `writes` `ask`; `network` `bridge`; `secrets` `none` | `bridge.policy` |
| Stale `running` rows | marked `error` after 600 s by the reaper job (every 300 s) | `skill_exec.janitor` |

## What it emits

* One `SkillInvocation` row per script run with status `running`, `succeeded`, `failed`,
  `timeout`, `refused` or `error`, the backend and OHO that ran it, runtime, argv, exit
  code, duration, bytes in and out, capped stdout and stderr (64 KiB / 32 KiB), output
  file metadata and an error code from one list (`SKILL_EXEC_OHO_OFFLINE`,
  `SKILL_RUN_TIMEOUT`, `SKILL_RUN_OUTPUTS_LOST`, `BRIDGE_REFUSED`, ...).
* A usage event with SKU `skill.execution.second` per finished run, attributed to the
  backend that ran it: the platform's cloud backend row for cloud runs, the OHO's own
  customer-hosted row (unpriced) for OHO runs. Turn cost tags are copied onto it.
* Chat events `skill_run_result` (outcome, backend, OHO name, fallback note) and
  `skill_output_files`, and a `skills_used` summary on the interaction (`invoked`,
  `run`, `read`).
* Bridge call rows for every tool call made by skill code, visible in `toolCallAudit`.
* Audit events: `skill.created`, `skill.version.created`, `skill.bundle.uploaded`,
  `skill.bundle.downloaded`, `skill.version.restored`, `skill.deleted`, `skill.bound`,
  `skill.binding.updated`, `skill.unbound`, `skill.trust_profile.updated`,
  `skill.execution_order.set`, `skill.run.finished`, `oho.skill_exec_allowed.set`;
  `mcp.upload_skill_bundle` for a bundle uploaded through an agent connection, next to the
  `skill.created` or `skill.bundle.uploaded` row it produced.
* HITL requests for the `/skill` pick card and for run consents.

## Known gaps

* **No dependency installation.** A script can use only what the curated image ships;
  `DEPENDENCY_NOT_IN_IMAGE` warns and the run fails at import. Per-skill dependency
  layers are deferred; the substitute is adding a package to the shared image.
* **Chat agents only.** Skills are resolved for the `web_chat` and `slack` environments
  of the server agent runtime. Cloud tasks, executor stages, workflow `create_task` runs
  and sandbox agents do not load skills.
* **A run must finish inside the chat turn.** There is no queued or detached run, so a
  script is bounded by the turn budget (about 270 s), and nothing waits for an offline
  OHO.
* **Text files only.** Bundles cannot carry images, fonts or other binary assets
  (`BINARY_FILE`); `bundle_url` is reserved and unused.
* **No secrets reach the sandbox.** The `secrets` dial is stored but never honoured and
  no environment variables carry credentials; code reaches systems only through the
  tool bridge.
* **`bridge` is not narrower than `internet`.** Every backend offers only egress
  isolation, so a run with a bridge session can also reach the internet; a forwarder
  channel is designed but not built.
* **No marketplace.** Versions come from the editor, the zip upload, the agent connection
  tool or restore (`created_via`); a skill authored inside a chat conversation (by the agent
  that runs it) is not supported.
* **Per-binding invocation override has no editor.** `invocationOverride` is settable
  through the API only; there is no UI control for it.
* **Cloud execution cannot be self-enabled.** Only a platform admin turns it on per
  company; the company's own switch covers OHO execution only.
* **Some limits are not settings.** Per-OHO concurrency and memory are OHO environment
  variables, an OHO has no `/work` disk quota, and the company-level
  `temp_file_max_size_mb` is editable but unread (the platform value applies).
* **`custom_code` tools** (a script attached to a tool rather than a skill) are parked and
  not offered today.

## Customer-safe summary

Skills let your team teach an agent a repeatable procedure once and reuse it everywhere
the agent chats. A skill is a short instruction document, optionally with reference
files and small Python or Node scripts, kept in your company library with a full version
history. You attach skills to the agents that need them, choose whether the agent or
the user may invoke each one, and users can call a skill directly from web chat or Slack
with a slash command. When a skill includes a script, the agent runs it in a disposable,
isolated sandbox, either in Olyros's cloud or on one of your own connected machines,
with time limits you set, and hands back any files it produced as download links. An
admin controls which of your tools a skill's code may reach and whether it may write,
and users are asked for consent before a write when that is the policy. Every run is
recorded with where it ran, how long it took and what it produced.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.