skeeper
Original:🇺🇸 English
Translated
Explains how to use skeeper to keep spec artifacts (SPEC.md, ADRs, RFCs, plan/PRD/TechSpec markdown, custom globs) next to the code they describe without polluting main-repo history. Covers strict hooks, the tracked skeeper.lock file, namespaces, sync/verify/fsck, safe drift workflows with diff/hydrate/reconcile/rescue/update, adopt/untrack/pattern, repair, SKEEPER_SKIP, and the GitHub Action. Use when setting up skeeper, configuring a sidecar, syncing/verifying a lockfile, recovering drift or failed syncs, auditing bypasses, or wiring CI. Do not use for general Git hook questions, repos with no .skeeper.yml and no intent to add one, or editing skeeper internals.
9installs
Sourcecompozy/skeeper
Added on
NPX Install
npx skill4agent add compozy/skeeper skeeperTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Skeeper Reference Guide
Comprehensive reference for the CLI: a Go binary that mirrors spec artifacts into a sidecar Git repository with a tracked lockfile, so a main repository's PR diffs stay focused on code and every commit can prove which spec state shipped with it.
skeeperWhat Is Skeeper
- Lockfile-backed reliability. is committed to the main repo and pins each main commit to exact sidecar commits per namespace, with content digests, file counts, and byte counts.
skeeper.lock - Strict managed hooks. and
pre-commitmirror staged content, push the sidecar, writepre-merge-commit, and stage it before Git creates the main commit.skeeper.lockre-verifies the lock against the sidecar remote.pre-push - Namespaces in shared sidecars. Many projects can share one sidecar Git remote without colliding because each project owns a namespace prefix and uses branch-aware refs of the form .
<namespace>/__branches__/<source-branch> - Safe drift handling. ,
diff,hydrate,reconcile, andrescueprotect local managed documents: Skeeper reports drift first, fails closed before overwrites, and preserves pruned files underupdate..git/skeeper/rescue/ - Single-binary, local-first. Skeeper shells out to (and
gitonly whenghcreates a brand-new sidecar repo). Every operation is debuggable with the same Git commands you already know.skeeper init
Mental Model: Four Invariants
- is the source of truth. It records sidecar URL, source branch, namespace branch, sidecar commit SHA, content digest, file count, and byte count. Hydrate, verify, and fsck all read from it. Never edit SHAs by hand.
skeeper.lock - Sync happens before the main commit, not after. Failure fails the commit. There is no async retry queue.
- Failure fails closed unless you opt out. allows a single bypass that is recorded to
SKEEPER_SKIP=1and surfaced in.git/skeeper/bypass.json,status, andfsckuntil cleared bypre-push.skeeper syncis unsupported because Git skips all hook code.git commit --no-verify - re-verifies before the remote sees the commit. A bypassed or stale lock blocks the push.
pre-push
mermaid
flowchart LR
A[git commit] --> B[existing user hook content]
B --> C[skeeper pre-commit block]
C --> D[reconcile staged specs and ownership]
D --> E[fetch and rebase sidecar branch]
E --> F[mirror namespace files into .skeeper/]
F --> G[commit and push sidecar]
G --> H[write and stage skeeper.lock]
H --> I[main commit proceeds]
I --> J[git push]
J --> K[skeeper pre-push verify]Quick Start
bash
# Inside any Git repository
skeeper init # interactive: pick sidecar mode, namespace, patterns
skeeper hooks install # one-time per clone
$EDITOR src/auth/SPEC.md
git add src/auth/service.go src/auth/SPEC.md
git commit -m "auth: design OAuth provider flow"
# the hook syncs the sidecar and stages skeeper.lock; commit it normally
git pushIf the working tree already contains specs that should be sidecar-managed, run after to migrate them in one transaction.
skeeper adopt <glob>initCommand Map
| Command | Purpose | Read-only? |
|---|---|---|
| Interactively bootstrap | no |
| Restore spec files from the sidecar commits recorded in | no |
| Mirror current specs to the sidecar and stage | no |
| Move main-tracked specs under sidecar coverage | no |
| Reverse adoption: stop tracking specs in the main repo | no |
| Preview which working-tree files a glob would match | yes |
| Add a glob to a namespace and update | no |
| Show sidecar URL, branch, lock state, namespace digests, repair, bypass | yes |
| Show sidecar history for a single spec file (default: locked commit; | yes |
| Compare working-tree specs against | yes |
| List path-level drift classes such as local-only, missing, modified, and conflict | yes |
| Resolve drift explicitly by adopting, pruning to rescue, merging, or choosing ours/theirs | no |
| Validate | yes |
| Install or refresh the strict hooks, | no |
| Validate that managed hook blocks and the merge driver are wired correctly | yes |
| Regenerate | no |
| List rescue manifests for files moved aside before prune or overwrite | yes |
| Restore all or selected files from a rescue manifest | no |
| Agent-friendly update workflow: fast-forward, verify, hydrate, fsck, hooks | no |
| Show the active transaction and any pending bypass | yes |
| Re-run the recorded plan after a transient failure | no |
| Clear the transaction (only safe before main-index mutation) | no |
| Print build metadata | yes |
--json--dry-run--forcesettings.guardrailsFor full per-flag detail, read .
references/cli-reference.mdConfiguration Cheatsheet
.skeeper.ymlyaml
sidecar: git@github.com:user/myproject-specs.git
namespaces:
- name: project
patterns:
- "**/SPEC.md"
- "docs/specs/**"
- ".claude/plans/**"
- "**/*.spec.md"
exclude:
- "docs/specs/private/**"Optional operational defaults:
yaml
settings:
guardrails:
max_files: 100 # default 100
max_bytes: 10485760 # default 10 MiB
hooks:
pre_push_timeout: 30s # default 30s
allow_skip_env: SKEEPER_SKIP # default SKEEPER_SKIPFour rules to know:
- Unknown keys are rejected. Decode is strict.
- is the only public exclusion mechanism. Negative globs (
exclude) inside!docs/private/**are rejected.patterns - Ownership must be unique. If two namespaces match the same file, the plan fails with a request to add an .
exclude - is reserved. It is the segment that separates a namespace from its branch-aware refs.
__branches__
For the full schema with every field and default, read .
references/config-reference.mdCommon Workflows
Bootstrap a new repository
bash
skeeper init \
--sidecar-name myproject-specs \
--visibility private \
--namespace project \
--patterns "**/SPEC.md" \
--patterns "docs/specs/**"
skeeper hooks install
git add .skeeper.yml .gitignore
git commit -m "chore: bootstrap skeeper"Join a repo with an existing sidecar
bash
skeeper init --sidecar git@github.com:user/shared-specs.git \
--namespace project \
--patterns "**/SPEC.md"
skeeper hydrateskeeper initskeeper hooks installAdopt files already in the main repo
bash
skeeper pattern test "docs/adrs/**" # confirm matches
skeeper adopt --dry-run "docs/adrs/**" # preview move
skeeper adopt "docs/adrs/**" # execute
git commit -m "chore: adopt ADRs into sidecar"Recover after a failed push
bash
skeeper repair status
# transaction: <id> (<phase>)
# fix the underlying network/auth/contention issue, then:
skeeper repair resume
# or, only before main-index mutation:
skeeper repair abortInspect and resolve local drift
bash
skeeper diff --modified
skeeper hydrate --dry-run
skeeper reconcile --adopt-local
# or preserve local-only files before restoring locked content:
skeeper reconcile --prune-local
skeeper rescue listUse when local edits are the intended spec state. Use when local-only files should be preserved in before restoring the locked sidecar content. Use , , or only when that conflict policy is explicit.
reconcile --adopt-localreconcile --prune-local.git/skeeper/rescue/<id>/--merge--ours--theirsUpdate a fresh clone or agent worktree
bash
skeeper update
skeeper update --reconcile keep-localupdateskeeper.lockfsckResolve a skeeper.lock
merge conflict
skeeper.lockbash
git merge feature/auth-redesign
# .gitattributes routes lock conflicts through skeeper merge-driver automatically
# if you resolved by hand:
skeeper sync
git add skeeper.lock
git commitCI Integration
Same-repository GitHub Action wraps the released binary:
yaml
name: skeeper
on:
pull_request:
push:
branches: [main]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: compozy/skeeper@v0.2.1
with:
args: |
verify
--json
ssh-private-key: ${{ secrets.SKEEPER_SSH_PRIVATE_KEY }}Credential precedence:
- writes a temp key and sets
ssh-private-key. The key is wiped on cleanup.GIT_SSH_COMMAND - configures HTTPS GitHub credentials in a per-job
token.GIT_CONFIG_GLOBAL - The runner's existing Git/SSH config is used when neither input is provided.
Secrets are always masked through before configuration.
::add-mask::When NOT To Use Skeeper
- Repos that already version specs in the main tree and want them to appear in PR diffs alongside code. Skeeper exists to keep specs out of those diffs.
- Teams that need PR review on the spec content itself before merge. Skeeper mirrors after the main commit succeeds, so spec review must happen against the sidecar repo or against the main-tree working copy before commit.
- Repos without a stable sidecar host. Skeeper requires a Git remote that the working tree can reach during commit; an unreachable remote means every commit fails closed unless someone uses .
SKEEPER_SKIP=1 - Storing build artifacts, generated code, or large binaries. Skeeper is for spec-shaped text artifacts. Guardrails default to 100 files and 10 MiB per plan precisely to keep it that way.
Anti-Patterns for Agents
- Never use on a skeeper-enabled repo. Use
git commit --no-verifyinstead so the bypass is audited.SKEEPER_SKIP=1 - Never edit SHAs in by hand. Use
skeeper.lockorskeeper syncto regenerate.skeeper merge-driver - Never reuse a sidecar remote across projects without unique namespaces. Skeeper requires unambiguous routing; ownership must be unique per file.
- Never run after the main index has been mutated. Use
skeeper repair abortinstead, or fix the sidecar manually if the sidecar has already received the push.skeeper repair resume - Never bypass with and forget to run
SKEEPER_SKIP=1afterward. The bypass keeps surfacing inskeeper sync,status, andfsckuntil cleared.pre-push - Never put negative globs in . Use
patternsinstead; the loader rejects negative globs explicitly.exclude - Never delete to "fix" a merge conflict. Resolve it via the merge driver, then run
skeeper.lock.skeeper verify - Never assume chases the latest tip. It restores from the locked commits;
skeeper hydrateonly exists on--latest.skeeper log - Never force hydrate/reconcile over local managed files without classifying drift first. Run and choose
skeeper diff,--adopt-local,--prune-local,--merge, or--oursdeliberately.--theirs
References
- — every command, every flag, every JSON schema.
references/cli-reference.md - — full
references/config-reference.mdschema, defaults, and validation rules..skeeper.yml