# nono-opencode-tinfoil A [`nono`](https://github.com/guybedford/nono) sandbox profile for running [OpenCode](https://opencode.ai) with access to [Tinfoil](https://tinfoil.sh) enclaves and other LLM providers. ## Install ### macOS / Linux ```bash git clone https://github.com/autonomic/nono-opencode-tinfoil.git cd nono-opencode-tinfoil make install ``` This installs: - The sandbox profile to `~/.config/nono/profiles/opencode-tinfoil.json` - A wrapper script to `~/.local/bin/opencode` ### Requirements - [nono](https://github.com/guybedford/nono) installed e.g. `brew install nono` - `opencode` installed globally — any of: - **Homebrew**: `brew install opencode` - **npm**: `npm i -g opencode-ai` - **Volta**, **fnm**, or any other Node version manager ## How it works ``` you type: opencode ↓ ~/.local/bin/opencode (wrapper) ↓ scans PATH for the real opencode binary (skips itself — finds brew, npm, volta, etc.) ↓ exec nono run --profile opencode-tinfoil --allow-cwd -- ↓ opencode runs inside the sandbox ``` The wrapper resolves the real `opencode` binary at runtime by scanning every directory in your `PATH`. It skips itself, so it works regardless of: - Where opencode is installed (Homebrew on macOS/Linux, npm global, Volta, etc.) - PATH ordering between the wrapper and the real binary - opencode version bumps You just type `opencode` from any project directory and it runs sandboxed. ### PATH ordering If a non-sandboxed `opencode` appears *earlier* on your `PATH` than the wrapper, typing `opencode` will bypass the sandbox. The installer detects and warns about this. Fix it by adding this to your shell config file (e.g., `~/.bashrc` or `~/.zshrc`): ```bash export PATH="$HOME/.local/bin:$PATH" ``` Or add an alias to your shell profile: ```bash alias opencode="$HOME/.local/bin/opencode" ``` ## Usage From any project directory: ```bash opencode ``` Or use the profile directly with any opencode binary: ```bash nono run --profile opencode-tinfoil --allow-cwd -- opencode ``` You can also point it at a specific binary: ```bash # Homebrew (macOS) nono run --profile opencode-tinfoil --allow-cwd -- /opt/homebrew/bin/opencode # Homebrew (Linux) nono run --profile opencode-tinfoil --allow-cwd -- /home/linuxbrew/.linuxbrew/bin/opencode # npm global nono run --profile opencode-tinfoil --allow-cwd -- $(npm root -g)/opencode/bin/opencode ``` ## TUI A terminal UI for managing the sandbox profile and checking environment status. ### Run from the repo ```bash make tui ``` ### Install for use from anywhere Build and install the binary to `~/.local/bin/nono-tui`: ```bash make tui-install ``` Then run from any directory: ```bash nono-tui ``` Make sure `~/.local/bin` is on your `PATH`. If it isn't, add this to your shell config file (e.g., `~/.bashrc` or `~/.zshrc`): ```bash export PATH="$HOME/.local/bin:$PATH" ``` The TUI reads and edits the installed profile at `~/.config/nono/profiles/opencode-tinfoil.json`, so it works regardless of your current directory. ### What it does The TUI has two tabs: **Dashboard** — Shows live status of your sandbox setup at a glance: ``` ✓ nono installed /home/linuxbrew/.linuxbrew/bin/nono nono 0.x.x ✓ profile installed ~/.config/nono/profiles/opencode-tinfoil.json ✓ wrapper installed ~/.local/bin/opencode ✗ wrapper first on PATH resolves to /opt/homebrew/bin/opencode ✓ opencode binary /opt/homebrew/bin/opencode ✓ tinfoil credentials ~/.tinfoil > Launch opencode in sandbox Validate profile Refresh checks ``` Use `j/k` to navigate the action list, `l` to launch opencode in the sandbox, `v` to validate the profile, and `r` to re-run all checks. **Editor** — Edit the installed profile (`~/.config/nono/profiles/opencode-tinfoil.json`) with four sub-tabs: | Sub-tab | Key | What you can edit | |---------|-----|-------------------| | Commands | `1` | Allowed binaries (git, node, npm, ...) and blocked binaries (sudo, su, mkfs, ...) | | Filesystem | `2` | Allowed, read-only, write, and denied paths | | Network | `3` | Allowed domains (`*.tinfoil.sh`, `api.openai.com`, ...) and network block toggle | | Environment | `4` | Set environment variables and denied env vars | Changes are applied to the live installed profile — they take effect on the next `opencode` launch. Press `s` to save (which also runs `nono profile validate`). Saved files are written as clean JSON (comments are stripped). ### Keybindings | Key | Action | |-----|--------| | `Tab` | Switch between Dashboard and Editor | | `1`-`4` | Switch editor sub-tab | | `j/k`, `↑/↓` | Move cursor | | `←/→` | Switch between lists within a sub-tab | | `a` | Add entry | | `x` | Remove selected entry | | `enter` | Edit selected entry inline | | `b` | Toggle network block (Network tab only) | | `s` | Save profile + validate | | `l` | Launch opencode in sandbox (Dashboard only) | | `v` | Validate profile (Dashboard only) | | `r` | Refresh checks (Dashboard only) | | `q` | Quit | | `Q` | Force quit (discard unsaved changes) | Unsaved changes are marked with `*` in the title. Pressing `q` with unsaved changes warns you; press `Q` to force quit. ## Tinfoil integration The profile allows network access to: - `*.tinfoil.sh` - `inference.tinfoil.sh` - `containers.tinfoil.sh` - `ghcr.io` and grants read/write access to `~/.tinfoil` for Tinfoil credentials. ## Security model - Current working directory: read/write - OpenCode config: read/write - Tinfoil config: read/write - SSH private keys, AWS/GCP/Azure credentials, kubeconfig: denied - `sudo`, `su`, `doas`, `passwd`, disk tools: denied ## Uninstall ```bash make uninstall ``` To also remove the TUI binary: ```bash rm -f ~/.local/bin/nono-tui ``` ## License GPL-3.0