Skip to content
Draft
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
51 changes: 51 additions & 0 deletions .opencode/commands/git-commit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
description: Review, document, and commit approved changes using Conventional Commits
agent: build
subtask: true
---

Commit the current approved changes using Conventional Commits.

Workflow:

1. Review `git status --short`.
2. Inspect the staged and unstaged diff for the files that will be committed.
3. Do not commit credentials, secrets, generated caches, local editor files, or unrelated changes.
4. If unrelated changes are present, ask the user whether to include or exclude them before committing.
5. If `CHANGELOG.md` already exists and the change is user-facing, update it before committing. Do not create a new changelog unless the user explicitly asks for one.
6. Read `WORKLOG.md` if it exists.
7. Run the smallest useful verification command available in the project. If no verification command exists, say that explicitly.
8. Append a concise entry to `WORKLOG.md` before committing.
9. Stage only approved files.
10. Use a concise Conventional Commit message, for example `feat: add sandbox commands` or `fix: preserve opencode home path`.
11. After committing, show the commit hash and final `git status --short`.

Use this exact timestamp command for the worklog:

```bash
TZ=Europe/Berlin date "+%d.%m.%Y, %H:%M (%Z)"
```

Append this shape to `WORKLOG.md`:

```markdown
---

## Commit: <short description>

**Status:** Done
**Date:** <timestamp>

### What Changed

- File: `<path>` — <specific changes included in the commit>

### Findings

- Verification: <command and result, or "No verification command available">
- Commit: `<hash>` <subject>

### Pending

- <remaining follow-up, or "None">
```
50 changes: 50 additions & 0 deletions .opencode/commands/refactor-apply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
description: Apply one approved refactor, verify it, and update WORKLOG.md
agent: build
subtask: true
---

Apply only the refactor requested in `$ARGUMENTS`.

If `$ARGUMENTS` is empty or the requested scope is unclear, ask the user to name the approved refactor before editing files.

Workflow:

1. Read `WORKLOG.md` if it exists.
2. Identify the smallest file/symbol scope needed for `$ARGUMENTS`.
3. Keep behavior unchanged.
4. Keep changes focused to the approved files or symbols.
5. Do not include unrelated cleanup.
6. Run the smallest useful verification command available in the project. If none exists, say that explicitly.
7. Append a concise entry to `WORKLOG.md` before finishing.
8. Summarize changed files and verification results.

Use this exact timestamp command for the worklog:

```bash
TZ=Europe/Berlin date "+%d.%m.%Y, %H:%M (%Z)"
```

Append this shape to `WORKLOG.md`:

```markdown
---

## Refactor: <short description>

**Status:** Done
**Date:** <timestamp>

### What Changed

- File: `<path>` — <specific changes>

### Findings

- <concrete findings or observations>
- Verification: <command and result, or "No verification command available">

### Pending

- <remaining follow-up, or "None">
```
20 changes: 20 additions & 0 deletions .opencode/commands/refactor-audit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
description: Audit refactor opportunities without editing files
agent: plan
subtask: true
---

Analyze the target given in `$ARGUMENTS` for code smells, duplicate code, unnecessary complexity, and technical debt.

If `$ARGUMENTS` is empty, inspect the current git diff first and then the smallest relevant surrounding files.

Do not edit files. Do not update `WORKLOG.md`; this is a read-only planning command unless the user explicitly asks you to document the audit.

Produce a concise audit with:

1. Findings ordered by impact
2. Exact files and symbols involved
3. Suggested refactor steps
4. Behavioral risks and verification needed
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security risks is missing


Ask the user which items should be implemented before making changes.
34 changes: 19 additions & 15 deletions .opencode/skills/write-worklog/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
---
name: write-worklog
description: Maintain a WORKLOG.md file in the project directory to track task progress, decisions, and outcomes. Use when completing tasks, making file changes, or working on multi-step project work.
description: Append structured WORKLOG.md entries for task progress, decisions, and outcomes. Use when a project requires a detailed worklog entry or the user asks for one.
---

# Write Worklog

