- Event rules: deterministic. “When
hit_limitarrives withlimit = ai_credits, open a signal.” No AI involved. - The AI reviewer: reads a per-person dossier (their event timeline filtered by the event dictionary, computed absences, your org brief) and answers with findings. Each finding recommends one action from your action catalog, and an admitted finding with a
signalaction becomes a signal.
https://api.flywheel.cx/mcp). For the server itself and how to connect, see /mcp/overview.
How the pieces fit together
The signal tools configure one pipeline. Read it left to right:- An event arrives for a person (from your app, an integration, or Flywheel itself).
- Event rules check it. Every enabled rule whose
on_event,filtersandoccurrencematch writes its own signal, unless theevent_rulesproducer is paused. Configure withcreate_signal_rule/update_signal_rule. - The reviewer may be booked. If the reviewer is on (
update_reviewer_settingswithreviewer_enabled: true) and the org has review allowance left, a matching review trigger (create_review_trigger) books a review of that person, after the trigger’s delay. Independently, an event classifiedcriticalin the event dictionary (update_event_dictionary) books a review with no trigger at all. A daily staleness backstop also books active people who have not been reviewed forreviewer_staleness_days. - The reviewer runs on the booked person: it reads their dossier, your
org_brief, and your enabled actions with theirguidance(list_signal_actions), and answers with up toreviewer_max_findingsfindings. Each finding must cite evidence from the dossier or it is dropped. - Admitted findings are delivered according to the chosen action’s
delivery:signalwrites a signal,watchsets a tripwire for a later review,noneis recorded on the review log only. - The signal is stamped with its routing from its rule (or action):
handlerhuman or agent,rungdraft, approve or auto, and an optionaldefault_assignee_user_id. It lands in the signals list in itsbucket. - The signal closes: worked by a person, resolved as won by a purchase (
purchase_resolves), or expired afterexpiry_minutes.
Some routing fields are saved and validated but not yet acted on: an agent is not started for
handler: "agent" with rung: "auto", follow_up does not start an agent run, resolve_on events do not close signals, and the $fw_signal_created event is not emitted. You can configure them now; they have no effect on people until Flywheel starts acting on them.Event rules and the reviewer are two separate producers. A signal from either looks the same downstream: same list, same routing fields. Pausing one does not affect the other: event rules are paused with
set_signal_producer_status, the reviewer is switched off with update_reviewer_settings.Permissions for signal tools
Every signal tool declares one permission, checked against the MCP connection’s credential:delete_signal_rule, delete_review_trigger and delete_signal_action are marked destructive. Any id you pass (handler_agent_id, follow_up.agent_id, default_assignee_user_id, scan_segment_id) must be a UUID that belongs to your organization; ids from another org are refused.
Routing: handler, rung and assignee
Signal rules (create_signal_rule) and reviewer actions (create_signal_action, update_signal_action) share the same routing fields:
handler:human(default) oragent. Who works the signal.handler_agent_id: the agent that works it. Required on a rule whenhandlerisagent, and refused whenhandlerishuman. Get ids fromlist_signal_agents.rung: the autonomy level,draft(default),approveorauto. Stamped on every signal the rule or action writes. On reviewer actions it can never exceed the action’srung_ceiling.default_assignee_user_id: the team member the signal is assigned to. Must be a member of the org.follow_up:{ "after_minutes": 4320, "agent_id": "..." }, meant to hand a still-unresolved signal to an agent after a delay.after_minutesis 5-86400 (60 days),agent_idmust be one of your org’s agents, and on a ruleafter_minutesmust be shorter thanexpiry_minutes.
handler to human without passing handler_agent_id drops the agent automatically.
Agent dispatch and follow-ups are saved and validated but not yet acted on: a signal with handler: "agent" and rung: "auto" does not start its agent, and a follow_up does not start a run. They are designed to let agents message people without per-message approval once they take effect, so confirm with the person you are working for before setting them.
Signal rules (event rules)
A signal rule turns a matching event into a signal. Tools:list_signal_rules, get_signal_rule, create_signal_rule, update_signal_rule, delete_signal_rule. Rule writes take effect at the next event after a cache of up to one minute turns over.
Every matching rule writes its own signal: rules are independent detectors, not a first-match pipeline. Two rules on the same event produce two signals, each deduplicated on its own.
list_signal_rules and get_signal_rule
list_signal_rules takes no arguments and returns { "rules": [...] } in display order. get_signal_rule returns { "rule": {...} } for one id, or not found if the rule is not in your org.
id, position, sent_count, undone_count and created_at.
create_signal_rule
Creates a rule. Onlyon_event and bucket are required; everything else has a default. Returns { "rule": {...}, "action": "created" | "updated" }.
If key matches an existing rule, that rule is replaced whole: fields you leave out are reset to their defaults, not kept. That makes creation with a key safe to retry. Without a key, every call creates a new rule. To change one field of an existing rule, use update_signal_rule.
on_event cannot be $fw_signal_created; a rule on it is refused.
update_signal_rule
Changes some fields of a rule. Passrule_id plus only the fields you want to change; omitted fields keep their stored value. Passing null clears the nullable fields (follow_up, handler_agent_id, occurrence, and also key, label, default_assignee_user_id, contact_reason). Returns { "rule": {...} }.
handler: "agent" with no agent, or a follow_up no longer shorter than expiry_minutes) is refused. Setting a key another rule already has is refused.
delete_signal_rule
Deletes a rule. Signals it already wrote keep their history (bucket, handler and rung live on each signal). Returns{ "deleted": true }. To stop a rule without losing it, use update_signal_rule with "enabled": false instead.
Signal rule fields
Signal rule dedupe
dedupe on create_signal_rule / update_signal_rule decides what counts as the same signal. A repeat detection inside the window lands on the existing signal instead of opening a new one. Dedupe is always scoped to the rule.
Closing signals with resolve_on
resolve_on on a signal rule lists outcome events meant to close the rule’s open signals for the same person as won when they arrive after the signal opened. It is saved and validated but not yet acted on: today an arriving resolve_on event does not close anything, and signals close by being worked, by a purchase (purchase_resolves), or by expiring. Up to 8 entries, each { "event": "...", "filters": [...] } with up to 8 equality filters (op must be eq). A number and its decimal string compare equal ("80" matches 80). An entry with no filters matches any event of that name. $fw_signal_created cannot resolve a signal.
purchase_resolves: true only on rules whose point is causing a purchase. A churn-risk rule with it on would be marked won when the person buys something unrelated.
Review triggers
A review trigger summons the AI reviewer to look at a person when an event happens. Triggers do not write signals themselves; they book a review, and the review’s findings may become signals. Tools:list_review_triggers, create_review_trigger, update_review_trigger, delete_review_trigger.
Triggers only book reviews while the reviewer is on (reviewer_enabled) and the org has review allowance left (see get_reviewer_settings). Each trigger fire costs a review unless it is merged or skipped (see “Cost and volume”).
list_review_triggers
No arguments. Returns{ "triggers": [...] } in creation order, each with id, label, on_event, property_filters, occurrence, delay_minutes, focus, priority, enabled, created_at, updated_at.
create_review_trigger
Returns{ "trigger": {...} }. Only on_event is required.
update_review_trigger
Passtrigger_id plus the fields to change; omitted fields keep their value. occurrence: null and focus: null clear those fields. Returns { "trigger": {...} }.
delete_review_trigger
Deletes a trigger. Returns{ "deleted": true }.
Signal actions (the reviewer’s action catalog)
The action catalog is the closed set of verbs the AI reviewer may answer with, and how each verb’s signals are routed. Tools:list_signal_actions, create_signal_action, update_signal_action, delete_signal_action.
Every org starts with five shipped actions:
delivery decides what an admitted finding produces: signal writes a signal (the only outward path), watch sets a tripwire for a later review, none is recorded on the review log only.
guidance goes into the reviewer’s prompt verbatim, and the reviewer is told to follow it over its own reading of the verb’s name. Only enabled actions are offered to the reviewer; a finding naming a disabled or unknown action is dropped.
list_signal_actions
No arguments. Returns{ "actions": [...] } sorted by key, each with id, key, label, guidance, delivery, rung, rung_ceiling, enabled, handler, handler_agent_id, default_assignee_user_id, follow_up, sent_count, undone_count, created_at, updated_at.
create_signal_action
Adds a verb. Required:key (lowercase letters, digits and _, starting with a letter, up to 64 characters, unique in the org), label, delivery. Optional: guidance, rung (default draft), rung_ceiling (default auto), enabled (default true), handler (default human), handler_agent_id, default_assignee_user_id, follow_up. Returns { "action": {...} }.
rung_ceiling is fixed at creation and can never be raised. rung may not exceed it, and a signal is always born at the lower of the two. Choose the ceiling deliberately: a ceiling of draft guarantees the action never sends on its own.
update_signal_action
Changes routing or guidance. Passaction_id plus fields to change: label, guidance, delivery, rung, enabled, handler, handler_agent_id, default_assignee_user_id, follow_up (null clears it). rung_ceiling cannot be changed. Switching handler to human without passing handler_agent_id drops the agent. Returns { "action": {...} }.
Route agent_draft to an agent at the auto rung (stored now; agents are not yet started automatically):
delete_signal_action
Deletes a verb. Permanent: the shipped catalog is only seeded when an org’s catalog is empty, so a deleted shipped verb does not come back. Findings that name it are dropped. To stop the reviewer using a verb reversibly, useupdate_signal_action with "enabled": false. Returns { "deleted": true }.
Event dictionary
The event dictionary says what each event means to the AI reviewer. Itssalience is the most consequential reviewer setting you have: it decides what the reviewer’s dossier keeps. Tools: list_event_dictionary, update_event_dictionary.
Events are classified automatically (by AI, and by a stats pass that demotes an event one person fires more than 500 times in 7 days). Operator edits outrank both.
list_event_dictionary
Returns{ "events": [...], "total": N } sorted by event name, including Flywheel’s shipped $fw_* classifications. query is a case-insensitive substring of the event name; limit defaults to 200, maximum 1000. total counts all matches, so a total above your limit means there are more.
update_event_dictionary
Classifies one event as an operator. Passevent_name and at least one of description, salience, category, expected_next (null clears it). The edit sets admin_verified and salience_source: "operator", so later AI and stats passes will not overwrite it. Returns { "event": {...} }.
Reviewer settings
The AI reviewer’s org-level settings, plus where the org stands against its review allowance. Tools:get_reviewer_settings, update_reviewer_settings.
get_reviewer_settings
No arguments. Returns{ "reviewer": {...} }:
update_reviewer_settings
Pass only the fields to change; omitted fields keep their value. Returns{ "reviewer": {...} } with the fresh allowance.
allowance before enabling: every review is a paid model call that counts against it.
Settings changes reach the event path within about a minute.
Signal agents and their caps
Agents are built in the Flywheel dashboard’s agent builder. The MCP tools only read them and set how many signals each may be handed. Tools:list_signal_agents, set_signal_agent_cap.
list_signal_agents
No arguments. Returns{ "agents": [...] }, each with id, name, status, version, signal_daily_dispatch_cap and signal_dispatches_today (signal runs started for this agent since 00:00 UTC). Call this before routing anything to an agent: the id is what handler_agent_id and follow_up.agent_id take.
set_signal_agent_cap
Sets how many signals one agent may be handed per UTC day, counting first dispatches and follow-ups together. Range 0-1000; the default for a new agent is 25.0 means the agent is never handed signals. Requires agents.write. Returns { "agent": {...} }. Agents are not yet started on signals automatically, so the cap is stored ahead of that.
handler: "agent" with rung: "auto", so it is already in place when agent dispatch takes effect.
Signal producers
Producers are the deterministic signal detectors:event_rules (all your signal rules) and webinar_session_ended (the post-webinar queue). Tools: list_signal_producers, set_signal_producer_status. The AI reviewer is not a producer here; its switch is reviewer_enabled in update_reviewer_settings.
list_signal_producers
No arguments. Returns{ "producers": [{ "key", "configured", "status" }] }. status is active, paused or archived. configured: false means the detector has never run or been toggled for this org; it reads as active, which is what it will be when it first fires.
set_signal_producer_status
Pauses or resumes one detector. A paused detector writes no signals: no event rule fires, and the webinar build skips.status is active or paused. Returns the full producer list.
event_rules is the fastest way to stop every rule at once without editing or deleting any of them.
The $fw_signal_created event
$fw_signal_created is a Flywheel event name reserved for announcing new signals, so that workflows (playbooks) can react to them. It is not emitted yet: no signal currently produces it, so a workflow triggered on it will not run. See /mcp/workflows for workflows in general.
The name is already protected: $fw_signal_created is refused as a signal rule’s on_event, as a resolve_on event, and as a review trigger’s on_event.
Cost and volume
What spends money (review allowance) and what creates more signals. Changes that increase reviews (cost):update_reviewer_settingswithreviewer_enabled: true. Nothing is reviewed while it is off.- Each
create_review_trigger. Every matching event books a review. Several bookings for one person merge into one pending review, and a review insidereviewer_debounce_minutesof the last one is canceled before the model runs. priority: "critical"on a trigger, which skips the debounce.update_event_dictionarywithsalience: "critical", which books a review on every occurrence of that event.- Lowering
reviewer_debounce_minutesorreviewer_staleness_days.
- A new or enabled signal rule, especially on a frequent event with no
filtersoroccurrence. - A narrower
dedupe(eventinstead ofcalendar), or a longerexpiry_minutes(more signals open at once). - A higher
reviewer_max_findings, or a new action withdelivery: "signal". - Resuming a paused producer.
enabled: false on a rule, trigger or action; queue: false on a rule; set_signal_producer_status to pause event_rules; “reviewer_enabled: false`.
Side effects on real people
Signal configuration changes what lands in your team’s signals list and what the AI reviewer looks at. None of the signal tools sends a message to a person by itself today. Two kinds of setting are designed to message people once Flywheel acts on them, and are saved and validated now:handler: "agent"withrung: "auto"on a rule or action (create_signal_rule,update_signal_rule,create_signal_action,update_signal_action): meant to start the agent on every new signal, up to its daily cap, with nobody approving each run.- A
follow_upon a rule or action: meant to start an agent on every signal still unresolved afterafter_minutes.
set_signal_agent_cap first, so the configuration is already safe when it takes effect.
What does have an effect today: rules, actions and producers decide which people your team is asked to contact (and default_assignee_user_id decides who), and reviewer settings, triggers and dictionary salience decide how many paid reviews run.
Common tasks
Flag accounts that keep hitting a limit
1
Check the event and its properties
Call
list_event_dictionary with { "query": "hit_limit" } to confirm the event exists and how it is named. Rule filters read event properties, so make sure the property you filter on (here limit) is sent on the event.2
Create the rule with a key
Call
create_signal_rule with key, bucket, on_event, filters, an occurrence and a dedupe, routed to a human. The key makes the call safe to retry.3
Pick the expiry and outcome
Set
expiry_minutes to how long the signal is worth working. If the rule’s point is a purchase, set purchase_resolves: true so a purchase closes it as won.Route a rule’s signals to an agent
Agents are not yet started on signals automatically, so this records the routing ahead of time.1
Pick the agent and set its cap
Call
list_signal_agents, choose the agent, and call set_signal_agent_cap with a conservative cap such as { "agent_id": "...", "signal_daily_dispatch_cap": 10 }.2
Route the rule
Call
update_signal_rule with { "rule_id": "...", "handler": "agent", "handler_agent_id": "..." }. Leave rung at draft unless the person you are working for has confirmed they want the agent to act without approval once dispatch takes effect; then add "rung": "auto".Turn on the AI reviewer
1
Check the allowance
Call
get_reviewer_settings. If allowance.reason is not_on_plan, the AI Reviewer add-on is needed first.2
Write the org brief
Call
update_reviewer_settings with an org_brief: what you sell, who your customers are, what activation and expansion look like.3
Tune the catalog
Call
list_signal_actions and adjust guidance with update_signal_action so each verb says when your team wants it used. Route agent_draft to an agent if you have one.4
Classify the events that matter
Use
update_event_dictionary to mark key events notable, demote chatter to noise, and add expected_next for the steps of your funnel.5
Add triggers and switch it on
Create one or two review triggers with
create_review_trigger, then call update_reviewer_settings with { "reviewer_enabled": true }.Ask the reviewer to check new signups after a day
Callcreate_review_trigger:
Teach the reviewer your funnel
Callupdate_event_dictionary for each step, with expected_next pointing at the step after it. An unmet step becomes an absence fact in the dossier once the window passes.
Stop everything quickly
- All event rules:
set_signal_producer_statuswith{ "key": "event_rules", "status": "paused" }. - The reviewer:
update_reviewer_settingswith{ "reviewer_enabled": false }.
Mistakes to avoid
- Calling
create_signal_rulewith an existingkeyto change one field. It replaces the rule whole and resets every field you left out to its default. Useupdate_signal_rule. - Calling
create_signal_rulewithout akeyon retry. Each call creates another rule. Give rules akey. - Filtering a rule on a person property.
filtersandproperty_filtersread the event’s properties only. - Routing to an agent without setting its cap first. The default cap is 25 per UTC day. Set it with
set_signal_agent_capbeforerung: "auto"goes on. - A
follow_uplonger thanexpiry_minutes. Refused by validation. - Marking a frequent event
criticalin the dictionary. Every occurrence books a review. Usenotable. - Classifying events before they have been sent.
update_event_dictionaryreturns not found for an event your org has never sent. - Deleting a shipped action to stop the reviewer using it. Deletion is permanent and it is never re-seeded. Set
enabled: falseinstead. - Choosing
rung_ceilingloosely on a new action. It can never be raised later, and it is the guarantee that an action never sends on its own. - Using
purchase_resolveson a rule unrelated to buying. Any purchase marks its signals won. - Expecting a rule edit to apply instantly. Rules are cached for up to a minute; the next event after that sees the change.
- Building a rule or a workflow on
$fw_signal_created. A rule on it is refused, and the event is not emitted yet, so a workflow on it never runs. - Relying on
resolve_on,follow_upor agent dispatch. They are saved and validated but not yet acted on. - Inventing ids. Agent, team member, segment, rule, trigger and action ids come from the list tools here, from /mcp/people for people and segments, and must belong to your org.