specs/005-agent-manifests-proc/spec.md
Feature Specification: Agent Manifests + Live /proc Refresh
Feature Branch: 005-agent-manifests-proc
Created: 2026-09-29
Status: Draft
Input: User description: "docs/14 directive 3 requires Know-thy-agents
two ways — hooks plus declarative per-agent detection manifests (herdr
manifests/*.toml: data, not code). Today every adapter is hardcoded Rust,
and spawn-time argv is the only process signal (no live /proc refresh even
though docs/02, docs/07 promise cwd/kind tracking)."
User Scenarios & Testing (mandatory)
User Story 1 - Extend detection without recompiling (Priority: P1)
A user runs agents through wrapper scripts (codex-wrap) or needs a new
hook mapping after a CLI update. They drop one TOML file into the agents
dir and the server picks it up on restart (and integration status shows
it) — no Rust change, no rebuild.
Why this priority: Directive 3 verbatim — "data, not code, community-extensible". Hardcoded adapters mean every CLI churn is a code change.
Independent Test: manifest mapping sleep→codex binaries in an
isolated agents dir; hook-event --agent codex from that binary classifies
as codex; malformed manifest logged + skipped, server still starts.
Acceptance Scenarios:
- Given
agents/codex-extra.tomlwithbinaries = ["codex-wrap"], When a pane spawnscodex-wrap, Then its kind iscodex. - Given a manifest with
[lifecycle.SomeFutureHook] lifecycle = "working", When that hook arrives, Then lifecycle is working (builtin fallthrough for unmapped hooks is unchanged). - Given a malformed manifest, When the server starts, Then it logs, skips that file, and serves everything else.
User Story 2 - Panes track the live process (Priority: P2)
A pane spawns sh which execs codex (or the user runs another agent
inside a shell). Within seconds the sidebar shows the real agent and the
real cwd — without hooks, without restart.
Why this priority: Docs/07 layer 4 (foreground process info) and
docs/02 (cwd refreshed from /proc) are promised but unimplemented;
spawn argv alone mislabels every shell-hosted agent.
Independent Test: spawn sh -c 'sleep 30' as generic; proc tick
keeps kind generic but refreshes cwd; spawn with manifest mapping
sleep→codex; tick promotes kind to codex and emits pane.updated
once (quiet afterwards).
Acceptance Scenarios:
- Given a live generic pane whose deepest child is a manifested
binary, When the proc tick runs, Then kind promotes (generic
→ specific only, never demotes) and one
pane.updatedemits. - Given a pane whose child cd's, When the tick runs, Then
pane.cwdfollows/proc/<pid>/cwdand emits on change only. - Given no change, When ticks run, Then no events, no persistence marks.
Requirements (mandatory)
Functional Requirements
- FR-001: Manifests live in
paths::agents_dir()($XDG_CONFIG_HOME/ signaltty/agents/*.toml,SIGNALTTY_AGENTS_DIRoverride); loaded once at server start; failures isolated per file. - FR-002: Manifest
kindMUST be an existingAgentKind(no new agent taxonomy without a Rust adapter — taxonomy stays typed). - FR-003: Overlays merge: extra
binaries, per-hook{lifecycle?, attention?, message?}overrides,session.keypayload key,resumeargv template with{session_id},display_nameoverride. Everything unmapped falls through to the builtin adapter. - FR-004: Hook routing (
agentname) and spawn detection consult overlays first;detect_kindtakes the overlay binaries into account. - FR-005: Proc tick every 10s over live panes only: deepest-descendant
basename → kind promotion (generic/none → specific),
/proccwd →pane.cwd; emitpane.updated+ persist only on change. - FR-006:
integration statusreports loaded manifests (name, kind, file) alongside hook shims.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: Manifest-only test (no Rust change) promotes a
sleeppane to codex end-to-end over the socket. - SC-002: A cwd change inside a live pane appears in
pane.getwithin ~15s with exactly onepane.updated. - SC-003: Malformed manifest never prevents startup (integration test with garbage file).