Division of ownership
The line between Nix and runtime state is deliberate:- Nix owns the
opencode.jsonplugin entry (programs.opencode.extraSettings.pluginin nix-ai’s root module) and theomo-senpibunx wrapper (modules/ai-tools.nix, version pinned inlib/versions.nix). The pin carries no Renovate annotation: everyomo-airelease is a prerelease and thelatestdist-tag points at a placeholder, so bump manually againstnpm view omo-ai@beta version. - Runtime state owns everything else:
~/.omo/omo.jsonc(agent→model mappings), provider auth (~/.local/share/opencode/auth.json,~/.codex/auth.json), the Light edition’s plugin cache and hook trust hashes. The installers are idempotent. Rerun them after an omo upgrade. - The bin named
omobelongs to the Light toolkit (~/.local/bin, first on PATH). The standalone Senpi command is therefore exposed asomo-senpi.
Why the plugin entry is declarative
OpenCode’s global config is a home-manager-owned store symlink. The Ultimate installer writes its plugin registration through that symlink unconditionally. That fails against the read-only store and would be clobbered by the next switch anyway. Declaring"oh-my-openagent@latest" (the tagged form the
installer itself writes) means the only thing left for the installer to manage
is ~/.omo runtime state.
Codex is the mirror image: nix-ai renders config.toml defaults through a
deep-merge activation that preserves every key Nix does not manage (only
mcp_servers is stripped). The installer’s [marketplaces.sisyphuslabs],
[plugins."omo@sisyphuslabs"], [features.multi_agent_v2], and
[hooks.state] blocks therefore survive every darwin-rebuild switch,
verified by switching after install and grepping the merged file.
Upgrading
-
Bump
omoSenpiin nix-ai’slib/versions.nix(manual, beta channel). -
Rerun both installers:
- Restart each host once. Codex shows a hooks review after plugin upgrades; re-approve. The hashes changed because the files did.
--codex-autonomous) is deliberately not used. nix-ai pins
approval_policy = "never" with a workspace-write sandbox and no network.
The next rebuild would revert the installer’s danger-full-access keys into
a mixed posture.
Verification
opencode run prints Sisyphus - ultraworker · <model> when the
plugin is live; a plain answer with no header means it is not loaded.
Known upstream skew
The latest published release disagrees with itself about agent model config. Itsdoctor command flags the installer-generated models[] arrays as
invalid, while calling the documented model/fallback_models shape
deprecated. Its own config migrate is a no-op. Either shape loads (exit 0); the normalized shape
avoids the startup-blocking warnings. Model IDs in generated chains can also
drift behind the live provider catalog (for example gpt-5-nano). Fallback
chains absorb it at runtime.