Skip to main content

myGate

Pipeline status Test coverage Python 3.11+ MIT license

myGate prevents expensive nested-agent fan-outs from happening silently. Known superheavy launches are denied before they start; launches visible only at runtime raise a desktop notification.

Install

Requires Python 3.11 or newer. Choose one route—installing both duplicates the hooks.

Universal CLI

The source repository is public; the PyPI project is not published yet. Install the CLI persistently from Git:

uv tool install git+https://gitlab.com/doering-ai/apps/gate.git
gate register
gate doctor

pipx works too:

pipx install git+https://gitlab.com/doering-ai/apps/gate.git
gate register
gate doctor

The default registers all three Claude Code layers in your user settings. For Factory Droid's pre-flight layer, use gate register --harness droid; use --harness all to register both.

Claude Code plugin

Run these inside Claude Code:

/plugin marketplace add https://gitlab.com/doering-ai/apps/gate.git
/plugin install my-gate@my-gate
/reload-plugins
/plugin

The bundled hooks/hooks.json registers all three layers without editing settings. The plugin route requires python3 on PATH; on Windows without that alias, use the CLI route, which records the installed interpreter's absolute path.

Important: Use the plugin or the CLI registration, not both. Duplicate hooks double notifications and can consume a one-off grant without allowing the launch.

Verify

For the CLI route:

gate doctor
gate status

A healthy persistent install ends doctor with 0 failure(s).. status checks settings-file registrations; plugin users should inspect Claude Code's /plugin Installed and Errors tabs instead.

To test the decision logic safely:

$ gate selftest
[ok] unpinned workflow under heavy session denied
[ok] fully light-pinned workflow allowed
[ok] explicit heavy pin denied even under light session
[ok] unpinned workflow under light session allowed
[ok] explicit heavy Agent override denied
[ok] garbage payload ignored
[ok] grant honored (heavy Agent allowed)
[ok] grant exhausted (heavy Agent denied)
[ok] expired grant ignored (heavy Agent denied)

0 failure(s).

selftest feeds synthetic hook payloads through the real gate. It launches no agents and suppresses notifications. Its output and the package's docstring examples are exercised in the test suite.

What happens

Situation Outcome
Explicit opus or fable nested-agent pin Denied before launch
Unpinned workflow under a resolvable superheavy session Denied before fan-out
Explicit sonnet or haiku pin Allowed
Allowlisted or one-off-granted launch Allowed and normally notified
Launch visible only after it starts Start notification, then stop-time ground truth

When a launch is denied, the calling agent gets the exact reason and a sanctioned next action: pin a light model, switch the parent session to one, or ask the human to mint a bounded grant.

Nested agent launch DENIED by myGate: subagent_type='general-purpose'
resolves to model='opus' via explicit override. ... ask the user to run:
`gate grant general-purpose --uses 1 --ttl 15m --session <session_id>`
See the captured incident

A workflow fan-out denied until its nested agents were pinned to lighter models

The captured conversation preserves a count mismatch: the gate reported six candidate launches, while the agent later found five explicit agent() calls. Treat a reported count as a prompt to inspect the workflow; the deny itself does not depend on that estimate.

Why

One orchestrator session on Claude Opus or Fable can be a deliberate choice. Twenty nested agents silently inheriting that model from a workflow fan-out is a budget incident. The dominant leak is inheritance, not explicit pins: subagents and workflow-internal agents use the parent session's model unless each call pins a lighter one.

myGate makes that fan-out impossible to trigger silently. It denies what can be established before launch and makes runtime-only evidence visible.

The three layers

Layer Hook event Action Covers
Pre-flight PreToolUse (Agent, Task, Workflow) deny + notify Explicit heavy pins and inherited workflow fan-outs
Start-time SubagentStart notify Built-in or inherited launches invisible pre-flight
Ground truth SubagentStop notify The model recorded in the agent's own transcript

For Workflow scripts, pre-flight analysis denies an explicit superheavy pin. Under a superheavy session, a workflow is allowed only when every recognized agent() call explicitly pins a light model. The start and stop layers cover what static inspection cannot prove.

Configuration

Configuration is optional. The defaults gate opus|fable, recognize sonnet|haiku as light, notify on confirmed events, and allow no standing exceptions.

gate init-config

That writes ~/.config/gate/config.toml on Linux and macOS or %APPDATA%\gate\config.toml on Windows. Override the location with GATE_CONFIG.

superheavy_pattern = "opus|fable"
light_pattern = "sonnet|haiku"
allow = [
    "adversarial-critic",
    "workflow:deep-research",
]
notify = true
notify_command = []
throttle_seconds = 60

Allowlisted launches remain visible: they are allowed and notify at normal urgency. notify_command is executed directly as an argument vector, without a shell. Keep it that way: {title} and {body} include hook-payload text, so do not embed them in sh -c, PowerShell source, or another shell-evaluated string.

