Jump to content

Opencode isolation and burner workflow 260216: Difference between revisions

From Game in the Brain Wiki
Update to match Claude Code isolation workflow: add opencode_isolation.sh, naming convention, daily workflow procedures, isolation table
Line 1: Line 1:
= OpenCode "Burner" Workflow & Hardware Reality Check =
== OpenCode Isolation and Burner Workflow ==


This guide establishes a '''Distrobox-based isolation workflow''' for running OpenCode. This prevents AI agents from accidentally modifying your host system files and allows you to "nuke" the environment if it gets corrupted or compromised.
This workflow uses Distrobox containers to run OpenCode in isolated environments. Key concepts:


== Command Context ==
* Each project runs in its own persistent container
* Save points capture container state as images
* A "golden image" serves as a template for new containers
* Containers are deleted on your schedule


Every command in this guide is prefixed with where it must be run:
'''Protection mechanism:''' Malicious prompt injection damage remains confined to the container, not affecting the host system.


{| class="wikitable"
== Hardware Reality ==
|-
! Prefix !! Meaning
|-
| <code>'''[HOST]'''</code> || Run this in a terminal on your normal Linux desktop, outside any container
|-
| <code>'''[DISTROBOX]'''</code> || Run this inside the Distrobox container after entering it
|}
 
== Part 1: The "Burner" Philosophy ==
 
'''The Goal:''' Run OpenCode in a disposable container (<code>opencode-burner</code>) that shares ''only'' specific project folders, not your entire home directory.
 
'''Simpler than Claude Code:'''
This workflow is significantly more streamlined than typical Claude Code isolation setups. We rely on '''Distrobox Custom Homes''' instead of Firejail for stability.
 
'''No Re-Authentication Loop:''' Unlike Claude, which often forces you to re-login via browser or copy keys every session, this container '''persists''' your "Burner Identity" (Git credentials & Configs).
 
'''Zero Boot Time:''' Distrobox shares your host kernel. There is no VM overhead; it launches instantly.
 
'''One-Step Launch:''' You don't need to manually start a Docker daemon, attach a shell, and then run a binary. The launcher script handles the context switch automatically.
 
'''The Loop:'''
 
'''Spin up''' a fresh Ubuntu container with a '''Custom Home'''.
 
'''Inject''' the necessary tools (NodeJS, Git, OpenCode CLI).
 
'''Mount''' only the target project.
 
'''Burn it''' (delete the container) when the project is done or the environment gets messy.
 
== Part 2: The Hardware Reality (VRAM is the Limit) ==
 
Running local coding agents requires massive '''Context Windows'''. Codebases are large. The standard 4k or 8k context is useless for an agent reading multiple files.
 
'''The Golden Rule:''' You need at least '''32k Context''' for a usable agent.


=== GPU Tier List (Discrete VRAM) ===
You need at least '''32k Context''' for a usable agent.


{| class="wikitable"
{| class="wikitable"
! GPU Class !! VRAM !! Price (PHP) !! Practical Limit !! Verdict
! VRAM !! GPU Example !! Context Window
|-
|-
| '''RX 7600''' || '''8 GB''' || ~₱18,000 || '''8k - 16k'''<br />''(32k Unstable)'' || '''Entry Level.'''<br />8GB is the hard floor. You can run a 7B model, but 32k context "sometimes works" and often crashes (OOM) because the OS + Model leaves almost no room for the cache.
| 8GB || RX 7600 || 8k–16k (unstable at 32k)
|-
|-
| '''RX 9070 XT''' || '''16 GB''' || ~₱50,000 || '''64k (Unstable)''' || '''The Danger Zone.'''<br />16GB is tight. You ''can'' force a '''64k context''', but it '''requires creating a custom <code>Modelfile</code>''' and is unstable. The model weights (~5GB) + OS (~4GB) leave little room for the KV cache. Expect OOM crashes.
| 16GB || RX 9070 XT || Tight; requires custom config
|-
|-
| '''RX 7900 XT''' || '''20 GB''' || ~₱80,000 || '''64k - 80k''' || '''The Sweet Spot.'''<br />That extra 4GB VRAM is crucial. It creates enough headroom to run a quantized 7B or 14B model with a healthy 64k context window comfortably.
| 20GB || RX 7900 XT || Sweet spot; 64k–80k
|-
|-
| '''Workstation'''<br />(e.g., W7800/R9700) || '''32 GB''' || High || '''128k+''' || '''The AI King.'''<br />Required if you want to run full 128k context locally. 32GB VRAM allows for uncompressed cache or running larger parameters (e.g., 32B models) with decent context.
| 32GB+ || || 128k+
|}
|}


