This repo holds configuration details for coding agents. It is primarily intended for us with OpenCode, but it can easily be adapted for other harnesses.
To run an autonomous coding loop, carry out the following steps:
- Give your request to the planning agent and answer any follow up questions
opencode run --agent="planner" "Write a plan to implement a flappy bird game that can be played on the browser"- Invoke the build-test-review loop to carry out the plan:
bash loops/build_test_review_loop.shCoding loops are designed to act autonomously, completing a task and reporting back to a human rather than asking a human's permission at every step. While this ia enourmously powerful and very productive, it introduces the risk of unexpected commands being issued and critical files being accessed and modified. It is therefore advisable to run the coding loop in a container, which imposes OS-level restrictions on the files that the agents can access.
- MacOS 12+
- homebrew
- an account with a coding assistant provider (if using a proprietary assistant)
- These instructions are intended as a general guide, not a rigorous specification. Details may differ depending on your OS or hardware.
- This sandbox setup allows access to the internet, so you still need to supervise your assistant.
- The functions below are working examples only, they are not recommendations of best security practice. You are responsible for deciding what implementation gives you an appropriate balance of security and functionality.
The following steps only need to be carried out the first time you set up your sandbox.
We use Podman because it doesn't require root privileges. To install it on MacOS, type into terminal:
brew install podmanThen create the lightweight Linux VM that will host your containers:
podman machine initFinally, create an image for the container that contains the coding agent and its dependencies:
podman build --no-cache -t localhost/opencode-base ~/coding_sandbox/Add this to your shell config file (.bashrc or .zshrc):
opencode_loop_sandboxed() {
# Require at least the target directory and the script to run
if [ "$#" -lt 2 ]; then
echo "Usage: opencode_loop_sandboxed <target_dir> <script_path_relative_to_target> [args...]"
return 1
fi
local target_dir="$1"
shift
# 1. Ensure the sandbox layout exists
mkdir -p "$HOME/.ai-sandbox-home/.local/bin"
mkdir -p "$HOME/.ai-sandbox-home/.local/share/opencode"
mkdir -p "$HOME/.ai-sandbox-home/.opencode"
chmod 700 "$HOME/.ai-sandbox-home/.local/share/opencode"
chmod 700 "$HOME/.ai-sandbox-home/.opencode"
chmod 700 "$HOME/.ai-sandbox-home/.opencode/agents"
# 2. Mirror the host OpenCode config/auth into the sandbox before starting
local OPENCODE_CONFIG_SRC="${OPENCODE_CONFIG_SRC:-$HOME/.config/opencode/opencode.jsonc}"
local OPENCODE_SANDBOX_CONFIG="${OPENCODE_SANDBOX_CONFIG:-$HOME/.ai-sandbox-home/.opencode/opencode.jsonc}"
local OPENCODE_AUTH_SRC="${OPENCODE_AUTH_SRC:-$HOME/.local/share/opencode/auth.json}"
local OPENCODE_SANDBOX_AUTH="${OPENCODE_SANDBOX_AUTH:-$HOME/.ai-sandbox-home/.local/share/opencode/auth.json}"
local OPENCODE_AGENTS_SRC="${OPENCODE_AGENTS_SRC:-$HOME/.config/opencode/agents}"
local OPENCODE_SANDBOX_AGENTS="${OPENCODE_SANDBOX_AGENTS:-$HOME/.ai-sandbox-home/.opencode/agents}"
if [ ! -f "$OPENCODE_CONFIG_SRC" ]; then
printf 'Host opencode config not present at %s, skipping copy.\n' "$OPENCODE_CONFIG_SRC" >&2
else
mkdir -p "$(dirname "$OPENCODE_SANDBOX_CONFIG")"
if [ -f "$OPENCODE_SANDBOX_CONFIG" ] && cmp -s "$OPENCODE_CONFIG_SRC" "$OPENCODE_SANDBOX_CONFIG"; then
chmod 600 "$OPENCODE_SANDBOX_CONFIG"
printf 'Sandbox opencode config already up to date (%s).\n' "$OPENCODE_SANDBOX_CONFIG" >&2
else
cp "$OPENCODE_CONFIG_SRC" "$OPENCODE_SANDBOX_CONFIG"
chmod 600 "$OPENCODE_SANDBOX_CONFIG"
printf 'Copied host opencode config into sandbox (%s).\n' "$OPENCODE_SANDBOX_CONFIG" >&2
fi
fi
if [ ! -f "$OPENCODE_AUTH_SRC" ]; then
printf 'Host opencode auth file not present at %s, skipping copy.\n' "$OPENCODE_AUTH_SRC" >&2
else
mkdir -p "$(dirname "$OPENCODE_SANDBOX_AUTH")"
if [ -f "$OPENCODE_SANDBOX_AUTH" ] && cmp -s "$OPENCODE_AUTH_SRC" "$OPENCODE_SANDBOX_AUTH"; then
chmod 600 "$OPENCODE_SANDBOX_AUTH"
printf 'Sandbox opencode auth file already up to date (%s).\n' "$OPENCODE_SANDBOX_AUTH" >&2
else
cp "$OPENCODE_AUTH_SRC" "$OPENCODE_SANDBOX_AUTH"
chmod 600 "$OPENCODE_SANDBOX_AUTH"
printf 'Copied host opencode auth file into sandbox (%s).\n' "$OPENCODE_SANDBOX_AUTH" >&2
fi
fi
if [ ! -d "$OPENCODE_AGENTS_SRC" ]; then
printf 'Host opencode agents dir not present at %s, skipping copy.\n' "$OPENCODE_AGENTS_SRC" >&2
else
mkdir -p "$OPENCODE_SANDBOX_AGENTS"
if command -v rsync >/dev/null 2>&1; then
rsync -a --delete "$OPENCODE_AGENTS_SRC"/ "$OPENCODE_SANDBOX_AGENTS"/
else
rm -rf "$OPENCODE_SANDBOX_AGENTS"
mkdir -p "$OPENCODE_SANDBOX_AGENTS"
cp -r "$OPENCODE_AGENTS_SRC"/. "$OPENCODE_SANDBOX_AGENTS"/
fi
find "$OPENCODE_SANDBOX_AGENTS" -type d -exec chmod 700 {} +
find "$OPENCODE_SANDBOX_AGENTS" -type f -exec chmod 600 {} +
printf 'Mirrored host opencode agents into sandbox (%s).\n' "$OPENCODE_SANDBOX_AGENTS" >&2
fi
echo "Starting bash sandbox for directory: $target_dir"
# 3. Run the container with a bash entrypoint
# "$@" now represents the script name and any arguments you pass
podman run --rm -it \
--entrypoint /bin/bash \
-v "$HOME/.ai-sandbox-home:/root:Z" \
-v "$(realpath "$target_dir"):/workspace:Z" \
-w "/workspace" \
localhost/opencode-base "$@"
}Having completed the Initial Setup procedure outlined above, the following steps need to be run each time you start up your computer.
To start the VM, run:
podman machine startAnd check that it has launched successfully by running:
podman infoOnce the podman VM is running, launch the loop with:
opencode_loop_sandboxed /path/to/your/project ./loops/build_test_review_loop.shIf you are using OpenCode, there are two files that you need to modify to ensure that OpenCode can run: auth.json and opencode.jsonc.
This file holds your API keys and metadata for your model deployments. On MacOS it can be found at:
~/.local/share/opencode/auth.json
Each cloud platform has a separate entry, with common variable names across the entries.
For example, if you want to access models deployed on Azure Foundry and AWS Bedrock, your auth.json will look like this:
{
"azure": {
"type": "api",
"key": "replace-with-your-Azure-Foundry-api-key",
"metadata": {
"resourceName": "replace-with-your-Azure-resource-name"
}
},
"amazon-bedrock": {
"type": "api",
"key": "replace-with-your-AWS-Bedrock-key"
}
}This file holds metadata about your cloud platforms and specifications for agents. On MacOS it can be found at:
~/.config/opencode/opencode.jsonc
This file allows you to specify different models for each agent. For example, if you want your build agent to use gpt-5.3-codex deployed on Azure Foundry, and your reviewer agent to use Claude Sonnet 5 deployed on AWS Bedrock, your opencode.jsonc will look like this:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"azure": {
"options": {
"resourceName": "replace-with-your-Azure-resource-name"
}
},
"amazon-bedrock": {
"options": {
"region": "replace-with-your-AWS-region"
}
}
},
"agent": {
"builder": {
"mode": "primary",
"model": "azure/gpt-5.3-codex",
"prompt": "You are the build engineer. Your primary task is to write source code to implement features.",
"permission": {
"bash": {
"git push": "deny",
"git commit": "deny"
}
}
},
"reviewer": {
"mode": "primary",
"model": "amazon-bedrock/anthropic.claude-sonnet-5",
"prompt": "You are the review agent. Your primary task is to review code.",
"permission": {
"edit": "deny"
}
}
}
}