Skip to main content
Nineteen commands. Each states what it does and what it deliberately does not — the boundary is the part that would otherwise be guessed. Four rules hold throughout. Nothing a colleague can observe happens implicitly. Only to11 skill release makes a skill reach anyone else. Nothing writes to a directory it did not create unless --force is given — and that covers anything already on the machine, not only skills you wrote yourself. Every command accepts --help and prints its own usage, flags and conflicts, as text. Long options take two dashes. A single dash is only ever a single-letter short option, and the only two are -h for --help and -v for --version. -location is refused rather than accepted as a synonym, so the documented spelling and the working spelling cannot drift apart. Nothing edits a preference. Disabling a skill, holding a version and choosing an environment are lines in a configuration file — you edit it, and sync applies it.

to11

The root command. With no arguments it does the job the CLI exists for: skills on disk, current. Does — in a location that is not linked yet, link it — signing you in first when nobody is — then take in the skills already in its targets, and then run to11 skill sync for it. In a linked location, run to11 skill sync under a one-line header, to11 CLI <version> on stderr, and ask nothing; stdout is the sync’s. After a sync that changed nothing, add one line to stderr: `to11 --help` lists the commands. Does not — print the command list, which is to11 --help; take a project, environment or target from a flag — it reads them from TO11_ORGANIZATION, TO11_PROJECT, TO11_PROJECT_ID and TO11_LABEL, and to11 link takes them as flags; guess a subcommand from a near-miss. Conflicts — --non-interactive with --interactive. The first run in a repository, signed in, with one organization and a folder named like a project:
Every later run in that directory is the sync:
The `to11 --help` line is never printed by to11 skill sync, nor under --format json. Without a terminal, or with an agent detected, the questions are not asked. A value the link still needs is answered with one action_required object on stdout, exit 1, and nothing is written. With nobody signed in the answer is not_signed_in, in a linked location as well as an unlinked one, and nothing is synced. An unknown subcommand prints the command list to stderr and exits non-zero. Settles which project a location receives skills from, at which environment, into which targets, and writes that location’s skills.yaml. Does — sign you in when nobody is; take each value from a flag, a variable, the file already there, or a default it can derive, and ask only for what is left; write <repo root>/.to11/skills.yaml inside a git repository, or ~/.to11/skills.yaml outside one or with --global; take in the skills already in the location’s targets; offer the to11 plugin for the agents on your PATH that lack it. Does not — sync — a bare to11 links and then syncs; create an organization, a project or an environment; ask for a prefix; set up routing, which stays in to11 ui and to11 code; remove a project, a standard target or a per-skill statement the file already holds. Conflicts — --non-interactive with --interactive.

What it decides

A value is asked for only when every source above it is empty, and only at a terminal. Without one, the question is an action_required answer instead. The environment is the one exception: without a terminal, a project that has prod takes prod rather than stopping. The directory-name match compares the repository root’s folder name, ignoring case, with the project part of each workspace/project you can read. One match is offered as a yes-or-no question; with none or several, Which project? lists every project with the matches first. It applies to a repository only, never to your home. --yes accepts a single match; it never chooses between several. A file that already names projects is read as answers. With exactly one project, that project is taken without asking. With several, Which project? offers the file’s first entry as the default. The write adds the chosen project, or updates its environment — when the file follows it on several, the entry already on the chosen one, or else the first — and keeps every other entry in the file — in a committed repository file, the entries a teammate added stay. A location belongs to one organization. --organization or TO11_ORGANIZATION naming an organization other than the one the file names is refused before anything is asked. A value you cannot read is asked again. A project, environment or organization given by flag or variable that you cannot read is said in one line, and the question follows; without a terminal, the same sentence leads the action_required message, and choices holds the values you can read. --yes answers confirmations, never data questions. It accepts a single directory-name match, the detected targets, and the plugin offer. It never chooses an organization, a project from a list, or an environment from several.

The questions