=== Unified Memory & Workstation Architectures (Massive Capacity, Slower Speed) ===
Workstation unified memory (Ryzen AI Max+, Mac Studio) supports large models but at slower inference speeds.


Use these if you need to run Huge Models (70B, 405B) that won't fit on any consumer GPU.
'''Recommended models:''' Qwen2.5-Coder-7B through Qwen2.5-Coder-14B; alternative: DeepSeek V3 API (~₱7.80/million tokens).


'''Trade-off:''' While capacity is massive, Tokens Per Second (T/s) is significantly lower (slower generation) compared to the Discrete GPUs above due to lower memory bandwidth.
== Core Naming Convention ==


{| class="wikitable"
{| class="wikitable"
! System / Chip !! RAM (Unified) !! Est. Cost (PHP) !! Capability !! Verdict
! Type !! Format !! Example
|-
| Working container || <code>PREFIX-YYMMDD</code> || <code>oc-260216</code>
|-
|-
| '''AMD Ryzen AI Max+ PRO 395'''<br />''(Strix Halo)'' || '''128 GB'''<br />''(allocates ~112GB to AI)'' || '''~₱135,000'''<br />''(Framework/MiniPC)'' || '''Llama 3 70B @ Q8'''<br />'''DeepSeek V2 Lite''' || '''The Compact Beast.'''<br />Allows running 70B models comfortably. Excellent value for capacity, but slower inference than a dGPU.
| Saved image || <code>localhost/PREFIX-YYMMDD:latest</code> || <code>localhost/oc-260216:latest</code>
|-
|-
| '''Apple Mac Studio'''<br />''(M3/M4 Ultra)'' || '''Up to 512 GB''' || '''~₱400,000 - ₱600,000+'''<br />''(Max Config)'' || '''Llama 3 405B @ Q4'''<br />'''DeepSeek V3 671B''' || '''The Whale.'''<br />One of the few ways to run "Frontier" models locally. Extremely expensive and slower generation speeds, but unparalleled privacy for massive models.
| Golden image || <code>localhost/PREFIX-base:latest</code> || <code>localhost/oc-base:latest</code>
|-
| Burner home || <code>~/sandbox-homes/PREFIX-YYMMDD</code> || <code>~/sandbox-homes/oc-260216</code>
|}
|}


=== Recommended High-Context Models ===
== One-Time Setup: Golden Image Creation ==
Select the model that fits your GPU tier.


'''7-8 Billion Parameter Models (Best for 12GB - 16GB VRAM)'''
'''Step 1: Install Distrobox''' (on host)
<pre>
sudo apt install distrobox    # Debian/Ubuntu
sudo dnf install distrobox    # Fedora
yay -S distrobox              # Arch
</pre>


'''Qwen2.5-Coder-7B-Instruct:''' The current gold standard. Supports up to '''128k natively'''. Excellent for bug fixing and large codebase understanding on consumer hardware.
'''Step 2: Create and enter base container'''
<pre>
mkdir -p ~/sandbox-homes/oc-base
distrobox create --name oc-base --image ubuntu:24.04 --home ~/sandbox-homes/oc-base
distrobox enter oc-base
</pre>


