Expand the documentation with measured figures and operational detail
Most of this replaces "roughly 550 characters per tool" with the actual per-tool measurements, and fills in the parts a reader hits after the happy path: what a specific error means, what a setting costs, what is not covered. Measured rather than estimated: - Per-tool byte cost, all fourteen, and the per-set totals. 7,673 B for the full set, averaging 548. - Builtin skill bodies at 5,284 B against a 681 B catalogue, which is the argument for loading bodies on demand. - Full system prompt 3,571 chars, core-only 2,045. New sections: - tools: which sets to keep and why, the jail function itself, an output-cap table, and the real error strings for edit_file and multi_edit. - configuration: env var per provider preset, cost-estimate limits, what each --no-* flag isolates, and three settings that do more than they look like. - agents: step caps per variant, which variant to reach for, and the fact that reasoning is charged as output and discarded first by compaction. - headless: exit code 0 means "the turn completed", not "the answer was yes" — with the jq pattern for gating on content. Timeouts, concurrent -c runs fighting over one session, CI recipes for --no-skills. - mcp: parallel connect, startup cost, a debugging ladder, and that toolSets does not gate MCP tools. - registry: publishing, local testing over http://localhost, and a troubleshooting section keyed on the actual validator messages. - memory: what compaction discards in what order, /compact versus automatic pruning, and that -c matches on cwd. - skills: the frontmatter reader's limits, and how to verify a skill loaded. Corrections found while cross-checking against the source: - The guard table was missing --force-with-lease and > /dev/sd… - The done event's token fields are optional, so the jq example filters on one rather than assuming it. Two honest limits now written down: the guard matches command strings, so a base64-decoded or script-wrapped command is not caught; and a registry index is trusted for its contents, not its authorship. Verified: all internal links and heading anchors resolve, every docs/ page is reachable from the README, 538 tests pass, typecheck clean.
This commit is contained in:
+100
-19
@@ -48,21 +48,48 @@ Written by `/provider`, editable by hand. Every field is optional.
|
||||
|
||||
`/provider` offers these. Each sets `baseURL` and the wire protocol for you.
|
||||
|
||||
| Preset | Protocol | Endpoint |
|
||||
|---|---|---|
|
||||
| Anthropic | `anthropic` | `api.anthropic.com/v1` |
|
||||
| OpenAI | `openai` | `api.openai.com/v1` |
|
||||
| OpenRouter | `openai` | `openrouter.ai/api/v1` |
|
||||
| Groq | `openai` | `api.groq.com/openai/v1` |
|
||||
| DeepSeek | `openai` | `api.deepseek.com/v1` |
|
||||
| xAI | `openai` | `api.x.ai/v1` |
|
||||
| Ollama | `openai` | `localhost:11434/v1` |
|
||||
| LM Studio | `openai` | `localhost:1234/v1` |
|
||||
| Custom OpenAI-compatible | `openai` | you supply it |
|
||||
| Custom Anthropic-compatible | `anthropic` | you supply it |
|
||||
| Preset | Protocol | Endpoint | Env var checked |
|
||||
|---|---|---|---|
|
||||
| Anthropic | `anthropic` | `api.anthropic.com/v1` | `ANTHROPIC_API_KEY` |
|
||||
| OpenAI | `openai` | `api.openai.com/v1` | `OPENAI_API_KEY` |
|
||||
| OpenRouter | `openai` | `openrouter.ai/api/v1` | `OPENROUTER_API_KEY` |
|
||||
| Groq | `openai` | `api.groq.com/openai/v1` | `GROQ_API_KEY` |
|
||||
| DeepSeek | `openai` | `api.deepseek.com/v1` | `DEEPSEEK_API_KEY` |
|
||||
| xAI | `openai` | `api.x.ai/v1` | `XAI_API_KEY` |
|
||||
| Ollama | `openai` | `localhost:11434/v1` | none, keyless |
|
||||
| LM Studio | `openai` | `localhost:1234/v1` | none, keyless |
|
||||
| Custom OpenAI-compatible | `openai` | you supply it | none |
|
||||
| Custom Anthropic-compatible | `anthropic` | you supply it | none |
|
||||
|
||||
After the key is entered, `GET /v1/models` is called and the list becomes a picker. If the
|
||||
endpoint does not implement it, you type the model id instead — the setup still completes.
|
||||
`provider` is the **wire protocol**, not the vendor. Groq, DeepSeek, xAI, OpenRouter, Ollama,
|
||||
and LM Studio all speak `openai`; only Anthropic speaks `anthropic`. Two things differ between
|
||||
them: the auth header (`Authorization: Bearer` versus `x-api-key`), and how thinking levels map.
|
||||
|
||||
After the key is entered, `GET /v1/models` is called and the list becomes a picker. Both
|
||||
protocols expose that endpoint with the same `data[].id` shape, so one code path handles both.
|
||||
If the endpoint does not implement it, a preset with a known model list falls back to that;
|
||||
otherwise you type the model id and setup still completes.
|
||||
|
||||
Anything the picker offers is a model the endpoint actually reports, which is more reliable than
|
||||
a hard-coded list — that is why the fallback lists are short and only exist for Anthropic and
|
||||
OpenAI.
|
||||
|
||||
## Cost estimates
|
||||
|
||||
`/cost` and the status bar price a turn from a table in `src/pricing.ts`, matched by longest
|
||||
prefix on the model id, so `claude-sonnet-4-5-20250929` resolves via `claude-sonnet-4-5`. An
|
||||
OpenRouter-style `anthropic/claude-sonnet-4-5` has its vendor prefix stripped first.
|
||||
|
||||
An unknown model is reported as unpriced rather than guessed:
|
||||
|
||||
```
|
||||
4210 in / 88 out tokens (llama-3.3-70b is unpriced)
|
||||
```
|
||||
|
||||
Two limits worth knowing. The rates are hand-entered and drift as vendors change them, so treat
|
||||
the figure as an estimate, not a bill. And the token counts come from the provider's usage
|
||||
report, while `~ctx` in the status bar is `JSON.stringify(messages).length / 4` — good enough to
|
||||
decide when to compact, wrong enough that it should not be read as a token count.
|
||||
|
||||
## Environment variables
|
||||
|
||||
@@ -74,12 +101,21 @@ endpoint does not implement it, you type the model id instead — the setup stil
|
||||
| `SHIRO_API_KEY` | overrides `apiKey` |
|
||||
| `ANTHROPIC_API_KEY` | used when `provider` is `anthropic` and no key is set |
|
||||
| `OPENAI_API_KEY` | used when `provider` is `openai` and no key is set |
|
||||
| `SHIRO_HOME` | relocates config, sessions, memory, history, and user skills |
|
||||
| `SHIRO_HOME` | relocates config, sessions, memory, history, user skills, and installs |
|
||||
| `SHIRO_INSTALL_DIR` | where `install:local` and the installers put the binary |
|
||||
| `SHIRO_REPO` | which GitHub repo the installers download from |
|
||||
| `SHIRO_VERSION` | pins the version the installers fetch |
|
||||
|
||||
`SHIRO_HOME` is what the test suite uses to keep a run out of your real config.
|
||||
`SHIRO_HOME` is what the test suite uses to keep a run out of your real config. It is also the
|
||||
way to run two isolated setups side by side — a work profile and a personal one — since it moves
|
||||
every piece of state at once:
|
||||
|
||||
```bash
|
||||
SHIRO_HOME=~/work-shiro shiro
|
||||
```
|
||||
|
||||
A key on the command line ends up in your shell history and in `ps`. `SHIRO_API_KEY` in front of
|
||||
one command is better; `/provider` writing to `config.json` is better still.
|
||||
|
||||
## Flags
|
||||
|
||||
@@ -103,13 +139,31 @@ cat file | shiro -p prompt read from stdin
|
||||
| `--no-mcp` | skip MCP servers |
|
||||
| `--no-subagent` | omit the `task` tool |
|
||||
| `--no-instructions` | ignore `AGENTS.md` and friends |
|
||||
| `--no-skills` | ignore builtin and project skills |
|
||||
| `--no-plugins` | disable all plugins, including the guard |
|
||||
| `--no-skills` | ignore builtin, installed, and project skills |
|
||||
| `--no-plugins` | disable all plugins, builtin and installed, including the guard |
|
||||
| `--no-memory` | do not load or write project memory |
|
||||
| `--yolo` | skip every approval prompt |
|
||||
| `-v`, `--version` | version, bun version, platform, source or compiled |
|
||||
| `-h`, `--help` | usage |
|
||||
|
||||
The `--no-*` flags exist for isolating a problem. All six together strip the agent to its
|
||||
built-in tools and nothing else, which answers "is this the loop or something layered on it?"
|
||||
in one run:
|
||||
|
||||
```bash
|
||||
shiro --no-plugins --no-skills --no-memory --no-instructions --no-subagent --no-mcp
|
||||
```
|
||||
|
||||
`--no-plugins` also disables the guard, so `rm -rf` becomes an ordinary approval prompt.
|
||||
Reasonable while debugging, not something to leave on.
|
||||
|
||||
An unknown value fails at startup with the valid list rather than falling back silently:
|
||||
|
||||
```
|
||||
$ shiro --agent turbo
|
||||
shiro: Unknown agent "turbo". Available: default, quick, deep, plan, review
|
||||
```
|
||||
|
||||
## Where things live
|
||||
|
||||
```
|
||||
@@ -133,7 +187,8 @@ Project files:
|
||||
```
|
||||
|
||||
Memory and history file names are SHA-256 prefixes of the absolute project path, because a
|
||||
path is not a safe filename.
|
||||
path is not a safe filename. Two consequences: moving a project loses its memory and history,
|
||||
and two checkouts of the same repo at different paths keep separate ones.
|
||||
|
||||
## OpenAI reasoning models
|
||||
|
||||
@@ -142,5 +197,31 @@ Newer OpenAI models reject function tools on `/v1/chat/completions` and require
|
||||
on the first switches to the second, sticks for the rest of the session, and prints one
|
||||
notice. Retryable failures — 429 and 5xx — are left to the SDK's backoff instead.
|
||||
|
||||
Only those six codes qualify, because they mean "this endpoint cannot serve this request shape".
|
||||
A 401 is a wrong key and switching endpoints would only produce a second 401 with a more
|
||||
confusing message.
|
||||
|
||||
The switch is sticky on purpose: once an endpoint rejects the shape it rejects every later step
|
||||
too, so re-probing would waste a round trip per step of every turn.
|
||||
|
||||
Third-party endpoints get a plain chat-completions model with no fallback probe, since they
|
||||
do not implement `/v1/responses`.
|
||||
|
||||
The two endpoints also differ in how they carry assistant history, which is where compaction gets
|
||||
interesting — see [memory](memory.md#the-pruning-repair).
|
||||
|
||||
## Config that changes behaviour subtly
|
||||
|
||||
Three fields do more than they look like they do.
|
||||
|
||||
**`thinking`** costs money and latency on every turn, not just hard ones. `off` on a hard problem
|
||||
produces confident wrong answers; `max` on a rename wastes cents and seconds. The agent variants
|
||||
already pick sensible levels — see [agents](agents.md).
|
||||
|
||||
**`toolSets`** removes tools from the model's view entirely. If the agent stops using a tool you
|
||||
expected, check the startup header for which sets loaded: an unrecognised name is dropped
|
||||
silently, so `"gti"` reads as "git is off". See [tools](tools.md#tool-sets).
|
||||
|
||||
**`registryUrl`** is the whole trust decision for installed skills and plugins. There are no
|
||||
signatures, so pointing it at an index means trusting whoever controls that URL — including for
|
||||
whatever they publish later. See [registry](registry.md).
|
||||
|
||||
Reference in New Issue
Block a user