Policy Architecture¶
Overview¶
In ArbiterOS, all governance policies can be classified into two fundamental implementation categories: PolicyChecker and PolicyRouter. This classification is derived from the timing and nature of policy enforcement in the agent execution lifecycle.
The Two Policy Categories¶
1. PolicyChecker: Pre-Execution Validation¶
PolicyChecker enforces constraints before a node executes. It answers the question: "Should this transition be allowed?"
- Timing: Runs before the instruction node
- Purpose: Validate preconditions, enforce architectural constraints, prevent forbidden transitions
- Output: Binary decision (PASS/FAIL) with optional violation messages
- Action: If FAIL, execution is blocked and the violation is logged
2. PolicyRouter: Post-Execution Routing¶
PolicyRouter makes decisions after a node executes. It answers the question: "Where should we go next based on the results?"
- Timing: Runs after the instruction node
- Purpose: Dynamic flow control based on execution results (confidence scores, verification outcomes, performance metrics)
- Output: Target node ID or
None(continue normal flow) - Action: If a target is returned, deterministically route execution to that node
Mapping Academic Policies to Implementation¶
Based on the ArbiterKernel paper's policy taxonomy, all policies map to these two categories:
Static Verification (Linter) → TODO¶
Dynamic Transition Verification → PolicyChecker¶
Description: At runtime, the policy engine intercepts impending state transitions, enforcing that a probabilistic step (e.g., GENERATE) must go through a deterministic verification step (e.g., VERIFY) before allowing a high-risk action (e.g., TOOL CALL).
Implementation: PolicyChecker
Why: This enforces preconditions at runtime before execution, ensuring verification occurs before high-risk actions.
Research Examples:
-
"Think then Verify" Workflow
Policyenforce_verify_before_action: If the previous instruction is from Cognitive Core, prohibit the next instruction from being Execution Core unless a Normative Core instruction is inserted between them. -
Stateful Policies
Policies based on the agent's "Managed State" data determine whether to allow an operation.
Example: "Ifhistory[-1].input_state.has_flag('high_risk_user')is true, prohibit TOOL CALL from invoking payment APIs." -
Temporal Policies (TODO)
Enforce time-related constraints, such as rate limiting.
Example: "Allow TOOL CALL to invoke a specific API no more than once every 5 seconds." -
Resource-Based Policies (TODO)
Decide whether to allow high-cost operations based on remaining "Reliability Budget".
Example: "Only allow expensive DECOMPOSE steps when remaining reliability budget is above 50%." -
Domain-Specific Policy (TODO)
For custom cores or instructions, enforce specific preconditions.
Example: "Policy can require that compute-intensive EXECUTE BACKTEST instructions must be preceded by MONITOR RESOURCES check."
Implementation Pattern:
@dataclass
class StateBasedPolicyChecker(PolicyChecker):
"""Checks state conditions before allowing execution."""
def check(self, history: list[History], current_instruction: str) -> bool:
latest_state = history[-1].output_state if history else {}
# Example: Check reliability budget
budget = latest_state.get("reliability_budget", 100)
if current_instruction == "decompose" and budget < 50:
return False
# Example: Check rate limiting
if self._exceeds_rate_limit(history, current_instruction):
return False
return True, ""
Dynamic Result Routing → PolicyRouter¶
Description: Policy checks the output results of probabilistic verification (e.g., LLM-as-judge confidence score) and determines the next routing step based on that score.
Implementation: PolicyRouter
Why: These policies inspect the results of execution (confidence scores, verification outcomes) and dynamically route flow based on those results.
Research Examples:
-
Confidence-Based Escalation
Policy checks the output results of probabilistic verification (e.g., LLM-as-judge confidence score) and determines the next routing step.
Example: "If LLM-as-judge returns a low confidence score (e.g., p<0.8), the policy deterministically triggers an INTERRUPT instruction to pause execution for human review." -
Fallback Routing
Policy checks if an instruction (e.g., VERIFY) output result is "failure"; if so, Arbiter Loop deterministically routes execution to a predefined FALLBACK plan.
Example: After API call failure causesverify_api_responseinstruction to returnresult: 'FAIL', Arbiter Loop intervenes and routes execution toFALLBACK (get_cached_sales_data)instruction. -
Strategic Self-Correction
Policy checks EVALUATE_PROGRESS instruction output results; if the result indicates current path is invalid (e.g., returns 'FAIL' signal), deterministically route execution to REPLAN step.
Example:EVALUATE_PROGRESScheck finds current progress is irrelevant to goal (is_productive: false), Arbiter Loop intervenes and routes execution toREPLANnode to correct strategy. -
Domain-Specific Validation Routing
Policy checks if a custom instruction's output passes specific validation checks before allowing subsequent operations.
Example: "CALCULATE ALPHA output must pass a custom VERIFY BOUNDS check before it can affect (route to) trading."
Implementation Example:
from arbiteros_alpha import PolicyRouter
@dataclass
class MetricThresholdPolicyRouter(PolicyRouter):
"""Routes based on output metrics (e.g., confidence scores)."""
key: str # e.g., "confidence"
threshold: float # e.g., 0.6
target: str # e.g., "generate" (retry node)
def route(self, history: list[History]) -> str | None:
if not history:
return None
latest = history[-1]
metric_value = latest.output_state.get(self.key)
if metric_value is not None and metric_value < self.threshold:
return self.target # Route to retry/fallback node
return None # Continue normal flow
Summary Table¶
| Academic Policy Category | Implementation | Timing | Purpose | Example |
|---|---|---|---|---|
| Static Verification (Linter) | TODO | Before-started | Validate graph structure | Reject GENERATE→TOOL_CALL pattern |
| Dynamic Transition Verification (Think then Verify) | PolicyChecker |
Pre-execution | Enforce preconditions | Require verification before tool calls |
| Stateful Policies | PolicyChecker |
Pre-execution | Check state conditions | Block actions for high-risk users |
| Temporal Policies | PolicyChecker |
Pre-execution | Rate limiting | Limit API calls to 1 per 5 seconds |
| Resource-Based Policies | PolicyChecker |
Pre-execution | Budget management | Block expensive ops when budget low |
| Domain-Specific Policies | PolicyChecker |
Pre-execution | Custom preconditions | Require resource monitoring before backtest |
| Confidence Escalation | PolicyRouter |
Post-execution | Route based on confidence | Retry generation if confidence < 0.8 |
| Fallback Routing | PolicyRouter |
Post-execution | Handle failures | Route to cached data on API failure |
| Strategic Self-Correction | PolicyRouter |
Post-execution | Escape bad paths | Route to REPLAN when unproductive |
| Validation Routing | PolicyRouter |
Post-execution | Conditional continuation | Block trading if bounds check fails |
Extending the Framework¶
To implement custom policies:
For Pre-Execution Constraints: Inherit from PolicyChecker
- Implement the
check()method - Return
(False, reason)to block execution - Use
historyto inspect past state and transitions
For Post-Execution Routing: Inherit from PolicyRouter
- Implement the
route()method - Return a
targetnode ID to redirect flow - Return
Noneto continue normal execution - Inspect the latest
history[-1]for output state and metrics
Example: Building a Complete Policy¶
from arbiteros_alpha import ArbiterOSAlpha, PolicyChecker, PolicyRouter
os = ArbiterOSAlpha()
# Pre-execution: Prevent direct GENERATE→TOOL_CALL
os.add_policy_checker(
HistoryPolicyChecker(
name="think_then_verify",
bad_sequence=[GENERATE, TOOL_CALL]
)
)
# Post-execution: Retry on low confidence
os.add_policy_router(
MetricThresholdPolicyRouter(
name="retry_on_low_confidence",
key="confidence",
threshold=0.7,
target="generate" # Retry the generation step
)
)
This dual-category architecture ensures:
- ✅ Separation of Concerns: Validation logic is separate from routing logic
- ✅ Composability: Mix and match checkers and routers for complex policies
- ✅ Auditability: Each policy has a clear name and documented purpose
- ✅ Extensibility: Easy to add custom policies by inheriting from base classes