[OneDev #11] research: interactive terminal driver app — TUI controller for scripted/automated shell workflows #18

Open
opened 2026-05-24 04:46:37 +00:00 by joseph · 2 comments
Owner

Imported from OneDev issue #11 (id 35277)
Original project: internal-joseph
Original state: Open
Original submitterId: 5
Original submitDate: 2026-04-10T16:44:10.771+00:00
Original lastActivity: {'date': '2026-04-24T21:24:45.415+00:00', 'description': 'commented', 'userId': 5}

Original fields:

  • Type: New Feature
  • Priority: Normal
  • Assignees: None

Idea

A TUI-first app that drives terminal sessions interactively — think a structured interface layered over a pty that lets you compose, inspect, and replay shell interactions. Could serve as an interactive front-end for automation scripts, command sequences, or remote session control with human-in-the-loop override capability.

Why

Pure automation is brittle; pure interactive is slow. A driver layer gives you the best of both — run scripted sequences but pause, inspect, and intervene at any step. Potentially useful for client onboarding scripts, diagnostic runbooks, or guided multi-step ops.

Open questions

  • Is this a standalone new tool or an extension of Station (TUI) / sshubble (remote runner)?
  • Target audience: Joseph only, or ship to clients/techs?
Imported from OneDev issue #11 (id 35277) Original project: internal-joseph Original state: Open Original submitterId: 5 Original submitDate: 2026-04-10T16:44:10.771+00:00 Original lastActivity: {'date': '2026-04-24T21:24:45.415+00:00', 'description': 'commented', 'userId': 5} Original fields: - Type: New Feature - Priority: Normal - Assignees: None ## Idea A TUI-first app that drives terminal sessions interactively — think a structured interface layered over a pty that lets you compose, inspect, and replay shell interactions. Could serve as an interactive front-end for automation scripts, command sequences, or remote session control with human-in-the-loop override capability. ## Why Pure automation is brittle; pure interactive is slow. A driver layer gives you the best of both — run scripted sequences but pause, inspect, and intervene at any step. Potentially useful for client onboarding scripts, diagnostic runbooks, or guided multi-step ops. ## Open questions - Is this a standalone new tool or an extension of Station (TUI) / sshubble (remote runner)? - Target audience: Joseph only, or ship to clients/techs?
Author
Owner

Imported from OneDev comment id 243 on issue #11
Original userId: 5
Original date: 2026-04-10T17:35:16.422+00:00

Research findings — interactive terminal driver / TUI controller

Landscape: key tools and trade-offs

Classic automation:

  • Expect / Tcl — original pty-spawn + pattern match. Still lowest common denominator. Dead language, Linux-only, no human-in-the-loop design.
  • pexpect (Python) — same model, pure Python. Has interact() (hands control to human mid-script) and autoexpect (records a session, emits a script). No Windows.
  • google/goexpect — Expect for Go. Has an SSH spawner (SpawnSSH, SpawnSSHPTY) — relevant to the PCT SSH-first model. No TUI layer, no Windows ConPTY. Last significant update 2020.
  • ActiveState/termtest — most mature cross-platform Go expect library. Wraps go-expect, adds xterm-compatible VT parser, scroll buffer, and Windows ConPTY support via ActiveState/termtest/conpty. Best for automated testing rather than presenting a TUI.

Session recording/replay:

  • asciinema — records terminal output as .cast JSON. Replay only, no pause-and-intervene.

tmux scripting:

  • tmux send-keys + capture-pane — what the current AI agent community uses. Zero new infrastructure, works on any Linux. Brittle text scraping, truncates, no structured breakpoints, Linux-only.
  • smux (ShawnPana) — tmux-bridge CLI for agent-to-agent coordination. Enforces read-before-act. Still fundamentally tmux send-keys underneath.

runme.dev — Markdown-as-runbook tool. Code blocks become executable steps with a TUI and CLI. No human-in-the-loop override mid-step, no Windows ConPTY. Worth cribbing the runbook schema from.


Human-in-the-loop patterns

Three patterns exist in the wild:

a. interact() escape hatch (pexpect/Expect) — automation runs, then at a decision point the library hands stdin/stdout to the human. Human types, presses a hotkey to return control. Simple on Linux, not portable to Windows, no visual chrome.

b. Approval-gate at step boundary — each step is discrete; script pauses between steps for human confirmation. This is the current Station wizard model. Works well and is Windows-compatible because no pty is needed — just waits for Enter.

c. Tmux pane capture + AI read-react loop — AI reads pane, decides what to send, human can intervene by physically typing. Not formally structured — no "pause requested" signal, just race conditions.

The gap: no structured, cross-platform tool exists that defines a runbook with named breakpoints, presents the human with context ("step 3 is about to run Set-ExecutionPolicy; approve?"), captures human edits to parameters, then resumes automation. That's the opportunity.


Go ecosystem options (Station is Go + Bubbletea)

  • tea.ExecProcess (Bubbletea built-in) — pauses the TUI, hands control to a subprocess. Loses the TUI panel while subprocess runs. Also documented as broken in Wish SSH sessions (issue #196). Not useful for showing live output alongside step controls.
  • taigrr/bubbleterm — embeddable terminal emulator Bubbletea component. Parses ANSI, maintains screen state, renders inside a Bubbletea viewport via pipes. This is the key component for embedding live pty output inside a TUI layout — right pane shows subprocess output, left pane shows step controls. Integrates with creack/pty. Maturity needs validation.
  • aymanbagabas/go-pty — cross-platform Go pty interface by a Charmbracelet maintainer. Returns ReadWriteCloser; Unix = POSIX pty, Windows = ConPTY via custom spawner. Best option for pty on both Linux and Windows from Go, but requires library's own Cmd wrapper (not os/exec).
  • google/goexpect — SSH spawner is particularly relevant for driving Linux containers over SSH from a Windows Station instance.

Windows / ConPTY considerations

ConPTY (Windows 10 1809+) is the Windows pty equivalent but requires PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE at process creation — not supported by Go's os/exec. Go proposal golang/go#62708 remains unresolved as of early 2026.

Workarounds (aymanbagabas/go-pty, ActiveState/termtest/conpty, UserExistsError/conpty) call CreateProcess directly via golang.org/x/sys/windows. Works but has reported instability: ERROR_INSUFFICIENT_BUFFER from CreatePseudoConsole on some machines, 0xc0000142 process exits, win32-input-mode encoding changes.

Practical consequence: If the target is a Linux LXC container over SSH, you avoid ConPTY entirely — the pty lives Linux-side. If the target is a local Windows process on a client machine, you need ConPTY or fall back to non-interactive (what sshubble currently does). Defer ConPTY to v0.2 and validate on VMID 130 first.


Recommendation: extend Station as a new subcommand

Not a sshubble extension. sshubble uses SSH exec channel (non-interactive), captures output, returns it. Adding structured interactive control would require replacing the execution model. Web operator UI is not the right interface for a technician walking a runbook.

Not a Station wizard extension. The existing wizard is a one-way installer — fixed sequence, no runtime input, no branching, no external process driving. Grafting pty embedding onto it distorts the architecture.

station run <runbook.yaml> is the right fit. Station: (1) already deployed to client Windows machines, (2) uses Bubbletea for TUI, (3) has two-pane layout established in the issues browser, (4) has Cobra command routing, (5) already integrates with sshubble's transport for remote commands. A new subcommand adds driver capability without disrupting existing functionality.

For Linux targets (LXC containers): use google/goexpect's SSH spawner or a direct SSH shell channel with aymanbagabas/go-pty on the remote side. Pty complexity stays server-side.

For Windows local targets (client machines): v0.1 avoids ConPTY — use structured command sequences via powershell -NonInteractive. Reserve ConPTY for v0.2 after VMID 130 validation.


Minimum viable design sketch (v0.1)

Command: station run <runbook.yaml>

Runbook YAML:

name: "INKY Onboarding"
target: ssh
host: "{{ session.code }}"
steps:
  - name: "Check PS version"
    command: "$PSVersionTable.PSVersion"
    expect: "5\\.|7\\."
    on_fail: pause

  - name: "Set execution policy"
    command: "Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force"
    approve: true
    timeout: 30

  - name: "Install INKY agent"
    command: "irm https://inky.example.com/install.ps1 | iex"
    approve: true
    expect: "Installation complete"
    timeout: 120

TUI layout (two-pane):

┌─────────────────────┬────────────────────────────────────┐
│  INKY Onboarding    │  Step 3: Install INKY agent        │
│  ─────────────────  │                                    │
│  ✓ Check PS ver     │  Command:                          │
│  ✓ Exec policy      │  irm https://inky.../install.ps1   │
│  ● Install INKY   ← │  | iex                             │
│  ○ Confirm svc      │                                    │
│                     │  Output:                           │
│  [s]kip [a]bort     │  Downloading INKY agent...         │
│                     │  Installing service...             │
│  Step 3 of 4        │  ▌ (live scroll)                   │
│                     │                                    │
│                     │  [Enter] next  [e] edit cmd        │
└─────────────────────┴────────────────────────────────────┘

v0.1 scope:

  • approve: true steps show confirmation before executing; tech can edit command inline
  • Output in scrolling viewport (Bubbletea viewport, not embedded pty emulator)
  • expect field: string/regex match; mismatch triggers on_fail behavior
  • pause on fail: halts automation, presents manual override prompt, tech can edit and retry
  • SSH transport: reuse sshubble's non-interactive exec model
  • Session log: every command + output + approval timestamp → .jsonl audit trail
  • Runbooks loaded from ~/.station/runbooks/ or URL

v0.1 defers: ConPTY, interactive subprocess embedding (bubbleterm), branching/conditionals, variable interpolation, web operator view, replay from recorded sessions.


Open questions remaining

  1. Runbook distribution: YAML by hand, or a PCT-maintained library pulled on demand (git repo, same ExecStartPre=git pull pattern as other services)?
  2. ConPTY production viability: needs a validation run on VMID 130 with aymanbagabas/go-pty or ActiveState/termtest/conpty before scoping v0.2.
  3. Target audience: internal techs only, or self-service on client machines? Changes security model significantly.
  4. sshubble session handoff: how does station run get the sshubble session code — flag, interactive prompt, or env var from daemon?
  5. taigrr/bubbleterm maturity: ANSI coverage needs validation against PowerShell output and common Linux shell prompts before adopting.
  6. runme as prior art: spend 30min with runme tui on a Linux container before writing the YAML schema from scratch — worth cribbing from even if the tool itself doesn't fit.

Relationship to #13 (tui-use): tui-use would be the substrate for the interactive subprocess embedding feature (v0.2+) — specifically for the right-pane live terminal view in the TUI layout. Currently rated BENCH (3 days old, one maintainer). Re-evaluate around 2026-04-24; if stable, it replaces the need to wire taigrr/bubbleterm + aymanbagabas/go-pty manually.

Imported from OneDev comment id 243 on issue #11 Original userId: 5 Original date: 2026-04-10T17:35:16.422+00:00 ## Research findings — interactive terminal driver / TUI controller ### Landscape: key tools and trade-offs **Classic automation:** - **Expect / Tcl** — original pty-spawn + pattern match. Still lowest common denominator. Dead language, Linux-only, no human-in-the-loop design. - **pexpect (Python)** — same model, pure Python. Has `interact()` (hands control to human mid-script) and `autoexpect` (records a session, emits a script). No Windows. - **google/goexpect** — Expect for Go. Has an SSH spawner (`SpawnSSH`, `SpawnSSHPTY`) — relevant to the PCT SSH-first model. No TUI layer, no Windows ConPTY. Last significant update 2020. - **ActiveState/termtest** — most mature cross-platform Go expect library. Wraps go-expect, adds xterm-compatible VT parser, scroll buffer, and Windows ConPTY support via `ActiveState/termtest/conpty`. Best for automated testing rather than presenting a TUI. **Session recording/replay:** - **asciinema** — records terminal output as `.cast` JSON. Replay only, no pause-and-intervene. **tmux scripting:** - **tmux send-keys + capture-pane** — what the current AI agent community uses. Zero new infrastructure, works on any Linux. Brittle text scraping, truncates, no structured breakpoints, Linux-only. - **smux (ShawnPana)** — tmux-bridge CLI for agent-to-agent coordination. Enforces read-before-act. Still fundamentally tmux send-keys underneath. **runme.dev** — Markdown-as-runbook tool. Code blocks become executable steps with a TUI and CLI. No human-in-the-loop override mid-step, no Windows ConPTY. Worth cribbing the runbook schema from. --- ### Human-in-the-loop patterns Three patterns exist in the wild: **a. `interact()` escape hatch** (pexpect/Expect) — automation runs, then at a decision point the library hands stdin/stdout to the human. Human types, presses a hotkey to return control. Simple on Linux, not portable to Windows, no visual chrome. **b. Approval-gate at step boundary** — each step is discrete; script pauses between steps for human confirmation. This is the current Station wizard model. Works well and is Windows-compatible because no pty is needed — just waits for Enter. **c. Tmux pane capture + AI read-react loop** — AI reads pane, decides what to send, human can intervene by physically typing. Not formally structured — no "pause requested" signal, just race conditions. **The gap:** no structured, cross-platform tool exists that defines a runbook with named breakpoints, presents the human with context ("step 3 is about to run `Set-ExecutionPolicy`; approve?"), captures human edits to parameters, then resumes automation. That's the opportunity. --- ### Go ecosystem options (Station is Go + Bubbletea) - **`tea.ExecProcess`** (Bubbletea built-in) — pauses the TUI, hands control to a subprocess. Loses the TUI panel while subprocess runs. Also documented as broken in Wish SSH sessions (issue #196). Not useful for showing live output alongside step controls. - **`taigrr/bubbleterm`** — embeddable terminal emulator Bubbletea component. Parses ANSI, maintains screen state, renders inside a Bubbletea viewport via pipes. This is the key component for embedding live pty output inside a TUI layout — right pane shows subprocess output, left pane shows step controls. Integrates with creack/pty. Maturity needs validation. - **`aymanbagabas/go-pty`** — cross-platform Go pty interface by a Charmbracelet maintainer. Returns ReadWriteCloser; Unix = POSIX pty, Windows = ConPTY via custom spawner. Best option for pty on both Linux and Windows from Go, but requires library's own `Cmd` wrapper (not `os/exec`). - **`google/goexpect`** — SSH spawner is particularly relevant for driving Linux containers over SSH from a Windows Station instance. --- ### Windows / ConPTY considerations ConPTY (Windows 10 1809+) is the Windows pty equivalent but requires `PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE` at process creation — not supported by Go's `os/exec`. Go proposal golang/go#62708 remains unresolved as of early 2026. Workarounds (`aymanbagabas/go-pty`, `ActiveState/termtest/conpty`, `UserExistsError/conpty`) call `CreateProcess` directly via `golang.org/x/sys/windows`. Works but has reported instability: `ERROR_INSUFFICIENT_BUFFER` from `CreatePseudoConsole` on some machines, `0xc0000142` process exits, win32-input-mode encoding changes. **Practical consequence:** If the target is a Linux LXC container over SSH, you avoid ConPTY entirely — the pty lives Linux-side. If the target is a local Windows process on a client machine, you need ConPTY or fall back to non-interactive (what sshubble currently does). Defer ConPTY to v0.2 and validate on VMID 130 first. --- ### Recommendation: extend Station as a new subcommand **Not a sshubble extension.** sshubble uses SSH exec channel (non-interactive), captures output, returns it. Adding structured interactive control would require replacing the execution model. Web operator UI is not the right interface for a technician walking a runbook. **Not a Station wizard extension.** The existing wizard is a one-way installer — fixed sequence, no runtime input, no branching, no external process driving. Grafting pty embedding onto it distorts the architecture. **`station run <runbook.yaml>` is the right fit.** Station: (1) already deployed to client Windows machines, (2) uses Bubbletea for TUI, (3) has two-pane layout established in the issues browser, (4) has Cobra command routing, (5) already integrates with sshubble's transport for remote commands. A new subcommand adds driver capability without disrupting existing functionality. **For Linux targets (LXC containers):** use `google/goexpect`'s SSH spawner or a direct SSH shell channel with `aymanbagabas/go-pty` on the remote side. Pty complexity stays server-side. **For Windows local targets (client machines):** v0.1 avoids ConPTY — use structured command sequences via `powershell -NonInteractive`. Reserve ConPTY for v0.2 after VMID 130 validation. --- ### Minimum viable design sketch (v0.1) **Command:** `station run <runbook.yaml>` **Runbook YAML:** ```yaml name: "INKY Onboarding" target: ssh host: "{{ session.code }}" steps: - name: "Check PS version" command: "$PSVersionTable.PSVersion" expect: "5\\.|7\\." on_fail: pause - name: "Set execution policy" command: "Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force" approve: true timeout: 30 - name: "Install INKY agent" command: "irm https://inky.example.com/install.ps1 | iex" approve: true expect: "Installation complete" timeout: 120 ``` **TUI layout (two-pane):** ``` ┌─────────────────────┬────────────────────────────────────┐ │ INKY Onboarding │ Step 3: Install INKY agent │ │ ───────────────── │ │ │ ✓ Check PS ver │ Command: │ │ ✓ Exec policy │ irm https://inky.../install.ps1 │ │ ● Install INKY ← │ | iex │ │ ○ Confirm svc │ │ │ │ Output: │ │ [s]kip [a]bort │ Downloading INKY agent... │ │ │ Installing service... │ │ Step 3 of 4 │ ▌ (live scroll) │ │ │ │ │ │ [Enter] next [e] edit cmd │ └─────────────────────┴────────────────────────────────────┘ ``` **v0.1 scope:** - `approve: true` steps show confirmation before executing; tech can edit command inline - Output in scrolling viewport (Bubbletea viewport, not embedded pty emulator) - `expect` field: string/regex match; mismatch triggers `on_fail` behavior - `pause` on fail: halts automation, presents manual override prompt, tech can edit and retry - SSH transport: reuse sshubble's non-interactive exec model - Session log: every command + output + approval timestamp → `.jsonl` audit trail - Runbooks loaded from `~/.station/runbooks/` or URL **v0.1 defers:** ConPTY, interactive subprocess embedding (`bubbleterm`), branching/conditionals, variable interpolation, web operator view, replay from recorded sessions. --- ### Open questions remaining 1. **Runbook distribution:** YAML by hand, or a PCT-maintained library pulled on demand (git repo, same `ExecStartPre=git pull` pattern as other services)? 2. **ConPTY production viability:** needs a validation run on VMID 130 with `aymanbagabas/go-pty` or `ActiveState/termtest/conpty` before scoping v0.2. 3. **Target audience:** internal techs only, or self-service on client machines? Changes security model significantly. 4. **sshubble session handoff:** how does `station run` get the sshubble session code — flag, interactive prompt, or env var from daemon? 5. **`taigrr/bubbleterm` maturity:** ANSI coverage needs validation against PowerShell output and common Linux shell prompts before adopting. 6. **runme as prior art:** spend 30min with `runme tui` on a Linux container before writing the YAML schema from scratch — worth cribbing from even if the tool itself doesn't fit. --- **Relationship to #13 (tui-use):** tui-use would be the substrate for the interactive subprocess embedding feature (v0.2+) — specifically for the right-pane live terminal view in the TUI layout. Currently rated BENCH (3 days old, one maintainer). Re-evaluate around 2026-04-24; if stable, it replaces the need to wire `taigrr/bubbleterm` + `aymanbagabas/go-pty` manually.
Author
Owner

Imported from OneDev comment id 458 on issue #11
Original userId: 5
Original date: 2026-04-24T21:24:45.415+00:00

Ghst partially moots this — the "PTY substrate for an AI agent" piece is solved. What remains is the technician-facing runbook driver concept (YAML runbooks, two-pane Station TUI with approval gates). That's a product idea separate from ghst. Recommend narrowing this issue to just the station run <runbook.yaml> proposal and deciding whether it's on the Station roadmap. No code action until that product call is made.

Imported from OneDev comment id 458 on issue #11 Original userId: 5 Original date: 2026-04-24T21:24:45.415+00:00 Ghst partially moots this — the "PTY substrate for an AI agent" piece is solved. What remains is the technician-facing runbook driver concept (YAML runbooks, two-pane Station TUI with approval gates). That's a product idea separate from ghst. Recommend narrowing this issue to just the `station run <runbook.yaml>` proposal and deciding whether it's on the Station roadmap. No code action until that product call is made.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
joseph/internal-joseph#18
No description provided.