Last refresh: 2026-10-28 (v0.13.56) · 29,687 daemon LOC (git ls-files daemon | rg '\.rs$' | xargs wc -l)
Earlier version of this report claimed "100% implemented." That claim was false. A second-pass line-by-line audit found 20+ gaps; an explicit follow-up round closed every one of the seven items the previous draft disclosed as remaining.
The matrix uses four statuses: FULL = wired with a working call site and (where applicable) tests; PARTIAL = surface present but a specific sub-feature deferred for measurement; GAP = spec verb has no implementation; DESIGN = aspirational target, not a code feature (perf budgets etc).
Every row cites file:line or file.rs::symbol for verification. Don't take the status word — open the file and confirm.
Round 2 closed: import catalog/shard/--all, export --all tar archive, fsnotify delta-walk via shared helper, cold-build-complete znotify, O_NOFOLLOW + MAP_PRIVATE for sensitive content, per-shell replay log + replay_log op, RTT bench harness binary.
Status as of 2026-10-28: three round-2 closures were undone when the AST-walk pipeline was removed in 15ec01dffb (2026-05-02): the replay-log writer (ops.rs::write_replay_log) and the fsnotify re-analysis caller (fsnotify.rs::reanalyze_zshrc) no longer exist, and zsync.rs::apply_delta_walk registers watches without walking. Cold-build-complete znotify went with op_first_init. Each is listed under "What's still legitimately incomplete".
May 2026 architectural moves (post earlier audit):
• Single home directory. Cache and config now collapsed into $ZSHRS_HOME (defaults to ~/.zshrs/) — one directory holds every zshrs file. CachePaths::ensure_default_configs seeds zshrs.toml, zshrs-daemon.toml, zshrs-recorder.toml on first run for every binary; idempotent. One-shot migration ingests the bare-named daemon.toml if present and the legacy macOS ~/Library/Application Support/zshrs/history.db → ~/.zshrs/zshrs_history.db.
• Three log files (zshrs.log, zshrs-daemon.log, zshrs-recorder.log) — one per binary. paths::is_zshrs_log_file matches all three for rotation/tail/clear. Levels via per-binary [log] level; $ZSHRS_LOG overrides.
• Recorder is its own binary (zshrs-recorder). Sources the full zsh login chain (8 files in order, missing files skipped silently); -f PATH overrides the chain. End-of-run ships recorder_ingest IPC bundle to the daemon.
• Daemon binary is independent (zshrs-daemon). The daemon is started explicitly — the shell never auto-spawns it. POSIX mode never spawns a daemon at all.
• Default HTTP listener on 127.0.0.1:7733 seeded into zshrs-daemon.toml so zd health works out of the box. Loopback bind requires no token; non-loopback bind refuses to start until [http.tokens] is populated. GET /openapi (alias /openapi.json) returns OpenAPI 3.1 doc auto-derived from OP_NAMES: 115 paths as of 2026-10-28, v0.13.56 (4 meta + 108 ops + 3 streams; http.rs::handler_openapi).
• History split. Shell-facing history is ~/.zshrs/zshrs_history (flat zsh-extended-history-format text) plus FTS5 sibling ~/.zshrs/zshrs_history.db. Daemon's separate FTS5 catalog history is ~/.zshrs/history.db.
• [shell] skip_configs = "auto" in zshrs.toml: when daemon is up + a recorded zshrs canonical shard exists, the shell SKIPS sourcing /etc/zshenv + ~/.{zshenv,zprofile,zshrc,zlogin} entirely; canonical_apply rebuilds executor state from the rkyv shard (alias/galias/salias/env/params/setopt/path/fpath/named_dirs/autoload_functions/zstyle/bindkey/compdef/zle widgets). Inline functions deferred until recorder ships bytecode in shard.
• zd two surfaces: bin (HTTP via ureq, 2.64 ms) for bash/fish/CI; builtin (in-process Unix socket via Client, 0.48 ms, 5.5× faster) inside zshrs.
• New zd subcommands: zd doctor, zd config get/set/list, zd snapshot save/list/load/diff, zd lock, zd publish, zd cache, zd job, zd artifact, zd schedule, zd export, zd view, zd ops. zd export TARGET FORMAT auto-unwraps — binary payloads (pdf/sh/csv/json/yaml/text) stream raw; --json opt-in restores the envelope.
• Since 2026-10-06: zd snapshot sign/verify/publish/pubkey/pull/bisect (per-user ed25519 key; directory or HTTP registry), zd daemon status|start|stop|restart, plugins.db populated from each recorder shard (recorder_shard.rs::plugin_from_path detects zinit, oh-my-zsh, zplug, antigen, antibody, sheldon, zgenom, zgen, prezto, zim), zwhere lists every definition with file:line and call chain and reads the shard when no daemon runs, zlog tail selects shell|daemon|recorder logs (default all three).
• New z* builtins: zlock (try/acquire/release/list), zpublish (TOPIC [DATA] [--json '{...}']), zwhere (SUBSYS NAME — file:line attribution from canonical state). Total z* family now 23 (was 15).
• zjob attach with bidirectional ptmx pump. --pty at submit time uses nix::pty::openpty(); child runs with slave on 0/1/2. Master fd lives in JobMeta. New IPC ops job_input {id, bytes_b64} and job_resize {id, rows, cols} (TIOCSWINSZ). zjob attach on a pty job: termios cfmakeraw on stdin, stdin reader thread batches keystrokes → job_input; job:N.stdout events (bytes_b64) decoded to user's tty; SIGWINCH → job_resize. Ctrl-] detaches. Drop guard restores termios.
• zsync up --all wired (was a stub). src/extensions/overlay_snapshot.rs snapshots every overlay table → push_canonical per subsystem. Covers alias/galias/salias, setopt, params (vars+arrays+assoc unioned), env, path, manpath, fpath, named_dir, compdef, zstyle. Skipped: function, bindkey, zmodload.
Live verification — 2026-10-06
Every op in OP_NAMES was driven against a running zshrs-daemon in an isolated $ZSHRS_HOME (HTTP POST /op/<name>), every z* builtin through a real zshrs client over the unix socket, zd through its HTTP transport, and zshrs-recorder -f through recorder_ingest to zwhere. Nine defects surfaced; all are fixed and pinned by tests.
| Feature | Defect observed | Fix | Where |
|---|---|---|---|
zcache clean zwc|zcompdump|legacy, verify | Walked $HOME 6 deep (DAEMON.md z* builtin family: "Out-of-scope dirs are never touched"); read_dir blocked in ~/Library/Containers on the async worker, wedging the daemon: /health hung, SIGTERM ignored. | $HOME/$ZDOTDIR top level only; shared scan_legacy on the blocking pool; nested roots deduped. | ops.rs legacy_scope / scan_legacy |
import_catalog, import_all, clean catalog | Database file swapped under the live connection: writes landed in the renamed backup inode; stale -wal made the restored file read as disk I/O error. | DaemonState::swap_db_file: checkpoint, close, swap, drop sidecars, reopen. | state.rs swap_db_file |
export --all | Archive held 0 of 5 history rows (all still in WAL). | WAL checkpoint before archiving. | state.rs checkpoint_dbs |
view / export default format | view defaulted to sh, so zd view history failed. | view → text; export → sh, or json for non-eval targets. | export.rs NON_SH_TARGETS |
| Federated definitions | A bash row from definitions_emit leaked into export aliases / pull / complete; eval applied the bash value. | rows_for is the zshrs view; federation readers use rows_for_all_shells. | canonical.rs rows_for |
zlock builtin | Sent caller_pid; daemon reads pid, recorded holder 0 (dead), so any shell stole the lock. | Sends pid. | builtins.rs zlock |
zd lock (binary) | Holder was the short-lived zd process; the lock freed as soon as zd exited. | Transport::lock_holder_pid; binary uses its parent. | zd_dispatch.rs, bins/zd.rs |
z* builtins via $var / "$@" | command not found for a run-time-resolved head. | One run_daemon_builtin for literal, dynamic and builtin NAME heads. | src/fusevm_bridge.rs |
schedule add | 5-field crontab lines rejected. | Accepted, firing at second 0. | schedule.rs normalize_cron |
Hygiene: test-spawned daemons now start with an empty zshrs-daemon.toml (no HTTP), so a daemon leaked by a killed test run cannot hold 127.0.0.1:7733; a daemon whose socket file disappears shuts itself down on the next ticker pass.
Closed in this audit pass
| Spec section | Verb / feature | Status before | What changed | Where |
|---|---|---|---|---|
| DAEMON.md z* builtin family (zcache clean zwc/zcompdump/legacy) | zcache clean zwc / zcompdump / legacy |
GAP | op_clean rejected those targets; only all/shards/index/log were valid. | ops.rs:1562 (op_clean) — added zwc/zcompdump/legacy/shard/catalog/stats arms; legacy_scope() bounds the walk to known dirs only |
| DAEMON.md z* builtin family (cache management) | --wait / --dry-run / --no-stats / shard <name> / catalog / stats |
GAP | None of these flags were parsed in zcache_clean or honored in op_clean. |
builtins.rs:669 (zcache_clean parses flags) + ops.rs:1562 (handler) |
| DAEMON.md z* builtin family (zcache verify) | zcache verify flags .zwc / .zcompdump as WARN |
GAP | op_verify only checked shards + catalog integrity. Now scans known scope and reports artifact counts + sample paths in a `warnings` array. | ops.rs:1917 (op_verify legacy scan) |
| DAEMON.md Universal cache dump / view / export | zcache view --filter / --range / --all |
GAP | op_view ignored these args. Wired through for command_hash (glob-to-regex), history (FTS query + time-range), subscriptions (--all fans out across shells). | export.rs:288 (sensitive guard) + render_filtered + glob_to_regex + parse_range |
| DAEMON.md Source / dot interception | --show-sensitive / --include-sensitive |
GAP | Sensitive flag stored on compiled_files but never gated terminal output. Now: refuse to print body of script/sourced sensitive paths without --show-sensitive. |
export.rs:288 (is_path_sensitive) — checks before render |
| DAEMON.md Compat surface (History migration) | zcache import history + zcache export history --format zsh-histfile |
GAP | Migration path was missing entirely. Now: full EXTENDED_HISTORY parser (`: epoch:dur;cmd` plus plain), reverse export emits zsh-compatible format. | ops.rs:2861 (op_import_history) + parse_zsh_history_file + export.rs:595 (render_zsh_histfile) |
| DAEMON.md Promoting client-local changes | push_canonical commit flow: validation + derived-hashtable rebuild + delta-walk + fsnotify register | PARTIAL | Was just an upsert + emit. Now: per spec step 1 (validate dirs exist for PATH, no duplicates, no empty), step 2 (in-mem + rkyv persist), step 3 (delta-walk only the new dirs into command_hash/autoload_table via walk::walk_paths + INSERT into entries), step 4 (fsnotify watch_path on new dir), step 5 (canonical_changed event includes delta_walked_dirs).As of 2026-10-28: step 3 no longer walks. walk::walk_paths was removed in 15ec01dffb; zsync.rs::apply_delta_walk only registers fsnotify watches for added dirs (command_hash/autoload_table come from recorder runs). op_push_canonical passes no removed dirs. |
zsync.rs:91 (op_push_canonical) + validate_push_payload |
Round 2 of audit — every previously-disclosed gap closed (three reopened 2026-05-02; see notes)
| Spec section | Feature | Was | Now |
|---|---|---|---|
| DAEMON.md Universal cache dump / view / export | zcache import catalog / shard / --all |
GAP | ops.rs:3082 op_import_catalog (validates SQLite schema + integrity_check, backs up existing catalog before overwrite); ops.rs:3161 op_import_shard (validates magic via MmappedShard::open, sanitizes name, atomic-rename copy); ops.rs:3340 op_import_all (parses ustar, restores every entry into ~/.zshrs/, *.preimport-<ts> backups for collisions) |
| DAEMON.md Universal cache dump / view / export | zcache export --all --out backup.tar |
GAP | ops.rs:3229 op_export_all + write_ustar_entry / parse_ustar — plain POSIX ustar (no zstd dep per CLAUDE.md durable-deps). Sensitive shards filtered out unless --include-sensitive. Read with tar -xf. |
| DAEMON.md Hard invariants (steady state) | fsnotify-driven delta-walk on .zshrc path/fpath edits |
PARTIAL | zsync.rs:190 apply_delta_walk extracted as shared helper. Called from both op_push_canonical (zsync up) and fsnotify::reanalyze_zshrc (steady-state). Adds dirs → walk + watch; removes dirs → drop entries + unwatch.As of 2026-10-28: fsnotify::reanalyze_zshrc was removed in 15ec01dffb; fsnotify is notification-only (shard_updated). apply_delta_walk’s only caller is zsync.rs::op_push_canonical, and added dirs get a watch, not a walk. |
| DAEMON.md Source / dot interception | Sensitive read/write: O_NOFOLLOW + MAP_PRIVATE |
PARTIAL | source_resolver.rs:read_file_nofollow — sources read with O_NOFOLLOW (defeats symlink-swap). shard.rs:write_shard — tmp file opened with O_NOFOLLOW | O_CREAT | O_EXCL. shard.rs:open_sensitive — new MmappedShard ctor uses memmap2 map_copy_read_only which calls MAP_PRIVATE. |
DAEMON.md Cache layout (replay/) |
Per-shell replay log for non-deterministic fragments | PARTIAL | paths.rs added replay_dir at ~/.zshrs/replay/. ops.rs:write_replay_log emits {hash8}-{stem}.zsh per source root with non_deterministic_lines body. New op replay_log (ops.rs:op_replay_log) returns body for client to eval at boot.As of 2026-10-28: write_replay_log was removed in 15ec01dffb. ops.rs::op_replay_log still reads replay/, but no daemon code writes it. |
| DAEMON.md Acceptance criteria | <5 ms / <2 ms / <30 s perf budgets | DESIGN | daemon/bins/zshrs-daemon-bench.rs — measurement bin. Connects to a running daemon (client.rs::Client::connect never spawns one), warms 50 calls, then runs --runs N per op (ping/complete/suggest/highlight/history_query/info/watcher_stats), prints JSON with min/p50/p90/p99/max in µs + verdict line on stderr. No criterion dep. Run: cargo build --bin zshrs-daemon-bench -p zshrs-daemon, then ./target/debug/zshrs-daemon-bench --runs 1000. |
What's still legitimately incomplete (no false claims)
| Spec section | Feature | Status | Why it's not "done" |
|---|---|---|---|
| Compiled_files.bytecode BLOB | Real bytecode storage in compiled_files | PARTIAL | source_resolver.rs:15 — the daemon does not yet bytecode-compile on a miss; the compiled_files row (source_resolver.rs:129) holds metadata only, the bytecode column having been dropped by the v1→v2 catalog migration (catalog.rs:109). Hash + sensitive flag + mtime + inode are populated correctly. |
| DAEMON.md acceptance criteria | Bench numbers measured against the perf budgets | DESIGN | zshrs-daemon-bench measures the IPC RTT criteria but does not assert thresholds; RSS and cold-source criteria have no harness (DAEMON.md "Acceptance criteria" TODO). DAEMON.md records one measurement on a 13.6M-row history.db: suggest and complete at 29 ms p50, above the <2 ms target. The <30 s zcache rebuild criterion was removed with the rebuild op. |
DAEMON.md Cache layout (replay/) |
Per-shell replay log writer | PARTIAL | ops.rs::op_replay_log reads paths.rs::CachePaths replay_dir; the writer write_replay_log was removed with the AST-walk pipeline (15ec01dffb). Nothing populates ~/.zshrs/replay/. |
| DAEMON.md Hard invariants (steady state) | fsnotify-driven delta-walk of new PATH/FPATH dirs | PARTIAL | fsnotify.rs is notification-only (shard_updated). zsync.rs::apply_delta_walk registers watches for dirs added by zsync up but does not walk them; command/autoload tables refresh only on a recorder run. |
| DAEMON.md zask | Ctrl-X q activation widget |
PARTIAL | DAEMON.md marks the zask-take widget and ZSHRS_ZASK_TAKE_KEY as planned, not shipped; activation is zask take [--id ID] (zask_builtin.rs::take). |
| Failure modes (section removed from DAEMON.md) | Quarantine + auto-recovery of corrupted shards | PARTIAL | ops.rs::op_doctor reports; recovery is delete + recorder run, no quarantine. |
| Versioning (section removed from DAEMON.md) | Migration test corpus | PARTIAL | catalog.rs::migrate_v1_to_v2 exists; no corpus of old-format catalogs/shards exercises it. |
1. IPC operations — every dispatch arm in ops::dispatch
From the match block in ops.rs::dispatch. As of 2026-10-28 (v0.13.56), all 108 op names in ops.rs::OP_NAMES route to a real handler; GET /openapi lists 115 paths (4 meta + 108 ops + 3 streams). Zero unimplemented!() arms remain. Newer ops include job_input, job_resize — bidirectional ptmx attach for --pty jobs (base64 input, TIOCSWINSZ resize). Since 2026-10-06: snapshot_sign, snapshot_verify, snapshot_publish, snapshot_pubkey, snapshot_pull, snapshot_bisect.
| Op | Handler fn | Where | Status |
|---|---|---|---|
info | op_info | ops.rs:295 | FULL |
ping | op_ping | ops.rs:320 | FULL |
list_shells | op_list_shells | ops.rs:330 | FULL |
tag / untag | op_tag, op_untag | ops.rs:348, 356 | FULL |
send | op_send + cmd_result | ops.rs:365, 438 | FULL |
notify | op_notify | ops.rs:584 | FULL |
daemon (status / stop / restart) | op_daemon + spawn_replacement_daemon | ops.rs:615 + ops.rs:3785 | FULL |
cmd_started | op_cmd_started | ops.rs:725 | FULL |
complete | op_complete | ops.rs:755 | FULL |
suggest | op_suggest | ops.rs:836 | FULL |
highlight | op_highlight + highlight_line + classify_word | ops.rs:894, 949, 1182 | FULL |
register | op_register | ops.rs:1239 | FULL |
doctor | op_doctor | ops.rs:1292 | FULL |
canonical_hydrate_view | op_canonical_hydrate_view | ops.rs:1458 | FULL |
clean (all/shards/shard/index/shell/log/catalog/stats/zwc/zcompdump/legacy + --dry-run + --no-stats) | op_clean + legacy_scope | ops.rs:1562 + 1846 | FULL |
verify (shards + catalog + legacy litter) | op_verify | ops.rs:1917 | FULL |
compact | op_compact | ops.rs:1985 | FULL |
fpath_changed | op_fpath_changed | ops.rs:1996 | FULL |
watcher_stats | op_watcher_stats | ops.rs:2120 | FULL |
log_level / log_rotate / log_stats | op_log_level, op_log_rotate, op_log_stats | ops.rs:2198, 2207, 2212 | FULL |
subscribe / unsubscribe / subscription_set_paused / publish | op_subscribe, op_unsubscribe, op_subscription_set_paused, op_publish | ops.rs:2242, 2289, 2269, 2305 | FULL |
load_script | op_load_script | ops.rs:2333 | FULL |
stats_flush | op_stats_flush | ops.rs:2352 | FULL |
keys | op_keys | ops.rs:2389 | FULL |
subscribe_shard | op_subscribe_shard | ops.rs:2413 | FULL |
export_zcompdump + synthesize_zcompdump | op_export_zcompdump | ops.rs:2428 + 2483 | FULL |
export_catalog | op_export_catalog | ops.rs:2556 | FULL |
export_shard | op_export_shard | ops.rs:2575 | FULL |
import_zcompdump | op_import_zcompdump + parse_zcompdump | ops.rs:2605 + 3607 | FULL |
import_zwc | op_import_zwc | ops.rs:2700 | FULL |
import_history + parse_zsh_history_file | op_import_history | ops.rs:2861 + parse_zsh_history_file | FULL |
import_catalog / import_shard / import_all | op_import_catalog, op_import_shard, op_import_all | ops.rs:3082, 3161, 3340 (closed in round 2 audit) | FULL |
job_* family (submit/list/status/output/kill/cancel/wait) | 7 op_job_* fns | ops.rs:3876+ | FULL |
job_input / job_resize (ptmx attach for --pty jobs) | op_job_input, op_job_resize | ops.rs (base64 input write to pty master; TIOCSWINSZ via nix) | FULL |
source_resolve + sensitive heuristic | op_source_resolve + is_sensitive + read_file_nofollow | source_resolver.rs:33 + 183; O_NOFOLLOW on read; O_NOFOLLOW | O_CREAT | O_EXCL on shard write; MAP_PRIVATE on sensitive mmap (closed in round 2) | FULL |
history_append / history_query | op_history_append, op_history_query | history.rs:250, 342 | FULL |
push_canonical / pull_canonical / diff_canonical | op_push_canonical, op_pull_canonical, op_diff_canonical | zsync.rs:91, 327, 347 | FULL |
view / export (with --filter/--range/--all/--show-sensitive) | op_view, op_export, render_filtered | export.rs:33, 37, 304 | FULL |
ask_* family (ask/pending/take/dismiss/response) | 5 op_ask_* fns | zask.rs:200, 319, 339, 362, 401 | FULL |
recorder_ingest | op_recorder_ingest | ops.rs::op_recorder_ingest | FULL |
autoload_prewarm | op_autoload_prewarm | ops.rs::op_autoload_prewarm | FULL |
watch_subscribe / watch_unsubscribe / watch_list | op_watch_subscribe, op_watch_unsubscribe, op_watch_list | ops.rs::op_watch_subscribe, ops.rs::op_watch_unsubscribe, ops.rs::op_watch_list | FULL |
replay_log | op_replay_log | ops.rs::op_replay_log (read-back only; no writer populates replay/, see "still incomplete") | FULL |
config_get / config_set / config_list | op_config_get, op_config_set, op_config_list | ops.rs::op_config_get, ops.rs::op_config_set, ops.rs::op_config_list | FULL |
export_all | op_export_all + write_ustar_entry | ops.rs::op_export_all, ops.rs::write_ustar_entry | FULL |
cache_* family (put/get/del/list/stats) | 5 op_cache_* fns | cache.rs::op_cache_put, op_cache_get, op_cache_del, op_cache_list, op_cache_stats | FULL |
lock_* family (acquire/try_acquire/release/list) | 4 op_lock_* fns | lock.rs::op_lock_acquire, op_lock_try_acquire, op_lock_release, op_lock_list | FULL |
artifact_* family (put/get/get_by_digest/gc/list) | 5 op_artifact_* fns | artifact.rs::op_artifact_put, op_artifact_get, op_artifact_get_by_digest, op_artifact_gc, op_artifact_list | FULL |
snapshot_* family (save/list/load/diff/sign/verify/publish/pull/bisect/pubkey) | 10 op_snapshot_* fns | snapshot.rs::op_snapshot_save … snapshot.rs::op_snapshot_bisect | FULL |
schedule_* family (add/add_once/remove/list) | 4 op_schedule_* fns + normalize_cron | schedule.rs::op_schedule_add, op_schedule_add_once, op_schedule_remove, op_schedule_list | FULL |
definitions_* family (query/kinds/emit/diff/subscribe/unsubscribe) | 6 op_definitions_* fns | definitions.rs::op_definitions_query … definitions.rs::op_definitions_unsubscribe | FULL |
metrics | op_metrics | metrics.rs::op_metrics | FULL |
2. z* builtin family
23 zshrs-owned builtins as of 2026-10-28, v0.13.56 (builtins.rs::ZSHRS_BUILTIN_NAMES: zcache, zls, zid, zping, ztag, zuntag, zsend, znotify, zsubscribe, zunsubscribe, zjob, zsync, zask, zhistory, zsource, zcomplete, zsuggest, zcmd-result, zlog, zwhere, zd, zlock, zpublish), anti-collision-checked vs upstream zsh (zmv/zparseopts/zformat/zstat/zstyle/zprof/zcompile/zargs/zcurses/zsystem/ztie/zuntie/zselect/zsocket/zftp/zpty/zed/zcalc/zregexparse/zutil/zmodload/zle).
| Builtin | Entry fn | File | Status |
|---|---|---|---|
zcache | dispatch / zcache | builtins.rs:26, 144 | FULL |
zls / zid / zping / ztag / zuntag | zls, zid, zping, ztag, zuntag | builtins.rs:796, 897, 909, 975, 994 | FULL |
zsend / znotify | zsend + parse_send_args, znotify | builtins.rs:1024, 1104 | FULL |
zsubscribe / zunsubscribe | zsubscribe, zunsubscribe + filter+pause+list | builtins.rs:1681, 2006 | FULL |
zsync (up/diff/pull/watch) | zsync + push + pull + diff + watch | zsync_builtin.rs:79, 177, 314, 332, 124 | FULL |
zask | zask + ask + take + dismiss + pending + progress + inbox-clear + response | zask_builtin.rs:53, 297, 392, 454, 364, 198, 283, 472 | FULL |
zlog (tail/grep/level/clear/rotate/path/stats) | zlog + zlog_level/rotate/path/tail/follow/grep/clear/stats | builtins.rs::zlog | FULL |
zjob (submit/list/status/output/cancel/kill/wait) | zjob + 7 sub-fns | zjob_builtin.rs:56-1037 | FULL |
zhistory (append/query/count) | zhistory + 3 sub-fns | zhistory_builtin.rs:50-209 | FULL |
zcomplete / zsuggest | zcomplete, zsuggest | zcomplete_builtin.rs:48, 91 | FULL |
zsource | zsource | zsource_builtin.rs:56 | FULL |
zlock (try/acquire/release/list) | zlock (try/acquire/release/list match arms) | builtins.rs::zlock | FULL |
zpublish (TOPIC [DATA] [--json '{...}']) | zpublish | builtins.rs::zpublish | FULL |
zwhere (SUBSYS NAME — file:line attribution) | zwhere | builtins.rs::zwhere | FULL |
zd (in-process builtin — same arg surface as zd bin, 5.5× faster: 0.48 ms vs 2.64 ms fork+exec) | zd | builtins.rs::zd + zd_dispatch.rs::dispatch | FULL |
zcmd-result | zcmd_result | builtins.rs::zcmd_result | FULL |
zjob attach (read-only file-tail / bidirectional raw-mode pump for --pty) | attach + attach_filetail / attach_pty + stdin_pump; libc::cfmakeraw; TermiosGuard Drop | zjob_builtin.rs::attach, zjob_builtin.rs::attach_pty | FULL |
3. Spec sections — coverage by section
Section names are the docs/DAEMON.md headings as of 2026-10-28. Rows whose section was dropped from DAEMON.md (most of them in 7eed04795f, 2026-05-03, "strip AST-walk fiction") are kept at the end for code coverage and say so.
| Section | Status | Where / what's missing |
|---|---|---|
| "v1 Locked Design" / "The 90/10 work split" | FULL | All daemon-owned subsystems wired (persistence, recorder-shard ingest, single fsnotify, zjob, pub/sub, ticker) |
| "NO WALKING IN CLIENTS" | FULL | Clients only mmap shards; canonical reads via IPC ops; client.rs has no walk code |
| "Daemon = sole writer" | FULL | flock singleton + Mutex<Connection> on catalog/history; atomic-rename ordering |
| "Snapshot-at-boot + overlay" | FULL | Per-client mmap snapshot; overlay → canonical via push; mid-session pull opt-in |
| "Cache layout (locked)" | FULL | Every file in paths.rs::CachePaths; 0700/0600 enforced by paths.rs::ensure_dir_700 / paths.rs::ensure_file_600. replay/ is created but never written (see "still incomplete"). |
| "catalog.db schema (daemon-only writer)" | FULL | catalog.rs::create_schema: plugins, plugin_deps, entries, hooks, entry_stats, compiled_files (with sensitive and parent_paths columns). Canonical table in zsync.rs, jobs table in jobs.rs. |
| "Special parameters served by daemon" (_comps, _services, _patcomps, _describe_handlers) | FULL | Each is a canonical subsystem; op_keys serves flat key arrays; export.rs renders all four |
| "Starting state captured by recorder, stored by daemon" (PATH/FPATH/MANPATH/CDPATH/INFOPATH/LD_LIBRARY_PATH/named_dir/aliases/galiases/saliases/setopt/bindkey/zmodload/env/params/zstyle/theme) | FULL | Captured by zshrs-recorder (runtime AOP intercept) and stored in the canonical engine via recorder_ingest and recorder shards (CanonicalEngine::sync_recorder_shards). theme via params subsystem. Static walker pipeline retired; see the comment block in daemon/lib.rs after the zsync_builtin module declaration. |
| "Source / dot interception and file registry" | FULL | source_resolver.rs handles mtime+inode cache + sensitive flag (source_resolver.rs::is_sensitive); sources read with O_NOFOLLOW (source_resolver.rs::read_file_nofollow); MAP_PRIVATE via shard.rs::open_sensitive. Misses store source, not bytecode (see "still incomplete"). |
| "Compat surface and zpwr-scale validation target" (zpwr ~1.6M LOC, 478k history, .tokens.sh) | DESIGN | No bench measurement yet; architecture supports it but no <60s cold-build proof exists |
| → "Plugin manager interop" paragraph | FULL | The daemon parses no manager syntax; the recorder runs the user's real manager and captures the result. Plugin attribution: recorder_shard.rs::plugin_from_path recognizes zinit, zplug, antigen, antibody, sheldon, zgenom, zgen, prezto, zim, oh-my-zsh layouts. |
| → "History migration" paragraph | FULL | ops.rs::op_import_history + ops.rs::parse_zsh_history_file; reverse via export.rs::render_zsh_histfile |
| "Promoting client-local changes to daemon canonical" (zsync up/diff/pull/watch) | FULL | zsync.rs::op_push_canonical validates (validate_push_payload), persists, registers fsnotify watches on new PATH/FPATH dirs, emits canonical_changed. No delta walk (see "still incomplete"). |
| "Universal cache dump / view / export" | FULL | Formats in export.rs::render: sh, json, yaml, text, csv, sql, native, disasm, zcompdump, zsh-histfile; pdf in export.rs::op_view_or_export. Not every format applies to every target (export.rs::NON_SH_TARGETS have no sh form and default to json; disasm is function-only). zd export TARGET FORMAT auto-unwraps binary formats — --json opt-in restores envelope. export --all emits POSIX ustar (ops.rs::op_export_all). Reverse-import: ops.rs::op_import_catalog, ops.rs::op_import_shard, ops.rs::op_import_all. |
| "IPC wire format" (length-prefixed JSON) | FULL | ipc.rs:230/252/269/291 framing; Hello/Welcome/Frame/ErrPayload all defined |
| "Operation table (client → daemon)" | FULL | Every op in ops.rs::OP_NAMES has a dispatch arm in ops.rs::dispatch; see section 1. |
| "Async event types (daemon → client)" | FULL | ipc.rs::Event (14 variants as of 2026-10-28, v0.13.56) |
| "z* builtin family (locked, no shadowing of zsh)" | FULL | builtins.rs::ZSHRS_BUILTIN_NAMES dispatched by builtins.rs::dispatch; see section 2. |
| "zshrs ↔ zshrs-daemon: independent processes" | FULL | client.rs::Client::connect never spawns; the shell runs in vanilla mode when no daemon is up. |
| "Daemon lifecycle (the daemon-binary side)" (singleton flock / crash recovery / degraded mode / explicit start) | FULL | pidlock.rs flock singleton; client.rs handles NotConnected fallback. Daemon is its own binary (zshrs-daemon) and is started explicitly — never auto-spawned from a shell entrypoint. |
| "First-run notification (the one-time exception to no-banner)" | FULL | firstrun.rs:18 maybe_print + ZSHRS_QUIET_FIRST_RUN gate |
| "Long-running command completion notices" (4 events) | FULL | history.rs:289-334 publishes long_cmd_complete/failed/signaled; ops.rs:725 op_cmd_started |
| "zask — daemon-queued UI primitives" | PARTIALCtrl-X q widget planned, not shipped | zask.rs inbox with critical-first ordering and 60-min default timeout; activation is zask take until the zask-take widget lands |
| "Daemon logging (every action goes to logfile)" | FULL | log.rs init + ticker.rs rotation (10MB, 4 archives) + zlog tail/grep/level/clear/rotate/path/stats |
| "Hard invariants (rejected proposal classes)" | PARTIAL steady-state delta-walk not wired | No client polling, sole writer, no .zwc auto-import, etc. Steady state is fsnotify notification only; new dirs are not walked (see "still incomplete"). |
| "Acceptance criteria" | DESIGN | zshrs-daemon-bench measures IPC RTT without threshold assertion; RSS and cold-source criteria have no harness |
| "Snapshot signing and registry" | FULL | snapshot.rs::op_snapshot_sign, op_snapshot_verify, op_snapshot_publish, op_snapshot_pull, op_snapshot_bisect, op_snapshot_pubkey |
| Determinism boundary / per-shell replay log (section removed from DAEMON.md) | PARTIAL | ops.rs::op_replay_log reads replay/; write_replay_log removed in 15ec01dffb, nothing writes it. |
| Walk lifecycle — first init (section removed from DAEMON.md) | DESIGN | Static 4-pass walker (op_first_init, op_zshrc_analyze, op_plugin_discover, op_rebuild) retired; state attribution comes from zshrs-recorder (recorder_ingest). |
| .zwc / .zcompdump invisible to scans, importable on demand (now a Hard invariants bullet) | FULL | ops.rs op_import_zwc + op_import_zcompdump for explicit ingest; verify+clean flag/remove litter. |
| Cold-build-complete znotify (section removed from DAEMON.md) | DESIGN | Tied to retired op_first_init walker (removed in 15ec01dffb). No recorder_ingest-complete broadcast exists. |
| Security model (section removed from DAEMON.md) | FULL | server.rs:357 peer_uid (SO_PEERCRED); paths.rs::ensure_dir_700 / paths.rs::ensure_file_600; export.rs:288 sensitive guard. O_NOFOLLOW reads (source_resolver.rs::read_file_nofollow); shard tmp file O_NOFOLLOW | O_CREAT | O_EXCL (shard.rs::write_shard); MAP_PRIVATE (shard.rs::open_sensitive). |
| Failure modes & disaster recovery (section removed from DAEMON.md) | PARTIAL zcache doctor lives; no quarantine of corrupted shards | ops.rs:1292 op_doctor 9-check sweep; corruption recovery is "delete + recorder run", not "quarantine + auto-recover" |
| Cross-platform support (section removed from DAEMON.md) | FULL | notify::RecommendedWatcher autoselects FSEvents/inotify/kqueue; server.rs:357 has Linux/macOS/BSD branches |
| Versioning & migration (section removed from DAEMON.md) | PARTIAL catalog v1→v2 migration exists, no migration test corpus | shard.rs:37 SHARD_FORMAT_VERSION = 2; catalog.rs:42 SCHEMA_VERSION = 2; catalog.rs:59 PRAGMA user_version; catalog.rs:109 migrate_v1_to_v2 |
4. Reproduce the verification
Three commands, in order, from repo root:
cargo build -p zshrs-daemon # → Finished, zero warnings
cargo test -p zshrs-daemon --lib # lib-only matrix (counts drift; run locally)
grep -nE "unimplemented|todo!|FIXME" daemon/*.rs # → no matches
What changed in this audit pass. First report claimed "100% implemented" — that was wrong. Re-reading DAEMON.md line by line surfaced 20+ gaps. Eight were fixable in one session and are now closed (round 1, top table). Round 2 closed every remaining item: import catalog/shard/--all, export --all tar archive, fsnotify delta-walk via shared helper, cold-build-complete znotify, O_NOFOLLOW + MAP_PRIVATE for sensitive content, per-shell replay log + replay_log op, RTT bench harness binary. May 2026 then landed the architectural moves listed in the second summary box (single $ZSHRS_HOME, separate zshrs-daemon/zshrs-recorder binaries, three log files, default 127.0.0.1:7733 listener with /openapi, zd two-surface design, zlock/zpublish/zwhere builtins, zjob attach bidirectional ptmx, zsync up --all, skip_configs). The AST-walk removal (15ec01dffb, 2026-05-02) reopened the replay-log writer, the fsnotify delta-walk and cold-build znotify. Open items as of 2026-10-28 are listed in "What's still legitimately incomplete." (The zcache rebuild --parallel row was retired alongside the walker pipeline; see the walker-removal comment in daemon/lib.rs.)