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 and sandboxes have
their own pages; see Agents for the agent itself.
What it does
A company library of versioned skills. A skill is created fromSKILL.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.managefor skill writes, bindings, trust profile, execution order, consent revocation,validateSkilland the bundle REST routes (403ADMIN_REQUIRED);tool.manage_restrictedandmcp.managefor the skill-code gates;tool.auditfortoolCallAudit;company.managefor the company settings;oho.managefor allowing an OHO. Settings -> Roles (/settings/roles) lists them, as does Company settings. - 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
- Create the skill (Skills -> New): write
SKILL.mdand save (createSkill(input{skillMd, displayName, isActive})), or upload a zip (POST /api/v1/skills/bundles, multipartfile, optionaldry_runanddisplay_name). Errors such asNAME_INVALID,DESCRIPTION_MISSING,FILE_TOO_LARGEorBINARY_FILEmust be fixed before the save succeeds. - Iterate: edit the text (
updateSkill), upload a new bundle version (POST /api/v1/skills/{skill_id}/bundleswith an optionalchange_note), compare versions and restore one (restoreSkillVersion(skillId, versionId, withFiles)). - Bind it to an agent on the agent’s Skills tab:
bindSkillToAgent(agentId, skillId, input{pinnedVersionId, environmentOverrides, invocationOverride}). - 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). - Set the trust profile on the Tools tab (
updateSkillTrustProfile), open the per-tool skill-code gates the skill needs (declare them inolyros.yamlto narrow access todeclared), and tune the agent’s budgets (skillCallTimeoutS,skillTurnBudgetS; bounds fromagentRuntimeLimits). - Test in the editor’s Chat tab, which runs a real conversation with a chosen agent.
- From a coding agent. With an agent connection that holds
skills:write(Agent access),upload_skill_bundle(files, dry_run)validates and uploads the same bundle the zip route takes anddownload_skill_bundlereturns one; the walk-throughs are on Olyros for agents.
Limits and defaults
What it emits
- One
SkillInvocationrow per script run with statusrunning,succeeded,failed,timeout,refusedorerror, 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.secondper 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) andskill_output_files, and askills_usedsummary 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_bundlefor a bundle uploaded through an agent connection, next to theskill.createdorskill.bundle.uploadedrow it produced. - HITL requests for the
/skillpick card and for run consents.
Known gaps
- No dependency installation. A script can use only what the curated image ships;
DEPENDENCY_NOT_IN_IMAGEwarns 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_chatandslackenvironments of the server agent runtime. Cloud tasks, executor stages, workflowcreate_taskruns 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_urlis reserved and unused. - No secrets reach the sandbox. The
secretsdial is stored but never honoured and no environment variables carry credentials; code reaches systems only through the tool bridge. bridgeis not narrower thaninternet. 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.
invocationOverrideis 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
/workdisk quota, and the company-leveltemp_file_max_size_mbis editable but unread (the platform value applies). custom_codetools (a script attached to a tool rather than a skill) are parked and not offered today.