Skip to main content
A signal is a person flagged for action: someone your team (or one of your agents) should do something about, with the reason attached. Signals come from two places:
  • Event rules: deterministic. “When hit_limit arrives with limit = 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 signal action becomes a signal.
Every signal carries its routing: who works it (a human or an agent), how much autonomy it has, and who it is assigned to. Signals are worked from the signals list in the Flywheel dashboard. This page covers the 21 signal configuration tools on the Flywheel MCP server (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:
  1. An event arrives for a person (from your app, an integration, or Flywheel itself).
  2. Event rules check it. Every enabled rule whose on_event, filters and occurrence match writes its own signal, unless the event_rules producer is paused. Configure with create_signal_rule / update_signal_rule.
  3. The reviewer may be booked. If the reviewer is on (update_reviewer_settings with reviewer_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 classified critical in 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 for reviewer_staleness_days.
  4. The reviewer runs on the booked person: it reads their dossier, your org_brief, and your enabled actions with their guidance (list_signal_actions), and answers with up to reviewer_max_findings findings. Each finding must cite evidence from the dossier or it is dropped.
  5. Admitted findings are delivered according to the chosen action’s delivery: signal writes a signal, watch sets a tripwire for a later review, none is recorded on the review log only.
  6. The signal is stamped with its routing from its rule (or action): handler human or agent, rung draft, approve or auto, and an optional default_assignee_user_id. It lands in the signals list in its bucket.
  7. The signal closes: worked by a person, resolved as won by a purchase (purchase_resolves), or expired after expiry_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) or agent. Who works the signal.
  • handler_agent_id: the agent that works it. Required on a rule when handler is agent, and refused when handler is human. Get ids from list_signal_agents.
  • rung: the autonomy level, draft (default), approve or auto. Stamped on every signal the rule or action writes. On reviewer actions it can never exceed the action’s rung_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_minutes is 5-86400 (60 days), agent_id must be one of your org’s agents, and on a rule after_minutes must be shorter than expiry_minutes.
On an update, switching 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.
Each rule carries every field below plus id, position, sent_count, undone_count and created_at.

create_signal_rule

Creates a rule. Only on_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. Pass rule_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": {...} }.
The merged rule is validated as a whole, so an edit that leaves the rule inconsistent (for example 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.
Use 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

Pass trigger_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. Pass action_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, use update_signal_action with "enabled": false. Returns { "deleted": true }.

Event dictionary

The event dictionary says what each event means to the AI reviewer. Its salience 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. Pass event_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": {...} }.
You can only classify events your org has already sent. Classifying an unseen event returns not found (“send one event first, then classify it”), because a dictionary row is also the event’s validation schema.
Setting an event to critical makes every occurrence of it book a review while the reviewer is on. A high-volume event marked critical spends review allowance fast. Use notable for events that matter but happen often.

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.
Switching the reviewer on (from off) requires the AI Reviewer add-on on the plan, and is refused with a failed-precondition error if it is missing. An org that has merely used up its allowance for the period keeps its switch; reviews pause and resume when the period renews or the plan changes. Read 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.
The cap is designed as the rail against runaway sends. Set it before routing any rule or action to 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.
Pausing 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_settings with reviewer_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 inside reviewer_debounce_minutes of the last one is canceled before the model runs.
  • priority: "critical" on a trigger, which skips the debounce.
  • update_event_dictionary with salience: "critical", which books a review on every occurrence of that event.
  • Lowering reviewer_debounce_minutes or reviewer_staleness_days.
Changes that increase signal volume:
  • A new or enabled signal rule, especially on a frequent event with no filters or occurrence.
  • A narrower dedupe (event instead of calendar), or a longer expiry_minutes (more signals open at once).
  • A higher reviewer_max_findings, or a new action with delivery: "signal".
  • Resuming a paused producer.
Ways to cut volume without deleting anything: 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" with rung: "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_up on a rule or action: meant to start an agent on every signal still unresolved after after_minutes.
Confirm with the person you are working for before setting either, and set the agent’s cap with 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

Call create_review_trigger:

Teach the reviewer your funnel

Call update_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_status with { "key": "event_rules", "status": "paused" }.
  • The reviewer: update_reviewer_settings with { "reviewer_enabled": false }.

Mistakes to avoid

  • Calling create_signal_rule with an existing key to change one field. It replaces the rule whole and resets every field you left out to its default. Use update_signal_rule.
  • Calling create_signal_rule without a key on retry. Each call creates another rule. Give rules a key.
  • Filtering a rule on a person property. filters and property_filters read 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_cap before rung: "auto" goes on.
  • A follow_up longer than expiry_minutes. Refused by validation.
  • Marking a frequent event critical in the dictionary. Every occurrence books a review. Use notable.
  • Classifying events before they have been sent. update_event_dictionary returns 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: false instead.
  • Choosing rung_ceiling loosely 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_resolves on 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_up or 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.
Related: /mcp/overview, /mcp/workflows, /mcp/people, /mcp/broadcasts, /mcp/webinars.