agent-change-control is a small Python package for evaluating agent-generated code changes before they become merge candidates.
“Agent-generated patches can pass tests and still be unsafe to merge.”
“Surface policy, isolated sandbox, scorecarding, and strict re-audit before merge.”
“Trusted local/CI evaluation only. Not hostile-code isolation.”
Alpha release. Intended for trusted local/CI evaluation, not hostile-code isolation.
It focuses on a narrow workflow:
- classify the files a proposal wants to touch
- generate a deterministic patch proposal object
- run the proposal in an isolated local workspace
- build a readable scorecard from sandbox results
- perform a strict re-audit before anything is considered merge-eligible
- sanitize reasoning payloads so hidden controller writes are not treated as normal model output
flowchart LR
proposal["proposal"] --> sandbox["sandbox"]
sandbox --> scorecard["scorecard"]
scorecard --> reaudit["re-audit"]
reaudit --> accept["accept"]
reaudit --> review["human_review"]
reaudit --> reject["reject"]
This package is a reusable change-control kernel for trusted local development and CI environments.
It helps answer questions like:
- Is this proposal touching protected surfaces?
- Did the sandboxed checks pass?
- Does this proposal still require human review even if tests passed?
- Does the reasoning payload contain forbidden hidden-controller style directives?
This package is not:
- a hardened sandbox for hostile arbitrary code
- a full repository governance system
- a merge bot
- a guarantee that passing tests means a patch is safe
The sandbox runner is meant for trusted local or CI evaluation of proposed changes. It isolates files and commands from the original source tree, but it does not claim strong containment against malicious code.
from agent_change_control import ProposalEvaluator, ProposalGenerator
generator = ProposalGenerator()
proposal = generator.generate_patch_proposal(
summary="Adjust a proposal draft",
rationale="Exercise the isolated evaluation flow.",
target_files=["proposals/sample.py"],
mode="offline",
file_overrides={"proposals/sample.py": "VALUE = 2\n"},
commands=['python -c "from proposals.sample import VALUE; assert VALUE == 2"'],
)
evaluation = ProposalEvaluator().evaluate(
proposal=proposal,
source_dir=".",
)
print(evaluation.scorecard.verdict)
print(evaluation.strict_reaudit.status)A proposal can pass all sandbox checks and still be ineligible for automatic merge.
Examples:
- it touches protected or offline-only surfaces
- it changes core runtime entry points
- it relies on reasoning payload fields that should never be accepted as ordinary model output
The scorecard therefore distinguishes between:
tests_passedrequires_human_reviewmerge_eligible
The default SurfacePolicy is a generic reference policy, not a private repository rule set:
- online edits to packaging and workflow control files are blocked
- proposal-like paths such as
proposals/,drafts/, andexperiments/are weakly allowed - everything else defaults to offline-only review unless you configure a different policy
You can inject your own policy when generating proposals or validating paths.
SandboxRunner copies files into a temporary workspace, applies proposal overrides there, and runs the requested commands against the copy.
By default it runs in strict mode: if none of the requested paths can be prepared, the run fails instead of silently copying the whole repository.
This preserves the original source tree, but it does not make untrusted code safe. Use it for trusted local evaluation, not as a hostile-code security boundary.
From this directory:
python -m pip install -e .[dev]
python -m pytest -q- examples/accept_patch_flow.py shows an accept path on a weakly allowed surface.
- examples/human_review_patch_flow.py shows a passing sandbox run that still lands in
human_review.