yaml
title: “Ouijit: Git Worktrees as Agent Sandboxes” description: “How a terminal manager uses Git worktrees for task isolation instead of containers, with lifecycle hooks that trigger scripts on kanban state changes.” pubDate: 2026-05-31T20:06:42.348890Z category: dev-tools heroImage: https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&w=1600&q=80 sourceUrl: https://ouijit.com/ sourceName: ouijit.com tags:
- agentic-ai
- orchestration
- infrastructure featured: false
Ouijit is a terminal session manager built for agent workflows. Instead of spinning up Docker containers or VMs for task isolation, it uses Git worktrees. Each task gets its own filesystem view and working directory, agents interact through a CLI exposed in every session, and lifecycle hooks fire shell scripts when tasks move across kanban columns.
The design targets Claude, Codex, and Pi agents out of the box. The developer reported an 8-hour work session, which suggests the isolation model holds up under real use.
Why Git Worktrees Instead of Containers
Git worktrees let you check out multiple branches simultaneously in separate directories. Each worktree shares the same .git repository but maintains its own working tree, index, and HEAD.
For agent task isolation, this means:
- Filesystem separation: Agent A working on
feature/authsees only files in that worktree. Agent B onbugfix/paymentsees a different directory tree. - No kernel overhead: Worktrees are just directories. No cgroups, namespaces, or image layers.
- Instant teardown: Deleting a worktree is
rm -rf. No dangling volumes or network cleanup. - Shared object store: All worktrees reference the same Git objects, so disk usage stays linear with unique file changes, not task count.
Containers give you process isolation, network sandboxing, and resource limits. Worktrees give you filesystem isolation and branch-level state management. If your agent workflow is “run tests, edit files, commit changes,” worktrees are enough. If you need network isolation or untrusted code execution, you need something heavier.
Ouijit offers optional Lima VM sandboxing for the latter case, but the default mode is worktree-only.
Architecture: CLI, Kanban, and Hooks
Every terminal session in Ouijit has access to the ouijit CLI. Agents discover commands through their system prompt or tool definitions. The CLI exposes:
ouijit task spawn <description>: Creates a task, checks out a new worktree, and opens a session.ouijit task move <task-id> <column>: Moves a task on the kanban board (e.g., “todo” → “in progress”).ouijit task list: Returns JSON or table output of all tasks.
The kanban board is a persistent data structure (likely SQLite or JSON file, though the source doesn’t specify). Each column can have lifecycle hooks defined as shell scripts:
# .ouijit/hooks/in-progress.sh
#!/bin/bash
# Runs when any task moves to "in progress"
TASK_ID=$1
TASK_TITLE=$2
WORKTREE_PATH=$3
cd "$WORKTREE_PATH"
npm install
npm run dev &
echo "Dev server started for $TASK_TITLE"
Hooks receive task metadata as arguments. They run in the context of the worktree, so they can start dev servers, run migrations, or trigger CI pipelines.
State Management and Uncommitted Changes
When an agent moves a task between columns while the worktree has uncommitted changes, Git’s normal rules apply:
- The worktree stays dirty.
- The hook script can inspect
git statusand decide whether to proceed. - If you move a task to “done” with uncommitted work, the hook can enforce a commit or block the transition.
Ouijit doesn’t abstract Git semantics. If you want to enforce clean states, you write that logic in the hook. This keeps the tool simple but pushes policy decisions to the user.
Agent Integration Surface
Supported agents (Claude, Codex, Pi) interact with Ouijit through:
- CLI tool calls: The agent invokes
ouijit task spawnorouijit task moveas shell commands. - Session awareness: Each terminal session knows which task it belongs to. The agent can query
ouijit task currentto get context. - Status indicators: Ouijit tracks agent working/idle state and can trigger desktop notifications or sounds when an agent finishes a task.
The agent doesn’t need special Ouijit-specific training. If it can call shell commands and parse JSON output, it can drive the workflow.
Lima VM Sandboxing
For untrusted code or network isolation, Ouijit supports Lima (Linux virtual machines on macOS). The integration is optional. When enabled:
- Each task can run in its own Lima VM instance, or tasks can share a single VM.
- The worktree is mounted into the VM via 9p or virtiofs.
- The
ouijitCLI still works inside the VM, so agents see the same interface.
This adds startup latency (VM boot time) and memory overhead (one or more Linux kernels). The trade-off table:
| Isolation Mode | Startup Time | Memory Overhead | Filesystem Isolation | Process Isolation | Network Isolation |
|---|---|---|---|---|---|
| Worktree-only | <100ms | ~0 MB | Yes | No | No |
| Shared Lima VM | ~5s (first) | ~512 MB | Yes | Yes | Yes |
| Per-task VM | ~5s (each) | ~512 MB × tasks | Yes | Yes | Yes |
Most agent workflows don’t need VMs. Use them when you’re running third-party code, testing network configurations, or need reproducible Linux environments on macOS.
Observability and Failure Modes
Ouijit exposes agent status (working/idle) and can trigger notifications. This is useful for long-running tasks where you want to know when the agent is blocked or finished.
Likely failure modes:
- Worktree conflicts: If two agents try to spawn tasks from the same branch, Git will complain. The CLI should return an error, but the agent needs to handle it.
- Hook script failures: If a lifecycle hook exits non-zero, does Ouijit block the state transition or log and continue? The docs don’t specify. Assume it logs and continues unless you add explicit guards.
- Disk space: Worktrees share objects, but each working tree still consumes disk. A hundred tasks with large
node_modulesdirectories will fill your drive. - Stale sessions: If an agent crashes mid-task, the worktree and session persist. You need manual cleanup or a garbage collection hook.
Technical Verdict
Use Ouijit when:
- You want lightweight task isolation without container overhead.
- Your agents primarily edit files, run tests, and commit code.
- You need lifecycle hooks to automate dev server startup, migrations, or notifications.
- You’re comfortable writing shell scripts for workflow automation.
Avoid Ouijit when:
- You need process or network isolation (use containers or VMs directly).
- Your workflow involves complex multi-agent orchestration with shared state (use a proper orchestrator like Temporal or Prefect).
- You need fine-grained resource limits or security boundaries (worktrees don’t enforce CPU/memory caps).
- You want a GUI-first tool (Ouijit is CLI and TUI only).
The worktree model is clever for file-based workflows. It’s not a replacement for container orchestration, but it’s a useful middle ground when you need isolation without the weight.