Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AI_DISCLOSURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ models-used:
- claude-opus-5-5
- claude-sonnet-4-6
- claude-sonnet-5
- claude-sonnet-5-5
- gpt-5.6-sol
providers:
- Anthropic
Expand All @@ -18,7 +19,7 @@ scope:
Shell wrapper scripts (bin/, lib/), the `azoidcapp` Python helper,
documentation (docs/), and CI/lint configuration — all with human
review and validation.
last-updated: 2026-10-23
last-updated: 2026-10-24
---

# AI Disclosure
Expand Down
27 changes: 21 additions & 6 deletions bin/bwopencode2
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@
# (database incl. saved sign-in, logs, ...)
# - OpenCode 2 cache (host ~/.cache/opencode2/opencode, mounted at
# ~/.cache/opencode): read-write
# - OpenCode 2 state (~/.local/state/opencode): ephemeral
# (last-used model and prompt history are not remembered)
# - OpenCode 2 state (~/.local/state/opencode): ephemeral, except the TUI
# plugin storage (host ~/.local/state/opencode2/opencode/latest/tui,
# mounted at ~/.local/state/opencode/latest/tui): read-write, so
# dismissed onboarding boxes and tab layout persist (locks and service
# files, and last-used model and prompt history, are not remembered)
# - Managed config: /etc/opencode/opencode.json{,c} and
# /etc/opencode/{agents,commands,plugins,skills}, read-only
# - Project .opencode/: persistent copy kept outside the repository
Expand Down Expand Up @@ -385,6 +388,7 @@ resolve_opencode2_paths() {
OC2_CONFIG_SRC="${_HOME}/.config/opencode2/opencode"
OC2_DATA_SRC="${_HOME}/.local/share/opencode2/opencode"
OC2_CACHE_SRC="${_HOME}/.cache/opencode2/opencode"
OC2_TUI_STATE_SRC="${_HOME}/.local/state/opencode2/opencode/latest/tui"

# Sandbox side: always the standard locations, which is where OpenCode 2
# looks by default, so no XDG_* override is needed. The XDG_* values are
Expand All @@ -394,6 +398,7 @@ resolve_opencode2_paths() {
OC2_DATA_DIR="${XDG_DATA_HOME}/opencode"
OC2_CACHE_DIR="${XDG_CACHE_HOME}/opencode"
OC2_STATE_DIR="${_HOME}/.local/state/opencode"
OC2_TUI_STATE_DIR="${OC2_STATE_DIR}/latest/tui"

# The opencode2 config directory holds service.json, which is never
# mounted: refuse a working directory / --ro-path / --rw-path that would
Expand All @@ -405,13 +410,14 @@ resolve_opencode2_paths() {
# the checks mirror bwopencode and also catch symlinked directories.
_check_dir_safe "${OC2_DATA_SRC}" "opencode2 data dir"
_check_dir_safe "${OC2_CACHE_SRC}" "opencode2 cache dir"
_check_dir_safe "${OC2_TUI_STATE_SRC}" "opencode2 TUI state dir"
}

# Ensure writable directories exist on host. The data dir is bound whole
# because the OpenCode 2 layout is not documented (database + -shm/-wal, log,
# repos, shell, ...), so no file list could be kept in sync.
ensure_host_dirs() {
mkdir -p "${OC2_DATA_SRC}" "${OC2_CACHE_SRC}"
mkdir -p "${OC2_DATA_SRC}" "${OC2_CACHE_SRC}" "${OC2_TUI_STATE_SRC}"
}

# Resolve opencode2 config symlinks.
Expand Down Expand Up @@ -583,13 +589,22 @@ build_opencode2_cache_mount() {
)
}

# ── OpenCode 2 state (ephemeral) ─────────────────────────────────
# ── OpenCode 2 state (ephemeral, TUI plugin storage persists) ────
# $HOME is a tmpfs, so state is discarded on exit; this avoids lock
# clashes on NFS homes. Create the directory chain so OpenCode 2 can
# write into it without having to create parents.
# clashes on NFS homes (locks/) and sharing service files with a host
# opencode2. Create the directory chain so OpenCode 2 can write into it
# without having to create parents.
#
# Only the TUI plugin storage directory is persisted: it holds the
# dismissed "Getting started" box and the tab layout, and is never locked.
# A directory is bound (not single files) because OpenCode writes a temp
# file and renames it over the target, which fails on a bind-mounted file.
# "latest" is the release channel directory name used by OpenCode 2; a
# different channel would use another name and not be persisted.
build_opencode2_state_dir() {
BWRAP_ARGS+=(
--dir "${OC2_STATE_DIR}"
--bind "${OC2_TUI_STATE_SRC}" "${OC2_TUI_STATE_DIR}"
)
}

Expand Down
11 changes: 8 additions & 3 deletions docs/bw-wrappers.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,16 +347,21 @@ binary path there too, not `opencode2`.
| `~/.config/opencode2/opencode` | `~/.config/opencode` | read-only, symlinks resolved |
| `~/.local/share/opencode2/opencode` | `~/.local/share/opencode` | read-write, the whole directory persists |
| `~/.cache/opencode2/opencode` | `~/.cache/opencode` | read-write (provider npm packages install here) |
| (none) | `~/.local/state/opencode` | not persisted (ephemeral) |
| (none) | `~/.local/state/opencode` | not persisted (ephemeral), except the next row |
| `~/.local/state/opencode2/opencode/latest/tui` | `~/.local/state/opencode/latest/tui` | read-write (TUI plugin storage: dismissed onboarding boxes, tab layout) |
| `<repo>/.opencode` | `<repo>/.opencode` | persistent copy under the host data dir `project-dotfiles/<hash>`, so repository content cannot inject config or plugins |
| `/etc/opencode/opencode.json{,c}`, `skills`, `agents`, `commands`, `plugins` | same | read-only, when present |

The whole data directory is bound because the OpenCode 2 layout (database with
`-shm`/`-wal`, `log`, `repos`, `shell`, ...) is not documented. Credentials are
stored in the `credential` table of its database, so `opencode2 auth login`
persists across sessions without anything like `--init-auth` (OpenCode 2's
legacy `auth.json` is only an import source). State is not persisted, so the
last-used model and prompt history are not remembered between sessions.
legacy `auth.json` is only an import source). State is not persisted, except
the TUI plugin storage directory (`latest/tui`), so a dismissed "Getting
started" box and the tab layout survive restarts. Locks and background-service
files stay ephemeral (avoids lock clashes on NFS homes and sharing service
files with a host `opencode2`), so the last-used model and prompt history are
not remembered between sessions.

### Config and authoring directories

Expand Down