Maintain a file called `WORKLOG.md` in the current project working directory at all times. This logs every task you complete, keeping context available for later sessions.
Append structured entries to `WORKLOG.md` in the current project working directory. This keeps concrete task context available for later sessions.

## Core rules

### Before starting a task

1. Read `WORKLOG.md` to understand prior context and what is still pending.
2. If the file does not exist, create it before doing anything else.
1. Read `WORKLOG.md` if it exists to understand prior context and pending work.
2. If the file does not exist, create it when a worklog entry is required.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"create it in the project directory"

i had that already, it created random entries in the "root dirs worklog" was fucking weird xD


### After completing a task

1. Append a new entry to `WORKLOG.md` immediately.
2. Do NOT proceed to the next task until the entry is written.
1. Append a new entry to `WORKLOG.md`.
2. Keep the entry concise and specific.

### Workflow checklist

Copy this checklist and track progress before moving on:
Use this checklist:

```
Worklog:
Expand All @@ -30,19 +30,25 @@ Worklog:
- [ ] Include files changed and exact lines modified
- [ ] Add concrete findings, not vague summaries
- [ ] List pending items
- [ ] Verify entry is written before continuing
- [ ] Verify entry is written
```

## Entry format

Each entry MUST include all of the following:

- Task heading (descriptive summary)
- **Status** and **Date** (DD.MM.YYYY, HH:MM - CET/CEZ, Europe/Berlin)
- **Status** and **Date** (DD.MM.YYYY, HH:MM - CET/CEST, Europe/Berlin)
- **What was done** (files changed, exact lines modified)
- **What was found** (issues, bugs, observations with concrete specifics)
- **Pending** (outstanding items or follow-ups)

For the timestamp, use:

```bash
TZ=Europe/Berlin date "+%d.%m.%Y, %H:%M (%Z)"
```

Use this structure:

```markdown
Expand All @@ -51,15 +57,15 @@ Use this structure:
## <task-description>

**Status:** Done | In Progress | Pending
**Date:** DD.MM.YYYY, HH:MM (CET/CEZ)
**Date:** DD.MM.YYYY, HH:MM (CET/CEST)

### What was done
### What Changed

- File: `path/to/file` — changed / created / removed
- Specific detail of what was modified
- Exact lines or sections if applicable

### What was found
### Findings

- Concrete issues, bugs, or observations
- Specific file paths and line numbers
Expand All @@ -70,9 +76,7 @@ Use this structure:
- Any blockers or follow-ups
```

## Do not
## Avoid

- Do NOT proceed to the next task without updating the worklog.
- Do NOT write vague summaries — include exact details.
- Do NOT skip entries, even for small tasks.
- Do NOT use relative time references without timestamps.
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM ubuntu:26.04@sha256:f3d28607ddd78734bb7f71f117f3c6706c666b8b76cbff7c9ff6e5718d46ff64

ARG ENABLE_NODEJS=true
ARG ENABLE_NODEJS=false
ARG ENABLE_PYTHON=false
ARG ENABLE_RUST=false
ARG PYTHON_VERSION=3.13
Expand All @@ -14,7 +14,7 @@ ENV DEBIAN_FRONTEND=noninteractive \
ENABLE_PYTHON=${ENABLE_PYTHON} \
ENABLE_RUST=${ENABLE_RUST} \
PYTHON_VERSION=${PYTHON_VERSION} \
# Pin tool data dirs explicitly — survives the HOME override in entrypoint.sh
# Pin tool data dirs explicitly so subprocesses find language toolchains reliably
CARGO_HOME=/home/opencode/.cargo \
RUSTUP_HOME=/home/opencode/.rustup \
# All user tool bins in PATH — inherited by every subprocess after exec gosu
Expand All @@ -27,6 +27,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
git \
gosu \
ripgrep \
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Baaaaaaaaaah

alphabetical order!

Heresy!

tzdata \
openssh-client \
&& apt-get autoremove -y \
&& apt-get clean \
Expand Down
54 changes: 36 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# A hardend Docker sandbox setup for opencode
# A hardened Docker sandbox setup for opencode

With OpenCode + vLLM (Gemma 4 26B MoE) configs
With OpenCode + vLLM local model configs
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name the model (qwen3.6-35b) is more descriptive for people cloning the repo, then hiding it inside the config inside a nested directory.


