Skip to content

feat(git): support configurable git remote name#1548

Open
deepakrawat-dce wants to merge 4 commits intocoleam00:devfrom
deepakrawat-dce:feat/configurable-git-remote
Open

feat(git): support configurable git remote name#1548
deepakrawat-dce wants to merge 4 commits intocoleam00:devfrom
deepakrawat-dce:feat/configurable-git-remote

Conversation

@deepakrawat-dce
Copy link
Copy Markdown

@deepakrawat-dce deepakrawat-dce commented May 3, 2026

Summary

  • Problem: Archon hardcodes 'origin' as the git remote name in all fetch/push/reset operations, breaking repos with non-standard remotes.
  • Why it matters: Organizations using custom-named remotes (e.g. jan, feb, mar for release-based workflows) cannot use Archon's worktree isolation at all.
  • What changed: Added worktree.remote config option, getDefaultRemote() auto-detection, and threaded remote name through all git operations.
  • What did not change (scope boundary): No changes to workflow execution, command parsing, adapter logic, or web UI. Only git/isolation plumbing.

UX Journey

Before

User                     Archon CLI                Git
────                     ──────────                ───
runs workflow ─────────▶ creates worktree
                         fetch origin <branch> ───▶ ERROR: 'origin' does not exist
                         ◀──────────────────────── fatal error
sees error ◀──────────── "Check network connection"

After

User                     Archon CLI                     Git
────                     ──────────                     ───
configures .archon/      (reads worktree.remote)
runs workflow ─────────▶ [resolveRemote()] ─────────▶  git remote
                         ◀─────────────────────────── returns 'mar'
                         fetch mar <branch> ──────────▶ SUCCESS
                         creates worktree from mar/main
sees worktree ◀────────── isolation ready

Architecture Diagram

Before

┌──────────────┐     ┌───────────────┐     ┌──────────────┐
│  CLI / Orch  │────▶│  @archon/iso  │────▶│  @archon/git │
│              │     │  worktree.ts  │     │  repo.ts     │
│              │     │               │     │  branch.ts   │
└──────────────┘     └───────────────┘     └──────────────┘
                            │
                     ┌──────┴──────┐
                     │ config-loader│
                     │ (RepoConfig) │
                     └─────────────┘

All git calls hardcode 'origin'

After

┌──────────────┐     ┌───────────────┐     ┌──────────────┐
│  CLI / Orch  │────▶│  @archon/iso  │────▶│  @archon/git │
│              │     │  worktree.ts  │     │ [~] repo.ts  │
│              │     │ [~] resolve   │     │ [~] branch.ts│
└──────────────┘     │    Remote()   │     │ [+] getDef.. │
                     └───────────────┘     └──────────────┘
                            │
                     ┌──────┴──────┐
                     │[~] config   │
                     │  +remote    │
                     └─────────────┘

All git calls use resolved remote name (config > auto-detect > error)

Connection inventory:

From To Status Notes
WorktreeProvider syncWorkspace modified Passes remote in options
WorktreeProvider getDefaultRemote new Used by resolveRemote()
WorktreeProvider execFileAsync modified Uses ${remote}/ instead of origin/
config-loader MergedConfig modified Propagates worktree.remote
syncWorkspace getDefaultBranch modified Passes remote param

Label Snapshot

  • Risk: risk: low
  • Size: size: M
  • Scope: git, isolation, config
  • Module: git:repo, isolation:worktree, core:config

Change Metadata

  • Change type: feature
  • Primary scope: multi (git + isolation + core)

Linked Issue

  • Closes: N/A (no existing issue — discovered during use)
  • Related: N/A

Validation Evidence (required)

bun test packages/git/src/git.test.ts
# 151 pass, 0 fail

bun test packages/isolation/src/providers/worktree.test.ts
# 147 pass, 0 fail

bun test packages/core/src/config/config-loader.test.ts
# 38 pass, 0 fail

# TypeScript
npx tsc --noEmit --project packages/git/tsconfig.json      # clean
npx tsc --noEmit --project packages/isolation/tsconfig.json # clean
npx tsc --noEmit --project packages/core/tsconfig.json      # clean
  • Evidence provided: All 336 tests pass, lint + prettier pass via pre-commit hooks
  • If any command is intentionally skipped: None skipped

Security Impact (required)

  • New permissions/capabilities? No
  • New external network calls? No (same git fetch/push, just configurable remote name)
  • Secrets/tokens handling changed? No
  • File system access scope changed? No
  • If any Yes: N/A

Compatibility / Migration

  • Backward compatible? Yes — all new parameters have defaults matching prior behavior ('origin')
  • Config/env changes? Yes — new optional worktree.remote field in .archon/config.yaml
  • Database migration needed? No
  • If yes, exact upgrade steps: N/A. Existing configs without worktree.remote behave identically.

Human Verification (required)

  • Verified scenarios: Ran workflow against a repo with non-origin remotes; confirmed getDefaultRemote() correctly auto-detects sole remote; confirmed worktree.remote config is respected
  • Edge cases checked: CRLF git output (Windows), multiple ambiguous remotes (actionable error), git failures propagating correctly, config absent (defaults to origin)
  • What was not verified: Docker environment, actual Windows host (CRLF test uses mock)