'''YaRN-Mistral-7b-64k:''' Specifically configured for '''64k context''' using the YaRN extension method. Benchmarks show stable perplexity at long lengths.
'''Step 3: Install dependencies''' (inside container)
<pre>
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs git python3
npm install -g opencode-ai
opencode  # Complete authentication / API key setup
</pre>


'''OpenCodeReasoning-Nemotron-7B:''' Supports '''64k context'''. Excels specifically at reasoning tasks for code generation.
'''Step 4: Add launcher script''' (inside container)


'''14-16 Billion Parameter Models (Best for 20GB - 24GB VRAM)'''
Create <code>~/project/opencode_isolation.sh</code>:
 
<pre>
'''Qwen2.5-Coder-14B-Instruct:''' The heavy hitter. Supports '''128k natively'''. Provides significantly more capacity for complex, multi-file project analysis and agentic workflows than the 7B version.
 
'''DeepCoder-14B-Preview:''' Supports '''64k context'''. Uses reinforcement learning to achieve performance comparable to much larger proprietary models.
 
=== The "DeepSeek V3" Alternative ===
Before spending ₱80k on hardware, consider the '''DeepSeek API'''.
 
'''Context:''' 64k (Output) / 128k (Input) natively.
 
'''Intelligence:''' DeepSeek V3 (671B MoE) is vastly smarter than any local Qwen 7B/14B.
 
'''Cost:''' ~₱7.80 ($0.14) per '''1 Million''' tokens.
 
'''Strategy:''' Use '''Local 7B''' for small, private edits. Use '''DeepSeek V3''' for "Build" agent tasks requiring long context.
 
== Part 3: GitHub Burner Identity ==
 
Agents need to pull/push code. Do not give them your main GitHub credentials (SSH keys) that have access to your private company/client repos.
 
'''The Strategy:'''
 
Start by testing with your main account (carefully) to verify the tool works.
 
'''IMMEDIATELY''' switch to a Burner GitHub Account for daily agentic work.
 
'''Generating a Token (PAT):'''
You cannot use a simple password for Git over HTTPS. You need a Personal Access Token.
 
Log in to your '''Burner GitHub Account'''.
 
Click your '''Profile Picture''' (top right) → '''Settings'''.
 
Scroll to the very bottom left sidebar → '''Developer settings'''.
 
Click '''Personal access tokens''' → '''Tokens (classic)'''.
 
Click '''Generate new token (classic)'''.
 
#* ''Note:'' You may be asked for 2FA or Email authentication.
 
'''Scopes:''' Select <code>repo</code> (Full control of private repositories) and <code>workflow</code>.
 
