|
|
| 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 |
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
[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