Side Effects / Blast Radius (required)

  • Affected subsystems/workflows: Worktree creation, workspace sync, branch detection, remote branch deletion
  • Potential unintended effects: None — all changes add an optional parameter with the existing 'origin' default. No behavior change for repos that already use origin.
  • Guardrails/monitoring: Existing tests cover all paths; the resolveRemote() method logs at info level when auto-detecting a non-origin remote

Rollback Plan (required)

  • Fast rollback command/path: Revert the single merge commit — all changes are additive with defaults, so reverting cleanly restores prior behavior
  • Feature flags or config toggles: The worktree.remote config field is the toggle — removing it reverts to origin behavior
  • Observable failure symptoms: "Failed to fetch base branch from ''" error during worktree creation

Risks and Mitigations

  • Risk: getDefaultRemote() now throws on git errors instead of returning null, which could surface unexpected errors in edge cases.

    • Mitigation: The function is only called inside resolveRemote() which is inside a createWorktree() try/catch that already surfaces errors with actionable messages. The error path is intentional — better to fail fast with the real error than mislead the user.
  • Risk: CRLF handling via /\r?\n/ regex could theoretically split differently on exotic git builds.

    • Mitigation: Git remote output is well-specified (one name per line). The regex handles both LF and CRLF, plus .trim() on each entry catches any trailing whitespace.

Summary by CodeRabbit

  • New Features

    • Repositories can now specify a custom Git remote via the worktree.remote setting in .archon/config.yaml, enabling support for repositories with non-standard remote names.
    • Automatic Git remote detection when the remote is not explicitly configured, with preference for origin and fallback to the sole configured remote.
  • Documentation

    • Updated configuration reference with remote selection behavior and auto-detection details.

Archon hardcoded 'origin' as the git remote name in all fetch/push/reset
operations. This breaks for repos that use non-standard remote names (e.g.
enterprise monorepos with numbered remotes like '260', '262', '264').

Add `worktree.remote` config option in `.archon/config.yaml` and auto-detection
via `getDefaultRemote()` when not configured:
  1. 'origin' if it exists (standard convention)
  2. The sole remote if only one is configured
  3. Actionable error if ambiguous (multiple non-origin remotes)

Thread the remote name through all git operations: syncWorkspace,
syncRepository, getDefaultBranch, getRemoteUrl, worktree creation (issue/PR/
task/fork), branch tracking, and remote branch deletion.

All existing callers default to 'origin' so this is fully backwards-compatible.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

📝 Walkthrough

Walkthrough

Adds repository-level git-remote support: introduces worktree.remote in repo config and remote on relevant types, adds getDefaultRemote() auto-detection, parameterizes git helpers and worktree lifecycle to use a resolved remote for fetch/reset/remote-url/default-branch logic, and updates tests/docs accordingly. (34 words)

Changes

Git Remote Configurability

