Skip to content

Task 3: Prove sharing end to end and document it #474

Description

@AkaraChen

Summary

Prove bidirectional sharing of the user's Herdr session for parent plan #466, then write that contract into docs/herdr-integration.md. Task 1 (#470 on task-1-attach-user-session) already attaches to the default socket and proves HerdrClient::workspace_create is visible in herdr api snapshot on an isolated XDG. Task 2 (#472 on task-2-version-policy) already accepts protocol >= 22, prefers PATH herdr, and surfaces herdr update. What is still missing is the parent-plan e2e: a workspace/pane created through 2code's runtime path (connect_gui_herdr / RuntimeRouter / create_with_runtime / create_session) must show up in the same server's session.snapshot / herdr api snapshot and herdr workspace list; and the reverse — a workspace the user creates with the herdr CLI must appear in 2code's derived profile list (list_with_runtime). Record the exact commands and sanitized output in the docs, and replace leftover production claims of a dedicated 2code namespace / never the user default session with that sharing contract.

Same clicks and labels. Seeing the user's real workspaces (join-keyed to the open project) is the point of this phase, not a redesign. This task is prove + document; do not change socket resolution, version policy, or the sidecar pin unless a live proof finds a real sharing hole Task 1/2 missed, and then fix only that hole.

Herdr is the profile authority. sqlite profiles is not source of truth (the table is DROPped). projects / project_groups / checkout_notes stay in 2code sqlite. Default-runtime switch and deleting Local/PTY/profiles rows already shipped in #436 — do not re-litigate or re-add them. Never let Local and Herdr own the same worktree (Local is gone; do not bring it back). Do not change interaction. Reuse the existing socket client, snapshot/event sync, frame bridge, and worktree/pane RPCs — this task proves which session 2code already talks to, not a new protocol layer.

This is #466 Task 3, not #394 Task 3 (#404), not #436 Task 3 (#441), not #458 Task 3 (#461), and not #463 Task 3 (#467). Do not implement or close those tickets here.

Dependencies: Parent plan #466. Prerequisites: #470 (Task 1, accepted on task-1-attach-user-session), #472 (Task 2, accepted on task-2-version-policy). Open #471 and #473 are line-count tracking only — not blockers and not work for this branch. Open task tickets from #394 / #436 / #458 / #463, leftover gaps (#396, #397, #398, #399, #401), and line-count trackers are out of scope.

Work to complete

  1. Forward: a 2code runtime workspace/pane is visible to the user's herdr CLI

    • Use the real pinned Herdr v0.9.0 binary. Isolate via fixture XDG_CONFIG_HOME so the proof's default socket is $fixture_xdg/herdr/herdr.sock, not the developer's ~/.config/herdr/herdr.sock. Do not retarget this onto the host's real session. Probe /tmp/2c*.sock isolation remains test isolation, not a production private 2code namespace.
    • Go through 2code's runtime path, not only HerdrClient::workspace_create (that one-direction snapshot check already exists as live_created_workspace_is_visible_on_default_socket). Wire connect_gui_herdr / RuntimeRouter on that fixture XDG (test GuiHerdrConnect.sidecar / isolated PATH as today).
    • Create a sqlite projects row for a disposable folder, then start a workspace and a pane the way the GUI does: create_with_runtime and/or adopt_existing_checkouts for the workspace (worktree.create / worktree.open / workspace.create --cwd), then create_session (tab.create) for the pane. Returned ids stay workspace_id / pane_id.
    • On that same default socket, with no HERDR_SESSION=2code and no sessions/2code/ path, show the workspace/pane in:
      • JSON session.snapshot
      • CLI herdr api snapshot
      • CLI herdr workspace list (if the v0.9.0 argv differs, record the actual command; JSON workspace.list is not a substitute for the CLI proof the parent named)
    • Quote the exact commands and a sanitized snippet (temp paths → /tmp/…) in the implementation reply and in the docs section below. Lease/GUI drop still leaves that default socket live (server stop still absent from exit).
  2. Reverse: an externally created workspace appears in 2code's derived list

    • On the same isolated default session, create a workspace outside 2code with the user's CLI (herdr workspace create --cwd <folder>, or the v0.9.0 equivalent) pointing at a folder that is a sqlite projects.folder.
    • list_with_runtime (live read, not adopt_existing_checkouts) must return that workspace_id as a derived profile for that project. Do not sqlite-fill. Join key still applies: only that project's folder, not every session workspace. Git folders join via worktree.list open_workspace_id; non-git via snapshot pane cwd. One disposable folder is enough; pick the join path that matches it.
    • Quote the exact CLI create + herdr workspace list / herdr api snapshot commands and the sanitized list_with_runtime ids in the reply and docs. A second, private server must not appear (sessions/2code/ absent, starts stay on the default socket).
  3. Write the sharing contract; lock leftover private-namespace claims

    • Add a Sharing contract section to docs/herdr-integration.md: one Herdr server, shared; 2code attaches to the session the user's herdr would (Task 1 resolution order); never a private 2code session; never herdr server stop on GUI exit; protocol >= 22 / herdr update (Task 2); bidirectional visibility with the recorded commands/output from steps 1–2.
    • Replace production current-state sentences that still imply a dedicated 2code namespace or that 2code never uses the user default session. The contract-probe dump line that says the dump uses a fixture socket, never the host's real default session, stays — reword it so it cannot be read as production policy.
    • docs/architecture.md / docs/configuration.md / AGENTS.md / CLAUDE.md twins only if they still contradict sharing. Extend docs_client_mode.rs so the sharing-contract section cannot regress to "dedicated 2code namespace" as live production text.
    • Do not retarget herdr_contract.rs onto the developer's ~/.config/herdr. Do not change pin.json / sidecar pin / protocol floor / PATH preference. Do not add a Settings health page or change New Profile / New Tab / Git / sidebar labels.
    • If line count grows past the estimate, open a tracking issue; this plan has no Task 4 to fold into this branch.

