Automation
Sequences with reply-exit, workflows on domain events, rules conditioned on the audit log. Why automation reads from the event log rather than firing as side-effects on the writer's path, what that costs in latency, and what it gives back in recoverability.
The question that determined the shape of the automation engine: should rules run as side-effects on the writer's path, or as subscribers to a durable event log. A naive automation engine fires rules inline. The operator marks a deal closed-won, the inline handler runs immediately, the proof-of-craft email goes out, the follow-up task gets created, the audit-log entry is written last. This is the path of fewest moving parts and the lowest latency, and it is also the path where every rule misfire is invisible because the audit log was written after the side-effect, not before. The rule fired, the email sent, the customer received it; the only record of why it fired is in the rule's own configuration at the moment of firing, which the operator may have changed since. Inline automation is fast and brittle. I chose the second path: every meaningful mutation in Canopy writes to the audit log first. Rules read from the log and act. That is slower by a few hundred milliseconds than firing rules inline; it is also the reason a rule that fires wrong is recoverable. The mutation records the actor and the change. The action records the rule that fired it and the input it was reading. The audit log holds both. So the question 'why did this email send' has a query, not a debugging session against an inline handler's stack trace and a rule configuration that may have changed since. I considered a no-code automation builder with hundred-step branching lifecycle programs. Drag-and-drop conditions, multi-path branches, A/B-tested templates, the whole pattern. I rejected it for the same reason I reject most product additions: the operator who needs that already bought Hubspot. The operator who has not bought anything yet needs the next ten things to happen without remembering them, not a hundred-step program nobody in the building understands by month four. Lifecycle marketing software is a real product category that deserves to exist; it is just not the product category Canopy is in. The mechanism splits into three primitives: sequences, workflows, and rules. Each has a narrow purpose and reads from the audit log in a different way. Sequences are multi-step outbound with reply-exit. A prospect enters a sequence at the operator's invocation; the sequence sends step one immediately or on a delay; step two follows after a configured interval; the prospect can be removed from the sequence by replying to any of the messages, by being moved to a deal stage that exits the sequence, or by the operator manually stopping it. Reply-exit is the part that matters most: a prospect who replies stops receiving the next message in the chain because the audit log writes the inbound reply event, the sequence's exit-condition rule reads that event, and the next step is cancelled. Without reply-exit, automated outbound chains keep firing into a conversation the prospect has already started, and the result is the kind of email cadence that makes recipients hate the sender. Reply-exit is non-optional for the same reason brakes are non-optional on a car. Workflows fire on domain events. A new deal hits a stage, an old deal goes silent for an extended window, a scan report flags a finding worth a follow-up, a contact's email bounces three times in a row, a new contact enters the database from a form submission. Each of these is an event in the audit log, and each workflow is a subscription to a particular event shape with a chain of actions to fire when that shape matches. Workflows are expressive: a single workflow can fire multiple actions, condition on multiple fields, and chain into other workflows through the events it itself writes. They are also bounded: the framework limits the depth of workflow chaining so a misconfigured workflow cannot recursively trigger itself. Rules are the lowest-level primitive: they condition on what changed in the audit log, not just what was triggered. The difference matters. A workflow fires on 'a deal was moved to proposal'; a rule fires on 'a deal was moved from qualified to proposal' (the from-state matters), or 'a deal was moved to proposal by operator X' (the actor matters), or 'a deal was moved to proposal AND its value is above twenty-five thousand dollars' (the field condition matters). Rules read the before-and-after snapshot from the audit log entry, not just the entry's event type, which means rules can be specific about what triggered them in ways workflows cannot. The cost of this expressiveness is that rules are a lower-level surface and require more thought to write correctly; the benefit is that the same expressiveness covers cases that would otherwise need custom code. Email templates are versioned. A template is a piece of marketing copy with merge fields and an associated subject line, and every template change writes a new version with a timestamp and an actor. When a sequence sends a step using a template, the audit log records which version of the template was sent. If a template is later edited and the operator wants to know 'what did this prospect actually receive last Tuesday,' the answer is queryable: the audit log holds the version sent, and the version is retrievable from the template version history. Templates can also be rolled back: the operator picks a previous version and promotes it to current, which is a separate audit-log event. The send history is preserved across rollbacks, so the buyer can audit what actually went out without reconstructing it from email-platform logs. Bulk actions cover the cases where automation is overkill. The operator wants to send a one-time outbound to a list of contacts, not enroll them in a sequence; the bulk-action tooling lets them compose the message, select the contacts, preview the merged copy, and send. Each bulk action writes a single audit-log entry with the affected contact IDs, the message content, and the actor. The audit log lets the buyer answer 'who sent this email to these fifty contacts' without sifting through fifty individual send records. Every automated action writes the rule that fired it back to the audit log. This is the load-bearing inversion of the inline-automation path. When something automates that should not have, the operator opens the audit log, finds the action, reads the rule that fired it, and either tunes the rule or disables it. The trail does not require a debugging session against a vendor's internal logs because the trail is in the buyer's own database. The same query that explains why an email sent also explains why a follow-up task got created or why a workflow chained into another workflow. The honest exclusion: this is not a marketing automation suite for thousand-step lifecycle programs. The framework is bounded by the kinds of operations a small-team operator needs to express: 'whenever X happens, do Y and Z, with reply-exit on outbound.' It is not a tool for orchestrating a Fortune-500 customer-lifecycle program with cohort analysis, predictive scoring, and seventeen-step branching journeys. The architecture intentionally stops short of that scale because the operators it is built for would not know how to operate the larger surface, and the operators who do know how to operate the larger surface are not buying small-business engagements. The operational consequence the buyer feels is the one the architecture targets: when something automates that should not have, the answer is one query away. The rule that fired is named in the audit log entry. The before-and-after state is retrievable. The rollback is a single bulk action against the affected records. The next ten things happen without the operator remembering them, and when one of those ten was wrong, the system explains itself instead of obscuring the cause. That is the version of automation that fits the architecture, and it is the one that holds up over months of operation.