Files
routstrd/README.md
T
hzrd149andClaude Opus 5 5b4ddf79c4 chore(docs): remove shipped planning docs, refresh CLI reference
Audit of the repo's non-source documentation and ad-hoc scripts.

Deleted (work already shipped, or scratch files):
- IMPLEMENTATION.md — the ~/.cocod → ~/.routstrd/wallet migration plan;
  shipped as src/daemon/wallet/{migration,paths}.ts.
- src/TUI refactor.md — plan to move src/cli/usage-tui.ts into src/tui/;
  done, src/cli/ no longer exists.
- v1-messages-format-report.md — the Messages-API passthrough bug it
  describes is fixed; http/index.ts now forwards path: url.pathname.
- routstr-cost-logging.md — note about the routstr proxy's cost fields vs
  pi-ai; not about this codebase.
- refund.js, refund_new.js — one-off scripts with hardcoded Cashu tokens.
- test_box.ts, test_split_box.ts, test_split_box2.ts — manual renderBox
  eyeball checks that asserted nothing and bun test never ran.

Moved:
- COCO-2.0.0-MIGRATION-PLAN.md → docs/plans/coco-2.0.0-migration.md, with a
  status header. This one is genuinely unexecuted: package.json is still on
  coco-core 1.0.1 / coco-cashu-core 1.1.2-rc.50, and its NPC compatibility
  gate is unresolved.

Added:
- src/tui/usage/render.test.ts — real assertions for what the three deleted
  scratch scripts checked by eye (box width with and without a title, ANSI
  padding, side-by-side composition including unequal heights). renderBox
  had no coverage before.

Updated:
- SKILL.md — ships in the npm package as the CLI reference but was missing
  ~15 commands (wallet doctor/cleanup/npc, nwc and auto-refill, history,
  ping, providers reviews, service install/uninstall/logs, daemon, local,
  update, refund, top, send/receive shortcuts). Also dropped the claim that
  onboard installs cocod (the wallet is in-process), removed two orphaned
  tables misfiled under `routstrd refresh`, and completed the config and
  env-var tables.
- README.md — same cocod correction, points at SKILL.md for the full command
  reference, fixes the stale Project Structure tree and the POST / endpoint
  description.
- SECURITY.md — drop the stray `## SECURITY.md` line above the real heading.
- package.json — add a `smoke` script so scripts/smoke/chat-completions.sh
  stops looking orphaned. Deliberately not wired into CI: it needs a funded
  API key.

Note: the Cashu tokens in the deleted refund scripts remain in git history.
They date from March/April 2026 and were being POSTed to refund endpoints, so
they are almost certainly spent — flagging rather than rewriting history.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UW5RBn7pxSuHbDQjtHfQVW
2026-09-09 14:49:25 -05:00

9.9 KiB

routstrd

Routstr daemon - A CLI tool for managing routstr processes, with a built-in Cashu wallet.

Overview

routstrd is a Bun-based CLI tool that provides a background daemon for the Routstr protocol. It carries an in-process Cashu wallet (coco) for payments and uses the Routstr SDK to handle provider routing and model discovery.

Routstr for Teams

For team-based routing, see routstrd-auth.

Features

  • Daemon Mode: Run routstrd as a background HTTP server
  • Wallet Integration: In-process Cashu wallet, with Lightning, NWC, and NPC support
  • Provider Routing: Automatically discovers and routes requests to available providers
  • Config Management: Stores configuration in ~/.routstrd/

Requirements

The standalone release does not require Bun, Node.js, or npm. Installing from npm or running from source requires the Bun runtime.

Installation

Step 1: Install

Standalone binary:

Download the archive for your operating system and architecture from the latest GitHub Release. Release archives are available for Linux and macOS on x64 and arm64.

grep "routstrd-v0.4.9-linux-x64.tar.gz" SHA256SUMS | shasum -a 256 -c -
tar -xzf routstrd-v0.4.9-linux-x64.tar.gz
mkdir -p "$HOME/.local/bin"
install -m 755 routstrd "$HOME/.local/bin/routstrd"