Likely files and directories

Estimated changes: 200–400 lines total, additions plus deletions, including tests and docs; excluding generated files, lockfile churn and binary artifacts. Material scope growth (unpinning the sidecar, retargeting the contract probe onto the host session, leftover capability gaps) should become a separate issue.

Acceptance criteria

  • Forward proof on an isolated default socket: a workspace and pane created through 2code's runtime path (RuntimeRouter / create_with_runtime and/or adopt + create_session, not only HerdrClient::workspace_create) appear in session.snapshot, herdr api snapshot, and herdr workspace list. No HERDR_SESSION=2code, no sessions/2code/. The implementation reply quotes the commands and a sanitized snippet.
  • Reverse proof on that same session: a workspace created with the user's herdr CLI against a sqlite projects.folder appears in list_with_runtime as that workspace_id. Live read, not adopt-to-invent. Join key still filters by project folder. Commands and sanitized list ids are quoted in the reply and docs.
  • docs/herdr-integration.md has a Sharing contract section with those commands/output. Production docs no longer say 2code uses a dedicated 2code namespace and never the user default session. Contract-probe notes may still isolate a fixture socket from the host's real default. docs_client_mode.rs locks the new contract text.
  • GUI/lease drop leaves the shared server running. No private session spawn. Sidecar pin remains v0.9.0. Protocol floor / PATH preference / herdr update copy stay as Task 2 left them.
  • No behavior change beyond proving and documenting sharing (and fixing a hole the live proof actually finds). sqlite profiles is not source of truth. projects still round-trip in sqlite. No Local adapter. No second events.subscribe. lib.rs still does not name HerdrRuntimeSync. Join key still filters profiles by project folder.
  • Named UX exceptions: none new. Existing Herdr-backed exceptions stay (route ids workspace_id; tab ids pane_id; splits flattened as extra tabs; non-git New Profile is folder workspace.create; Herdr-down New Tab errors). Showing join-keyed user workspaces in the sidebar is the phase goal, not a click/label redesign.
  • Tests: cargo test --workspace from src-tauri (or cargo test --workspace --exclude code where GTK is unavailable), including the new live sharing tests when the pinned binary is present (HERDR_SIDECAR_REQUIRED=1 must not skip them into a green run). Frontend lint/typecheck/tests only if frontend scope is introduced (none expected). bun run typegen only if IPC signatures change (none expected); do not hand-edit src/generated/.
  • No push. No pull request.

Out of scope

Standing constraints

  • Never start a private session. 2code as a session name, sessions/<name>/herdr.sock used as 2code's production socket, and the default-socket refusal stay deleted. Nothing in 2code may spawn a server on a socket the user's own herdr cannot see.
  • Never stop the user's server. GUI exit, disconnect, crash and update must not issue herdr server stop or kill the shared server process.
  • Fail with an actionable message, never with silence. Old/absent server copy stays as Task 2; this task must not paper over an old server by spawning a private instance.
  • Do not change interaction. Same clicks and labels. If a label genuinely cannot survive, name the exception in this issue (none new).
  • Reuse the code that already works — socket client, snapshot/event sync, frame bridge, worktree and pane RPCs.
  • Do not treat sqlite profiles as source of truth. projects stay in 2code sqlite.
  • Never let Local and Herdr own the same worktree (Local is already removed; do not bring it back).
  • Default-runtime switch and deleting Local/PTY/profiles rows already shipped in Plan: 2code as a Herdr client (profiles derived from Herdr) #436; this task does not re-litigate those decisions and does not change them.
  • One task; stack on task-2-version-policy. Do not push. Do not open a PR.

Why this is next

#466 has three tasks. Task 1 (#470) and Task 2 (#472) are accepted on task-2-version-policy. Task 3 is the remaining bidirectional e2e proof plus sharing-contract docs rewrite that both earlier tickets explicitly deferred. The leftover open gaps (#396/#397/#398/#399/#401) and #471 / #473 are Linux-unverifiable leftovers or line-count tracking, not in-flight replacements. #404 is #394 Task 3. #441 is #436 Task 3. #461 is #458 Task 3. #467 is #463 Task 3.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions