{"id":"4d15fa5f-e37d-40d2-9f31-b2334b131acf","slug":"repokeeper","kind":"mcp","name":"repokeeper","summary":"Repository automation and policy tooling.","owner":"skaphos","repoUrl":"https://github.com/skaphos/repokeeper","license":"MIT","licenseTier":"permissive","trust":"community","stars":3,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-02-12T21:53:56.000Z","addedAt":"2026-10-21T16:49:07.628Z","logoUrl":"https://avatars.githubusercontent.com/u/200722013?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["utilities"],"tags":["automation","governance"],"runtime":"go","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-21T19:15:28.979Z","sample":false,"url":"https://conduits.dev/tools/repokeeper","language":"Go","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# RepoKeeper\n\nA cross-platform multi-repo hygiene tool for developers who work across multiple machines and directory layouts.\n\nRepoKeeper inventories your repositories, reports drift and broken tracking, and performs safe sync actions (remote refresh by default, optional local update when explicitly enabled) — without hidden working-tree mutation or submodule recursion.\n\n## Features\n\n- **Discover** repositories across configured root directories (Git by default, optional experimental Hg)\n- **Report** per-repo health: dirty/clean, branch, tracking status, ahead/behind, stale upstreams\n- **Sync** safely with fetch/prune-first behavior; optional `--update-local` uses `pull --rebase` under explicit conditions\n- **Registry** is stored in `.repokeeper.yaml` with staleness detection\n- **Repo-local metadata** can be read from `.repokeeper-repo.yaml` or `repokeeper.yaml` and surfaced in JSON, describe output, and MCP repository context\n- **Remote-ref hygiene** reports stale remote-tracking refs in status, sync plans, and JSON/MCP output without pruning them during inspection\n- **CLI-first** with tabular (`table`/`wide`) and JSON output formats\n- **Cross-platform** — macOS, Windows, Linux (incl. WSL)\n\n## Multi-VCS (Experimental)\n\nRepoKeeper is Git-first. The Mercurial (`hg`) adapter is available as an **experimental** backend.\n\n- Default backend remains `git`\n- Opt in per command with `--vcs git,hg`\n- Mixed roots are auto-detected per repo path when multiple backends are selected\n\nCurrent experimental limits:\n\n- `hg`: discovery/status and safe `pull`-based fetch are supported\n- `hg`: `reconcile --update-local` (rebase/push/stash flows) is intentionally unsupported and is skipped with a reason\n- Repair and remote mismatch reconciliation flows remain Git-oriented\n\n## Install\n\nSee [INSTALL.md](INSTALL.md) for full install and upgrade instructions.\n\n### Homebrew (cask)\n\n```bash\nbrew tap skaphos/tools\nbrew install --cask skaphos/tools/repokeeper\n```\n\n### Linux packages\n\n```bash\n# Debian/Ubuntu\nsudo dpkg -i repokeeper_<version>_amd64.deb\n\n# Fedora/RHEL\nsudo rpm -i repokeeper-<version>-1.x86_64.rpm\n```\n\nDownload from the [Releases](https://github.com/skaphos/repokeeper/releases) page. **There is no\nhosted apt or yum repository** — a `.deb` on a release page is not an implied apt repo. Upgrading\nmeans downloading the next release's package.\n\n### From release binaries\n\nDownload the latest release from the [Releases](https://github.com/skaphos/repokeeper/releases) page.\n\n### From source\n\n```bash\ngo install github.com/skaphos/repokeeper/v2@latest\n```\n\nThe `/v2` suffix is required from 2.0.0 onward — Go encodes the major version in the module path.\nStaying on v1 needs no change: the unsuffixed path keeps resolving the newest v1 release, so\n`go install github.com/skaphos/repokeeper@latest` continues to install the latest v1.\n\n### Container (MCP server)\n\n```bash\ndocker pull ghcr.io/skaphos/repokeeper:latest\n```\n\nSee [MCP Server](#mcp-server-agent-integration) for the client configuration and its workspace\ncontract.\n\n## Upgrading\n\nRepoKeeper ships **no `update` subcommand**. Upgrade through the channel you installed from — the\ntable below is the complete list. The reasoning is recorded in\n[ADR-0016](docs/adr/0016-no-self-update-subcommand.md): a self-updater that cannot be skipped must\nverify in-process, and the dependency that makes that possible more than doubles the binary for\nevery user on every channel to serve one install path.\n\n| Installed via | Upgrade with |\n| --- | --- |\n| Homebrew cask | `brew upgrade --cask skaphos/tools/repokeeper` |\n| `.deb` | Download the next release's `.deb`, then `sudo dpkg -i repokeeper_<version>_amd64.deb` |\n| `.rpm` | Download the next release's `.rpm`, then `sudo rpm -U repokeeper-<version>-1.x86_64.rpm` |\n| `go install` | `go install github.com/skaphos/repokeeper/v2@latest` — note the `/v2`; the unsuffixed path stays on v1 |\n| Release archive | Download the next archive and replace the binary on your `PATH` |\n| Container image | `docker pull ghcr.io/skaphos/repokeeper:latest` |\n\nNot sure which you have? `repokeeper version` reports whether the binary was produced by the release\npipeline or installed from source, which narrows it.\n\n## Quick Start\n\n```bash\n# Bootstrap config and run initial scan for this directory\nrepokeeper init\n\n# Scan your roots for git repos\nrepokeeper scan\n\n# Scan/get across mixed git + hg roots\nrepokeeper scan --vcs git,hg\nrepokeeper get --vcs git,hg\n\n# Check the health of all repos\nrepokeeper get\n\n# Preview repo-local metadata for one tracked repo\nrepokeeper index github.com/org/repo\n\n# Write repo-local metadata after preview\nrepokeeper index github.com/org/repo --write\n\n# Fetch/prune all repos safely\nrepokeeper reconcile\n```\n\n## Expected User Flow\n\n1. From the directory you want to manage, run `repokeeper init`.\n2. `init` creates `.repokeeper.yaml`, sets that directory as the default root, and performs an initial scan.\n3. Run `repokeeper get` to review repo health and identify issues (dirty worktrees, gone upstreams, missing repos).\n4. Run `repokeeper reconcile` to safely fetch/prune across registered repos.\n5. Re-run `repokeeper scan` whenever clones are added, moved, or removed so the embedded registry stays current.\n6. If needed, widen scope for a specific run with `repokeeper scan --roots <dir1,dir2,...>`.\n\nScans preserve each known checkout's identity and local labels, including when another checkout of the same repository is temporarily unavailable. Missing checkouts remain registered. A new path gets a distinct `checkout_id`; a matching directory name and an absent old path do not establish a move. After an unrecorded move, scan retains the old entry as missing and registers the new path separately.\n\nScan treats each discovered repository root as a boundary and does not descend into it. Nested repositories or linked worktrees stored inside an already discovered working tree are therefore not registered separately and do not require extra exclude patterns.\n\n## Commands\n\nDetailed command breakdown moved to docs:\n\n- [docs/commands.md](docs/commands.md) - full command reference, flags, and behavior notes\n- [docs/adapter-contract.md](docs/adapter-contract.md) - stable machine-readable surfaces, adapter support declarations, and runtime compatibility checks\n- [docs/skills/README.md](docs/skills/README.md) - installable agent skill for OpenCode/compatible runtimes\n- [docs/man/README.md](docs/man/README.md) - manpage generation and release integration plan\n\nQuick highlights:\n\n- `repokeeper get` and `repokeeper reconcile` are direct command forms (`... repos` aliases still supported).\n- `repokeeper edit <selector>` opens a single repo entry YAML in your editor (`$VISUAL`/`$EDITOR`), validates, then saves.\n- `describe`, `label`, `edit`, `delete`, `move`, and `index` accept an absolute path, bare `checkout_id`, `repo_id`, or qualified `repo_id@checkout_id`. Relative paths work from the current directory or config root; symlink paths are resolved when available. Ambiguous IDs list matching qualified IDs and absolute paths.\n- `repokeeper label <selector>` manages machine-local labels via `--set key=value` and `--remove key`.\n- `repokeeper index <selector>` interactively proposes repo-local metadata and writes it only when `--write` is passed.\n- `repokeeper index repos --local-selector ... --promote-local-labels --write` explicitly bulk-promotes machine-local labels into repo-local metadata for selected repos.\n- Running `repokeeper` with no subcommand prints help. There is no interactive dashboard; see [ADR-0017](docs/adr/0017-retire-the-tui.md). Use `label` for repo labels and `index` for repo-local metadata.\n- `repokeeper install` registers `repokeeper mcp` with your agent runtime (Claude Code, Codex, OpenCode, or Grok); `repokeeper install list` shows registration state; `repokeeper uninstall` removes the entry.\n- MCP `plan_sync` matches CLI `reconcile --dry-run` for equivalent health filters and update options, including skip/failure reasons and repositories after a failed entry. Sync does not accept label filters; unsupported MCP `label_selector` requests are rejected.\n- Adapter JSON uses a versioned object with named payloads; see the [adapter contract](docs/adapter-contract.md) for fields and migration notes. MCP config and registry resources use snake_case fields and omit unknown observation timestamps. `describe -o json` reads live metadata without updating the on-disk cache. Batch commands may return valid JSON alongside a nonzero exit when individual repositories fail.\n- `get` reports repository errors on stderr, includes their count in the completion summary, and adds `ERROR_CLASS` to the default table when errors are present. Error diagnostics remain visible with `--quiet`; JSON stays on stdout.\n- `get` supports shared label filtering with `-l/--selector` and machine-local label filtering with `--local-selector` (`key` and `key=value`, comma-separated AND).\n- `add` supports metadata on create with `--label` and `--annotation` (repeatable `key=value`).\n\n### MCP Server (Agent Integration)\n\nRepoKeeper includes a built-in [MCP](https://modelcontextprotocol.io/) server for agent runtimes that support the Model Context Protocol (Claude Code, Codex, OpenCode, Grok, Cursor, Windsurf, etc.). MCP is the preferred integration path for inspection and planning workflows — it provides typed tool schemas, structured JSON responses, and automatic tool discovery.\n\nThe fastest setup is `repokeeper install`, which auto-detects Claude Code, Codex, OpenCode, and Grok and writes the server entry into the runtime's config:\n\n```bash\nrepokeeper install            # register with every detected runtime\nrepokeeper install list       # inspect registration state\nrepokeeper uninstall          # remove entries (prompts unless --yes)\n```\n\nFor runtimes without a flat-file MCP config RepoKeeper can adapter (Cursor, Windsurf), `repokeeper install --manual` prints the snippet you paste into their settings UI. See [docs/mcp-setup.md](docs/mcp-setup.md) for per-runtime paths, the full `install`/`uninstall` flag reference, and the MCP tool catalog.\n\nThe MCP server is primarily intended for inspection and planning workflows with browsable resources, but the current tool surface also includes some explicit state-changing operations. Those mutation-capable tools follow the same safety gates and opt-in behavior as their CLI counterparts, so agents and users should treat them as execution surfaces when enabled. The server reloads workspace configuration and registry state from disk for every request, keeping long-running sessions current without silently reverting manual configuration edits.\n\nRepoKeeper is published to the MCP registry as `io.skaphos/repokeeper`.\n\n#### Running the MCP server from a container\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"repokeeper\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\", \"-i\", \"--rm\",\n        \"-v\", \"/home/me/work/skaphos:/home/me/work/skaphos:ro\",\n        \"ghcr.io/skaphos/repokeeper:latest\",\n        \"mcp\", \"--config\", \"/home/me/work/skaphos/.repokeeper.yaml\"\n      ]\n    }\n  }\n}\n```\n\nFour things about this configuration are deliberate, and each is a constraint rather than a\npreference:\n\n- **The workspace is mounted at its identical host path.** `.repokeeper.yaml` records absolute\n  paths, so mounting anywhere else makes every registry entry miss and the inventory reports every\n  repository as missing. There is no path remapping — the registry means the same thing inside and\n  outside the container.\n- **The mount is read-only by default.** All nine inspection tools work normally. The five mutating\n  tools (`scan_workspace`, `execute_sync`, `set_labels`, `add_repository`, `remove_repository`)\n  refuse and name the read-only mount as the reason. They stay advertised rather than disappearing,\n  so a refusal is explainable rather than a silently missing capability. For read-write use, drop\n  the `:ro` suffix, add `--user \"$(id -u):$(id -g)\"` so files land with your ownership, and supply\n  git credentials.\n- **One configured entry serves exactly one workspace root.** The CLI finds its registry by walking\n  upward from the current directory, which is what lets several purpose-specific roots self-select\n  by where you are. A container's working directory and mounts are fixed before any tool call, so\n  that cannot be reproduced. If you keep several roots, add one server entry per root — and for a\n  position-sensitive multi-root workflow, the native binary remains the better path.\n- **The container supports Git only.** Mercurial is not installed in the image.\n\n### Repo-local metadata\n\nRepoKeeper can read optional repo-root metadata from either `.repokeeper-repo.yaml` or `repokeeper.yaml`.\n\n- `.repokeeper.yaml` remains the machine-local workspace config and registry.\n- `.repokeeper-repo.yaml` is the source-controlled repo metadata surface.\n\n- Reads are automatic and read-only in `scan`, `get`, `describe`, and the MCP repository resources.\n- `label` remains machine-local only.\n- `index --promote-local-labels --write` explicitly promotes machine-local labels into shared repo metadata.\n- `index repos --selector ...` / `--local-selector ...` previews or writes that promotion across multiple selected repos.\n- Inspection refreshes repo-metadata snapshots in memory when on-disk metadata changes. Plain `get` / `status` reads do not persist those refreshes; explicit scan and reconciliation operations save the registry.\n- `--yes` skips the final write confirmation, but does not change the requirement to pass `--write`.\n- Existing `repo_metadata.labels` win on key conflicts; promoted local labels only fill missing keys.\n\nRepoKeeper keeps two identity layers:\n\n- `repo_id`: stable upstream identity, used as the cross-machine join key.\n- `checkout_id`: machine-local checkout identity, used to distinguish multiple local clones of the same `repo_id`.\n\nExample:\n\n```yaml\napiVersion: repokeeper/v1\nkind: RepoMetadata\nrepo_id: ops-runbooks\nname: Ops Runbooks\nlabels:\n  role: runbooks\n  domain: ops\nentrypoints:\n  readme: README.md\npaths:\n  authoritative:\n    - runbooks/\n    - templates/\n  low_value:\n    - generated/\nprovides:\n  - runbook-templates\nrelated_repos:\n  - repo_id: internal-docs\n    relationship: references\n```\n\n### Global flags\n\n- `--verbose` / `-v` — increase verbosity (repeatable: `-vv` for debug)\n- `--quiet` / `-q` — suppress non-essential output\n- `--config <path>` — override config file location\n- `--no-color` — disable colored output (also respects `NO_COLOR` env var)\n- `--yes` — accept mutating actions without interactive confirmation\n\n## Configuration\n\nBy default, `repokeeper init` writes `.repokeeper.yaml` in your current directory.\n\nRuntime commands (`scan`, `get`, `reconcile`) resolve config in this order:\n\n1. `--config <path>`\n2. `REPOKEEPER_CONFIG` environment variable\n3. Nearest `.repokeeper.yaml` found by walking upward from the current directory\n4. Global fallback in platform config dir:\n- Linux: `$XDG_CONFIG_HOME/repokeeper/config.yaml` (default `~/.config/repokeeper/config.yaml`)\n- macOS: `~/Library/Application Support/repokeeper/config.yaml`\n- Windows: `%APPDATA%\\\\repokeeper\\\\config.yaml`\n\nFlag precedence (highest to lowest):\n1. Explicit command flags (`--config`, `--only`, `--field-selector`, `--selector`, etc.)\n2. Environment variables where supported (`REPOKEEPER_CONFIG`, `NO_COLOR`)\n3. Values loaded from the resolved config file\n4. Built-in command defaults\n\nSelector precedence:\n1. `--field-selector` when set\n2. `--only` when `--field-selector` is not set\n3. Providing both in one command is rejected\n4. `-l/--selector` is applied as an additional shared-label filter on the resulting repo set\n5. `--local-selector` is applied as an additional machine-local label filter on the resulting repo set\n\nExample config:\n\n```yaml\napiVersion: \"skaphos.io/repokeeper/v1beta1\"\nkind: \"RepoKeeperConfig\"\nexclude:\n  - \"**/node_modules/**\"\n  - \"**/.terraform/**\"\n  - \"**/vendor/**\"\nregistry:\n  updated_at: \"2026-02-14T10:00:00Z\"\n  repos: []\ndefaults:\n  concurrency: 8\n  timeout_seconds: 60\n```\n\nThe default scan/display root is inferred from the directory containing the active config file.\n\n## Safety\n\nRepoKeeper is designed to be safe to run on repos with dirty working trees:\n\n- By default, sync does **not** run checkout, reset, merge, or other hidden branch-navigation behavior\n- **Never** updates or recurses into submodules\n- Fetch uses `--no-recurse-submodules` and `-c fetch.recurseSubmodules=false` as belt-and-suspenders\n- All mutating commands support `--dry-run`\n- `scan`, `get`, `describe`, `add`, and `import` do not create or rewrite repo-local metadata files\n- `label` and `edit` do not write repo-local metadata files\n- `index --write` is the explicit repo-local metadata write path\n\nOptional local checkout update:\n\n- `repokeeper reconcile --update-local` adds `pull --rebase` after fetch, but only when all of these are true:\n- working tree is clean (or `--rebase-dirty` is set)\n- branch is not detached\n- branch tracks an upstream\n- branch is not ahead\n- branch is not diverged unless `--force` is set\n- branch is not matched by `--protected-branches` (default: none) unless `--allow-protected-rebase` is set\n- `--rebase-dirty` stashes changes, rebases, then pops the stash\n- `--push-local` pushes local commits when a branch is ahead (instead of skipping with \"local commits to push\")\n- `--continue-on-error` keeps processing all repos after per-repo failures (default true)\n- In dry-run/preflight mode, these checks are evaluated up front so the plan calls out which repos are candidates for `fetch + rebase` versus `skip local update (...)`.\n\nBranch switching and prune execution are separate workflow areas rather than hidden sync side effects.\n\n## Documentation\n\n- [docs/commands.md](docs/commands.md) - command reference\n- [docs/adapter-contract.md](docs/adapter-contract.md) - stable machine-readable contract for external adapters\n- [docs/mcp-setup.md](docs/mcp-setup.md) - MCP server setup for agent runtimes\n- [docs/skills/README.md](docs/skills/README.md) - user-scope agent skill installation and usage\n- [docs/man/README.md](docs/man/README.md) - manpage generation plan\n- [DESIGN.md](DESIGN.md) — full design specification and architecture\n- [TASKS.md](TASKS.md) — implementation milestones and task tracking\n- [CONTRIBUTING.md](CONTRIBUTING.md) — contributor workflow and PR expectations\n- [RELEASE.md](RELEASE.md) — release and tagging process\n- [INSTALL.md](INSTALL.md) — installation and upgrade paths\n\n## Development\n\nSpec Kit includes repo-local Codex skills in `.agents/skills/speckit-*/SKILL.md`.\nOpen Codex in this repository and invoke `$speckit-specify`, `$speckit-plan`,\n`$speckit-tasks`, or `$speckit-implement` to use the specification workflow.\nThe skills share the constitution and templates in `.specify/` and feature\nartifacts in `specs/`. Claude remains the default Spec Kit integration; Codex\nskills can be invoked directly without changing that default. If the skills\ndo not appear in an existing Codex session, restart the session.\n\nWith the Specify CLI installed, run `specify integration status` to check the\nsetup and `specify integration upgrade codex` to refresh the generated skills.\n\nThe fast unit tier remains `go test ./...`. Process-level coverage is integration-tagged and excluded from the ordinary package graph:\n\n```sh\ngo -C tools tool task test-integration\ngo -C tools tool task test-integration-race\ngo -C tools tool task test-default-excludes-e2e\n```\n\nSee [test/e2e/README.md](test/e2e/README.md) for recipe authoring, focused CLI/MCP runs, isolation guarantees, compatibility matrix commands, and failure diagnosis.\n\nThe Ginkgo unit command (also used by `task test`) explicitly excludes E2E packages because Ginkgo discovers test files without evaluating their `integration` build tags. Use `test-integration` above to run those packages.\n\n```bash\n# List all task targets without installing task globally\ngo -C tools tool task --list\n\n# Run unit tests\ngo run github.com/onsi/ginkgo/v2/ginkgo@v2.33.1 --skip-package=e2e ./...\n\n# Run with coverage\ngo test -coverprofile=coverage.out ./...\n\n# Run with coverage and enforce per-package thresholds\ngo -C tools tool task test-cover-check\n\n# Run coverage and print lowest-covered packages/functions\ngo -C tools tool task coverage-report\n\n# Run performance benchmarks and append historical record\ngo -C tools tool task perf-bench\n\n# Lint\ngo run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.14.0 run ./...\n\n# Build locally\ngo build -o repokeeper .\n\n# Build locally (task runner)\ngo -C tools tool task build\n\n# CI-style full platform build (task runner)\ngo -C tools tool task build-ci\n\n# Run standard CI pipeline locally (lint/test/staticcheck/vuln/build-ci)\ngo -C tools tool task ci\n\n# Format imports + code\ngo -C tools tool task fmt\n```\n\n## Security\n\nReport suspected vulnerabilities privately using the [security policy](SECURITY.md).\nPlease do not use public issues for security reports.\n\n## License\n\n[MIT](LICENSE)\n\n## Third-Party Notices\n\nRepoKeeper includes third-party open source components.\n\n- Runtime dependency notices for distributed binaries live in [`third_party_licenses/runtime/`](third_party_licenses/runtime/) with an inventory in [`third_party_licenses/runtime-report.csv`](third_party_licenses/runtime-report.csv).\n- The maintenance workflow and attribution expectations live in [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md).\n\nWhen dependencies change, regenerate the notice artifacts before opening a PR:\n\n```bash\ngo -C tools tool task notices\n```\n\n---\n\nSkaphos is a project of [Rillan AI LLC](https://skaphos.io), a Missouri\nlimited liability company. © 2026 Rillan AI LLC. Released under\nthe [MIT License](LICENSE).\n"}