Layer / File(s) Summary
Data Shape
packages/core/src/config/config-types.ts, packages/isolation/src/types.ts
Adds remote?: string to RepoConfig.worktree and MergedConfig; adds remote?: string to WorktreeCreateConfig and WorktreeDestroyOptions with docs describing auto-detection and failure conditions.
Configuration Loading
packages/core/src/config/config-loader.ts
mergeRepoConfig() trims and propagates repo.worktree.remote into the merged config result when present.
Core Git Helpers
packages/git/src/repo.ts, packages/git/src/branch.ts
Introduces `getDefaultRemote(repoPath): Promise<string
Worktree Provider Wiring
packages/isolation/src/providers/worktree.ts, packages/isolation/src/pr-state.ts
Worktree creation resolves remote (config → getDefaultRemote() → actionable error if ambiguous) and threads remote into syncWorkspaceBeforeCreate, PR and branch creation, deletion helpers; getPrState() parameterized to use the selected remote for git remote get-url.
Module Exports
packages/git/src/index.ts
Re-exports getDefaultRemote.
Orchestration
packages/core/src/orchestrator/orchestrator-agent.ts
Repository discovery/sync now loads per-repo config and passes resolved remote into syncWorkspace.
Cleanup Service
packages/core/src/services/cleanup-service.ts
Functions for determining main branch and PR safety accept/forward an optional remote.
Tests / Documentation
packages/git/src/git.test.ts, packages/isolation/src/providers/worktree.test.ts, packages/core/src/config/config-loader.test.ts, packages/docs-web/src/content/docs/reference/configuration.md
Adds/updates tests and docs: getDefaultRemote behavior, syncWorkspace remote usage and error messages, WorktreeProvider custom-remote test suite, config propagation tests, and docs describing worktree.remote resolution rules.

Sequence Diagram(s)

sequenceDiagram
    participant Config
    participant Orchestrator
    participant WorktreeProvider
    participant GitModule
    participant RepoFS

    Config->>Orchestrator: loadRepoConfig(repoPath)
    Orchestrator->>WorktreeProvider: request worktree create (repoPath, repoConf)
    alt repoConf.worktree.remote present
        WorktreeProvider->>WorktreeProvider: use configured remote (trimmed)
    else repoConf.worktree.remote missing
        WorktreeProvider->>GitModule: getDefaultRemote(repoPath)
        GitModule-->>WorktreeProvider: remote name or null
        alt remote null
            WorktreeProvider-->>RepoFS: throw actionable "ambiguous remote" error
        end
    end
    WorktreeProvider->>GitModule: syncWorkspace(workspacePath, baseBranch?, { remote })
    GitModule->>GitModule: git fetch <remote> <branch>
    GitModule->>GitModule: git reset --hard <remote>/<branch>
    WorktreeProvider->>GitModule: create branch / set-upstream using <remote>/<branch>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐇 I trimmed the remote, hopped through the tree,
origin or lone one — tell it to me.
I fetch and I reset from the named domain,
No more hardcoded hops — clarity for main.
A rabbit-approved refactor — tidy and spry.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: adding support for configurable git remote names, which is the core feature across all modifications in the changeset.
Description check ✅ Passed The PR description fully addresses the template with comprehensive sections covering problem statement, UX journey, architecture diagrams, connection inventory, change metadata, validation evidence, security impact, compatibility, human verification, side effects, rollback plan, and risk mitigation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/configurable-git-remote

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/isolation/src/pr-state.ts (1)

42-54: ⚡ Quick win

Use getRemoteUrl() here instead of duplicating the git call.

This PR already added a remote-aware helper in @archon/git, but this path still shells out directly. Reusing the helper keeps the no-remote/error behavior centralized and avoids the two implementations drifting again.

Suggested fix
-import { execFileAsync } from '@archon/git';
+import { execFileAsync, getRemoteUrl } from '@archon/git';
-  let remoteUrl = '';
-  try {
-    const { stdout } = await execFileAsync('git', ['-C', repoPath, 'remote', 'get-url', remote], {
-      timeout: 10000,
-    });
-    remoteUrl = stdout.trim();
-  } catch (error) {
+  let remoteUrl = '';
+  try {
+    remoteUrl = (await getRemoteUrl(repoPath, remote)) ?? '';
+  } catch (error) {
     getLog().debug(
       { err: error as Error, repoPath, branch },
       'isolation.pr_state_remote_lookup_failed'
     );
     cache?.set(branch, 'NONE');
     return 'NONE';
   }

As per coding guidelines, "Use @archon/git functions for git operations; use execFileAsync (not exec) when calling git directly".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/isolation/src/pr-state.ts` around lines 42 - 54, Replace the direct
git shell-out using execFileAsync that sets remoteUrl with the shared helper
getRemoteUrl from `@archon/git`: call getRemoteUrl(repoPath, remote) (or the
helper's appropriate param order) instead of execFileAsync, assign its result to
remoteUrl, and preserve the existing error handling path (log via getLog().debug
with the caught error, set cache?.set(branch, 'NONE') and return 'NONE') so
behavior remains identical; remove the duplicated git call and import
getRemoteUrl where pr-state.ts currently references execFileAsync/remoteUrl.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/git/src/repo.ts`:
- Around line 54-60: The remotes array may contain CRLF/trailing whitespace
(e.g., "origin\r") so remotes.includes('origin') can fail; update the
construction of remotes in repo.ts (the code that builds the remotes variable)
to normalize entries by trimming each item after split (e.g., .split('\n').map(r
=> r.trim()).filter(r => r.length > 0)) and then use the normalized remotes when
checking for 'origin' (and when returning remotes[0]) so CRLF or trailing spaces
won't break detection.
- Around line 62-66: The catch block in packages/git/src/repo.ts is swallowing
any git execution error and returning null (seen around the
get_default_remote_failed log), which incorrectly signals "no default remote";
change it to rethrow or propagate the git error except in the explicit case of
"no remote configured": in the catch in the function that queries the default
remote (references repoPath, getLog(), and the get_default_remote_failed log
key), inspect the error (err.stderr / exit code) and if it clearly indicates "no
remote" return null, otherwise rethrow the error so callers see the actual git
failure instead of the ambiguous null sentinel.

---

Nitpick comments:
In `@packages/isolation/src/pr-state.ts`:
- Around line 42-54: Replace the direct git shell-out using execFileAsync that
sets remoteUrl with the shared helper getRemoteUrl from `@archon/git`: call
getRemoteUrl(repoPath, remote) (or the helper's appropriate param order) instead
of execFileAsync, assign its result to remoteUrl, and preserve the existing
error handling path (log via getLog().debug with the caught error, set
cache?.set(branch, 'NONE') and return 'NONE') so behavior remains identical;
remove the duplicated git call and import getRemoteUrl where pr-state.ts
currently references execFileAsync/remoteUrl.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d656e48b-0636-4ddf-865b-01f8ac12f6dc

📥 Commits

Reviewing files that changed from the base of the PR and between 69b2c89 and ee4bbb3.

📒 Files selected for processing (10)
  • packages/core/src/config/config-loader.ts
  • packages/core/src/config/config-types.ts
  • packages/git/src/branch.ts
  • packages/git/src/git.test.ts
  • packages/git/src/index.ts
  • packages/git/src/repo.ts
  • packages/isolation/src/pr-state.ts
  • packages/isolation/src/providers/worktree.test.ts
  • packages/isolation/src/providers/worktree.ts
  • packages/isolation/src/types.ts

Comment thread packages/git/src/repo.ts Outdated
Comment thread packages/git/src/repo.ts Outdated
deepak-rawat added 2 commits May 3, 2026 17:18
Use 'jan', 'feb', 'mar' as example remote names instead of numbered
remotes that reference a specific organization.
- Split on /\r?\n/ instead of '\n' so Windows CRLF doesn't break
  origin detection (e.g. 'origin\r' fails includes('origin'))
- Let git execution errors propagate instead of swallowing them as
  null — callers now see the real failure instead of a misleading
  "set worktree.remote" message
@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 4, 2026

@deepakrawat-dce related to #1419 — worktree.baseBranch config vs configurable remote name share git-config concerns.

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 4, 2026

Hi @deepakrawat-dce — thanks for opening this PR.

This repository uses a PR template at .github/pull_request_template.md with several required
sections. A few of them appear to be empty or placeholder here:

  • UX Journey
  • Architecture Diagram
  • Label Snapshot
  • Change Metadata
  • Linked Issue
  • Validation Evidence
  • Security Impact
  • Compatibility / Migration
  • Human Verification
  • Side Effects / Blast Radius
  • Rollback Plan
  • Risks and Mitigations

Could you fill those out (even briefly)? The template
helps reviewers understand scope, risk, and rollback — it
speeds up review significantly.

If a section genuinely doesn't apply, just write "N/A" in
it rather than leaving it blank.

@leex279
Copy link
Copy Markdown
Collaborator

leex279 commented May 4, 2026

🔗 Related issue: This PR is related to issue #1273 ("syncWorkspace always resets managed source clone to origin/main, ignoring configured default_branch"). Supporting configurable remote names complements the branch-detection fix for that issue.

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 4, 2026

Review Summary

Verdict: blocking-issues

Your PR adds a well-scoped, well-tested feature that removes the hardcoded 'origin' assumption from Archon's git operations. The @archon/git and @archon/isolation layers are solid — the new remote-aware functions are covered by tests and the error handling is clean and actionable. The two gaps are both in @archon/core: the orchestrator and cleanup service still hardcode 'origin', so the feature silently degrades for repos configured with a custom remote. There's also no user-facing documentation for the new worktree.remote config surface.

Blocking issues

  1. packages/core/src/orchestrator/orchestrator-agent.ts:437-438syncWorkspace() called without the remote option. The orchestrator syncs the canonical repo before every workflow run; for repos with a custom remote this will fetch from the wrong remote and may cause stale-code issues. Load repoConfig.remote and pass it: syncWorkspace({ remote: repoConfig.remote ?? undefined }).

  2. worktree.remote config field undocumentedpackages/core/src/config/config-types.ts:199-218 and packages/core/src/config/config-loader.ts:458-461. Users cannot discover or configure this feature. Add documentation to packages/docs-web/src/content/docs/reference/configuration.md covering the resolution order (explicit config → auto-detect: origin → sole remote → error on ambiguity) and its effect on git fetch/push operations.

Suggested fixes

  1. packages/core/src/services/cleanup-service.ts:457getPrState() called without passing the remote. For repos with a non-origin GitHub remote, this silently returns 'NONE', so PR-merged branch cleanup is skipped. Thread config.remote from the repo config through the isSafeToRemove call chain to getPrState().

  2. packages/core/src/config/config-loader.ts:458-461mergeRepoConfig propagates worktree.remote but has no tests (the analogous worktree.baseBranch field has three). Add: 'propagates remote from repo worktree config', 'trims whitespace from remote', 'remote is undefined when not configured' under the loadConfig describe block in config-loader.test.ts.

  3. packages/docs-web/src/content/docs/reference/configuration.md:211 — "Base branch behavior" section still says "Auto-detects the default branch via git remote show origin". Update to describe the getDefaultRemote() auto-detection logic and how worktree.remote overrides it.

  4. CHANGELOG.md [Unreleased] section — missing an entry for the worktree.remote feature.

Minor / nice-to-have

  • packages/core/src/config/config-types.ts:209-210 and packages/isolation/src/types.ts:273: Comment examples "e.g. 'jan', 'feb', 'mar' for release-based remotes" are tied to one use case. Generalize or remove.
  • packages/core/src/config/config-types.ts:214: Docstring describes error-throwing behavior that lives in resolveRemote(), not this field. Rewrite as a return-value description.
  • packages/isolation/src/providers/worktree.test.ts:2361, 2401: Test assertions hardcode "Failed to fetch base branch from 'origin'" — use a regex to match the dynamic remote name.
  • packages/git/src/repo.ts:62: Redundant "(defaults to 'origin')" — remove (the function signature already says it).
  • packages/isolation/src/providers/worktree.test.ts: Add a test for createNewBranch with custom remote when request.fromBranch is set to confirm the start-point and sync behavior are correct.

Compliments

The end-to-end test coverage in worktree.test.ts (152 new lines for custom remote scenarios) is thorough and follows the project's testing patterns well. The resolveRemote() error message improvements and the getDefaultRemote() resolution logic are clean implementations with good comments. The error classification in classifyIsolationError remains consistent across the new remote-aware paths.


Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality, docs-impact.

Address review feedback:

- Load repo config before syncWorkspace in orchestrator-agent.ts and
  pass the resolved remote name
- Thread remote through cleanupMergedWorktrees → isSafeToRemove →
  getPrState so PR-state detection works for non-origin remotes
- Add getDefaultBranch remote param to getWorktreeStatusBreakdown
- Add config-loader tests: propagates remote, trims whitespace,
  undefined when not configured
- Add worktree test: fromBranch + custom remote (task workflow)
- Document worktree.remote in configuration.md reference
- Add CHANGELOG entry under [Unreleased]
- Generalize comment examples (remove org-specific language)
- Fix redundant docstring in getRemoteUrl
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/core/src/orchestrator/orchestrator-agent.ts (1)

774-780: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Sync notification always says "origin/" even when a different remote is configured.

remote is scoped inside discoverAllWorkflows and is not surfaced through DiscoverResult, so this user-facing message will be misleading whenever worktree.remote is set to something other than 'origin'.

🛠️ Proposed fix

Add remote to DiscoverResult and thread it through:

 interface DiscoverResult {
   workflows: WorkflowWithSource[];
   errors: readonly WorkflowLoadError[];
   syncResult?: WorkspaceSyncResult;
   syncError?: string;
   config?: MergedConfig;
+  remote?: string;
 }

Inside discoverAllWorkflows, return the resolved value:

-          return { workflows, errors: allErrors, syncResult, syncError, config };
+          return { workflows, errors: allErrors, syncResult, syncError, config, remote };

At the destructuring call site (lines 752–758):

 const {
   workflows: workflowsWithSource,
   errors: workflowErrors,
   syncResult,
   syncError,
   config: discoveredConfig,
+  remote: syncRemote,
 } = await discoverAllWorkflows(conversation);

In the notification template:

-        content: `Synced with origin/${syncResult.branch} \u2014 updated ${syncResult.previousHead} \u2192 ${syncResult.newHead}`,
+        content: `Synced with ${syncRemote ?? 'origin'}/${syncResult.branch} \u2014 updated ${syncResult.previousHead} \u2192 ${syncResult.newHead}`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/orchestrator/orchestrator-agent.ts` around lines 774 - 780,
The message hardcodes "origin/" because the remote name is not included in
DiscoverResult; update the discoverAllWorkflows return type (DiscoverResult) to
include a remote string, set that remote from worktree.remote inside
discoverAllWorkflows, thread it through to where syncResult is produced (ensure
the destructuring/site that consumes discoverAllWorkflows includes remote), and
replace the hardcoded "origin/" in the platform.sendStructuredEvent payload with
the remote value from syncResult (e.g., use
syncResult.remote/${syncResult.branch}) so the notification reflects the
configured remote.
packages/core/src/services/cleanup-service.ts (1)

587-611: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add remote parameter to the cleanupMergedEnvironments wrapper's options type.

The wrapper at isolation-operations.ts:168–174 accepts { includeClosed?: boolean }, but the underlying cleanupMergedWorktrees function now accepts { includeClosed?: boolean; remote?: string }. Without updating the wrapper's type, callers using the public API cannot pass the remote option.

Fix in isolation-operations.ts
 export async function cleanupMergedEnvironments(
   codebaseId: string,
   mainPath: string,
-  options: { includeClosed?: boolean } = {}
+  options: { includeClosed?: boolean; remote?: string } = {}
 ): Promise<CleanupOperationResult> {
   return cleanupMergedWorktrees(codebaseId, mainPath, options);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/services/cleanup-service.ts` around lines 587 - 611, The
wrapper function cleanupMergedEnvironments currently types its options as {
includeClosed?: boolean } but calls cleanupMergedWorktrees which accepts {
includeClosed?: boolean; remote?: string }, so update the wrapper's options type
to include remote?: string and forward options.remote when invoking
cleanupMergedWorktrees (ensure the function signature/parameter typing for
cleanupMergedEnvironments and any related call site or exported type reflect
remote?: string so callers can pass the remote option).
🧹 Nitpick comments (1)
packages/core/src/services/cleanup-service.ts (1)

308-316: Scheduled cleanup diverges from on-demand cleanup for non-origin remotes.

runScheduledCleanup (line 311) calls getDefaultBranch(mainRepoPath) without a remote, hardcoding 'origin' behavior. After this PR, the on-demand cleanupMergedWorktrees is remote-aware, but the periodic background cycle is not. For a repo configured with worktree.remote: upstream, the scheduler could fail to detect branches as merged (if they are merged into upstream/main but haven't reached origin/main), leaving worktrees behind indefinitely.

This is pre-existing behavior not changed by this PR, but the delta is now observable. A follow-up task to thread repo-config remote loading into runScheduledCleanup's per-environment loop would close the gap.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/services/cleanup-service.ts` around lines 308 - 316,
runScheduledCleanup currently calls getDefaultBranch(mainRepoPath) with the
implicit 'origin' behavior and should be made remote-aware like
cleanupMergedWorktrees; in the per-environment loop, load the repo config
(repo-config/worktree.remote) for mainRepoPath and pass the configured remote
down to getDefaultBranch and/or isBranchMerged (or call cleanupMergedWorktrees
with the remote) so branch-merger checks use the correct remote (e.g., pass
remote into getDefaultBranch, isBranchMerged, and any calls referencing
env.branch_name) to ensure the scheduler detects merges against non-origin
remotes such as upstream.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/services/cleanup-service.ts`:
- Around line 448-452: The worktree remote argument isn't flowing through the
isolation cleanup path: update the IsolationResolverDeps.cleanup.getBreakdown
type to accept an optional third parameter (remote?: string), adjust the
IsolationResolver implementation (the cleanup.getBreakdown caller/implementer)
to forward the remote to the underlying getWorktreeStatusBreakdown logic, and
update the command handler call site that currently does
getWorktreeStatusBreakdown(codebase.id, codebase.default_cwd) to load the repo
config (worktree.remote) and pass that value as the third argument so merge
detection uses the correct remote.

---

Outside diff comments:
In `@packages/core/src/orchestrator/orchestrator-agent.ts`:
- Around line 774-780: The message hardcodes "origin/" because the remote name
is not included in DiscoverResult; update the discoverAllWorkflows return type
(DiscoverResult) to include a remote string, set that remote from
worktree.remote inside discoverAllWorkflows, thread it through to where
syncResult is produced (ensure the destructuring/site that consumes
discoverAllWorkflows includes remote), and replace the hardcoded "origin/" in
the platform.sendStructuredEvent payload with the remote value from syncResult
(e.g., use syncResult.remote/${syncResult.branch}) so the notification reflects
the configured remote.

In `@packages/core/src/services/cleanup-service.ts`:
- Around line 587-611: The wrapper function cleanupMergedEnvironments currently
types its options as { includeClosed?: boolean } but calls
cleanupMergedWorktrees which accepts { includeClosed?: boolean; remote?: string
}, so update the wrapper's options type to include remote?: string and forward
options.remote when invoking cleanupMergedWorktrees (ensure the function
signature/parameter typing for cleanupMergedEnvironments and any related call
site or exported type reflect remote?: string so callers can pass the remote
option).

---

Nitpick comments:
In `@packages/core/src/services/cleanup-service.ts`:
- Around line 308-316: runScheduledCleanup currently calls
getDefaultBranch(mainRepoPath) with the implicit 'origin' behavior and should be
made remote-aware like cleanupMergedWorktrees; in the per-environment loop, load
the repo config (repo-config/worktree.remote) for mainRepoPath and pass the
configured remote down to getDefaultBranch and/or isBranchMerged (or call
cleanupMergedWorktrees with the remote) so branch-merger checks use the correct
remote (e.g., pass remote into getDefaultBranch, isBranchMerged, and any calls
referencing env.branch_name) to ensure the scheduler detects merges against
non-origin remotes such as upstream.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: edd0d4b1-1289-49fb-ad66-af1eaed9ad68

📥 Commits

Reviewing files that changed from the base of the PR and between 1415e15 and c55ab6d.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • packages/core/src/config/config-loader.test.ts
  • packages/core/src/config/config-types.ts
  • packages/core/src/orchestrator/orchestrator-agent.ts
  • packages/core/src/services/cleanup-service.ts
  • packages/docs-web/src/content/docs/reference/configuration.md
  • packages/git/src/repo.ts
  • packages/isolation/src/providers/worktree.test.ts
  • packages/isolation/src/types.ts
✅ Files skipped from review due to trivial changes (3)
  • CHANGELOG.md
  • packages/core/src/config/config-loader.test.ts
  • packages/isolation/src/types.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/isolation/src/providers/worktree.test.ts
  • packages/git/src/repo.ts

Comment on lines 448 to 452
export async function getWorktreeStatusBreakdown(
codebaseId: string,
mainRepoPath: string
mainRepoPath: string,
remote?: string
): Promise<WorktreeStatusBreakdown> {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all callers of getWorktreeStatusBreakdown and whether they pass remote
rg -n --type ts -A 3 "getWorktreeStatusBreakdown\s*("

Repository: coleam00/Archon

Length of output: 170


🏁 Script executed:

#!/bin/bash
# Fix regex: escape parenthesis properly
rg -n --type ts "getWorktreeStatusBreakdown" -A 3

Repository: coleam00/Archon

Length of output: 4480


🏁 Script executed:

#!/bin/bash
# Also verify the function signature in cleanup-service.ts around lines 448-452
rg -n -B 2 -A 8 "export async function getWorktreeStatusBreakdown" packages/core/src/services/cleanup-service.ts

Repository: coleam00/Archon

Length of output: 484


🏁 Script executed:

#!/bin/bash
# Check the command-handler.ts line 1004 context
sed -n '998,1015p' packages/core/src/handlers/command-handler.ts

Repository: coleam00/Archon

Length of output: 774


🏁 Script executed:

#!/bin/bash
# Read the full getWorktreeStatusBreakdown implementation
sed -n '448,520p' packages/core/src/services/cleanup-service.ts

Repository: coleam00/Archon

Length of output: 2163


🏁 Script executed:

#!/bin/bash
# Check orchestrator.ts context around line 91
sed -n '80,110p' packages/core/src/orchestrator/orchestrator.ts

Repository: coleam00/Archon

Length of output: 1180


🏁 Script executed:

#!/bin/bash
# Check if there's repo config loading at the command-handler call site
sed -n '990,1020p' packages/core/src/handlers/command-handler.ts

Repository: coleam00/Archon

Length of output: 1229


🏁 Script executed:

#!/bin/bash
# Check the getDefaultBranch signature and default behavior
rg -n -B 2 -A 5 "export.*function getDefaultBranch" packages/core/src

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Search for where getBreakdown is called in IsolationResolver
rg -n "getBreakdown" packages -t ts -A 3

Repository: coleam00/Archon

Length of output: 661


🏁 Script executed:

#!/bin/bash
# Check if loadConfig or loadRepoConfig is used in the command-handler.ts handler
grep -n "loadRepoConfig\|loadConfig" packages/core/src/handlers/command-handler.ts

Repository: coleam00/Archon

Length of output: 364


🏁 Script executed:

#!/bin/bash
# Find getDefaultBranch definition
rg -n "getDefaultBranch" packages/core/src/services/cleanup-service.ts -B 2 -A 3

Repository: coleam00/Archon

Length of output: 1006


🏁 Script executed:

#!/bin/bash
# See how getBreakdown is actually called in IsolationResolver
rg -n "getBreakdown" packages/isolation/src/resolver.ts -B 5 -A 5

Repository: coleam00/Archon

Length of output: 470


🏁 Script executed:

#!/bin/bash
# Check the full cleanup function that uses getBreakdown
sed -n '40,200p' packages/isolation/src/resolver.ts

Repository: coleam00/Archon

Length of output: 5127


🏁 Script executed:

#!/bin/bash
# Find where getBreakdown is actually invoked in IsolationResolver
rg -n "this\.cleanup\?.getBreakdown\|\.getBreakdown\(" packages/isolation/src/resolver.ts -B 2 -A 2

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Check the getDefaultBranch function signature
rg -n "^export.*function getDefaultBranch" packages/core/src/services/cleanup-service.ts -A 3

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/all/bin/bash
# Check if loadRepoConfig is available in command-handler context
rg -n "loadRepoConfig" packages/core/src/handlers/command-handler.ts

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Search for getDefaultBranch more broadly
rg -n "getDefaultBranch" packages/core/src/services/cleanup-service.ts | head -20

Repository: coleam00/Archon

Length of output: 293


🏁 Script executed:

#!/bin/bash
# Find the actual definition of getDefaultBranch
rg -n "function getDefaultBranch" packages/core/src

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Search in all .ts files for getDefaultBranch import and definition
rg -n "getDefaultBranch" packages/core/src -A 2 | head -40

Repository: coleam00/Archon

Length of output: 2960


🏁 Script executed:

#!/bin/bash
# Look at the imports in cleanup-service.ts to find where getDefaultBranch comes from
head -50 packages/core/src/services/cleanup-service.ts

Repository: coleam00/Archon

Length of output: 1973


🏁 Script executed:

#!/bin/bash
# Find getDefaultBranch definition in `@archon/git`
rg -n "export.*getDefaultBranch" packages/git/src -A 5

Repository: coleam00/Archon

Length of output: 520


🏁 Script executed:

#!/bin/bash
# Also search for it in git package more broadly
find packages/git -name "*.ts" -exec grep -l "getDefaultBranch" {} \;

Repository: coleam00/Archon

Length of output: 166


🏁 Script executed:

#!/bin/bash
# Check if repo config has a remote field and how it's accessed
rg -n "worktree\.remote" packages/core/src -B 2 -A 2

Repository: coleam00/Archon

Length of output: 833


🏁 Script executed:

#!/bin/bash
# Look at the Codebase type to see if it has remote info
rg -n "type Codebase\|interface Codebase" packages/core/src -A 10

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Check the config-loader to see what repo config contains
head -100 packages/core/src/config/config-loader.ts

Repository: coleam00/Archon

Length of output: 3379


🏁 Script executed:

#!/bin/bash
# Check the Codebase type definition
rg -n "export.*interface Codebase\|export.*type Codebase" packages/core/src -A 15

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Check if codebase has remote field or if it needs to be loaded from config
rg -n "codebase\." packages/core/src/handlers/command-handler.ts | grep -i remote

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# See what fields the Codebase has in the database
rg -n "type CodebaseRow\|interface CodebaseRow" packages/core/src -A 15

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Look for Codebase import in command-handler to understand where it comes from
grep -n "Codebase" packages/core/src/handlers/command-handler.ts | head -10

Repository: coleam00/Archon

Length of output: 762


🏁 Script executed:

#!/bin/bash
# Find Codebase type in types or db
find packages/core/src -name "*.ts" -exec grep -l "type Codebase\|interface Codebase" {} \;

Repository: coleam00/Archon

Length of output: 205


🏁 Script executed:

#!/bin/bash
# Search more broadly for Codebase type definition
rg -n "Codebase" packages/core/src/db -A 5 | grep -E "type|interface" -A 5

Repository: coleam00/Archon

Length of output: 5849


🏁 Script executed:

#!/bin/bash
# Get the Codebase type definition
grep -n "export.*type Codebase\|export.*interface Codebase" packages/core/src/types/index.ts -A 15

Repository: coleam00/Archon

Length of output: 474


🏁 Script executed:

#!/bin/bash
# Check if there's a loadRepoConfig call or similar available in command-handler
sed -n '550,560p' packages/core/src/handlers/command-handler.ts

Repository: coleam00/Archon

Length of output: 378


🏁 Script executed:

#!/bin/bash
# Check how repo config is used elsewhere to understand the pattern
rg -n "loadRepoConfig\|loadConfig" packages/core/src/handlers -B 2 -A 5

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Verify the IsolationResolver's actual function signature expectation
sed -n '45,55p' packages/isolation/src/resolver.ts

Repository: coleam00/Archon

Length of output: 437


🏁 Script executed:

#!/bin/bash
# Check how cleanup functions are called in IsolationResolver to see if remote can be passed through
rg -n "cleanup.getBreakdown\|\.cleanup\?.getBreakdown" packages/isolation/src/resolver.ts -B 3 -A 3

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Verify if loadRepoConfig is accessible in command-handler context
rg -n "loadRepoConfig\|loadConfig" packages/core/src/config/config-loader.ts | head -5

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Double-check: search for all places getBreakdown is actually called in IsolationResolver
rg -n "getBreakdown" packages/isolation/src/resolver.ts -B 5 -A 5

Repository: coleam00/Archon

Length of output: 470


🏁 Script executed:

#!/bin/bash
# Verify if makeRoom function also has the same signature issue
sed -n '46,52p' packages/isolation/src/resolver.ts

Repository: coleam00/Archon

Length of output: 352


🏁 Script executed:

#!/bin/bash
# Check if there are any recent changes to getWorktreeStatusBreakdown signature
git log -p --all -S "getWorktreeStatusBreakdown" -- packages/core/src/services/cleanup-service.ts | head -100

Repository: coleam00/Archon

Length of output: 41


🏁 Script executed:

#!/bin/bash
# Check if TypeScript compilation would catch this type mismatch
# by looking at the actual assignment in orchestrator.ts
sed -n '85,95p' packages/core/src/orchestrator/orchestrator.ts

Repository: coleam00/Archon

Length of output: 463


🏁 Script executed:

#!/bin/bash
# Verify the complete picture: search for all instances of remote configuration in cleanup/isolation contexts
rg -n "remote" packages/isolation/src/resolver.ts

Repository: coleam00/Archon

Length of output: 139


🏁 Script executed:

#!/bin/bash
# Check if there are any type assertions or overloads for getBreakdown
rg -n "getBreakdown" packages/core/src/orchestrator/orchestrator.ts -B 5 -A 5

Repository: coleam00/Archon

Length of output: 475


🏁 Script executed:

#!/bin/bash
# Check if TypeScript compilation errors are expected or if there's a tsconfig that might suppress this
rg -n "getWorktreeStatusBreakdown" packages/core/src/orchestrator/orchestrator.ts -B 2 -A 2

Repository: coleam00/Archon

Length of output: 390


🏁 Script executed:

#!/bin/bash
# Check the types more carefully - does the assignment work despite the signature mismatch?
# Let's look at the complete function in cleanup-service to verify the parameter count
sed -n '448,455p' packages/core/src/services/cleanup-service.ts

Repository: coleam00/Archon

Length of output: 336


🏁 Script executed:

#!/bin/bash
# Verify the interface definition once more and check if there's been a recent update
sed -n '48,52p' packages/isolation/src/resolver.ts

Repository: coleam00/Archon

Length of output: 294


🏁 Script executed:

#!/bin/bash
# Search for any TypeScript error suppressions around this code
rg -n "@ts-ignore\|@ts-expect-error" packages/core/src/orchestrator/orchestrator.ts -B 3 -A 3

Repository: coleam00/Archon

Length of output: 41


Type signature mismatch and missing remote parameter flow in worktree status breakdown.

getWorktreeStatusBreakdown function signature has 3 parameters including optional remote, and its implementation passes remote to getDefaultBranch(repoPath, remote) at line 466. However, the IsolationResolverDeps.cleanup.getBreakdown interface (packages/isolation/src/resolver.ts:50) is defined with only 2 parameters: (codebaseId: string, repoPath: string). This type incompatibility prevents remote from being passed through the isolation resolver path.

Additionally, the command-handler.ts call (line 1004) passes only 2 arguments: getWorktreeStatusBreakdown(codebase.id, codebase.default_cwd), meaning repos with non-origin remotes configured via worktree.remote will always use 'origin' for merge detection, producing incorrect merged/stale counts in /worktree status output.

Fix requires:

  1. Update IsolationResolverDeps.cleanup.getBreakdown interface to accept an optional 3rd parameter for remote
  2. Update the IsolationResolver implementation to pass remote through the cleanup path
  3. Load repo config in command-handler.ts at line 1004 and pass the configured remote to getWorktreeStatusBreakdown
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/services/cleanup-service.ts` around lines 448 - 452, The
worktree remote argument isn't flowing through the isolation cleanup path:
update the IsolationResolverDeps.cleanup.getBreakdown type to accept an optional
third parameter (remote?: string), adjust the IsolationResolver implementation
(the cleanup.getBreakdown caller/implementer) to forward the remote to the
underlying getWorktreeStatusBreakdown logic, and update the command handler call
site that currently does getWorktreeStatusBreakdown(codebase.id,
codebase.default_cwd) to load the repo config (worktree.remote) and pass that
value as the third argument so merge detection uses the correct remote.

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.

3 participants