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.
Codex approval defaults
Source configurationThe Nix modules provide these defaults. A host receives them through its
input update and normal rebuild. A session’s permission selection is separate
from the generated file.
approval_policy = "on-request" and approvals_reviewer = "auto_review".
The sandbox stays workspace-write. Operators can override either value
through programs.codex.approvalPolicy and
programs.codex.approvalsReviewer.
The option schema lives in
nix-codex’s approval module.
The consumer defaults and TOML renderer live in
nix-ai.
Nix uses defaults that yield to explicit operator settings.
Local checks verify default and overridden TOML and repeated module imports.
The upstream Nix CI workflow calls the shared validator on Linux and macOS,
with each platform building its own checks before a release promotion.
The upstream export and consumer defaults are published on main.
The existing bot workflow owns dependency updates. A host uses the defaults
after its input update and normal rebuild.
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.