OutcomeLock
Stop autonomous agents from redoing work that is already complete.
Your agent planned an action. Then the user finished it elsewhere, an email confirmed it, or a canonical tracker changed. The old plan is still queued.
OutcomeLock puts a deterministic evidence check between plan and act:
[SKIP] SUPPRESS tax.ay2026-27.prefiling-documents
Work is superseded; evidence is newer than the plan.
evidence: official-confirmation | email:itr-everification-success
[OK] PROCEED website.measure.search-console
No completion or conflict evidence exists.
No LLM judge. No cloud account. No probabilistic memory lookup.
Why this exists
Agent memory and agent execution state are different systems. A memory backend can correctly recall that work was completed while a stale queue still executes the old task.
OutcomeLock protects that boundary with four rules:
- Every logical outcome has a stable
work_key. - Completion evidence is stored with source, locator, timestamp, confidence, and content hash.
- Terminal assertions are monotonic. The same work key cannot silently reopen.
- Ambiguous, contradictory, or weak evidence fails closed.
30-second demo
pip install "outcomelock @ git+https://github.com/godhiraj-code/outcomelock.git"
outcomelock demo
Open outcomelock-demo/report.html. The demo also emits reusable evidence.json, plan.json, and state.db files.
Replay the generated JSON from any directory:
outcomelock import outcomelock-demo/evidence.json --db outcomelock-demo/imported.db
outcomelock guard outcomelock-demo/plan.json \
--db outcomelock-demo/imported.db \
--report outcomelock-report.html
OutcomeLock returns a non-zero exit code because the generated plan contains stale work.
Coding-agent example
A coding agent queues a production deployment after GitHub Actions already completed it:
outcomelock import examples/deployment-evidence.json --db deployment.db
outcomelock guard examples/deployment-plan.json --db deployment.db
OutcomeLock suppresses release.v1.4.0.deploy.production while allowing the new release.v1.4.1.build outcome. This is the intended planner-to-executor hook: only exit code 0 may reach the executor.
CLI
Record evidence
outcomelock assert tax.ay2026-27.prefiling-documents \
--verdict superseded \
--source official-confirmation \
--locator email:itr-everification-success \
--summary "Return submitted and e-verification succeeded" \
--observed-at 2026-07-19T12:00:00Z
Check before one action
outcomelock check tax.ay2026-27.prefiling-documents \
--planned-at 2026-07-19T09:00:00Z
Guard a complete plan
outcomelock guard plan.json --report report.html
Import evidence in CI
outcomelock import evidence.json
outcomelock guard plan.json
init, assert, and import may create a store. Safety reads (check, guard, history, and status) require an existing initialized store. A missing or mistyped database path returns exit code 1 without creating a file; it never means “no evidence, proceed.”
Decisions and exit codes
| Decision | Meaning | Exit code |
|---|---|---|
proceed |
No completion or conflict evidence exists | 0 |
suppress |
Strong evidence says the outcome is complete or obsolete | 2 |
blocked |
Evidence is ambiguous, contradictory, or below confidence policy | 3 |
| input error | Invalid JSON, work key, timestamp, or schema | 1 |
If a plan contains both suppressed and blocked actions, blocked wins.
Plan format
{
"schema_version": "1.0",
"actions": [
{
"id": "task-42",
"work_key": "learning.module0.cpu.usable",
"title": "Repeat CPU assessment",
"planned_at": "2026-07-19T09:00:00Z"
}
]
}
See schemas/plan.schema.json and schemas/evidence.schema.json.
GitHub Action
- uses: godhiraj-code/outcomelock@v0
with:
plan: agent-plan.json
evidence: completion-evidence.json
- name: Preserve the reconciliation report
if: always()
uses: actions/upload-artifact@v4
with:
name: outcomelock-report
path: outcomelock-report.html
The action imports evidence atomically, writes outcomelock-report.html, and fails when the plan is stale or unresolved. Inputs are passed through environment variables rather than interpolated into shell commands.
Python API
from outcomelock import EvidenceStore, evaluate
store = EvidenceStore(".outcomelock/state.db")
store.require_initialized()
decision = evaluate(
"tax.ay2026-27.prefiling-documents",
store.facts("tax.ay2026-27.prefiling-documents"),
planned_at="2026-07-19T09:00:00Z",
)
if decision.state != "proceed":
raise RuntimeError(decision.reason)
Evidence policy
OutcomeLock intentionally does not decide whether an email, tracker, database row, or user statement is trustworthy. Your adapter records that assertion and provenance. OutcomeLock deterministically applies your confidence threshold and conflict policy.
A newer ambiguous assertion blocks an older completion. Equal-timestamp contradictory verdicts also block. Timestamps are normalized to UTC while preserving microseconds, so distinct observations within one second retain their order. Evidence identity includes every decision-relevant field; corrected timestamps or confidence values are stored as new observations rather than silently discarded. Reopening requires a new work_key, making the changed outcome explicit.
Use cases
- Long-running autonomous agents
- Personal AI assistants and chief-of-staff systems
- Coding-agent task queues
- Browser and workflow automation
- Scheduled research and operations agents
- Human-in-the-loop approval systems
- CI checks for generated execution plans
What OutcomeLock is not
- An agent framework
- A vector memory database
- An LLM evaluation platform
- A cloud observability service
- Proof that the underlying real-world task was completed
It solves one narrow problem: do not act on a plan whose outcome is already satisfied or cannot be safely reconciled.
Development
uv venv
uv pip install -e . --python .venv/Scripts/python.exe
.venv/Scripts/python.exe -m unittest discover -s tests -v
On macOS/Linux use .venv/bin/python.
Security and privacy
Evidence stays in local SQLite by default. HTML output escapes untrusted evidence text. Do not put passwords, tokens, tax identifiers, or document contents in summaries or locators. Use opaque source references instead.
See SECURITY.md.
License
MIT
Metadata
Release files for outcomelock 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| outcomelock-0.1.1.tar.gz | 23.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| outcomelock-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.0 kB
Release files / outcomelock-0.1.1.tar.gz
| Download URL | outcomelock-0.1.1.tar.gz |
|---|---|
| Size | 23.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
177dca6444010c9f2917170d3c05160065a6f88ef154d52e6434cd6189ff2618
|
|
BLAKE2b-256 checksum How to use checksums |
feeb4e74f43a63a7974eda9ff043f534d8a275913cb19cdac93e11c3cc884311
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / outcomelock-0.1.1-py3-none-any.whl
| Download URL | outcomelock-0.1.1-py3-none-any.whl |
|---|---|
| Size | 15.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
efeb21586290f967e0ea6775999170d78d9b7d20d9a3b7fbd510783e59b6ff9f
|
|
BLAKE2b-256 checksum How to use checksums |
9a274a5fb7562b993d8d62efe0b6605f0b210fc9e7bafc027ce75eac2049e114
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Security for outcomelock 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.