tuistory

repository·main·Indexed 43 days ago

https://github.com/remorses/tuistory

A tool for Playwright-like testing and automation of TUI applications. It provides a background relay daemon that allows AI agents and developers to wrap terminal commands in sessions, read logs, wait for specific output patterns, take screenshots, and simulate user input without blocking execution. Includes a CLI for session management and a TypeScript API via launchTerminal for programmatic control.

Tokens
10.4K
Snippets
41
Records
51
Agent score
56%

What's inside tuistory

  1. What is tuistory and when to use it

    main

    tuistory is a tool designed for AI agents to run and interact with dev servers and terminal user interfaces (TUIs) in named background sessions. It acts as a reactive alternative to tmux, allowing agents to wait for specific terminal output instead of using blind sleep commands, making automation faster and more reliable.

    Use tuistory to:

    • Run background dev servers or long-lived processes.
    • Control interactive CLIs and TUIs (typing, pressing keys, clicking, waiting, and taking snapshots).
    • Write Playwright-style tests for terminal applications.

    Core Interfaces:

    • CLI (tuistory): Used for managing background sessions.
    • JS/TS API (launchTerminal): Used for programmatic control and automated testing.
  2. Understand the tuistory Daemon Architecture

    main

    tuistory operates using a background relay daemon that maintains all sessions in memory.

    • Lifecycle: The first CLI command you run automatically starts the daemon. All subsequent commands connect to this existing daemon.
    • Auto-restart: If you upgrade the tuistory CLI, the next command will detect the version mismatch and automatically restart the daemon to match the new CLI version. This process is race-safe due to file locking.
    • Security: The daemon is secured by binding to 127.0.0.1, rejecting requests with an Origin header (to prevent browser-based attacks), and allow-listing specific host headers (127.0.0.1, localhost, [::1]) to prevent DNS rebinding.
  3. How tuistory sessions work

    main

    tuistory acts as "tmux for AI agents." It wraps any terminal command in a named background session.

    Key Concepts:

    • Background Execution: When an agent runs a command via tuistory, the command launches in the background and returns immediately, preventing the agent's tool call from hanging.
    • Shared State: Both humans and agents share the same terminal state. Humans can use tuistory attach to see live output and interact, while agents use CLI commands to read, wait, and type.
    • Human Interaction:
      • Ctrl+C twice: Detach from the session (the process keeps running).
      • Ctrl+X twice: Kill the process and close the session.
    • Idempotency: Running a command that is already running will reattach (for humans) or print session info (for agents) instead of failing with "port already in use" errors.
  4. Add tuistory to your dev script

    main

    The simplest way to use tuistory is to replace your dev command in package.json. This allows the dev server to run in the background so agents don't hang, while humans can still auto-attach to the session.

    When using this method, the session name is automatically derived from <cwd-basename>-<command> in kebab-case (e.g., a project in ~/myapp running next dev becomes myapp-next-dev).

    {
      "scripts": {
        "dev": "tuistory -- next dev"
      }
    }
    {
      "scripts": {
        "dev": "tuistory -- next dev"
      }
    }
  5. Set up a project to be agent-friendly with tuistory

    main

    To make a project's dev server accessible to agents, follow these three steps. This creates a shared dev session where humans and agents can collaborate on the same process.

    1. Add tuistory to dev dependencies:

      pnpm add -D tuistory
    2. Wrap dev scripts in package.json: Wrap long-running commands with tuistory --. Ensure tuistory -- is on the outside of any other wrappers (like sigillo or kimaki).

      {
        "scripts": {
          "dev": "tuistory -- next dev",
          "dev:api": "tuistory -- node api/server.js"
        }
      }
    3. Document in AGENTS.md: Add a section so agents know how to interact with the server without needing to know tuistory internals. Include commands for starting, restarting, reading logs, and waiting for readiness.

    {
      "scripts": {
        "dev": "tuistory -- next dev",
        "dev:api": "tuistory -- node api/server.js",
        "dev:worker": "tuistory -- wrangler dev"
      }
    }
  6. Install tuistory

    main

    Install tuistory via npm to wrap terminal commands in background sessions that AI agents can interact with.

    npm install tuistory

    Alternatively, install it globally or use via npx/bunx:

    npm install -g tuistory
    npx tuistory --help
    bunx tuistory --help
    npm install tuistory
  7. Use tuistory in Passthrough mode (traforo, sigillo)

    main

    When tuistory detects TRAFORO_URL (traforo) or SIGILLO (sigillo) environment variables, it enters passthrough mode. In this mode, it skips session management and spawns the command directly with inherited stdio.

    Crucial Pattern: If your dev script is wrapped in a tool like kimaki tunnel, the inner tuistory will be in passthrough mode and will block the agent. To get background session management for a tunneled server, you must use an outer tuistory command.

    Example: Running a tunneled dev server in the background:

    # Wrap the entire tunnel command with tuistory to ensure a background session
    tuistory -s myapp-dev -- kimaki tunnel -- pnpm dev
    
    # Now the agent can wait for the tunnel URL to appear in the background session
    tuistory -s myapp-dev wait "/tunnel/i" --timeout 30000
    
    # And read the output to find the public URL
    tuistory read -s myapp-dev
    tuistory -s myapp-dev -- kimaki tunnel -- pnpm dev
  8. Use the tuistory library for terminal automation

    main

    You can use tuistory programmatically in TypeScript to control terminal sessions (similar to Playwright for terminals). This is useful for testing or automating TTY-based applications like debuggers or interactive CLIs.

    To start, use launchTerminal to spawn a process and then interact with the returned session object.

    import { launchTerminal } from 'tuistory'
    
    const session = await launchTerminal({
      command: 'claude',
      args: [],
      cols: 150,
      rows: 45,
    })
    
    await session.waitForText('claude', { timeout: 10000 })
    
    // Interact with the session
    await session.type('/help')
    await session.press('enter')
    
    // Read output
    const output = session.read()
    
    // Cleanup
    await session.press(['ctrl', 'c'])
    session.close()
  9. Correct option ordering with `--`

    main

    When launching a session, tuistory options must come before the -- separator. Everything after -- is passed verbatim to the child process.

    # Correct: tuistory options first
    tuistory -s myserver --cols 150 -- node server.js --port 3000
    
    # Wrong: tuistory options after -- will be ignored by tuistory
    tuistory -- node server.js -s myserver --cols 150
    tuistory -s myserver --cols 150 -- node server.js --port 3000
  10. Automate dev server workflows with the CLI

    main

    Use these CLI patterns to manage background processes without blocking your terminal or wasting time with sleep.

    Background Process Loop

    1. Start: tuistory -- <command> (Session name is auto-derived from <cwd-basename>-<command>).
    2. Wait: tuistory -s <session-name> wait "<regex>" --timeout <ms> (Reacts as soon as output matches).
    3. Read: tuistory read -s <session-name> (View logs).
    4. Restart: tuistory -s <session-name> restart (Sends Ctrl+C, waits, and relaunches).

    Interactive TUI Loop

    1. Observe: tuistory -s <session-name> snapshot --trim (Capture current terminal state).
    2. Act: tuistory -s <session-name> press <key> (e.g., enter).
    3. Observe: tuistory -s <session-name> snapshot --trim.

    Important CLI Rules

    • Ordering: Options must come before --. The command and its arguments come after --.
      • Correct: tuistory -s myserver --cols 150 -- node server.js
      • Incorrect: tuistory -- node server.js -s myserver
  11. Wait for specific terminal output

    main

    Instead of using sleep, use wait or wait-idle to reactively wait for the terminal to reach a specific state. This is much faster and more reliable for automation.

    • Wait for a pattern: tuistory -s <name> wait "<pattern>" [--timeout <ms>]. Supports regex (e.g., /regex/).
    • Wait for stability: tuistory -s <name> wait-idle [--timeout <ms>]. Waits until the terminal stops receiving data (default ~200ms of silence).

    Example:

    tuistory -s my-server wait "ready on" --timeout 30000
    tuistory -s x wait "ready on" --timeout 30000
  12. Configure tuistory CLI options

    main

    Common options for tuistory commands:

    OptionDescription
    -s, --session <name>Session name (defaults to <cwd-basename>-<command>)
    --cols <n>Terminal columns (default: 120)
    --rows <n>Terminal rows (default: 36)
    --env <key=value>Environment variable (repeatable)
    --timeout <ms>Wait timeout in milliseconds
    --trimTrim whitespace from snapshot
    --jsonOutput as JSON
    --allFor read: return entire buffer
    --followFor read: block until new output