One-off grants

A standing allowlist entry is permanent and broad. A grant is single-use by default, always expires, and is minted only from the human's terminal.

gate grant general-purpose --uses 1 --ttl 15m
gate grants
gate revoke general-purpose

Use --session <session_id> to bind a grant to the exact session named in a deny message. Every successful consumption sends a normal-urgency notification and decrements the remaining uses.

Grants live at ~/.config/gate/grants.json by default; override the path with GATE_GRANTS. If the CLI is not installed, a one-off diagnostic or grant command can run directly from the public source:

uvx --from git+https://gitlab.com/doering-ai/apps/gate.git \
  gate grant general-purpose --uses 1 --ttl 15m

Uninstall

Settings-file registration is reversible:

gate unregister --harness all
uv tool uninstall my-gate

Plugin users can remove the plugin inside Claude Code:

/plugin uninstall my-gate@my-gate

Platform support

Platform Pre-flight deny Start/stop detection Desktop notification
Linux yes yes notify-send, kitten notify
macOS yes yes terminal-notifier, osascript (best-effort, untested)
Windows yes yes PowerShell toast (best-effort, untested)

Claude Code's three layers have been exercised end to end on Linux. Factory Droid registration covers its documented Task hook; live deny enforcement remains advisory until observed. Other harnesses currently expose no equivalent hookable nested-launch event.

Design notes

  • Fail open on uncertainty. Unrecognized or unparseable payloads exit normally in silence. A deny is emitted only for a confirmed match, plus documented conservative workflow cases.
  • Resolve the session model. Hook payloads omit it, but the transcript records it on every assistant message, including mid-session model switches.
  • State facts, not guesses. Confirmed superheavy launches notify plainly; unresolved cases stay silent until stop-time ground truth is available.
  • Back prevention with detection. Dynamic model construction can evade static analysis but not the model recorded in the completed agent's transcript.
  • Keep exceptions visible. Allowlisted and granted launches still notify.

Known limitations

  • SubagentStop is detection, not prevention; that agent's tokens have already been spent.
  • Dynamically built model options can escape workflow static analysis, then surface at stop-time.
  • Built-in agent defaults without an on-disk definition are invisible before launch.
  • A missing hook script blocks the matched Claude Code call; uninstall through the supported command instead of deleting files by hand.
  • New model families remain ungated until superheavy_pattern includes them.
  • Grant locking is advisory on network filesystems.
  • Notification throttling groups repeated detections by subject and session.

Terminal tinting: the gate you can see

gate tint turns gate state into your terminal's background color (OSC 11) — a recent denial, a heavy subagent or workflow in flight, a live grant — plus ambient colors for directories and commands. Wire it into your prompt:

precmd() { gate tint -d "$PWD" -s "$?" &! }

The escape goes to /dev/tty, so it survives redirection; tmux needs set -g allow-passthrough on. Configure events, aliases, and triggers in ~/.config/gate/tint.toml (gate tint init writes a commented starter; see the tint documentation). Manual overrides: gate tint set jade / show / clear; gate tint multiset colors every kitty window in the tab.

Documentation and development

The full documentation uses the same Sphinx + MyST + furo structure as the other Python projects in this ecosystem, with executable examples and an autodoc API page.

task docs
task eval
task test

The release build is dependency-free at runtime. Source metadata, plugin metadata, the runtime version, the typed-package marker, and license claims are checked by the test suite.

Versioning

This project follows workflow-gated semver: the minor version records the highest completed py-workflow step, with 0.9.0 gated on at least nine external users and 1.0.0 on a maintainer social guarantee. Version 0.5.0 means implementation gate 5 is the highest cleared release.

Licensed under the MIT License.

Release files for my-gate 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for my-gate 0.5.0
File Size Uploaded
my_gate-0.5.0.tar.gz 40.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for my-gate 0.5.0
File Interpreter ABI Platform
my_gate-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 84.2 kB

Release files / my_gate-0.5.0.tar.gz

Download URL my_gate-0.5.0.tar.gz
Size 40.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d06eda951740c2090d47756c6ca025e0a8667190b8ef6bdf8add4feb03c9a182
BLAKE2b-256 checksum
How to use checksums
d64712ca6412408301578df767986b8cc62299ee47afccaa42fced68a5627597
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / my_gate-0.5.0-py3-none-any.whl

Download URL my_gate-0.5.0-py3-none-any.whl
Size 43.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5fdb377d049bfe5104ec19ae8acb9252d3da5d1fe0f92e5f5e216380d8d50ec0
BLAKE2b-256 checksum
How to use checksums
9f59a77232b1487b36355534389f67fa3efdda3353f7d90bf1630e91199c3910
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page