Skip to main content

Crate fno_agents

Crate fno_agents 

Source
Expand description

fno-agents substrate crate (Phase 6, ab-a09e1eaf).

This crate is the Rust substrate for PTY-managed agents (codex / gemini / future OpenCode). It is split per the design’s Locked Decisions:

§Scope of Wave 1 (this PR)

Wave 0’s smoke prototype (cli/scripts/smoke/pty-survival/) refuted the “direct daemon-owned PTY survives daemon restart” assertion: a child on a PTY whose master the supervisor owns is SIGHUP’d and dies the instant the master closes. The locked outcome (Outcome B) was a per-agent worker process that owned the master and outlived the daemon. That daemon-owned PTY hosting was retired at G4: the mux is now the agent-PTY substrate, and this crate keeps the registry, inside-leg reports, and the claude stream-json adopt lane.

Deliberately deferred (documented seams, not gaps):

  • alacritty_terminal grid wiring + per-CLI readiness::ReadinessDetector impls -> Wave 2, alongside the smoke captures that define the grid patterns (the trait operates over readiness::ScreenView so Wave 2 only adds impls).
  • tokio runtime integration -> Wave 3 (the daemon is its only consumer; the substrate stays runtime-agnostic and is driven from spawn_blocking).

§Scope of Wave 2 (this PR)

Wave 2 fills the seams Wave 1 left:

Modules§

