unifier-cli 0.5.0

Filesystem postbox for inter-process communication via a Unix tree
Documentation
name: unifier
description: |
  Filesystem postbox for inter-process communication. Programs share state by
  writing values to files in a Unix tree under ~/.local/unifier, treating the
  filesystem as a global data structure (same strategy as filesystem-git-issues:
  directories are namespaces, files are keys, UUID-named drops are messages).

  Layout:
    keys/<path>              — persistent key-value entries (global root)
    mailbox/<recipient>/<uuid>.txt — point-to-point messages
    cron/<min>_<hour>_<dom>_<mon>_<dow>/<uuid>.txt — scheduled drops
    sqlite/<name>.sqlite     — managed SQLite databases (triples.sqlite reserved)
    chroots/<name>/          — isolated subtree (keys/, mailbox/, cron/, sqlite/) via --chroot

  A cron runner polls `poll-cron` (matching five-field directory names against
  the current clock) and acks processed files. Any program can `put`/`get` keys or
  `send`/`poll` mailboxes without a central server.

  Future applications of this filesystem-as-store pattern:
    - Shell session handoff: zshrc hooks write intent files; unifier poll on login
    - Build orchestration: CI agents drop artifact paths into mailbox/builder
    - Agent pipelines: LLM workers poll mailbox/agent-<id> for task payloads
    - Config propagation: put shared keys instead of env vars across tmux panes
    - Lightweight job queue: producers cron-post work items; workers poll+ack
    - Cross-repo notifications: git post-commit hooks send to mailbox/reviewer
    - Home automation triggers: cron slots fire shell snippets read by a daemon
    - Test fixtures: integration tests seed keys/ under a temp --home root
tags:
  - rust
  - cli
  - ipc
  - filesystem
  - cron
  - sqlite
language: rust
scripts:
  build:
    command: cargo build --release
  test:
    command: cargo test
  fmt:
    command: cargo fmt
  clippy:
    command: cargo clippy
  run:
    command: cargo run -- --help
  package:
    command: cargo package
  publish:
    command: cargo publish
  release:
    command: ./scripts/release.sh
  release-dry-run:
    command: ./scripts/release.sh --dry-run
  release-minor:
    command: ./scripts/release.sh --minor
  release-major:
    command: ./scripts/release.sh --major
roadmap:
  done:
    - "State root at ~/.local/unifier with $UNIFIER_HOME override"
    - "Key put/get/del under keys/"
    - "Mailbox send/poll/ack with UUID message files"
    - "Cron post/list/poll-cron with five-field schedule directories"
    - "Atomic key writes and integration tests"
    - "Chroots under chroots/<name>/ with --chroot / $UNIFIER_CHROOT and chroot init/list"
    - "Hot daemon: in-memory HotStore with dirty tracking; flush/stop writes to disk; Unix socket IPC; daemon start/stop/status/flush commands"
    - "Gradle-style invocation: CLI auto-starts daemon on data commands (--no-daemon to opt out)"
    - "ACID tick staging: tick start/end/status/phase, key locks, read previous tick / write current / commit versioned snapshot under ticks/<n>/"
    - "Tick control socket (.daemon/tick.sock): Jan (and CLI) drive tick lifecycle; same JSON as unifier.sock but tick ops only; start/phase/end broadcast on events.sock"
    - "unifier event command for JSON event drops under events/"
    - "unifier message --from <agent> <recipient> for structured agent mailbox envelopes"
    - "Max concurrent ticks: queue tick start when one is active; auto-start next queued tick on end"
    - "Event Unix socket (.daemon/events.sock): mailbox send/message/event broadcast wakeup notices with recipient + message id for Jan cron"
    - "Idle auto-flush: persist dirty daemon state after quiet period when 1-minute loadavg is low"
    - "Idle auto-stop + missing-home exit + daemon gc: prevent orphan Gradle-style daemons from piling up"
    - "Process-scoped key namespaces: namespace set/get/clear and --namespace / $UNIFIER_NAMESPACE prefix keys for a script until it exits"
    - "Managed SQLite under sqlite/: sql list/create/tables/exec; reserved triples DB with triple add/query"
    - "unifier log command: span-tree tracing for Jan cron scripts; log start/end/event/field/tree/list; spans stored as JSON under logs/"
    - "Daemon web server: pipe HTML via `serve` into `.daemon/www/`; localhost HTTP (default :17355); web list/rm/url/key-url/status; GET /keys/… for live key values; optional --wrap Unifier chrome for Jan reports"
    - "Event expiry: events/<uuid>.json stores expires_at (default 24h); --ttl / payload ttl|expires_at; GC on load, flush, and daemon sweep"
    - "Daemon durability: multiple requests per connection (fixes poll --ack broken pipe), setsid detach so the daemon outlives its launcher, flush on SIGTERM/SIGINT/SIGHUP"
    - "Job pipeline (scout -> analyst -> responder -> digest) lives in sister repo dotfiles/jan/jobs.yaml; coordinates purely through Unifier mail and events"
  in_progress: []
  todo:
    - "Tick-based agents: three-phase lockstep per tick (sense → decide → act); no side effects during decide"
    - "Agent state: hot in-memory between ticks; cold checkpoint watermark (state + tick number) at tick end for crash replay"
    - "Tick concurrency modes: serial barrier, pipelined async with state snapshots, drop-on-overflow mailbox"
    - "Inter-agent coordination: global synchronous tick vs async local ticks writing to Unifier blackboard"
    - "Differential sensing: read changes since last tick to avoid time-quantization blind spots between samples"
    - "Logical tick index vs wall-clock jitter: scale actions when cron arrives late"
    - "Factorio factory model: isolated arms sense belt contents, filter, and act; coordinated system pursues shared goal"
    - "zshrc integration: poll multiple mailboxes and cron slots on shell startup"
    - "Optional JSON output and metadata sidecar files (.meta) per message"
    - "Namespace permissions or lock files for multi-user hosts"
    - "Validator for on-disk layout and stale message GC"