ruvnet/ruflo · error · Error
repoRoot must be the git top-level: ${top}
Error message
repoRoot must be the git top-level: ${top} What it means
The CodexWorktreeCoordinator constructor resolves the passed repoRoot and requires it to equal (after resolve()) the `git rev-parse --show-toplevel` of that directory. Passing a subdirectory of the repository (or a path outside one) throws, because worktrees and the in-repo registry (.claude-flow/swarm/worktrees) are anchored to the top-level.
Source
Thrown at v3/@claude-flow/codex/src/worktrees/coordinator.ts:42
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
maxBuffer: 4 * 1024 * 1024,
}).trim();
}
function assertId(value: string, label: string): void {
if (!SAFE_ID.test(value)) throw new Error(`invalid ${label}: ${value}`);
}
export class CodexWorktreeCoordinator {
readonly repoRoot: string;
readonly registryDir: string;
readonly worktreeBase: string;
constructor(repoRoot: string) {
this.repoRoot = resolve(repoRoot);
const top = git(this.repoRoot, ['rev-parse', '--show-toplevel']);
if (resolve(top) !== this.repoRoot) throw new Error(`repoRoot must be the git top-level: ${top}`);
this.registryDir = join(this.repoRoot, '.claude-flow', 'swarm', 'worktrees');
this.worktreeBase = join(dirname(this.repoRoot), '.ruflo-worktrees', basename(this.repoRoot));
}
prepare(
runId: string,
agents: Array<{ id: string; readOnly?: boolean }>,
options: { allowDirty?: boolean; baseRef?: string } = {},
): WorktreeRunRecord {
assertId(runId, 'run id');
if (!agents.length) throw new Error('at least one agent is required');
const unique = new Set<string>();
for (const agent of agents) {
assertId(agent.id, 'agent id');
if (unique.has(agent.id)) throw new Error(`duplicate agent id: ${agent.id}`);
unique.add(agent.id);
}
const registryPath = this.registryPath(runId);View on GitHub (pinned to fa13ee4ad6)
Solutions
- Construct with the git top-level: execSync('git rev-parse --show-toplevel').trim()
- Add a resolveRoot helper that walks up from cwd until .git is found, then pass that
- Run the coordinator's entrypoint from the repository root
Example fix
// before
new CodexWorktreeCoordinator('v3/@claude-flow/codex'); // subdir -> throws
// after
import { execSync } from 'node:child_process';
const root = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
new CodexWorktreeCoordinator(root); Defensive patterns
Strategy: validation
Validate before calling
import { execSync } from 'node:child_process';
const gitRoot = (p: string) =>
realpathSync(execSync('git rev-parse --show-toplevel', { cwd: p, encoding: 'utf8' }).trim());
if (gitRoot(p) !== realpathSync(resolve(p))) throw new Error('not the git top-level'); Prevention
- Resolve the root once via rev-parse --show-toplevel and pass it to every git-anchored API
- Write a walk-up-to-.git helper for CLI entrypoints started in subdirectories
- Test coordinators from monorepo package directories
When it happens
Trigger: new CodexWorktreeCoordinator(process.cwd()) while the process runs in a package subdirectory; constructing with a monorepo package path; passing a directory that is not a git repository at all (rev-parse then fails or returns a different root).
Common situations: Monorepos where CLIs start in v3/@claude-flow/codex instead of the repo root; scripts hardcoding relative package paths; running inside a linked worktree's subdirectory.
Related errors
- repoPath must be the Git top-level: ${top}
- duplicate agent id: ${agent.id}
- duplicate repository path: ${path}
- invalid ${label}: ${value}
- at least one agent is required
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/e077d4344029b6ae.
Report an issue: GitHub.