Everything here is on stderr; a link prints nothing on stdout. Each answered question stays on screen as one ? question answer line. The header names the location by its scope. Repository <path> for a repository; Home ~/.to11 (every directory) for your home, because skills linked there reach every directory. A location with nobody signed in shows no Signed in as row: the sign-in runs after the header and ends on ✓ Signed in as. The row names your organization only when you belong to one; in several, Which organization? comes next and lists them by slug, with each display name beside it. Skills is how many skills the environment publishes, said before anything is written. When it is more than one, Which skills? lists them, each checked unless your file disables it, so Enter receives them all:
Typing filters the list by name, ignoring case. space checks or clears the row under the cursor; on Select All it checks every skill, or clears them all when every one is checked. At most 20 rows show at once, with ↑ N more ↓ M more counting the rest; on a short terminal fewer rows show, then the description goes. Description shows the highlighted skill’s description, two lines at most. Enter with nothing checked does nothing, and the ↑↓ move, space select, enter confirm line under Search: reads ↑↓ move, space select · select at least one to continue until one is checked again; once answered, the list leaves one line, ? Which skills? code-review, incident-triage. A skill another project in your file already names is that project’s to enable or disable; a Not listed row says which. Unchecking a skill writes disabled: true for it under the project in skills.yaml, and checking one again removes that. A skill unchecked in your home file is off in your own directories only; a repository that asks for it still installs it there. To keep it out of repositories too, write enforced: true beside the disabled: true it wrote — that reaches a repository whose file names the same organization and the project the same way (acme/web, not its id). You keep following the environment, so a skill released to it later still arrives. --yes and runs without a terminal skip the question and leave the file’s choices as they are. --skill answers Which skills? without the list, with or without a terminal: the skills named, matched by slug ignoring case, are checked and every other one is unchecked; --skill '*' checks them all. At a terminal a Chosen row names them; a named skill another project in your file already names stays that project’s, and a Not listed row says so, with or without a terminal. A name the environment does not publish fails the link before anything is written, and the error lists the skills it does publish. Targets lists each directory the link will write and the agents that read it. When no coding agent is on your PATH, an Agents row says so above it. Change targets? opens one question, Which targets?, choosing among Claude Code, Codex, and any standard targets the file already holds, which are always kept. It is the same list, without Select All or descriptions: each row shows its directory beside it, and a Selected: line under the list names what is checked. --yes skips it and keeps what was detected. ✓ Linked names the project and environment, and Saved to the file it wrote. The plugin offer is made for each of Claude Code and Codex that is on your PATH without the to11 plugin. When every agent found already has it, a Plugin already installed for … row says so instead. --no-plugin declines it. Without a terminal it is skipped unless --yes was given. The last line after a first link is the next step: using the skills in a new agent session; to11 skill sync after a to11 link, which fetches nothing; when the environment publishes none yet, to11 skill store and to11 skill release; when nothing was installed because your own skills already use every name, setting prefix: <name> in the file it wrote; and to11 skill list when how many it publishes could not be read, or when nothing arrived for another reason. At a terminal the questions, answers and ✓ lines are colored; NO_COLOR turns that off, and output that is not a terminal is never colored. The Next: line is printed only after the first link of a location. Re-running to11 link in a linked location ends on the ✓ lines.

Signing in

With nobody signed in, the link’s first step is the sign-in:
Enter opens the browser sign-in. Ctrl-C, or the end of input, stops with error: sign-in declined and nothing was stored — run to11 login when you want to sign in; no browser opens and nothing is stored. Without a terminal there is no sign-in: the answer is action_required with reason: not_signed_in. to11 login signs in without this question.

Ctrl-C

Ctrl-C ends the link with error: cancelled, the question or step it stopped at, and what is left to do, and exits 1.

Skills already there

