Skip to content

Integrate a software producer

Installed software can submit a configured prompt without creating HAL pins. The catalog still owns the visible content and available actions; the producer supplies only the configured prompt name and request identity.

Use this path for an installed process that already owns a workflow outside HAL. Use a HAL-backed prompt when the request and result belong to the machine’s HAL sequence.

Create a complete template without hal, then configure an instance:

version: 1
templates:
shop.confirm-fixture:
title: Verify fixture
message: Confirm that fixture A is installed and clamped.
severity: warning
actions:
- id: continue
label: Continue
intent: primary
- id: cancel
label: Cancel operation
intent: secondary
allow_abort: true
prompts:
confirm-fixture-a:
template: shop.confirm-fixture

A software producer cannot submit a configured prompt that has a HAL contract. Its rising-edge trigger owns that instance.

Non-HAL submissions have no producer-supplied template variables. They may still use the captured is_lathe and tools values in their configured content.

The installed ctrl_prompt package provides an asynchronous client:

import asyncio
from ctrl_prompt import PromptClient
async def main():
async with PromptClient(source_id="fixture-loader") as client:
handle = await client.submit(
"confirm-fixture-a",
request_id="load-a12",
)
result = await handle.wait(timeout=30)
try:
if result.status == "answered":
print(result.action_id)
elif result.status == "aborted":
print("operator aborted the prompt")
finally:
await handle.acknowledge()
asyncio.run(main())

source_id identifies the producer to the UI. request_id identifies one logical request on that producer’s connection. Reusing the same request ID before acknowledging its result returns the existing prompt instead of adding a duplicate.

wait() returns an answered, aborted, or cancelled result. For answered, action_id is one of the IDs declared in the catalog. A timeout from wait() does not cancel or acknowledge the outstanding request; decide explicitly whether to continue waiting or call handle.cancel().

Always acknowledge a completed result after the workflow has recorded or acted on it. Acknowledgement releases the broker’s retained result and allows that request ID to be used for a later request.

Other languages can use the versioned ctrl.prompt.v1.PromptService interface. Its installed protobuf definition is /usr/share/ctrl/prompt/proto/ctrl/prompt/v1/prompt.proto.

The producer-facing sequence is:

  1. Open ProducerSession with a stable source_id.
  2. Send SubmitConfigured and retain the returned prompt_id.
  3. Wait for the pushed PromptResolved event.
  4. Handle the returned status and action ID.
  5. Send AcknowledgeResult after the result is no longer needed.

Call Cancel(promptId) to withdraw the producer’s queued or active request. Cancellation is owner-restricted. The UI uses Respond and Abort; those methods are not producer acknowledgement shortcuts.

The broker displays one prompt at a time. WatchEvents exposes complete state snapshots and broker faults for the Ctrl UI; producers should track their own request by prompt_id rather than depending on queue position.

Keep the bidirectional producer stream alive while it owns pending work and retained results. If a producer disconnects with an outstanding prompt, the broker cancels its work and reports a producer-disconnection fault. Design the surrounding machine workflow so an unexpected producer exit cannot be mistaken for an operator confirmation.

The broker is started by the machine HAL configuration and listens on 127.0.0.1:50053 by default. A software producer should treat the service being unavailable as a workflow failure, not assume that connecting will start it.