'''Expiration:''' Set to '''90 days'''. (This is fine; we want these to expire so we don't leave loose ends).
 
'''Copy the token immediately.''' You will not see it again.
 
'''Inside the Burner Container:'''
When OpenCode asks for Git authentication, use your Burner Username and paste this Token as the password.
 
== Part 4: Setup Instructions ==
 
=== Step 1: Install Distrobox ===
 
'''[HOST]'''
 
<syntaxhighlight lang="bash">
curl -s https://raw.githubusercontent.com/89luca89/distrobox/main/install | sudo sh
</syntaxhighlight>
 
=== Step 2: Create the Burner Container ===
 
'''[HOST]'''
 
We create a container with a '''custom home directory'''. This is the key isolation step.
 
On your host, this folder will be <code>~/opencode_burner_data</code>.
 
Inside the container, this folder will be seen as <code>/home/username</code>.
 
The AI '''cannot''' see your real SSH keys or Documents because they literally do not exist in this folder.
 
<syntaxhighlight lang="bash">
# Create the storage folder on your host first
mkdir -p ~/opencode_burner_data
 
# Create the container mapped to this folder
distrobox create --name opencode-burner --image ubuntu:24.04 --home ~/opencode_burner_data
</syntaxhighlight>
 
=== Step 3: Enter the Container ===
 
'''[HOST]''' Run this to step inside. Your prompt will change.
 
<syntaxhighlight lang="bash">
distrobox enter opencode-burner
</syntaxhighlight>
 
=== Step 4: Install Dependencies ===
 
'''[DISTROBOX]'''
 
<syntaxhighlight lang="bash">
sudo apt update && sudo apt install -y nodejs npm git build-essential python3
</syntaxhighlight>
 
=== Step 5: Install OpenCode ===
 
'''[DISTROBOX]'''
 
<syntaxhighlight lang="bash">
sudo npm install -g opencode-ai
</syntaxhighlight>
 
=== Step 6: Configure OpenCode ===
 
'''[DISTROBOX]'''
 
<syntaxhighlight lang="bash">
mkdir -p ~/.config/opencode
nano ~/.config/opencode/opencode.json
</syntaxhighlight>
 
'''Nano Shortcuts to Clear File:'''
If the file already has content, use this sequence to clear it quickly:
 
<code>Alt</code> + <code>\</code> : Go to the very first line (Top).
 
<code>Alt</code> + <code>A</code> : 'Mark' the text (Start selection).
 
<code>Alt</code> + <code>/</code> : Go to the very last line (End).
 
<code>Ctrl</code> + <code>K</code> : Cut/Remove the selected text.
 
'''Paste the Configuration:'''
 
<syntaxhighlight lang="json">
{
  "provider": {
    "ollama": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Ollama Local",
      "options": {
        "baseURL": "http://127.0.0.1:11434/v1"
      },
      "models": {
        "qwen2.5-coder:7b": { "name": "Qwen 2.5 Coder (7B)" }
      }
    },
    "deepseek": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "DeepSeek API",
      "options": {
        "baseURL": "https://api.deepseek.com/v1",
        "apiKey": "sk-YOUR_API_KEY"
      },
      "models": {
        "deepseek-chat": { "name": "DeepSeek V3 (Fast & Smart)" },
        "deepseek-reasoner": { "name": "DeepSeek R1 (Thinking Model)" }
      }
    }
  }
}
</syntaxhighlight>
 
'''Save and Exit:''' <code>Ctrl+O</code> → Enter → <code>Ctrl+X</code>
 
=== Step 7: Create Workspace ===
 
'''[DISTROBOX]'''
 
<syntaxhighlight lang="bash">
mkdir -p ~/opencode_workspace
cd ~/opencode_workspace
</syntaxhighlight>
 
=== Step 8: Launch OpenCode ===
 
'''[DISTROBOX]'''
Inside your OpenCode burner container, create the script inside your project directory:<syntaxhighlight lang="bash">
nano ~/opencode_workspace/opencode_isolation.sh
</syntaxhighlight>Copy this Code<syntaxhighlight lang="sh">
#!/bin/bash
#!/bin/bash
# =============================================================================
# Launcher for OpenCode inside Distrobox container
# opencode_isolation.sh
# Launcher script for OpenCode inside a Distrobox container.
#
# Place this script in your project directory inside the container.
# Run it from there to start an OpenCode session scoped to that directory.
# =============================================================================


# -----------------------------------------------------------------------------
# WORK_DIR — the directory OpenCode will run in.
#
# The default below auto-detects the directory this script lives in.
# This works for most setups and requires no changes.
# -----------------------------------------------------------------------------
WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
# WORK_DIR="/home/USER/your-project-directory"  # uncomment for hardcoded path


# -----------------------------------------------------------------------------
# Move into the work directory.
# OpenCode will treat this as its root — all file reads and writes
# happen relative to here.
# -----------------------------------------------------------------------------
cd "$WORK_DIR"
cd "$WORK_DIR"


Line 285: Line 84:
echo ""
echo ""


# -----------------------------------------------------------------------------
# Launch OpenCode.
#
# 'exec' replaces this shell process with opencode — keeps the process tree clean.
# '$@' passes any arguments you gave this script directly through to opencode.
# -----------------------------------------------------------------------------
exec opencode "$@"
exec opencode "$@"
</syntaxhighlight>
</pre>


