--- name: author-signals-and-sensors description: Create or update reusable signals and message sensors in an explicit Speakeasy AI Control Plane project, with confirmed atomic authoring and live verification. --- # Author signals and sensors Use this workflow when someone wants the Speakeasy AI Control Plane (AICP) to classify conversation messages into reusable labels, exclusive choices, or ordered scores. Sensors perform classification; they do not enforce access policies. ## Discover 1. Successfully call `list_projects` through this client's authenticated Speakeasy connection. Have the user select the exact project. Package installation alone grants no authority. These tools require signals intelligence enabled and live project permissions; they are currently external-user-only. 2. Call `find_sensors` and `find_signals` for that project, searching and following pagination as needed. Present candidates rather than silently selecting a name match. Reuse a signal only after the user agrees its full criteria fit. 3. For an existing sensor, call `get_sensor` and inspect its complete ordered definitions. For a shared signal change, use `update_signal` with `confirmed:false` to inspect the affected sensors before asking for confirmation. ## Choose the definition 4. Agree the mode: `multi_label` evaluates independent labels; `exclusive` chooses one option; `ordered_score` uses two to ten levels ordered from low to high, each with classifier criteria. Agree instructions, display names, optional slugs, and reusable signal definitions. Agree whether the sensor should be enabled. `proposal.enabled` defaults to true on creation; omission on update preserves the current state. Disabled sensors remain visible and editable but skip new evaluations; evaluations already in progress may finish. 5. Agree the matching expression. Omission on creation defaults to `message.role == "user"`. Only `message.role` is exposed; do not invent actor, department, cohort, replay, or tool fields. Conversation ingestion currently evaluates user/assistant creation events, including historical imports. 6. Optionally call `preview_sensor_match` with bounded, caller-supplied role examples. Report matched, not matched, and errors separately. Missing message context is unbound, not an empty role. This tests metadata eligibility, not classification quality, and neither retrieves transcripts nor runs inference. ## Preview and confirm 7. Prefer `create_sensor` with a `proposal` containing existing signal IDs and/or inline `new_signal` definitions. The operation creates new signals and the sensor together atomically. Use `create_signal` when the user only wants a reusable catalog definition. Use `update_sensor` for a selected sensor's own fields or ordered membership, and `update_signal` to deliberately change a shared definition. Set `proposal.operation` to the tool name. 8. Call with `confirmed:false`. Show the normalized configuration, matching expression, enabled state, complete signal order, draft reasons, and every affected sensor returned for a shared-signal update. Preview creation IDs are provisional and are not committed resources. Omitted update fields are preserved; a supplied signals list replaces the entire membership, and an empty list clears it. 9. Obtain explicit confirmation of that exact proposal and its shared impact. Resend the identical proposal with `confirmed:true`, the returned `expected_version` (from `version`) and `preview_token`, and a stable `idempotency_key`. Keep that key and all inputs unchanged when retrying an uncertain request. A version conflict requires another read, preview, and confirmation; the version covers the whole project's configuration. ## Verify 10. For a sensor, call `get_sensor` using the committed ID. For a standalone signal, call `find_signals` and verify its exact ID and definition. Report committed enabled state and configuration readiness separately from active inference or observed readings, which these tools cannot prove. 11. A committed receipt with `snapshot_scope: verification_unavailable` means the write succeeded but the fresh read failed. Keep the same retry key and inputs; retry verification rather than creating again. A false `target_available` in this state does not prove deletion. A replayed receipt proves a historical write, not current existence. Check `target_available` and the fresh target state; do not recreate a deleted target by changing the retry key. Present the returned dashboard path when available. If the capability is unavailable, stop rather than bypassing its permissions or inventing another tool. Never ask for API keys, passwords, tokens, OAuth codes, client secrets, or secret headers. Use synthetic examples rather than requesting private transcripts. If the user wants to report workflow feedback, obtain consent before calling `send_platform_mcp_feedback`.