Observed since 20 Oct, 23:16 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
agent-safe-runner
A local-first, auditable job runner for AI-agent automation
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.
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.
[!WARNING] 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.
Agent workflows often grow from scripts into unattended queues. At that point, a plain subprocess.run() leaves important questions unanswered:
This runner makes those controls explicit without adding a service, broker, or cloud dependency.
check-policy command--execute0.1.x / 0.2.xPython 3.11 or newer is required.
Install the published release from PyPI in an isolated environment:
pipx install agent-safe-runner
Confirm that the command is available:
agent-safe --version
Need pipx first? Follow the official installation guide.
If agent-safe is not found, run pipx ensurepath and reopen your terminal.
Prefer pip? In an activated virtual environment, use
python -m pip install agent-safe-runner.
For AI-agent integrations, see the optional MCP adapter.
For setup, troubleshooting, and GitHub source installation, see the getting-started guide. Contributors should use the development setup.
Create a dedicated workspace so the queue, policy, and audit files stay together:
mkdir agent-safe-workspace
cd agent-safe-workspace
agent-safe init-policy
agent-safe check-policy
The generated agent-safe-policy.json contains a few example rules. Review it
before use: python --version prints a version, but pytest executes project
code and is appropriate only in a trusted workspace.
Queue a command that prints the installed Python version:
agent-safe submit --cwd . --timeout 30 -- python --version
The command returns a JSON object. Copy its id, then inspect the job and perform
a dry run. Replace JOB_ID below with that value:
agent-safe show JOB_ID
agent-safe assess JOB_ID
agent-safe run JOB_ID
assess returns allowed, reason, and matched_rule. An allowed job is still
pending approval. run without --execute remains a dry run.
After reviewing the exact command, directory, timeout, and retry limit, record
your decision. Replace local-operator with a label meaningful to you:
agent-safe approve JOB_ID --by local-operator --reason "Reviewed version check"
agent-safe run JOB_ID --execute --worker local-1
--by is an audit label, not authentication. Anyone with access to the
approval CLI or writable database can approve jobs; this is a workflow gate.
The final JSON should report "status": "succeeded". Verify the audit chain's
integrity:
agent-safe audit-verify
See Getting started for installation isolation, upgrades, troubleshooting, and a complete first-run walkthrough.
agent-safe check-policy
agent-safe list
agent-safe inbox
agent-safe list --approval pending
agent-safe list --status queued --status retry_wait
agent-safe show JOB_ID
agent-safe assess JOB_ID
agent-safe deny JOB_ID --by local-operator --reason "Not needed"
agent-safe cancel JOB_ID
agent-safe retry JOB_ID
agent-safe work --once --execute --worker local-1
agent-safe audit-verify
Global paths must appear before the subcommand:
agent-safe --db /path/to/jobs.sqlite3 --audit /path/to/audit.jsonl --policy /path/to/policy.json list
Everything after -- in submit is stored as an argument vector and is never
passed through a shell parser. All commands emit JSON. Expected input, state, and
policy errors return exit code 2 with a stable error code.
work --once --execute picks only approved jobs. Manual retry clears the old
decision and requires fresh approval; automatic retries keep the existing
approval for the unchanged job. deny cancels a pending job. To stop an already
approved queued job, use cancel.
Upgrading from 0.2.x or older? Stop all workers and back up your local state before installing. Old queued jobs become pending and will not run until reviewed. See the 0.3 migration guide.
Upgrade a pipx installation to the latest published release:
pipx upgrade agent-safe-runner
Remove the command-line application:
pipx uninstall agent-safe-runner
For a pip installation, use python -m pip install --upgrade agent-safe-runner
or python -m pip uninstall agent-safe-runner inside its virtual environment.
Uninstalling does not delete your queue, policy, or audit files.
After editing a policy, run agent-safe --policy /path/to/policy.json check-policy.
It validates configuration only; it does not approve jobs or prove a command is safe.
Version 0.4.1 rejects unknown fields, duplicate keys, and incorrect JSON types.
An omitted or empty args_prefix still explicitly allows all arguments for that
program, so review such rules carefully. UTF-8 files with or without a BOM work.
Execution is denied when the policy file is absent. A policy contains:
{
"version": 1,
"allowed_commands": [
{"program": "python", "args_prefix": ["--version"]},
{"program": "python", "args_prefix": ["-m", "pytest"]},
{"program": "git", "args_prefix": ["status"]}
],
"allowed_working_roots": ["."],
"denied_arguments": ["--force", "--hard"],
"environment_allowlist": ["PATH", "PATHEXT", "SYSTEMROOT", "WINDIR", "TEMP", "TMP"],
"max_timeout_seconds": 300,
"max_output_chars": 8000
}
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.
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.
queued -> running -> succeeded
-> retry_wait -> running
-> failed
queued/retry_wait -> cancelled -> queued (manual retry)
queued/retry_wait -> dead_letter (policy denial)
Approval is separate from execution status: pending, approved, denied, or
legacy for historical records. New jobs start queued + pending.
Policy-invalid approved jobs become dead_letter without spawning a process.
Nonzero exits, timeouts, and process-start failures retry up to max_attempts.
agent-safe.sqlite3: queue state, commands, and redacted resultsaudit.jsonl: redacted event records and hash-chain metadataagent-safe-policy.json: local execution policyThese 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.
cancel; cancellation applies to queued and retry-wait jobs.See Architecture, Threat model, Roadmap, Contributing, and Security policy.
MIT
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest>=8; extra == "dev" | runtime |
jsonschemaEnvironment{
"extras": "",
"marker": "extra == \"mcp\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | jsonschema<5,>=4.20; extra == "mcp" | runtime |
mcpEnvironment{
"extras": "",
"marker": "extra == \"mcp\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | mcp<3,>=2.1; extra == "mcp" | runtime |
bdist_wheel · 24.82 KB · Python py3
sdist · 47.92 KB · Python source
Shared repository data · GitHub
Observed since 20 Oct, 23:16 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:d69ef0b609abfd44a7dc9d458fa3d429336cd0cc17b6023d0e34aa99455ef516