{% comment %} The rule editor. Three condition halves and three actions, in one form. The contact half is templates/contacts/_filter_bar.html — the same builder the segment editor uses, driven by the same payload from apps.contacts.builder.builder_config. It serialises its Alpine state into one hidden `filter` input, so the server hands the document straight to the condition engine instead of re-assembling it from separate fields; a second parser for a language that already has one is exactly what ROADMAP contract 8 exists to prevent. Its script half has to come with it — see the include at the bottom. {% endcomment %} {% load common_extras %} {% comment %} No id on this root. It is swapped into rule_settings.html's #inbox-rule-editor with htmx's default innerHTML, so repeating that id here would put two elements with one id in the document — and every later hx-target="#inbox-rule-editor" would resolve to the outer wrapper. {% endcomment %}
{% if rule %}{% endif %}
When a message arrives

A rule needs at least one condition. Every condition it carries has to match; a condition it leaves empty is not a filter.

Containing any of these words {% comment %} Two parallel lists, the shape apps/flows/triggers/forms.py already parses for keyword triggers — and the same three modes, matched by apps.flows.triggers.keywords, so a rule and a trigger agree about what "any_word" means. {% endcomment %} {% for keyword in condition.keywords %}
{% endfor %}
And the contact matches {% comment %} The partial carries its own hidden `filter` input (line 131 there), so there is nothing to add here — and adding a second one would post the document twice. {% endcomment %} {% include "contacts/_filter_bar.html" %}
Then {% comment %} Hydrated from `selected_actions`, like the keyword rows and the channel selects above. Without it, opening an existing rule and saving it posts an empty action list — which validate_actions refuses with "a rule needs at least one action", after silently forgetting what the rule did. {% endcomment %}

Only when nobody has the conversation already. A rule never takes a thread off a colleague.

An automated reply reopens a conversation, so “mark done” means done unless a flow answers it.

{% comment %} The builder's script is NOT included here. `contactFilters` has to be defined before Alpine initialises this markup, and this partial arrives by htmx swap long after Alpine booted — so rule_settings.html defines it in its alpine_components block, exactly as contacts/list.html does for its own copy. {% endcomment %}