Skip to content

session mirror: --follow, --all, compact (+ cwd-encoding fix)#10

Merged
Arrmlet merged 5 commits into
mainfrom
feat/session-follow
Jun 27, 2026
Merged

session mirror: --follow, --all, compact (+ cwd-encoding fix)#10
Arrmlet merged 5 commits into
mainfrom
feat/session-follow

Conversation

@Arrmlet

@Arrmlet Arrmlet commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Live and multi-session mirroring for tracecraft session, plus a real bugfix surfaced along the way. Four focused commits.

What's new

session mirror --follow (-f) [--interval SECONDS] — near-real-time mirroring. Re-flushes every interval (default 5s) until Ctrl-C, so a crash loses at most one interval of trace. Reuses the incremental cursor + --min-bytes gate, so idle cycles upload nothing. Ctrl-C stops cleanly and stamps ended_at. One PUT per interval (batches, doesn't stream per event) to keep request cost flat.

session mirror --all — one terminal mirrors a whole project: follows every session under --cwd, including sessions that start after the loop begins, each with its own cursor. Implies --follow, rejects --session-id. Scoped to one cwd + harness.

session compact <id> [--keep-tail N] — merges a session's many part files into one, byte-for-byte; session show output is identical before/after. Safe ordering: merged part is uploaded and meta.json rewritten before any original is deleted, so an interrupted compact leaves a harmless duplicate, never a gap.

fix(claude-code): cwd slugify for _ and ._encode_cwd only replaced /, but Claude Code collapses every run of non-alphanumeric chars (incl. _ and .) to -. So sessions for any folder like test_session_flow were silently undiscoverable and forced users to pass --session-id by hand. Now matches Claude Code's real encoding, with a regression test.

Testing

  • 99 tests pass (--ignore=tests/test_replay_collect.py, a pre-existing untracked/broken module). New tests cover: follow loop clean-stop, --all multi-session + mid-run pickup, compact byte-identical replay / --keep-tail / single-part no-op, and the underscore/dot encoding regression.
  • ruff check + format clean.
  • Verified end-to-end against real MinIO and a live HF bucket (a real Claude Code session mirrored, then replayed).

Docs

README quick-ref + docs/session-mirror.md updated for --follow, --all, and compact.

Not in this PR (deliberate)

  • Auto-launch SessionStart/SessionEnd hooks (so mirroring starts without a second terminal) — written locally but not yet tested; will come as a follow-up once verified.
  • --all is per-cwd/per-harness; cross-folder / cross-harness auto-mirroring is the hooks' job.

🤖 Generated with Claude Code

Arrmlet and others added 5 commits June 24, 2026 23:16
session mirror --follow/-f re-flushes every --interval seconds (default 5)
until Ctrl-C, so a crash loses at most one interval of trace instead of the
whole run. Refactors the mirror body into a reusable _mirror_once() so single-
shot and follow behave identically; reuses the incremental cursor + --min-bytes
gate (empty cycles cost no upload). Ctrl-C stops cleanly and stamps ended_at.
Batches one PUT per interval rather than streaming per event, keeping
per-operation request cost flat.

Tests: follow loop (patched sleep raises KeyboardInterrupt after N cycles,
asserts two disjoint parts + ended_at) and non-positive --interval rejection.
Docs: README session-mirroring section + docs/session-mirror.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_encode_cwd only replaced "/" with "-", but Claude Code slugifies the cwd by
collapsing every run of non-alphanumeric chars (including "_" and ".") to "-".
So sessions for any folder like test_session_flow or my.proj were silently
undiscoverable — `session mirror` reported "No claude-code session found" and
forced users to pass --session-id by hand. Now uses re.sub to match.

Regression test pins the _ and . cases and confirms plain hyphenated names
(data-universe) are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
--follow writes one part per flush, so long sessions accumulate many small
objects. `session compact <id>` concatenates them in seq order, byte-for-byte,
into a single new part and deletes the originals. Replay (session show) is
identical before/after.

Safe ordering: merged part uploaded + meta rewritten BEFORE any original is
deleted, so a crash mid-compact leaves a harmless duplicate, never a gap.
--keep-tail N leaves the newest N parts alone (e.g. while --follow still appends).

Tests: byte-identical replay after merge, --keep-tail, single-part no-op.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
One terminal mirrors a whole project: --all re-discovers all sessions under
--cwd each cycle and flushes each (own cursor), picking up sessions that start
after the loop begins. Implies --follow, rejects --session-id. Ctrl-C marks all
followed sessions ended.

Tests: multi-session + mid-run pickup, --session-id rejection. Docs updated for
--all and compact (README quick-ref + docs/session-mirror.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI runs ruff format --check with a newer ruff (0.15.20) than local; it expands
the --all/--session-id test invocation across lines and collapses two wrapped
lines in compact(). Pure formatting, no logic change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Arrmlet Arrmlet merged commit 0589914 into main Jun 27, 2026
3 checks passed
Arrmlet added a commit that referenced this pull request Jun 27, 2026
session mirror --follow / --all / compact + claude-code cwd-encoding fix
(PR #10). Also syncs __init__.__version__ (was stale at 0.2.1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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