Files
shiro-neko/docs/configuration.md
T
Muhammad Zakir Ramadhan 84c60f2022 Fix the loop stalling after compaction, add an external registry
The compaction bug, which is the important one:

beta.2 taught the pruner to drop any assistant part whose reasoning item it had
removed. That was right about the 400 and wrong about everything else. On a
reasoning model every tool call carries a provider itemId, so past the threshold
the model could no longer see what it had already run, and re-ran the same tools
until maxSteps ended the turn. Reproduced at 12 model calls for a job needing 4,
with nothing but the user message reaching the wire.

The dependency is not the part, it is the itemId. A part carrying one is
serialised as `{ type: 'item_reference', id }`, a pointer to an item stored
provider-side that depends on its reasoning item. Without the itemId the same
content goes out inline and carries no dependency at all. Verified against the
provider's own serialiser: `text` with an itemId becomes item_reference, the
identical part without one becomes output_text.

So `dropOrphanedItems` becomes `detachOrphanedItems`: strip the itemId, keep the
content. Compaction may shorten the history; it must not blank it. The new test
asserts behaviour rather than shape — the loop must end because the model chose
to, and every call after the first must still carry the earlier exchange. A shape
assertion passed the whole time the model was losing its memory.

Registry, via `/registry [list|search|add|remove|installed]`:

Skills and plugins are treated differently on purpose. A skill is prompt text, so
installing one puts a stranger's words into the system prompt of every future
session in this project; the install shows the body first and the origin is
recorded, so /skills always says where an instruction came from. A plugin is a
JSON manifest of deny rules, evaluated by compiled code identical for every
install. Loading TypeScript from a URL is declined outright: a plugin that can
block tool calls could otherwise lie about blocking them.

Validated before anything is written: https only (file: and data: rejected), name
matched against ^[a-z0-9][a-z0-9-]*$ so it cannot escape its directory, size
caps on index and body, every regex compiled, pattern length capped since it runs
on every tool call, and the body's own name checked against the index. Installed
skills rank below your own, so an install can never shadow a skill you wrote.

Interface:
- Context is a percentage of the compaction threshold, amber from two thirds and
  red at 90. A turn about to lose history now says so beforehand.
- Aligned command menu and registry tables; /skills and /plugins name origins.

538 tests, up from 488. The registry is tested against a real local HTTP server,
and the guard is proven to refuse a .env write end to end rather than assumed to.
2026-09-03 03:07:56 +07:00

5.6 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,
  "plugins": ["guard", "time"],
  "toolSets": ["edit-plus", "git"],
  "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
plugins which builtin plugins to enable. Omit for ["guard", "time"]
toolSets optional tool sets beyond core: edit-plus, git. Omit for all of them. See tools
registryUrl index for /registry. Omit for the default. See registry
mcpServers see MCP

Provider presets

/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

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.

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, and user skills
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.

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 and project skills
--no-plugins disable all plugins, 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

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.

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.

Third-party endpoints get a plain chat-completions model with no fallback probe, since they do not implement /v1/responses.