# read_program

Source: https://libtmux.org/en/ts/latest/mcp/tools/read_program/

> Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read what a started program printed after cursor, waiting up to timeoutMs for new output or its end, and report whether it has ended and how. Omit cursor on the first read and pass back the one returned; a read returns up to about 24,000 characters of text, ending on a line break, or maxLines lines when fewer, so call again with the cursor for the rest; a read that times out returns no text, and the next read with the same cursor carries on. The text is the byte stream with escape sequences removed, in write order, and a carriage return on its own starts a new line, so each state of a progress line is a line; capture_pane on its paneId shows the screen while it runs, and after the end for one beside fromPaneId, whose pane stays until stop_program or its lifetime. Output stays readable after the end until stop_program, or until enough programs have ended after it.

tool MCPlatest

MCP concept example

A working example of the core library. It can change without notice.

[What concept means](https://libtmux.org/en/meta/support/#concept-and-alpha)

* **read_program**( [cursor](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2Fcursor)?: [integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"), [maxLines](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2FmaxLines)?: [integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"), [programId](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2FprogramId): [string](https://json-schema.org/understanding-json-schema/reference/string "string (JSON Schema)"), [timeoutMs](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2FtimeoutMs)?: [integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"), )

  tool \[[source](https://github.com/libtmux/libtmux-ts/blob/f7b03a361f7c97677406b4ab937b2772ddb5f7dd/packages/mcp/src/tools/programs.ts#L378)][¶](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program)

  Read pane output; accepts no client-supplied executable input. Returned content may be sensitive or untrusted. Read what a started program printed after cursor, waiting up to timeoutMs for new output or its end, and report whether it has ended and how. Omit cursor on the first read and pass back the one returned; a read returns up to about 24,000 characters of text, ending on a line break, or maxLines lines when fewer, so call again with the cursor for the rest; a read that times out returns no text, and the next read with the same cursor carries on. The text is the byte stream with escape sequences removed, in write order, and a carriage return on its own starts a new line, so each state of a progress line is a line; [capture_pane](https://libtmux.org/en/ts/latest/mcp/tools/capture_pane/) on its paneId shows the screen while it runs, and after the end for one beside fromPaneId, whose pane stays until [stop_program](https://libtmux.org/en/ts/latest/mcp/tools/stop_program/) or its lifetime. Output stays readable after the end until [stop_program](https://libtmux.org/en/ts/latest/mcp/tools/stop_program/), or until enough programs have ended after it.

  * MCP request method

    `tools/call` Send `read_program` as the tool name, with the arguments below.

  ## Arguments[#](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.parameters)

  * **[`cursor`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2Fcursor)**? ([integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"))

    The cursor the previous read_program returned. Omit to read from the start.

    * minimum

      `0`

    * maximum

      `9007199254740991`

  * **[`maxLines`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2FmaxLines)**? ([integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"))

    Return at most this many lines from cursor. A page also stops at about 24,000 characters, so fewer lines come back when they are long.

    * maximum

      `9007199254740991`

    * exclusiveMinimum

      `0`

  * **[`programId`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2FprogramId)** ([string](https://json-schema.org/understanding-json-schema/reference/string "string (JSON Schema)"))

    The id [start_program](https://libtmux.org/en/ts/latest/mcp/tools/start_program/) returned.

    * minLength

      `1`

    * maxLength

      `64`

  * **[`timeoutMs`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.input%2Fproperties%2FtimeoutMs)**? ([integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"))

    How long to wait for something new: 0 returns at once, and omitted is 30 seconds. Clamped by the server ceiling.

    * minimum

      `0`

    * maximum

      `9007199254740991`

  ## Result[#](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.result)

  Returns [object](https://json-schema.org/understanding-json-schema/reference/object "object (JSON Schema)")

  * **[`cursor`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2Fcursor)** ([integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"))

    Pass to the next read_program.

    * minimum

      `-9007199254740991`

    * maximum

      `9007199254740991`

  * **[`effectiveTimeoutMs`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2FeffectiveTimeoutMs)** ([integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"))

    The wait allowed.

    * minimum

      `-9007199254740991`

    * maximum

      `9007199254740991`

  * **[`ended`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2Fended)** ([boolean](https://json-schema.org/understanding-json-schema/reference/boolean "boolean (JSON Schema)"))

    Whether it has ended and every byte it wrote has been returned. Until it is true, call again with cursor.

  * **[`exitStatus`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2FexitStatus)** ([integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)") | [null](https://json-schema.org/understanding-json-schema/reference/null "null (JSON Schema)"))

    The exit status once it completed, or 127 or 126 when not_started; null for a program a signal ended (see signal) or one still running.

    Matches one or more variants.

    * **[Variant 1](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2FexitStatus%2FanyOf%2F0)** ([integer](https://json-schema.org/understanding-json-schema/reference/numeric "numeric (JSON Schema)"))

      * minimum

        `-9007199254740991`

      * maximum

        `9007199254740991`

  * **[`lostEnd`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2FlostEnd)** ([boolean](https://json-schema.org/understanding-json-schema/reference/boolean "boolean (JSON Schema)"))

    True when tmux closed the pane before reading the end of the output.

  * **[`outcome`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2Foutcome)** ("running" | "completed" | "not_started" | "expired" | "stopped" | "gone")

    How the program stands, set from the first read after it ends, while ended stays false until its output is all read. running: it still runs. completed: it ended on its own, as exitStatus or signal says. not_started: it never ran, because argv\[0] was not found or is not executable, or startDirectory could not be entered; text says which. expired: its lifetime ended it; start it again with a longer lifetimeMs. stopped: [stop_program](https://libtmux.org/en/ts/latest/mcp/tools/stop_program/) ended it while this read waited. gone: its pane was removed from outside, with no status.

  * **[`outputComplete`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2FoutputComplete)** ([boolean](https://json-schema.org/understanding-json-schema/reference/boolean "boolean (JSON Schema)"))

    True once ended is true and nothing is missing. False while it runs, when outputCut or lostEnd is true, or when a stop or the lifetime ended the program before its output was read to the end.

  * **[`outputCut`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2FoutputCut)** ([boolean](https://json-schema.org/understanding-json-schema/reference/boolean "boolean (JSON Schema)"))

    True once the copy stopped at its limit; later output is not kept.

  * **[`signal`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2Fsignal)** ([string](https://json-schema.org/understanding-json-schema/reference/string "string (JSON Schema)") | [null](https://json-schema.org/understanding-json-schema/reference/null "null (JSON Schema)"))

    The signal that ended the program, such as “SIGTERM”; otherwise null. A program that exits 130 on its own reads as SIGINT, as that status means.

  * **[`text`](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.output%2Fproperties%2Ftext)** ([string](https://json-schema.org/understanding-json-schema/reference/string "string (JSON Schema)"))

    What it printed after cursor.

  No other properties are accepted.

  ## Annotations[#](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.annotations)

  * [`destructiveHint`](https://libtmux.org/en/ts/latest/mcp/reference/glossary/#destructiveHint)

    `true`

  * [`idempotentHint`](https://libtmux.org/en/ts/latest/mcp/reference/glossary/#idempotentHint)

    `false`

  * [`openWorldHint`](https://libtmux.org/en/ts/latest/mcp/reference/glossary/#openWorldHint)

    `true`

  * [`readOnlyHint`](https://libtmux.org/en/ts/latest/mcp/reference/glossary/#readOnlyHint)

    `false`

  ## Protocol data[#](https://libtmux.org/en/ts/latest/mcp/tools/read_program/#mcp.tool.read_program.schemas)

  Use the complete advertised contract for validation and client integration.

  Input schema

  ```json
  {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "properties": {
      "cursor": {
        "description": "The cursor the previous read_program returned. Omit to read from the start.",
        "maximum": 9007199254740991,
        "minimum": 0,
        "type": "integer"
      },
      "maxLines": {
        "description": "Return at most this many lines from cursor. A page also stops at about 24,000 characters, so fewer lines come back when they are long.",
        "exclusiveMinimum": 0,
        "maximum": 9007199254740991,
        "type": "integer"
      },
      "programId": {
        "description": "The id start_program returned.",
        "maxLength": 64,
        "minLength": 1,
        "type": "string"
      },
      "timeoutMs": {
        "description": "How long to wait for something new: 0 returns at once, and omitted is 30 seconds. Clamped by the server ceiling.",
        "maximum": 9007199254740991,
        "minimum": 0,
        "type": "integer"
      }
    },
    "required": [
      "programId"
    ],
    "type": "object"
  }
  ```

  Output schema

  ```json
  {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "additionalProperties": false,
    "properties": {
      "cursor": {
        "description": "Pass to the next read_program.",
        "maximum": 9007199254740991,
        "minimum": -9007199254740991,
        "type": "integer"
      },
      "effectiveTimeoutMs": {
        "description": "The wait allowed.",
        "maximum": 9007199254740991,
        "minimum": -9007199254740991,
        "type": "integer"
      },
      "ended": {
        "description": "Whether it has ended and every byte it wrote has been returned. Until it is true, call again with cursor.",
        "type": "boolean"
      },
      "exitStatus": {
        "anyOf": [
          {
            "maximum": 9007199254740991,
            "minimum": -9007199254740991,
            "type": "integer"
          },
          {
            "type": "null"
          }
        ],
        "description": "The exit status once it completed, or 127 or 126 when not_started; null for a program a signal ended (see signal) or one still running."
      },
      "lostEnd": {
        "description": "True when tmux closed the pane before reading the end of the output.",
        "type": "boolean"
      },
      "outcome": {
        "description": "How the program stands, set from the first read after it ends, while ended stays false until its output is all read. running: it still runs. completed: it ended on its own, as exitStatus or signal says. not_started: it never ran, because argv[0] was not found or is not executable, or startDirectory could not be entered; text says which. expired: its lifetime ended it; start it again with a longer lifetimeMs. stopped: stop_program ended it while this read waited. gone: its pane was removed from outside, with no status.",
        "enum": [
          "running",
          "completed",
          "not_started",
          "expired",
          "stopped",
          "gone"
        ],
        "type": "string"
      },
      "outputComplete": {
        "description": "True once ended is true and nothing is missing. False while it runs, when outputCut or lostEnd is true, or when a stop or the lifetime ended the program before its output was read to the end.",
        "type": "boolean"
      },
      "outputCut": {
        "description": "True once the copy stopped at its limit; later output is not kept.",
        "type": "boolean"
      },
      "signal": {
        "description": "The signal that ended the program, such as \"SIGTERM\"; otherwise null. A program that exits 130 on its own reads as SIGINT, as that status means.",
        "type": [
          "string",
          "null"
        ]
      },
      "text": {
        "description": "What it printed after cursor.",
        "type": "string"
      }
    },
    "required": [
      "cursor",
      "effectiveTimeoutMs",
      "ended",
      "exitStatus",
      "lostEnd",
      "outcome",
      "outputComplete",
      "outputCut",
      "signal",
      "text"
    ],
    "type": "object"
  }
  ```
