Automation Rules Engine
Relevant source files
The following files were used as context for generating this wiki page:
- packages/api/src/test/automationExecutor.test.ts
- packages/api/src/test/automationEvaluator.test.ts
- packages/api/src/services/automationEvaluator.ts
- packages/api/src/test/automationSchema.test.ts
- packages/api/src/test/automationAttemptLifecycle.test.ts
- packages/api/src/services/automationAttemptLifecycle.ts
- packages/api/src/test/automationOnAutomationGate.integration.test.ts
The Automation Rules Engine is an event-driven system within Orcy designed to orchestrate workflows through configurable rules. It allows the system to automatically respond to lifecycle events—such as task rejections, priority changes, or signal postings—by evaluating conditions and executing a sequence of actions. The engine is built with a focus on reliability, providing built-in guards for cooldowns, rate limits, and causal loops.
Sources: README.md, packages/api/src/test/automationSchema.test.ts:117-133
Core Architecture and Lifecycle
The engine operates on a 10-step canonical lifecycle for every rule attempt. This lifecycle ensures that targets are valid, conditions are met, and safety constraints are respected before any side effects occur.
The Rule Attempt Lifecycle
The primary entry point for rule execution is attemptRuleRun. The process follows a strict sequence:
- Normalization: The target entity (Task, Mission, etc.) is validated.
- Cooldown Check: Ensures the rule hasn't run too recently for the specific target.
- Admitted-Attempt Cap: Enforces an hourly limit on successful runs to prevent resource exhaustion.
- Reservation: Starts the run in the database to prevent duplicate processing.
- Validation: Ensures the rule's condition tree is structurally sound.
- Evaluation: Recursively evaluates the condition tree against the current context.
- Causal Guard: Detects infinite loops (cycles) or excessive automation depth.
- Kill Switch: Checks if automation execution is globally or habitat-disabled.
- Action Execution: Runs the configured actions (e.g., notifications, priority changes).
- Terminalization: Updates the run status to a final state (succeeded, failed, skipped).
Sources: packages/api/src/test/automationAttemptLifecycle.test.ts:6-25, packages/api/src/services/automationAttemptLifecycle.ts
Lifecycle Data Flow
The following diagram illustrates the flow of an event through the rule attempt lifecycle.
This diagram shows the sequence of checks performed by the attemptRuleRun service before executing automation actions.
Sources: packages/api/src/test/automationAttemptLifecycle.test.ts:6-25
Condition Evaluation Engine
The evaluation engine is responsible for determining if a rule should fire based on a recursive condition tree.
Condition Types
The engine supports complex logic through nested boolean operators and specific entity checks:
| Type | Description |
|---|---|
always | Matches unconditionally. |
and / or / not | Logic operators for nesting conditions. |
priority_above / priority_below | Compares task priority against a threshold. |
status_in | Checks if a task is in specific states (e.g., claimed, submitted). |
assigned_to | Validates the current assignee of a task. |
overdue_by | Checks if a mission's dueAt is past a certain minute threshold. |
field | Generic operator to check specific fields using equals, contains, greater_than, etc. |
plugin | Dispatches to a third-party plugin for custom evaluation logic. |
Sources: packages/api/src/services/automationEvaluator.ts:44-118, packages/api/src/test/automationEvaluator.test.ts:169-320
Technical Constraints
To ensure system stability, the evaluation engine enforces a strict maximum nesting depth of 5. Exceeding this depth throws a ConditionDepthExceededError. This prevents stack overflows and overly complex rule definitions.
Sources: packages/api/src/services/automationEvaluator.ts:10-21
Action Execution
When a rule's conditions are met, the automationExecutor performs the requested actions. Actions are executed in the order they are defined.
Supported Action Types
notify: Sends a message to recipients (e.g., assignee, creator) based on a template.create_signal: Posts a Pulse signal to the mission board.create_task: Spawns a new task under a mission.change_priority: Updates the priority level of a task.assign/release_assignment: Manages task ownership.request_review: Triggers a review request for a task.call_webhook: Sends a POST request to an external URL (restricted to non-private IPs).mark_risk: Flags a task or mission as being at risk.plugin: Executes a custom action defined in an enrolled plugin.
Sources: packages/api/src/test/automationExecutor.test.ts:135-430, packages/api/src/services/automationExecutor.ts
Composite Execution Outcomes
A rule run containing multiple actions can result in a partial_failed status if some actions succeed while others fail. This allows for granular error reporting in the automation_rule_runs table.
Sources: packages/api/src/test/automationSchema.test.ts:241-265, packages/api/src/test/automationAttemptLifecycle.test.ts:316-339
Safety and Guard Mechanisms
The Rules Engine implements several critical safety features to prevent automation "storms":
Causal Loop Protection
The engine tracks the "provenance" of events. If a rule attempt is triggered by a previous automation run, the engine checks the causal chain.
causal_cycle: Occurs if the same rule is detected earlier in the current chain.causal_depth_limit: Occurs if the chain length exceeds theCAUSAL_DEPTH_LIMIT(default 10).
Sources: packages/api/src/test/automationAttemptLifecycle.test.ts:182-225, packages/api/src/services/automationAttemptLifecycle.ts
Admission Control
- Cooldown: Rules can be configured with
cooldownSecondsto prevent rapid re-firing on the same target. - Hourly Cap: The
maxRunsPerHoursetting limits how many times a rule can reach the execution stage within a rolling window.
Sources: packages/api/src/test/automationSchema.test.ts:98-106, packages/api/src/test/automationAttemptLifecycle.test.ts:392-425
Data Model
The system persists rules and their execution history in two primary tables.
Automation Rules Schema
The automation_rules table stores the configuration for each rule.
| Field | Type | Description |
|---|---|---|
id | Text | Unique identifier. |
habitatId | Text | The scope of the rule. |
trigger | JSON | Trigger type (event or scan) and event type. |
condition | JSON | The nested condition tree. |
actions | JSON | Array of action configurations. |
cooldownSeconds | Integer | Minimum time between runs for a specific target. |
Sources: packages/api/src/test/automationSchema.test.ts:34-60, packages/api/src/db/schema/automation.ts
Automation Rule Runs Schema
The automation_rule_runs table tracks every attempt to execute a rule.
| Field | Type | Description |
|---|---|---|
status | Enum | matched, skipped, succeeded, failed, partial_failed. |
skipReason | Enum | cooldown, rate_limited, condition_false, causal_cycle, disabled. |
conditionResult | JSON | The full evaluation tree with match results for each node. |
actionResults | JSON | Status and error details for each executed action. |
fingerprint | Text | Deterministic string identifying a specific rule, target, and event. |
Sources: packages/api/src/test/automationSchema.test.ts:63-100, packages/api/src/db/schema/automation.ts
Integration with Workflow Gates
The Rules Engine is integrated with the Workflow system through on_automation gates. These gates allow a task to remain blocked until a specific automation rule completes with a designated outcome (e.g., succeeded or skipped). This creates a powerful mechanism for gating human work behind automated checks.
Sources: packages/api/src/test/automationOnAutomationGate.integration.test.ts:1-25, packages/api/src/test/automationOnAutomationGate.integration.test.ts:80-110
The Automation Rules Engine provides a robust framework for agentic coordination, ensuring that automated processes are predictable, safe, and transparently logged within the Orcy habitat.