Run OpenCode as a sandboxed, hardenend non-root Docker container connected to a self-hosted vLLM inference server. No cloud API keys required.
Run OpenCode as a sandboxed, hardened non-root Docker container connected to a self-hosted vLLM inference server. No cloud API keys required.

---

## Table of Contents

- [A hardend Docker sandbox setup for opencode](#a-hardend-docker-sandbox-setup-for-opencode)
- [A hardened Docker sandbox setup for opencode](#a-hardened-docker-sandbox-setup-for-opencode)
- [Table of Contents](#table-of-contents)
- [Prerequisites](#prerequisites)
- [Directory Structure](#directory-structure)
Expand All @@ -22,6 +22,7 @@ Run OpenCode as a sandboxed, hardenend non-root Docker container connected to a
- [Security Notes](#security-notes)
- [Feature Toggles](#feature-toggles)
- [Using Tools and Skills](#using-tools-and-skills)
- [Commands](#commands)
- [Skills](#skills)


Expand All @@ -37,9 +38,9 @@ Verify your vLLM is reachable before starting:
curl http://10.0.0.13:8000/v1/models
```

You should see your model ID in the response (e.g. `gemma4-26b-a4b`).
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

You should see your model ID in the response (e.g. `qwen3.6-35b`).

Use the exact `"id"` value from the response — e.g. `gemma4-26b-a4b`.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Use the exact `"id"` value from the response — e.g. `qwen3.6-35b`.

**Finding your context size:**
The `max_model_len` field in the `/v1/models` response is your context limit. Use that value for `"context"`.
Expand All @@ -57,9 +58,10 @@ opencode-sandbox/
├── start.sh
├── config/
│ ├── opencode.json
│ ├── AGENTS.md ← global sandbox rules (mounted read-only)
│ └── auth.json ← provider auth tokens (mounted read-only)
├── data/ ← opencode session state, persisted across runs
├── .opencode/ ← skills and agent config (optional)
├── .opencode/ ← global sandbox commands and skills (mounted read-only)
└── workspace/ ← put your code projects here
```

Expand Down Expand Up @@ -88,7 +90,7 @@ Inside the TUI:

1. Press `/model` — your model should appear under your provider name with an orange dot
2. Type `hello, what model are you?` — the response should mention your model ID
3. Check the status bar at the bottom — it should show `Gemma 4 26B MoE · vLLM (Gemma4 local)`
3. Check the status bar at the bottom — it should show your configured model, for example `Qwen3.6 35B A3B · vLLM`
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice, the previous part should be named just like that.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean "Qwen3.6 35B A3B"

4. Check the right panel — `$0.00 spent` confirms no cloud API is being used

---
Expand All @@ -97,7 +99,7 @@ Inside the TUI:

### Working with files

Drop files into `./workspace/` on your host. They appear at `~/workspace/` inside the container. OpenCode operates within this directory and cannot access anything outside it.
Drop files into `./workspace/` on your host. They appear at `/home/opencode/workspace/` inside the container. OpenCode starts in this directory; the global config still lives under `/home/opencode/.config/opencode/`.

```bash
# Copy a project into the sandbox
Expand Down Expand Up @@ -146,7 +148,7 @@ If this fails, your vLLM IP is unreachable from the container. Use the actual ho

**Tool calling loops or model halts mid-task**

This is a known Gemma 4 behavior with agentic tool use. Mitigations:
Some local models can struggle with long agentic tool-use loops. Mitigations:

- Prefer **Ask mode** for questions and code review that don't require file editing
- For Build mode, give explicit step-by-step instructions rather than open-ended goals
Expand All @@ -165,7 +167,7 @@ The container starts as root to handle setup (creating the user, fixing file own
- **`cap_add: CHOWN, SETUID, SETGID, DAC_OVERRIDE`** — only the four capabilities the entrypoint actually needs for its setup phase are added back. Once `gosu` drops to the non-root user, the kernel automatically clears the effective capability set on the UID transition, and `no-new-privileges` blocks any path to reclaiming them.
- **`PUID` / `PGID`** — the in-container user is created at runtime with the same UID/GID as your host user. This ensures bind-mounted files in `./workspace` and `./data` have correct ownership on both sides of the mount.
- Bridge networking only — isolated from the host network
- Filesystem access limited to `./workspace` and `./data` on the host
- Writable filesystem access is limited to `./workspace` and `./data` on the host. Config, commands, skills, and auth are mounted read-only.

The model runs entirely on your local vLLM server. No data leaves your network.

Expand All @@ -187,18 +189,34 @@ docker compose build --build-arg ENABLE_PYTHON=true --build-arg PYTHON_VERSION=3
./start.sh --no-cache # rebuild with new toggles
```

All runtimes are installed at **build time** under the `opencode` user, so the container starts instantly with no network downloads at runtime. The tool binaries are on `PATH` and their data directories (`CARGO_HOME`, `RUSTUP_HOME`) are pinned via environment variables so they survive the `HOME` override that redirects opencode's session state to the mounted workspace.
All runtimes are installed at **build time** under the `opencode` user, so the container starts instantly with no language runtime downloads at startup. Base tooling includes `ripgrep` for OpenCode search tools and `tzdata` for correct Europe/Berlin timestamps. The tool binaries are on `PATH` and their data directories (`CARGO_HOME`, `RUSTUP_HOME`) are pinned via environment variables.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove "so they survive the HOME override that redirects opencode's session state to the mounted workspace."?


---

## Using Tools and Skills

### Commands

Sandbox-wide commands and skills are mounted globally:

```yaml
- ./config/AGENTS.md:/home/opencode/.config/opencode/AGENTS.md:ro
- ./.opencode/commands:/home/opencode/.config/opencode/commands:ro
- ./.opencode/skills:/home/opencode/.config/opencode/skills:ro
```

This makes the commands available regardless of which project under `./workspace/` you open. Project-specific commands, skills, and `AGENTS.md` files can still live inside the project directory.

`AGENTS.md` is intentionally short: it gives global orientation. Repeatable process requirements live directly in the commands, because local models follow concrete command workflows more reliably than broad standing instructions.

Available sandbox commands:

- `/refactor-audit <target>` — analyze refactor opportunities without editing files
- `/refactor-apply <approved scope>` — apply one focused approved refactor, verify it, and update `WORKLOG.md`
- `/git-commit` — review, document, and commit approved changes using Conventional Commits

### Skills

Skills a special capabilities for an Agent that tells him how to do things or how to handle tools.
They have a specific Format and a SKILL.md file is mandatory.
Read more about Skills here https://agentskills.io/home
Skills are reusable on-demand capabilities for an agent. They use one directory per skill with a mandatory `SKILL.md`.

You have 2 options to use them
- just copy over the `.opencode` folder into your workspace. Opencode will then recognize them
- just add them to the worklog example skill in the `compose.yml`
The included `write-worklog` skill provides a structured `WORKLOG.md` entry format for ad-hoc tasks. Command-driven workflows inline their own worklog format so they do not depend on automatic skill selection.
8 changes: 5 additions & 3 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ services:
volumes:
# Config files (read-only mounts)
- ./config/opencode.json:/home/opencode/.config/opencode/opencode.json:ro
- ./.opencode/skills/write-worklog/SKILL.md:/home/opencode/.config/opencode/skills/write-worklog/SKILL.md:ro
- ./config/auth.json:/home/opencode/.local/share/opencode/auth.json:ro
- ./config/AGENTS.md:/home/opencode/.config/opencode/AGENTS.md:ro
- ./.opencode/commands:/home/opencode/.config/opencode/commands:ro
- ./.opencode/skills:/home/opencode/.config/opencode/skills:ro
# Your project workspace (read-write so opencode can edit files)
- ./workspace:/home/opencode/workspace:rw
- ./data:/home/opencode/.local/share/opencode
- ./config/auth.json:/home/opencode/.local/share/opencode/auth.json:ro
# No network_mode: host — use bridge so container is isolated
# but can still reach your vLLM server via host IP
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- HOME=/home/opencode
- HOME=/home/opencode
Loading