After ✓ Linked, every to11 link — and a bare to11 that links — looks in the location’s targets for skill folders to11 did not deliver, before the plugin offer and the sync. It is to11 skill import run as a step: an exact match of a published version is adopted without a question, the folders the project does not have are offered for upload with none selected, and a folder that differs from the project’s skill of the same name gets one question. A location with no such folder prints nothing for it. A bare to11 in a linked location never looks.
Each answer is carried out when it is given. After an upload the last line names to11 skill release instead of to11 ui. Without a terminal, a location with such a folder stops after the write and before the sync, with the unmanaged_skills answer on stdout, exit 1; nothing is adopted, uploaded or synced. Each command in its next[] is a to11 skill import line.

What only a person can fix

An account with no organization, an organization with no project you can read, and a project with no environments cannot be linked by any command. At a terminal each is an error naming what to create and the dashboard address. Without one it is action_required with an ask — see Non-interactive mode.

to11 ui

An overview of what is set up on this machine or in this repository, full-screen in your terminal, and where routing is set up. A bare to11 is what sets a location up. On a location that is not set up yet, to11 ui first walks its own onboarding — Skills, then the plugin — which writes what to11 link writes, through the same functions, so a location linked by either is complete to the other. Does — sign you in as a person when nobody is; inside a repository, ask whether to set up the repository or your home; take the organization from the configuration, or from your only membership, or ask; then walk onboarding step by step — Skills, then Code · to11 Plugin. Each step saves as soon as you confirm it. Onboarding ends on All set, which says it is complete; Exit leaves. Later runs open on an overview of what is set up, with anything that no longer holds marked. While an onboarding step is missing, the overview offers to continue onboarding, walking only the missing steps. Esc leaves onboarding at any step; what was saved stays saved. Routing Claude Code or Codex through to11 is not part of onboarding: it is a row on the overview. Does not — work as an API key; run without a terminal; switch the organization of a setup; edit an existing provider; repair a configuration it cannot read. It takes no flags. It works only as you. Every request it makes carries your signed-in credential, whatever TO11_API_KEY says. The plugin is installed for you, in every project — Claude Code at user scope. It is never written into a repository’s agent settings. Codex has no scope flag, so a Codex install lands where Codex puts it. Only passthrough providers of the agent’s vendor are used — Anthropic for Code · Claude Code, OpenAI or ChatGPT for Code · Codex: providers for that vendor, not archived, live in at least one environment of the project, whose every credential is passthrough. A provider holding a stored key is never used. A routing row on the overview lists the qualifying providers. The row is shown when that agent is on your PATH or its file already exists. You pick the project, and each provider is offered at the environments it is live in: ←→ changes the environment on its row, and space or Enter chooses the row. Create a provider asks for a name and a slug. The name defaults to Anthropic (to11 CLI) for Claude Code; for Codex, ChatGPT (to11 CLI) when Codex is signed in with ChatGPT ("auth_mode": "chatgpt" in auth.json under $CODEX_HOME, default ~/.codex) and OpenAI (to11 CLI) otherwise. The slug defaults to anthropic-to11-cli, chatgpt-to11-cli or openai-to11-cli, with -2, -3 and so on added when the project already uses it; it cannot be changed later. It connects that vendor in passthrough mode with the Allow by default access policy — every model the vendor serves is allowed, including models it releases later — and goes live in every environment of the project. Creating it brings you back to the provider list with the new provider chosen, ready to save. A setup it cannot use stops the screen. A file that does not parse, two files in one location naming different organizations, an organization you are not a member of, or no organization at all: it says what is wrong, gives a prompt to copy into an AI assistant, prints both on stderr when it closes, and exits 1. The one thing it fixes itself is a code.claude.yaml or code.codex.yaml without organization, which gets the location’s organization written in. Without a terminal it exits 1:

to11 init

to11 init is an alias of to11 link, kept so existing scripts keep working, and is not listed. Its old flags are translated: Like to11 link, it never syncs.

to11 login

