Skip to content

feat(governance): implement agent governance protocol — gates, evidence, charter, SoD, JIT grants#1186

Draft
ohdearquant wants to merge 13 commits into
mainfrom
pr/governance-core
Draft

feat(governance): implement agent governance protocol — gates, evidence, charter, SoD, JIT grants#1186
ohdearquant wants to merge 13 commits into
mainfrom
pr/governance-core

Conversation

@ohdearquant

@ohdearquant ohdearquant commented May 27, 2026

Copy link
Copy Markdown
Owner

Summary

Implements `lionagi.protocols.governance` — a complete agent governance protocol covering policy authoring, runtime enforcement, evidence collection, and session integration.

17 governance modules

DSL & compilation

  • `dsl.py` — CharterDocument schema: agents, constraints, registry, SoD, permissions, trace requirements
  • `charter.py` — CharterParser with YAML security validation (wildcard/exec token rejection, tab prohibition)
  • `compiler.py` — CharterCompiler: YAML charter → runtime GateRegistrations, PolicyPin, SoDRules, TraceExpectations
  • `targets.py` — Runtime types: GateRegistration, PolicyPin, SoDRule, EvidenceRequirement, TraceExpectation
  • `context.py` — OperationContext with budget tracking + contextvar bridge (set/get_operation_context)

Evidence & tracing

  • `evidence.py` — EvidenceChain: append-only SHA-256 hash chain with MUTABLE/PROTECTED/IMMUTABLE tiers
  • `tracing.py` — GovernanceTracer, GovernanceSpan, trace_gate_evaluation, trace_certificate_mint

Enforcement

  • `gates.py` — GateExecutor, GateResult, GateVerdict (ALLOW/DENY/ADVISORY), GovernanceViolationError
  • `sod.py` — SoDEnforcer, SoDViolation for separation-of-duties rules
  • `resolution.py` — PolicyResolver with 4-scope specificity ordering (resource > role > tenant > global)
  • `governed_tool.py` — `@governed_tool` decorator annotating Tool with governance metadata
  • `jit_grant.py` — PermitToken, JITGrantStore, check_jit_grant, jit_gate_override for just-in-time grants
  • `breakglass.py` — BreakGlassSession: timed override with attestation, expiry, and evidence recording
  • `certificate.py` — TaskCertificate with CertificateGrade (FULL/PARTIAL/FAILED)

Session integration

  • `flow_integration.py` — GovernedFlowController wrapping DAG pre/post-op checks
  • `session_integration.py` — `governed_flow()` drop-in for `Session.flow()` with charter governance

Dependency modifications (governance wiring only)

File Change
`protocols/generic/pile.py` `append_only` mode + `PileAppendOnlyError`
`protocols/generic/log.py` `DataLogger.emit()` with LogTier routing; EvidenceChain integration
`protocols/action/tool.py` `governance_meta` field; `func` alias for `func_callable`
`protocols/action/manager.py` `execute_governed()` + evidence sidecar emission
`libs/schema/function_to_schema.py` Handle forward-ref annotations (string annotations)
`operations/operate/operate.py` `ctx` param; `set_operation_context` bridge
`session/branch.py` `evidence_chain` attachment; `emit_evidence()`
`session/session.py` PolicyPin construction in `flow()` when charter attached

Tests: 496 passing

13 test files covering every module + `conftest.py` with contextvar isolation fixture.

Test fixes applied:

  • `tests/governance/conftest.py` — autouse fixture resets `_operation_context_var` after each test (GovernedFlowController sets it without cleanup)
  • `test_charter_dsl.py::test_dsl_module_has_no_top_level_yaml_import` — replaced `sys.modules` poisoning with file-based AST inspection to avoid cross-test module cache corruption

Test plan

  • `uv run pytest tests/governance/ -q` → 496 passed (parallel xdist)
  • `uv run pytest tests/governance/ --override-ini="addopts=" -q` → 496 passed (serial)
  • All pre-commit hooks pass (ruff format, ruff lint, pyupgrade, ast check)

🤖 Generated with Claude Code

ohdearquant and others added 10 commits May 26, 2026 21:48
Existing ADRs 0004–0032: added forward-reference notices pointing
to the governance ADR series (0041-0052). Also fixed pre-existing
markdownlint issues (MD032 blanks-around-lists, MD040 code-fence
language specs, MD028 blockquote blanks).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 0033: Unified Entity State Model (lifecycle × health × delivery)
- 0034: Frontend Data & State Architecture (TanStack + SSE)
- 0035: Design System & Component Library (shadcn/Radix)
- 0039: Knowledge Substrate Minimal Interface (5th Branch manager)

Foundation for the governance ADR series (0041-0052).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Twelve governance ADRs establishing the governed-orchestration
substrate for lionagi:

- 0041: Immutable Evidence Nodes
- 0042: Task Certificate
- 0043: Governed Tool Declaration
- 0044: Tool Gates
- 0045: Break-Glass Protocol
- 0046: JIT Tool Grant
- 0047: Agent Charter
- 0048: Agent Segregation of Duties
- 0049: Log Tier Governance
- 0050: Operation Context
- 0051: Tool Registry Allowlists
- 0052: Policy Resolution

