# 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.
 
## Quick Start
 
```bash
git clone https://github.com/autonomic/nono-opencode-tinfoil.git
cd nono-opencode-tinfoil
make install
# Ensure ~/.local/bin is in your PATH
opencode
```
 
## 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. If not already installed, you can use any of:
  - **Homebrew**: `brew install opencode`
  - **npm**: `npm i -g opencode-ai`
  - **Other**: Any Node version manager (Volta, fnm, etc.)

## 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 -- <real-opencode>
       ↓
  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
 
### Environment Variables
 
| Status | Variables / Patterns |
|--------|----------------------|
| Allowed | `PATH`, `HOME`, `USER`, `SHELL`, `TERM` |
| Denied  | `AWS_*`, `GOOGLE_*`, `AZURE_*`, `KUBECONFIG`, `SSH_AUTH_SOCK` |
 
## Uninstall


```bash
make uninstall
```

To also remove the TUI binary:

```bash
rm -f ~/.local/bin/nono-tui
```

## License
 
GPL-3.0

## Troubleshooting
 
**"command not found: opencode"**
Ensure `~/.local/bin` is in your `PATH`. Add `export PATH="$HOME/.local/bin:$PATH"` to your `.bashrc` or `.zshrc` and restart your terminal.
 
**Sandbox is being bypassed**
If you have another version of `opencode` installed (e.g. via Homebrew) that appears earlier in your `PATH` than the wrapper, the sandbox will be bypassed. Check this using `which -a opencode`. The wrapper at `~/.local/bin/opencode` must come first.