Does — sign in as a person and store the credential. When the identity provider offers sign-in with a one-time code, print the code, wait for Enter, and open the page to type it into; otherwise open a browser that reports back to a listener on this machine. Does not — accept a password typed into the terminal; ask before opening the browser in the browser flow — it is the explicit command; write anything before the sign-in completes — an abandoned or declined sign-in leaves the machine exactly as it was; run without a terminal. Conflicts — --device with --browser (they pick opposite sign-ins); --non-interactive with --interactive. Which sign-in runs. The code flow when the identity provider’s metadata advertises a device authorization endpoint, or with --device. The browser flow otherwise, and with --browser. A provider can advertise the code flow and still refuse it for this client; that refusal falls back to the browser flow without a word, and only with --device is it an error. With a code, any browser on any machine completes it. The code is printed before anything opens, so on a remote machine you can type it into a browser elsewhere; a browser that cannot open here is not a failure:
The code expires at the identity provider, and the CLI stops waiting when it does: the one-time code expired. Denying the sign-in in the browser stops with the sign-in was denied. Either way nothing is stored. Through a browser, it needs a browser on this machine. The command opens one and prints the address as well in case it does not open — but both reach a listener on 127.0.0.1, so the address cannot be carried to another device:
Without a terminal, it does not wait. It prints the not_signed_in answer on stdout and exits 1, starting no sign-in. A machine where nobody signs in, such as CI, uses an API key in TO11_API_KEY instead. A bare to11 or to11 link with nobody signed in signs in inline, through the browser, after asking first: Nobody is signed in. Press Enter to open your browser to sign in, or Ctrl-C to stop.

to11 logout

Does — delete the stored credential and report what was removed. Does not — remove API keys; remove configuration; delete installed skills. After it, commands use TO11_API_KEY when it is set. Logging out leaves skills on disk — logging out is not a request for your agent to stop working.

to11 whoami

Does — print the identity, its organizations, and which credential kind is in use. The answer comes from the platform, so it is a real check rather than a local echo. Does not — modify anything; list skills; fall back to a cached answer when the platform is unreachable — a stale identity answer is worse than none.
With an API key it says so, and never prints the key:

Naming a project

--project takes workspace/project or a proj_ id. An id needs no organization. A workspace/project is looked up in one organization. to11 environment list, to11 provider list and to11 provider create belong to no location, and take the organization from:
  1. --organization <slug>, else TO11_ORGANIZATION
  2. the only organization you belong to
  3. the organization this repository’s skills.yaml and your home one name, when only one names one or both name the same
  4. when they name two different ones: the one that has the project. A project both have, or neither has, needs --organization
  5. with no skills.yaml naming one: the only one of your organizations that has the project. When several have it, the command stops and names them
to11 skill store, to11 skill release and to11 code take --organization or TO11_ORGANIZATION first, then the organization of the location they act on.

to11 project list

Lists the projects you can read. Without an organization, the projects of every organization you belong to. It needs a signed-in person. With TO11_API_KEY it stops with listing projects needs a signed-in person.

to11 environment list

Lists a project’s environments. Archived environments are left out.

to11 provider list

Lists a project’s providers.

to11 provider create

Creates a provider in a project. The kind is the second argument, or --kind; giving both is an error. Every input is checked before anything is sent, and the kind against the platform’s list of kinds. It needs a signed-in person: the platform does not let TO11_API_KEY read that list.

to11 provider kind list

Lists the kinds of provider the platform can connect. It needs a signed-in person. With TO11_API_KEY it stops with listing the kinds of provider needs a signed-in person.

to11 skill

Does — with no subcommand, print the subcommand list. Does not — sync, list, or contact the platform. Inert by design: a bare parent command that did work would make the most exploratory thing you can type the thing with the most side effects.

to11 skill sync

