Files
ssmithxandClaude Opus 5.5 657b0ff802 fix(routstr): stop reconcile failing on nodes without llama-server
Reconcile resolves secret_env for every catalog app before it checks the
app is installed. Routstr's UPSTREAM_API_KEY reads llama-server's key, so
a node without llama-server (archy-x250-beta) logged "required secret
'llama-server-api-key' is missing" on every pass. Mark the entry optional,
as btcpay does for its LND secret. Installing Routstr still installs
llama-server first (a declared dependency), so the key is present
whenever Routstr runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 02:47:28 +00:00
..

Routstr provider — development candidate

This is the local-server foundation of docs/routstr-fips-llama-integration.md. It is not yet lifecycle-qualified or catalog-published. The node's FIPS gateway (/routstr/v1/models, /routstr/v1/chat/completions) serves it to mesh peers only after the operator sets routstr_selling on; it has not yet been exercised between two real nodes. Do not install it over an existing Routstr wallet/database to test it.

Package boundary

  • Builds Routstr Core main at immutable source commit 8ce9ef69fc1b5ecd6f92f1baf54d8c2620ea0e89 (2026-10-24; v0.5.0 plus 87 commits, upstream CI green), using its frozen uv dependency lock. It includes upstream #829 and #872: an X-Cashu payment is refunded when forwarding or settlement fails (connect or read timeout, upstream error), in the error response's x-cashu header and as saved change. No release is tagged after v0.5.0 yet; move to the next tag once there is one. Routstr reports its version as 0.5.0+g8ce9ef6.
  • Upstream's image workflow publishes moving latest images; we therefore build from reviewed source instead of inventing an upstream versioned image tag. The base image is pinned by multi-arch index digest; a production image build remains an acceptance gate.
  • Host API binds only 127.0.0.1:8200. auth: local prevents the app gate from opening external listeners. There is deliberately no browser launch interface.
  • Root filesystem is read-only; /data contains the database, encryption key, relative .wallet directory and logs. /tmp is disposable.
  • A dedicated generated admin secret enters through Podman secrets. No appliance Nostr private key is copied. Admin credential UI is not wired yet.
  • Upstream is the node's private llama-server (http://llama-server:8080/v1), authenticated with llama-server's generated key (llama-server-api-key).
  • The node ecash wallet owns payment settings. CASHU_MINTS renders from {{ECASH_MINTS}} (the wallet's accepted mints; Minibits by default) and RECEIVE_LN_ADDRESS from {{ECASH_LN_ADDRESS}} (the wallet's Minibits address), so earnings above Routstr's 210-sat payout floor are paid to the node wallet, where the existing claim flow redeems them. Never leave CASHU_MINTS empty: Routstr then silently trusts its built-in mint.minibits.cash default.
  • Routstr's database copy of settings wins over the environment after the first start, so archy-start.py (the image's PID 1) re-applies the mints and payout address through the admin API on every start. Mint changes made in Routstr's own admin UI are therefore overwritten by the node wallet's list.
  • The archy-llama model is priced once at install defaults ($1 / $2 per million prompt / completion tokens, plus Routstr's 1% fee). Routstr refuses to serve an unpriced model; an operator's later price is never replaced.
  • No Nostr identity or publication address; analytics and upstream 5xx retries are disabled.
  • Upstream starts exchange-rate/background tasks; disabled pricing refresh does not establish zero external traffic. Runtime egress qualification is pending.
  • TCP health means the API listener is up, not that inference/payments are ready.

llama-server connection contract

The reviewed upstream GenericUpstreamProvider accepts an OpenAI-compatible base URL and optional API key. The initial target is llama.cpp's llama-server:

  • provider base URL points at the private runtime's /v1 API;
  • fetch /v1/models, then explicitly import/enable the chosen model and pricing;
  • enforce a stable model alias and bounded context/output/concurrency;
  • verify usage token accounting and the actual model's chat template;
  • do not advertise tool/streaming support until tested with that model;
  • keep the raw runtime off external listeners and give it a dedicated upstream key.

A candidate managed runtime now lives in apps/llama-server; its source build and lifecycle still need qualification. Private network isolation, configuration RPC/key handoff and model acquisition UI are still to be implemented. There is intentionally no automatic model download or default cloud upstream. Merely sharing archy-net does not isolate the runtime from other installed apps; that is a remaining security gate.

Payment modes (observed at the pinned revision)

X-Cashu: <token> pays for one request and returns change in the X-Cashu response header (the whole token when the request is refused). Authorization: Bearer <token> instead funds a server-side sk- balance and returns no change until POST /v1/balance/refund, which replays the same token if repeated. Buyers must use X-Cashu; the existing Archipelago clients are fixed by the ngit proposal "fix(routstr): pay per request with X-Cashu so change is refunded".

A buyer whose reply never carried its change claims it over the mesh at POST /routstr/v1/balance/refund with the original token: the seller gateway forwards only that token to Routstr's POST /v1/balance/refund, which returns the change it saved for the request (425 while the request is still running).

Upstream routstr/balance.py has persisted refund retrieval and pending outcomes; routstr/upstream/base.py emits millisatoshi cost headers. Neither is evidence that an ambiguous completion can safely be resubmitted. Recovery must not issue another payment or inference request by default.

Source-only checks

From the repository root:

bash scripts/validate-app-manifest.sh apps/routstr/manifest.yml
python3 -m unittest discover -s tests/routstr-provider -p 'test_*.py' -v

These tests do not build/start containers, contact a provider, or touch wallets. For future disposable builds, use docker/routstr as the build context. For node packaging the manifest references /opt/archipelago/docker/routstr, following the normal runtime payload contract. Do not stage this on a live node for acceptance without an explicit test plan and isolated data.