# car-registry
File-based agent registry for cross-process discovery, used by menubar
/ tray UIs that want to enumerate locally running agents without
running a coordinating daemon.
## How it works
Each agent owns one JSON file under `~/.car/registry/<name>.json`. On
startup it calls `AgentRegistry::register`, which atomically writes the
entry (temp file + rename). Periodically it calls `heartbeat` to bump
`last_heartbeat_at`. On shutdown — or after a panic, on next launch —
`unregister` removes the file. UIs poll with `list`, optionally
calling `reap_stale(timeout)` first to drop entries whose last
heartbeat is too old.
There is no daemon, no shared lock, no IPC. The directory is the
shared state; atomic writes give consistency.
## API
```rust
use car_registry::{AgentEntry, AgentRegistry, AgentStatus};
let reg = AgentRegistry::new()?; // ~/.car/registry/
reg.register(AgentEntry {
name: "musicart".into(),
display_name: Some("MusicArt".into()),
dashboard_url: "http://127.0.0.1:8723".into(),
status: AgentStatus::Running,
port: Some(8723),
pid: Some(std::process::id()),
registered_at: 0, // 0 = now
last_heartbeat_at: 0,
})?;
reg.heartbeat("musicart")?;
let agents = reg.list()?;
reg.reap_stale(std::time::Duration::from_secs(120))?;
reg.unregister("musicart")?;
```
## File layout
```
~/.car/registry/
musicart.json
flyx.json
car-host.json
```
Each file is a `AgentEntry` serialized as JSON. Filenames mirror the
agent name; non-filesystem-safe characters are rejected at register
time.
## Crash-durable reboot cutover proof
The crate also contains the prove-first `reboot_cutover` filesystem
transaction for [Parslee-ai/car#1127](https://github.com/Parslee-ai/car/issues/1127).
It preserves a LaunchAgent generation across SIGKILL and simulated power loss,
but is intentionally not wired into an installer or launchd. Its filesystem
transaction compiles only on Unix; other targets retain the public API and
return `UnsupportedPlatform` before creating transaction state. The transaction
states, ownership rules, sync coverage, and 52-boundary interruption matrix are
documented in
[`docs/reboot-cutover-transaction-2026-09-10.md`](../../../docs/reboot-cutover-transaction-2026-09-10.md).
## Why a separate crate
Agents that consume the registry don't necessarily depend on
`car-engine` (a tray UI does not need the runtime). Splitting the
registry off keeps it a thin dependency while hosting lifecycle primitives
shared by native CAR hosts.
## Tracking issue
#111 — agent registry + menubar discovery.