Reconciles every configured location to what your configuration resolves to. Does — fetch the rendered skills for each target and write them; remove skills configuration no longer resolves; skip and report anything edited on disk; report per skill and per location what changed; leave previous skills in place when a fetch fails, so a broken network still beats nothing. Does not — publish or modify anything upstream; touch a directory it did not create; partially write a skill; prompt for anything; skip because a refresh ran recently — an explicit sync always runs. One flag, not several. A directory already there and a skill you edited are one request: install what the configuration asks for, whatever is in the way. Each refusal --force waives exists to stop a sync destroying work nobody agreed to lose, and the flag is that agreement. A directory your configuration stops asking for — a skill removed, or a target removed — loses the files we wrote that still hold what we wrote, and then the directory if that left it empty. A file you changed or added stays, because those bytes are the only copy of that work, and the directory is reported on every sync until it is empty. --force does not remove it: nothing is in the way of a removal, and nothing that differs from what we wrote is ever deleted. Conflicts — --dry-run with --force (a write requested in a mode that writes nothing).
Each location says where it delivers, once. Its header names the folders and the agents that read each one; a row names a folder only when the skill reached some of them and not others. ✓ arrived, ↑ moved to a newer version, − went away on this run, ! needs you. A skill your configuration disables is counted, not listed: the summary says 3 disabled, on every run, and no row repeats it. The run that takes back a copy it installed says so once: − legacy-migration disabled in your configuration — removed. to11 skill list still names every disabled skill. One row per skill. A skill written the same way into several targets is one row; a row that would say something different in one target — blocked there, or a removal naming its own path — stays a row of its own. The counts follow the rows, and in sync counts skills whose every target already matched. --format json keeps one object per skill and target. Names your own skills already use are one block per location rather than a row each: how many, which, what holds them — a to11 skill your home follows, or a folder another tool put there — and the fix. The summary counts them as not installed. Where the rows came from. When every row comes from one project and environment, the summary ends with · from <project> @ <environment>; the rows do not repeat it. When locations follow different projects, as above, each location’s header says its own with a from line. A location that follows several sources — projects, or one project on two environments — names <project> @ <environment> on each row. Who released it, and when. An installed or updated row ends with the release the environment points at: released <date> by <name>, the date in UTC. Only to11 skill release makes a version reach anyone, so this is who put it on your machine. The part is absent when the platform does not say — a dry run, or a version installed by to11 skill store. The summary counts what did not change as well as what did. 1 updated on its own does not say whether that was one skill out of one or one out of forty, so a run that changed something also says how many already matched their configuration. Those skills get no line of their own — a person reading this wants the diff, and the count is the context the diff is missing. A sync that changes nothing prints one line saying so: an empty terminal is indistinguishable from a crash. There is no count on that line, because the words already carry it. When nothing you follow publishes any skill, that line is no skills to install — nothing you follow publishes any yet instead of nothing to do, because “everything already matches” reads as having your skills.

--remove-all is how you get out

Removal is a sync whose desired state is empty, so it takes the same path and the same report as any other sync. Does — remove every skill installed in the current context, and name every path it touched. A file you changed or added is left, with its directory, exactly as when a single target is dropped — and a directory the CLI cannot read is left whole. Each stays recorded, and is named on every run, until the directory is empty; the run after that removes it and the record. With nothing left to hold, the state file is cleared. --dry-run prints the same thing without doing it — the directories it would keep included. Does not — touch anything not in the state file; delete your configuration or your refresh hooks. Those are one file each, and deleting a file you own is not something a sync should do quietly. It works in the current context only, and never scans the disk. Removal in a repository removes that repository’s; removal at home removes home’s. The platform is untouched, so onboarding again restores everything you can still access.

to11 skill list

