Coverage-aware deploy bulletin for multi-agent laptops.
When Cursor, Claude Code, Hermes, and friends share one machine, they will
happily burn 15 minutes each shipping the same staging surface. CI deploy
locks solve this for pipelines. Agent bulletin boards (bb, etc.) solve
checkout fights. deploy-gate sits in between:
| Situation | Result |
|---|---|
| Same target in-flight, your HEAD is not covered | DENY — read the bulletin, wait |
| Same target, your HEAD is covered (SHA ancestry + files) | ALREADY_COVERED — skip; don't redeploy |
| Clear / holder PID gone | ALLOW — write bulletin, deploy, finish |
MIT · zero dependencies · Python 3.10+
git clone https://github.com/Divinci-AI/deploy-gate.git
cd deploy-gate
# optional: pip install -e .
./bin/deploy-gate showOr add the clone to your PATH:
export PATH="$HOME/src/deploy-gate/bin:$PATH"Wrap a deploy:
./examples/wrap-deploy.sh -- wrangler deploy --env staging
# or wire start/finish into your own script (see below)Inspect / check:
deploy-gate show
deploy-gate check -- ./scripts/deploy-web-client.sh stageDisable (CI / intentional parallel ops):
DEPLOY_GATE=0 ./your-deploy.shGATE=deploy-gate # or absolute path to bin/deploy-gate
_deploy_gate_finish() {
local status="${1:-failed}"
"$GATE" finish --status "$status" -- ./my-deploy.sh "$@" >/dev/null 2>&1 || true
}
set +e
"$GATE" start -- ./my-deploy.sh "$@"
rc=$?
set -e
[ "$rc" = "3" ] && echo "ALREADY_COVERED — skip" && exit 0
[ "$rc" != "0" ] && exit "$rc"
trap '_deploy_gate_finish failed' EXIT
# … your real deploy …
trap - EXIT
_deploy_gate_finish successExit codes: 0 allow/ok · 2 DENY · 3 ALREADY_COVERED.
Point your agent harness at hooks/agent-hook.py (absolute path). Examples:
- Cursor —
examples/cursor-hooks.json→.cursor/hooks.json(beforeShellExecution) - Claude Code —
examples/claude-hooks.json→.claude/hooks.json(PreToolUse/ Bash) - Hermes —
examples/hermes-hooks.yaml→~/.hermes/config.yaml
The hook DENYs both hard conflicts and ALREADY_COVERED skips so the agent reads the bulletin instead of starting a redundant deploy.
Conservative by design:
- Bulletin records
git_sha+files_touchedatstart - A later agent is covered only if:
- neither tree is dirty, and
- bulletin SHA is an ancestor of HEAD, and
- needed files ⊆ bulletin
files_touched(or no file delta)
- Dirty trees never auto-skip
Base refs for the file diff default to origin/main, origin/master,
origin/preview, … Override with:
export DEPLOY_GATE_BASE_REFS=origin/preview,origin/mainDefault: ~/.deploy-gate/bulletin/
export DEPLOY_BULLETIN_DIR=~/.omnigent/deploy-bulletin # share with other toolsStale in-flight entries (dead PID) are cleared automatically. On macOS,
PermissionError from kill(pid, 0) is treated as alive (not stale).
- CI locks —
github/lock, Actionsconcurrency, GitLabresource_group: binary mutex for pipelines. - Agent claims —
3stacks/bulletin-board(bb): directory/resource leases so agents don't clobber checkouts. - deploy-gate — deploy-target bulletin + coverage-aware skip.
Complementary, not competing: use bb for repo claims; use deploy-gate so
two agents don't both ship web-client:staging.
MIT © Divinci AI