Human-in-the-loop approval workflows: policy rules, request lifecycle, peer pairing codes
Project description
nodus-approvals
Human-in-the-loop approval workflows for Nodus AI systems.
Policy-driven action gating with auto/deny/require/pairing modes, a full request lifecycle, and cryptographic peer-pairing codes. No required external dependencies — pure stdlib.
Status: v0.1.0 — prepared, not yet published.
Install
pip install nodus-approvals
What it provides
| Component | Purpose |
|---|---|
ApprovalPolicy / ApprovalRule |
fnmatch-pattern rules; first match wins |
ApprovalRequest / ApprovalResult |
Pending action + decision record |
InMemoryApprovalStore |
Thread-safe request storage |
ApprovalGate |
check / approve / deny / poll lifecycle |
PairingStore / generate_code |
6-digit code exchange for peer pairing |
Quick start
from nodus_approvals import ApprovalGate, ApprovalPolicy, ApprovalRule, ApprovalMode
policy = ApprovalPolicy(rules=[
ApprovalRule(action_pattern="admin.*", mode=ApprovalMode.REQUIRE),
ApprovalRule(action_pattern="read.*", mode=ApprovalMode.AUTO),
ApprovalRule(action_pattern="*", mode=ApprovalMode.DENY),
])
gate = ApprovalGate(policy=policy)
result = gate.check("read.memory", requester_id="u1")
# result.approved == True (matched AUTO rule)
result = gate.check("admin.delete", requester_id="u1")
# result.approved == False, result.pending == True (REQUIRE — needs human)
gate.approve(result.request_id, approver_id="admin-1")
Approval modes
| Mode | Behaviour |
|---|---|
AUTO |
Immediately approved; no human required |
DENY |
Immediately denied |
REQUIRE |
Creates a pending ApprovalRequest; blocks until approved or denied |
PAIRING |
Requires a valid pairing code exchange before approval |
ApprovalPolicy
Rules are evaluated in order; the first matching rule wins. Patterns use
fnmatch — * matches any sequence, ? matches one character.
policy = ApprovalPolicy(rules=[
ApprovalRule("payments.*", ApprovalMode.REQUIRE, approver_ids=["finance"]),
ApprovalRule("reports.*", ApprovalMode.AUTO),
ApprovalRule("*", ApprovalMode.DENY),
])
policy.evaluate(action) returns the matching ApprovalRule (or the default
DENY rule if no pattern matches).
ApprovalGate
gate = ApprovalGate(policy=policy, store=my_store) # store defaults to InMemory
result = gate.check("some.action", requester_id="u1", context={"key": "val"})
# result.approved — True/False
# result.pending — True if REQUIRE mode and awaiting human decision
# result.request_id — present when pending
gate.approve(request_id, approver_id="approver-1", reason="looks good")
gate.deny(request_id, approver_id="approver-1", reason="not authorised")
gate.poll(request_id) # ApprovalResult | None — check current decision
Pairing codes
from nodus_approvals import PairingStore, generate_code
store = PairingStore(code_length=6, ttl_seconds=300)
code = store.issue(peer_id="peer-abc") # e.g. "847291"
entry = store.validate(code) # PairingEntry | None
store.approve(code, approver_id="admin-1") # mark as approved
generate_code(length=6) produces a cryptographically random numeric code.
Expired entries are automatically excluded from validate.
InMemoryApprovalStore
from nodus_approvals import InMemoryApprovalStore, ApprovalRequest
store = InMemoryApprovalStore()
req = ApprovalRequest(action="admin.delete", requester_id="u1")
store.save(req)
store.get(req.id)
store.list_pending()
store.list_by_requester("u1")
Design
- No required dependencies. Pure stdlib (
fnmatch,secrets,threading,dataclasses,datetime,uuid). - Thread-safe.
InMemoryApprovalStoreandPairingStoreusethreading.Lock. - Pluggable storage. Any class satisfying the
ApprovalStoreprotocol works.
Development
pip install -e ".[dev]"
pytest tests/ -q
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nodus_approvals-0.1.0.tar.gz.
File metadata
- Download URL: nodus_approvals-0.1.0.tar.gz
- Upload date:
- Size: 11.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35452b0f75d4bf303d6556bca2a2e1547f4162a18ceb285c11bb10fb2b6ca681
|
|
| MD5 |
f82704cc75984f290c4a2c8bda84e894
|
|
| BLAKE2b-256 |
3639447311de07cba183a1b26df0e3302df376a30423c9348d5f7d47e21e8d2f
|
File details
Details for the file nodus_approvals-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nodus_approvals-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b239786c1135214fdb6a31be3937e013e93a04aa634f00398437f4922ec67e4
|
|
| MD5 |
be453850e86ee30aa183a007c97a3299
|
|
| BLAKE2b-256 |
65937f3c38568c97c29adea0d68867a60fa23e81865160f831e9e0a46e080bc1
|