Launch it
Make executable: <code>chmod +x ~/project/opencode_isolation.sh</code>


<syntaxhighlight lang="bash">
'''Step 5: Commit golden image''' (on host)
./opencode_workspace/opencode_isolation.sh
<pre>
</syntaxhighlight>
exit  # Leave container
distrobox stop oc-base
podman container commit oc-base localhost/oc-base:latest
podman image ls  # Verify
</pre>


=== Step 9: Save as a Golden Image ===
== GitHub Burner Identity ==


Once the container is fully configured, save it as a reusable '''golden image''' so future sessions start pre-installed without repeating Steps 4–7.
Create a separate GitHub account exclusively for agent work. Generate Personal Access Tokens (90-day expiration) scoped to <code>repo</code> and <code>workflow</code> permissions rather than sharing primary credentials.


'''[DISTROBOX]''' Exit the container first:
== Daily Workflow Procedures ==


<syntaxhighlight lang="bash">
=== Starting a New Container ===
exit
<pre>
</syntaxhighlight>
[HOST]      mkdir -p ~/sandbox-homes/oc-260216
[HOST]      distrobox create --name oc-260216 --image localhost/oc-base:latest --home ~/sandbox-homes/oc-260216
[HOST]      distrobox enter oc-260216
[DISTROBOX] cd ~/project && ./opencode_isolation.sh
</pre>


Your prompt should return to the host (e.g., <code>justin@hostname</code>).
=== Continuing an Existing Container ===
<pre>
[HOST]      distrobox enter oc-260216
[DISTROBOX] cd ~/project && ./opencode_isolation.sh
</pre>


'''[HOST]''' Stop the container:
=== Saving a Checkpoint ===
<pre>
[HOST] distrobox stop oc-260216
[HOST] podman container commit oc-260216 localhost/oc-260216:latest
[HOST] distrobox enter oc-260216  # Resume work
</pre>


<syntaxhighlight lang="bash">
=== Branching from a Save Point ===
distrobox stop opencode-burner
<pre>
</syntaxhighlight>
mkdir -p ~/sandbox-homes/oc-260217
distrobox create --name oc-260217 --image localhost/oc-260216:latest --home ~/sandbox-homes/oc-260217
distrobox enter oc-260217
</pre>


'''[HOST]''' Commit the container state to a named Podman image:
=== Restoring from a Checkpoint ===
<pre>
[HOST] distrobox rm oc-260217 && rm -rf ~/sandbox-homes/oc-260217
[HOST] mkdir -p ~/sandbox-homes/oc-260217
[HOST] distrobox create --name oc-260217 --image localhost/oc-260216:latest --home ~/sandbox-homes/oc-260217
</pre>


<syntaxhighlight lang="bash">
=== Promoting a Container to Golden Image ===
podman commit opencode-burner localhost/opencode-golden:latest
<pre>
</syntaxhighlight>
[HOST] distrobox stop oc-260216
 
[HOST] podman container commit oc-260216 localhost/oc-base:latest
'''[HOST]''' Verify the image was created:
</pre>
 
<syntaxhighlight lang="bash">
podman image ls | grep opencode-golden
</syntaxhighlight>
 
You should see output like:


=== Cleanup Commands ===
<pre>
<pre>
localhost/opencode-golden  latest   a1b2c3d4e5f6  2 minutes ago  1.1 GB
podman image ls              # List all images
podman image rm localhost/oc-260216:latest
podman ps -a                # List containers
distrobox rm oc-260216 && rm -rf ~/sandbox-homes/oc-260216
</pre>
</pre>


== Part 5: Starting Sessions from the Golden Image ==
== Parallel Sessions ==
 
Each new working session creates a throwaway container from the golden image. When the session ends, delete the container — leaving no trace.
 
=== Single Session ===
 
'''[HOST]''' Create a new session container:
 
