Developing the Agent Interaction

Receive instructions, report progress and complete an agent session in Pulse.

Once an agent app is installed and authenticated, it can join work inside Pulse. An agent session tracks one run, while agent activities make the app's progress, questions and answer visible to people.

This guide follows the same path the app follows: a person delegates or mentions it, Pulse opens a session and sends a webhook, and the app answers through activities. The session's state follows those activities automatically.

The examples use the Pulse REST API and snake_case fields. For registration, OAuth, token storage and webhook signatures, see App setup and API reference.

Agent session

A session connects a person's request to the app's work on an issue or comment. Pulse creates one when someone delegates an issue to the app or @mentions it in a comment. The created webhook includes the request, relevant context and session ID. People can follow the session, reply to it or press Stop.

Session states

You never set the state. Pulse derives it from your last activity.

StateMeaning
pendingCreated, or reopened by a person's message. Nothing from your app yet.
activeYour last activity was a thought or an action
awaitingInputYour last activity was an elicitation
errorYour last activity was an error
completeYour last activity was a response, or Pulse ended the session
stale30 minutes in pending or active with no activity from your app. Recoverable: post any activity.
stoppingA person pressed Stop, or the issue was undelegated. Your next response or error, or 60 seconds, ends it.

A person's message on a complete, error or stale session reopens it to pending and sends you prompted.

Session external URL

If the app has its own run page, add an external URL so people can open it from the Pulse session. Setting one within 10 seconds of created also counts as an initial response while the app starts work.

