Backend architecture: providers, presenters, and the herdr backend#79
Open
ewilazarus wants to merge 4 commits into
Open
Backend architecture: providers, presenters, and the herdr backend#79ewilazarus wants to merge 4 commits into
ewilazarus wants to merge 4 commits into
Conversation
Separate worktree lifecycle, preparation, and presentation into independently testable components behind a backend seam: - WorktreeProvider protocol + NativeGitProvider owning the full worktree creation chain; reusable provider contract tests for future providers - WorkspacePreparer extracted from operations.py (assets, env, fingerprints, hooks); backend-agnostic by construction - WorkspacePresenter protocol + capabilities; no implementations yet, seam covered by fakes - WorkspaceService orchestrating the lifecycle state machine over provider/preparer/presenter/state store - Injectable CommandRunner; git.py migrated (hooks keep shell=True intentionally); tests inject fakes instead of patching subprocess - Minimal per-worktree state (schema v1) under .workspace/.state/ with atomic writes; failed setup is now remembered and retried - flock-based per-worktree operation locks, fail-fast - New 'git workspace prepare [path]' incl. worktrees created by other tools anywhere on disk (.workspace discovered as sibling of the git common dir) - doctor: flag failed preparations and stale state files BREAKING: prune --apply now runs detach/teardown hooks (continues past failures, exits 1 with summary); CLI exits non-zero on errors; reset is deprecated in favor of 'prepare --force'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVBc3r3WrJeXzaogVD6GwX
Implement spec phase 4 against the real herdr 0.7.x CLI contract (captured by probing a live server): - subprocesses/herdr.py: JSON-envelope plumbing for worktree list/create/open/remove and workspace focus/close; errors are parsed from the payload since herdr can report them with exit code 0 - HerdrWorktreeProvider: creation via 'herdr worktree create --no-focus', discovery via list entries (open_workspace_id -> provider_id), removal by workspace id with a git fallback for unpresented worktrees and explicit partial-failure reporting - HerdrPresenter: open (natively idempotent), find by canonical path, focus (opens when absent; stale ids raise PresentationNotFoundError), close (idempotent, tolerates already-closed), full capabilities - Backend resolution: presets native/herdr/auto; auto selects herdr only inside a verified context (HERDR_ENV=1 + reachable session socket) -- the executable existing is never enough; explicit kinds override presets, CLI --backend overrides manifest [workspace] settings - CLI: up gains --backend/--provider/--presenter/--focus; detached up never steals focus; prepare and reset pin the native provider so preparation stays dependency-free for CI and external hosts - Tests: fake herdr executable backed by real git (CI needs no herdr); provider and new presenter contracts pass against it; root conftest scrubs HERDR_* env so auto-detection stays inert in the suite - Verified live: up --backend herdr and flagless rm inside a real herdr session (create, present, close, remove; branch preserved) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVBc3r3WrJeXzaogVD6GwX
A herdr plugin (integrations/herdr/) that closes the reverse loop: when herdr creates or opens a worktree, the plugin runs 'git workspace prepare <path>' so assets and setup hooks apply regardless of which side initiated the worktree. Contract discovered by probing herdr 0.7.4's plugin system live: herdr-plugin.toml manifest (id/min_herdr_version/platforms required), dotted event names (worktree.created/opened/removed), commands resolved relative to the plugin root, payload delivered via HERDR_PLUGIN_EVENT_JSON / HERDR_PLUGIN_CONTEXT_JSON env vars, execution captured in 'herdr plugin log'. - events: worktree.created + worktree.opened -> prepare (idempotent) - actions: prepare / reprepare for the current worktree - non-git-workspace repos are skipped silently (herdr fires events for every repo it manages); failures raise a herdr notification with the retry command - deliberately thin per spec: no config parsing, no direct hooks, no state; everything delegates to git-workspace - lock contention now exits 75 (EX_TEMPFAIL) instead of 1 so the plugin can skip benignly while 'up --backend herdr' is still preparing the worktree it just created via herdr - tested without herdr: hook driven directly with captured payload shapes against real workspaces; fake herdr gained 'notification show' - manifest validated against real herdr: links with zero warnings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVBc3r3WrJeXzaogVD6GwX
- Features, TOC, and commands cover backends, prepare, and lifecycle state - New 'Preparing worktrees' section: prepare semantics, --force as the reset replacement, state tracking and failure retry, lock exit code 75 - Hook table reflects reality: on_setup runs on preparation, detach and teardown hooks now also run on prune --apply - Pruning section no longer claims hooks are skipped (they run since the lifecycle fix), documents skip-and-report failure handling - Doctor checks table gains failed-preparation and stale-state rows - Detached mode notes presentations open without stealing focus - Development layout updated to the providers/presenters/backends tree, with the contract-test entry points for new implementations Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVBc3r3WrJeXzaogVD6GwX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactors git-workspace so worktree lifecycle, project setup, and presentation are independent concerns, then builds the first real backend on top of the seam:
WorktreeProviderowns git worktree creation/discovery/removal (NativeGitProvider,HerdrWorktreeProvider)WorkspacePreparerowns setup (assets, env, fingerprints, hooks) — backend-agnostic by constructionWorkspacePresenterowns how a worktree is surfaced (HerdrPresenter)WorkspaceServiceorchestrates the lifecycle state machine over provider/preparer/presenter/state storeNew features
git workspace prepare [path] [--force]— prepares any worktree of the repository, wherever and however it was created (workspace discovered via the worktree's git metadata). The primitive external hosts and CI invoke;resetis now a deprecated alias forprepare --force..workspace/.state/(schema v1, atomic writes): failed setups are remembered and retried by the nextup/prepareinstead of silently ignored;doctorreports failures with the retry command and flags stale state.75(EX_TEMPFAIL) so callers can distinguish busy from broken.upcreates the worktree through herdr, prepares it, and opens/focuses it as a herdr workspace;downcloses the workspace,rmremoves through herdr. Selection via--backend/--provider/--presenter, the[workspace]manifest table, or auto-detection (--backend nativeopts out).integrations/herdr/): runsgit workspace prepareon herdr'sworktree.created/worktree.openedevents plusprepare/reprepareactions — no config parsing, no state, everything delegates to the CLI.Breaking changes
prune --applynow runson_detach/on_teardownhooks per worktree (skip-and-report on failure, exit 1)uppreserves the worktree, records the failure, and prints a retry commandTesting
tests/contracts/) that future implementations must passup --backend herdr, flagless auto-detectedrm, and plugin manifest linking (zero warnings)Rollout note
After merging and releasing, upgrade the installed binary (currently 0.7.0 lacks
prepare) before enabling the plugin withherdr plugin link <repo>/integrations/herdr.🤖 Generated with Claude Code
https://claude.ai/code/session_01EVBc3r3WrJeXzaogVD6GwX