Camps
Isolated git worktrees, pooled per project and reused only when safe.
A camp is the git worktree a soldier works in. It has its own checkout and its own branch, so a soldier can edit, commit and run tests without touching your working tree, and several soldiers never step on each other.
Where camps live
Camps are pooled per project, under that project's state directory:
~/.vexillum/projects/<repo>-<hash>/camps/
pool.json which slots exist, and which task holds each
1/<repo>/ a worktree
2/<repo>/Each camp's branch is vexillum/<task-id>, forked from the branch your project had checked out when the task was dispatched (recorded as the task's base).
Acquire and reuse
A new task takes an idle, clean, already-landed slot from the pool when one exists, resetting it to a fresh branch. Otherwise vexillum creates a new worktree and slot. Slot assignment is serialized with a lock, so two simultaneous dispatches never get the same slot.
Strike
Striking a camp (dismantling it) returns it to the pool, and only when it is safe to reuse: the worktree has no uncommitted changes and, for a mission, its commits are already on the base branch. vx strike <task-id> enforces this and refuses otherwise. A scout is also gated on its report existing; --force skips only that report check, never the clean-and-landed check. For a shipped mission, vx strike also asks gh (best effort, never required) whether the pull request merged, and trusts a merge whose commit is on the local base. --discard is the explicit escape hatch for a camp whose work the general confirmed is already on the base or abandoned: it strikes anyway and prints what it threw away. After a successful strike it also deletes the task's local branch when that is safe (an ancestor of the base, or a merged pull request on a pulled base, never -D, never a branch checked out elsewhere) and runs git worktree prune. See How it ends.
vx land strikes the camp for you after a successful local fast-forward. A shipped mission is the exception: its pull request is the source of truth, so its camp stays open on purpose until you merge the PR, then git pull and vx strike <task-id>. See Why a shipped soldier stays open.
Run vexillum from the project root
vexillum refuses to run from inside a camp (any path under ~/.vexillum). A second dispatch from there would create a separate pool keyed on the camp's own path, invisible to every later command.