AI (BYOK)
Marchyo ships a bring-your-own-key (BYOK) AI desktop. Enabling marchyo.ai
installs per-user AI clients wired to OpenRouter (an OpenAI-compatible
aggregator), adds task-based model routing, a local OpenViking context
layer, MCP tools, and a set of Agent Skills surfaced to every client.
Your API key never enters the Nix store: it is supplied through a sops-nix secret (or any runtime file) and read at startup.
Quick start
Section titled “Quick start”{ # owner is required: the sops-nix default is a root-only 0400 file under # /run/secrets, which the desktop user's AI clients cannot read. sops.secrets."openrouter-api-key".owner = "your-username";
marchyo.ai = { enable = true; openrouter.apiKeyFile = config.sops.secrets."openrouter-api-key".path; };}Clients
Section titled “Clients”- aichat — terminal chat client, also bound to
Super+A(floating terminal). - pi — Armin Ronacher’s minimal coding agent, wired to OpenRouter via a
registered provider (
~/.pi/agent/settings.json+ an extension). - claude-code — installed for convenience, but it speaks the Anthropic API and is not wired to OpenRouter; authenticate it separately.
Options
Section titled “Options”| Option | Default | Description |
|---|---|---|
marchyo.ai.enable |
false |
Enable BYOK AI tooling |
marchyo.ai.provider |
"openrouter" |
AI service provider (enum; "openrouter" is the only value for now — reserved for future providers) |
marchyo.ai.openrouter.apiKeyFile |
null |
Runtime path to the API key (required) |
marchyo.ai.openrouter.baseUrl |
https://openrouter.ai/api/v1 |
OpenAI-compatible base URL |
marchyo.ai.openrouter.defaultModel |
anthropic/claude-sonnet-4 |
Model used when routing is off |
marchyo.ai.tooling.enable |
true |
Install aichat / pi / claude-code |
marchyo.ai.routing.enable |
true |
Task→model routing (see below) |
marchyo.ai.routing.tasks.<bucket> |
pinned defaults | Per-bucket { model; fallbacks; } — primary OpenRouter slug plus fallback chain |
marchyo.ai.routing.tools |
{ aichat = "everydayCoding"; pi = "everydayCoding"; } |
Which task bucket each OpenRouter-backed client defaults to |
marchyo.ai.context.enable |
false |
OpenViking local context layer |
marchyo.ai.context.workspacePath |
".openviking/workspace" |
OpenViking workspace dir, relative to $HOME |
marchyo.ai.context.service.enable |
false |
Run the OpenViking HTTP server as a per-user systemd service |
marchyo.ai.context.embeddingModel |
openai/text-embedding-3-small |
OpenRouter embedding model slug used by OpenViking |
marchyo.ai.skills.enable |
true |
Install Agent Skills to all clients |
marchyo.ai.mcp.enable |
true |
Wire MCP tools into MCP-capable clients |
marchyo.ai.mcp.nixos.enable |
true |
Enable the mcp-nixos server (run via uvx) |
marchyo.ai.local.enable |
false |
Local inference — not yet implemented |
Model routing
Section titled “Model routing”marchyo.ai.routing maps task buckets to a primary OpenRouter model plus a
fallback chain (consumed as OpenRouter’s native models array, which auto-fails
over on errors/rate-limits). Defaults pin the frontier/reasoning buckets and lean
on openrouter/auto and the :nitro/:floor variant suffixes elsewhere so
quarterly model churn is absorbed. Slugs are starting points — verify them
against OpenRouter’s live model list and adjust. Every default is overridable:
marchyo.ai.routing.tasks.frontier.model = "openai/gpt-5.5";marchyo.ai.routing.tools.aichat = "frontier"; # which bucket aichat usesBuckets: frontier, everydayCoding, fast, reasoning, summarize,
longContext, budget, local (placeholder). Both aichat and pi default to the
everydayCoding bucket (marchyo.ai.routing.tools). The resolved policy is
exported to ~/.config/marchyo/ai-routing.json, and each bucket is available as
an aichat role (aichat -r frontier).
Context / memory (OpenViking)
Section titled “Context / memory (OpenViking)”marchyo.ai.context.enable installs the OpenViking ov
CLI — a local context database for AI agents. Data stays under
~/.openviking/workspace (configurable via context.workspacePath); embeddings
are pointed at OpenRouter. The key is injected into ~/.openviking/ov.conf at
activation (never in the store). Index your skills with
ov add-resource ~/.claude/skills.
Only the
ovCLI is packaged (not the separateopenviking-server), socontext.service.enableis not wired yet.
Skills
Section titled “Skills”marchyo.ai.skills installs Marchyo Agent Skills (SKILL.md) — marchyo-config
and nix-build-debug — to every client in skills.clients. claude-code
(~/.claude/skills) and pi (~/.pi/agent/skills) consume the Agent Skills
standard natively; aichat gets each skill as a role. Add more skills by dropping
<name>/SKILL.md dirs under modules/home/ai-skills/skills/.
MCP tools
Section titled “MCP tools”marchyo.ai.mcp wires mcp-nixos into
claude-code (merged into ~/.claude.json), giving grounded NixOS package/option
lookups (no hallucinated attr names). It runs via uvx (uv is installed).
Supplying the key with sops-nix
Section titled “Supplying the key with sops-nix”age-keygen -o ~/.config/sops/age/keys.txtand record the public key.- Add a
.sops.yaml, thensops secrets/ai.yamlcontainingopenrouter-api-key: sk-or-v1-.... - Declare the secret and point Marchyo at its path:
{ sops.defaultSopsFile = ./secrets/ai.yaml; sops.age.keyFile = "/var/lib/sops-nix/key.txt"; # owner so the desktop user can read it (default is root-only 0400). sops.secrets."openrouter-api-key".owner = "your-username";
marchyo.ai = { enable = true; openrouter.apiKeyFile = config.sops.secrets."openrouter-api-key".path; };}The sops NixOS and Home Manager modules are wired into Marchyo’s defaults — you
only declare the secret and provide your age key.
Local inference
Section titled “Local inference”marchyo.ai.local.enable is declared but not implemented; enabling it fails an
assertion. Use OpenRouter for now.