> ## Documentation Index
> Fetch the complete documentation index at: https://docs.boat.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Steer a running turn

> Send a new message to a turn that is already running, without losing what the agent is doing. This is what typing into a coding agent while it works does: the instruction is taken into account and the work continues.

Where the harness has a native mid-turn primitive (Claude Code, Codex, pi, Prime Agent) nothing is interrupted and the response has `native: true`. Where it does not (OpenCode), Boat interrupts that turn and immediately continues the SAME conversation with the instruction, keeping the session and its memory, and the response has `native: false`.

Refused with **409 `no_running_turn`** when the conversation has nothing in flight; queue work with `POST /prompt` instead. The steer shows up in `GET /events` as a `steer` event. See [Integrated agents](/integrated-agents).



## OpenAPI

````yaml openapi/boat-v1.yaml POST /sandboxes/{sandboxId}/steer
openapi: 3.1.0
info:
  title: Boat Public API v1
  version: 1.0.0
  description: >
    Public JSON API for creating, operating, prompting, observing, and exposing
    sandboxes from backend services, CI jobs, hosted workers, and Boat
    automation products.


    The v1 reference intentionally documents the developer integration surface
    only. Dashboard billing actions are not part of v1.
servers:
  - url: https://boat.dev/api/v1
security:
  - BoatBearerAuth: []
tags:
  - name: Boat
    description: >-
      Unified Boat account, setup, lifecycle, prompting, event history, desktop
      access, and SSH operations.
