Reference
Usage
corralctl takes an owner and converges your local tree to match. Everything else is a flag, and every flag has a default that works.
Running it
clone is the documented spelling; the bare form, corralctl <owner>, does the same and keeps every existing script working. Every other operation is a subcommand too: sync, status, plan, prune, exec and mcp.
<owner> is a GitHub username or organisation and is the only required argument. base_dir defaults to $HOME/Code, and limit to 1000 repositories.
Authenticate first, either with the GitHub CLI or by setting GITHUB_TOKEN:
Nothing is written until you are happy with it — --dry-run prints what would happen and stops.
Smart syncing
corralctl keeps a .corral-state.json sidecar next to each repository's .git directory and compares the remote pushed_at against it. If nothing has been pushed since the last run, git pull is skipped rather than attempted, which is where the 10x to 50x speed-up on repeat runs comes from.
Pass --force-sync to pull regardless, or --no-sync to skip updates entirely.
Flags
| Option | Short | Default | Description |
|---|---|---|---|
--base-dir | $HOME/Code | Root directory for cloned repositories | |
--limit | -l | 1000 | Maximum repositories to fetch |
--concurrency | -c | 1 | Concurrent workers |
--dry-run | -n | off | Preview actions without making changes |
--orphans | -o | off | Detect local repositories no longer on GitHub |
--protocol | -p | https | Clone protocol: ssh or https |
--no-sync | off | Skip pulling changes for existing clones | |
--force-sync | off | Pull regardless of cached state | |
--layout | templated | Path layout for repositories | |
--finder-tags | on (macOS) | Apply managed native Finder tags | |
--interactive | -i | off | Launch the selector TUI |
--recurse-submodules | off | Initialise submodules on clone and sync | |
--output | text | Output format: text, json, ndjson | |
--auth | auto | Auth mode: auto, token, gh | |
--visibility | all | Filter: all, public, private | |
--include-forks | on | Include forks under Forks/ | |
--include-archived | on | Include archived repositories, tagged On Hold | |
--languages | Comma-separated language filter | ||
--exclude-languages | Comma-separated exclude list | ||
--clone-depth | 0 | Shallow clone depth; 0 disables | |
--blobless | off | Partial clone with filter=blob:none | |
--api-timeout | 30s | Deadline for GitHub API operations | |
--log-level | info | Verbosity on stderr: error, warn, info, debug |
Results go to stdout in whichever format --output selects. Diagnostics go to stderr, so --output json stays machine-readable when you redirect it.
Exec mode
exec runs a shell command across every clone that matches your filters, concurrently:
The command line is interpreted by /bin/sh -c on Unix and cmd.exe /C on Windows, whatever $SHELL names, so it means the same thing for everyone. To use another shell, name it in the command: corralctl exec "fish -c '...'".
--timeout 2m gives each repository its own deadline (the default, 0, means none). A command that overruns is killed with the processes it started, reported as timed out and counted as failed; the rest carry on.
--output ndjson writes one record per repository as it finishes, and --output json one document with every record and a summary, in the same shapes sync uses. A record carries repo (the path under the base directory), exit_code, duration_ms, stdout, stderr, timed_out and, when the command failed, error:
|
The same filtering flags apply, so you can scope a command to one ecosystem, one collection, or both. --visibility takes all or any top-level collection of the layout: public, private, work or forks. --dry-run works here too, and lists the repositories a command would run against without running it.
Mirror to other forges
corralctl sync pushes the organised tree out to other forges, creating each destination repository when it is missing and bringing its branches and tags to parity with the local clone. Branches are never forced.
A destination is <forge>[:<owner>][@<url>] — gitlab, gitlab:my-group, github:my-org, codeberg, bitbucket:workspace, or gitea@https://git.example.com for a self-hosted instance. The token for each forge comes from the environment variable its own tooling uses, and over HTTPS it authenticates the push too; pass --protocol ssh to use your keys.
| Option | Default | Description |
|---|---|---|
--to | Destination; repeatable, at least one required | |
--protocol | https | Push transport: https or ssh |
--concurrency | 4–8 | Repositories mirrored at once |
--timeout | 5m | Deadline for one repository on one destination |
--output | text | text, json or ndjson |
--dry-run | off | Report what would happen without creating or pushing |
Two things are refused. A repository is never pushed to the forge its origin lives on, so a clone taken from GitLab is not pruned against GitLab. And a destination that already holds a same-named repository with the other visibility is an error rather than a silent reuse.
One destination setting is changed. When a GitHub, Gitea, Forgejo or Codeberg repository's default branch no longer exists locally — deleted upstream, say — the push would prune it, and the forge would reject the whole push. sync first pushes the local default branch (origin's default, else the checked-out branch), makes it the destination's default, and reports default branch <old> -> <new>. A default that still exists locally is left alone. GitLab and Bitbucket destinations are pushed as before: Bitbucket Cloud's API cannot change a repository's main branch, and GitLab protects its default branch, so repointing it would not let the prune through. Change the default in the forge's settings when sync reports the rejection.
Worktree management
corralctl worktree creates, lists, removes, and prunes linked Git worktrees for repository clones across your workspace:
# List all linked worktrees across workspace repositories
# Create an isolated worktree for a feature branch
# Remove a worktree
# Prune stale and temporary worktrees
| Option | Default | Description |
|---|---|---|
--repo | Filter operation to a specific repository | |
--dry-run | off | Preview pruning without deleting files |
--temp-only | off | Only prune ephemeral scratchpad worktrees |
--force | off | Force removal even if uncommitted changes exist |
--output | text | Output format: text or json |
Multi-repository branching
corralctl branch coordinates Git branching operations across multiple workspace repositories matching your criteria:
# List branches across repositories
# Create a feature branch across all Go repositories
# Switch to the branch across all matching repositories
| Option | Default | Description |
|---|---|---|
--repo | Target a specific repository | |
--language | Filter repositories by language | |
--visibility | Filter repositories by visibility | |
--start-point | HEAD | Starting point for new branch |
--dry-run | off | Simulate operations without modifying repositories |
--all | off | List remote branches as well as local branches |
--output | text | Output format: text or json |
Workspace health audits
corralctl doctor audits all clones in your workspace for uncommitted changes, unpushed commits, detached heads, disk budget, cache integrity, and stale linked worktrees:
# Run workspace health audit
# Refresh macOS Finder tags and folder color labels across all clones
# Automatically prune stale and ephemeral linked worktrees
# Exclude large third-party trees or specific repositories
# Set a per-repository audit deadline
# Output as JSON for automated pipelines
Custom rule thresholds can be declared in .corral.json at your workspace root to configure warnings and limits for unpushed work, dirty working trees, disk usage, and stale worktrees.
| Option | Default | Description |
|---|---|---|
--refresh-tags | off | Refresh macOS Finder tags and folder color labels for all workspace repositories |
--prune-worktrees | off | Automatically prune stale and temporary linked worktrees |
--exclude | Comma-separated repository names or path patterns to exclude from audit | |
--timeout | 30s | Deadline per repository check (0 to disable) |
--config | Path to custom .corral.json configuration file | |
--output | text | Output format: text or json |
Adopting local repositories
corralctl adopt discovers untracked or unmanaged repositories on your filesystem, optionally relocates them into your structured corral layout, provisions the remote repository on your target forge (GitHub, GitLab, Gitea, Forgejo, Codeberg, Bitbucket), and links the local repository's origin remote:
# Discover untracked repositories and run interactive selection
# Adopt into your workspace and provision on GitHub
# Dry run adoption preview
| Option | Default | Description |
|---|---|---|
--forge | Target remote forge (github, gitlab, gitea, forgejo, codeberg, bitbucket) | |
--forge-url | Base URL for self-hosted instances | |
--owner | Remote namespace or user | |
--visibility | private | Visibility of created remote repo (private, public) |
--relocate | off | Relocate local repository into structured corral workspace layout |
--collection | Target collection directory (Public, Private, Forks, Work) | |
--target-dir | Destination root directory for relocation | |
--max-depth | 0 | Maximum traversal depth to discover repositories (0 for unlimited) |
--protocol | https | Git transfer protocol (https, ssh) |
--interactive, -i | off | Enable interactive Bubble Tea candidate selection wizard |
--untracked-only | true | Only inspect untracked repositories |
--finder-tags | on (macOS) | Apply managed macOS Finder Tags (e.g. Orange New Repo) |
--tag-only | off | Flag untracked repositories in macOS Finder without moving files |
--dry-run | off | Simulate operations without modifying local disk or remotes |
--output | text | Output format: text, json, or ndjson |
macOS Finder color tags and taxonomy
On macOS, corralctl automatically categorises repository folders using native Finder tags and color labels (com.apple.metadata:_kMDItemUserTags and com.apple.FinderInfo). This taxonomy visually signals repository state and makes Finder searches and Smart Folders intuitive across large collections:
| Color | Tag Name | Meaning & Trigger Signal |
|---|---|---|
| 🔴 Red | Needs Fix | Sync error or merge conflict: Merge conflicts, diverged tracking branches, or sync failures requiring manual intervention. |
| 🟢 Green | In-Flight | Active modifications in progress: Uncommitted working tree changes, unpushed commits, or stashes. |
| 🟣 Purple | Worktree / Experiment | Linked worktrees & experimental clones: Active linked worktrees, upstream forks, templates, and mirrors. |
| 🔵 Blue | Pristine | Clean, synced ground truth: Clean repository, fully pushed, in sync with upstream. |
| 🟡 Yellow | On Hold | Archived repository: Upstream repository has been archived on the remote forge. |
| ⚪ Grey | Dormant | Untouched reference repository: Clean repository with no commits for over 60 days. |
| 🟠 Orange | New Repo | Untracked or local repository: Discovered by corralctl adopt without an origin remote or not yet published upstream. |
Searching in Finder
You can search by tag in macOS Finder or Spotlight using tag:"In-Flight", tag:Pristine, tag:"New Repo", tag:"Needs Fix", or tag:Go, or click on any tag color in the Finder sidebar. Existing user-defined tags are always preserved.