Does — report, per location, every skill the CLI manages, every skill your configuration names but does not install, and every skill directory that is not ours; each with one state and where it came from. Does not — browse the catalog; fetch bodies; install; write anything; print an empty list when nothing is configured. Absent skills are listed by default. A skill configuration names but that is not on disk is a row with a state, and that state is the only answer to why is a skill I expected missing.
Each location is printed under the header sync prints for it, which names its folders once and the agents that read them, and its skills are grouped by the project and environment they come from. What sits in a skills folder without coming from a project is last, under not from to11. One row per skill. A row names target folders only when the skill is not the same in every folder the header names — a skill you changed in one of them is a row per state, each naming its folders:
A row spells its folders as the header does: ./ in a repository, ~/ at home. A row says from <workspace/project/skill> only when a prefix renamed it, since the name otherwise says it. The state says what the next sync would do, not what a sync did: to install, to update, to remove, or the state that holds the skill (unchanged, blocked, disabled, …). A row about to be removed says why: no longer configured, or disabled when your configuration still names the skill and disables it. Rows that need doing come first, then steady states. The states table lists every word. --format json keeps the state names (installed, removed, conflict, …) and one object per skill and target. Disabled skills are one line of names under their project, every one of them: the same fact about each, and for most catalogs most of the list. --expand folds nothing: every skill is a row per folder, each naming its folder, disabled skills included, under the same headings. The summary is the same either way. The summary counts skills, not rows, with the same words as the states. on disk is how many of the skills to11 installed are on disk now; a folder deleted by hand is not counted. At a terminal the list is in color — the location and project headings bold, skill names cyan, what the next sync would write green, states that need you yellow, and steady states, disabled skills and the agents in the header gray — and never when it is piped or NO_COLOR is set. Skills you have are listed before disabled ones. There is no --location or --state filter: the headings say both.

to11 skill import

Takes in the skill folders a location’s targets already hold that to11 did not deliver. to11 link runs the same step after it writes the file. Does — in a linked location, list every directory in the targets that holds a SKILL.md, is not a symbolic link, is not one to11 delivered, and is not named in a skills.sh lockfile (skills-lock.json at the repository root, ~/.agents/.skill-lock.json for home); compare each with the linked project, target by target; and act on each through a question or a flag. Does not — run in a location no link has written; release anything; read directories outside the configured targets; follow a link; touch a folder skills.sh installed, a symbolic link, a bare <name>.md document, or a folder holding a skill the project has but this location does not receive (it is not on the environment you follow), which are counted and left alone — the last as not received here, since no sync touches it; untrack a folder git already tracks, which it names the command for instead. Conflicts — --non-interactive with --interactive; --skip with each of --adopt, --upload, --keep and --take. Each folder is one of three. Its files are compared with the files the platform renders for its target — name by name and SHA-256 by SHA-256, leaving out the .gitignore to11 writes and any local dot-prefixed file the render does not carry; a dot-prefixed file the render does carry is compared like the rest — trying the version your environment points at first, then the newest, then the rest. The platform generates each delivered SKILL.md — its name, its description and a line naming the version — so only a folder to11 delivered can be a match: one whose record was lost, for example after ~/.to11 was deleted. A hand-written folder is differs or new. An upload is exactly a to11 skill store --dir. It pins the stored version in the location’s skills.yaml, takes the folder over as the installed copy, and releases nothing. A new folder whose SKILL.md carries no description cannot be uploaded and is listed with needs a description in SKILL.md. A slug the platform refuses is reported on its own line and the others go on. Keep never disables a copy to11 already owns. When the same skill is a match in one target and differs in another, the matching copy is adopted, and keep mine then leaves the differing folder exactly as it is instead of writing disabled: true, which would disable the skill in every target and make the next sync remove the adopted copy. The other targets go on receiving the published skill, and the sync reports the kept folder as blocked until you move it or replace it:
Take deletes the folder’s files. It is what to11 skill sync --force does, for one skill. Without a terminal it needs --yes; at one it asks first. With a flag naming a folder it asks nothing, acts on the folders the flags name, and leaves every other folder as it is. Every name is checked before anything is done. At a terminal without one it adopts every match, asks one multi-select for the new folders with none selected, and one question per skill that differs, defaulting to keep mine. Without a terminal and without one it stops with unmanaged_skills and writes nothing. --yes alone is not an answer: a folder’s fate is a data question. A skill already disabled under the project is not asked about again.
The classification is stdout; the ✓ lines and the Next: line are stderr. Inside a repository, adopting or uploading a folder git already tracks adds one line:
Under --format json stdout is one row per folder:
outcome is adopted, uploaded, kept, took, left or refused, and reason says why a folder was refused or what it needs.

