my-gate 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
my_gate-0.5.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robb Doering
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
my_gate-0.5.0/PKG-INFO ADDED
@@ -0,0 +1,319 @@
1
+ Metadata-Version: 2.4
2
+ Name: my-gate
3
+ Version: 0.5.0
4
+ Summary: Hook-pack that denies or flags nested agent launches on top-tier ("superheavy") models -- pre-flight deny, start-time notify, ground-truth detection. Ships as both a PyPI CLI (Claude Code + Factory Droid registration) and a Claude Code plugin marketplace in one repo. Also ships `gate tint`: trigger-driven terminal background tinting for gate events (denials, grants, heavy subagents, workflows), directories, and commands.
5
+ Author: Robb Doering
6
+ Author-email: Robb Doering <robb@doering.ai>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Environment :: Console
14
+ Classifier: Typing :: Typed
15
+ Classifier: Operating System :: OS Independent
16
+ Requires-Python: >=3.11
17
+ Project-URL: Homepage, https://gitlab.com/doering-ai/apps/gate
18
+ Project-URL: Source, https://gitlab.com/doering-ai/apps/gate
19
+ Project-URL: Issues, https://gitlab.com/doering-ai/apps/gate/-/issues
20
+ Project-URL: Documentation, https://gitlab.com/doering-ai/apps/gate/-/blob/main/docs/index.md
21
+ Description-Content-Type: text/markdown
22
+
23
+ # myGate
24
+
25
+ [![Pipeline status](https://img.shields.io/gitlab/pipeline-status/doering-ai/apps/gate?branch=main)](https://gitlab.com/doering-ai/apps/gate/-/pipelines)
26
+ [![Test coverage](https://img.shields.io/gitlab/pipeline-coverage/doering-ai/apps/gate?branch=main)](https://gitlab.com/doering-ai/apps/gate/-/graphs/main/charts)
27
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](pyproject.toml)
28
+ [![MIT license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
29
+
30
+ myGate prevents expensive nested-agent fan-outs from happening silently.
31
+ Known superheavy launches are denied before they start; launches visible only at runtime
32
+ raise a desktop notification.
33
+
34
+ ## Install
35
+
36
+ Requires Python 3.11 or newer.
37
+ Choose **one** route—installing both duplicates the hooks.
38
+
39
+ ### Universal CLI
40
+
41
+ The source repository is public; the PyPI project is not published yet.
42
+ Install the CLI persistently from Git:
43
+
44
+ ```sh
45
+ uv tool install git+https://gitlab.com/doering-ai/apps/gate.git
46
+ gate register
47
+ gate doctor
48
+ ```
49
+
50
+ `pipx` works too:
51
+
52
+ ```sh
53
+ pipx install git+https://gitlab.com/doering-ai/apps/gate.git
54
+ gate register
55
+ gate doctor
56
+ ```
57
+
58
+ The default registers all three Claude Code layers in your user settings.
59
+ For Factory Droid's pre-flight layer, use `gate register --harness droid`;
60
+ use `--harness all` to register both.
61
+
62
+ ### Claude Code plugin
63
+
64
+ Run these inside Claude Code:
65
+
66
+ ```text
67
+ /plugin marketplace add https://gitlab.com/doering-ai/apps/gate.git
68
+ /plugin install my-gate@my-gate
69
+ /reload-plugins
70
+ /plugin
71
+ ```
72
+
73
+ The bundled `hooks/hooks.json` registers all three layers without editing settings.
74
+ The plugin route requires `python3` on `PATH`; on Windows without that alias, use the CLI
75
+ route, which records the installed interpreter's absolute path.
76
+
77
+ > **Important:** Use the plugin or the CLI registration, not both.
78
+ > Duplicate hooks double notifications and can consume a one-off grant without
79
+ > allowing the launch.
80
+
81
+ ## Verify
82
+
83
+ For the CLI route:
84
+
85
+ ```sh
86
+ gate doctor
87
+ gate status
88
+ ```
89
+
90
+ A healthy persistent install ends `doctor` with `0 failure(s).`.
91
+ `status` checks settings-file registrations; plugin users should inspect Claude Code's
92
+ `/plugin` **Installed** and **Errors** tabs instead.
93
+
94
+ To test the decision logic safely:
95
+
96
+ ```console
97
+ $ gate selftest
98
+ [ok] unpinned workflow under heavy session denied
99
+ [ok] fully light-pinned workflow allowed
100
+ [ok] explicit heavy pin denied even under light session
101
+ [ok] unpinned workflow under light session allowed
102
+ [ok] explicit heavy Agent override denied
103
+ [ok] garbage payload ignored
104
+ [ok] grant honored (heavy Agent allowed)
105
+ [ok] grant exhausted (heavy Agent denied)
106
+ [ok] expired grant ignored (heavy Agent denied)
107
+
108
+ 0 failure(s).
109
+ ```
110
+
111
+ `selftest` feeds synthetic hook payloads through the real gate.
112
+ It launches no agents and suppresses notifications.
113
+ Its output and the package's docstring examples are exercised in the test suite.
114
+
115
+ ## What happens
116
+
117
+ | Situation | Outcome |
118
+ | --- | --- |
119
+ | Explicit `opus` or `fable` nested-agent pin | Denied before launch |
120
+ | Unpinned workflow under a resolvable superheavy session | Denied before fan-out |
121
+ | Explicit `sonnet` or `haiku` pin | Allowed |
122
+ | Allowlisted or one-off-granted launch | Allowed and normally notified |
123
+ | Launch visible only after it starts | Start notification, then stop-time ground truth |
124
+
125
+ When a launch is denied, the calling agent gets the exact reason and a sanctioned next action:
126
+ pin a light model, switch the parent session to one, or ask the human to mint a bounded grant.
127
+
128
+ ```text
129
+ Nested agent launch DENIED by myGate: subagent_type='general-purpose'
130
+ resolves to model='opus' via explicit override. ... ask the user to run:
131
+ `gate grant general-purpose --uses 1 --ttl 15m --session <session_id>`
132
+ ```
133
+
134
+ <details>
135
+ <summary>See the captured incident</summary>
136
+
137
+ ![A workflow fan-out denied until its nested agents were pinned to lighter models](assets/workflow-denial.png)
138
+
139
+ The captured conversation preserves a count mismatch: the gate reported six candidate
140
+ launches, while the agent later found five explicit `agent()` calls. Treat a reported count
141
+ as a prompt to inspect the workflow; the deny itself does not depend on that estimate.
142
+
143
+ </details>
144
+
145
+ ## Why
146
+
147
+ One orchestrator session on Claude Opus or Fable can be a deliberate choice.
148
+ Twenty nested agents silently inheriting that model from a workflow fan-out is a budget
149
+ incident.
150
+ The dominant leak is **inheritance, not explicit pins**: subagents and workflow-internal
151
+ agents use the parent session's model unless each call pins a lighter one.
152
+
153
+ myGate makes that fan-out impossible to trigger silently.
154
+ It denies what can be established before launch and makes runtime-only evidence visible.
155
+
156
+ ## The three layers
157
+
158
+ | Layer | Hook event | Action | Covers |
159
+ | --- | --- | --- | --- |
160
+ | Pre-flight | `PreToolUse` (`Agent`, `Task`, `Workflow`) | **deny + notify** | Explicit heavy pins and inherited workflow fan-outs |
161
+ | Start-time | `SubagentStart` | notify | Built-in or inherited launches invisible pre-flight |
162
+ | Ground truth | `SubagentStop` | notify | The model recorded in the agent's own transcript |
163
+
164
+ For `Workflow` scripts, pre-flight analysis denies an explicit superheavy pin.
165
+ Under a superheavy session, a workflow is allowed only when every recognized `agent()` call
166
+ explicitly pins a light model.
167
+ The start and stop layers cover what static inspection cannot prove.
168
+
169
+ ## Configuration
170
+
171
+ Configuration is optional.
172
+ The defaults gate `opus|fable`, recognize `sonnet|haiku` as light, notify on confirmed
173
+ events, and allow no standing exceptions.
174
+
175
+ ```sh
176
+ gate init-config
177
+ ```
178
+
179
+ That writes `~/.config/gate/config.toml` on Linux and macOS or
180
+ `%APPDATA%\gate\config.toml` on Windows.
181
+ Override the location with `GATE_CONFIG`.
182
+
183
+ ```toml
184
+ superheavy_pattern = "opus|fable"
185
+ light_pattern = "sonnet|haiku"
186
+ allow = [
187
+ "adversarial-critic",
188
+ "workflow:deep-research",
189
+ ]
190
+ notify = true
191
+ notify_command = []
192
+ throttle_seconds = 60
193
+ ```
194
+
195
+ Allowlisted launches remain visible: they are allowed and notify at normal urgency.
196
+ `notify_command` is executed directly as an argument vector, without a shell. Keep it that way:
197
+ `{title}` and `{body}` include hook-payload text, so do not embed them in `sh -c`,
198
+ PowerShell source, or another shell-evaluated string.
199
+
200
+ ## One-off grants
201
+
202
+ A standing allowlist entry is permanent and broad.
203
+ A grant is single-use by default, always expires, and is minted only from the human's terminal.
204
+
205
+ ```sh
206
+ gate grant general-purpose --uses 1 --ttl 15m
207
+ gate grants
208
+ gate revoke general-purpose
209
+ ```
210
+
211
+ Use `--session <session_id>` to bind a grant to the exact session named in a deny message.
212
+ Every successful consumption sends a normal-urgency notification and decrements the
213
+ remaining uses.
214
+
215
+ Grants live at `~/.config/gate/grants.json` by default; override the path with
216
+ `GATE_GRANTS`.
217
+ If the CLI is not installed, a one-off diagnostic or grant command can run directly from
218
+ the public source:
219
+
220
+ ```sh
221
+ uvx --from git+https://gitlab.com/doering-ai/apps/gate.git \
222
+ gate grant general-purpose --uses 1 --ttl 15m
223
+ ```
224
+
225
+ ## Uninstall
226
+
227
+ Settings-file registration is reversible:
228
+
229
+ ```sh
230
+ gate unregister --harness all
231
+ uv tool uninstall my-gate
232
+ ```
233
+
234
+ Plugin users can remove the plugin inside Claude Code:
235
+
236
+ ```text
237
+ /plugin uninstall my-gate@my-gate
238
+ ```
239
+
240
+ ## Platform support
241
+
242
+ | Platform | Pre-flight deny | Start/stop detection | Desktop notification |
243
+ | --- | --- | --- | --- |
244
+ | Linux | yes | yes | `notify-send`, `kitten notify` |
245
+ | macOS | yes | yes | `terminal-notifier`, `osascript` (best-effort, untested) |
246
+ | Windows | yes | yes | PowerShell toast (best-effort, untested) |
247
+
248
+ Claude Code's three layers have been exercised end to end on Linux.
249
+ Factory Droid registration covers its documented `Task` hook; live deny enforcement remains
250
+ advisory until observed.
251
+ Other harnesses currently expose no equivalent hookable nested-launch event.
252
+
253
+ ## Design notes
254
+
255
+ - **Fail open on uncertainty.** Unrecognized or unparseable payloads exit normally in silence.
256
+ A deny is emitted only for a confirmed match, plus documented conservative workflow cases.
257
+ - **Resolve the session model.** Hook payloads omit it, but the transcript records it on every
258
+ assistant message, including mid-session model switches.
259
+ - **State facts, not guesses.** Confirmed superheavy launches notify plainly; unresolved cases
260
+ stay silent until stop-time ground truth is available.
261
+ - **Back prevention with detection.** Dynamic model construction can evade static analysis but
262
+ not the model recorded in the completed agent's transcript.
263
+ - **Keep exceptions visible.** Allowlisted and granted launches still notify.
264
+
265
+ ## Known limitations
266
+
267
+ - `SubagentStop` is detection, not prevention; that agent's tokens have already been spent.
268
+ - Dynamically built model options can escape workflow static analysis, then surface at stop-time.
269
+ - Built-in agent defaults without an on-disk definition are invisible before launch.
270
+ - A missing hook script blocks the matched Claude Code call; uninstall through the supported
271
+ command instead of deleting files by hand.
272
+ - New model families remain ungated until `superheavy_pattern` includes them.
273
+ - Grant locking is advisory on network filesystems.
274
+ - Notification throttling groups repeated detections by subject and session.
275
+
276
+ ## Terminal tinting: the gate you can see
277
+
278
+ `gate tint` turns gate state into your terminal's background color (OSC 11) — a recent
279
+ denial, a heavy subagent or workflow in flight, a live grant — plus ambient colors for
280
+ directories and commands.
281
+ Wire it into your prompt:
282
+
283
+ ```zsh
284
+ precmd() { gate tint -d "$PWD" -s "$?" &! }
285
+ ```
286
+
287
+ The escape goes to `/dev/tty`, so it survives redirection; tmux needs
288
+ `set -g allow-passthrough on`.
289
+ Configure events, aliases, and triggers in `~/.config/gate/tint.toml`
290
+ (`gate tint init` writes a commented starter; see the
291
+ [tint documentation](docs/tint.md)).
292
+ Manual overrides: `gate tint set jade` / `show` / `clear`; `gate tint multiset` colors
293
+ every kitty window in the tab.
294
+
295
+ ## Documentation and development
296
+
297
+ The [full documentation](docs/index.md) uses the same Sphinx + MyST + furo structure as the
298
+ other Python projects in this ecosystem, with executable examples and an autodoc API page.
299
+
300
+ ```sh
301
+ task docs
302
+ task eval
303
+ task test
304
+ ```
305
+
306
+ The release build is dependency-free at runtime.
307
+ Source metadata, plugin metadata, the runtime version, the typed-package marker, and license
308
+ claims are checked by the test suite.
309
+
310
+ ## Versioning
311
+
312
+ This project follows [workflow-gated semver]: the minor version records the highest completed
313
+ `py-workflow` step, with `0.9.0` gated on at least nine external users and `1.0.0` on a
314
+ maintainer social guarantee.
315
+ Version `0.5.0` means implementation gate 5 is the highest cleared release.
316
+
317
+ [workflow-gated semver]: https://gitlab.com/doering-ai/corpus/-/blob/main/docs/versioning.md
318
+
319
+ Licensed under the [MIT License](LICENSE).
@@ -0,0 +1,297 @@
1
+ # myGate
2
+
3
+ [![Pipeline status](https://img.shields.io/gitlab/pipeline-status/doering-ai/apps/gate?branch=main)](https://gitlab.com/doering-ai/apps/gate/-/pipelines)
4
+ [![Test coverage](https://img.shields.io/gitlab/pipeline-coverage/doering-ai/apps/gate?branch=main)](https://gitlab.com/doering-ai/apps/gate/-/graphs/main/charts)
5
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](pyproject.toml)
6
+ [![MIT license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
+
8
+ myGate prevents expensive nested-agent fan-outs from happening silently.
9
+ Known superheavy launches are denied before they start; launches visible only at runtime
10
+ raise a desktop notification.
11
+
12
+ ## Install
13
+
14
+ Requires Python 3.11 or newer.
15
+ Choose **one** route—installing both duplicates the hooks.
16
+
17
+ ### Universal CLI
18
+
19
+ The source repository is public; the PyPI project is not published yet.
20
+ Install the CLI persistently from Git:
21
+
22
+ ```sh
23
+ uv tool install git+https://gitlab.com/doering-ai/apps/gate.git
24
+ gate register
25
+ gate doctor
26
+ ```
27
+
28
+ `pipx` works too:
29
+
30
+ ```sh
31
+ pipx install git+https://gitlab.com/doering-ai/apps/gate.git
32
+ gate register
33
+ gate doctor
34
+ ```
35
+
36
+ The default registers all three Claude Code layers in your user settings.
37
+ For Factory Droid's pre-flight layer, use `gate register --harness droid`;
38
+ use `--harness all` to register both.
39
+
40
+ ### Claude Code plugin
41
+
42
+ Run these inside Claude Code:
43
+
44
+ ```text
45
+ /plugin marketplace add https://gitlab.com/doering-ai/apps/gate.git
46
+ /plugin install my-gate@my-gate
47
+ /reload-plugins
48
+ /plugin
49
+ ```
50
+
51
+ The bundled `hooks/hooks.json` registers all three layers without editing settings.
52
+ The plugin route requires `python3` on `PATH`; on Windows without that alias, use the CLI
53
+ route, which records the installed interpreter's absolute path.
54
+
55
+ > **Important:** Use the plugin or the CLI registration, not both.
56
+ > Duplicate hooks double notifications and can consume a one-off grant without
57
+ > allowing the launch.
58
+
59
+ ## Verify
60
+
61
+ For the CLI route:
62
+
63
+ ```sh
64
+ gate doctor
65
+ gate status
66
+ ```
67
+
68
+ A healthy persistent install ends `doctor` with `0 failure(s).`.
69
+ `status` checks settings-file registrations; plugin users should inspect Claude Code's
70
+ `/plugin` **Installed** and **Errors** tabs instead.
71
+
72
+ To test the decision logic safely:
73
+
74
+ ```console
75
+ $ gate selftest
76
+ [ok] unpinned workflow under heavy session denied
77
+ [ok] fully light-pinned workflow allowed
78
+ [ok] explicit heavy pin denied even under light session
79
+ [ok] unpinned workflow under light session allowed
80
+ [ok] explicit heavy Agent override denied
81
+ [ok] garbage payload ignored
82
+ [ok] grant honored (heavy Agent allowed)
83
+ [ok] grant exhausted (heavy Agent denied)
84
+ [ok] expired grant ignored (heavy Agent denied)
85
+
86
+ 0 failure(s).
87
+ ```
88
+
89
+ `selftest` feeds synthetic hook payloads through the real gate.
90
+ It launches no agents and suppresses notifications.
91
+ Its output and the package's docstring examples are exercised in the test suite.
92
+
93
+ ## What happens
94
+
95
+ | Situation | Outcome |
96
+ | --- | --- |
97
+ | Explicit `opus` or `fable` nested-agent pin | Denied before launch |
98
+ | Unpinned workflow under a resolvable superheavy session | Denied before fan-out |
99
+ | Explicit `sonnet` or `haiku` pin | Allowed |
100
+ | Allowlisted or one-off-granted launch | Allowed and normally notified |
101
+ | Launch visible only after it starts | Start notification, then stop-time ground truth |
102
+
103
+ When a launch is denied, the calling agent gets the exact reason and a sanctioned next action:
104
+ pin a light model, switch the parent session to one, or ask the human to mint a bounded grant.
105
+
106
+ ```text
107
+ Nested agent launch DENIED by myGate: subagent_type='general-purpose'
108
+ resolves to model='opus' via explicit override. ... ask the user to run:
109
+ `gate grant general-purpose --uses 1 --ttl 15m --session <session_id>`
110
+ ```
111
+
112
+ <details>
113
+ <summary>See the captured incident</summary>
114
+
115
+ ![A workflow fan-out denied until its nested agents were pinned to lighter models](assets/workflow-denial.png)
116
+
117
+ The captured conversation preserves a count mismatch: the gate reported six candidate
118
+ launches, while the agent later found five explicit `agent()` calls. Treat a reported count
119
+ as a prompt to inspect the workflow; the deny itself does not depend on that estimate.
120
+
121
+ </details>
122
+
123
+ ## Why
124
+
125
+ One orchestrator session on Claude Opus or Fable can be a deliberate choice.
126
+ Twenty nested agents silently inheriting that model from a workflow fan-out is a budget
127
+ incident.
128
+ The dominant leak is **inheritance, not explicit pins**: subagents and workflow-internal
129
+ agents use the parent session's model unless each call pins a lighter one.
130
+
131
+ myGate makes that fan-out impossible to trigger silently.
132
+ It denies what can be established before launch and makes runtime-only evidence visible.
133
+
134
+ ## The three layers
135
+
136
+ | Layer | Hook event | Action | Covers |
137
+ | --- | --- | --- | --- |
138
+ | Pre-flight | `PreToolUse` (`Agent`, `Task`, `Workflow`) | **deny + notify** | Explicit heavy pins and inherited workflow fan-outs |
139
+ | Start-time | `SubagentStart` | notify | Built-in or inherited launches invisible pre-flight |
140
+ | Ground truth | `SubagentStop` | notify | The model recorded in the agent's own transcript |
141
+
142
+ For `Workflow` scripts, pre-flight analysis denies an explicit superheavy pin.
143
+ Under a superheavy session, a workflow is allowed only when every recognized `agent()` call
144
+ explicitly pins a light model.
145
+ The start and stop layers cover what static inspection cannot prove.
146
+
147
+ ## Configuration
148
+
149
+ Configuration is optional.
150
+ The defaults gate `opus|fable`, recognize `sonnet|haiku` as light, notify on confirmed
151
+ events, and allow no standing exceptions.
152
+
153
+ ```sh
154
+ gate init-config
155
+ ```
156
+
157
+ That writes `~/.config/gate/config.toml` on Linux and macOS or
158
+ `%APPDATA%\gate\config.toml` on Windows.
159
+ Override the location with `GATE_CONFIG`.
160
+
161
+ ```toml
162
+ superheavy_pattern = "opus|fable"
163
+ light_pattern = "sonnet|haiku"
164
+ allow = [
165
+ "adversarial-critic",
166
+ "workflow:deep-research",
167
+ ]
168
+ notify = true
169
+ notify_command = []
170
+ throttle_seconds = 60
171
+ ```
172
+
173
+ Allowlisted launches remain visible: they are allowed and notify at normal urgency.
174
+ `notify_command` is executed directly as an argument vector, without a shell. Keep it that way:
175
+ `{title}` and `{body}` include hook-payload text, so do not embed them in `sh -c`,
176
+ PowerShell source, or another shell-evaluated string.
177
+
178
+ ## One-off grants
179
+
180
+ A standing allowlist entry is permanent and broad.
181
+ A grant is single-use by default, always expires, and is minted only from the human's terminal.
182
+
183
+ ```sh
184
+ gate grant general-purpose --uses 1 --ttl 15m
185
+ gate grants
186
+ gate revoke general-purpose
187
+ ```
188
+
189
+ Use `--session <session_id>` to bind a grant to the exact session named in a deny message.
190
+ Every successful consumption sends a normal-urgency notification and decrements the
191
+ remaining uses.
192
+
193
+ Grants live at `~/.config/gate/grants.json` by default; override the path with
194
+ `GATE_GRANTS`.
195
+ If the CLI is not installed, a one-off diagnostic or grant command can run directly from
196
+ the public source:
197
+
198
+ ```sh
199
+ uvx --from git+https://gitlab.com/doering-ai/apps/gate.git \
200
+ gate grant general-purpose --uses 1 --ttl 15m
201
+ ```
202
+
203
+ ## Uninstall
204
+
205
+ Settings-file registration is reversible:
206
+
207
+ ```sh
208
+ gate unregister --harness all
209
+ uv tool uninstall my-gate
210
+ ```
211
+
212
+ Plugin users can remove the plugin inside Claude Code:
213
+
214
+ ```text
215
+ /plugin uninstall my-gate@my-gate
216
+ ```
217
+
218
+ ## Platform support
219
+
220
+ | Platform | Pre-flight deny | Start/stop detection | Desktop notification |
221
+ | --- | --- | --- | --- |
222
+ | Linux | yes | yes | `notify-send`, `kitten notify` |
223
+ | macOS | yes | yes | `terminal-notifier`, `osascript` (best-effort, untested) |
224
+ | Windows | yes | yes | PowerShell toast (best-effort, untested) |
225
+
226
+ Claude Code's three layers have been exercised end to end on Linux.
227
+ Factory Droid registration covers its documented `Task` hook; live deny enforcement remains
228
+ advisory until observed.
229
+ Other harnesses currently expose no equivalent hookable nested-launch event.
230
+
231
+ ## Design notes
232
+
233
+ - **Fail open on uncertainty.** Unrecognized or unparseable payloads exit normally in silence.
234
+ A deny is emitted only for a confirmed match, plus documented conservative workflow cases.
235
+ - **Resolve the session model.** Hook payloads omit it, but the transcript records it on every
236
+ assistant message, including mid-session model switches.
237
+ - **State facts, not guesses.** Confirmed superheavy launches notify plainly; unresolved cases
238
+ stay silent until stop-time ground truth is available.
239
+ - **Back prevention with detection.** Dynamic model construction can evade static analysis but
240
+ not the model recorded in the completed agent's transcript.
241
+ - **Keep exceptions visible.** Allowlisted and granted launches still notify.
242
+
243
+ ## Known limitations
244
+
245
+ - `SubagentStop` is detection, not prevention; that agent's tokens have already been spent.
246
+ - Dynamically built model options can escape workflow static analysis, then surface at stop-time.
247
+ - Built-in agent defaults without an on-disk definition are invisible before launch.
248
+ - A missing hook script blocks the matched Claude Code call; uninstall through the supported
249
+ command instead of deleting files by hand.
250
+ - New model families remain ungated until `superheavy_pattern` includes them.
251
+ - Grant locking is advisory on network filesystems.
252
+ - Notification throttling groups repeated detections by subject and session.
253
+
254
+ ## Terminal tinting: the gate you can see
255
+
256
+ `gate tint` turns gate state into your terminal's background color (OSC 11) — a recent
257
+ denial, a heavy subagent or workflow in flight, a live grant — plus ambient colors for
258
+ directories and commands.
259
+ Wire it into your prompt:
260
+
261
+ ```zsh
262
+ precmd() { gate tint -d "$PWD" -s "$?" &! }
263
+ ```
264
+
265
+ The escape goes to `/dev/tty`, so it survives redirection; tmux needs
266
+ `set -g allow-passthrough on`.
267
+ Configure events, aliases, and triggers in `~/.config/gate/tint.toml`
268
+ (`gate tint init` writes a commented starter; see the
269
+ [tint documentation](docs/tint.md)).
270
+ Manual overrides: `gate tint set jade` / `show` / `clear`; `gate tint multiset` colors
271
+ every kitty window in the tab.
272
+
273
+ ## Documentation and development
274
+
275
+ The [full documentation](docs/index.md) uses the same Sphinx + MyST + furo structure as the
276
+ other Python projects in this ecosystem, with executable examples and an autodoc API page.
277
+
278
+ ```sh
279
+ task docs
280
+ task eval
281
+ task test
282
+ ```
283
+
284
+ The release build is dependency-free at runtime.
285
+ Source metadata, plugin metadata, the runtime version, the typed-package marker, and license
286
+ claims are checked by the test suite.
287
+
288
+ ## Versioning
289
+
290
+ This project follows [workflow-gated semver]: the minor version records the highest completed
291
+ `py-workflow` step, with `0.9.0` gated on at least nine external users and `1.0.0` on a
292
+ maintainer social guarantee.
293
+ Version `0.5.0` means implementation gate 5 is the highest cleared release.
294
+
295
+ [workflow-gated semver]: https://gitlab.com/doering-ai/corpus/-/blob/main/docs/versioning.md
296
+
297
+ Licensed under the [MIT License](LICENSE).
@@ -0,0 +1,15 @@
1
+ # `gate`: Hook and CLI package
2
+
3
+ The package has five deliberately small modules:
4
+
5
+ - `hook` contains the stdlib-only decision engine and hook entrypoint.
6
+ - `cli` registers the hook, diagnoses installations, runs self-tests, manages grants,
7
+ and drives terminal tinting.
8
+ - `telemetry` records content-free local counters and event state without network I/O.
9
+ - `paths` migrates pre-rename (`superheavy-gate`) state locations once, best-effort.
10
+ - `tint` decides and emits OSC 11 terminal background colors from triggers and gate
11
+ events (a stdlib port of irix's `colorcode`).
12
+
13
+ Start with the [project README](../README.md), follow the
14
+ [quickstart](../docs/quickstart.md), or browse the rendered
15
+ [Python API](../docs/api.md).
@@ -0,0 +1,5 @@
1
+ """myGate: deny or flag nested AI-agent launches on superheavy models."""
2
+
3
+ from gate.hook import __version__, process
4
+
5
+ __all__ = ['__version__', 'process']
@@ -0,0 +1,8 @@
1
+ """Module entrypoint: ``python -m gate`` runs the CLI."""
2
+
3
+ import sys
4
+
5
+ from gate.cli import main
6
+
7
+ if __name__ == '__main__':
8
+ sys.exit(main())