All ADRs use lionagi primitives (Element, Pile, Tool, Branch
managers) as integration points. Status: Proposed — pending
validation via the governance show.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Navigation aids for the ADR corpus — glossary of governance terms
and a reader's guide for navigating the ADR dependency graph.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Automated fix of MD032 (blanks-around-lists), MD040 (code-fence
language), MD058 (blanks-around-tables) across ADRs 0003, 0007,
0010, 0015, 0016, 0018, 0020-0023, 0027. Pure formatting.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ce, charter, SoD, JIT grants

Adds the complete lionagi.protocols.governance package with 17 modules:

Core DSL and compilation:
- dsl.py: CharterDocument, CharterMetadata, ConstraintDef, Enforcement, SodDef, etc.
- charter.py: CharterParser with YAML security checks (wildcard/exec rejection)
- compiler.py: CharterCompiler → CompilationResult with PolicyPin binding
- targets.py: Runtime compiled targets (GateRegistration, PolicyPin, SoDRule, etc.)
- context.py: OperationContext, OperationBudget, PolicyPin with contextvar bridge

Evidence and tracing:
- evidence.py: EvidenceChain (append-only SHA-256 hash chain), EvidenceNode, LogTier
- tracing.py: GovernanceTracer, GovernanceSpan, trace_gate_evaluation, trace_certificate_mint

Enforcement:
- gates.py: GateExecutor, GateResult, GateVerdict, GovernanceViolationError
- sod.py: SoDEnforcer, SoDViolation for separation-of-duties
- resolution.py: PolicyResolver with 4-scope specificity ordering
- governed_tool.py: @governed_tool decorator for tool metadata annotation
- jit_grant.py: PermitToken, JITGrantStore, check_jit_grant, jit_gate_override
- breakglass.py: BreakGlassSession with expiry, attestation, and evidence recording
- certificate.py: TaskCertificate with CertificateGrade (FULL/PARTIAL/FAILED)

Integration:
- flow_integration.py: GovernedFlowController wrapping DAG execution
- session_integration.py: governed_flow() drop-in wrapper for Session.flow()

Dependency modifications (governance hooks only):
- protocols/generic/pile.py: append_only mode + PileAppendOnlyError
- protocols/generic/log.py: DataLogger.emit() with LogTier routing + EvidenceChain wiring
- protocols/action/tool.py: governance_meta field + func alias
- protocols/action/manager.py: execute_governed() + evidence sidecar emission
- libs/schema/function_to_schema.py: handle forward-ref annotations
- operations/operate/operate.py: ctx param + set_operation_context bridge
- session/branch.py: evidence_chain attachment + emit_evidence()
- session/session.py: PolicyPin construction in flow() when charter attached

Tests: 496 passing across 13 test files + conftest.py contextvar isolation fixture.
Test fixes: remove sys.modules poisoning in test_charter_dsl; add noqa for ReAct naming.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
F1 (flow_integration.py): GovernedFlowController now owns its ContextVar
lifecycle. Adds close() (idempotent) that resets _ctx_token, and
__enter__/__exit__ so callers can use `with GovernedFlowController(...)`.
Previously the ContextVar set during __init__ was never reset, causing
OperationContext leaks across sessions on the same thread.

F2 (evidence.py): EvidenceChain.append() is now thread-safe. A
threading.Lock is initialised in model_post_init via object.__setattr__
(bypassing Pydantic's extra="forbid") and acquired around the
tip_hash/node_count read-compute-write sequence. Without this, concurrent
post_op_record() calls from parallel flow ops could fork the hash chain.

F3 (compiler.py): Replace deprecated datetime.datetime.utcnow() with
datetime.datetime.now(tz=datetime.timezone.utc) in CharterCompiler.compile().
Aligns with every other module in the governance package that already uses
timezone-aware datetimes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
governed_flow() now wraps the controller in a `with` block so that
`controller.close()` (which resets the OperationContext ContextVar) is
always called on exit, even when an exception is raised.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e (F10)

F9: governed path in invoke_action() called execute_governed() then also
called function_calling.invoke() — the tool executed twice. Remove the
redundant invoke() after the governed path returns.

F10: pinned_at=datetime.utcnow() produced a naive datetime incompatible
with timezone-aware comparisons. Replace with datetime.now(tz=timezone.utc)
and add timezone to the local import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tionContext resets (F12)

F11: ActionManager.invoke() governed path called execute_governed() but never
     copied the result back onto the original FunctionCalling object, leaving
     its .response=None and .status=PENDING. Now captures the return value and
     sets execution.response + COMPLETED status directly.

F12: set_operation_context() in Session.flow(), Branch.operate(), and
     operate() leaked the ContextVar token — context was never reset after the
     call completed. All three sites now capture the Token and reset it in a
     finally block, ensuring LIFO cleanup even on exceptions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ohdearquant ohdearquant marked this pull request as draft May 27, 2026 23:48
ohdearquant and others added 3 commits May 28, 2026 15:45
…ies enforcement

- Added `session_integration.py` for governed flow execution with optional charter governance.
- Introduced `sod.py` to enforce separation of duties (SoD) rules, maintaining actor records and checking for violations.
- Created `targets.py` to define runtime target types produced by the Charter DSL compiler.
- Developed `tracing.py` for lightweight governance span recording, emitting structured spans for governance events.
- Updated `operate.py`, `manager.py`, `log.py`, `branch.py`, and `session.py` to refactor governance-related imports and ensure compatibility with the new governance structure.
Consolidate governance exception classes into errors.py, move mid-file
imports to top-of-file, and rename session_integration to governed_flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant