Autonomy policy (composed, not enum)¶
Per-Thread policy composed from orthogonal axes. Saved compositions are configuration, not types. Sub-threads override DOWN axis-by-axis only. Stage 5 wired the runtime — auto-advance branch resolvers gate every INFERRING_ → AWAITING__CONFIRMATION transition.
Details¶
Saved compositions (named bundles)¶
Common shapes get names. These are CONFIGURATION, not types — adding a new named composition is a YAML edit, not a code change. Threads can deviate from a saved composition without forking it.
end_to_end— auto-advance through inference + confirmation + executing; pause only on risk amplifier.plan_then_review— auto-advance through intent + context confirmations; require user consent on action_approved. This is the default for spawned threads (configurable viathreads.default_autonomy_compositionin config.yaml).hands_off— every event kind requires user input; no auto-advance.
Sub-thread inheritance¶
Children inherit axis-by-axis. Override DOWN (more conservative) is allowed; override UP is not. A parent at hands_off cannot have a child at end_to_end. Enforced at sub-thread spawn time by the decompose Standard Action.
Risk-amplifier safety net¶
When pause_on_risk_amplifier=True, an action's intrinsic amplifiers OR the Thread's risk profile exceeding the policy's thresholds force awaiting_confirmation regardless of auto_advance_states.
Auto-advance branch resolvers (Stage 5 runtime)¶
The FSM table maps each (INFERRING_*, TRIG_INFERENCE_DONE) cell to a branch label (intent_review_or_advance, context_review_or_advance, action_review_or_execute). The engine's default branch resolver delegates to work_buddy.threads.autonomy_branch.resolve_by_label, which reads the thread's effective policy (walking parents) and decides:
- Auto-advance (skip the wait state, go to the next inference target or directly to EXECUTING) iff:
- The would-be wait state is in
policy.auto_advance_states. confidence >= policy.inference_confidence_floor.- The proposal's event kind is NOT in
policy.consent_required_kinds. - (action only) action's irreversibility ≤
policy.irreversibility_threshold. - (action only) action's regret_potential ≤
policy.regret_potential_threshold. - (action only) NOT (
policy.pause_on_risk_amplifierAND action.has_risk_amplifier). -
(action only) action.kind in
policy.allowed_action_kinds. -
Surface (enter the AWAITING_*_CONFIRMATION state) otherwise.
The wait state is never entered when auto-advance applies — its state-entry handlers (notification publish, etc.) never fire. Every decision (positive or negative) is recorded as an auto_advance_decision event with the per-axis trace so the user can audit what the agent decided on its own.
Combined-inference axis (Stage 5)¶
combined_inference: bool (default False) opts the thread into single-LLM-call inference: one InferenceTarget.COMBINED call returns intent + context + action together. The worker records three separate *_inferred events plus a combined_inferred_meta audit event, and walks the FSM through all three INFERRING states with the autonomy resolver gating each step. Combined is an optimization (one call vs three), not a policy bypass — every transition still respects auto_advance_states, confidence floor, and risk thresholds.
Notification surface targeting (Stage 5)¶
Differentiated via work_buddy.threads.resolution_surface._surfaces_for(rr): legitimate user-pause states (AWAITING_CONFIRMATION, clarifications, post-execution review, failed cleanup) fan out across all surfaces (Obsidian + Dashboard + Telegram). The intent/context confirmation states — when reached because confidence was below the floor or the policy is conservative — only land on the dashboard, never on Telegram or Obsidian. Reduces noise without losing visibility.
Mid-process visibility toggle (Stage 5)¶
The dashboard threads list hides AWAITING_INFERENCE / INFERRING_* / EXECUTING / MONITORING / CLEANING_UP states by default (the user has nothing to act on). A 'Show mid-process' toggle (query param include_mid_process=1) surfaces them with a muted style and a display_mode='mid_process' render hint, useful for auditing 'what is the agent doing right now?' and for debugging.
Where this lives in code¶
work_buddy/threads/autonomy.py— saved compositions, override-down validator,default_spawn_policy()config helper.work_buddy/threads/autonomy_branch.py— the runtime resolvers (intent/context/action).work_buddy/threads/fsm.py— branch labels in TRANSITION_TABLE.work_buddy/threads/engine.py— default resolver delegates by label, writes the audit event after state_transition lands.work_buddy/threads/inference.py— TargetSpec forInferenceTarget.COMBINEDwith the merged schema.work_buddy/threads/inference_worker.py—_process_combinedorchestrates the three FSM transitions for a single combined call.work_buddy/threads/resolution_surface.py—_surfaces_fordecides notification fan-out per state.