Substitute the version, platform, and architecture for the archive you downloaded, and ensure $HOME/.local/bin is on PATH.

Global with bun:

bun i -g routstrd

OR - From source:

git clone https://github.com/routstr/routstrd.git
cd routstrd
bun install
bun link

Step 2: Setup & Fund

routstrd onboard
routstrd receive <cashu>       # receive a Cashu token
routstrd receive 2100         # to top up 2100 sats with lightning

Step 3: Integrate with Claude Code

routstrd clients add --claude-code  # or --pi-agent / --opencode

Use Routstrd Skill

Tip: You can also install the routstrd skill so the agent can manage routstrd for you.

More Commands

SKILL.md is the complete per-command reference — every command, subcommand, and flag. The sections below cover the common ones.

Start Daemon

Start the background daemon:

routstrd start

With custom port:

routstrd start --port 9000

The daemon binds to 127.0.0.1 by default. To expose it on another interface:

routstrd start --host 0.0.0.0

Only expose the daemon behind appropriate network controls.

With specific provider:

routstrd start --provider https://your-provider.com

CLI Commands

Check daemon status:

routstrd status

Get wallet balance:

routstrd balance

Test connection:

routstrd ping

Refresh models and client integrations on demand:

routstrd clients --manual-refresh   # same as `routstrd refresh`

Turn the daemon's scheduled refresh on or off (no restart needed):

routstrd clients --disable-automatic-refresh
routstrd clients --enable-automatic-refresh

Stop the daemon:

routstrd stop

NPC (Lightning Address)

The in-process wallet registers the NPC (npubx.cash) plugin, which gives the daemon a persistent Lightning address backed by the wallet's Cashu mints. Payments to the address are imported into the wallet automatically (websocket push, plus manual sync on demand).

# Show your NPC Lightning address (username@npubx.cash, or npub fallback)
routstrd wallet npc address

# Claim a username (quote first, then confirm to pay the claim fee from the wallet)
routstrd wallet npc username myname
routstrd wallet npc username myname --confirm

# Manually sync paid NPC quotes into the wallet
routstrd wallet npc sync

Equivalent daemon endpoints: GET /wallet/npc/address, POST /wallet/npc/username, POST /wallet/npc/sync.

Daemon API

The daemon exposes an HTTP server (default port 8008) with the following endpoints:

Health Check

GET /health

Automatic Refresh Settings

POST /settings/auto-refresh

Request body:

{ "enabled": false }

Enables or disables the scheduled refresh job. Persisted to the daemon's config.json as autoRefresh.enabled and picked up on the next tick, so no daemon restart is required.

Route Request

POST /v1/chat/completions

Any unmatched POST path is proxied to the selected provider with the incoming path preserved, so POST /v1/messages (Anthropic Messages API) and POST /v1/responses (OpenAI Responses API) work in their own formats too.

Request body:

{
  "model": "model-id",
  "messages": [...],
  "stream": false
}

Response:

{
  "choices": [...],
  "usage": {...}
}

Wallet storage

The in-process Cashu wallet stores its mnemonic and proof database in ~/.routstrd/wallet/. On first startup, an existing wallet in ~/.cocod/ is migrated automatically after routstrd verifies that the legacy cocod daemon is not running. Back up your mnemonic before upgrading.

Set ROUTSTRD_WALLET_DIR to override the canonical wallet directory. The COCOD_DIR, COCOD_SOCKET, and COCOD_PID variables are retained only for locating and excluding a legacy external cocod process.

If both ~/.routstrd/wallet and ~/.cocod contain different wallets, startup refuses to migrate rather than picking a mnemonic for you. Run routstrd wallet doctor to compare the two wallets (mnemonic fingerprints, timestamps, and balances) and see which one to keep.

Configuration

Configuration is stored in ~/.routstrd/config.json:

