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

# CLI commands

> Every to11 command, its flags, its conflicts, and what each one deliberately does not do.

Eleven commands. Each states what it does **and what it deliberately does not** — the boundary is the part that would otherwise be guessed.

| Command                                     | Does                                                            |
| ------------------------------------------- | --------------------------------------------------------------- |
| [`to11`](#to11)                             | Print the command list and where configuration lives            |
| [`to11 init`](#to11-init)                   | Configure this machine or this repository, and sync once        |
| [`to11 logout`](#to11-logout)               | Remove a stored credential                                      |
| [`to11 whoami`](#to11-whoami)               | Report who you are signed in as                                 |
| [`to11 skill`](#to11-skill)                 | Print the skill subcommands                                     |
| [`to11 skill sync`](#to11-skill-sync)       | Make disk match configuration. `--remove-all` clears it instead |
| [`to11 skill list`](#to11-skill-list)       | Every skill and its state, including ones not installed         |
| [`to11 skill store`](#to11-skill-store)     | Push a new version upstream. **Moves no label**                 |
| [`to11 skill release`](#to11-skill-release) | Move a label to a stored version. The only command others see   |
| [`to11 code`](#to11-code)                   | Run a coding agent through the gateway                          |
| [`to11 version`](#to11-version)             | Print the CLI version                                           |

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.** Turning a skill off, holding a version and choosing a label are lines in a [configuration file](/docs/reference/cli/configuration) — you edit it, and `sync` applies it.

## `to11`

The root command.

**Does** — with no arguments, print the command list and where the two configuration locations live, with whether each exists.

**Does not** — do any work; contact the platform; read or write configuration; guess a subcommand from a near-miss.

| Flag        | Effect                          |
| ----------- | ------------------------------- |
| `--help`    | The same output as no arguments |
| `--version` | Print the CLI version and exit  |

An unknown subcommand prints the command list to stderr and exits non-zero.

## `to11 init`

Configures one location.

**Does** — resolve identity and project; list environments so a label is chosen from real values; **add the project to the config, or update the entry already naming it**; create the target directories; offer refresh hooks; run an initial sync. Re-running offers what is configured, so changing one thing is a single answer.

**Does not** — create projects or environments; manage skills; install an agent; install itself; make any offer silently; write outside the location's own config directory and its target directories; **write a project id** — the file names `workspace/project`, and an id that cannot be resolved to one fails the command.

**A credential scoped to one project is not asked which project.** It already names one, and that is what is written.

| Flag                                               | Effect                                                                          |
| -------------------------------------------------- | ------------------------------------------------------------------------------- |
| `--location home\|repo`                            | Which config to write; default `home`, or `repo` inside a configured repository |
| `--project <name>`                                 | Name the project, as `workspace/project` or `proj_…`                            |
| `--label <slug>`                                   | Choose the label non-interactively                                              |
| `--api-url <url>`                                  | Point at a non-default install for this run                                     |
| `--prefix <name>`                                  | Name installed directories `<prefix>-<slug>`; `""` clears one already set       |
| `--no-hook`, `--no-provider`, `--no-starter-skill` | Decline an offer up front                                                       |

`--project` takes either form — `workspace/project` or `proj_…` — told apart by shape. One flag rather than two, so a run cannot name one project twice and contradict itself.

**The hooks are installed in your own agent settings**, and never in a repository. A session-start hook there fires whatever directory the agent opens in, and `sync` reconciles every location, so one set keeps both current. `to11 init --location repo` therefore offers no hook, and `--no-hook` alongside it is accepted and reported as unnecessary.

One hook per [refresh mode](#refresh-hook-modes), each running `to11` as it resolves on your `PATH` rather than the location the CLI was installed at when you ran `init`. A mode counts as installed when its event already runs a command naming that mode, however the rest of the command is written, and under a matcher that reaches where the mode fires — an absent matcher, `""` or `"*"`, or the mode's own scope. A `PreToolUse` entry scoped to `Bash` is therefore not the skill refresh, and the `Skill`-scoped hook is added beside it.

`init` adds only what is missing and changes or removes nothing, so an entry you have edited yourself survives every later run, and re-running never leaves a second copy.

## `to11 logout`

**Does** — delete the stored credential for the default identity or for `--profile`, and report what was removed.

**Does not** — remove API keys; remove configuration; delete installed skills. **Logging out leaves skills on disk** — logging out is not a request for your agent to stop working.

| Flag               | Effect                       |
| ------------------ | ---------------------------- |
| `--profile <name>` | Log out of a named identity  |
| `--all`            | Remove every stored identity |

**Conflicts** — `--profile` with `--all`.

## `to11 whoami`

**Does** — print the identity, its organizations, the active profile, 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.

| Flag                   | Effect                       |
| ---------------------- | ---------------------------- |
| `--profile <name>`     | Report a named identity      |
| `--format plain\|json` | Output form; default `plain` |

```text theme={null}
$ to11 whoami
marius@to11.ai
organization  acme
credential    person (profile: default)
```

With an API key it says so, and never prints the key:

```text theme={null}
$ to11 whoami
api key ····4f2a
organization  acme
credential    api key
```

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

| Flag                  | Effect                                                                                                      |
| --------------------- | ----------------------------------------------------------------------------------------------------------- |
| `--dry-run`           | Report what would change; write nothing                                                                     |
| `--force`             | Do it anyway: take a directory already there, replace a skill edited on disk, remove one the config dropped |
| `--detailed-exitcode` | Split the outcome ([exit codes](/docs/reference/cli/errors#detailed-exit-codes))                                 |
| `--remove-all`        | Reconcile to nothing: remove every skill installed here, keeping only what you have edited                  |

**One flag, not several.** A directory already there, a skill you edited, and a directory your configuration dropped but you have since changed are one request: *make the machine match the configuration, 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 — is taken back when it still holds what we wrote. One you have edited is reported on every sync and left alone, because those bytes are the only copy of that work. `--force` removes it too.

**Conflicts** — `--dry-run` with `--force` (a write requested in a mode that writes nothing).

```text theme={null}
$ to11 skill sync
home   ~/.claude/skills, ~/.agents/skills
  + incident-triage      v7    sre/runbooks
  ~ release-checklist    v2 → v4
  - legacy-migration     no longer configured
repo   /work/api/.claude/skills
  ! house-style          changed on disk — `to11 skill sync --force` replaces it
2 installed, 1 updated, 1 removed, 1 changed, 6 in sync
```

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

### `--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 directory you have edited is reported and left, exactly as when a single target is dropped — as is one the CLI cannot read at all. Each stays yours, and stays recorded so it can be named again, until `to11 skill sync --remove-all --force`. 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](/docs/reference/cli/output#states) and where it came from.

**Does not** — browse the catalog; fetch bodies; install; write anything; print an empty list when nothing is configured.

| Flag                   | Effect                      |
| ---------------------- | --------------------------- |
| `--slug <slug>`        | Show only these; repeatable |
| `--format plain\|json` | Default `plain`             |

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

```text theme={null}
SKILL              VERSION             STATE        TARGET              LOCATION  PROJECT
incident-triage    pinned 4            unchanged    claude-code         home      acme/sre/runbooks
release-checklist  live · 7            unchanged    claude-code, codex  home      acme/sre/runbooks
house-style        live · 2 → 4        updated      claude-code         repo      acme/web/checklists
audit-runbook      pinned 4 (live: 7)  unchanged    claude-code         home      acme/sre/runbooks
orphaned-runbook   7                   orphaned     claude-code         home      acme/sre/runbooks
my-own-notes       —                   unmanaged    claude-code         home      —
```

**`TARGET` names the [targets](/docs/reference/cli/configuration#where-skills-land) a row is configured for**, whether or not the skill has been installed to them. A row configured for more than one names them all.

There is no `--location` or `--state` filter: every row names both.

## `to11 skill store`

Pushes a new version upstream. **It moves no label**, 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** — move a label; 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.

| Flag                        | Effect                                                                                           |
| --------------------------- | ------------------------------------------------------------------------------------------------ |
| `--dir <path>`              | Import a directory; with an existing skill this **replaces the file set**                        |
| `--from <file>`, `--from -` | One file, or stdin                                                                               |
| `--body <text>`             | Inline text                                                                                      |
| `--description <text>`      | One of the two sources of a new skill's description; afterward replaces it, except under `--dir` |
| `--reason <text>`           | Recorded in history                                                                              |
| `--location home\|repo`     | Which project to store into; default the repo if configured                                      |
| `--no-install`              | Store without putting it on this machine                                                         |

**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:

```text theme={null}
$ to11 skill store incident-triage --dir .
stored    incident-triage v4    sre/runbooks (home)
installed /home/you/.claude/skills/incident-triage
not published — `to11 skill release incident-triage` releases it on `live`

$ to11 skill store incident-triag --dir . --description "…"
created   incident-triag v1     sre/runbooks (home)
```

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 label 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:

```text theme={null}
$ to11 skill store code-review --body "…" --description "…"
error: code-review is taken by a chat prompt named "Code review"
  choose another slug for your skill — a chat prompt's slug cannot move
```

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

## `to11 skill release`

Moves a label to a stored version. **The only command that makes a skill reach anyone else.**

**Does** — two things, one remote and one local. It moves the label to a stored version, defaulting to the newest; 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; move more than one label; act silently.

| Flag                    | Effect                                                      |
| ----------------------- | ----------------------------------------------------------- |
| `--version <n>`         | A specific saved version; default the newest                |
| `--label <slug>`        | Which label to move; default the project's configured label |
| `--location home\|repo` | Which project's label                                       |
| `--reason <text>`       | Recorded in history                                         |

**Conflicts** — an unknown version is an error listing what exists.

```text theme={null}
$ to11 skill release incident-triage
published incident-triage v1 → live    sre/runbooks (home)
everyone who follows `live` in that project receives it on their next sync
```

**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 label moves 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, check that the configured provider can serve the session, set the environment pointing the agent at 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; manage 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.

| Flag                             | Effect                                           |
| -------------------------------- | ------------------------------------------------ |
| `--no-gateway`                   | Run the agent untouched                          |
| `--conversation-id <id>`         | Group turns under an existing conversation       |
| `--gateway-project <name or id>` | Route to a project other than the configured one |

**Conflicts** — `--no-gateway` with either other flag. **Everything after the agent name is the agent's** and is never parsed as ours, including flags that collide with these.

`claude` is the only agent in this release. Anything else is an error naming what is supported, rather than an attempt that fails somewhere inside the agent's own startup.

**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 one exception is on stderr, when something is wrong enough that the agent would fail confusingly.

### It needs a `code.claude.yaml`

A routed session names the provider it routes to, in [`code.claude.yaml`](/docs/reference/cli/configuration#codeclaudeyaml). Without one there is no routed session:

```text theme={null}
$ to11 code claude
to11: no code.claude.yaml — nothing says which provider to route to
  run `to11 init`, or write one naming the project, the environment
  and the provider a session should use
  `to11 code claude --no-gateway` runs the agent without routing
```

`to11 init` writes the file, so a configured machine already has one.

### The check before the agent starts

The three coordinates are checked against the platform before Claude Code is launched, and the session does not start when one of them is wrong:

```text theme={null}
$ to11 code claude
to11: provider `anthropic` is not active in `production`
  ~/.to11/code.claude.yaml
  it is live in staging, dev
  deploy it to `production`, or name an environment it serves
```

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

`ANTHROPIC_MODEL` is read and checked, never written. The agent chooses its model; this command decides where its traffic goes.

### Refresh hook modes

Modes an agent harness invokes to refresh skills. **Not for typing by hand**, and each takes no agent name.

| Mode                           | Invoked                              | Claude Code event             |
| ------------------------------ | ------------------------------------ | ----------------------------- |
| `--claude-session-start-hook`  | When a session opens                 | `SessionStart`                |
| `--claude-prompt-submit-hook`  | When a prompt is submitted           | `UserPromptSubmit`            |
| `--claude-skill-invoke-hook`   | Before the agent uses a skill        | `PreToolUse`, matcher `Skill` |
| `--claude-command-expand-hook` | Before a typed skill command expands | `UserPromptExpansion`         |

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.

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.

```text theme={null}
$ to11 version
0.4.2
```

`to11 --version` prints the same thing.
