omp is a nono package for Oh My Pi (OMP), the pi-coding-agent fork. It provides a secure sandbox for running OMP and any tools it invokes, with built-in protections for your API keys, system credentials, and filesystem. Use it to safely run OMP on your machine: even if OMP or a tool it runs goes rogue, your secrets and system are protected by nono's multi-layered security model.
This pack is a port of the always-further/pi pack. It ships:
- a sandbox profile (
policy.json) granting the filesystem and network access OMP needs, with phantom credential routes for OpenAI, Anthropic, Gemini, GitHub, GitLab, and opencode - an extension (
extensions/nono-sandbox.ts) that injects nono sandbox context at session start, detects denial signatures in tool results, appends Option A/B remediation guidance, shows anonostatus-line entry inside the sandbox, and registers a/nono-statuscommand - a
nono-sandboxskill that teaches the correct diagnostic flow for filesystem and network denials and for credential route setup
Registry pulls require packs signed with keyless Sigstore (GitHub Actions OIDC → Fulcio → Rekor), which a local pack cannot carry. Until this pack is published, install it directly:
~/nono-omp-pack/tools/install-local.shThe script performs the same wiring nono pull would run: symlinks extensions/nono-sandbox.ts into ~/.omp/agent/extensions/ and skills/nono-sandbox into ~/.omp/agent/skills/, writes the profile-drafts marker, installs policy.json as the local base profile ~/.config/nono/profiles/omp-base.json, and creates the child profile omp-local extending it (nono profile init omp-local --extends omp-base --full). This mirrors the published base/child shape — the child's extends switches to always-further/omp once the pack is published. Customize the child profile (credential routes, extra grants), then run:
nono run --profile omp-local --allow-cwd -- ompThe extension and skill are symlinks into the pack directory, so add the pack directory to the profile's filesystem.read list (the first-run grants prompt will suggest it). Credential route lookups use the credential_key account name in the nono keychain — if your keyring stores keys under different account names (e.g. opencode instead of OPENCODE_API_KEY), override the route in the child profile with the matching credential_key. After publishing, switch to the registry flow: nono pull always-further/omp, point the child profile's extends at always-further/omp, and the pack-directory grant can be dropped — the pack store under ~/.config/nono/packages is already readable.
Pull the package first, then create a custom profile before running. This avoids the interactive grants prompt that appears when nono encounters paths the base profile doesn't cover:
Step 1 — pull the package:
nono pull always-further/ompStep 2 — create a custom profile:
nono profile init omp --extends always-further/omp --fullStep 3 — run OMP inside the sandbox:
nono run --profile omp --allow-cwd -- ompA custom profile is also where you add credential routes, API keys, tokens, extra filesystem grants, and any other customizations — see the sections below. It's worth running step 2 even if you don't think you'll need custom grants, just to avoid the grants prompt later.
If you run nono before creating a custom profile, nono may detect paths that OMP needs but that the base profile doesn't cover — your shell config, a tool on a non-standard path, etc. When this happens you'll see a prompt like:
Sandbox denial: 3 paths blocked.
~/.config/gh (read)
~/dev/dotfiles/zsh (read)
/usr/local/sbin (read)
[nono] Choose suppress to keep denying all listed paths and stop future save suggestions.
Save suggestions to a user profile? [g] grant / [s] suppress / [Enter] skip:
g(grant) — saves the extra path grants to a user profile. Use the same name you plan to use for your custom profile (e.g.omp) so both sets of grants live in one place.s(suppress) — stops nono from suggesting these paths in future. The paths remain denied.- Enter (skip) — skips saving for now. You'll be prompted again next time.
The cleanest approach is to skip (Enter) and add any extra paths manually to your child profile's filesystem.read or filesystem.allow block.
To create your own custom profile that extends the base always-further/omp profile, use nono profile init with the --extends flag:
nono profile init my-omp --extends always-further/omp --fullEdit ~/.config/nono/profiles/my-omp.json to add credential routes, extra filesystem grants, and any other customizations, then run with nono run --profile my-omp -- omp. When you're happy with the profile, publish it to the registry so you can pull the same setup on any machine.
nono protects API keys using a phantom credential model. Rather than passing your real key into the sandbox, nono generates a short-lived random token and injects that into OMP instead. When OMP makes an outbound API call carrying the phantom token, nono's proxy intercepts the request, validates the token, fetches the real key from your system keystore (macOS Keychain, Linux Secret Service, 1Password, etc.), and swaps it in before the request leaves the machine. The real key is never visible to the sandboxed process.
Do not store API keys in
~/.omp. OMP's own credential store (~/.omp/agent/agent.db) is inside the sandbox because OMP must read it; a real key there is visible to the sandboxed process and bypasses nono's phantom credential protection. Keep keys in nono's keychain (or a URI ref source) and let nono inject them.
The base omp profile does not enable provider credentials by default. This avoids warnings for unused providers from becoming part of the session boundary.
The following providers are built in and ready to use. How you store the key depends on the route — some read from the system keychain, others from an environment variable in nono's own process:
| Route Name | Provider | Storage method | Key name / account |
|---|---|---|---|
openai |
OpenAI | nono keychain | OPENAI_API_KEY |
anthropic |
Anthropic | nono keychain | ANTHROPIC_API_KEY |
gemini |
Gemini | nono keychain | GOOGLE_API_KEY |
github |
GitHub | nono keychain | GITHUB_TOKEN |
gitlab |
GitLab | nono keychain | GITLAB_TOKEN |
opencode |
opencode | nono keychain | OPENCODE_API_KEY |
Store each key in the nono keychain service under the exact account name shown in the table above. Then add the route name to the credentials array in your child profile's network block to activate it:
"network": {
"block": false,
"allow_domain": [],
"credentials": ["opencode"],
"open_port": [],
"listen_port": [],
"custom_credentials": {}
},secret-tool store --label="nono: OPENCODE_API_KEY" \
service nono username OPENCODE_API_KEY target defaultOn macOS use security add-generic-password -U -s "nono" -a "OPENCODE_API_KEY" -w (keep -w last so macOS prompts for the value instead of recording it in shell history). On Linux this requires a running Secret Service provider such as GNOME Keyring or KWallet. In SSH-only or headless environments, check the nono credential docs before choosing a storage backend.
If your keys live in 1Password, a file, or an environment variable, you can override any built-in route using custom_credentials — see below. For the full credential URI ref model (op://, apple-password://, file://, env://), see https://nono.sh/docs/cli/features/credential-injection.
If the provider you need isn't in the built-in list, add it with custom_credentials in your child profile. This example adds OpenRouter — an OpenAI-compatible model-routing API that authenticates with Authorization: Bearer <key>:
"network": {
"block": false,
"allow_domain": [],
"credentials": ["openrouter"],
"open_port": [],
"listen_port": [],
"custom_credentials": {
"openrouter": {
"upstream": "https://openrouter.ai/api/v1",
"credential_key": "OPENROUTER_API_KEY",
"env_var": "OPENROUTER_API_KEY"
}
}
}Note: keep the real OpenRouter secret stored under OPENROUTER_API_KEY, but inject the phantom token into OPENROUTER_API_KEY for OMP. OMP currently chooses API-key environment variables by inspecting the configured base URL host. Inside nono, OMP sees the local proxy URL (http://127.0.0.1:<port>/openrouter), not openrouter.ai, so it follows its OpenAI-compatible fallback path and reads OPENROUTER_API_KEY.
The map key ("openrouter") is the route name. It must also appear in the credentials array — nono only activates routes explicitly listed there. inject_header and credential_format are omitted because the defaults ("Authorization" and "Bearer {}") already match what OpenRouter expects.
For tighter control you can add endpoint_rules — a list of {"method", "path"} pairs that act as an L7 allow-list. When non-empty, the proxy rejects any request that doesn't match, even with a valid phantom token. Omit it, as above, to allow all paths under the route.
Every nono session produces an append-only audit log recording what OMP did: the command and arguments (with secrets redacted), start/end timestamps, exit code, capability decisions, network events, and the filesystem paths it touched. Logs are written to ~/.nono/audit/ as session.json and audit-events.ndjson, and are tamper-evident by default.
nono audit list # all sessions
nono audit list --today # today only
nono audit list --command omp # filter by command
nono audit show <session-id> # inspect a session
nono audit show <session-id> --json # machine-readable
nono audit verify <session-id> # verify log integrity
nono audit cleanup # remove old sessionsTo disable audit logging for a session, pass --no-audit:
nono run --profile omp --no-audit -- ompnono can snapshot the filesystem before OMP runs and let you selectively restore any files it changed or deleted:
nono run --rollback --profile omp -- ompWith --rollback active, nono takes a baseline snapshot before execution and a final snapshot after. When OMP exits, if any files were modified or deleted you get an interactive review showing a per-file diff and a prompt to restore whichever files you want back. Snapshots are stored in ~/.nono/rollbacks/<session-id>/ using SHA-256 content-addressable storage with Merkle tree verification.
nono rollback list # past sessions grouped by project
nono rollback show <id> --diff # inspect what changed
nono rollback restore <id> # interactive restore
nono rollback restore <id> --dry-run # preview without writing
nono rollback verify <id> # check Merkle integrity
nono rollback cleanup --older-than 7 # remove sessions older than 7 daysTo suppress the interactive review prompt (for scripting):
nono run --rollback --no-rollback-prompt --profile omp -- ompExclude noisy paths from snapshot tracking in your child profile:
"rollback": {
"exclude_patterns": ["node_modules", ".next", "__pycache__"],
"exclude_globs": ["*.tmp.[0-9]*.[0-9]*"]
}.gitignore entries in the working directory are also respected automatically.
nono comes with a built-in PTY multiplexer, so you can detach and re-attach to OMP sessions at will:
nono run --profile omp --detach -- omp
nono attach <session-id>nono remove always-further/omp- Name:
omp - Version:
0.0.1 - Pack type:
agent - Platforms:
macos,linux - License:
Apache-2.0