agent-safe-runner 0.4.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.
Files changed (35) hide show
  1. agent_safe_runner-0.4.0/.github/ISSUE_TEMPLATE/bug_report.yml +28 -0
  2. agent_safe_runner-0.4.0/.github/workflows/ci.yml +32 -0
  3. agent_safe_runner-0.4.0/.github/workflows/publish.yml +72 -0
  4. agent_safe_runner-0.4.0/.gitignore +14 -0
  5. agent_safe_runner-0.4.0/CHANGELOG.md +72 -0
  6. agent_safe_runner-0.4.0/CONTRIBUTING.md +44 -0
  7. agent_safe_runner-0.4.0/LICENSE +21 -0
  8. agent_safe_runner-0.4.0/PKG-INFO +273 -0
  9. agent_safe_runner-0.4.0/README.md +245 -0
  10. agent_safe_runner-0.4.0/ROADMAP.md +37 -0
  11. agent_safe_runner-0.4.0/SECURITY.md +25 -0
  12. agent_safe_runner-0.4.0/docs/architecture.md +87 -0
  13. agent_safe_runner-0.4.0/docs/getting-started.md +195 -0
  14. agent_safe_runner-0.4.0/docs/mcp.md +134 -0
  15. agent_safe_runner-0.4.0/docs/migration-0.3.md +70 -0
  16. agent_safe_runner-0.4.0/docs/publishing.md +83 -0
  17. agent_safe_runner-0.4.0/docs/threat-model.md +40 -0
  18. agent_safe_runner-0.4.0/policy.example.json +13 -0
  19. agent_safe_runner-0.4.0/pyproject.toml +43 -0
  20. agent_safe_runner-0.4.0/scripts/check_release.py +55 -0
  21. agent_safe_runner-0.4.0/src/agent_safe_runner/__init__.py +3 -0
  22. agent_safe_runner-0.4.0/src/agent_safe_runner/__main__.py +5 -0
  23. agent_safe_runner-0.4.0/src/agent_safe_runner/audit.py +126 -0
  24. agent_safe_runner-0.4.0/src/agent_safe_runner/cli.py +156 -0
  25. agent_safe_runner-0.4.0/src/agent_safe_runner/core.py +531 -0
  26. agent_safe_runner-0.4.0/src/agent_safe_runner/errors.py +32 -0
  27. agent_safe_runner-0.4.0/src/agent_safe_runner/mcp_server.py +170 -0
  28. agent_safe_runner-0.4.0/src/agent_safe_runner/policy.py +121 -0
  29. agent_safe_runner-0.4.0/src/agent_safe_runner/redaction.py +56 -0
  30. agent_safe_runner-0.4.0/tests/test_approval.py +340 -0
  31. agent_safe_runner-0.4.0/tests/test_cli.py +56 -0
  32. agent_safe_runner-0.4.0/tests/test_cli_approval.py +57 -0
  33. agent_safe_runner-0.4.0/tests/test_core.py +188 -0
  34. agent_safe_runner-0.4.0/tests/test_mcp.py +146 -0
  35. agent_safe_runner-0.4.0/tests/test_optional_mcp.py +23 -0
