fno-agents 0.3.1

PTY supervisor substrate for persistent, attachable multi-CLI coding agents (codex, gemini, claude)
Documentation
# Gemini readiness manifest (E6.3) - declarative port of the hardcoded
# `GeminiReadinessDetector` / `prompt_ready` in `readiness.rs`.
#
# Identical in rule shape to codex.toml today (gemini shares PROMPT_GLYPHS and
# the same prompt_ready logic). Kept as its own file because manifests resolve
# per agent id and these WILL diverge when each is pinned against its live TUI;
# collapsing them would break the per-agent resolution the engine relies on.
#
# The load-bearing case (design Open Question #3): gemini's "Waiting for auth"
# is a known FALSE-READY - a prompt glyph is on screen but the CLI is at an auth
# wall. The auth_wall rule (priority 980, above idle_prompt's 100) is what keeps
# it from badging idle. See readiness.rs WALL_MARKERS.
#
# State vocabulary + arbitration: see codex.toml header (same contract).
#
# ponytail: glyphs/markers mirror readiness.rs; pin against a live gemini TUI
# (capture-readiness-grid.sh) when E2 lands. Conservative bias: a wrong glyph is
# false-NOT-ready, never false-ready.

[[rule]]
id = "auth_wall"
state = "blocked"
priority = 980
region = "bottom_non_empty_lines(3)"
gate = { any = [
  { contains = "Waiting for auth" },
  { contains = "waiting for auth" },
  { contains = "Do you trust" },
  { contains = "Login required" },
] }

[[rule]]
id = "busy"
state = "working"
priority = 900
region = "bottom_non_empty_lines(3)"
gate = { any = [
  { contains = "esc to interrupt" },
  { contains = "Esc to interrupt" },
  { contains = "Working" },
  { contains = "Thinking" },
] }

[[rule]]
id = "idle_prompt"
state = "idle"
priority = 100
region = "bottom_non_empty_lines(1)"
gate = { regex = '[\x{276f}\x{203a}\x{2595}][ \t]*$' }

# Answerable numbered prompt (x-5103). Gemini's trust prompt renders a BOXED
# numbered radio ("│ ● 1. Trust folder … │" / "│   2. … │" / "│   3. Don't trust │"):
# a left/right box border (│ U+2502) frames each line and the selected row
# carries a "●" (U+25CF) radio marker. Distinct from codex.toml (borderless, ›
# marker) - the divergence the per-agent split exists for. Validated against a
# live gemini TUI (fresh untrusted dir): the bare digit COMMITS and advances to
# the next screen, so send="digit"; digit_enter would leak a CR into that next
# prompt. Region is 12 (not codex's 10) because gemini's box padding lines count
# as non-empty, pushing the "Do you trust" question further up the window. The
# option regex consumes the optional border + radio marker before the digit and
# an optional trailing border after the label. Gated on the trust question AND a
# MARKED numbered line: the gate's line_regex REQUIRES the "●" radio glyph before
# the digit (the answer regex below keeps it optional to extract every option). A
# live radio always draws "●" on its current choice; a model reply printing "Do
# you trust …" plus a plain numbered list has no "●" before those digits, so it
# can't fake the gate and inject a digit into the composer (codex review P2). A
# bare auth wall keeps its focus-only auth_wall fallback.
[[rule]]
id = "trust_prompt"
state = "blocked"
priority = 985
region = "bottom_non_empty_lines(12)"
gate = { all = [
  { any = [ { contains = "Do you trust" }, { contains = "do you trust" } ] },
  { line_regex = '^\s*\x{2502}?\s*\x{25cf}\s*[0-9]\.\s' },
] }
[rule.answer]
option = '^\s*\x{2502}?\s*\x{25cf}?\s*(?P<idx>[0-9])\.\s+(?P<label>.+?)\s*\x{2502}?\s*$'
send = "digit"