Human-in-the-loop checkpoint for AI agent pipelines.
AI agents run fast. Sometimes too fast. gate pauses any script or pipeline and waits for a human decision before continuing.
⏸ GATE [gate-1710345600]
Deploy to production?
[a] approve [r] reject [s] skip
> _
curl -fsSL https://raw.githubusercontent.com/techtaek77/gate/main/install.sh | bashOr manually:
mkdir -p ~/.local/bin
curl -o ~/.local/bin/gate https://raw.githubusercontent.com/techtaek77/gate/main/gate.sh
chmod +x ~/.local/bin/gate
# Make sure ~/.local/bin is in your PATH
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc# Basic checkpoint
gate "Deploy to production?"
# Show context before asking
gate "Review AI changes" --context ./diff.md
# Timeout: auto-reject after 5 minutes
gate "Approve autoresearch result?" --timeout 5m --default reject
# Named gate (shows in log)
gate "QA passed?" --id qa-check
# Notify via Telegram when gate is waiting
gate "Deploy to prod?" --notify telegram --timeout 30m --default reject
# View decision history
gate log
# Clear log
gate cleargate returns exit codes your pipeline can use:
| Decision | Exit code |
|---|---|
| approve | 0 |
| skip | 0 |
| reject | 1 |
| timeout (fail) | 1 |
| timeout (approve) | 0 |
#!/usr/bin/env bash
# AI pipeline with human checkpoint
run_ai_agent "analyze codebase" > result.md
gate "Review analysis before applying changes?" --context result.md \
|| { echo "Rejected. Stopping."; exit 1; }
apply_changes# autoresearch produces a candidate
@autoresearch-loop .claude/agents/foo.md design quality
# gate pauses the pipeline
gate "autoresearch done — keep candidate?" \
--context .claude/temp/autoresearch/foo/result.md \
--timeout 30m --default reject
# only runs if approved
@builder-quality-check
@agent-opsNote: GitHub Actions runners have no interactive TTY.
gatewill immediately timeout onread. Always use--defaultto set the fallback behavior explicitly.
- name: Gate — approve deploy
run: gate "Deploy to prod?" --timeout 10m --default reject
env:
GATE_LOG: /tmp/gate.log
# Result: always rejects (no TTY). Use this pattern only when --default approve is acceptable,
# or pair with `gate remote` (roadmap) for real async approval.gate is designed for local interactive terminals. For CI, use --default approve for auto-pass
or wire up the exit code as a status check without expecting human input.
deploy: build test
gate "Ship it?" && ./deploy.sh| Variable | Default | Description |
|---|---|---|
GATE_LOG |
~/.gate/log.jsonl |
Decision log path |
GATE_TELEGRAM_TOKEN |
(unset) | Telegram bot token (for --notify telegram) |
GATE_TELEGRAM_CHAT_ID |
(unset) | Telegram chat ID (for --notify telegram) |
NO_COLOR |
(unset) | Disable colors |
Decisions are logged as JSONL at ~/.gate/log.jsonl:
{"ts":"2026-03-13T12:00:00Z","id":"gate-123","msg":"Deploy?","decision":"approved","reason":""}
{"ts":"2026-03-13T12:05:00Z","id":"qa-check","msg":"QA passed?","decision":"rejected","reason":"tests failing"}AI pipelines need the same thing CI/CD learned a decade ago: automatic by default, human when it matters.
gate is the read -p "Are you sure? [y/N]" you should have been writing all along, but with:
- Structured logging
- Timeout + default action
- Context display
- Clean exit codes
No daemon. No server. No config. One bash script.
-
--notify telegram— send Telegram alert when gate is waiting (v0.2.0) -
gate remote— approve/reject via Slack or Telegram (async) -
gate stats— approval rate, avg decision time - Homebrew formula
- Go rewrite for single-binary distribution
MIT — see LICENSE