covenant-agents 0.1.1__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.
- covenant_agents-0.1.1/LICENSE +21 -0
- covenant_agents-0.1.1/PKG-INFO +412 -0
- covenant_agents-0.1.1/README.md +382 -0
- covenant_agents-0.1.1/pyproject.toml +48 -0
- covenant_agents-0.1.1/setup.cfg +4 -0
- covenant_agents-0.1.1/src/covenant/__init__.py +6 -0
- covenant_agents-0.1.1/src/covenant/__main__.py +3 -0
- covenant_agents-0.1.1/src/covenant/alerts.py +176 -0
- covenant_agents-0.1.1/src/covenant/bench/__init__.py +10 -0
- covenant_agents-0.1.1/src/covenant/bench/oracle.py +70 -0
- covenant_agents-0.1.1/src/covenant/bench/runner.py +305 -0
- covenant_agents-0.1.1/src/covenant/bench/task.py +72 -0
- covenant_agents-0.1.1/src/covenant/ci.py +182 -0
- covenant_agents-0.1.1/src/covenant/cli.py +705 -0
- covenant_agents-0.1.1/src/covenant/compiler/__init__.py +17 -0
- covenant_agents-0.1.1/src/covenant/compiler/bind.py +397 -0
- covenant_agents-0.1.1/src/covenant/compiler/clarify.py +160 -0
- covenant_agents-0.1.1/src/covenant/compiler/extract.py +316 -0
- covenant_agents-0.1.1/src/covenant/compiler/ground.py +224 -0
- covenant_agents-0.1.1/src/covenant/compiler/pipeline.py +155 -0
- covenant_agents-0.1.1/src/covenant/compiler/schema.py +85 -0
- covenant_agents-0.1.1/src/covenant/dashboard.html +388 -0
- covenant_agents-0.1.1/src/covenant/dashboard.py +414 -0
- covenant_agents-0.1.1/src/covenant/events.py +66 -0
- covenant_agents-0.1.1/src/covenant/explain.py +124 -0
- covenant_agents-0.1.1/src/covenant/feedback.py +71 -0
- covenant_agents-0.1.1/src/covenant/github.py +159 -0
- covenant_agents-0.1.1/src/covenant/hookclient.py +128 -0
- covenant_agents-0.1.1/src/covenant/integrations/__init__.py +0 -0
- covenant_agents-0.1.1/src/covenant/integrations/claude_code.py +384 -0
- covenant_agents-0.1.1/src/covenant/integrations/mcp_server.py +184 -0
- covenant_agents-0.1.1/src/covenant/ir.py +104 -0
- covenant_agents-0.1.1/src/covenant/locking.py +44 -0
- covenant_agents-0.1.1/src/covenant/monitors/__init__.py +0 -0
- covenant_agents-0.1.1/src/covenant/monitors/effects.py +123 -0
- covenant_agents-0.1.1/src/covenant/monitors/snapshot.py +129 -0
- covenant_agents-0.1.1/src/covenant/monitors/trace.py +281 -0
- covenant_agents-0.1.1/src/covenant/packs.py +95 -0
- covenant_agents-0.1.1/src/covenant/paths.py +51 -0
- covenant_agents-0.1.1/src/covenant/policy.py +198 -0
- covenant_agents-0.1.1/src/covenant/runtime.py +629 -0
- covenant_agents-0.1.1/src/covenant/sandbox.py +170 -0
- covenant_agents-0.1.1/src/covenant/sandbox_proxy.py +122 -0
- covenant_agents-0.1.1/src/covenant/server.py +252 -0
- covenant_agents-0.1.1/src/covenant/snapshots.py +165 -0
- covenant_agents-0.1.1/src/covenant/status.py +28 -0
- covenant_agents-0.1.1/src/covenant/suggest.py +166 -0
- covenant_agents-0.1.1/src/covenant/testcmd.py +119 -0
- covenant_agents-0.1.1/src/covenant/validate.py +88 -0
- covenant_agents-0.1.1/src/covenant/verifiers/__init__.py +0 -0
- covenant_agents-0.1.1/src/covenant/verifiers/api_surface.py +297 -0
- covenant_agents-0.1.1/src/covenant/verifiers/budget.py +122 -0
- covenant_agents-0.1.1/src/covenant/verifiers/command_guard.py +145 -0
- covenant_agents-0.1.1/src/covenant/verifiers/dependency_diff.py +144 -0
- covenant_agents-0.1.1/src/covenant/verifiers/diff_guard.py +368 -0
- covenant_agents-0.1.1/src/covenant/verifiers/llm_review.py +142 -0
- covenant_agents-0.1.1/src/covenant/verifiers/network.py +96 -0
- covenant_agents-0.1.1/src/covenant/verifiers/ownership.py +55 -0
- covenant_agents-0.1.1/src/covenant/verifiers/registry.py +84 -0
- covenant_agents-0.1.1/src/covenant/verifiers/schema_guard.py +77 -0
- covenant_agents-0.1.1/src/covenant/verifiers/source_api.py +546 -0
- covenant_agents-0.1.1/src/covenant/verifiers/sql_guard.py +109 -0
- covenant_agents-0.1.1/src/covenant/verifiers/sqlite_guard.py +274 -0
- covenant_agents-0.1.1/src/covenant/verifiers/test_gate.py +14 -0
- covenant_agents-0.1.1/src/covenant/verifiers/ts_api_surface.py +144 -0
- covenant_agents-0.1.1/src/covenant/verifiers/ts_extract.js +133 -0
- covenant_agents-0.1.1/src/covenant_agents.egg-info/PKG-INFO +412 -0
- covenant_agents-0.1.1/src/covenant_agents.egg-info/SOURCES.txt +99 -0
- covenant_agents-0.1.1/src/covenant_agents.egg-info/dependency_links.txt +1 -0
- covenant_agents-0.1.1/src/covenant_agents.egg-info/entry_points.txt +2 -0
- covenant_agents-0.1.1/src/covenant_agents.egg-info/requires.txt +6 -0
- covenant_agents-0.1.1/src/covenant_agents.egg-info/top_level.txt +1 -0
- covenant_agents-0.1.1/tests/test_amend.py +111 -0
- covenant_agents-0.1.1/tests/test_api_surface.py +80 -0
- covenant_agents-0.1.1/tests/test_bench.py +64 -0
- covenant_agents-0.1.1/tests/test_ci.py +152 -0
- covenant_agents-0.1.1/tests/test_claude_code.py +253 -0
- covenant_agents-0.1.1/tests/test_cli.py +81 -0
- covenant_agents-0.1.1/tests/test_command_guard.py +91 -0
- covenant_agents-0.1.1/tests/test_compiler.py +418 -0
- covenant_agents-0.1.1/tests/test_dashboard.py +154 -0
- covenant_agents-0.1.1/tests/test_diff_guard.py +141 -0
- covenant_agents-0.1.1/tests/test_effects.py +65 -0
- covenant_agents-0.1.1/tests/test_explain_alerts.py +135 -0
- covenant_agents-0.1.1/tests/test_hookclient.py +104 -0
- covenant_agents-0.1.1/tests/test_ir.py +51 -0
- covenant_agents-0.1.1/tests/test_llm_review.py +73 -0
- covenant_agents-0.1.1/tests/test_mcp.py +51 -0
- covenant_agents-0.1.1/tests/test_more_verifiers.py +111 -0
- covenant_agents-0.1.1/tests/test_new_guards.py +204 -0
- covenant_agents-0.1.1/tests/test_policy.py +216 -0
- covenant_agents-0.1.1/tests/test_runtime.py +153 -0
- covenant_agents-0.1.1/tests/test_sandbox.py +97 -0
- covenant_agents-0.1.1/tests/test_server.py +77 -0
- covenant_agents-0.1.1/tests/test_snapshots.py +87 -0
- covenant_agents-0.1.1/tests/test_source_api.py +133 -0
- covenant_agents-0.1.1/tests/test_sqlite_guard.py +138 -0
- covenant_agents-0.1.1/tests/test_testcmd.py +55 -0
- covenant_agents-0.1.1/tests/test_trace.py +118 -0
- covenant_agents-0.1.1/tests/test_ts_api_surface.py +141 -0
- covenant_agents-0.1.1/tests/test_validate.py +64 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 viswesh-dev
|
|
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.
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: covenant-agents
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Compile plain-English instructions for coding agents into enforced contracts.
|
|
5
|
+
Author: viswesh-dev
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/visweshdev/Covenant
|
|
8
|
+
Project-URL: Repository, https://github.com/visweshdev/Covenant
|
|
9
|
+
Project-URL: Changelog, https://github.com/visweshdev/Covenant/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Issues, https://github.com/visweshdev/Covenant/issues
|
|
11
|
+
Keywords: coding agents,ai safety,policy,claude code,mcp,guardrails
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: pydantic>=2.6
|
|
25
|
+
Requires-Dist: pyyaml>=6
|
|
26
|
+
Requires-Dist: anthropic>=2.3
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
<p align="center"><img src="https://raw.githubusercontent.com/visweshdev/Covenant/main/docs/logo.png" width="110" alt="Covenant logo: a C closed by a short bar"></p>
|
|
32
|
+
|
|
33
|
+
# Covenant
|
|
34
|
+
|
|
35
|
+
Covenant turns the rules you give a coding agent ("don't change public APIs, don't delete
|
|
36
|
+
user data, run tests before committing") into checks that actually run, and enforces them
|
|
37
|
+
while the agent works, in git, and in CI.
|
|
38
|
+
|
|
39
|
+
It checks **outcomes**, not tool calls: the API surface after the edits, what happened to
|
|
40
|
+
protected files however they were touched, and the order of events (tests passed after the
|
|
41
|
+
last edit, before the commit).
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
sh install.sh # or on Windows: powershell -File install.ps1 (pipx, from GitHub)
|
|
45
|
+
cd your-repo
|
|
46
|
+
covenant compile "Update dependencies, but don't change public APIs, don't delete user data, and run tests before committing."
|
|
47
|
+
covenant init # git hooks + Claude Code hooks, then start enforcing
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or start from a ready-made rule set: `covenant compile --pack hotfix "fix the login crash"`
|
|
51
|
+
(`covenant packs` lists them). `covenant suggest` proposes rules from what went wrong in the
|
|
52
|
+
repo's own history.
|
|
53
|
+
|
|
54
|
+
## How it works
|
|
55
|
+
|
|
56
|
+
1. **Compile** (`covenant compile`): Claude, or the offline extractor with `--offline`, splits the
|
|
57
|
+
instruction into a goal and clauses. Claude is reached through `ANTHROPIC_API_KEY` if it is set,
|
|
58
|
+
and otherwise through your Claude Code login (`claude -p`), so a Claude subscription is enough
|
|
59
|
+
(`--backend api|claude-code` to choose). Deterministic passes then:
|
|
60
|
+
- ground each clause in the repo: the real exports, data folders, tables and test command;
|
|
61
|
+
- bind it to a checker;
|
|
62
|
+
- ask at most three questions about specific things in the repo;
|
|
63
|
+
- check the result statically.
|
|
64
|
+
|
|
65
|
+
You approve the resulting `covenant.yaml`. To add a rule mid-task (`covenant amend "also don't
|
|
66
|
+
touch config/"`), the new rules apply from then on and the task's history is kept.
|
|
67
|
+
2. **Enforce locally:** hooks turn what the agent does into events. Checkers judge them, and a
|
|
68
|
+
violation goes back to the agent as a report naming the rule, the evidence and a fix.
|
|
69
|
+
3. **Enforce in CI** (`covenant ci` / the GitHub Action): every pull request is judged against
|
|
70
|
+
the Covenant from its base commit.
|
|
71
|
+
|
|
72
|
+
## Checkers
|
|
73
|
+
|
|
74
|
+
| Rule kind | Checker | What it checks |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| Semantic invariant | `api_surface_diff` | Python exported names and signatures vs. the base commit (`ast`) |
|
|
77
|
+
| Semantic invariant | `ts_api_surface_diff` | TypeScript exported types, via the project's own compiler |
|
|
78
|
+
| Semantic invariant | `source_api_diff` | Go, Rust and Java public API, read from source (no compiler needed) |
|
|
79
|
+
| Semantic invariant | `schema_guard` | No dropped tables or columns, truncation, unqualified deletes or type changes in new migrations |
|
|
80
|
+
| Semantic invariant | `dependency_diff` | Only allowed packages change; locked versions keep their major version |
|
|
81
|
+
| Semantic invariant | `sqlite_guard` | Rows, tables and columns in SQLite databases are never lost; inserts are allowed. Checked after every step, and lost rows are put back from a snapshot |
|
|
82
|
+
| Effect prohibition | `effect_monitor` | Protected files and tables aren't deleted, truncated or overwritten, whatever does it; rolled back from a snapshot |
|
|
83
|
+
| Temporal obligation | `trace_monitor` | Ordering, limit and deadline rules over the agent's steps, in past-time LTL (see below) |
|
|
84
|
+
| Semantic invariant | `scope_guard` | Only the files you name change ("only change files in src/"); optionally no new or deleted files |
|
|
85
|
+
| Semantic invariant | `secret_scan` | No API keys, tokens, private keys, passwords or `.env` files in the change (reports are masked) |
|
|
86
|
+
| Semantic invariant | `test_guard` | Tests aren't deleted, removed, skipped or focused with `.only` |
|
|
87
|
+
| Semantic invariant | `diff_budget` | The change stays within a number of files or lines |
|
|
88
|
+
| Semantic invariant | `no_debug_code` | No breakpoints, `debugger`, `console.log` or (optionally) debug prints left behind |
|
|
89
|
+
| Semantic invariant | `no_suppressions` | No new `# type: ignore`, `# noqa`, `@ts-ignore`, `eslint-disable` and the like |
|
|
90
|
+
| Semantic invariant | `large_files` | No added or changed file over a size limit |
|
|
91
|
+
| Effect prohibition | `command_guard` | Shell commands, web fetches and database tool calls refused before they run (see below) |
|
|
92
|
+
| Effect prohibition | `budget` | The task stops at a time, action or (estimated) cost limit |
|
|
93
|
+
| Semantic invariant | `path_owner` | Folders that belong to one team's agent change only by that agent |
|
|
94
|
+
| Semantic invariant | `llm_review` | Claude reviews each commit against a rule no checker covers; advisory, never blocks |
|
|
95
|
+
|
|
96
|
+
A rule with no checker ("keep the code readable") becomes an `llm_review` rule when Claude is
|
|
97
|
+
available: Claude reads each commit's change against it, and its findings go to the agent and to
|
|
98
|
+
you as warnings that never block. With `--offline` or `--no-review` the rule is kept and marked
|
|
99
|
+
`unenforceable`, never silently dropped.
|
|
100
|
+
|
|
101
|
+
### Rules the compiler understands
|
|
102
|
+
|
|
103
|
+
| Say | Becomes |
|
|
104
|
+
|---|---|
|
|
105
|
+
| "don't change public APIs" | `api_surface_diff` / `ts_api_surface_diff` / `source_api_diff` |
|
|
106
|
+
| "don't delete user data", "don't touch config/" | `effect_monitor`, `sqlite_guard` |
|
|
107
|
+
| "no destructive migrations" | `schema_guard` |
|
|
108
|
+
| "only update requests", "no major upgrades" | `dependency_diff` |
|
|
109
|
+
| "don't add new dependencies" | `dependency_diff` (upgrades are fine; new packages aren't) |
|
|
110
|
+
| "only change files in src/" | `scope_guard` |
|
|
111
|
+
| "don't commit secrets or API keys" | `secret_scan` |
|
|
112
|
+
| "don't delete or skip tests" | `test_guard` |
|
|
113
|
+
| "keep the change under 200 lines", "touch at most 3 files" | `diff_budget` |
|
|
114
|
+
| "no leftover debug prints" | `no_debug_code` |
|
|
115
|
+
| "don't silence type errors" | `no_suppressions` |
|
|
116
|
+
| "don't commit files over 5 MB" | `large_files` |
|
|
117
|
+
| "run tests before committing", "push at most once", "run tests within 5 steps of an edit" | `trace_monitor` |
|
|
118
|
+
| "never force push", "don't deploy", "don't install packages", "no network access", "don't read .env" | `command_guard` |
|
|
119
|
+
| "never run destructive SQL" | `command_guard` (`destructive_sql`) |
|
|
120
|
+
| "only reach pypi.org and github.com" | `command_guard` (`network` with `allow_hosts`) |
|
|
121
|
+
| "only the payments team's agent may edit billing/" | `path_owner` |
|
|
122
|
+
| "stop after 20 minutes", "spend at most $2", "use at most 50 tool calls" | `budget` |
|
|
123
|
+
|
|
124
|
+
`command_guard` categories: `force_push`, `history_rewrite`, `branch_delete`, `discard_changes`,
|
|
125
|
+
`sudo`, `pipe_to_shell`, `recursive_delete`, `install_packages`, `publish`, `deploy`, `network`,
|
|
126
|
+
`read_secrets`, `database_cli`, `kill_processes`, `system_changes`, `destructive_sql`, plus your
|
|
127
|
+
own `patterns`. It guards against mistakes and shortcuts; an agent determined to hide a command
|
|
128
|
+
(by writing it into a script first) needs the sandbox.
|
|
129
|
+
|
|
130
|
+
- **Destructive SQL** (Postgres, MySQL, SQLite, SQL Server, DuckDB, MongoDB, Redis): Covenant
|
|
131
|
+
reads the SQL itself, inline (`psql -c`, `mysql -e`, piped in), in `.sql` files fed to a client,
|
|
132
|
+
and in database MCP tool calls. `DROP`, `TRUNCATE`, `ALTER TABLE ... DROP`, and `DELETE` or
|
|
133
|
+
`UPDATE` without a `WHERE` are refused; a `DELETE ... WHERE` is fine.
|
|
134
|
+
- **Network allowlist:** with `allow_hosts`, only those hosts (and their subdomains) can be
|
|
135
|
+
reached, by commands, `git push`/`pull` (the remote's host), package installs (their registry)
|
|
136
|
+
and the WebFetch tool. A network command whose destination can't be worked out is refused.
|
|
137
|
+
- **Path ownership:** an agent says who it is with `COVENANT_AGENT=payments claude`; edits to
|
|
138
|
+
folders it doesn't own are refused, and so is a commit that changes them.
|
|
139
|
+
- **Budgets:** checked before each action. Cost is estimated from the token counts in Claude
|
|
140
|
+
Code's session log at Anthropic's API prices (on a subscription nothing is charged per token,
|
|
141
|
+
but it is still a fair measure of how much work was done).
|
|
142
|
+
|
|
143
|
+
### Rule packs
|
|
144
|
+
|
|
145
|
+
`covenant compile --pack NAME` adds a ready-made rule set to your instruction. Packs always
|
|
146
|
+
compile offline, so a pack means the same rules everywhere.
|
|
147
|
+
|
|
148
|
+
| Pack | For |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `safe-refactor` | restructuring code without changing what it does |
|
|
151
|
+
| `dependency-bump` | updating dependencies without breaking anything |
|
|
152
|
+
| `docs-only` | changing documentation and nothing else |
|
|
153
|
+
| `hotfix` | a small, urgent, well-tested fix |
|
|
154
|
+
| `data-safe` | working near user data and databases without losing any |
|
|
155
|
+
| `secure` | keeping secrets and the machine safe |
|
|
156
|
+
| `lockdown` | the strictest set: no installs, no network, no history rewrites |
|
|
157
|
+
|
|
158
|
+
### Rules over the agent's steps
|
|
159
|
+
|
|
160
|
+
A step is one recorded action: an edit, a command, a test run, a commit or a push.
|
|
161
|
+
|
|
162
|
+
| Instruction | Formula |
|
|
163
|
+
|---|---|
|
|
164
|
+
| "run tests before committing" | `G(commit -> (!edit S test_pass))` |
|
|
165
|
+
| "never push" | `G(!push)` |
|
|
166
|
+
| "push at most once", "don't commit more than 3 times" | `G(#push <= 1)`, `G(#commit <= 3)` |
|
|
167
|
+
| "run the tests within 5 steps of any edit" | `G(!(!test S[>=5] edit))` |
|
|
168
|
+
|
|
169
|
+
The operators:
|
|
170
|
+
- `S` (since), `Y` (previous step), `O` (at some step so far) and `H` (at every step so far);
|
|
171
|
+
- bounded forms of these, `O[<=n]`, `H[<=n]` and `a S[<=n] b` / `a S[>=n] b`, which count steps back;
|
|
172
|
+
- `#a <= n` (also `<`, `>=`, `>`, `==`), which counts how often `a` has happened.
|
|
173
|
+
|
|
174
|
+
A limit counts every commit or push this task, including ones later undone with `git reset`.
|
|
175
|
+
|
|
176
|
+
## Agents
|
|
177
|
+
|
|
178
|
+
**Claude Code:** `covenant init` (or `covenant install-claude`) adds hooks to `.claude/settings.json`:
|
|
179
|
+
|
|
180
|
+
| Hook | What Covenant does |
|
|
181
|
+
|---|---|
|
|
182
|
+
| `SessionStart` | Starts a session and tells Claude the rules |
|
|
183
|
+
| `PreToolUse` | Denies commits and pushes that would break a rule, edits to protected or someone else's files, refused commands, web fetches and database tool calls, actions past a budget, changes to Covenant's own files, and hook bypasses (`--no-verify`, `core.hooksPath`). Takes a restore point before risky steps |
|
|
184
|
+
| `PostToolUse` / `PostToolUseFailure` | Records edits, commands and test runs, and reports side effects found by the snapshot scan |
|
|
185
|
+
| `Stop` | Claude can't finish while a rule is broken; after repeated blocks it hands over to you |
|
|
186
|
+
|
|
187
|
+
The hook fails closed: if it crashes before a tool call, the call is denied.
|
|
188
|
+
|
|
189
|
+
Hooks are fast: each one starts a tiny client that uses only Python's standard library and hands
|
|
190
|
+
the event to a background `covenant daemon` for the repo, which keeps Covenant loaded. That takes
|
|
191
|
+
about 0.2 s per agent action on Windows instead of about 1 s. When no daemon answers, the client
|
|
192
|
+
runs the full check itself and starts one, so a missing daemon never skips a check. The daemon
|
|
193
|
+
listens on 127.0.0.1 only, exits after 30 idle minutes, and restarts when Covenant is upgraded.
|
|
194
|
+
`covenant init --no-fast-hooks` starts a fresh Python for every hook instead.
|
|
195
|
+
|
|
196
|
+
A test run counts when it runs the whole suite and its exit status is visible. Extra flags
|
|
197
|
+
that only change output or speed (`-x`, `-v`, `-p no:cacheprovider`, `--cov`, `-n auto`,
|
|
198
|
+
`2>&1`) are fine. A run that picks some tests (a path, `-k`, `-m`, `--lf`) or pipes its output
|
|
199
|
+
doesn't count, and the agent is told why right away.
|
|
200
|
+
|
|
201
|
+
**Cursor, Codex and other MCP clients:** `covenant --repo <path> mcp` is an MCP server with
|
|
202
|
+
`covenant_rules`, `covenant_run_tests`, `covenant_record_edit`, `covenant_preflight`,
|
|
203
|
+
`covenant_check`, `covenant_check_command` and `covenant_explain`. MCP only works when the
|
|
204
|
+
agent chooses to call it, so the git hooks (and CI) are what enforce commits and pushes for
|
|
205
|
+
these agents.
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
// .cursor/mcp.json
|
|
209
|
+
{ "mcpServers": { "covenant": { "command": "covenant", "args": ["--repo", ".", "mcp"] } } }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```toml
|
|
213
|
+
# ~/.codex/config.toml
|
|
214
|
+
[mcp_servers.covenant]
|
|
215
|
+
command = "covenant"
|
|
216
|
+
args = ["--repo", "/path/to/repo", "mcp"]
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Team policies
|
|
220
|
+
|
|
221
|
+
A repo's `covenant.yaml` can list `extends: [policies/team.yaml]`. Policy files hold clauses
|
|
222
|
+
in the same format and can extend each other. `COVENANT_POLICY` (paths separated by your
|
|
223
|
+
OS's path separator) applies policies to every repo on a machine.
|
|
224
|
+
|
|
225
|
+
A policy can also live at an https address, such as a raw file in an org-wide repo:
|
|
226
|
+
`extends: ["https://example.com/team.yaml#sha256=<hash>"]`. The `#sha256=` pin is optional;
|
|
227
|
+
with it, a policy that changes without the pin being updated is an error. The last good copy
|
|
228
|
+
is kept in `~/.covenant/policies/` and used when the network is down.
|
|
229
|
+
|
|
230
|
+
Policy rules:
|
|
231
|
+
- are merged in first, with an `origin` naming their policy;
|
|
232
|
+
- can't be redefined by a repo: an id clash is an error;
|
|
233
|
+
- are protected from the agent like Covenant's own files;
|
|
234
|
+
- in CI, come from the base commit, and a PR that changes them is flagged.
|
|
235
|
+
|
|
236
|
+
## Dashboard
|
|
237
|
+
|
|
238
|
+
`covenant dashboard` opens a page on `127.0.0.1:8765` covering every repo Covenant enforces on this
|
|
239
|
+
machine:
|
|
240
|
+
- each repo's rules, with how close each is to handing over to a human;
|
|
241
|
+
- a timeline of blocks and reports;
|
|
242
|
+
- recent events and protected paths;
|
|
243
|
+
- an editor for the rules: write a rule in plain English and Claude drafts it, check the result,
|
|
244
|
+
then save and approve. Added rules apply from now on, like `covenant amend`; changing or
|
|
245
|
+
removing a rule restarts the task, after asking;
|
|
246
|
+
- a replay of any task, this one or one of the last 30: step through everything the agent did
|
|
247
|
+
and every decision Covenant made, with why each rule fired and how to fix it.
|
|
248
|
+
|
|
249
|
+
It refreshes every few seconds and rejects requests whose Host header isn't localhost. Changes
|
|
250
|
+
need a key created at start: the browser gets it in the part of the address after `#`, which is
|
|
251
|
+
never sent over the network, and the page removes it from the address bar. Requests from other
|
|
252
|
+
web pages are refused. `--read-only` turns editing off.
|
|
253
|
+
|
|
254
|
+
## Undo, explain, alerts
|
|
255
|
+
|
|
256
|
+
- **Undo snapshots:** before a risky step (`rm`, `mv`, `git reset`/`checkout`/`clean`, `sed -i`,
|
|
257
|
+
redirects, formatters, rewriting a whole file), Covenant records the working tree, untracked
|
|
258
|
+
files included, as a git commit under `refs/covenant/snapshots/`. Your branch, index and stash
|
|
259
|
+
aren't touched, and the refs are never pushed. `covenant snapshots` lists them and
|
|
260
|
+
`covenant undo [ID]` restores one. An undo first snapshots the current state, so it can be
|
|
261
|
+
undone too. `COVENANT_SNAPSHOTS=0` turns them off.
|
|
262
|
+
- **`covenant explain`:** what was blocked, why, what the agent can do and what you can do, in
|
|
263
|
+
plain words (`-n 3` for the last three).
|
|
264
|
+
- **Alerts:** a Slack message, a webhook call or an email when an agent needs a human (and
|
|
265
|
+
optionally whenever it is blocked). Set `COVENANT_SLACK_WEBHOOK`, `COVENANT_ALERT_WEBHOOK` or
|
|
266
|
+
`COVENANT_ALERT_EMAIL`, or write `~/.covenant/alerts.yaml` (see `src/covenant/alerts.py`).
|
|
267
|
+
`covenant alerts test` sends a test message. The same problem alerts at most once every 10
|
|
268
|
+
minutes.
|
|
269
|
+
- **`covenant suggest`:** reads the repo's history for reverted changes, removed secrets,
|
|
270
|
+
deleted tests, debug code cleaned up later, restored APIs and rolled-back upgrades, and
|
|
271
|
+
proposes rules with the evidence. `--github` also reads recent PR review comments.
|
|
272
|
+
|
|
273
|
+
## Sandbox
|
|
274
|
+
|
|
275
|
+
`covenant sandbox` runs the agent in Docker, in three containers on a private network with no
|
|
276
|
+
route to the internet:
|
|
277
|
+
- **agent:** your repo and Claude Code (or any command after `--`);
|
|
278
|
+
- **hooks:** `covenant serve`, holding the task's state in a volume the agent can't see;
|
|
279
|
+
- **proxy:** the only way out, and only to `api.anthropic.com`, the hosts in your `allow_hosts`
|
|
280
|
+
rules and `--allow` hosts. Everything else gets a 403.
|
|
281
|
+
|
|
282
|
+
So an agent that dodges a command rule (say, by writing the command into a script) still can't
|
|
283
|
+
reach a host that isn't allowed, or touch Covenant's state. `covenant sandbox --print` writes
|
|
284
|
+
the files and shows the `docker compose` commands without running them. One limit: the hook
|
|
285
|
+
token is in the agent's settings, so a determined agent could post made-up hook events. The
|
|
286
|
+
server still checks commits, pushes and diffs itself, but a made-up "tests passed" would count;
|
|
287
|
+
run `covenant test` from outside when that matters.
|
|
288
|
+
|
|
289
|
+
## Hook server
|
|
290
|
+
|
|
291
|
+
`covenant serve --install` runs Covenant as a long-lived local server.
|
|
292
|
+
- **Claude Code** uses HTTP hooks to reach it at `/hook`.
|
|
293
|
+
- **Git** hooks call it with `curl`, and refuse the commit if it's unreachable.
|
|
294
|
+
|
|
295
|
+
State and snapshots then live with the server instead of wherever the agent runs, which is
|
|
296
|
+
the building block for running agents in a container. Requests need a bearer token created at
|
|
297
|
+
start; that keeps other local processes out, but not an agent that can read the hook settings.
|
|
298
|
+
|
|
299
|
+
## VS Code
|
|
300
|
+
|
|
301
|
+
`vscode-extension/` adds a Covenant panel, the current violations in Problems, a 🔒 badge on
|
|
302
|
+
protected files, and commands to compile rules, approve them and run tests. It updates live as
|
|
303
|
+
an agent's hooks record events. Its checks never change files. Build it with `npm run package`
|
|
304
|
+
and install the `.vsix` (see `vscode-extension/README.md`).
|
|
305
|
+
|
|
306
|
+
## CI
|
|
307
|
+
|
|
308
|
+
```yaml
|
|
309
|
+
# .github/workflows/covenant.yml
|
|
310
|
+
on: pull_request
|
|
311
|
+
permissions:
|
|
312
|
+
contents: read
|
|
313
|
+
pull-requests: write # for the comments
|
|
314
|
+
jobs:
|
|
315
|
+
covenant:
|
|
316
|
+
runs-on: ubuntu-latest
|
|
317
|
+
steps:
|
|
318
|
+
- uses: actions/checkout@v4
|
|
319
|
+
with: { fetch-depth: 0 }
|
|
320
|
+
- uses: visweshdev/Covenant@main
|
|
321
|
+
# with: { comment: "false", run-tests: "false", agent: payments }
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
The action comments on the exact lines that break a rule (once; re-runs don't repeat a
|
|
325
|
+
comment) and keeps one summary comment on the PR up to date. Problems with no changed line to
|
|
326
|
+
point at, like a deleted protected file, go in the summary. Without the action:
|
|
327
|
+
`covenant ci --format github --comment` does the same with `GITHUB_TOKEN` set.
|
|
328
|
+
|
|
329
|
+
How the CI check judges a pull request:
|
|
330
|
+
- The rules come from the **base** commit, so a PR can't weaken them; a PR that changes `covenant.yaml` is flagged for human review.
|
|
331
|
+
- API and migration checkers compare against the base.
|
|
332
|
+
- Protected files are checked against the diff.
|
|
333
|
+
- Test commands run on the PR's final state.
|
|
334
|
+
|
|
335
|
+
## Commands
|
|
336
|
+
|
|
337
|
+
| Command | What it does |
|
|
338
|
+
|---|---|
|
|
339
|
+
| `covenant compile "<instruction>"` | Writes `covenant.yaml`. Flags: `--pack`, `--offline`, `--backend`, `--no-review`, `--unattended`, `--answer Q1=2`, `--dry-run`, `--yes` |
|
|
340
|
+
| `covenant packs` | Lists the rule packs |
|
|
341
|
+
| `covenant suggest` | Proposes rules from the repo's history (`--github` adds PR review comments) |
|
|
342
|
+
| `covenant explain` | Why something was blocked and what can be done (`-n`, `--format json`) |
|
|
343
|
+
| `covenant snapshots` / `snapshot` / `undo [ID]` | Lists, takes and restores working-tree restore points |
|
|
344
|
+
| `covenant alerts [test]` | Shows the alert settings, or sends a test alert |
|
|
345
|
+
| `covenant sandbox [-- cmd]` | Runs the agent in Docker with the internet and Covenant's state out of reach (`--allow`, `--print`) |
|
|
346
|
+
| `covenant init` | Validates, installs git and Claude Code hooks, starts a session (`--no-fast-hooks`) |
|
|
347
|
+
| `covenant start` | Approves the current `covenant.yaml` and begins a task |
|
|
348
|
+
| `covenant amend "<instruction>"` | Adds rules mid-task, keeping the history; only additions are accepted. Same flags as `compile` |
|
|
349
|
+
| `covenant test` / `check` / `status` | Runs the declared tests / every check / shows the state |
|
|
350
|
+
| `covenant ci` | Checks a pull request (`--base`, `--format github\|json\|text`, `--no-tests`, `--comment`) |
|
|
351
|
+
| `covenant mcp` | Runs the MCP server |
|
|
352
|
+
| `covenant serve` | Runs the hook server (`--install` points Claude Code and git at it) |
|
|
353
|
+
| `covenant dashboard` | Opens the local dashboard, where rules can be edited and approved (`--read-only`) |
|
|
354
|
+
| `covenant daemon` | The background process behind the fast hooks (started automatically) |
|
|
355
|
+
| `covenant bench run` / `report` | Runs and scores CovenantBench (see `bench/README.md`) |
|
|
356
|
+
|
|
357
|
+
Exit codes: 0 clean, 1 violations (the agent should revise), 2 needs a human, 3 bad setup.
|
|
358
|
+
|
|
359
|
+
Compiling with Claude reads `ANTHROPIC_API_KEY`, or uses your Claude Code login when it isn't set. If `ANTHROPIC_BASE_URL` points somewhere other
|
|
360
|
+
than Anthropic (agent CLIs and proxies often export it), `compile` warns you; set
|
|
361
|
+
`COVENANT_ANTHROPIC_BASE_URL=https://api.anthropic.com` to override it for Covenant only.
|
|
362
|
+
|
|
363
|
+
## Safety model
|
|
364
|
+
|
|
365
|
+
- State lives outside the repo, in `~/.covenant/workspaces/<repo>-<hash>` (set `COVENANT_HOME` to move it). A file lock keeps parallel hooks from corrupting it.
|
|
366
|
+
- The approved Covenant is pinned when a session starts. If `covenant.yaml`, the git hooks or the Claude settings change, it's reported as an `INTEGRITY` violation, and so is `disableAllHooks` or `core.hooksPath`.
|
|
367
|
+
- A verifier that can't run blocks rather than passes.
|
|
368
|
+
|
|
369
|
+
**Limits.** Outside the sandbox, Covenant runs as your user. An agent with a shell could still
|
|
370
|
+
edit its state folder directly. That gets detected, but it isn't prevented; `covenant sandbox`
|
|
371
|
+
prevents it. Effects are found by comparing hashes on every event, not by kernel events. SQLite
|
|
372
|
+
databases are compared row by row; for other databases, Covenant sees the SQL the agent runs
|
|
373
|
+
(commands, `.sql` files, database tools) and migrations, but not queries the app makes on its own.
|
|
374
|
+
|
|
375
|
+
## Development
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
pip install -e ".[dev]"
|
|
379
|
+
npm install --prefix /tmp/ts typescript@5.6.3 # for the TypeScript checker tests
|
|
380
|
+
COVENANT_TYPESCRIPT=/tmp/ts/node_modules/typescript python -m pytest -q
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Layout of `src/covenant/`:
|
|
384
|
+
- `ir.py`: the rule format;
|
|
385
|
+
- `policy.py`: team policies;
|
|
386
|
+
- `runtime.py`, `monitors/` and `verifiers/`: enforcement;
|
|
387
|
+
- `compiler/`;
|
|
388
|
+
- `integrations/`: Claude Code and MCP;
|
|
389
|
+
- `ci.py`, `server.py`, `dashboard.py` and `cli.py`;
|
|
390
|
+
- `bench/`: CovenantBench.
|
|
391
|
+
|
|
392
|
+
The worked example from the proposal is in `examples/mylib`. The benchmark tasks are in
|
|
393
|
+
`bench/tasks/`, and the VS Code extension is in `vscode-extension/`.
|
|
394
|
+
|
|
395
|
+
## Not built yet
|
|
396
|
+
|
|
397
|
+
- **The sandbox hasn't run in Docker yet:** its compose file, images and allowlist proxy are
|
|
398
|
+
built and tested (the proxy for real, over sockets), but this project's development machine
|
|
399
|
+
has no Docker, so the three containers haven't been started together.
|
|
400
|
+
- **Live database proxy:** row-level rollback of SQL as it runs against Postgres or MySQL,
|
|
401
|
+
including queries the app makes on its own. Destructive SQL the agent runs is already refused
|
|
402
|
+
(`destructive_sql`), and SQLite is guarded row by row. It needs a database server to test against.
|
|
403
|
+
- **A real-repo CovenantBench:** the harness, metrics and six synthetic tasks exist. The
|
|
404
|
+
proposal's 60–200 tasks from real repos, using commits after the models' training cutoff and
|
|
405
|
+
with annotated ground truth, are curation work.
|
|
406
|
+
- **Publishing:** `.github/workflows/release.yml` publishes to PyPI and the VS Code Marketplace
|
|
407
|
+
on a `v*` tag, once the PyPI trusted publisher and the `VSCE_PAT` secret are set up.
|
|
408
|
+
|
|
409
|
+
## Contributing and license
|
|
410
|
+
|
|
411
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and tests, and [SECURITY.md](SECURITY.md) to
|
|
412
|
+
report a way around Covenant. Covenant is released under the [MIT License](LICENSE).
|