Skip to content

feat(git): switch branches from the Git panel and the composer chip - #23102

Draft
inariku wants to merge 2 commits into
kirodotdev:mainfrom
inariku:feat/branch-switcher-takeover
Draft

inariku wants to merge 2 commits into
kirodotdev:mainfrom
inariku:feat/branch-switcher-takeover

Conversation

@inariku

@inariku inariku commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Problem / Motivation

Goal: Switch, check out and create git branches from the dashboard's Git panel and from the project chip under the chat box, the way VS Code and Zed do from their status bar.

Today the Git panel header and the composer's project chip only show the current branch with a click-to-copy button. Changing branch means leaving the dashboard for a terminal, then coming back and waiting for the panel to notice. Users report this as the thing that stops them using the dashboard as their main surface (#22670).

This takes over #17628 by @kyleseaman, rebased onto current main, with its red CI fixed and its review findings addressed. Kyle is credited as co-author.

Why it matters

Moving between local branches is the most common git action while reviewing an agent's work in a session's project folder. Without a switcher the dashboard shows the branch but cannot act on it, so every switch costs a context change to a terminal, and the file tree and Changes list lag until they repoll.

Not a goal

  • Stage, commit, fetch, pull or push controls. Fetch/pull/push need credentials, which is a separate security question.
  • Deleting, renaming or rebasing branches.
  • Switching when the session's project folder is a subfolder of a repository (refused, same rule as "Start in new worktree").
  • Changing what a workflow step does with its session. A failed or cancelled step keeps its session, as it does on main.

What changed (motivation → approach → change)

One searchable picker, reused in the Git panel header and on the composer chip, backed by two narrow endpoints. A switch is refused while any agent work runs in the repository, so git never rewrites files under a live turn.

