Skip to content

Add pure Python resurrect APIs#703

Open
tony wants to merge 22 commits into
masterfrom
resurrect
Open

Add pure Python resurrect APIs#703
tony wants to merge 22 commits into
masterfrom
resurrect

Conversation

@tony

@tony tony commented Jul 4, 2026

Copy link
Copy Markdown
Member

Summary

  • Add libtmux.resurrect workspace archive dataclasses and JSON read/write helpers.
  • Add archive capture/restore through the stable libtmux Server API for headless tmux-resurrect parity.
  • Add tmux-continuum style one-shot autosave state helpers that downstream callers can drive from cron, daemons, CLIs, tmuxp, or MCP tools.

Closes #701.
Closes #702.

Validation

  • uv run ruff format .
  • uv run pytest -q
  • uv run ruff check . --fix --show-fixes
  • uv run mypy .
  • uv run pytest -q

tony added 2 commits July 4, 2026 13:41
why: Provide a pure Python tmux-resurrect parity layer that can
capture and restore tmux workspaces without TPM or plugin scripts.

what:
- Add typed JSON workspace archive dataclasses
- Capture sessions, windows, panes, layouts, commands, and paths
- Restore archives through libtmux's stable Server API
- Cover grouping, JSON round-trips, and restore command planning
why: Provide tmux-continuum style autosave parity as a reusable
headless API instead of requiring TPM plugin timers.

what:
- Add autosave state and result dataclasses
- Add due-time checks and next-save calculation
- Add one-shot archive autosave with optional persisted state
- Cover interval skips, forced saves, and state round-trips
@codecov

codecov Bot commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.54259% with 147 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.61%. Comparing base (54f9b72) to head (133abfb).

Files with missing lines Patch % Lines
src/libtmux/resurrect/archives.py 82.89% 42 Missing and 36 partials ⚠️
src/libtmux/resurrect/continuum.py 82.05% 17 Missing and 11 partials ⚠️
src/libtmux/resurrect/processes.py 85.88% 17 Missing and 7 partials ⚠️
src/libtmux/resurrect/resurrect_file.py 91.12% 6 Missing and 5 partials ⚠️
src/libtmux/resurrect/storage.py 86.36% 4 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #703      +/-   ##
==========================================
+ Coverage   51.78%   58.61%   +6.83%     
==========================================
  Files          25       31       +6     
  Lines        3638     4589     +951     
  Branches      733      895     +162     
==========================================
+ Hits         1884     2690     +806     
- Misses       1448     1533      +85     
- Partials      306      366      +60     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

tony added 20 commits July 4, 2026 14:38
why: tmux 3.4 and 3.5 escape raw control-byte separators in
list-panes format output, which broke archive doctests in CI. The
parity API also needs inspectable capture metadata and socket-aware
continuum paths for downstream headless callers.

what:
- Use libtmux's configured FORMAT_SEPARATOR for archive capture rows
- Record captured parity capabilities in WorkspaceArchive JSON
- Add socket-aware autosave path resolution for independent servers
- Cover the separator, capability, and autosave path contracts in tests
why: Full tmux-resurrect parity needs archive fields for focus,
grouping, window flags, pane titles, process commands, and optional pane
contents while keeping existing JSON archives readable.

what:
- Add defaulted archive dataclass fields for richer tmux state
- Persist and read the extended metadata in native JSON archives
- Cover old minimal archive compatibility and extended round trips
why: tmux-resurrect parity requires more than topology; archives need
window flags, pane titles, group names, client focus, and window option
state to restore a workspace faithfully.

what:
- Extend list-panes capture with flags, titles, and history size
- Capture client active/alternate sessions and session groups
- Capture automatic-rename per saved window
- Keep legacy 9-field parser compatibility and tmux 3.4/3.5 coverage
why: Restores should be idempotent when requested; existing sessions should
not force callers to choose between doing nothing and deleting live tmux state.

what:
- Make on_exists="reuse" inventory existing windows and panes
- Create only missing windows and panes through tmux commands
- Preserve existing panes instead of replaying topology into them
- Cover reuse behavior with focused restore tests
why: tmux-resurrect parity requires restore to replay more than the
window and pane topology. Focus state, pane titles, zoom flags, and
window automatic-rename options are user-visible workspace state.