to11 skill store

Pushes a new version upstream. It releases the version to no environment, so nobody else receives it. Does — take a slug and a content source; create the skill if it does not exist; save a new version; put that version on this machine; pin the skill to it in your configuration so your machine and your config agree; report whether the skill was created or a version added, and that it is not published. It also converts what it reads into the one stored text form before posting: CRLF becomes LF, a byte-order mark is dropped, and a file that is not valid UTF-8 is reported rather than sent. A Windows folder imports without anyone editing it by hand. Does not — release a version to an environment; make anything reach anyone else; overwrite an earlier version — a version is immutable and store only ever adds; turn a skill into a chat prompt or the reverse; guess a description for a new skill. Conflicts — exactly one of --dir, --from, --body is required. The description’s source depends on the content source. Creating takes it from --description, falling back to the entry document’s frontmatter — with any source, because --from and --body are stored as a SKILL.md as well. A new skill with neither is the error; the flag alone is not required. On a skill that already exists, --from and --body take it from the flag, while --dir takes it from the entry document and prints --description ignored: the entry document carries the description of an imported directory. A directory is the skill’s own record of what it is, so the flag cannot quietly disagree with the file the agent reads. An entry document carrying no description updates nothing and leaves the stored one standing. Creating and adding are reported differently, and that is the guard against a typo:
A mistyped slug creates a new skill rather than failing, so the word created is what tells you that you meant stored. A new skill nobody has published is harmless — no environment points at it, so the recovery is to store into the right slug and leave the stray one unpublished. A slug belongs to whichever kind claimed it first. A project holding a chat prompt called code-review cannot also hold a skill called code-review, so a store can fail on a name you have never used for a skill:
The way out only runs one way. A skill’s slug can be changed and a chat prompt’s cannot, so the skill is what moves aside — which is also the thing nobody depends on yet. The version you just stored is what lands on disk, not what your environment currently publishes. You are looking at your own work, so seeing the released version under its name would be worse than seeing nothing. It is written as pinned, and sync leaves it alone until you release or unpin it. The files are rendered by the platform, exactly as an installed skill is — frontmatter and all — so what you read on disk is the artifact an agent receives, not the bytes you uploaded. A workspace/project of another organization is stored into, and nothing else. When --organization or TO11_ORGANIZATION names an organization other than the one the configuration follows, the version is not pinned and, without --no-install, not installed:

to11 skill release

Releases a stored version to an environment. The only command that makes a skill reach anyone else. Does — two things, one remote and one local. It releases a stored version to an environment, defaulting to the newest version; and it removes the pin from your own configuration when that pin named the version just released. Does not — create or modify content; release a version that fails validation; release to more than one environment at once; act silently. Conflicts — an unknown version is an error listing what exists.
The last line is deliberate. This is the only command whose effect reaches other people, and you should not have to infer that from the absence of a warning. A pin at a different version is left alone: it names a version you are still deliberately holding. If the version is released and the config edit then fails, you are released but still pinned locally — visible rather than silent, with the row showing both versions. Re-running is safe.

to11 code

