agentgovern 2.7.0__tar.gz → 2.7.2__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.
Files changed (78) hide show
  1. {agentgovern-2.7.0 → agentgovern-2.7.2}/CHANGELOG.md +23 -0
  2. {agentgovern-2.7.0 → agentgovern-2.7.2}/PKG-INFO +22 -15
  3. {agentgovern-2.7.0 → agentgovern-2.7.2}/README.md +20 -12
  4. {agentgovern-2.7.0 → agentgovern-2.7.2}/RELEASING.md +8 -0
  5. agentgovern-2.7.2/agentgovern/_version.py +1 -0
  6. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/hook/installer.py +10 -0
  7. {agentgovern-2.7.0 → agentgovern-2.7.2}/pyproject.toml +2 -3
  8. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_installer.py +31 -0
  9. agentgovern-2.7.0/agentgovern/_version.py +0 -1
  10. {agentgovern-2.7.0 → agentgovern-2.7.2}/.gitignore +0 -0
  11. {agentgovern-2.7.0 → agentgovern-2.7.2}/LICENSE +0 -0
  12. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/__init__.py +0 -0
  13. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/__main__.py +0 -0
  14. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/client.py +0 -0
  15. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/exceptions.py +0 -0
  16. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/gate2.py +0 -0
  17. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/hook/__init__.py +0 -0
  18. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/hook/cli.py +0 -0
  19. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/hook/data/__init__.py +0 -0
  20. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/hook/data/hook.py +0 -0
  21. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/hook/drift.py +0 -0
  22. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/hook/settings.py +0 -0
  23. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/instrumentors/__init__.py +0 -0
  24. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/instrumentors/_base.py +0 -0
  25. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/instrumentors/langchain.py +0 -0
  26. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/instrumentors/langgraph.py +0 -0
  27. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentgovern/types.py +0 -0
  28. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentshield/__init__.py +0 -0
  29. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentshield/client.py +0 -0
  30. {agentgovern-2.7.0 → agentgovern-2.7.2}/agentshield/types.py +0 -0
  31. {agentgovern-2.7.0 → agentgovern-2.7.2}/examples/langgraph_credit_decision_agent.py +0 -0
  32. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/__init__.py +0 -0
  33. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/conftest.py +0 -0
  34. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/__init__.py +0 -0
  35. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/conftest.py +0 -0
  36. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/fixtures/claude_code_pretooluse_output_keys.json +0 -0
  37. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/fixtures/hook_2_4_0_golden_outputs.json +0 -0
  38. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_bundled_hook.py +0 -0
  39. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_drift.py +0 -0
  40. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_context_snapshot.py +0 -0
  41. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_dispatch.py +0 -0
  42. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_nagt400.py +0 -0
  43. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_nagt400_compat.py +0 -0
  44. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_outbox_queue.py +0 -0
  45. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_payload_extraction.py +0 -0
  46. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_payloads.py +0 -0
  47. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_remediation_message.py +0 -0
  48. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_system_message.py +0 -0
  49. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_timing_log.py +0 -0
  50. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_transcript_reading.py +0 -0
  51. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_turn_index.py +0 -0
  52. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_hook_v2_warn_verdict.py +0 -0
  53. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_matcher_coverage.py +0 -0
  54. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_settings.py +0 -0
  55. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/hook/test_tool_map_classification.py +0 -0
  56. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_base_instrumentor.py +0 -0
  57. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_client.py +0 -0
  58. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_evaluate_input.py +0 -0
  59. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_gate2_full_path.py +0 -0
  60. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_gate2_latency.py +0 -0
  61. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_gate2_verdict_handler.py +0 -0
  62. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_import_guard.py +0 -0
  63. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_instrument_langchain.py +0 -0
  64. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_langchain.py +0 -0
  65. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_langchain_1x_agent.py +0 -0
  66. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_langchain_gate1.py +0 -0
  67. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_langchain_gate2_callbacks.py +0 -0
  68. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_langgraph.py +0 -0
  69. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_nagt380_enforce_propagation.py +0 -0
  70. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_no_localhost_3000_config.py +0 -0
  71. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_no_localhost_3000_traffic.py +0 -0
  72. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_output_capture_contract.py +0 -0
  73. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_payload_schema.py +0 -0
  74. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_policy_engine_url.py +0 -0
  75. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_rate_limit_handling.py +0 -0
  76. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_register_contract.py +0 -0
  77. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_timestamp.py +0 -0
  78. {agentgovern-2.7.0 → agentgovern-2.7.2}/tests/test_version_consistency.py +0 -0
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.7.2 — release date is the `sdk-v2.7.2` tag's (prepared 2026-10-19)
4
+
5
+ **`agentgovern hook uninstall` now leaves Claude Code's settings exactly as they were before the install.** The bundled Claude Code hook (2.5.0), the dependencies and the Python requirement (3.10 or later) are unchanged from 2.7.1. There is no need to reinstall the hook.
6
+
7
+ ### Fix — the uninstall leaves nothing behind in settings.json (NAGT-391 F8)
8
+
9
+ - **The install-mode marker (`_agentgovern_install_mode`) is removed with the hook entries.** It was left in `~/.claude/settings.json`.
10
+ - **The backup the uninstall writes (`settings.json.bak`) is removed once the new settings are written.** Left behind, it was a copy of the settings that still registered the hook, and restoring it would have pointed Claude Code at a hook script the uninstall steps delete. If the write fails, the backup stays.
11
+ - Found by the install rehearsal workflow (`.github/workflows/guard-install-rehearsal.yml`), which installs and uninstalls on clean Linux, macOS and Windows runners and compares the home folder before and after.
12
+
13
+ ## 2.7.1 — release date is the `sdk-v2.7.1` tag's (prepared 2026-10-16)
14
+
15
+ **Documentation and package metadata only. The code, its dependencies and the bundled Claude Code hook (2.5.0) are unchanged from 2.7.0.** There is no need to reinstall the hook.
16
+
17
+ ### Fix — the links on PyPI work (NAGT-391 F2)
18
+
19
+ - **The project's Repository and Issues links pointed at a GitHub repository that is not public,** so they returned "not found" for everyone outside Zirahn. They are replaced by a **Support** link, https://zirahn.com/contact. The README's own links are corrected the same way.
20
+
21
+ ### Fix — the README says which Python you need (NAGT-391 F2)
22
+
23
+ - **The install line now needs Python 3.10 or later and asks for `agentgovern>=2.7.0`.** On Python 3.9, such as the macOS system Python, an unpinned `pip install agentgovern` installed 2.5.0 without a word; the pinned line fails with "No matching distribution found" instead.
24
+ - **The Claude Code hook section says what each policy mode does,** and that a new organization starts with nothing in enforce mode. It said the hook enforces your policies, which read as if it always blocked.
25
+
3
26
  ## 2.7.0 — release date is the `sdk-v2.7.0` tag's (prepared 2026-10-16)