<syntaxhighlight lang="bash">
mkdir -p ~/opencode_burner_data_session1
distrobox create --name opencode-session-1 --image localhost/opencode-golden:latest --home ~/opencode_burner_data_session1
</syntaxhighlight>
 
'''[HOST]''' Enter it:
 
<syntaxhighlight lang="bash">
distrobox enter opencode-session-1
</syntaxhighlight>
 
'''[DISTROBOX]''' Start working immediately — everything is pre-installed:
 
<syntaxhighlight lang="bash">
cd ~/opencode_workspace
opencode
</syntaxhighlight>
 
'''[HOST]''' When the session is done, delete the container and its data:
 
<syntaxhighlight lang="bash">
distrobox rm opencode-session-1
rm -rf ~/opencode_burner_data_session1
</syntaxhighlight>
 
=== Multiple Parallel Sessions (Cloning) ===
 
Run several independent sessions at the same time from the same golden image:
 
'''[HOST]'''
 
<syntaxhighlight lang="bash">
mkdir -p ~/opencode_burner_data_{A,B,C}
 
distrobox create --name opencode-session-A --image localhost/opencode-golden:latest --home ~/opencode_burner_data_A
distrobox create --name opencode-session-B --image localhost/opencode-golden:latest --home ~/opencode_burner_data_B
distrobox create --name opencode-session-C --image localhost/opencode-golden:latest --home ~/opencode_burner_data_C
</syntaxhighlight>
 
Each container is completely independent. Changes in session A do not affect B or C.
 
'''[HOST]''' List all containers:
 
<syntaxhighlight lang="bash">
distrobox list
</syntaxhighlight>
 
'''[HOST]''' Clean up all sessions when done:
 
<syntaxhighlight lang="bash">
distrobox rm opencode-session-A opencode-session-B opencode-session-C
rm -rf ~/opencode_burner_data_{A,B,C}
</syntaxhighlight>
 
=== Updating the Golden Image ===
 
'''[HOST]''' Create a temporary update container:
 
<syntaxhighlight lang="bash">
distrobox create --name opencode-update --image localhost/opencode-golden:latest
distrobox enter opencode-update
</syntaxhighlight>
 
'''[DISTROBOX]''' Make your changes:
 
<syntaxhighlight lang="bash">
sudo npm update -g opencode-ai
</syntaxhighlight>
 
'''[DISTROBOX]''' Exit:
 
<syntaxhighlight lang="bash">
exit
</syntaxhighlight>
 
'''[HOST]''' Commit and clean up:
 
<syntaxhighlight lang="bash">
distrobox stop opencode-update
podman commit opencode-update localhost/opencode-golden:latest
distrobox rm opencode-update
</syntaxhighlight>
 
== Part 6: Automated Launcher (Optional) ==
 
If you get tired of typing <code>distrobox enter</code> every time, you can use the <code>launch_burner.sh</code> script (provided separately) from your '''[HOST]''' terminal. It handles the context switching automatically.
 
== Troubleshooting ==
 
=== "Failed to mount /sys" or Immediate Exit ===
If you try to run Firejail inside Distrobox, you may see:


Clone the golden image into multiple independent containers simultaneously:
<pre>
<pre>
Warning: failed to mount /sys
distrobox create --name oc-A --image localhost/oc-base:latest --home ~/sandbox-homes/oc-A
Child process initialized in 91.91 ms
distrobox create --name oc-B --image localhost/oc-base:latest --home ~/sandbox-homes/oc-B
(Prompt returns immediately)
distrobox create --name oc-C --image localhost/oc-base:latest --home ~/sandbox-homes/oc-C
</pre>
</pre>


'''Cause:''' This is a "Nest Isolation" conflict. Firejail is trying to create a sandbox inside a container that has already virtualized the system files.
== Isolation Coverage ==
'''Fix:''' Use the <code>--home</code> custom directory method (Part 4, Step 2). This creates a container where the ''entire'' home directory is separate, so you don't need Firejail to protect your files—they simply aren't there.


