Skip to content
Core Engine + Concepts

gpty-core

Library crate for the gpty multi-PTY emulator. This is the engine - all terminal lifecycle, ANSI parsing, concept matching, capture buffering, and grid management live here.

Module Layout

Module Purpose Key Types
types Data vocabulary shared across all modules Concept, Action, TerminalConfig, CaptureMode, CapturedOutput, PaneType
concept Trigger matching (gated by a combined RegexSet) and capture routing ConceptMatcher, match_line()
agent_state Tiered, display-only agent-state detection (events / OSC / heuristics) AgentState, StateTier, AgentStateTracker
engine Runtime orchestrator; spawns terminal tasks, capture state machine WorkspaceEngine, PtyTerminalHandle, SpawnedTerminal, TaskContext
pty Cross-platform PTY lifecycle via portable-pty PtyHandle
cli cli_view backend: one argv child (never a shell); stdout+stderr merged into a bounded line queue CliProcess
parser Strips ANSI escape sequences; extracts plain-text lines LineParser
term Full terminal grid + damage tracking via alacritty_terminal TermGrid, CellInfo, GridUpdate
color ANSI color mapping - named, indexed, true-color → RGB color_to_rgb()
keymap Keyboard event → byte sequence translation key_event_to_bytes()
lock Poison-tolerant locking: skip the work, report the first occurrence lock_or_warn(), read_or_warn(), write_or_warn()
history SQLite-backed scrollback history store and its write-behind thread HistoryStore, PaneHistory
vault SQLite + FTS5 index over a directory of Markdown notes - the wiki pane’s list and search VaultStore, scan_vault(), index_vault()
links [[wikilink]] parsing (occurrences with their line; code and escapes are literal) and resolution against a note set (stem or path, exact case then a unique case-insensitive match, ambiguity never silently picked) parse_links(), Link, NoteIndex, Resolution

Concept System

Concepts capture terminal output and route it to a pane: a regular expression trigger, optional conditions (extra predicates over the same line), a stop condition, and a target pane kind.

Concept {
    name: "cat_command",
    trigger_regex: Regex::new(r"(?:^|[$#>]\s)\bcat\s+\S").unwrap(),
    conditions: vec![],
    enabled: true,
    capture_mode: CaptureMode::UntilStop { stop_timeout_ms: 300, stop_on_input: true },
    destinations: vec![Action { target_label: "code_viewer".into() }],
}

How it works:

  1. PTY output bytes stream through the vte parser
  2. The parser strips ANSI escape sequences and extracts visible text lines
  3. Each line is tested against every registered concept’s trigger_regex, then against its conditions (all must match the same line). One combined RegexSet pass answers “could anything match” first, so a line that matches no trigger - the common case - never enters the per-concept loop
  4. On an UntilStop match the terminal enters capture mode and buffers raw bytes; a SingleLine match is queued as a notice and stops here
  5. The capture ends on timeout (silence for N ms) or user input
  6. GDScript drains the completed capture and routes its text to the first pane whose type matches the action’s target_label - with no receiver, the raw bytes are replayed into the grid

Concepts never execute anything. A concept definition is data: it starts a capture and chooses which pane kind displays the result. It cannot write to a PTY. That is deliberate - the trigger is a regex over terminal output, which is untrusted, so a concept that could act would be an execution primitive driven by whatever a program happens to print. capture_mode is UntilStop (capture and route) or SingleLine (notify-only: the match is published on the event socket and nothing is captured, routed, or shown); a missing or unknown value captures, and a legacy cmd key in an action is ignored.

Key functions: match_line(), finalize_capture(), handle_command(), feed_grid(), store_line().

Use Cases

  • Read the code you just catted: cat README.md in a shell pane opens the file in a code viewer pane.
  • Error triage: route a compiler error block, a traceback, or a failing test log to the Inspector - gated behind its own opt-in (accept_concept_captures), because captured output leaves the terminal.
  • Diff and log review: git diff / git log output lands in a viewer pane instead of eating scrollback.
  • Documentation lookup: match a compiler error code and open the relevant snippet or link in an adjacent pane.

Why Flat?

All modules are single files in src/. When a module grows beyond ~200 lines or needs helper files, it will be promoted to src/<name>/mod.rs. This keeps navigation simple during prototyping while leaving room for future nesting.

Key Dependencies

Crate Version Role
portable-pty 0.9 Cross-platform PTY (Linux /dev/ptmx, Windows ConPTY)
vte 0.15 ANSI/VT100 escape sequence parser
alacritty_terminal 0.26 Full terminal grid emulator
tokio 1.52 Async runtime + broadcast channel
regex 1.12 Concept trigger patterns
rusqlite 0.31 SQLite storage: scrollback history and the vault index
serde 1 Serialization framework (derive support)
serde_json 1 JSON encoding for IPC + schema output