Skip to content

Divinci-AI/deploy-gate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

deploy-gate

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+

Install

git clone https://github.com/Divinci-AI/deploy-gate.git
cd deploy-gate
# optional: pip install -e .
./bin/deploy-gate show

Or add the clone to your PATH:

export PATH="$HOME/src/deploy-gate/bin:$PATH"

Quick start

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 stage

Disable (CI / intentional parallel ops):

DEPLOY_GATE=0 ./your-deploy.sh

Wire into your deploy script

GATE=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 success

Exit codes: 0 allow/ok · 2 DENY · 3 ALREADY_COVERED.

Agent hooks

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.

How coverage works

Conservative by design:

  1. Bulletin records git_sha + files_touched at start
  2. 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)
  3. 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/main

Bulletin location

Default: ~/.deploy-gate/bulletin/

export DEPLOY_BULLETIN_DIR=~/.omnigent/deploy-bulletin   # share with other tools

Stale in-flight entries (dead PID) are cleared automatically. On macOS, PermissionError from kill(pid, 0) is treated as alive (not stale).

Related work

  • CI locksgithub/lock, Actions concurrency, GitLab resource_group: binary mutex for pipelines.
  • Agent claims3stacks/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.

License

MIT © Divinci AI

About

Coverage-aware deploy bulletin for multi-agent laptops (Cursor / Claude / Hermes)

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages