> ## 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.

# Olyros for agents

> Olyros is a workspace where a company runs AI agents on its own terms.

Olyros is a workspace where a company runs AI agents on its own terms. It uses its own model
keys, its own machines or a managed cloud, its own Slack, GitHub and Jira, and its own rules
about who may talk to which agent. This page is written for a coding agent (Claude Code or any
other MCP client) that a person has pointed at their company's Olyros account so that the
agent can set things up for them: connect a machine, describe a runtime image, create or
clone an environment, inspect what runs where, build a skill and bind it to an agent. It says
what the objects are, how to connect,
which scopes a connection can hold, which tools exist, and what an agent can never do. The
other pages on this site describe each product area in full; read the one for the area
before you change anything in it.

## The object model in one screen

1. **A company** is the tenant: every object below belongs to exactly one company, and a
   person reaches a company through a membership with a role (Viewer, Editor, Admin).
   [Company settings, users and roles](https://user-docs.olyrosstudios.com/company-settings.md).
2. **Integrations** connect the company to outside systems and hold the credentials: model
   providers (the keys every agent runs on), GitHub, Jira, Slack, remote MCP servers and
   custom HTTP APIs. [Integrations](https://user-docs.olyrosstudios.com/integrations.md) and its per-kind pages.
3. **Agents** are the assistants people talk to. Three kinds share one model: a chat
   **agent** ([Agents](https://user-docs.olyrosstudios.com/agents.md)), a persistent **sandbox** with its own working directory
   and repositories ([Sandboxes](https://user-docs.olyrosstudios.com/sandboxes.md)), and a **router**, one Slack app that forwards
   each person to their agent ([Routers](https://user-docs.olyrosstudios.com/routers.md)). Agents draw on **tools**, **MCP
   servers**, **skills** and **memory**.
4. **Automation** makes agents work without a person typing: **workflows** react to Jira,
   GitHub, webhook and agent events ([Workflows](https://user-docs.olyrosstudios.com/workflows.md)); **schedules** fire on a
   cadence ([Schedules](https://user-docs.olyrosstudios.com/schedules.md)); both, and people, create **cloud tasks**, one-shot
   units of work with an executor and a result
   ([Cloud tasks and executors](https://user-docs.olyrosstudios.com/cloud-tasks-and-executors.md)).
5. **Execution** decides where and in what a task or sandbox runs: an **OHO** (Olyros Home
   Orchestrator) machine the company connects, the Olyros Cloud pool, or the company's own GCP project, and a
   **runtime image** (called an *environment* in the API) with a Dockerfile, env vars and
   secrets ([OHO machines and environments](https://user-docs.olyrosstudios.com/oho-and-environments.md)). **Executors**
   describe how the model loop runs.
6. **Billing and usage** meter all of the above: a plan, a credit wallet, usage breakdowns
   and cost tags ([Billing and usage](https://user-docs.olyrosstudios.com/billing-and-usage.md)).

How they relate: an agent runs on a provider integration's key. A sandbox is an agent plus
a venue (an OHO or a cloud backend) plus a runtime image. A router has routes to agents and
sandboxes and no model of its own. A task is placed on a backend (the agent's pin, else the
company default, else any backend) and runs inside a runtime image through an executor.

## How to connect an agent

Olyros exposes one hosted MCP endpoint over HTTP. An agent authenticates with an **agent
connection token** that a member of the company creates under **Settings -> Agent access** in
the Olyros client app and hands to the agent ([Agent access](https://user-docs.olyrosstudios.com/agent-access.md) describes that
page). The connection acts as that person: it carries a set of scopes (below), and
inside every operation the person's role still applies, so a Viewer's connection only reads
even when it holds a write scope. Tokens are shown once, expire after 30, 90 or 180 days, can be re-issued for the same
connection when lost (**New token**), and can be revoked at any time by the company.

Claude Code:

```
claude mcp add --transport http olyros https://server-api.olyrosstudios.com/api/mcp --header "Authorization: Bearer <token>"
```

Any other MCP client that reads a JSON configuration:

```json theme={null}
{ "mcpServers": { "olyros": { "type": "http", "url": "https://server-api.olyrosstudios.com/api/mcp",
  "headers": { "Authorization": "Bearer <token>" } } } }
```

Replace `<token>` with the connection token. The endpoint above is the hosted Olyros
service; a company on its own deployment reads the exact endpoint from the connection's
`mcpUrl`, which the Agent access page fills into both snippets. The first call in every session should be
`olyros_whoami`: it returns the connection's name, company, scopes and expiry, the role and
abilities of the person it acts for, the documentation URL and the server version. Read the relevant documentation page (through
`olyros_docs` or this site) before you change anything, and ask the person before any
destructive call.

## Scopes

A scope is `<domain>:<access>` for one of six domains. `write` implies `read`. A connection
holds any subset of these twelve; a call that needs a scope the connection lacks is refused with
the name of the missing scope, so you can tell the person what to grant.

| Scope | What it allows |
| - | - |
| `agents:read` | List and inspect agents, sandboxes and routers (one list, filtered by kind): configuration, versions, knowledge items, runtime limits, router routes and thread bindings. |
| `agents:write` | Create, update, archive and restore agents, publish versions, manage knowledge items, memory settings and default repositories; create routers and manage their routes and default target. |
| `environments:read` | List runtime images (environments): type, Dockerfile, build args, env vars, secret key names, Dockerfile warnings. |
| `environments:write` | Create, update, duplicate and delete runtime images (secret values are written, never read back). |
| `executors:read` | Executors, the execution backends gallery (Olyros Cloud, your cloud, OHOs) with the runs and sandboxes placed on each, the company's Olyros Cloud access, cloud worker images. |
| `executors:write` | Create, update and delete executors, pin an agent to a backend, switch Olyros Cloud on or off, delete older worker images. |
| `oho:read` | Connected OHO machines and their pending registrations, assigned agents, versions and upgrade history; cloud tasks, their events and repositories. |
| `oho:write` | Approve or reject a registration, rename, revoke, allow skill execution, assign or remove agents, run diagnostics, upgrade an OHO; create, dispatch, cancel, retry and delete cloud tasks. |
| `sandboxes:read` | Sandbox chat threads, messages, sessions, the current invocation and lifecycle events. |
| `sandboxes:write` | Send a chat message, interrupt, start, stop, rebuild, reconcile or delete a sandbox, set its overlay env vars, secrets and scripts, its resources and idle timeout. |
| `skills:read` | The skill library: skills, their versions and files, bindings per agent, tool consents, execution capabilities and the tool-call audit; the company's registered MCP servers with their discovered tool catalogs (names, descriptions, input schemas), never their credentials or who is connected to them. |
| `skills:write` | Create, update, restore and delete skills, upload and download bundles (`upload_skill_bundle`, `download_skill_bundle`), bind and unbind skills to agents, set a skill's execution order, revoke a tool consent, and set a skill's trust profile (needs `confirm: true`). |

Everything outside these six domains (users and roles, billing, integrations and their
credentials, Slack, tools, workflows, schedules, memories, usage, cost tags, platform
administration) is not reachable through an agent connection at all. MCP servers can be read
(the catalog), not managed.

## Tools

Four generic tools cover the whole surface:

* `olyros_whoami` returns the connection (name, company, scopes, expiry, last use), the
  person it acts for (role and abilities), the documentation URL and the server version.
  Call it first.
* `olyros_schema(domain)` returns the GraphQL schema for one domain (`agents`,
  `environments`, `executors`, `oho`, `sandboxes` or `skills`), cut down to what the
  connection's scopes allow. Read it before composing a query.
* `olyros_graphql(query, variables, confirm)` runs one GraphQL operation. Queries and
  mutations only, one operation per call. Destructive mutations (names starting with
  `delete`, `revoke`, `archive` or `rebuild`) need `confirm: true`; ask the person first.
  `updateSkillTrustProfile` also needs `confirm: true`, because it changes what a skill's
  code may do.
* `olyros_docs(page)` returns one documentation page as markdown, or the list of pages when
  called without a page. The same pages are available as MCP resources named
  `olyros://docs/<page>`.

Five curated tools cover the common asks without composing GraphQL:

* `create_runtime_environment(name, dockerfile, env_vars, build_args, secrets, description)`
  creates a Docker runtime image. Names use letters, digits, hyphens and underscores only
  (`runtime-x`, not `Runtime X`). The Dockerfile is your job: read the project's
  `pyproject.toml` or `package.json` and write the `FROM` and `RUN` lines; Olyros validates
  and stores it, returns warnings for lines the runtime will override (`ENTRYPOINT`, `CMD`,
  `USER`, `VOLUME`), and builds the image on first use.
* `clone_runtime_environment(source_name, new_name, add_env_vars, dockerfile_append)` copies
  an existing runtime image by name, merges extra env vars and appends text to the copied
  Dockerfile. Secrets are carried over on the server; you never see their values.
* `list_agents(kind)` lists the company's agents, sandboxes and routers in one answer, with
  status and counts; `kind` is `all` by default and narrows to `agents`, `sandboxes` or
  `routers`.
* `upload_skill_bundle(files, skill_id, dry_run, display_name, change_note)` validates and
  uploads a skill bundle: `files` is the skill folder as a list of `{path, content}` text
  files and must include `SKILL.md`; paths are relative to the folder (`references/x.md`,
  `scripts/run.py`, `olyros.yaml`). Call it with `dry_run: true` first and fix every
  `errors` entry; warnings do not block. Without `skill_id` a new skill is created (version
  1, named by `display_name` or the frontmatter `name`); with it a new version of that skill
  is written (same frontmatter `name` required, `change_note` kept on the version; an
  identical bundle is a no-op with `created: false`). Needs `skills:write` and an admin
  member. Limits: 64 files, 256 KB per file, `SKILL.md` 64 KB, 4 MB unpacked, about 900 KB
  of text per call (the request body is capped at 1 MiB; bigger bundles go through the
  browser upload). Declare the tools the scripts call in `olyros.yaml`, so the skill runs
  with `toolAccess: declared`. The result is the shape the browser upload returns: `ok`,
  `dry_run`, `created`, `errors` and `warnings` (entries `{code, message, severity, line,
  path}`), `manifest`, `files` (`{path, kind, size_bytes}`), `skill_id`, `version_id`,
  `version_no`, `file_count`, `bundle_bytes`. A bundle that fails validation is a result
  with `ok: false` and `errors`, not a refused call.
* `download_skill_bundle(skill_id, version_id)` returns one skill version as text files:
  `skill_id`, `skill_name`, `version_id`, `version_no`, `files` as `[{path, content}]`
  with `SKILL.md` first, `file_count` and `bundle_bytes`; without `version_id` it is the
  skill's latest version. Needs `skills:read`; the download is recorded in the company's
  audit trail. To change an existing skill, download it, edit the files and upload them as a
  new version with `skill_id`.

## Build a skill from this repository

A skill is a `SKILL.md` document, optionally with reference files and small Python or Node
scripts, that a chat agent loads when a request matches and whose scripts it runs in a
disposable sandbox ([Skills](https://user-docs.olyrosstudios.com/skills.md) describes the format, the sandbox and the trust
profile in full). The steps, one call each:

1. `olyros_whoami`: the connection must hold `skills:write` and the person must be a company
   admin (`skill.manage`); `agents:read` lets you find the agent to bind to yourself.
2. `olyros_docs("skills")`: read the frontmatter rules, the bundle limits, the packages the
   sandbox image ships and the trust profile before writing anything.
3. Write `SKILL.md` from what the repository tells you. Frontmatter: `name` (lowercase
   kebab-case, at most 64 characters, the `olyros-` prefix is reserved) and `description`
   (at most 1024 characters, saying what the skill does and when to use it); the body says
   how to run each script, with the exact command (`python scripts/run.py in/x.json
   out/y.md`), its arguments and what lands under `out/`. Put longer material under
   `references/` and scripts under `scripts/` as `*.py` (Python 3.12) or `*.js`, `*.mjs`,
   `*.cjs` (Node 22). Scripts read only from `/work/in` and the skill folder, write only to
   `/work/out`, use only the packages the image ships, and make no network calls of their
   own: anything outside the sandbox goes through the tool bridge. Text files only, no
   `.env`, key or certificate files, paths at most four segments deep.
4. If a script calls one of the agent's tools through the bridge (the `olyros` client
   package: `from olyros import tools` then `tools.<name>(...)`, or `from olyros.mcp import <slug>` then `<slug>.<tool>(...)`), add `olyros.yaml` declaring every tool it calls:

   ```yaml theme={null}
   schema: 1
   requires:
     tools: [jira_search]
     mcp:
       github: [create_issue]
   ```

   With this file the skill runs with `toolAccess: declared` (these tools and nothing else)
   and a run is refused when the agent lacks one of them; without it the default is `agent`
   (everything the agent has). `bridgeStub(kind, name, language)` under `skills:read` returns
   the exact function the sandbox client exposes for one tool (`kind` `tool`, `mcp` or
   `builtin`; `name` is the tool name, or `<slug>/<tool>` for an MCP tool; `language`
   `python` or `node`); its `declaration` is the TypeScript declaration for Node stubs and is
   empty for Python. The `olyros.yaml` line is the tool name under `tools:` or `<slug>: [<tool>]`
   under `mcp:`, spelled exactly as the catalog returns them.
5. `upload_skill_bundle(files, dry_run: true)`: fix every `errors` entry (`code`, `message`,
   `path`, `line`) and call again until `ok` is `true`. Read the `warnings`
   (`DEPENDENCY_NOT_IN_IMAGE`, `NETWORK_CALL`, `BRIDGE_UNDECLARED_TOOL`,
   `FILE_UNREFERENCED`, ...) and fix what you can; they do not block.
6. `upload_skill_bundle(files, display_name)`: the result holds `skill_id`, `version_id` and
   `version_no` 1. Keep `skill_id`.
7. Find the agent: `list_agents(kind: "agents")` returns ids and names (sandboxes and routers
   do not load skills), or ask the person which agent to bind.
8. `olyros_graphql` with `bindSkillToAgent(agentId, skillId, input: {pinnedVersionId: null})`:
   a null pin follows the skill's latest version; `environmentOverrides` (`web_chat`,
   `slack`) and `invocationOverride` (`model`, `user`, `both`) narrow where and by whom it is
   invoked.
9. `olyros_graphql` with `agentSkills(agentId)`: check that your binding is listed with an
   empty `missingTools` (tools the skill text names that the agent lacks) and that every
   `bridgeTools` entry your scripts call has `status` `ok`; a `missing` status means the agent
   does not mount that tool or MCP server, which `missingTools` does not report. The person tests the skill in the editor's
   Chat tab or in a conversation with the agent.
10. Leave the trust profile alone unless the person asks for a change. The effective
    defaults are `toolAccess` `declared` with `olyros.yaml` (else `agent`), `writes` `ask`
    (the person answers a consent card before a writing tool call), `network` `bridge` and
    `secrets` `none`. When the person wants a different setting, call
    `updateSkillTrustProfile(skillId, input: {toolAccess, writes, network})` with
    `confirm: true`; without it the call is refused with `CONFIRM_REQUIRED`, and with it
    the change is listed under the connection on the Agent access page.

To ship a change later, `download_skill_bundle(skill_id)` returns the latest version as
`files`; edit them and call `upload_skill_bundle(files, skill_id, change_note)`, with
`dry_run: true` first. The frontmatter `name` must stay the same (`NAME_MISMATCH`
otherwise); an unchanged bundle answers `created: false` and writes no version.

## Wrap a third-party MCP server in a skill

A company registers remote MCP servers under Agents -> MCP Servers and discovers their tools
([MCP servers](https://user-docs.olyrosstudios.com/mcp-servers.md)). A skill can wrap one such server: `SKILL.md` tells the agent
when to use which tool, and scripts call the tools through the bridge so the data never
passes through the model. You read the catalog Olyros already discovered; you never talk to
the server yourself. One call per step:

1. `olyros_whoami`: `skills:write` and an admin member, as above.
2. `olyros_graphql` with `mcpServers { id slug displayName description url authMode
   toolCount allowedTools isActive skillCodeEnabled }`: pick the server. Note its `slug`
   (the name your `olyros.yaml` and scripts use) and its `allowedTools` (`null` means every
   discovered tool is allowed; otherwise only those names may be called). If `toolCount` is
   `0`, ask the person to open the server's page and run **Discover tools**; you cannot
   discover. If `skillCodeEnabled` is `false`, ask an admin to allow skill code to call the
   server (the skill-code switch on its page); a run would otherwise be refused.
3. `olyros_graphql` with `mcpServerTools(mcpServerId) { name description inputSchema access
   skippedReason }`: the catalog. `inputSchema` is the JSON schema of each tool's arguments,
   `access` is `read` or `write` (a write asks the person for consent at run time under the
   default trust profile), and a tool with a `skippedReason` has no stored schema and
   cannot be called from code.
4. `olyros_graphql` with `bridgeStub(kind: "mcp", name: "<slug>/<tool>", language:
   "python")` (or `"node"`) for each tool the scripts will call: `source` is the exact
   function signature the sandbox client exposes, `declaration` the TypeScript declaration for
   Node stubs (empty for Python), `access` the read or write class.
5. Write the bundle: `SKILL.md` whose `description` names the server and the asks it serves,
   with one section per tool saying when to use it, its arguments and the command that runs
   it; `references/tools.md` with the catalog (name, description, input schema) so the agent
   can answer questions without a run; `scripts/*.py` (or `*.js`) that take their input as
   arguments or files under `in/`, call `from olyros.mcp import <slug>` then
   `<slug>.<tool>(...)`, and write results under `out/`; and `olyros.yaml`:

   ```yaml theme={null}
   schema: 1
   requires:
     mcp:
       <slug>: [<tool>, <tool>]
   ```

   Use `<slug>` exactly as `mcpServers` returned it and the tool names exactly as
   `mcpServerTools` returned them.
6. `upload_skill_bundle(files, dry_run: true)`: fix every `errors` entry; a
   `REQUIRES_UNKNOWN_TOOL` warning means a declared name is not in the server's catalog, and
   `BRIDGE_UNDECLARED_TOOL` means a script calls a tool `olyros.yaml` does not declare.
7. `upload_skill_bundle(files, display_name)`: keep `skill_id`.
8. `olyros_graphql` with `agentMcpServers(agentId) { mcpServerId isActive }`: the agent that
   will run the skill must mount the server with `isActive: true`; if it does not, ask the
   person to bind the server on the agent's MCP servers tab, which you cannot do.
9. `olyros_graphql` with `bindSkillToAgent(agentId, skillId)`, then `agentSkills(agentId)` as
   in the previous walk-through: every `bridgeTools` entry for the server must have `status`
   `ok` (`missing` means the agent does not mount the server, step 8).

For a server whose `authMode` is `oauth_per_user`, each person who runs the skill must have
connected their own account under Settings -> Connected Accounts; the first run asks them.
What you cannot do here: register, change, discover, delete or connect to an MCP server,
change its allowed tools or its skill-code switch, bind it to an agent, or see who is
connected to it and with what. Those stay with the people in the client app.

## Limits

The endpoint bounds what one connection can do per minute. These are not tool errors but HTTP
answers, so your MCP client reports them as transport failures:

| Limit | Value | Answer when exceeded |
| - | - | - |
| Requests per connection | 60 per sliding minute | `429` with detail `AGENT_RATE_LIMITED` and a `Retry-After` header |
| Concurrent requests per connection | 4 in flight | `429` with detail `AGENT_TOO_MANY_IN_FLIGHT`, `Retry-After: 1` |
| Request body | 1 MiB; a `Content-Length` header is required | `413` (`AGENT_BODY_TOO_LARGE`) or `411` (`AGENT_CONTENT_LENGTH_REQUIRED`) |
| Operations per `olyros_graphql` call | one query or mutation, no subscriptions | `MULTIPLE_OPERATIONS`, `SUBSCRIPTION_NOT_ALLOWED` |
| Query depth | 10 levels, like the client app | a GraphQL validation error |
| Token | bad, expired or revoked token | `401`; `403` when the member has left the company; `404` when agent access is off for the deployment |

Wait for `Retry-After` and send the call again; do not retry in a tight loop. Keep queries
small and paginate lists through their `limit` and `offset` arguments where the schema offers
them.

## How calls are refused

A refused call returns a tool error whose text carries a code (after the `Error executing tool <name>:` prefix the MCP library adds), so you can act on it:

* `SCOPE_REQUIRED`: the connection lacks the named scope. Tell the person what to grant.
* `UNKNOWN_FIELD`: the operation is outside the six domains. There is no scope for it.
* `FIELD_EXCLUDED`: the operation is never available to agent connections (next section).
* `CONFIRM_REQUIRED`: a destructive mutation, or `updateSkillTrustProfile`, was called
  without `confirm: true`.
* `SUBSCRIPTION_NOT_ALLOWED`, `MULTIPLE_OPERATIONS`, `INVALID_GRAPHQL`: the document itself
  is not accepted; send one query or mutation.
* `UNKNOWN_DOMAIN`, `UNKNOWN_PAGE`, `NOT_FOUND`, `AMBIGUOUS_NAME`: a tool argument did not
  match; the message lists what would.
* `INVALID_NAME`: a runtime image name breaks the rule (letters, digits, hyphens and
  underscores only, no spaces, up to 100 characters); nothing was created.
* `INVALID_INPUT`: a skill bundle tool argument is malformed: an empty `files` list, more
  entries than `SKILL.md` plus 64 files, an empty path or one over 255 characters, content
  that is not valid text, a `skill_id` that is not a UUID, `display_name` given with
  `skill_id` or `change_note` given without it, or either text over 8192 characters.
  Nothing was validated or written.
* `RATE_LIMITED`: skill bundle uploads and downloads are limited to 60 per company per hour,
  shared with the browser; try again later.
* `CONFLICT`: another write to the same skill got in the way of the upload; call again.
* `GRAPHQL_ERROR`: the operation ran and the server refused it, most often because the
  person's role does not allow it ("Editor or admin role required").

## Common questions

* **How do I find an id?** Query the list first: `environments`, `agents`, `executors`,
  `ohoInstances`, `skills`, `mcpServers` and the sandbox queries return ids and names;
  `list_agents` does the same for agents, sandboxes and routers. Objects of another company answer "not found" like
  unknown ids.
* **A write failed with "Editor or admin role required".** The person behind the connection
  is a Viewer. Tell them which role the operation needs; a wider scope does not help.
* **Can I read a secret I set?** No. Environment and sandbox overlay secrets are write-only
  for every connection; queries return key names only.
* **Can I see what I did earlier?** Every mutation you run, every bundle upload and every
  bundle download is written to the company's audit trail and shown under the connection on
  the Agent access page; other reads are not recorded.
* **Why does the schema miss a mutation I know exists?** `olyros_schema` shows only what the
  connection's scopes allow and never shows excluded operations; a `read` scope hides every
  mutation of that domain.

## What an agent cannot do

An agent connection never reads a secret value. It can set environment secrets and sandbox
overlay secrets and see their key names, but the operations that reveal a stored value, that
rotate an OHO's device credentials or that look up a pending OHO registration by its token
are excluded for every connection, whatever its scopes. It cannot connect, verify, cap or
revoke a bring-your-own Google Cloud backend, because those operations carry integration
credentials. It cannot change who may talk to an agent (the Access table) or an agent's
Slack reply options. It cannot subscribe to live events, run more than one operation per
call, or reach anything outside the six domains: users, invitations, roles, billing,
integrations, Slack, tools, workflows, schedules and platform administration stay with the
people in the client app. It can read the company's MCP servers and their tool catalogs but
cannot register, change, discover, delete or connect to one, and never sees who is connected
to a server or with what. It cannot grant a tool consent for a skill run (people answer
consent cards in chat); it can only revoke one. It cannot exceed the role of the person it
acts for. And it should not delete, revoke, archive or rebuild anything, or change a skill's
trust profile, without telling the person first; the `confirm` flag exists so that the
question is asked.


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