=== "WARN: failed to kill all processes / cgroup not exist" ===
{| class="wikitable"
When stopping a container, you may see this warning:
! Surface !! Isolated? !! Notes
|-
| Host home || ✅ Yes || Burner home via <code>--home</code>
|-
| Host filesystem || ⚠️ Partial || Read-write by default; add <code>--additional-flags</code> for read-only mounts
|-
| System packages || ✅ Yes || Overlay filesystem isolation
|-
| Network || ❌ No || Shares host network (API access required)
|-
| Kernel || ❌ No || Rootless containers share kernel
|-
| Display || ❌ No || GUI renders on host
|}


<pre>
== Troubleshooting ==
WARN[0000] failed to kill all processes... error="cgroup not exist"
opencode-burner
</pre>


'''Verdict:''' It worked. This is a common warning in rootless containers where Distrobox cannot access system-level cgroups to force-kill background processes. The container name printed on the last line confirms it stopped successfully.
* '''Mount failures:''' Use <code>--home</code> custom directory; avoid nested Firejail
* '''cgroup warnings:''' Expected in rootless containers; operation succeeds despite messages
* '''Command separation required:''' Run <code>mkdir</code> and <code>distrobox create</code> as separate commands; combining them can fail silently
* '''$HOME path issue:''' Inside <code>--home</code> containers, <code>$HOME</code> resolves to the burner directory; use absolute paths in scripts
* '''Firejail incompatibility:''' Fails with <code>--home</code> due to whitelist mode blocking Node.js dependencies; use Distrobox isolation alone


== See Also ==
== Prerequisites ==


* [[Claude_Code_Isolation_and_Burner_Workflow_260211]] — Claude Code version of this workflow with Firejail
* Linux host (Fedora, Ubuntu, Arch, etc.)
* [[Creating_a_Distrobox_from_a_Golden_Image]] — Detailed golden image reference
* Distrobox installed
* Podman installed
* OpenCode account / API key configured

Revision as of 15:55, 23 February 2026

OpenCode Isolation and Burner Workflow

This workflow uses Distrobox containers to run OpenCode in isolated environments. Key concepts:

  • Each project runs in its own persistent container
  • Save points capture container state as images
  • A "golden image" serves as a template for new containers
  • Containers are deleted on your schedule

Protection mechanism: Malicious prompt injection damage remains confined to the container, not affecting the host system.

Hardware Reality

You need at least 32k Context for a usable agent.

VRAM GPU Example Context Window
8GB RX 7600 8k–16k (unstable at 32k)
16GB RX 9070 XT Tight; requires custom config
20GB RX 7900 XT Sweet spot; 64k–80k
32GB+ 128k+

Workstation unified memory (Ryzen AI Max+, Mac Studio) supports large models but at slower inference speeds.

Recommended models: Qwen2.5-Coder-7B through Qwen2.5-Coder-14B; alternative: DeepSeek V3 API (~₱7.80/million tokens).

Core Naming Convention

Type Format Example
Working container PREFIX-YYMMDD oc-260216
Saved image localhost/PREFIX-YYMMDD:latest localhost/oc-260216:latest
Golden image localhost/PREFIX-base:latest localhost/oc-base:latest
Burner home ~/sandbox-homes/PREFIX-YYMMDD ~/sandbox-homes/oc-260216

One-Time Setup: Golden Image Creation

Step 1: Install Distrobox (on host)

sudo apt install distrobox    # Debian/Ubuntu
sudo dnf install distrobox    # Fedora
yay -S distrobox              # Arch

Step 2: Create and enter base container

mkdir -p ~/sandbox-homes/oc-base
distrobox create --name oc-base --image ubuntu:24.04 --home ~/sandbox-homes/oc-base
distrobox enter oc-base

Step 3: Install dependencies (inside container)

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs git python3
npm install -g opencode-ai
opencode  # Complete authentication / API key setup

