Files
shiro-neko/docs/configuration.md
T
asepharyana a3739eb628
ci / check (macos-latest) (push) Canceled after 0s
ci / check (ubuntu-latest) (push) Canceled after 0s
ci / check (windows-latest) (push) Canceled after 0s
workflow: project-driven agent workflow (docs-first, TODO/ROADMAP tracking, verify-before-done)
- system prompt gains a Project workflow block when the repo tracks its own
  progress (TODO.md/ROADMAP.md/docs): read the task list first and keep it
  current, spec-first for non-trivial work, complete unit tests, verify before
  declaring done
- TODO.md + ROADMAP.md loaded as 'Project tracker' instruction blocks, capped
  tighter than AGENTS.md so the agent sees the shape without drowning in it
- one soft nudge per session when a turn writes files without touching the
  task list; suppressed when todo_write was called; never a gate
- /workflow command + panel showing TODO/ROADMAP/docs presence, line/file
  counts, nudge state
- config: workflow.enabled (default true), workflow.docsDir (default docs)
- prompt-cache version key extended with wf: so toggling the workflow busts
  the cached system prompt
- docs: docs/workflow.md, configuration table row, ROADMAP + TODO entries
- tests: test/workflow.test.ts (9 tests)

830 tests pass, typecheck clean, build green, live headless demo verified
2026-09-09 19:00:22 +07:00

12 KiB

Configuration

Settings come from three places. Later wins:

  1. ~/.shiro-neko/config.json
  2. environment variables
  3. command-line flags

The config file

Written by /provider, editable by hand. Every field is optional.

{
  "provider": "openai",
  "model": "gpt-5",
  "baseURL": "https://api.openai.com/v1",
  "apiKey": "sk-...",
  "presetId": "openai",
  "agent": "default",
  "thinking": "medium",
  "maxRetries": 3,
  "maxSpendUsd": 5,
  "maxSpendPerTurn": 0.5,
  "subagentModel": "gpt-5-nano",
  "plugins": ["guard", "time"],
  "toolSets": ["edit-plus", "extra", "git"],
  "permission": {
    "bash": { "*": "ask", "git *": "allow" }
  },
  "registryUrl": "https://example.com/my-registry/index.json",
  "mcpServers": {
    "fs": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "."] }
  }
}
Field Meaning
provider wire protocol: anthropic or openai. Not the vendor — Groq, OpenRouter, and Ollama all speak openai
model model id as the endpoint names it
baseURL API root. Defaults to the official endpoint for the provider
apiKey sent as Authorization: Bearer for openai, x-api-key for anthropic
presetId which preset /provider chose, so it can show what is configured
agent default variant: default, quick, deep, plan, review
thinking default level: off, low, medium, high, max
maxRetries retries per model call for transient failures. Default 3
maxSpendUsd session spend ceiling: warn at 80%, refuse the next turn at 100%. Headless exits non-zero naming the ceiling. Only enforced on priced models
maxSpendPerTurn per-turn spend ceiling: a single turn past this line is stopped at a step boundary, even when the session ceiling is far away. Only enforced on priced models
workflow project-driven workflow: { "enabled": true, "docsDir": "docs" }. When the repo has TODO.md/ROADMAP.md/docs, the agent's prompt carries a workflow policy and the session nudges once when files change without the task list being updated. See docs/workflow.md
subagentModel model id for explore subagents, which search rather than reason. Omit to share the parent's model. /cost reports subagent spend separately
plugins which builtin plugins to enable. Omit for ["guard", "secrets", "protect", "time", "no-force-push", "no-net-pipe", "no-root", "no-env-write"]
toolSets optional tool sets beyond core: edit-plus, nav, extra, git, and net. Omit for the defaults; net is opt-in. See tools
permission which calls run, ask, or are refused, matched per command or path. See permissions
registryUrl index for /registry. Omit for the default. See registry
mcpServers see MCP

Directories

Beyond the config file, these locations are read on every start:

Path Holds
~/.shiro-neko/config.json the config above
~/.shiro-neko/skills/*.md .shiro/skills/*.md auto-loaded skills — extensions
~/.shiro-neko/tools/*.json .shiro/tools/*.json auto-loaded tool manifests
~/.shiro-neko/plugins/*.json .shiro/plugins/*.json auto-loaded plugin manifests
~/.shiro-neko/commands/*.md .shiro/commands/*.md custom slash commands — custom commands
~/.shiro-neko/registry/{skills,plugins}/ entries installed with /registry
~/.shiro-neko/sessions/ saved sessions, for -c / -r

SHIRO_HOME overrides the home directory for all of these, which is also how the test suite isolates itself.

Provider presets

/provider offers these. Each sets baseURL and the wire protocol for you.

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

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

Variable Effect
SHIRO_PROVIDER overrides provider
SHIRO_MODEL overrides model
SHIRO_BASE_URL overrides baseURL
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, 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. 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:

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

shiro [options]
shiro -p "prompt"          headless, prints to stdout
cat file | shiro -p        prompt read from stdin
Flag Effect
-p, --print [prompt] headless mode. Needs --yolo for tool use
--json with -p, one JSON event per line
-c, --continue resume the newest session for this directory
-r, --resume <id> resume by session id or unique prefix
--agent <name> default, quick, deep, plan, review
--think <level> off, low, medium, high, max
--provider <name> anthropic or openai
--model <id> model id
--base-url <url> API root
--no-mcp skip MCP servers
--no-subagent omit the task tool
--no-instructions ignore AGENTS.md and friends
--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:

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

~/.shiro-neko/
  config.json                 provider, model, key, defaults
  sessions/<uuid>.json        transcripts, token counts, cost, task list
  memory/<hash>.json          durable per-project notes
  history/<hash>.json         prompt history for up-arrow recall
  skills/*.md                 your own skills
  registry/skills/*.md        skills installed with /registry
  registry/plugins/*.json     plugin manifests installed with /registry

Project files:

<project>/
  AGENTS.md                   instructions injected into the system prompt
  .shiro/skills/*.md          project skills, override user and builtin
  .shiroignore                extra ignore rules on top of .gitignore

Memory and history file names are SHA-256 prefixes of the absolute project path, because a 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

Newer OpenAI models reject function tools on /v1/chat/completions and require /v1/responses. For api.openai.com both are chained: a 400, 404, 405, 415, 422, or 501 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.

Config that changes behaviour subtly

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

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.

permission replaces a tool's defaults rather than merging with them, so { "read_file": { "*": "allow" } } also allows reading .env. Order inside a rule table decides the outcome, since later rules win. See permissions.

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.