paths:
  /sandboxes/{sandboxId}/steer:
    post:
      tags:
        - Boat
      summary: Steer a running turn
      description: >-
        Send a new message to a turn that is already running, without losing
        what the agent is doing. This is what typing into a coding agent while
        it works does: the instruction is taken into account and the work
        continues.


        Where the harness has a native mid-turn primitive (Claude Code, Codex,
        pi, Prime Agent) nothing is interrupted and the response has `native:
        true`. Where it does not (OpenCode), Boat interrupts that turn and
        immediately continues the SAME conversation with the instruction,
        keeping the session and its memory, and the response has `native:
        false`.


        Refused with **409 `no_running_turn`** when the conversation has nothing
        in flight; queue work with `POST /prompt` instead. The steer shows up in
        `GET /events` as a `steer` event. See [Integrated
        agents](/integrated-agents).
      operationId: steer
      parameters:
        - $ref: '#/components/parameters/SandboxId'
        - name: conversation
          in: query
          schema:
            type: string
          description: >-
            Conversation id to steer. Also accepted in the body. Omit to steer
            the sandbox's most-recently-active conversation.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SteerRequest'
            examples:
              addATask:
                value:
                  message: >-
                    Also write /home/user/steered.txt containing the word
                    STEERED, then finish.
              oneConversation:
                value:
                  conversation: 8f1c2b7a-3d4e-4f5a-9b0c-1d2e3f4a5b6c
                  message: Skip the integration tests, unit tests are enough.
      responses:
        '200':
          description: Message delivered to the running turn.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SteerResponse'
              examples:
                steered:
                  value:
                    ok: true
                    type: prompt.steered
                    id: bx_23456789
                    conversationId: 8f1c2b7a-3d4e-4f5a-9b0c-1d2e3f4a5b6c
                    promptId: prompt_456
                    native: true
                    mode: native
                    status: steered
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
components:
  parameters:
    SandboxId:
      name: sandboxId
      in: path
      required: true
      schema:
        type: string
        pattern: ^bx_[23456789abcdefghjkmnpqrstuvwxyz]{8}$
      description: Public Sandbox id returned by create/list/get sandbox calls.
  schemas:
    SteerRequest:
      type: object
      description: >
        A message for a turn that is ALREADY RUNNING. The agent takes it into
        account and keeps what it was doing, instead of queueing behind the turn
        (`POST /prompt`) or stopping it (`POST /interrupt`).


        **Conversations:** omit `conversation` to steer the sandbox's
        most-recently-active conversation, exactly like `POST /prompt` chooses
        one. Pass a `conversation` id to steer a specific one while the others
        keep running.


        The response's `native` says how the harness took it. See [Integrated
        agents](/integrated-agents).
      required:
        - message
      properties:
        message:
          type: string
          minLength: 1
          description: The extra instruction for the running turn.
        conversation:
          type:
            - string
            - 'null'
          description: >-
            Conversation id to steer. Omit to steer the sandbox's
            most-recently-active conversation.
          format: uuid
      examples:
        - message: >-
            Also write /home/user/steered.txt containing the word STEERED, then
            finish.
        - conversation: 8f1c2b7a-3d4e-4f5a-9b0c-1d2e3f4a5b6c
          message: Skip the integration tests, unit tests are enough.
    SteerResponse:
      allOf:
        - $ref: '#/components/schemas/SuccessBase'
        - type: object
          required:
            - id
            - conversationId
            - promptId
            - native
            - status
          properties:
            type:
              type: string
              const: prompt.steered
            id:
              type: string
              description: Sandbox id.
            conversationId:
              type: string
              description: The conversation whose running turn was steered.
            promptId:
              type: string
              description: >-
                Id of the steer record. It appears in `GET /events` as a `steer`
                event; it is not a prompt run and has no lifecycle to poll.
            native:
              type: boolean
              description: >-
                `true` when the harness accepted the message into the turn that
                was already running, so nothing was interrupted. `false` when
                Boat interrupted that turn and immediately continued the SAME
                conversation with the instruction, which keeps the harness
                session and all of its memory but may repeat a little of the
                work in flight.
            mode:
              type: string
              enum:
                - native
                - fallback
                - late
              description: >-
                How the message was delivered. `native` and `fallback` mirror
                the `native` field; `late` means the turn finished between the
                request and its delivery, so the message ran as an ordinary new
                turn on the conversation. A steer reported `native` here can
                settle as `native-continued` on the `steer` event: the harness
                accepted it but its turn ended without acting on it, so Boat
                continued it immediately as its own turn on the same session.
                Read the event for the settled mode.
            status:
              type: string
              enum:
                - steered
    SuccessBase:
      type: object
      required:
        - ok
        - type
      properties:
        ok:
          type: boolean
          examples:
            - true
        type:
          type: string
          description: Stable success envelope discriminator added by v1.
    ErrorEnvelope:
      type: object
      required:
        - ok
        - type
        - status
        - code
        - message
        - error
        - requestId
      properties:
        ok:
          type: boolean
          examples:
            - false
        type:
          type: string
          examples:
            - sandbox.error
        status:
          type: integer
          examples:
            - 409
        code:
          type: string
          examples:
            - provider_not_configured
        message:
          type: string
          examples:
            - Prompting is locked until Codex is configured on the Agents page.
        requestId:
          type: string
          examples:
            - req_01HX...
        error:
          type: object
          required:
            - code
            - message
            - status
          properties:
            code:
              type: string
            message:
              type: string
            status:
              type: integer
            details:
              type: object
              additionalProperties: true
  responses:
    BadRequest:
      description: Invalid request body or parameters.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          examples:
            invalid:
              value:
                ok: false
                type: sandbox.error
                status: 400
                code: invalid_json
                message: Request body must be valid JSON.
                error:
                  code: invalid_json
                  message: Request body must be valid JSON.
                  status: 400
                requestId: req_01HX...
    Unauthorized:
      description: Missing or invalid bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          examples:
            unauthorized:
              value:
                ok: false
                type: sandbox.error
                status: 401
                code: unauthorized
                message: Unauthorized
                error:
                  code: unauthorized
                  message: Unauthorized
                  status: 401
                requestId: req_01HX...
    PaymentRequired:
      description: >-
        Account cannot currently create or operate sandboxes. The error body may
        include a dashboard billing URL, but billing actions are not part of the
        v1 API.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Conflict:
      description: Request conflicts with current account or sandbox state.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  securitySchemes:
    BoatBearerAuth:
      type: http
      scheme: bearer
      bearerFormat: sandbox_api_key
      description: >-
        Boat bearer token in the form `boat_...`. Service API keys authenticate
        sandbox operations.

````