active_backlog
Active backlog dispatcher: the mission drain-tick core + circuit breaker.
agents_config
Read agents.<provider>.headless_yolo (and sibling knobs) from config.toml.
agy_ask
Client-side agy -p ask path (Phase C, agy harness).
claims
Native work-claim substrate: a second implementation of the lockfile protocol owned by cli/src/fno/claims/ (Python stays the reference implementation and the only CLI surface).
claude_adopt
Adopt an externally-spawned claude --bg worker into the fno registry.
claude_ask
Client-side claude --bg ask path (ab-cc926b4e).
claude_attach
Speak Claude’s daemon control.sock: the op:'attach' handshake + the newline-delimited JSON transport.
claude_drive
The proven drive primitive: inject a turn into an adopted claude --bg session and confirm delivery by reading the session transcript.
claude_roster
Read Claude Code’s own daemon roster and resolve its control.sock / control.key.
client
Client side of the daemon protocol (Wave 3): lazy-start the daemon, connect, and forward one request. Kept in the library so it is exercised by the integration tests without shelling out to the compiled binary.
client_verbs
Client-side fno-agents verbs ported from the Python fno agents app (the “Python-only verbs” bucket: drive-authority, trace, ping, attach, resume, plus the non-streaming logs paths).
codex_ask
Client-side codex exec ask path (ab-0429c6e1).
codex_inject
mail-inject --harness codex: LIVE delivery into a running codex session over the codex app-server daemon socket (US8, node x-d899). The codex sibling of crate::mail_inject’s claude control.sock path. Python’s send path (_mail_inject_codex) runs this as a subprocess and falls back to the durable bus ONLY when it reports not-delivered (live-inject-first).
daemon
The supervisor daemon (Wave 3, tasks 3.0 + 3.4).
delivery_completion
Strict process boundary for explicitly activated generic delivery.
digest
fno-agents digest — the “while you were gone” fold (x-4e2d).
drift
Daemon binary-version drift detection (ab-1891cdff).
envelope
Structural anti-injection envelope (design module envelope.rs, LD15).
events
Operator-facing events.jsonl emitter (Wave 3, task 3.2).
finalize
fno-agents finalize (control-plane step 6, ab-f8e5f214): the terminal-only WRITER the stop-hook shim invokes on a terminal-allow loop-check decision.
gc
Dead-row garbage collection decision (x-b1aa).
gemini_ask
Client-side gemini -p ask path (ab-73da4ac2).
kill_criteria
fno-agents kill-check verb — Rust port of scripts/lib/kill-criteria.sh (packaging EPIC ab-8bdb4642, eliminate-don’t-vendor leg).
logs
Daemon-side agent.logs streaming handler (Category C / ab-d82655d7).
logs_client
Client side of fno agents logs <name> --follow for codex/gemini (Category C / ab-d82655d7).
loop_dispatch
Shellout dispatcher that wraps the bash driver-lib contract.
loop_runtime
Unified loop runtime primitive for target, megawalk, and megatron drivers.
loop_target
Target driver: TargetQueue + the loop run CLI verb.
loopcheck
fno-agents loop-check verb (Task 1.1, ab-d0337fbc).
mail_inject
mail-inject: the one-shot LIVE-DELIVERY verb fno mail send calls to inject an a2a turn into a LIVE adopted claude --bg session over the daemon control.sock. Python’s _deliver_live runs it as a binary subprocess and falls back to the durable bus queue ONLY when this reports not-delivered (live-inject-first, durable fallback – node x-1f23, epic x-07c1).
manifest
Detection manifest engine (E6.2).
needs
fno-agents needs - the needs-me-queue events-fold leg (x-feec).
nudge
P2 loop-boundary inbox nudge (ab-098967b4).
opencode_ask
Client interceptor for the ask verb on an opencode target (x-51f6), plus the headless one-shot dispatch (dispatch_opencode_once).
osc
OSC (Operating System Command) capture for the readiness read loop (E6.1).
paths
~/.fno/agents/ filesystem layout (Wave 3).
protocol
Unix-socket wire format (Wave 3, task 3.1).
provider
The Provider abstraction (design module provider.rs, LD8).
readiness
Readiness detection (design module readiness.rs).
scrape
Screen-manifest scrape sweep: the fallback rung of the badge lattice (pane-exit > inside-leg hook > screen-manifest > liveness).
screen
Terminal-grid construction behind the ScreenView seam (Wave 2).
spawn_gate
Spawn gate (x-c5cc): global concurrency cap + free-RAM floor + queue loop.
state
Shared state files (Wave 3): registry.json (schema v4) and per-agent state.json (schema v1), plus the flock-protected, atomic read/modify/write helpers the daemon and worker share.
stream_worker
Per-session stream-json worker (Group 1, Outcome B) — the claude analog of the retired PTY worker lane.
subprocess_ask
Shared one-shot-subprocess primitives for the client-side ask ports (codex + gemini). Extracted from codex_ask.rs (ab-73da4ac2) so the SIGINT forwarding, process-group kill, grace reap, watchdog, and output tee live in ONE place and the PR #371/#372 hardening carveouts apply to every provider:
subscribe
fno-agents subscribe – stream registry state transitions + pane exits as newline-delimited JSON.
supervisor
Restart policy state machine (design module supervisor.rs).
terminal_stop
Terminal-stop markers for fire-and-forget claude --bg workers (x-fcbf).
verify_evidence
fno-agents verify-evidence verb — Rust port of scripts/lib/verify-event-evidence.sh (packaging EPIC ab-8bdb4642, eliminate-don’t-vendor leg).
version
Shared version reporter for the fno-agents bins (client, daemon, worker).
wait
fno-agents wait – block until a named agent reaches a target state.
write_queue
Bounded-backpressure stdin queue (design module write_queue.rs).

Structs§

MonotonicTimestamp
A monotonic timestamp that counts during system sleep, used for drive-window heartbeat math (LD17 + Domain Pitfall: macOS/Linux suspend divergence).
ShortId

Enums§

AgentStatus
Agent lifecycle status. state.status is canonical; registry.status is a denormalized projection of it (LD10). Serialized snake_case for the JSON state files and the cross-language schemas.
ParsedEvent
Sealed event vocabulary every provider parses INTO (LD9). Variant additions are a one-line crate-wide change; no per-provider enums. #[serde(tag="kind")] matches the wire shape in the design’s Architecture section.
ShortIdError
A short, opaque agent identifier (e.g. wkA). Stored in the registry and used to name per-agent state directories. Validation is intentionally light at this layer; dispatch-layer validation (US1 invariant) owns argv rules.

Constants§

KNOWN_EVENT_KINDS
All real operator-facing event kinds emitted by the Rust supervisor. Excludes test-only kinds (tick, heartbeat).

Functions§

emit_schema_json
Build the unified (x-2901) events.jsonl envelope JSON Schema and the status-v1 AgentState schema as static JSON objects.