{
  "port": 8008,
  "host": "127.0.0.1",
  "provider": null,
  "cocodPath": null,
  "autoRefresh": { "enabled": true }
}

autoRefresh.enabled (default true) controls the daemon's scheduled refresh job, which re-fetches Nostr events, routstr21 models, and client integrations every 21 minutes. Set it to false (or run routstrd clients --disable-automatic-refresh) to turn the schedule off and refresh manually with routstrd clients --manual-refresh. autoRefresh.intervalMs overrides the 21-minute interval.

Environment Variables

  • ROUTSTRD_DIR - Config directory (default: ~/.routstrd)
  • ROUTSTRD_SOCKET - Socket path (default: ~/.routstrd/routstrd.sock)
  • ROUTSTRD_PID - PID file path (default: ~/.routstrd/routstrd.pid)
  • ROUTSTRD_WALLET_DIR - Wallet data directory (default: ~/.routstrd/wallet)
  • COCOD_DIR - Legacy external cocod directory, used only for migration and exclusion (default: ~/.cocod)

Development

Install dependencies:

bun install

Run the CLI from source:

bun src/index.ts <command>

Run the daemon:

bun run start

Run the tests:

bun test

Build a standalone executable for the current platform:

bun run build:binary
./dist/routstrd --version

Standalone installations update directly from GitHub Releases with routstrd update. npm installations continue to update through Bun. PM2 is an optional external dependency used only by routstrd service; normal daemon operation does not require it.

When an update finds a process on the configured daemon port, it only stops that process if the wallet PID file confirms a live daemon owned by the same routstrd configuration. Otherwise the update remains installed, but automatic restart is refused so an unrelated daemon is not interrupted.

Existing PM2 registrations created by routstrd 0.4.x continue to work through a compatibility daemon entrypoint. Recreate the registration to use the unified CLI entrypoint and remove its legacy path dependency:

routstrd service uninstall
routstrd service install
pm2 save

Typecheck:

bun run lint

Manual chat-completions smoke test

With a funded daemon running, create or reuse a client API key and pass one or more current model IDs to the smoke script:

routstrd clients add --name smoke-test
ROUTSTRD_API_KEY=<api-key> bun run smoke <model> [model ...]

Set ROUTSTRD_BASE_URL to test a daemon at a different address. The script makes live provider requests that may spend wallet funds, so it is intentionally not part of bun test.

Publishing a standalone release

  1. Set a new package.json version and commit it. The release tag must be the same version prefixed with v, and the tag must not already exist.
  2. Push the tag. The release workflow runs lint and tests, builds Linux and macOS executables for x64 and arm64, smoke-tests them, and publishes the archives with SHA256SUMS.
  3. Verify all four archives appear in the GitHub Release and validate each checksum before announcing it.
  4. In disposable environments for each platform, test --version, --help, foreground startup failure, and background start, status, and stop without Bun on PATH.
  5. Test routstrd service install and restart behavior with PM2 in a disposable environment. Never run release/update lifecycle tests against a production daemon. When isolation is needed, use both a separate ROUTSTRD_DIR and a non-production port in that configuration.

Project Structure

routstrd/
├── src/
│   ├── index.ts        # CLI entry point with shebang
│   ├── cli.ts          # Commander CLI commands
│   ├── daemon.ts       # Compatibility daemon entrypoint (legacy PM2 registrations)
│   ├── start-daemon.ts # Daemon process launcher
│   ├── daemon/         # HTTP server, wallet, provider routing
│   ├── integrations/   # Client integrations (Claude Code, pi, OpenCode, ...)
│   ├── tui/            # Interactive usage monitor (`routstrd monitor`)
│   └── utils/          # Config, paths, daemon client, update checker
├── tests/              # Integration tests (unit tests sit beside their source)
├── scripts/smoke/      # Manual end-to-end smoke test
├── docs/plans/         # Design/migration plans not yet executed
├── package.json
└── tsconfig.json

License

MIT