Area Change
dashboard/handlers/git_branches.py GET /api/project/git/branches and owner-gated, SEL-audited POST /api/project/git/switch: sandboxed git with hooks off and LC_ALL=C, --no-overwrite-ignore, --no-recurse-submodules, everything redacted; refused for subfolder projects and checkout filters. A cancelled switch still audits its outcome (_audit_abandoned_switch). A busy refusal names the running chat or workflow (busy).
kiro_crew/repo_checkout_guard.py, dashboard/repo_checkout_guard.py The busy registry: a reservation taken before the check, chat turns on every folder they touch (a linked Slack thread's turn included, via the session lease), pending sub-agents, workflow steps, and every prompt in flight. A teardown that leaves something running keeps a probe of the leftovers here, so a respawn cannot strand the repository.
acp/ (client_transport.py, client_lifecycle.py, runtime_wire.py, runtime_reader_loop.py, runtime_tree_kill.py, runtime_class.py) Both transports wait out a checkout of the session's folder before a prompt is written and count it until the backend answers or the tree is gone; the same seam on every harness.
dashboard/chat_turn/, dashboard/state_parts/, subagent_manager/run_lifecycle.py, subagent_parts/manager.py, workflows/agent_exec.py, workflows/agent_pool.py Turns, sub-agents (pre_run_gate) and workflow steps (tracked_work) wait out a checkout before they touch files. Workflow steps keep their session whatever the step's outcome.
website/src/components/BranchSwitcher.tsx, LazyBranchSwitcher.tsx, GitPanel.tsx, ChatInput.tsx, website/src/api/client/files.ts, website/src/pages/chat/ActivityViewer.tsx The picker, its lazy boundary and both hosts; the two client methods.
website/src/i18n/ Strings in all 12 catalogs, en-XA regenerated, plural keys, translator context.
security_posture.py, docs The redaction-sink row the security-posture inventory requires for the new handler; feature map row; learn-cron-dashboard.md and acp-client.md spec text.

Changed from #17628, each a review finding:

  • Workflow steps no longer end their session on a failed or cancelled step (First Principles BLOCK, Design CONCERNS). A turn whose backend may still run tools stays counted on its prompt instead, so the workflow spec's retention rule holds as written.
  • Rebased onto the split ACP runtime; main's _session_cwds replaces the duplicate _session_folders behind the AttributeError reds.
  • A cancelled switch is audited from the worker's own completion (GPT 6.1 blocking finding).
  • The knowledge pool's CCWorker is not counted: it runs in the gateway's own cwd and could mark every repository under it busy until restart (Opus).
  • A teardown verdict survives a respawn; a steer-started adapter turn ends with the next finished turn on that session (local review).
  • UX copy: a one-line hint, a "Switch →" affordance on the highlighted row, "■ in the message box" instead of a missing "Send" button, an invalid-name message that says what is wrong, and a dirty refusal that leads with asking the agent.

Backwards compatibility

Compatible: two new routes and a new optional c_locale flag on _run_git; existing git endpoints and their responses are unchanged. Workflow steps behave as on main.

Changes one click target, removes no capability: when idle, clicking the branch name on the composer chip or Git panel header opens the picker instead of copying (copy is in the picker footer); while a response runs, the same click still copies, as before.

Removes nothing: no route, key, field or record is removed or tightened; the busy registry is new state.

Tests

  • test/test_project_git_branches.py and test/test_project_git_branches_coverage.py: listing, switching, creating, tracking, every refusal and parse path; new: a cancelled switch audits its outcome even through a second cancel, each worker outcome maps to the right SEL verdict, a linked channel's lease on an idle slot is running work (held, unplaced, unreadable), the 409 carries the running chat's name.
  • test/test_repo_checkout_guard.py: the reservation registry and both admission orderings; new: a failed or cancelled workflow step keeps its named session, an unanswered prompt keeps the repository busy after its step ends, the refusal names the tracked workflow.
  • test/test_prompt_checkout_seam.py: prompts counted at both ACP transports from before their write until their exact answer; new: the knowledge pool's worker never marks a repository busy, a teardown survivor keeps the prompt counted across a respawn until it exits, a Windows drain that raises keeps it until its root is gone, an inconclusive probe stays busy, and a steer-started turn ends only on a finished later turn on the same session (not on another session, an error answer, or an earlier turn). Absence assertions wait on a positive signal (the prompt parked on the reservation, or the reader past a trailing frame), not a fixed number of loop yields.
  • Determinism: the three changed test files ran 20 times at -n0, 10 times at -n 4 beside their neighbours, and once in reversed order, all green.
  • test/test_workflows_agent_pool*.py, test_workflow_agent_spawn_governance.py, test_workflow_memory_backend_reset.py: back to their main expectations, which now pass unchanged.
  • Frontend: BranchSwitcher.test.tsx (new: the named busy refusal, the switch affordance on the highlighted row only), GitPanel, GitReposPanel, ChatInput.projectBranch, LazyBranchSwitcher.

Local, on this head: black, isort, flake8, mypy --platform linux, docs lint, tsc, eslint, i18n:check; 1,351 backend tests across the guard, transports, bindings and workflows; 1,195 frontend tests; scripts/local-gate.py related sets: about 130,000 backend tests and 14,961 frontend tests, where every red (48 backend, all in environment-bound tests such as test_dashboard_gallery_*, test_pi_gate_extension_mcp.py, test_local_gate.py) reproduces on a clean origin/main worktree on this host. Full CI is the authority.

Manual verification

Driven in the production build with mocked git responses (website/scripts/capture-branch-switcher.mjs, not a live gateway): open, filter, switch, dirty-tree refusal, named busy refusal, filter-blocked state, composer chip opening upward, copy while a response runs, dark and light themes.

Screenshots / video

Picker open, with the one-line hint and the highlighted row's switch affordance:

Branch picker open

The busy refusal names the chat that is still running:

Busy refusal naming the running chat

While a response runs, the chip copies and says where the stop control is:

Chip while a response runs

More states

Header closed
Filtered with create row
Create row highlighted
After switch
Dirty-tree refusal
Content filter blocks switching
Light theme
Composer chip open
Empty list, invalid new name

Related Issues

Closes #22670. Supersedes #17628.

Checklist

  • At most two commits (one is the norm), with a Conventional Commits title
  • Existing tests pass and new tests added for new functionality
  • Self-review completed; code follows project style guidelines
  • Documentation updated (if applicable)
  • No secrets, credentials, or internal references in the diff

Contribution License Agreement

Contributions are accepted under the project's Apache-2.0 license.

@inariku
inariku requested review from a team and KiroCrewCaptain as code owners October 22, 2026 13:55
@inariku
inariku requested a review from buluoray October 22, 2026 13:55
@github-actions github-actions Bot added fork Pull request from a fork (external contributor) readiness: action required A blocking check or review needs attention labels Oct 22, 2026
@inariku

inariku commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Sensitive change review

  • Head commit: d39aa94
  • What rule changed: none. One row is added to security_posture._REDACTION_SINKS for the new handler dashboard/handlers/git_branches.py, which redacts every branch name, commit subject, author and git diagnostic it returns; test_every_redactor_call_site_is_a_registered_sink_or_allowlisted requires the row.
  • Before -> after (what was allowed/blocked, now): before, the module did not exist. After, the security posture panel lists "Git panel branch switcher" as a redaction sink. No allow or deny decision changes and no sandbox, command floor or secret path is touched.
  • Worst case if wrong (breaks commands / leaks secret / locks user out): the panel's sink inventory describes the handler wrongly. The redaction itself lives in the handler and is pinned by its own tests (redacted names listed as not switchable, a token straddling the 300-character diagnostic cut).
  • Evidence checked (which sandbox result proves it): test/test_security_posture.py (every-sink and unique-label checks) and test/test_project_git_branches.py, which runs real git through the strict sandbox where the host supports it.
  • No regression:
    • Tools still work (which tools/commands were run, result): git branch listing and switching through worktree._run_git (strict sandbox, hooks off) in test_project_git_branches.py; the screenshot harness against the production build.
    • Backward compatible (old config / old data / old callers still work, how checked): an additive tuple row; no existing row changed (the diff on security_posture.py is +7/-0).
    • Existing tests (which suites passed on this head): test_security_posture.py, the git_branches suites, the checkout guard and prompt seam suites, and scripts/local-gate.py's related sets.
  • How to undo: revert the PR; the row and the handler go together.

This PR comes from a fork, so per docs/ci/ci-and-reviews.md the gate refuses it whatever this template says; a maintainer would need to take it over on a branch of this repository (it already carries Co-authored-by: and Supersedes #17628).

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

UX Review (Opus 5.5, fork) — ✅ PASS (a BLOCK with no Trigger and no Outcome does not block)

UX-level review of 181cb7465070e0e2c0e5934e69da914f59c6b240 via the fork AI-review pipeline — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS does not.

UX-Verdict: PASS

cannot evaluate: missing the clipboard-failure note and its "Try again" button, plus the picker's loading, load-error, detached-HEAD and truncated-list states. None of the 12 committed screenshots shows any of them.

Evidence gaps

  • Copy-failure note and retry, on the trigger: copy_failed ("Couldn't copy “{{name}}” to the clipboard.") with the RetryCopyButton labelled "Try again", in both the chip and header variants. It should be a screenshot of a copy the browser refused while a response runs.
  • Copy-failure notice in the picker footer: branch-switcher-footer-copy-failed and its retry button. It should be a screenshot of the open picker after the footer copy fails.
  • Picker loading state: the "Loading branches…" spinner row. It should be a screenshot taken while the list request is still pending.
  • List load error: load_failed, "Couldn't load the branch list." It should be a screenshot of the picker after /api/project/git/branches fails.
  • Detached HEAD: the trigger label "Detached at {{sha}}" and the "Copy commit {{sha}}" busy mode. It should be a chip and header screenshot with HEAD detached.
  • Truncated list footer: "Only the {{limit}} most recent are listed". It should be a screenshot of a repository with more than 200 branches.
  • Hidden branch row: the dimmed row whose tooltip is not_switchable. It should be a screenshot with a row whose name was redacted.

Notes

  • The error_dirty notice runs to four sentences plus a file list, all in red, which makes a wall of text (attachment-09). Keep only "Not switched: these files would be overwritten: {{files}}." followed by "Ask the agent to commit or stash them." and drop the terminal aside.
  • The remote row says "uncommitted changes are kept", and the safety line above the list plus row_switch_hint repeat the same promise. Cut remote_row_action down to "Makes a local branch {{name}}".

[UX-REVIEWED] 181cb74

Description read

[DESCRIPTION-READ] d60c4066a5a766aa9472b64ec5739e359b8279814f426cf3dd9693bd989114d2

That sha256 names everything this verdict read: the PR description, plus the 15 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with .github/scripts/pr-description-capture.sh over the same inputs; if it differs, the description or that evidence changed after this verdict was formed and any finding drawn from either is unproven.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

First Principles Review (Opus 5.5, fork) — ✅ PASS

Premise-level review of 181cb7465070e0e2c0e5934e69da914f59c6b240 via the fork AI-review pipeline — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS does not.

First-Principles-Verdict: PASS

Nothing blocks. The switcher answers a linked user report (#22670), and the busy guard exists because git would otherwise rewrite files under a running turn.

What this change ships

Inventory (10 items) — 10 justified

Intent: let a user switch, track or create a git branch from the dashboard instead of going to a terminal — ADDITION.

  1. The Git panel header's branch (the chat's own project only) opens a searchable branch picker — justified
  2. The same picker opens upward from the composer's project chip — justified
  3. When idle, clicking the branch name opens the picker instead of copying; copy moves to the picker footer, and the click still copies while a response runs — justified
  4. The picker can create a new branch or check out a remote branch as a tracking branch — justified
  5. A switch is refused while agent work runs in that repository, and the refusal names the chat or workflow — justified
  6. A switch is refused for a subfolder project, checkout filters or files in the way — justified
  7. Every prompt, on both ACP transports, waits out an in-flight checkout of its folder and counts as busy until it is answered or its process tree is gone — justified
  8. Sub-agent runs and workflow steps wait out a checkout before they start work — justified
  9. Each switch, including a cancelled one, is SEL-audited and owner-gated — justified
  10. Two new routes: GET /api/project/git/branches, POST /api/project/git/switch — justified

[FIRST-PRINCIPLES-REVIEWED] 181cb74

Description read

[DESCRIPTION-READ] 561fc70f458e32557231fb66ccfa07de34a214af06bc99056175eef0e46e5162

That sha256 names the PR description this verdict read. Recompute it with .github/scripts/pr-description-capture.sh; if it differs, the description changed after this verdict was formed and any finding drawn from the description is unproven.

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Opus 5.5 Review (fork) — ✅ no blocking findings

Reviewed 181cb7465070e0e2c0e5934e69da914f59c6b240 via the fork AI-review pipeline; updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 181cb74

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

GPT 6.1 Review (fork) — ✅ no blocking findings

Reviewed 181cb7465070e0e2c0e5934e69da914f59c6b240 via the fork AI-review pipeline; updated in place on each push.

Review details

No findings.
[GPT-REVIEWED] 181cb74

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running merge conflict Branch has merge conflicts with its base — author must resolve before merge and removed readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention labels Oct 22, 2026
@inariku
inariku force-pushed the feat/branch-switcher-takeover branch from d39aa94 to 1f78cbe Compare October 22, 2026 21:17
@inariku

inariku commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Both GPT 6.1 blocking findings are fixed in 1f78cbe (squashed into the feature commit to stay within the two-commit limit, and rebased onto current main).

F1 (cancelled unwritten prompts left the repo busy) - fixed. The runtime and client request writers now call repo_checkout_guard.prompt_not_written(instance, request_id) when the write exits with confirmed non-delivery (a cancel before the stdin lock is taken, or a LOCK_STALL, which wrote no byte), so the registration is dropped. Once any byte may have reached the backend the registration is kept, as suggested. test/test_prompt_checkout_seam.py covers both sides for the runtime and the client writer: a prompt cancelled while waiting for stdin is no longer busy, and one cancelled after the stdin write stays busy.

F2 (Windows root death released prompts while descendants ran) - fixed. The teardown probe now consults platform_compat.windows_tree_cleanup_pending(root_pid, root_start); while that reports retained cleanup the instance stays busy, so root exit alone no longer admits a checkout. Covered by test_a_windows_pending_tree_keeps_a_dead_root_busy_until_cleanup_finishes.

The rebase also moved the new _reset_checkout_guard_tracking fixture into test/conftest_resets.py, following the conftest split in #22671. acp-client.md is updated for both changes.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: action required A blocking check or review needs attention labels Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Design Review (Opus 5.5, fork) — ✅ PASS

Design-level review of 181cb7465070e0e2c0e5934e69da914f59c6b240 via the fork AI-review pipeline — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS does not.

Design-Verdict: PASS

Nothing blocks: if any of the new busy bookkeeping goes wrong, the only effect is that a branch switch is refused, and chat turns, sub-agents and spawning keep working.

Notes

  • The new prompt registry is a module-global _prompts dict, and its entries are cleared from about six teardown and reader call sites across acp/. A missed clear can leave a repository refusing every switch for the rest of the gateway's life, with no in-product way to clear it. A small TTL-free reconcile step that drops entries for process instances that no longer exist, or a diagnostic that names what is holding the repository, would make that failure visible.
  • In _admit_prompt, a session missing from _session_cwds falls back to "", which counts as "busy in every repository". So one channel or cron prompt whose folder is unknown blocks switching in every repository. Confirm that every caller of the prompt and steer methods records its folder in _session_cwds.
  • The ## Manual verification section was cut off where the description was truncated, so this review did not judge it.

[DESIGN-REVIEWED] 181cb74

Description read

[DESCRIPTION-READ] 5c85731f819e6de244e12b9415818a462be810f1c7d5ce2b7790dfaf5915a697

That sha256 names everything this verdict read: the PR description, plus the 1 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with .github/scripts/pr-description-capture.sh over the same inputs; if it differs, the description or that evidence changed after this verdict was formed and any finding drawn from either is unproven.

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Oct 22, 2026
@inariku
inariku force-pushed the feat/branch-switcher-takeover branch from 1f78cbe to e65b52e Compare October 22, 2026 23:20
@inariku

inariku commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Updated to e65b52e (still two commits):

GPT 6.1 Review on the previous head ended without a verdict (Bedrock 429 on both passes, run 39863015457), so the earlier blocking comment still shows d39aa94. A maintainer re-run on this head would be appreciated.

@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Oct 22, 2026
@inariku
inariku force-pushed the feat/branch-switcher-takeover branch from e65b52e to 181cb74 Compare October 23, 2026 00:56
@inariku

inariku commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Updated to 181cb74 (still two commits, same base as e65b52e). On e65b52e the GPT 6.1 Review produced a blocking verdict but could not post it, and the Opus 5.5 Review stopped in validation; both lanes hit the GitHub API rate limit. I read both reports from the run logs and fixed what they found:

  • Nested repository shadowed by its enclosing project (GPT, git_branches.py): _resolve_repo_root now picks the deepest allow-listed project containing the path (_most_specific_allowed_root), so a nested repo is no longer resolved to the outer one. The shared _match_allowed_root is unchanged. Test: test_a_nested_repository_is_not_shadowed_by_its_enclosing_project.
  • Right-click switched or created a branch (GPT, BranchSwitcher.tsx): a row now chooses on the primary button only; preventDefault still runs for every button to keep focus in the search box. Test: ignores a right-click on a branch row and on the create row.
  • {"result": null} answer never ended the prompt (Opus candidate, runtime_reader_loop.py): the runtime reader now ends it when the raw frame carries the key, matching AcpClient. Response routing is unchanged.
  • A runtime that died on its own kept its prompts counted (Opus candidate, runtime_liveness.py): _retire_tracking_after_exit calls end_prompts_after_teardown once the exit is confirmed (reaped and the pid gone), with the descendants it last recorded; an unconfirmed exit keeps them.

Each fix has a regression test that fails without it. acp-client.md is updated.

Unrelated Windows failures on e65b52e: test_security_sensitive_paths::test_cache_dict_is_bounded (known flaky, #23251), test_ci_file_shards::test_reduced_backend_scope_populates_every_ci_shard (45s subprocess timeout, also on the previous head), and 33 test_sibling_list_check.py cases where bash resolved to WSL with no distro installed. This branch touches none of them.

A maintainer approval of the fork runs on this head, and a re-run of GPT 6.1 / Opus 5.5 if they hit the rate limit again, would be appreciated. Thanks!

@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention merge conflict Branch has merge conflicts with its base — author must resolve before merge and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Oct 23, 2026
@inariku
inariku force-pushed the feat/branch-switcher-takeover branch from 181cb74 to 893b4dc Compare October 24, 2026 09:35
@inariku

inariku commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main 1241954 (head 893b4dc, still two commits) to clear the merge conflict.

The only conflict was src/kiro_crew/security_posture.py: #23357 split it into a facade and owners, so the one row this PR adds ("Git panel branch switcher") now lives in security_posture_sinks_delivery.py, right after "Git panel status and log" where it sat before. No other change to the patch; every other file carries the same added and removed lines as before.

Local checks on the rebased head: flake8, isort, black gate, mypy --platform linux, tsc, i18n:check, the branch-switcher vitest files (282), and the related backend tests (1,623 passed). 17 tests in test_acp_spawn_offload.py::TestRuntimeProjectedLaunchDocuments fail here, and fail the same way on a clean checkout of main 1241954 on this machine, so they are not from this PR.

@github-actions github-actions Bot removed the merge conflict Branch has merge conflicts with its base — author must resolve before merge label Oct 24, 2026
@inariku
inariku marked this pull request as draft October 24, 2026 09:53
inariku added a commit to inariku/KiroCrew that referenced this pull request Oct 24, 2026
Record the design kirodotdev#23102 implements so it can be agreed before any
code lands: a branch picker in the Git panel header and the composer
chip, an owner-only switch on the worktree route's project boundary,
and a busy rule that refuses a switch while any chat turn,
linked-channel turn, sub-agent, workflow step or ACP prompt in flight
works in the repository, ending no session. Splits the implementation
into four phases and lists the open questions for the maintainers.

Part of kirodotdev#22670
@inariku

inariku commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Moved to draft while the design goes through an RFC: #23725. Once it is accepted this pull request will be split along the RFC's four phases.

inariku added a commit to inariku/KiroCrew that referenced this pull request Oct 24, 2026
Record the design kirodotdev#23102 implements so it can be agreed before any
code lands: a branch picker in the Git panel header and the composer
chip, an owner-only switch on the worktree route's project boundary,
and a busy rule that refuses a switch while any chat turn,
linked-channel turn, sub-agent, workflow step or ACP prompt in flight
works in the repository, ending no session. Splits the implementation
into four phases and lists the open questions for the maintainers.

Part of kirodotdev#22670
@inariku
inariku force-pushed the feat/branch-switcher-takeover branch from 893b4dc to 84f59d9 Compare October 24, 2026 10:26
@inariku

inariku commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

Fixed the credit to match CONTRIBUTING.md: both commits now carry Co-authored-by: kyleseaman <2904635+kyleseaman@users.noreply.github.com> (the noreply form the contributors job reads). Trees are unchanged.

One gap I could not close here: CONTRIBUTING asks to keep the superseded author's commits as-is, but #17628's two commits plus this work would exceed the two-commit limit. When the RFC (#23725) is accepted and this is split into its phases, each phase PR will carry the same trailer.

inariku added a commit to inariku/KiroCrew that referenced this pull request Oct 24, 2026
Record the design kirodotdev#23102 implements so it can be agreed before any
code lands: a branch picker in the Git panel header and the composer
chip, an owner-only switch on the worktree route's project boundary,
and a busy rule that refuses a switch while any chat turn,
linked-channel turn, sub-agent, workflow step or ACP prompt in flight
works in the repository, ending no session. Splits the implementation
into four phases and lists the open questions for the maintainers.

Part of kirodotdev#22670
inariku added a commit to inariku/KiroCrew that referenced this pull request Oct 24, 2026
Record the design kirodotdev#23102 implements so it can be agreed before any
code lands: a branch picker in the Git panel header and the composer
chip, an owner-only switch on the worktree route's project boundary,
and a busy rule that refuses a switch while any chat turn,
linked-channel turn, sub-agent, workflow step or ACP prompt in flight
works in the repository, ending no session. Splits the implementation
into four phases and lists the open questions for the maintainers.

Part of kirodotdev#22670
inariku added a commit to inariku/KiroCrew that referenced this pull request Oct 24, 2026
Record the design kirodotdev#23102 implements so it can be agreed before any
code lands: a branch picker in the Git panel header and the composer
chip, an owner-only switch on the worktree route's project boundary,
and a busy rule that refuses a switch while any chat turn,
linked-channel turn, sub-agent, workflow step or ACP prompt in flight
works in the repository, ending no session. Splits the implementation
into four phases and lists the open questions for the maintainers.

Part of kirodotdev#22670
inariku and others added 2 commits October 25, 2026 08:13
Clicking the branch name in the Git panel header, or the branch segment
of the project chip under the chat box, opens a searchable picker that
switches local branches, checks out a remote-only branch as a tracking
branch, or creates a branch from the current commit.

GET /api/project/git/branches lists branches; POST
/api/project/git/switch is owner-gated and audited, runs git sandboxed
with hooks off, never overwrites uncommitted or ignored local files, and
refuses for subfolder projects and repositories declaring a checkout
filter. A switch whose request is cancelled mid-checkout still writes
its outcome to the SEL from the worker's own completion.

A switch is refused while work runs in the repository: a chat turn, a
turn a linked channel runs on a chat's session, pending sub-agents, a
workflow step, or any prompt in flight at the ACP transport until the
backend answers it. The switch reserves the repository before that
check, and turns, sub-agents, workflow steps and prompts wait out a
checkout in flight. Workflow steps keep their session whatever the step's
outcome; an unanswered prompt is what keeps the repository busy. The
refusal names the running chat or workflow.

Supersedes kirodotdev#17628.

Co-authored-by: kyleseaman <2904635+kyleseaman@users.noreply.github.com>
Fork PRs cannot attach media, so the review lanes read these from the branch.

Co-authored-by: kyleseaman <2904635+kyleseaman@users.noreply.github.com>
@inariku
inariku force-pushed the feat/branch-switcher-takeover branch from 84f59d9 to db42efd Compare October 24, 2026 23:27
@github-actions github-actions Bot added the merge conflict Branch has merge conflicts with its base — author must resolve before merge label Oct 24, 2026

This branch has not been deployed

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

Labels

fork Pull request from a fork (external contributor) merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: action required A blocking check or review needs attention

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard: add a branch picker to switch the project's checked-out branch

1 participant