@@ -0,0 +1,28 @@
1
+ name: Bug report
2
+ description: Report a reproducible defect
3
+ title: "[Bug]: "
4
+ labels: [bug]
5
+ body:
6
+ - type: textarea
7
+ attributes:
8
+ label: What happened?
9
+ description: Include the expected and observed behavior.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ attributes:
14
+ label: Reproduction
15
+ description: Provide the smallest safe reproduction without credentials or private data.
16
+ validations:
17
+ required: true
18
+ - type: input
19
+ attributes:
20
+ label: Version and operating system
21
+ validations:
22
+ required: true
23
+ - type: checkboxes
24
+ attributes:
25
+ label: Safety check
26
+ options:
27
+ - label: I removed credentials, tokens, cookies, and private paths from this report.
28
+ required: true
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_call:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, windows-latest]
17
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
18
+ runs-on: ${{ matrix.os }}
19
+ steps:
20
+ - uses: actions/checkout@v5
21
+ - uses: actions/setup-python@v6
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+ cache: pip
25
+ - run: python -m pip install ".[dev]"
26
+ - run: agent-safe --version
27
+ - run: python -m agent_safe_runner --version
28
+ - run: python -m pytest -q
29
+ - name: Install optional MCP adapter
30
+ run: python -m pip install ".[mcp]"
31
+ - name: Test real MCP stdio client
32
+ run: python -m pytest tests/test_mcp.py -q
@@ -0,0 +1,72 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ publish:
7
+ description: "Publish to PyPI (requires configured Trusted Publisher); false only validates artifacts"
8
+ type: boolean
9
+ required: true
10
+ default: false
11
+ release:
12
+ types: [published]
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ concurrency:
18
+ group: pypi-publish
19
+ cancel-in-progress: false
20
+
21
+ jobs:
22
+ test:
23
+ if: github.event_name == 'release' || github.ref == 'refs/heads/main'
24
+ uses: ./.github/workflows/ci.yml
25
+
26
+ build:
27
+ needs: test
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v5
31
+ with:
32
+ persist-credentials: false
33
+ - uses: actions/setup-python@v6
34
+ with:
35
+ python-version: "3.11"
36
+ - run: python -m pip install build twine pipx
37
+ - run: python -m build
38
+ - name: Validate package metadata, contents, and release tag
39
+ env:
40
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
41
+ run: python scripts/check_release.py dist
42
+ - run: python -m twine check --strict dist/*
43
+ - name: Verify pipx installation of the exact wheel
44
+ env:
45
+ PIPX_HOME: ${{ runner.temp }}/agent-safe-pipx
46
+ PIPX_BIN_DIR: ${{ runner.temp }}/agent-safe-bin
47
+ run: |
48
+ python -m pipx install --python "$(command -v python)" dist/*.whl
49
+ "$PIPX_BIN_DIR/agent-safe" --version
50
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
51
+ with:
52
+ name: python-distributions
53
+ path: dist/
54
+ if-no-files-found: error
55
+ retention-days: 14
56
+
57
+ publish:
58
+ needs: build
59
+ if: github.event_name == 'release' || inputs.publish == true
60
+ runs-on: ubuntu-latest
61
+ environment:
62
+ name: pypi
63
+ url: https://pypi.org/project/agent-safe-runner/
64
+ permissions:
65
+ id-token: write
66
+ steps:
67
+ - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
68
+ with:
69
+ name: python-distributions
70
+ path: dist/
71
+ - name: Publish verified distributions using short-lived OIDC credentials
72
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ .coverage
5
+ .ruff_cache/
6
+ build/
7
+ dist/
8
+ *.egg-info/
9
+ *.sqlite3
10
+ *.sqlite3-*
11
+ audit.jsonl
12
+ *.jsonl.lock
13
+ agent-safe-policy.json
14
+ .venv/
@@ -0,0 +1,72 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.4.0] - 2026-09-03
8
+
9
+ ### Added
10
+
11
+ - Optional local stdio MCP interface: submit_command, get_job, list_jobs, assess_job, verify_audit.
12
+ - Strict bounded input schemas, MCP source labels, namespaced idempotency keys, redacted errors, and per-request policy reload.
13
+ - Read-only SQLite access for MCP inspection; approval/execution remain separate operator actions.
14
+ - Real subprocess MCP client tests, core-only dependency checks, and optional-extra CI coverage.
15
+ - PyPI Trusted Publishing workflow with cross-platform tests, artifact validation, pipx smoke test, and isolated OIDC publishing job.
16
+ - MCP setup and first-time PyPI publication documentation. The workflow alone does not mean PyPI publication has completed.
17
+
18
+ ## [0.3.0] - 2026-09-02
19
+
20
+ ### Added
21
+
22
+ - Pending-by-default approval, operator label, decision time/reason, and proposal source.
23
+ - `inbox`, read-only `assess`, explicit `approve` / `deny`, and `list --approval`.
24
+ - Transactional decision checks and redacted audit intents; audit append failure rolls back a decision.
25
+ - Migration checklist and regression tests for approval, concurrent decisions, and old queues.
26
+
27
+ ### Changed
28
+
29
+ - **Breaking:** execution and claims require approval as well as policy allowance.
30
+ - Old queued/retry-wait jobs and expired running jobs require review after migration.
31
+ - Manual retry (including dead-letter jobs) clears approval; automatic retries retain it.
32
+ - New jobs store an absolute working directory even when `--cwd` is omitted.
33
+ - Argument prefixes are case-sensitive; review policies that relied on case folding.
34
+
35
+ ### Fixed
36
+
37
+ - Missing executable names no longer match each other; POSIX executable paths retain case sensitivity.
38
+ - Execution uses the resolved executable path instead of searching again in the job directory.
39
+ - Process-start failures release the lease and follow the bounded retry policy.
40
+ - Workers recover expired leases even when no other queued job exists.
41
+ - Cancellation and manual retry use conditional state updates to avoid overwriting a concurrent claim.
42
+
43
+ ## [0.2.1] - 2026-08-28
44
+
45
+ ### Added
46
+
47
+ - End-user installation, upgrade, uninstall, troubleshooting, and first-run instructions.
48
+ - `agent-safe --version` and `python -m agent_safe_runner` entry points.
49
+ - A harmless `python --version` rule in the generated sample policy.
50
+
51
+ ### Changed
52
+
53
+ - Package metadata now links to the Umefor Labs repository, documentation, and issue tracker.
54
+ - CI action runtimes were updated and now include an installed-command smoke test.
55
+
56
+ ## [0.2.0] - 2026-08-28
57
+
58
+ ### Added
59
+
60
+ - Deny-by-default command policy with prefixes, working roots, argument denials, and execution limits.
61
+ - Atomic job leases, expired-lease recovery, bounded retry with backoff, cancellation, and manual retry.
62
+ - Secret-like argument rejection, minimal child environment, output redaction, and output limits.
63
+ - Hash-chained JSONL audit verification.
64
+ - Structured CLI commands for policy initialization, queue inspection, execution, workers, cancellation, retry, and audit verification.
65
+ - Migration support for databases created by `0.1.x`.
66
+ - Cross-platform CI configuration, threat model, security policy, and contributing guide.
67
+
68
+ ## [0.1.0] - 2026-08-28
69
+
70
+ ### Added
71
+
72
+ - Initial SQLite queue, idempotent submission, dry run, execution, JSONL audit, and CLI.
@@ -0,0 +1,44 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve `agent-safe-runner`.
4
+
5
+ ## Development setup
6
+
7
+ ```bash
8
+ python -m venv .venv
9
+ ```
10
+
11
+ Activate it in PowerShell on Windows:
12
+
13
+ ```powershell
14
+ .\.venv\Scripts\Activate.ps1
15
+ ```
16
+
17
+ Or on macOS/Linux:
18
+
19
+ ```bash
20
+ source .venv/bin/activate
21
+ ```
22
+
23
+ Then install and test (repeat the install after changing package metadata):
24
+
25
+ ```bash
26
+ python -m pip install -e ".[dev]"
27
+ python -m pytest
28
+ ```
29
+
30
+ Keep runtime dependencies in the Python standard library unless a new dependency has a clear security and maintenance benefit.
31
+
32
+ ## Pull requests
33
+
34
+ 1. Open an issue before a large behavior or schema change.
35
+ 2. Add focused tests for changed behavior.
36
+ 3. Preserve deny-by-default execution and backward-compatible database migration.
37
+ 4. Do not add examples containing real credentials, tokens, cookies, or private paths.
38
+ 5. Update the README and changelog when user-facing behavior changes.
39
+
40
+ Security-sensitive changes should include the threat being addressed, assumptions, failure mode, and test evidence.
41
+
42
+ ## Commit style
43
+
44
+ Use a short imperative subject, for example `Reject secrets before persistence`. Keep unrelated changes in separate commits.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JARVIS contributors
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,273 @@
1
+ Metadata-Version: 2.5
2
+ Name: agent-safe-runner
3
+ Version: 0.4.0
4
+ Summary: A local-first, auditable job runner for AI-agent automation
5
+ Project-URL: Homepage, https://github.com/umefor-labs/agent-safe-runner
6
+ Project-URL: Documentation, https://github.com/umefor-labs/agent-safe-runner/blob/main/docs/getting-started.md
7
+ Project-URL: Issues, https://github.com/umefor-labs/agent-safe-runner/issues
8
+ Project-URL: Source, https://github.com/umefor-labs/agent-safe-runner
9
+ Author: Umefor Labs
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,automation,job-queue,local-first,security
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: License :: OSI Approved :: MIT License
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: Programming Language :: Python :: 3.14
21
+ Requires-Python: >=3.11
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=8; extra == 'dev'
24
+ Provides-Extra: mcp
25
+ Requires-Dist: jsonschema<5,>=4.20; extra == 'mcp'
26
+ Requires-Dist: mcp<3,>=2.1; extra == 'mcp'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # agent-safe-runner
30
+
31
+ [![CI](https://github.com/umefor-labs/agent-safe-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/umefor-labs/agent-safe-runner/actions/workflows/ci.yml)
32
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
33
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
34
+
35
+ `agent-safe-runner` is a small, local-first queue for automation commands proposed by AI agents. It stores jobs in SQLite, requires a separate approval decision and an explicit command policy before execution, and writes a redacted JSONL audit trail.
36
+
37
+ The project is intentionally narrow: it helps a local operator control which commands may run, when they may run, and what evidence is retained afterward.
38
+
39
+ > [!WARNING]
40
+ > This project is an execution gate, not an operating-system sandbox. Run workers with a low-privilege account and use containers or OS isolation for untrusted code.
41
+
42
+ ## Why it exists
43
+
44
+ Agent workflows often grow from scripts into unattended queues. At that point, a plain `subprocess.run()` leaves important questions unanswered:
45
+
46
+ - Was the command explicitly allowed?
47
+ - Who reviewed it before execution?
48
+ - Could two workers run the same job?
49
+ - Did a retry happen, and why?
50
+ - Did logs accidentally store a token?
51
+ - Can the operator verify the event history?
52
+
53
+ This runner makes those controls explicit without adding a service, broker, or cloud dependency.
54
+
55
+ ## Features
56
+
57
+ - Deny-by-default JSON policy with command-prefix and working-directory rules
58
+ - Approval inbox, read-only assessment, and explicit approve/deny decisions
59
+ - Dry run by default; real execution requires approval, policy allowance, and `--execute`
60
+ - SQLite queue with idempotency keys and fail-closed schema migration from `0.1.x` / `0.2.x`
61
+ - Atomic leases, expired-lease recovery, bounded retries, and exponential backoff
62
+ - Job cancellation, manual retry, status filtering, and one-pass worker mode
63
+ - Secret-like argument rejection before persistence
64
+ - Minimal child-process environment and redacted output capture
65
+ - Append-only JSONL audit events with a verifiable SHA-256 hash chain
66
+ - Structured JSON output and errors for scripting
67
+ - Optional stdio MCP adapter with proposal/read-only tools; no approval or execution tools
68
+ - Standard-library runtime with no required third-party dependencies
69
+
70
+ ## Install
71
+
72
+ Python 3.11 or newer is required.
73
+
74
+ Install the latest version directly from GitHub:
75
+
76
+ ```bash
77
+ python -m pip install "https://github.com/umefor-labs/agent-safe-runner/archive/refs/heads/main.zip"
78
+ ```
79
+
80
+ Confirm that the command is available:
81
+
82
+ ```bash
83
+ agent-safe --version
84
+ ```
85
+
86
+ If your system does not expose the `agent-safe` command after installation,
87
+ use `python -m agent_safe_runner` in its place.
88
+
89
+ ### Short installation command (after PyPI publication)
90
+
91
+ Once a release is listed on [PyPI](https://pypi.org/project/agent-safe-runner/),
92
+ users can install it in isolation with:
93
+
94
+ ```bash
95
+ pipx install agent-safe-runner
96
+ ```
97
+
98
+ Until the first PyPI upload is verified, use the GitHub installation above.
99
+ A GitHub push alone does not publish to PyPI; maintainers can follow the
100
+ [publishing checklist](docs/publishing.md).
101
+
102
+ For AI-agent integrations, see the [optional MCP adapter](docs/mcp.md).
103
+
104
+ For an isolated installation with `pipx`, see the
105
+ [getting-started guide](docs/getting-started.md). Contributors should use the
106
+ [development setup](CONTRIBUTING.md).
107
+
108
+ ## Quick start
109
+
110
+ Create a dedicated workspace so the queue, policy, and audit files stay together:
111
+
112
+ ```bash
113
+ mkdir agent-safe-workspace
114
+ cd agent-safe-workspace
115
+ agent-safe init-policy
116
+ ```
117
+
118
+ The generated `agent-safe-policy.json` contains a few example rules. Review it
119
+ before use: `python --version` prints a version, but `pytest` executes project
120
+ code and is appropriate only in a trusted workspace.
121
+
122
+ Queue a command that prints the installed Python version:
123
+
124
+ ```bash
125
+ agent-safe submit --cwd . --timeout 30 -- python --version
126
+ ```
127
+
128
+ The command returns a JSON object. Copy its `id`, then inspect the job and perform
129
+ a dry run. Replace `JOB_ID` below with that value:
130
+
131
+ ```bash
132
+ agent-safe show JOB_ID
133
+ agent-safe assess JOB_ID
134
+ agent-safe run JOB_ID
135
+ ```
136
+
137
+ `assess` returns `allowed`, `reason`, and `matched_rule`. An allowed job is still
138
+ pending approval. `run` without `--execute` remains a dry run.
139
+
140
+ After reviewing the exact command, directory, timeout, and retry limit, record
141
+ your decision. Replace `local-operator` with a label meaningful to you:
142
+
143
+ ```bash
144
+ agent-safe approve JOB_ID --by local-operator --reason "Reviewed version check"
145
+ agent-safe run JOB_ID --execute --worker local-1
146
+ ```
147
+
148
+ `--by` is an audit label, **not authentication**. Anyone with access to the
149
+ approval CLI or writable database can approve jobs; this is a workflow gate.
150
+
151
+ The final JSON should report `"status": "succeeded"`. Verify the audit chain's
152
+ integrity:
153
+
154
+ ```bash
155
+ agent-safe audit-verify
156
+ ```
157
+
158
+ See [Getting started](docs/getting-started.md) for installation isolation,
159
+ upgrades, troubleshooting, and a complete first-run walkthrough.
160
+
161
+ ## Common commands
162
+
163
+ ```bash
164
+ agent-safe list
165
+ agent-safe inbox
166
+ agent-safe list --approval pending
167
+ agent-safe list --status queued --status retry_wait
168
+ agent-safe show JOB_ID
169
+ agent-safe assess JOB_ID
170
+ agent-safe deny JOB_ID --by local-operator --reason "Not needed"
171
+ agent-safe cancel JOB_ID
172
+ agent-safe retry JOB_ID
173
+ agent-safe work --once --execute --worker local-1
174
+ agent-safe audit-verify
175
+ ```
176
+
177
+ Global paths must appear before the subcommand:
178
+
179
+ ```bash
180
+ agent-safe --db /path/to/jobs.sqlite3 --audit /path/to/audit.jsonl --policy /path/to/policy.json list
181
+ ```
182
+
183
+ Everything after `--` in `submit` is stored as an argument vector and is never
184
+ passed through a shell parser. All commands emit JSON. Expected input, state, and
185
+ policy errors return exit code `2` with a stable error code.
186
+
187
+ `work --once --execute` picks only approved jobs. Manual `retry` clears the old
188
+ decision and requires fresh approval; automatic retries keep the existing
189
+ approval for the unchanged job. `deny` cancels a pending job. To stop an already
190
+ approved queued job, use `cancel`.
191
+
192
+ ## Upgrade and uninstall
193
+
194
+ **Upgrading from 0.2.x or older?** Stop all workers and back up your local state
195
+ before installing. Old queued jobs become pending and will not run until
196
+ reviewed. See the [0.3 migration guide](docs/migration-0.3.md).
197
+
198
+ Upgrade to the latest GitHub version:
199
+
200
+ ```bash
201
+ python -m pip install --upgrade "https://github.com/umefor-labs/agent-safe-runner/archive/refs/heads/main.zip"
202
+ ```
203
+
204
+ Remove the command-line application:
205
+
206
+ ```bash
207
+ python -m pip uninstall agent-safe-runner
208
+ ```
209
+
210
+ Uninstalling does not delete your queue, policy, or audit files.
211
+
212
+ ## Policy
213
+
214
+ Execution is denied when the policy file is absent. A policy contains:
215
+
216
+ ```json
217
+ {
218
+ "version": 1,
219
+ "allowed_commands": [
220
+ {"program": "python", "args_prefix": ["--version"]},
221
+ {"program": "python", "args_prefix": ["-m", "pytest"]},
222
+ {"program": "git", "args_prefix": ["status"]}
223
+ ],
224
+ "allowed_working_roots": ["."],
225
+ "denied_arguments": ["--force", "--hard"],
226
+ "environment_allowlist": ["PATH", "PATHEXT", "SYSTEMROOT", "WINDIR", "TEMP", "TMP"],
227
+ "max_timeout_seconds": 300,
228
+ "max_output_chars": 8000
229
+ }
230
+ ```
231
+
232
+ Rules compare resolved executable paths and the case-sensitive beginning of the argument list. Missing executables do not match. An empty `args_prefix` allows every argument for that executable and should be used cautiously.
233
+
234
+ Never place credentials in a command. The runner rejects common secret flags and token formats, but detection cannot identify every secret. Use a dedicated secret provider and grant the worker only the environment variables it needs.
235
+
236
+ ## Job states
237
+
238
+ ```text
239
+ queued -> running -> succeeded
240
+ -> retry_wait -> running
241
+ -> failed
242
+ queued/retry_wait -> cancelled -> queued (manual retry)
243
+ queued/retry_wait -> dead_letter (policy denial)
244
+ ```
245
+
246
+ Approval is separate from execution status: `pending`, `approved`, `denied`, or
247
+ `legacy` for historical records. New jobs start `queued` + `pending`.
248
+ Policy-invalid approved jobs become `dead_letter` without spawning a process.
249
+ Nonzero exits, timeouts, and process-start failures retry up to `max_attempts`.
250
+
251
+ ## Data files
252
+
253
+ - `agent-safe.sqlite3`: queue state, commands, and redacted results
254
+ - `audit.jsonl`: redacted event records and hash-chain metadata
255
+ - `agent-safe-policy.json`: local execution policy
256
+
257
+ These runtime files are ignored by Git. SQLite commands are stored in plain text, so do not submit secrets or place the database in a public or broadly synchronized directory.
258
+
259
+ ## Current limits
260
+
261
+ - The audit chain detects accidental edits; it is not a cryptographic signature and an attacker with write access can rebuild it.
262
+ - Audit appends use advisory file locking on Windows and POSIX; filesystems that ignore advisory locks are unsupported for multi-process writers.
263
+ - Running jobs cannot currently be interrupted by `cancel`; cancellation applies to queued and retry-wait jobs.
264
+ - Approval records are not signatures or user authentication. This gate cannot constrain an agent that already has unrestricted terminal or file access.
265
+ - SQLite state and JSONL audit are separate stores, not a single crash-atomic transaction. See [Architecture](docs/architecture.md).
266
+ - Output limits bound stored text, not peak capture memory; lease recovery is at-least-once, not an exactly-once guarantee for external side effects.
267
+ - MCP is local stdio only. There is no remote API, scheduler daemon, plugin system, or secret-provider integration yet.
268
+
269
+ See [Architecture](docs/architecture.md), [Threat model](docs/threat-model.md), [Roadmap](ROADMAP.md), [Contributing](CONTRIBUTING.md), and [Security policy](SECURITY.md).
270
+
271
+ ## License
272
+
273
+ MIT