I’ve been experimenting with agentic development since 2024 and documenting lessons learned while building BattleTabs. This post is part of an ongoing series about the project.
Initial Friction with Direct Machine Setup
When I first used Claude Code for BattleTabs, running it directly on my machine created recurring friction. Each session required ensuring the correct Node version was active, Docker was running, and the database was operational. Additionally, Claude needed approval for every command — installing dependencies, running test suites, or generating Prisma types. It adds up fast.
The Devcontainer Solution
Moving to a devcontainer eliminated this friction. A devcontainer functions as an isolated virtual environment pre-loaded with project-specific tools. Because it’s isolated from the host machine, Claude can operate freely without permission prompts. The container is the sandbox.
Instead of monitoring every command, the workflow becomes task-focused. Claude identifies necessary steps, executes them, encounters errors, fixes them, and continues — all autonomously.
Launcher Script: ./dev
A launcher script streamlines the process:
./dev # Start Claude Code (creates or reuses container)
./dev # Second instance — execs into same container, instant
./dev rm # Fresh start when needed
./dev status # How many instances are running?
The script checks Docker and database status, rebuilds container images when the Dockerfile changes, and launches Claude Code with --dangerously-skip-permissions. The container persists between sessions, allowing multiple Claude instances to share the same node_modules and database.
Dockerfile Configuration
The Dockerfile installs Claude Code directly into the image, eliminating startup installation steps. It also includes Chromium and a virtual display server for automated browser testing, enabling screenshots without GPU or physical display requirements.
Git Worktrees for Parallel Work
Since BattleTabs is a monorepo, I combined devcontainers with git worktrees to enable simultaneous work on multiple features:
/workspaces/battletabs # main checkout
/workspaces/battletabs-feature-a # worktree for feature A
/workspaces/battletabs-feature-b # worktree for feature B
Each worktree functions as an independent checkout with its own branch, allowing separate Claude sessions to work in parallel without interfering with each other.
File Sharing with Containers
Sharing files with containerised Claude required a creative solution. Running npx serve on the host machine creates a file server:
# On your host machine
npx serve ~/Downloads -p 3001
# Claude (inside the container) can now fetch:
# http://host.docker.internal:3001/screenshot.png
This enables showing Claude visual context directly rather than attempting textual descriptions. While Claude’s web tools sometimes struggle with host.docker.internal URLs, curl consistently works for file retrieval.
Development Workflow
BattleTabs runs on a fixed local port inside the container, accessible from the host browser. Hot reload provides near-instant feedback. The workflow cycle becomes: Claude codes, I test, screenshots capture the result, Claude fetches the image and adjusts accordingly.
Conclusion
Initial devcontainer setup required effort, but it has become essential for starting new projects. The approach transforms agent-driven development from permission-heavy and environment-dependent work into autonomous, focused task completion.