Skip to content

feat: rain command + token-window watcher (0.8) - #81

Merged
huximaxi merged 2 commits into
mainfrom
feat/rain-0.8
Sep 13, 2026
Merged

huximaxi merged 2 commits into
mainfrom
feat/rain-0.8

Conversation

@huximaxi

@huximaxi huximaxi commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

The rain command + token-window watcher, as an 0.8 scope item (deliberately skipping the 0.7 line, which stays focused on the CLI write-side). One concern, one commit. This code briefly lived on #79 and was pulled out pre-merge so the beta shipped only fleet-reviewed code; it returns here carrying the three fixes its own pre-mortems found.

Draft until the gate passes. The merge gate for this PR is an adversarial (Cipher-lens) pass over the two sensitive surfaces: the transcript reader (the most secret-dense files on a user's disk, read-only or not) and the exec hand-off. Recommended to run jointly with the deferred loci sync/loci serve threat model, since three exec-adjacent surfaces converge on the same trust question.

What it contains

  • templates/skills/rain.md: the garden watering round as a portable skill. Full persona roster fans out over the idea garden, each agent picks its own plant, exactly one serial applier writes; convergence of several personas on one plant is signal, not conflict. Never auto-fires: weather is a suggestion, spending is a gate. Includes the wiring note that --fire sends the literal word rain and the palace's orchestrator instructions must route it.
  • loci tokens (CLI): approximate agent-runtime 5-hour session-window status, reconstructed read-only from local transcripts, streamed line-by-line. Reports timing and spend, explicitly not quota, and labels itself approximate.
  • loci rain [--fire] (CLI): watering weather on one screen (window signal fresh/open/closing, plant count, last rain from the garden/.rain/ archive). --fire is the CLI's one hand-off: execs the user's agent runtime from the palace root and exits. The CLI itself still does no inference.
  • Desktop rain-gauge card: same weather + garden state, "make it rain" button behind an explicit click. Three commands: read_token_window, read_rain_status, fire_rain.

Fixes carried from the #79 pre-mortems

  1. Child reaping: fire_rain now waits on the spawned round in a reaper thread; previously each fired round left a zombie process for the app's lifetime.
  2. Streaming reader: both watchers stream transcripts line-by-line instead of read_to_string; peak memory is one line regardless of transcript size (multi-hundred-MB transcripts are real).
  3. Trigger-word wiring note in the skill template, so a palace without a rain trigger knows why the word arrives bare.

Pre-mortem

  • The token watcher reads transcripts. Read-only, no network, computes over content the user already holds, sends nothing, labels itself approximate. Risk is misread weather, never a write. The adversarial pass gating this draft verifies exactly that claim in code.
  • fire_rain / rain --fire spawns the user's agent runtime. Explicit flag or click only; no schedule, no daemon, no auto-fire path. Binary absent = immediate plain error. The runtime invoked is claude on the user's PATH, same trust class as their shell profile.
  • Window reconstruction is floor-to-the-hour approximate; the provider's authoritative reset only appears in its own limit messages. Stated in the module docs, the CLI output, and the card.
  • Rollback: one squash commit, one revert.

Verification

CLI built and live-run against a real palace (window signal, garden state, --json); tauri backend suite 22/22; leptos wasm type-checks; bleed and em-dash scans clean on the full diff.

🤖 Generated with Claude Code

huximaxi and others added 2 commits September 9, 2026 09:10
- rain, the garden watering round, as a portable skill (templates/skills/rain.md): full-roster fan-out, pick-your-own plant, one serial applier; never auto-fires; wiring note added for the trigger word
- token watcher: 5h session-window weather (fresh/open/closing) reconstructed read-only from local transcripts, streamed line-by-line; timing and spend, not quota
- CLI grows loci tokens + loci rain [--fire] (the one hand-off: execs the agent runtime from the palace root and exits); desktop grows a rain-gauge card behind an explicit click (read_token_window / read_rain_status / fire_rain), spawned rounds reaped on exit
- carries the three pre-merge pre-mortem fixes from #79: child reaping, streaming reader, trigger-word doc
An adversarial review of the token-window watcher and rain command found
two gaps in the transcript scanner (loci-cli/src/tokens.rs,
desktop/src-tauri/src/token_watcher.rs):

- The directory walk followed symlinks via Path::is_dir(), so a symlink
  planted in the scanned tree could redirect the scan outside it.
- BufRead::lines() buffers one line in full before yielding it; an
  unterminated multi-GB "line" would force an unbounded allocation despite
  the file itself being read as a stream.

Both files get a file_type()-based symlink guard and a bounded line reader
that drains and discards any line over 8MB instead of buffering it. Added
unit tests for the new reader; neither file had any test coverage before.
@huximaxi
huximaxi marked this pull request as ready for review September 9, 2026 11:44
@huximaxi
huximaxi merged commit 9640760 into main Sep 13, 2026
5 checks passed
@huximaxi
huximaxi deleted the feat/rain-0.8 branch September 13, 2026 09:11
huximaxi added a commit that referenced this pull request Sep 13, 2026
Resolve CHANGELOG.md Unreleased conflict as the union: restore the #84
loci-wal / loci-cli entries (dropped from main by #81's squash), keep the
#81 rain + token-window entry, add #87's Fixed section. loci-cli builds
clean; 11 unit tests pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant