Send input and read output

Send one JSON value to an open Session:

helmr actor send SESSION_ID \
  --project agents --env development \
  --data-json '{"type":"instruction","text":"also update the tests"}' \
  --idempotency-key slack:T123:C456:1712345678.000100

Use a stable upstream event identifier as the idempotency key. A retry then replays the original admission instead of adding duplicate work. send routes to the active Turn before settlement or enqueues when idle; use enqueue to always queue a new Turn. Messages accepted before handler registration wait for delivery to that same Turn. Acceptance does not mean the application has handled the message; inspect message outcomes in the Session timeline. A held Session rejects send. For an answer or approval tied to existing work, use session.turn(turnId).send or helmr actor turn send SESSION_ID TURN_ID. These never retarget a late reply.

Read one finite event page:

helmr actor events SESSION_ID \
  --project agents --env development \
  --after 0 --limit 50 --json

Each event has a durable sequence, kind, data, timestamp, nullable Turn ID and nullable Run provenance. Pass next_after as --after to continue. Multiple readers can keep independent cursors. Output EOF is not a terminal Turn outcome.

With the SDK:

const session = client.sessions.ref("SESSION_ID")
await session.send(
  { type: "instruction", text: "also update the tests" },
  { idempotencyKey: "slack:T123:C456:1712345678.000100" },
)

const page = await session.events.list({
  after: 0,
  limit: 50,
})
for (const record of page.records) {
  console.log(record.sequence, record.data)
}

Run logs are execution telemetry. Session output is the Actor’s durable application protocol; do not substitute one for the other.