4
27
 
5
28
  **The Claude Code hook bundled with this release is hook 2.5.0** (it was 2.4.0). Install it with `agentgovern hook install --force` after upgrading; see "Upgrading an existing install" in the README. Until you do, the hook you have keeps working exactly as before, and the AgentGovern server shows it a once-per-session notice that a newer hook is available.
@@ -1,10 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentgovern
3
- Version: 2.7.0
3
+ Version: 2.7.2
4
4
  Summary: Compliance-as-code middleware for agentic AI workflows.
5
5
  Project-URL: Homepage, https://agentgovern.zirahn.com
6
- Project-URL: Repository, https://github.com/ahmedkhan-zirahn/agentgovern
7
- Project-URL: Issues, https://github.com/ahmedkhan-zirahn/agentgovern/issues
6
+ Project-URL: Support, https://zirahn.com/contact
8
7
  Author-email: Ahmed Khan <ahmed.khan@zirahn.com>
9
8
  License: MIT
10
9
  License-File: LICENSE
@@ -44,14 +43,16 @@ Description-Content-Type: text/markdown
44
43
 
45
44
  **Compliance-as-code for agentic AI workflows.**
46
45
 
47
- > **Beta** — API may change before 1.0. [Report issues](https://github.com/ahmedkhan-zirahn/agentgovern/issues).
46
+ > **Beta** — API may change before 1.0. Report issues through [zirahn.com/contact](https://zirahn.com/contact).
48
47
 
49
48
  AgentGovern intercepts AI agent actions, evaluates them against configurable compliance policies (the EU AI Act today; NIST AI RMF and ISO 42001 are on the roadmap — see the table below), and generates audit-ready evidence in near real-time. Tracking runs in a background thread and fails open. An `enforce`-mode block raises in your code (see *Enforcement modes* below for exactly what it stops). *(Corrected again 2026-10-03: the first correction said "the SDK blocks only if you enable Gate 2 `enforce` mode, where a block verdict raises `OutputBlocked`", which reads as if enforce mode halts an agent; through the integrations it does not — NAGT-380.)* This SDK auto-instruments LangChain and LangGraph; any other framework (CrewAI, OpenAI Agents and the rest) can report actions with `track_action()`. *(Corrected 2026-10-03: this said NIST AI RMF and ISO 42001 were supported, that the SDK never blocks, and that it instruments CrewAI and OpenAI Agents code.)*
50
49
 
51
50
  ## Install
52
51
 
52
+ Needs **Python 3.10 or later**. The macOS system Python is 3.9, which is too old: install a newer one first, from python.org or with Homebrew (`brew install python@3.12`). On 3.9 this command fails with "No matching distribution found" rather than installing an old release.
53
+
53
54
  ```bash
54
- pip install "agentgovern[langchain]"
55
+ python3 -m pip install "agentgovern[langchain]>=2.7.0"
55
56
  ```
56
57
 
57
58
  ## Quickstart — LangChain
@@ -212,19 +213,25 @@ Enable policy packs from the [AgentGovern dashboard](https://agentgovern.zirahn.
212
213
  **Policy engine address (2.4.0).** The default engine address is now the stable name
213
214
  `https://engine.zirahn.com`. Versions 2.3.0 and earlier call `https://agentgovern.onrender.com`
214
215
  directly. That address keeps working, so nothing breaks if you stay on an older version, but only
215
- the stable name can follow the engine if it moves. Upgrade with `pip install --upgrade agentgovern`.
216
+ the stable name can follow the engine if it moves. Upgrade with `python3 -m pip install --upgrade "agentgovern>=2.7.0"`.
216
217
  If you set `policy_engine_url` or `AGENTGOVERN_POLICY_ENGINE_URL` yourself, it still takes precedence.
217
218
 
218
219
  ## Claude Code Hook
219
220
 
220
221
  The SDK ships a built-in CLI for installing the AgentGovern hook into Claude Code. The hook
221
- intercepts `PreToolUse` events for every tool call and enforces your tenant policies in real
222
- time — before the tool executes. A tool AgentGovern doesn't yet have a specific classification
223
- for is still captured and evaluated, tagged `action_type=unmapped_tool` rather than silently
224
- skipped.
222
+ checks every tool call against your tenant's policies before the tool runs. A policy in
223
+ **enforce** mode blocks the call and Claude Code shows the reason; **warn** lets it run and
224
+ shows a warning; **log** only records it. A new organization starts with no policy in enforce
225
+ mode. A tool AgentGovern doesn't yet have a specific classification for is still captured and
226
+ evaluated, tagged `action_type=unmapped_tool` rather than silently skipped.
225
227
 
226
228
  ### Install
227
229
 
230
+ **The simplest way is the dashboard:** on **Settings → Developers**, **Add Developer** gives an
231
+ install snippet for bash and PowerShell that checks for Python 3.10 or later, installs this
232
+ package into its own virtual environment, saves your two settings for new terminals, and runs
233
+ the command below. To do it by hand:
234
+
228
235
  ```bash
229
236
  agentgovern hook install
230
237
  ```
@@ -242,7 +249,7 @@ reports it as already installed and changes nothing. Upgrade, read what is insta
242
249
  reinstall with `--force`:
243
250
 
244
251
  ```bash
245
- python3 -m pip install --upgrade agentgovern # or the extra you installed with, e.g. "agentgovern[langchain]"
252
+ python3 -m pip install --upgrade "agentgovern>=2.7.0" # or the extra you installed with, e.g. "agentgovern[langchain]>=2.7.0"
246
253
  agentgovern hook status # note each line's cmd= value and the "Install mode" line
247
254
  agentgovern hook install --force # plus the flags below, if status calls for them
248
255
  agentgovern hook status # reports no [DRIFT] lines once the hook is current
@@ -268,7 +275,7 @@ Your environment variables are not touched. Restart any running Claude Code sess
268
275
 
269
276
  ```bash
270
277
  python3 -m venv ~/.agentgovern-venv
271
- ~/.agentgovern-venv/bin/python -m pip install --upgrade agentgovern
278
+ ~/.agentgovern-venv/bin/python -m pip install --upgrade "agentgovern>=2.7.0"
272
279
  ~/.agentgovern-venv/bin/agentgovern hook status
273
280
  ~/.agentgovern-venv/bin/agentgovern hook install --force # plus the flags status called for
274
281
  ```
@@ -315,7 +322,7 @@ In PowerShell (the variable is removed again when claude exits):
315
322
  try { $env:AGENTGOVERN_HOOK_MODE='off'; claude } finally { Remove-Item Env:AGENTGOVERN_HOOK_MODE }
316
323
  ```
317
324
 
318
- See `packages/claude-hook/README.md` for the full option reference.
325
+ `agentgovern hook install --help` lists the install options, and `agentgovern hook status` shows what is installed. The environment variables are in *Required env vars* and *Bypass* above.
319
326
 
320
327
  ## Design guarantees
321
328
 
@@ -327,8 +334,8 @@ See `packages/claude-hook/README.md` for the full option reference.
327
334
  ## Links
328
335
 
329
336
  - **Dashboard:** https://agentgovern.zirahn.com
330
- - **Documentation:** https://github.com/ahmedkhan-zirahn/agentgovern
331
- - **Issues:** https://github.com/ahmedkhan-zirahn/agentgovern/issues
337
+ - **Documentation:** this README
338
+ - **Support and issues:** https://zirahn.com/contact
332
339
 
333
340
  ## License
334
341
 
@@ -2,14 +2,16 @@
2
2
 
3
3
  **Compliance-as-code for agentic AI workflows.**
4
4
 
5
- > **Beta** — API may change before 1.0. [Report issues](https://github.com/ahmedkhan-zirahn/agentgovern/issues).
5
+ > **Beta** — API may change before 1.0. Report issues through [zirahn.com/contact](https://zirahn.com/contact).
6
6
 
7
7
  AgentGovern intercepts AI agent actions, evaluates them against configurable compliance policies (the EU AI Act today; NIST AI RMF and ISO 42001 are on the roadmap — see the table below), and generates audit-ready evidence in near real-time. Tracking runs in a background thread and fails open. An `enforce`-mode block raises in your code (see *Enforcement modes* below for exactly what it stops). *(Corrected again 2026-10-03: the first correction said "the SDK blocks only if you enable Gate 2 `enforce` mode, where a block verdict raises `OutputBlocked`", which reads as if enforce mode halts an agent; through the integrations it does not — NAGT-380.)* This SDK auto-instruments LangChain and LangGraph; any other framework (CrewAI, OpenAI Agents and the rest) can report actions with `track_action()`. *(Corrected 2026-10-03: this said NIST AI RMF and ISO 42001 were supported, that the SDK never blocks, and that it instruments CrewAI and OpenAI Agents code.)*
8
8
 
9
9
  ## Install
10
10
 
11
+ Needs **Python 3.10 or later**. The macOS system Python is 3.9, which is too old: install a newer one first, from python.org or with Homebrew (`brew install python@3.12`). On 3.9 this command fails with "No matching distribution found" rather than installing an old release.
12
+
11
13
  ```bash
12
- pip install "agentgovern[langchain]"
14
+ python3 -m pip install "agentgovern[langchain]>=2.7.0"
13
15
  ```
14
16
 
15
17
  ## Quickstart — LangChain
@@ -170,19 +172,25 @@ Enable policy packs from the [AgentGovern dashboard](https://agentgovern.zirahn.
170
172
  **Policy engine address (2.4.0).** The default engine address is now the stable name
171
173
  `https://engine.zirahn.com`. Versions 2.3.0 and earlier call `https://agentgovern.onrender.com`
172
174
  directly. That address keeps working, so nothing breaks if you stay on an older version, but only
173
- the stable name can follow the engine if it moves. Upgrade with `pip install --upgrade agentgovern`.
175
+ the stable name can follow the engine if it moves. Upgrade with `python3 -m pip install --upgrade "agentgovern>=2.7.0"`.
174
176
  If you set `policy_engine_url` or `AGENTGOVERN_POLICY_ENGINE_URL` yourself, it still takes precedence.
175
177
 
176
178
  ## Claude Code Hook
177
179
 
178
180
  The SDK ships a built-in CLI for installing the AgentGovern hook into Claude Code. The hook
179
- intercepts `PreToolUse` events for every tool call and enforces your tenant policies in real
180
- time — before the tool executes. A tool AgentGovern doesn't yet have a specific classification
181
- for is still captured and evaluated, tagged `action_type=unmapped_tool` rather than silently
182
- skipped.
181
+ checks every tool call against your tenant's policies before the tool runs. A policy in
182
+ **enforce** mode blocks the call and Claude Code shows the reason; **warn** lets it run and
183
+ shows a warning; **log** only records it. A new organization starts with no policy in enforce
184
+ mode. A tool AgentGovern doesn't yet have a specific classification for is still captured and
185
+ evaluated, tagged `action_type=unmapped_tool` rather than silently skipped.
183
186
 
184
187
  ### Install
185
188
 
189
+ **The simplest way is the dashboard:** on **Settings → Developers**, **Add Developer** gives an
190
+ install snippet for bash and PowerShell that checks for Python 3.10 or later, installs this
191
+ package into its own virtual environment, saves your two settings for new terminals, and runs
192
+ the command below. To do it by hand:
193
+
186
194
  ```bash
187
195
  agentgovern hook install
188
196
  ```
@@ -200,7 +208,7 @@ reports it as already installed and changes nothing. Upgrade, read what is insta
200
208
  reinstall with `--force`:
201
209
 
202
210
  ```bash
203
- python3 -m pip install --upgrade agentgovern # or the extra you installed with, e.g. "agentgovern[langchain]"
211
+ python3 -m pip install --upgrade "agentgovern>=2.7.0" # or the extra you installed with, e.g. "agentgovern[langchain]>=2.7.0"
204
212
  agentgovern hook status # note each line's cmd= value and the "Install mode" line
205
213
  agentgovern hook install --force # plus the flags below, if status calls for them
206
214
  agentgovern hook status # reports no [DRIFT] lines once the hook is current
@@ -226,7 +234,7 @@ Your environment variables are not touched. Restart any running Claude Code sess
226
234
 
227
235
  ```bash
228
236
  python3 -m venv ~/.agentgovern-venv
229
- ~/.agentgovern-venv/bin/python -m pip install --upgrade agentgovern
237
+ ~/.agentgovern-venv/bin/python -m pip install --upgrade "agentgovern>=2.7.0"
230
238
  ~/.agentgovern-venv/bin/agentgovern hook status
231
239
  ~/.agentgovern-venv/bin/agentgovern hook install --force # plus the flags status called for
232
240
  ```
@@ -273,7 +281,7 @@ In PowerShell (the variable is removed again when claude exits):
273
281
  try { $env:AGENTGOVERN_HOOK_MODE='off'; claude } finally { Remove-Item Env:AGENTGOVERN_HOOK_MODE }
274
282
  ```
275
283
 
276
- See `packages/claude-hook/README.md` for the full option reference.
284
+ `agentgovern hook install --help` lists the install options, and `agentgovern hook status` shows what is installed. The environment variables are in *Required env vars* and *Bypass* above.
277
285
 
278
286
  ## Design guarantees
279
287
 
@@ -285,8 +293,8 @@ See `packages/claude-hook/README.md` for the full option reference.
285
293
  ## Links
286
294
 
287
295
  - **Dashboard:** https://agentgovern.zirahn.com
288
- - **Documentation:** https://github.com/ahmedkhan-zirahn/agentgovern
289
- - **Issues:** https://github.com/ahmedkhan-zirahn/agentgovern/issues
296
+ - **Documentation:** this README
297
+ - **Support and issues:** https://zirahn.com/contact
290
298
 
291
299
  ## License
292
300
 
@@ -93,4 +93,12 @@ To re-run a publish after a failed run, trigger the workflow manually **from the
93
93
  - its bundled `hook.py` is hook 2.4.0, byte-identical to the tag commit's;
94
94
  - each file's PyPI attestation names publisher `ZirahnAI/agentgovern`, workflow `publish-sdk.yml`, environment `pypi`, with a subject digest equal to the file's;
95
95
  - an unpinned install resolves 2.6.0 on Python 3.12 and 2.5.0 on Python 3.9.6 (`/usr/bin/python3`, macOS 15.8.1).
96
+ - **2026-10-16:** 2.7.0 was published by run `38849510745` from tag `sdk-v2.7.0` at `90a5d6db` (#947's merge). **The tag was pushed by Claude Code under Ahmed's explicit, one-time authorisation for this tag**; the push printed the tag ruleset's "Cannot create ref due to creations being restricted" line and created the tag (the admin bypass). Build 04:13:32–04:13:52Z, Publish 04:13:56–04:14:27Z; files uploaded 04:14:22Z and 04:14:23Z. Verified afterwards, read-only:
97
+ - the wheel and sdist sha256 match PyPI's digests (`57105511…`, `e266e7e9…`), compared with the run's own `dist` artifact;
98
+ - the wheel's `METADATA` says `Version: 2.7.0`, `Requires-Python: >=3.10`;
99
+ - its bundled `hook.py` is **hook 2.5.0**, sha256 `f43c3c95010120dd34e8a91982de11516d9d3c582b5e2fd4bb7791c8fa6ffec1`, byte-identical to the tag commit's;
100
+ - each file's PyPI attestation names publisher `ZirahnAI/agentgovern`, workflow `publish-sdk.yml`, environment `pypi`;
101
+ - a fresh Python 3.12 venv installing `agentgovern==2.7.0` from PyPI reports `__version__` 2.7.0, and `hook install` into a temporary HOME writes hook 2.5.0 with all four events OK (`hook test` not run: it calls production);
102
+ - Python 3.9.6 (`/usr/bin/python3`) resolves `agentgovern-2.5.0`;
103
+ - the hook version changed, so the released-hook manifest moved to 2.5.0 after the tag (NAGT-400 (c), #953, `b748b1f7`).
96
104
 
@@ -0,0 +1 @@
1
+ __version__ = "2.7.2"
@@ -703,6 +703,10 @@ def uninstall() -> int:
703
703
  print("AgentGovern hook is not installed (no entry found in settings.json).")
704
704
  return 0
705
705
 
706
+ # NAGT-391 F8: the install-mode marker is Guard's own key, written by the
707
+ # install; it goes with the hook, so the settings are left as they were.
708
+ new_settings.pop(INSTALL_MODE_KEY, None)
709
+
706
710
  if settings_path.exists():
707
711
  backup(settings_path)
708
712
 
@@ -712,6 +716,12 @@ def uninstall() -> int:
712
716
  print(f"Error: {exc}", file=sys.stderr)
713
717
  return 1
714
718
 
719
+ # NAGT-391 F8: the backup only guards the write above, which succeeded. Left
720
+ # behind, it is a copy of the settings that still registers Guard's hook, and
721
+ # restoring it would point Claude Code at a hook script the uninstall
722
+ # snippet then deletes. (Found by the install rehearsal workflow.)
723
+ settings_path.with_suffix(".json.bak").unlink(missing_ok=True)
724
+
715
725
  print(f"AgentGovern hook removed from {settings_path} (all event types).")
716
726
  print(f"The hook script at {hook_target} was not deleted.")
717
727
  return 0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentgovern"
3
- version = "2.7.0"
3
+ version = "2.7.2"
4
4
  description = "Compliance-as-code middleware for agentic AI workflows."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -64,8 +64,7 @@ agentgovern = "agentgovern.__main__:main"
64
64
 
65
65
  [project.urls]
66
66
  Homepage = "https://agentgovern.zirahn.com"
67
- Repository = "https://github.com/ahmedkhan-zirahn/agentgovern"
68
- Issues = "https://github.com/ahmedkhan-zirahn/agentgovern/issues"
67
+ Support = "https://zirahn.com/contact"
69
68
 
70
69
  [build-system]
71
70
  requires = ["hatchling"]
@@ -601,6 +601,37 @@ def test_uninstall_preserves_other_config(tmp_path: Path, monkeypatch: pytest.Mo
601
601
  assert cfg.get("theme") == "dark"
602
602
 
603
603
 
604
+ def test_uninstall_leaves_the_settings_exactly_as_before_the_install(
605
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
606
+ ) -> None:
607
+ """NAGT-391 F8: no install-mode marker and no backup are left behind."""
608
+ home = _fake_home(tmp_path, monkeypatch)
609
+ before = {"theme": "dark", "permissions": {"allow": ["Bash(ls:*)"]}}
610
+ _write_json(_settings_path(home), before)
611
+ installer.install(_default_args())
612
+ assert _MARKER_KEY in json.loads(_settings_path(home).read_text())
613
+ assert _settings_path(home).with_suffix(".json.bak").exists()
614
+ assert installer.uninstall() == 0
615
+ assert json.loads(_settings_path(home).read_text()) == before
616
+ assert not _settings_path(home).with_suffix(".json.bak").exists()
617
+
618
+
619
+ def test_uninstall_keeps_the_backup_when_the_write_fails(
620
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
621
+ ) -> None:
622
+ """The backup is removed only after a successful write."""
623
+ home = _fake_home(tmp_path, monkeypatch)
624
+ _write_json(_settings_path(home), {"theme": "dark"})
625
+ installer.install(_default_args())
626
+
627
+ def refuse(*_args, **_kwargs): # type: ignore[no-untyped-def]
628
+ raise PermissionError("read-only")
629
+
630
+ monkeypatch.setattr(installer, "atomic_write", refuse)
631
+ assert installer.uninstall() == 1
632
+ assert _settings_path(home).with_suffix(".json.bak").exists()
633
+
634
+
604
635
  def test_uninstall_not_installed_exits_zero(
605
636
  tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture
606
637
  ) -> None:
@@ -1 +0,0 @@
1
- __version__ = "2.7.0"
File without changes
File without changes