gh-smart-clone is a GitHub CLI extension that encodes a canonical local
workspace layout for GitHub repositories. Paths answer project identity and
workspace relationship; remotes and optional local git identity answer push,
pull, and authorship. Humans and AI agents can read those facts from the
checkout without reconstructing them from memory. An agent skill
ships with the repo so agents know when to use each mode.
Before — common layouts after cloning with git clone, gh repo clone, or
an owner/repo wrapper. Destinations are tidy, but they do not say what kind of
work each checkout is:
~/Code/
├── YOUR_USERNAME/
│ ├── notes/
│ ├── widgets/ # your fork of acme/widgets — path says you own it
│ ├── illo-website/ # related repos scattered flat under the owner
│ ├── illo-skill/
│ └── illo-characters/
└── contoso/
└── cli/ # contribution checkout mixed with first-party work
YOUR_USERNAME stands for your own GitHub account; acme and contoso are
other people's.
After — the same repos with gh smart-clone (normal, --oss,
--contribute, and --group):
~/Code/
├── YOUR_USERNAME/
│ ├── notes/ # first-party
│ └── illo/ # --group illo (one logical multi-repo workspace)
│ ├── illo-website/
│ ├── illo-skill/
│ └── illo-characters/
├── acme/
│ └── widgets/ # fork lives under upstream project identity
│ # origin -> YOUR_USERNAME/widgets
└── oss/
├── acme/
│ └── widgets/ # --oss: external inspection of the same project
└── contoso/
└── cli/ # --contribute: origin=fork, upstream=contoso/cli
What changed: project identity stays in owner/repo, first-party vs external
work is a root (oss/), related repos share a group folder, and fork ownership
stays on the remotes—not the path.
gh repo clone already clones well and sets up fork remotes. Tools like
ghq already give deterministic
host/owner/repo layouts. Owner/repo wrappers already avoid dumping clones into
the current directory.
The gap is workspace semantics: the local tree should encode what kind of work a checkout is, not only where the bytes live. That matters for day-to-day navigation and even more for AI agents, which otherwise confuse project identity, fork ownership, and write authority.
For forks, the clone source stays as the repository you requested: your fork
remains origin, while gh repo clone can still configure the parent as
upstream. Contribution mode (--contribute) is different: it treats the
input as the upstream project, creates or reuses your fork, clones the fork as
origin, and configures upstream to the original repository.
Five concerns are kept separate on purpose:
| Concern | Encoded by | Answers |
|---|---|---|
| Project identity | owner/repo path segment (upstream by default for forks) |
What canonical project is this? |
| Workspace relationship | Main prefix vs oss/ |
First-party/maintained work, or external OSS? |
| Fork ownership | Remotes (origin / upstream), not the path |
Where do pushes and upstream pulls go? |
| Logical multi-repo workspace | --group parent directory |
Which related repos form one working surface? |
| Git identity | Optional local user.name / user.email in contribution mode |
Which author should commits use here? |
Fork owner is a push mechanism, not project identity. The oss/ root is a
workflow boundary, not merely a tidy folder name. --group defines a shared
parent directory that humans and agents can treat as one logical project root
across multiple repositories; it does not change remotes, fork ownership, or
local git identity.
| Tool | What it does well | What it does not encode |
|---|---|---|
git clone |
Lowest-level clone control | Destination taxonomy, fork/upstream workflow, workspace modes |
gh repo clone |
GitHub auth, clone UX, fork remotes (origin / upstream) |
Local path meaning: first-party vs external, upstream project placement, contribution setup |
ghq |
Deterministic host/owner/repo layout across hosts |
GitHub-specific workspace relationship, contribution fork placement, multi-repo group roots, contribution identity |
| Owner/repo clone wrappers | Simple namespaced destinations under an owner | Distinction between inspection and contribution, explicit fork creation, upstream-path contribution checkouts |
gh-smart-clone is not a replacement for those tools. It sits on gh repo clone
for cloning and remotes, prefers a GitHub-only owner/repo layout (no host
segment), and adds the semantics those tools intentionally leave open: when
work is external, when a fork may be created, where a contribution checkout
lives, how related repos share a workspace root, and optional local identity
for contribution work.
Requirements:
- GitHub CLI
git
gh extension install tmchow/gh-smart-cloneTo install from a local checkout:
git clone https://github.com/tmchow/gh-smart-clone
cd gh-smart-clone
gh extension install .This repository also publishes an agent skill at
skills/gh-smart-clone/SKILL.md. Use it so agents default to gh smart-clone
and choose correctly among normal mode, --oss inspection, and --contribute
fork setup—instead of falling back to raw git clone / gh repo clone.
Install it globally (recommended):
npx skills add tmchow/gh-smart-clone --skill gh-smart-clone --globalCloning happens outside any one repo, so the skill is only useful if it is available everywhere. Project-only installs are supported but not recommended: the skill will be missing exactly when you clone from somewhere else.
npx skills add tmchow/gh-smart-clone --skill gh-smart-cloneInstall it for a specific agent:
npx skills add tmchow/gh-smart-clone --skill gh-smart-clone --global --agent codex
npx skills add tmchow/gh-smart-clone --skill gh-smart-clone --global --agent claude-codeList installed skills:
npx skills list
npx skills list --globalUpdate the skill:
npx skills update gh-smart-clone
npx skills update gh-smart-clone --globalRemove the skill:
npx skills remove gh-smart-clone
npx skills remove gh-smart-clone --globalUse the skill once without installing it:
npx skills use tmchow/gh-smart-clone@gh-smart-clonegh smart-clone YOUR_USERNAME/notes
gh smart-clone acme/widgets
gh smart-clone YOUR_USERNAME/widgetsThe default clone root is ~/Code. Override it with --prefix:
gh smart-clone --prefix ~/Developer YOUR_USERNAME/widgetsor with configuration:
git config --global smart-clone.prefix ~/Developeror with an environment variable:
GH_SMART_CLONE_PREFIX=~/Developer gh smart-clone YOUR_USERNAME/widgetsSometimes several repositories belong together even though GitHub stores them
flat under one owner. Use --group to place them under a shared parent
directory that acts as a logical multi-repo workspace root—one place humans and
AI agents can operate across related checkouts:
gh smart-clone --group illo YOUR_USERNAME/illo-website
gh smart-clone --group illo YOUR_USERNAME/illo-skill
gh smart-clone --group illo YOUR_USERNAME/illo-characters
# -> ~/Code/YOUR_USERNAME/illo/illo-website
# -> ~/Code/YOUR_USERNAME/illo/illo-skill
# -> ~/Code/YOUR_USERNAME/illo/illo-charactersThe group is a directory segment placed between owner and repo. It is never
itself a git repository, and grouping never changes origin, upstream, fork
ownership, or local git identity. Grouping is always explicit; a shared name
prefix like illo- does not imply a group on its own.
--group composes with every mode and accepts nested segments:
gh smart-clone --oss --group vendor contoso/cli
# -> ~/Code/oss/contoso/vendor/cli
gh smart-clone --group clients/northwind northwind/invoices
# -> ~/Code/northwind/clients/northwind/invoicesUse --oss when a checkout is external upstream work rather than first-party
work:
gh smart-clone --oss contoso/cli
# -> ~/Code/oss/contoso/cli
gh smart-clone --oss YOUR_USERNAME/widgets
# -> ~/Code/oss/acme/widgetsThe owner/repo part still answers "what canonical project is this?" The
oss/ segment answers "is this external work?" Keeping those questions separate
helps avoid confusing maintained or first-party repositories with third-party
OSS inspection and contribution checkouts.
The default OSS root is <resolved-prefix>/oss. Override it with --oss-prefix:
gh smart-clone --oss-prefix ~/src/external contoso/clior with configuration:
git config --global smart-clone.ossPrefix ~/src/externalor with an environment variable:
GH_SMART_CLONE_OSS_PREFIX=~/src/external gh smart-clone --oss contoso/cli--oss-prefix implies --oss. --external is an alias for --oss.
Use --contribute when you intend to make changes through a fork:
gh smart-clone --contribute contoso/cli
# -> ~/Code/oss/contoso/cliThis mode may create external GitHub state. Normal clone mode and --oss never
create forks.
Contribution mode:
- resolves the input as the upstream project
- determines the fork owner
- creates or reuses the fork
- clones
<forkOwner>/<repo>into the upstream OSS path - sets
originto the fork - sets
upstreamto the original project - optionally sets local
user.nameanduser.email - optionally rewrites
originto an SSH alias URL
Configure contribution defaults with git config:
git config --global smart-clone.forkOwner OWNER_OR_ORG
git config --global smart-clone.gitName "Example Name"
git config --global smart-clone.gitEmail person@example.com
git config --global smart-clone.sshAlias github.com-workUse a one-off fork owner:
gh smart-clone --contribute --fork-owner OWNER_OR_ORG contoso/cliIf the fork owner differs from the authenticated gh user, gh-smart-clone
treats it as an organization fork target and passes --org OWNER_OR_ORG to
gh repo fork.
Require the fork to already exist:
gh smart-clone --contribute --no-fork contoso/cliIf a contribution checkout already exists, reconfigure it intentionally:
gh smart-clone --contribute --reconfigure contoso/cli--print-path and --dry-run do not create forks:
gh smart-clone --contribute --print-path contoso/cli
gh smart-clone --contribute --dry-run contoso/cliPreview the path without cloning:
gh smart-clone --print-path YOUR_USERNAME/widgets
gh smart-clone --dry-run YOUR_USERNAME/widgetsUse your fork owner instead of the upstream owner:
gh smart-clone --fork-placement fork YOUR_USERNAME/widgetsForward supported gh repo clone fork flags:
gh smart-clone --upstream-remote-name parent YOUR_USERNAME/widgets
gh smart-clone --no-upstream YOUR_USERNAME/widgetsForward raw git clone flags after --:
gh smart-clone YOUR_USERNAME/widgets -- --depth=1-P, --prefix <path> Clone root. Defaults to GH_SMART_CLONE_PREFIX,
then git config smart-clone.prefix, then ~/Code.
-g, --group <path> Organizational subfolder placed between owner
and repo. Cosmetic only: never changes remotes,
fork ownership, or local git identity.
--oss Use the OSS/external clone root.
--external Alias for --oss.
--oss-prefix <path> OSS clone root. Implies --oss. Defaults to
GH_SMART_CLONE_OSS_PREFIX, then git config
smart-clone.ossPrefix, then <prefix>/oss.
--contribute Create/reuse a fork, clone the fork, and place
the checkout under the upstream OSS path.
--fork-owner <owner> Account or org that should own contribution
forks. Defaults to smart-clone.forkOwner,
then the authenticated gh user.
--no-fork Do not create a fork. Require it to exist.
--reconfigure Reconfigure an existing contribution checkout
instead of cloning.
--fork-placement <policy> Where forks are placed: upstream or fork.
Defaults to upstream.
--dry-run Print what would happen without cloning.
--print-path Print the destination path without cloning.
--no-upstream Pass through to gh repo clone.
--upstream-remote-name <n> Pass through to gh repo clone.
-h, --help Show help.
--version Show version.
Run the test suite:
./test/run-tests.bashRun linting:
shellcheck gh-smart-clone test/run-tests.bashThe tests use a fake gh binary, so they do not clone repositories or require
network access.
This extension builds on ideas from:
spenserblack/gh-namespace-clone, which wrapsgh repo cloneand namespaces destinations by repository owner.AaronMoat/gh-cloneandhbowron/gh-clone, which use simpleowner/repoclone layouts.x-motemen/ghq, whosehost/owner/repolayout helped clarify why a GitHub-only workflow may prefer omitting the host segment.
gh-smart-clone takes the next step of using GitHub repository metadata to
encode workspace relationship and place contribution forks under their upstream
project identity.
MIT