what:
- Replay pane titles, zoom flags, and automatic-rename settings
- Restore alternate and active window focus for new and reused sessions
- Best-effort workspace session focus without requiring attached clients
why: tmux-resurrect preserves grouped sessions as shared window
sets with independent session focus. A pure Python restore needs to
use tmux's native grouping primitive instead of duplicating windows.

what:
- Restore one representative session per group with full topology
- Recreate follower sessions with new-session -t
- Replay grouped-session active window focus after recreation
why: tmux-resurrect does not restart every pane command by default.
A pure Python restore needs the same conservative allow-list and
explicit opt-in controls for safer headless replay.

what:
- Add typed process restore rules and option parsing
- Thread process policy through archive restore commands
- Cover default, custom, relaxed, and restore-all process policies
why: Restoring process arguments needs more than tmux's pane current
command. A pure Python implementation should offer headless providers
without forcing every archive capture to collect full commands.

what:
- Add procfs, ps, and composite process command providers
- Capture pane full_command when a provider is supplied
- Preserve compatibility with older list-panes row formats
why: Full parity needs a bridge to existing tmux-resurrect save
files without requiring TPM or shell plugin execution. Import and
export let users migrate or interoperate with the native archive API.

what:
- Add tmux-resurrect tab-file import and export helpers
- Preserve pane paths, full commands, window options, and client state
- Handle grouped-session follower rows without duplicating windows
why: tmux-continuum parity needs retained archive history and a
portable last pointer. Symlink-only behavior is brittle on filesystems
or platforms where symlink creation is unavailable.

what:
- Add timestamped archive snapshot writing with retention rotation
- Update last.json as a relative symlink or portable copy fallback
- Export storage helpers from the resurrect package
why: tmux-continuum parity needs explicit startup restore behavior that
can run headlessly without clobbering active sessions or racing other
servers. Downstream wrappers also need stable skip reasons.

what:
- Add startup restore decision and result dataclasses
- Gate startup restore on enablement, halt file, sessions, servers, and age
- Add a one-shot restore helper that returns guard reasons without side effects
why: The resurrect and continuum APIs need user-facing guidance for
capture, restore, process policy, snapshot rotation, and startup
restore before the branch can be reviewed as a complete feature.

what:
- Add workspace archive topic and API reference page
- Link resurrect docs from topics and API indexes
- Add the unreleased changelog entry for #701 and #702 parity work
why: Reuse restore created a missing window but skipped the remaining
panes and metadata for that archived window.

what:
- Add a regression for missing reuse-window state
- Restore additional panes after creating a missing reused window
- Replay layout and pane metadata for the created window
why: The default procfs provider received tmux pane PIDs, which
usually identify the shell instead of the active foreground program.

what:
- Resolve procfs descendants in the pane foreground process group
- Fall back to descendant and root commands when foreground state is absent
- Cover shell-to-foreground command capture with typed test cases
why: Reuse restores left existing window names stale even though
fresh windows used archived names.

what:
- Add a regression for reused existing window names
- Restore archived names through the shared metadata path
why: Restoring an archived window name after enabling automatic
rename leaves tmux automatic rename disabled again.

what:
- Restore archived window names before automatic-rename
- Add a regression for automatic rename call order
why: Archived pane indexes can differ from restored tmux pane
indexes when pane-base-index changes between capture and restore.

what:
- Map archived panes to restored pane ids by pane order
- Use mapped targets for pane titles and active pane focus
- Add a regression for pane-base-index mismatch restores
why: The ps fallback reads the pane shell from pane_pid on
non-procfs platforms, which can poison archived full commands.

what:
- Remove ps from the default process command provider chain
- Keep PsProcessCommandProvider available for explicit opt-in use
- Add a regression for shell output from ps fallback
why: Snapshot rotation could delete the archive it had just
written when saved_at moved backward, leaving last.json dangling.

what:
- Protect the just-written archive during retention rotation
- Add a regression for non-monotonic snapshot timestamps
why: The resurrect topic still described a ps fallback after the
default process provider became procfs-only.

what:
- Document procfs-only default command capture
- Mention PsProcessCommandProvider as explicit opt-in
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.

Research tmux-continuum parity for headless autosave Research tmux-resurrect parity for workspace archives

1 participant