Link people to your own UI for the session (at most 10, each url unique and https://, label up to 60 characters). Replace the list with external_urls, or change it with added_external_urls and removed_external_urls (not both at once):

{ "added_external_urls": [{ "label": "Open in Scout", "url": "https://scout.acme.example/runs/42" }] }
{ "removed_external_urls": ["https://scout.acme.example/runs/42"] }

Session pull request

When the app publishes a pull request, add its HTTPS URL to external_urls with a clear label, such as Open pull request. Pulse shows it alongside the session's other external links. Pulse does not have a separate pull-request field or a repository-suggestion query for agent sessions.

{ "added_external_urls": [{ "label": "Open pull request", "url": "https://github.com/acme/app/pull/88" }] }

Include the result and what needs human review in the final response; the external link alone is not the completion message.

Session webhooks

AgentSessionEvent is always delivered to the installation's webhook endpoint and must not be listed in resource_types. Verify the signature, deduplicate by data.event_id, answer within 5 seconds, and process the request asynchronously.

ActionBehavior
createdA person delegated an issue or @mentioned the app. The payload includes agent_session, prompt_context, guidance and earlier comments. Start the run and post a thought or set an external URL within 10 seconds.
promptedA person sent a follow-up, answered an elicitation or pressed Stop. The new message is in agent_activity.content.body. Resume the same run; inspect agent_activity.signal before treating it as an ordinary message.

The complete created and prompted envelopes, including the XML-shaped prompt_context, are in the event payload reference. Webhooks deliver at least once, so a retry must not start duplicate work.

Proactively creating sessions

The app can start a session on an issue or comment it can access, even when nobody delegated or mentioned it.

POST /agent-sessions with an issue_id or a comment_id your installation covers starts work nobody delegated:

{ "issue_id": "6ab5b0024f48187cbd3ce990" }

The response is the new session (201), with your app user as creator. No created webhook is sent for it. On a comment there is one open session per app per thread: if yours exists it comes back with 200.

Agent activity

Activities are the conversation record for a run. The app posts a thought to acknowledge work, action while doing it, elicitation when a person must decide, and response or error when the run ends. People can post prompt activities; the app cannot.

Read activities rather than editable issue comments when resuming a run. Each activity has an author and a growing seq; use after_seq to read what arrived since the last step. Interaction best practices shows a complete read example.

Sending agent activities

Send an Idempotency-Key of up to 64 characters and keep it when you retry: a replay returns the original activity with 201 and stores nothing new.

POST https://api.trypulse.tech/api/v1/agent-sessions/sess_01J9Z3K8T5N2/activities
Authorization: Bearer $APP_ACCESS_TOKEN
X-Workspace-ID: 6a34cfb024a3b4ed28806e3b
Idempotency-Key: scout-sess_01J9Z3K8T5N2-1
Content-Type: application/json

{ "content": { "type": "thought", "body": "Looking at PUL-123…" } }

An ephemeral action, then its result:

{ "ephemeral": true, "content": { "type": "action", "action": "Searching code", "parameter": "Retry-After" } }
{ "content": { "type": "action", "action": "Searched code", "parameter": "Retry-After", "result": "3 files match" } }

The 201 response is the stored activity:

{
  "id": "act_01J9Z3M1A2",
  "seq": 4,
  "type": "action",
  "content": { "type": "action", "action": "Searched code", "parameter": "Retry-After", "result": "3 files match" },
  "ephemeral": false,
  "superseded_by_seq": null,
  "signal": null,
  "signal_metadata": null,
  "author": {
    "kind": "app",
    "id": "6ab5a2d134765b14d76a6b12",
    "name": "Scout",
    "avatar_url": "https://images.trypulse.tech/avatars/scout.png"
  },
  "created_at": "2026-09-25T09:12:05.410Z"
}

Finish with a response, or an error when a person has to act:

{ "content": { "type": "response", "body": "Fixed in https://github.com/acme/app/pull/88: retries now honour `Retry-After`." } }

Activity content payload

Pulse accepts five app activity types. The content.type selects the shape; invalid shapes return 422 VALIDATION_ERROR. Markdown is supported in body. Open each example to see the fields to send.

A short acknowledgement or progress update. It keeps the session active.

{ "content": { "type": "thought", "body": "Reading the issue and its recent comments." } }

Ask the person for a decision or missing information. The session becomes awaitingInput.

{ "content": { "type": "elicitation", "body": "Should I update the Go client too?" } }

A prompt is a person's message. Posting one from an app returns 422 PROMPT_IS_HUMAN_ONLY.

Repository suggestions

The created event may include a <repository-hint> inside prompt_context. It is a clue from the issue's team, not a grant of git access or a verified repository selection. Use your own credentials and confirm the repository before writing code.

<repository-hint repository="pulse/pulse-api"/>

Pulse has no issueRepositorySuggestions endpoint. If the hint is missing or ambiguous, ask the person through an elicitation before taking an action in a repository.

Signals

Signals add intent to an activity. A person's stop signal asks the app to disengage; an app can attach auth or select to an elicitation to request a connection or a choice. Inspect the signal alongside the activity content. Signals covers the payloads and response rules.

Ephemeral activities

A thought or action can be temporary while the app is working. Set ephemeral: true and the next app activity replaces it in the panel. The original remains in the activity list with superseded_by_seq, so the conversation can still be reconstructed.

{ "ephemeral": true, "content": { "type": "action", "action": "Searching code", "parameter": "Retry-After" } }

Only thought and action support this flag. A response or question should remain visible.

Agent plans

A plan gives people a session-level checklist during a multi-step run. Replace the whole plan array on each PATCH /agent-sessions/{session_id} update; Pulse does not update one step in isolation. A plan can have at most 50 items.

Send the whole array each time:

PATCH https://api.trypulse.tech/api/v1/agent-sessions/sess_01J9Z3K8T5N2
Content-Type: application/json

{
  "plan": [
    { "content": "Read the issue and its threads", "status": "completed" },
    { "content": "Draft the change", "status": "inProgress" },
    { "content": "Report back", "status": "pending" }
  ]
}

status is pending, inProgress, completed or canceled; content is up to 500 characters.

Recommendations

Acknowledge a new session quickly, keep long work visible with meaningful updates, and finish with a result a person can act on. Handle Stop before any queued work. Continue with Interaction best practices for follow-ups, access changes and handoff. For every endpoint and full event envelope, use the API reference.

Last updated on