Step 4: Add launcher script (inside container)

Create ~/project/opencode_isolation.sh:

#!/bin/bash
# Launcher for OpenCode inside Distrobox container

WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
# WORK_DIR="/home/USER/your-project-directory"   # uncomment for hardcoded path

cd "$WORK_DIR"

echo "Starting OpenCode..."
echo "  Working directory: $WORK_DIR"
echo ""

exec opencode "$@"

Make executable: chmod +x ~/project/opencode_isolation.sh

Step 5: Commit golden image (on host)

exit  # Leave container
distrobox stop oc-base
podman container commit oc-base localhost/oc-base:latest
podman image ls  # Verify

GitHub Burner Identity

Create a separate GitHub account exclusively for agent work. Generate Personal Access Tokens (90-day expiration) scoped to repo and workflow permissions rather than sharing primary credentials.

Daily Workflow Procedures

Starting a New Container

[HOST]      mkdir -p ~/sandbox-homes/oc-260216
[HOST]      distrobox create --name oc-260216 --image localhost/oc-base:latest --home ~/sandbox-homes/oc-260216
[HOST]      distrobox enter oc-260216
[DISTROBOX] cd ~/project && ./opencode_isolation.sh

Continuing an Existing Container

[HOST]      distrobox enter oc-260216
[DISTROBOX] cd ~/project && ./opencode_isolation.sh

Saving a Checkpoint

[HOST] distrobox stop oc-260216
[HOST] podman container commit oc-260216 localhost/oc-260216:latest
[HOST] distrobox enter oc-260216  # Resume work

Branching from a Save Point

mkdir -p ~/sandbox-homes/oc-260217
distrobox create --name oc-260217 --image localhost/oc-260216:latest --home ~/sandbox-homes/oc-260217
distrobox enter oc-260217

Restoring from a Checkpoint

[HOST] distrobox rm oc-260217 && rm -rf ~/sandbox-homes/oc-260217
[HOST] mkdir -p ~/sandbox-homes/oc-260217
[HOST] distrobox create --name oc-260217 --image localhost/oc-260216:latest --home ~/sandbox-homes/oc-260217

Promoting a Container to Golden Image

[HOST] distrobox stop oc-260216
[HOST] podman container commit oc-260216 localhost/oc-base:latest

Cleanup Commands

podman image ls              # List all images
podman image rm localhost/oc-260216:latest
podman ps -a                 # List containers
distrobox rm oc-260216 && rm -rf ~/sandbox-homes/oc-260216

Parallel Sessions

Clone the golden image into multiple independent containers simultaneously:

distrobox create --name oc-A --image localhost/oc-base:latest --home ~/sandbox-homes/oc-A
distrobox create --name oc-B --image localhost/oc-base:latest --home ~/sandbox-homes/oc-B
distrobox create --name oc-C --image localhost/oc-base:latest --home ~/sandbox-homes/oc-C

Isolation Coverage

Surface Isolated? Notes
Host home ✅ Yes Burner home via --home
Host filesystem ⚠️ Partial Read-write by default; add --additional-flags for read-only mounts
System packages ✅ Yes Overlay filesystem isolation
Network ❌ No Shares host network (API access required)
Kernel ❌ No Rootless containers share kernel
Display ❌ No GUI renders on host

Troubleshooting

  • Mount failures: Use --home custom directory; avoid nested Firejail
  • cgroup warnings: Expected in rootless containers; operation succeeds despite messages
  • Command separation required: Run mkdir and distrobox create as separate commands; combining them can fail silently
  • $HOME path issue: Inside --home containers, $HOME resolves to the burner directory; use absolute paths in scripts
  • Firejail incompatibility: Fails with --home due to whitelist mode blocking Node.js dependencies; use Distrobox isolation alone

Prerequisites

  • Linux host (Fedora, Ubuntu, Arch, etc.)
  • Distrobox installed
  • Podman installed
  • OpenCode account / API key configured