Repository navigation
Description
Goal
gitcd clones a repository into a predictable path under root and the shell can jump to it.
No profiles yet.
Context
- Trigger: first milestone of the tool, bootstrapped from the design below.
- Affected: the whole repository, which does not exist as code yet.
Design this milestone implements
Per host settings, with a default template for the rest:
root: ~/Code
layout:
default: "{host}/{owner}/{repo}"
hosts:
dev.azure.com:
layout: "{host}/{org}/{project}/{repo}"
aliases: [ssh.dev.azure.com, vs-ssh.visualstudio.com]
github.com:
aliases: [github-work, github-private]
protocol: sshThe alias map is not optional. Two GitHub accounts are driven by SSH host aliases, because
GitHub binds one SSH key to one account, so the parser sees github-work as the host. Without
the map the layout breaks for the case the tool exists for.
Accepted inputs: SSH URL, HTTPS URL, scp style git@host:owner/repo.git, the Azure DevOps
_git form, and the bare host/owner/repo shorthand. The host is lowercased at parse time.
{owner} accepts slashes, for GitLab subgroups.
The binary prints the resolved path on stdout and everything else on stderr, so a shell function
can wrap it. gitcd shell-init zsh|bash|fish prints that snippet and gitcd path <query> is the
plumbing command it calls.
House conventions
cmd/gitcd/holds flag parsing and dispatch only, logic ininternal/<area>. No CLI
framework,flagand hand written dispatch, as inrelease-me.- Standard library plus
gopkg.in/yaml.v3, the parserrelease-mealready uses. Any other
dependency needs a reason in the pull request. - Apache-2.0 license header first in every
.gofile. mise.tomlpins every tool,Taskfile.yamlholds one target per check,checkaggregates
and holds no command of its own, CI runs one job per target.
Acceptance criteria
- Repository scaffolding exists:
AGENTS.md,CLAUDE.mdholding@AGENTS.md,README.md,
LICENSE,mise.toml,Taskfile.yaml,.golangci.yaml,.goreleaser.yaml,
renovate.json,.editorconfig,.gitignore,.github/workflows/,.agent-skills.json. -
docs/concepts/gitcd.mdrecords problem, goals, non goals, approach, alternatives and open
questions, carried over from the bootstrap plan. -
internal/remoteparses all five input forms into host, owner, project and repo, resolves
host aliases, and lowercases the host. One test per form. -
internal/layoutrenders a template to a path and maps a path back to a remote. -
internal/configloads~/.gitcd.yaml, falls back to$XDG_CONFIG_HOME/gitcd/config.yaml,
applies defaults and rejects an unknown key with a named error. -
gitcd clone <url|shorthand>clones into the rendered path and prints that path on stdout. -
gitcd cloneis idempotent: a target that exists with the same remote prints the path and
exits 0, and a target that exists with a different remote fails with both remotes named. -
gitcd path <query>resolves an exact repository name or ahost/owner/repoto its path. -
gitcd shell-init zsh|bash|fishprints a working wrapper function. -
gitcd versionprints the version, set at build time. - Every command supports
--dry-runwhere it writes. - Tests build git repositories under a temporary directory with
GIT_CONFIG_GLOBAL,
GIT_CONFIG_NOSYSTEM=1and a controlledHOME. No network. -
task checkpasses. - The bootstrap
PLAN.mdis deleted, its content now living in this issue series and in
docs/concepts/gitcd.md.
Out of scope
- Profiles, identity and anything writing git config. That is the next milestone.
list,cd, fuzzy matching,doctor,adopt,status,sync.- The landing page at gitcd.ostendorf.cloud.
Open question to resolve while implementing
- Azure DevOps SSH remotes are assumed to use host
ssh.dev.azure.comwith path
v3/{org}/{project}/{repo}, and HTTPSdev.azure.com/{org}/{project}/_git/{repo}. Unverified.
Confirm against a real remote before fixing the parser's behaviour.
Activity
simonostendorf commentedon Nov 13, 2026
Implemented on
feat/1-navigation-core, draft pull request #6.internal/remote,internal/layout,internal/config,internal/gitandinternal/shellare in place, with
cmd/gitcddispatchingclone,path,shell-initandversion.per target.
docs/concepts/gitcd.mdcarries the design and the decisions.task checkexit 0: ten targets green, six test packages ok with-race.gopkg.in/yaml.v3.git config --getrather thangit remote get-url, which expandsan
insteadOfrewrite and broke clone idempotency. Regression tested.Worth confirming before feat: identity profiles applied per remote #2 builds rules on them.
fix(layout): keep the Azure DevOps project in the rendered path
fix(shell): only cd when the clone created a directory
fix(git): stream clone progress instead of buffering it