Git Worktrees
Git worktrees let you have multiple working directories from the same repository. Hubcode uses them to run agents in isolated branches without switching contexts.
Why worktrees?
Without worktrees, running multiple agents on the same repo means they share the working directory. One agent's changes interfere with another's. You can't safely run parallel tasks.
With worktrees, each agent gets its own directory and branch. They can work simultaneously without conflict. When an agent finishes, you review the diff, merge the branch, and archive the worktree.
Directory structure
Hubcode creates worktrees under $HUBCODE_HOME/worktrees/, organized by a short hash of the source checkout path:
~/.hubcode/worktrees/
├── 1vnnm9k3/
│ ├── tidy-fox/ # random slug
│ └── bold-owl/ # random slug
└── 4k8q2d1p/
└── swift-hare/ # random slugThe hash avoids collisions between repositories that share the same directory or remote name. Worktree directory names are random slugs — the branch name is separate and chosen when you first launch an agent in the worktree.
Branches
When you create a worktree, Hubcode generates a random directory name. The branch name is set when you first launch an agent — Hubcode generates one automatically.
This means the worktree directory and branch are independent. You can rename the branch later without affecting the worktree path.
Multiple agents per worktree
You can launch multiple agents into the same worktree. They share the working directory and branch, which is useful when you want agents to collaborate on the same feature or when one agent hands off to another.
Be mindful of conflicts — agents working on the same files simultaneously can step on each other. This works best when agents have distinct responsibilities or run sequentially.
Lifecycle hooks with hubcode.json
When Hubcode creates a worktree, it's a fresh checkout. Dependencies aren't installed, config files aren't copied. You can automate setup by creating a hubcode.json file in your repository root:
{
"worktree": {
"setup": [
"npm ci",
"cp \"$HUBCODE_SOURCE_CHECKOUT_PATH/.env\" \"$HUBCODE_WORKTREE_PATH/.env\""
]
}
}The setup array contains shell commands that run after the worktree is created. Use it to install dependencies, copy local config files, or run any other initialization.
You can also add a teardown array for cleanup commands that run before Hubcode removes the worktree directory during archive:
{
"worktree": {
"teardown": [
"pkill -f \"vite --port $HUBCODE_WORKTREE_PORT\" || true",
"rm -rf \"$HUBCODE_WORKTREE_PATH/.cache\""
]
}
}hubcode.json in the selected base branch. If you pick main, Hubcode reads the committed file on main. Local or uncommitted changes in another branch are not used for that worktree.Environment variables
Setup and teardown commands have access to these environment variables:
$HUBCODE_SOURCE_CHECKOUT_PATH— your source checkout path (original repository root)$HUBCODE_ROOT_PATH— legacy alias of$HUBCODE_SOURCE_CHECKOUT_PATH$HUBCODE_WORKTREE_PATH— the new worktree directory$HUBCODE_BRANCH_NAME— the branch name created$HUBCODE_WORKTREE_PORT— the worktree port, when runtime metadata exists
Use $HUBCODE_SOURCE_CHECKOUT_PATH to copy files that shouldn't be in git (like .env) from your source checkout to the worktree.
$HUBCODE_WORKTREE_PORT is available when the worktree was bootstrapped with a port. That makes it useful for both starting services in setup and stopping them again in teardown.
Teardown
Teardown runs during archive, before Hubcode removes the worktree directory. Use it for cleanup that needs access to the worktree path or its assigned port.
Common uses include stopping dev servers on $HUBCODE_WORKTREE_PORT, deleting generated files, or deregistering services tied to that worktree.
{
"worktree": {
"setup": [
"npm ci",
"nohup npm run dev -- --port $HUBCODE_WORKTREE_PORT > \"$HUBCODE_WORKTREE_PATH/dev.log\" 2>&1 &"
],
"teardown": [
"pkill -f \"npm run dev -- --port $HUBCODE_WORKTREE_PORT\" || true",
"rm -f \"$HUBCODE_WORKTREE_PATH/dev.log\""
]
}
}Common patterns
Node.js / npm
{
"worktree": {
"setup": ["npm ci"]
}
}Python / Poetry
{
"worktree": {
"setup": ["poetry install"]
}
}Copy environment files
{
"worktree": {
"setup": [
"npm ci",
"cp \"$HUBCODE_SOURCE_CHECKOUT_PATH/.env\" \"$HUBCODE_WORKTREE_PATH/.env\"",
"cp \"$HUBCODE_SOURCE_CHECKOUT_PATH/.env.local\" \"$HUBCODE_WORKTREE_PATH/.env.local\""
]
}
}Run database migrations
{
"worktree": {
"setup": [
"npm ci",
"cp \"$HUBCODE_SOURCE_CHECKOUT_PATH/.env\" \"$HUBCODE_WORKTREE_PATH/.env\"",
"npm run db:migrate"
]
}
}Workflow
The typical workflow is:
- Create a worktree — Hubcode creates the directory and runs setup
- Launch an agent — Hubcode creates or assigns a branch
- Agent works in isolation — changes stay in its worktree
- Review the diff — compare against the base branch
- Merge or discard — if approved, merge the branch; otherwise archive
- Archive the worktree — cleans up the directory and optionally the branch
You can run multiple agents in different worktrees simultaneously. Each worktree has its own branch and working directory.
CLI reference
Create an agent in a new worktree:
hubcode run --worktree feature-auth --base main "implement auth"
List all worktrees:
hubcode worktree ls
Archive a worktree (stops agents, removes directory):
hubcode worktree archive feature-auth
Metadata
Hubcode stores metadata in each worktree's git directory to track the base branch. This is used for diff operations and to know what branch to merge into.
You don't need to manage this manually — Hubcode handles it when creating and archiving worktrees.