Runs a coding agent with its traffic going through the to11 gateway. Does — take an agent name, set up a route on the first session when there is none, check that the configured provider can serve the session, point the agent at a local listener that forwards to the gateway, group the session’s turns under one conversation, pass every remaining argument to the agent untouched, and exit with the agent’s exit code. Does not — install the agent; edit providers or credentials; choose the agent’s model; modify the agent’s arguments; interpret its output; put the API key anywhere it could be read. --gateway-project is the earlier name of --project and still works. Conflicts — --no-gateway with any other flag. Everything after the agent name is the agent’s and is never parsed as ours, including flags that collide with these. Anything else is an error naming what is supported, rather than an attempt that fails somewhere inside the agent’s own startup. The agent must already be on your PATH: claude is not on your PATH or codex is not on your PATH, and this command installs neither. The agent is pointed at a listener on 127.0.0.1, open for the session and closed when the agent exits. Claude Code finds it through variables set in its own process environment only. Codex runs with a profile written for the session, <CODEX_HOME>/to11-code-<hex>.config.toml, selected with --profile and removed when the session ends; ~/.codex/config.toml is never written. The agent holds a token good for that listener and nothing else. The listener adds your to11 credential to each request and passes the agent’s own credential headers through. Codex is told to send its own login only when every credential on the provider is passthrough; a provider holding a stored key can serve the session with that key instead. It prints nothing on the way through, so a captured session is byte-for-byte what the agent produced — no “routing through to11” confirmation, ever. The two exceptions are on stderr: what a first session connected and saved, and something wrong enough that the agent would fail confusingly.

Without a code.<agent>.yaml, the first session sets one up

A routed session names the provider it routes to, in code.claude.yaml or code.codex.yaml — one file per agent. When there is none, the session sets one up from the most specific skills.yaml: the repository’s when it has one, else your home’s. It routes through the first project that skills.yaml names, and through the provider at a fixed slug there: anthropic-to11-cli for Claude Code; for Codex, chatgpt-to11-cli when Codex is signed in with ChatGPT ("auth_mode": "chatgpt" in auth.json under $CODEX_HOME, default ~/.codex) and openai-to11-cli otherwise. When the project has no provider at that slug, the session connects one — named Anthropic (to11 CLI), ChatGPT (to11 CLI) or OpenAI (to11 CLI) — in passthrough mode with the Allow by default access policy, so every model the vendor serves is allowed, including models it releases later, and goes live in every environment of the project. Connecting needs the routing:write permission on the project. The environment is prod when the provider is live there, else the first environment it is live in. The file is saved beside that skills.yaml, and the session says so on stderr before the agent starts:
A provider at that slug that is not a passthrough provider of the agent’s vendor, live in one of the project’s environments, stops the session instead, with nothing connected or saved. The error names the to11 ui overview row where another provider can be chosen. With no skills.yaml either, there is no routed session:
to11 ui also writes the file, from the Code · Claude Code or Code · Codex row on its overview.

The check before the agent starts

The three coordinates are checked against the platform before the agent is launched, and the session does not start when one of them is wrong:
Each coordinate has its own error: no such project, no such environment, no such provider, a provider that is archived, and a provider not active in the named environment — the last naming the environments it is active in. --no-gateway does not route and checks nothing. The refresh hook modes launch no agent and check nothing.

The model

The agent chooses its model; this command decides where its traffic goes. It neither reads nor sets ANTHROPIC_MODEL, and the Codex profile sets no model. A model the provider does not allow is refused by the gateway.

Refresh hook modes

Modes an agent harness invokes to refresh skills. Not for typing by hand, and each takes no agent name. Each agent names its own, because an agent’s events are its own: Codex has no expansion event, and a point one agent fires is not the point the other fires. --refresh-hook is for an integration that is neither. Each names a mode, not an action, so what a refresh point does can change in the CLI without rewriting a file in your agent configuration. The to11 plugin is what wires them to their events; to11 link and to11 ui offer to install it. Every mode exits zero in every state, writes nothing to either stream, and emits no hook decision. A refresh does not get a vote on whether your work proceeds.

to11 version

Does — print the CLI version and exit zero. Does not — contact the platform; check for updates; read configuration. So it answers on a machine with no configuration and no network, which is the state you are in when you are working out why nothing else works.
to11 --version prints the same thing.