@compozy/skeeper 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -44
- package/package.json +16 -16
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<
|
|
3
|
-
|
|
2
|
+
<p>
|
|
3
|
+
<img src="docs/assets/skeeper-readme-hero.png" alt="skeeper hero showing AI specs syncing into a sidecar Git repository" width="100%">
|
|
4
|
+
</p>
|
|
4
5
|
<p>
|
|
5
6
|
<a href="https://github.com/compozy/skeeper/actions/workflows/ci.yml">
|
|
6
7
|
<img src="https://github.com/compozy/skeeper/actions/workflows/ci.yml/badge.svg" alt="CI">
|
|
@@ -25,9 +26,9 @@ Specs and code want to live together. Spec files (`SPEC.md`, `docs/specs/*`, `.c
|
|
|
25
26
|
## ✨ Highlights
|
|
26
27
|
|
|
27
28
|
- **One sidecar repo, full Git history.** Specs version normally — `git log`, `git blame`, branches, PRs — without touching your main repo's diff.
|
|
28
|
-
- **Shared sidecars without collisions.**
|
|
29
|
+
- **Shared sidecars without collisions.** Named namespaces isolate stored paths and pushed branches inside one sidecar remote.
|
|
29
30
|
- **Edit specs where they belong.** Spec files stay next to the code they describe. `skeeper` mirrors them into `.skeeper/` for you.
|
|
30
|
-
- **A post-commit hook that never breaks your commit.** 750 ms foreground budget; on failure, the sync queues locally and retries on the next manual `skeeper sync`.
|
|
31
|
+
- **A post-commit hook that never breaks your commit.** 750 ms foreground budget per namespace; on failure, the sync queues locally and retries on the next manual `skeeper sync`.
|
|
31
32
|
- **Branch-aware mirroring.** Sidecar branches track main-tree branches, so feature work and `main` stay isolated.
|
|
32
33
|
- **Fresh-clone hydration.** `skeeper hydrate` restores matched specs into a new clone so teammates start with full context.
|
|
33
34
|
- **Glob-based pattern matching.** Doublestar globs (`**/SPEC.md`, `docs/specs/**`, `.claude/plans/**`) — match specs the way you actually organize them.
|
|
@@ -77,22 +78,22 @@ docker run --rm -v "$PWD:/workspace" -w /workspace skeeper:dev status
|
|
|
77
78
|
|
|
78
79
|
## 🔄 How It Works
|
|
79
80
|
|
|
80
|
-
Spec files live at their natural paths next to code. Your main repo's `.gitignore` lists
|
|
81
|
+
Spec files live at their natural paths next to code. Your main repo's `.gitignore` lists the effective namespace patterns plus `.skeeper/`, so neither owned specs nor the sidecar clone ever appear in a main-repo diff.
|
|
81
82
|
|
|
82
|
-
On every `git commit`, the managed post-commit hook runs `skeeper sync --hook` with a 750 ms foreground budget. `skeeper` matches files against
|
|
83
|
+
On every `git commit`, the managed post-commit hook runs `skeeper sync --hook` with a 750 ms foreground budget per namespace. `skeeper` matches files against namespace patterns, copies them into `.skeeper/`, commits with a reference to the main commit SHA, and pushes to the sidecar remote.
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
Each namespace stores files under `<namespace>/<path>` in the sidecar and pushes branch `<namespace>/__branches__/<source-branch>`. For example, namespace `skills` on source branch `main` stores `skills/review.md` as `skills/skills/review.md` and pushes sidecar branch `skills/__branches__/main`.
|
|
85
86
|
|
|
86
|
-
If anything fails — network, auth, push rejection, timeout — `skeeper` writes a retry record to `.git/skeeper/queue.json
|
|
87
|
+
If anything fails — network, auth, push rejection, timeout — `skeeper` writes a retry record to `.git/skeeper/queue.json` with the failing namespace when one is known, appends a one-line audit entry to `.git/skeeper/sync.log`, and exits 0 so your `git commit` always succeeds. Run `skeeper sync` later to drain the queue.
|
|
87
88
|
|
|
88
89
|
```mermaid
|
|
89
90
|
flowchart LR
|
|
90
91
|
A[Developer<br/>git commit] --> B[post-commit hook<br/>skeeper sync --hook]
|
|
91
|
-
B --> C{
|
|
92
|
+
B --> C{Namespace sync within<br/>750 ms?}
|
|
92
93
|
C -- yes --> D[Copy matched specs<br/>into .skeeper/]
|
|
93
94
|
D --> E[git commit<br/>in sidecar]
|
|
94
95
|
E --> F[git push<br/>to sidecar remote]
|
|
95
|
-
C -- no / error --> G[Write retry record<br/>.git/skeeper/queue.json]
|
|
96
|
+
C -- no / error --> G[Write namespace retry record<br/>.git/skeeper/queue.json]
|
|
96
97
|
G --> H[Hook exits 0<br/>main commit succeeds]
|
|
97
98
|
H -. later .-> I[skeeper sync<br/>drains queue]
|
|
98
99
|
I --> D
|
|
@@ -106,15 +107,20 @@ flowchart LR
|
|
|
106
107
|
# Required: sidecar repository URL
|
|
107
108
|
sidecar: git@github.com:user/myproject-specs.git
|
|
108
109
|
|
|
109
|
-
#
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
|
|
110
|
+
# Required: namespaces route files into sidecar paths and branches
|
|
111
|
+
namespaces:
|
|
112
|
+
- name: skills
|
|
113
|
+
patterns:
|
|
114
|
+
- "skills/*.md"
|
|
115
|
+
|
|
116
|
+
- name: myproject
|
|
117
|
+
patterns:
|
|
118
|
+
- "**/SPEC.md"
|
|
119
|
+
- "docs/specs/**"
|
|
120
|
+
- ".claude/plans/**"
|
|
121
|
+
- "**/*.spec.md"
|
|
122
|
+
exclude:
|
|
123
|
+
- "skills/*.md"
|
|
118
124
|
|
|
119
125
|
# Optional: install one-liner shown to teammates after `skeeper hydrate`
|
|
120
126
|
bootstrap: brew tap compozy/compozy && brew install --cask skeeper
|
|
@@ -122,9 +128,9 @@ bootstrap: brew tap compozy/compozy && brew install --cask skeeper
|
|
|
122
128
|
|
|
123
129
|
Unknown keys are rejected — config errors fail loud, not silently.
|
|
124
130
|
|
|
125
|
-
|
|
131
|
+
Every namespace needs a `name` and at least one `patterns` glob. `exclude` removes ownership from that namespace; if another namespace owns the excluded files, they stay tracked there. A file owned by more than one namespace is a configuration error because hidden precedence would make deletes unsafe.
|
|
126
132
|
|
|
127
|
-
|
|
133
|
+
`skeeper init` writes one namespace by default. Add more namespaces by editing `.skeeper.yml`.
|
|
128
134
|
|
|
129
135
|
Local-only state lives under `.git/skeeper/` (already gitignored by Git's hooks directory):
|
|
130
136
|
|
|
@@ -149,13 +155,13 @@ In a Git repo where you want to track specs:
|
|
|
149
155
|
skeeper init
|
|
150
156
|
```
|
|
151
157
|
|
|
152
|
-
Interactive by default — opens a terminal form for the sidecar mode, repository name or URL,
|
|
158
|
+
Interactive by default — opens a terminal form for the sidecar mode, repository name or URL, namespace, bootstrap command, and optional extra context globs. The interactive flow always includes the default spec globs (`**/SPEC.md`, `docs/specs/**`, `.claude/plans/**`, and `**/*.spec.md`) in the initial namespace; the extra context prompt starts empty and is only for additional folders or files you explicitly want in that namespace. Or pass values as flags:
|
|
153
159
|
|
|
154
160
|
```bash
|
|
155
161
|
skeeper init \
|
|
156
162
|
--sidecar-name myproject-specs \
|
|
157
163
|
--visibility private \
|
|
158
|
-
--
|
|
164
|
+
--namespace myproject \
|
|
159
165
|
--patterns "**/SPEC.md" \
|
|
160
166
|
--patterns ".claude/plans/**"
|
|
161
167
|
```
|
|
@@ -165,11 +171,13 @@ To reuse one shared sidecar remote across multiple source repos:
|
|
|
165
171
|
```bash
|
|
166
172
|
skeeper init \
|
|
167
173
|
--sidecar git@github.com:user/shared-specs.git \
|
|
168
|
-
--
|
|
174
|
+
--namespace myproject \
|
|
169
175
|
--patterns "**/SPEC.md"
|
|
170
176
|
```
|
|
171
177
|
|
|
172
|
-
`skeeper init` creates the GitHub repo with `gh repo create` unless `--sidecar` points to an existing remote. It clones the sidecar into `.skeeper/`, writes `.skeeper.yml`, updates `.gitignore`, and installs the post-commit hook. New init
|
|
178
|
+
`skeeper init` creates the GitHub repo with `gh repo create` unless `--sidecar` points to an existing remote. It clones the sidecar into `.skeeper/`, writes `.skeeper.yml`, updates `.gitignore`, and installs the post-commit hook. New init defaults the namespace to the source repo name.
|
|
179
|
+
|
|
180
|
+
When using flags, repeated `--patterns` values are the complete pattern set written to `.skeeper.yml`; they do not append to the interactive defaults.
|
|
173
181
|
|
|
174
182
|
### 3. Edit specs and commit normally
|
|
175
183
|
|
|
@@ -209,11 +217,11 @@ skeeper sync --pull # rebase the sidecar branch first — useful when teammat
|
|
|
209
217
|
|
|
210
218
|
## 🧰 How Sync Works
|
|
211
219
|
|
|
212
|
-
The post-commit hook is a _managed block_ in `.git/hooks/post-commit`, installed idempotently. It runs `skeeper sync --hook` with a 750 ms foreground budget so your `git commit` stays
|
|
220
|
+
The post-commit hook is a _managed block_ in `.git/hooks/post-commit`, installed idempotently. It runs `skeeper sync --hook` with a 750 ms foreground budget per namespace so your `git commit` stays bounded even on a slow network.
|
|
213
221
|
|
|
214
|
-
On the success path, `skeeper` matches files with doublestar globs, copies them into `.skeeper/`, then runs `git add`, `git commit`, and `git push` against the sidecar remote.
|
|
222
|
+
On the success path, `skeeper` matches files with doublestar globs, copies them into `.skeeper/`, then runs `git add`, `git commit`, and `git push` against the sidecar remote. Each namespace copies to `.skeeper/<namespace>/<path>` and pushes `<namespace>/__branches__/<source-branch>`. Sidecar commits reference the main-repo SHA so you can correlate spec changes back to the code change that triggered them.
|
|
215
223
|
|
|
216
|
-
On the failure path — timeout, auth failure, network failure, or push rejection — `skeeper` writes a retry record to `.git/skeeper/queue.json
|
|
224
|
+
On the failure path — timeout, auth failure, network failure, or push rejection — `skeeper` writes a retry record to `.git/skeeper/queue.json` with the failing namespace when one is known, appends to `.git/skeeper/sync.log`, prints a one-line note, and the hook exits 0. The next `skeeper sync` drains the queue before running a normal sync. Use `skeeper sync --pull` when a teammate pushed sidecar updates between your commits; it fetches and rebases before pushing.
|
|
217
225
|
|
|
218
226
|
This design has two consequences worth knowing:
|
|
219
227
|
|
|
@@ -229,17 +237,16 @@ This design has two consequences worth knowing:
|
|
|
229
237
|
skeeper init [flags]
|
|
230
238
|
```
|
|
231
239
|
|
|
232
|
-
| Flag | Default | Description
|
|
233
|
-
| ---------------- | --------- |
|
|
234
|
-
| `--sidecar` | | Existing sidecar repository URL
|
|
235
|
-
| `--sidecar-name` | | GitHub sidecar repository name or `OWNER/REPO`
|
|
236
|
-
| `--visibility` | `private` | GitHub visibility: `private`, `public`, or `internal`
|
|
237
|
-
| `--
|
|
238
|
-
| `--
|
|
239
|
-
| `--
|
|
240
|
-
| `--patterns` | | Spec glob pattern; repeat for multiple patterns |
|
|
240
|
+
| Flag | Default | Description |
|
|
241
|
+
| ---------------- | --------- | ------------------------------------------------------------ |
|
|
242
|
+
| `--sidecar` | | Existing sidecar repository URL |
|
|
243
|
+
| `--sidecar-name` | | GitHub sidecar repository name or `OWNER/REPO` |
|
|
244
|
+
| `--visibility` | `private` | GitHub visibility: `private`, `public`, or `internal` |
|
|
245
|
+
| `--namespace` | repo slug | Initial sidecar namespace for this source repo |
|
|
246
|
+
| `--bootstrap` | | Optional install command stored in `.skeeper.yml` |
|
|
247
|
+
| `--patterns` | | Complete spec glob pattern set; repeat for multiple patterns |
|
|
241
248
|
|
|
242
|
-
When run interactively, `init` opens a terminal form. It runs `gh repo create` for `--sidecar-name` or the create mode, but skips GitHub creation when `--sidecar` is provided. `--sidecar` and `--sidecar-name` are mutually exclusive
|
|
249
|
+
When run interactively, `init` opens a terminal form. It includes the default spec globs automatically, then asks whether to add extra context globs such as `AGENTS.md`, `CLAUDE.md`, or `.codex/plans/**`. It runs `gh repo create` for `--sidecar-name` or the create mode, but skips GitHub creation when `--sidecar` is provided. `--sidecar` and `--sidecar-name` are mutually exclusive.
|
|
243
250
|
|
|
244
251
|
</details>
|
|
245
252
|
|
|
@@ -261,10 +268,10 @@ Use after a fresh clone of the main repo. `hydrate` clones the sidecar into `.sk
|
|
|
261
268
|
skeeper sync [flags]
|
|
262
269
|
```
|
|
263
270
|
|
|
264
|
-
| Flag | Default | Description
|
|
265
|
-
| -------- | ------- |
|
|
266
|
-
| `--pull` | `false` | Pull and rebase the sidecar branch before syncing
|
|
267
|
-
| `--hook` | `false` | Run in post-commit hook mode: 750 ms foreground budget, always exits 0 |
|
|
271
|
+
| Flag | Default | Description |
|
|
272
|
+
| -------- | ------- | ------------------------------------------------------------------------------------ |
|
|
273
|
+
| `--pull` | `false` | Pull and rebase the sidecar branch before syncing |
|
|
274
|
+
| `--hook` | `false` | Run in post-commit hook mode: 750 ms foreground budget per namespace, always exits 0 |
|
|
268
275
|
|
|
269
276
|
Drains queued retries from `.git/skeeper/queue.json`, then mirrors spec files into `.skeeper/`, commits, and pushes. Use `--pull` when teammates may have pushed sidecar updates between your commits. `--hook` is what the installed post-commit hook calls — you rarely run it manually.
|
|
270
277
|
|
|
@@ -277,7 +284,7 @@ Drains queued retries from `.git/skeeper/queue.json`, then mirrors spec files in
|
|
|
277
284
|
skeeper status
|
|
278
285
|
```
|
|
279
286
|
|
|
280
|
-
Prints the sidecar URL, current source branch,
|
|
287
|
+
Prints the sidecar URL, current source branch, one status block per namespace, last sync commit and age, remote state, tracked file counts, and pending queued syncs. No flags.
|
|
281
288
|
|
|
282
289
|
</details>
|
|
283
290
|
|
|
@@ -288,7 +295,7 @@ Prints the sidecar URL, current source branch, directory namespace when configur
|
|
|
288
295
|
skeeper log <path>
|
|
289
296
|
```
|
|
290
297
|
|
|
291
|
-
Runs `git log` against the sidecar for one spec file. The path is relative to the main repo root, e.g. `skeeper log src/auth/SPEC.md`.
|
|
298
|
+
Runs `git log` against the sidecar for one spec file. The path is relative to the main repo root, e.g. `skeeper log src/auth/SPEC.md`. `skeeper` resolves the current owning namespace and reads `<namespace>/<path>` inside that namespace branch.
|
|
292
299
|
|
|
293
300
|
</details>
|
|
294
301
|
|
|
@@ -342,6 +349,10 @@ make release-snapshot # requires GoReleaser Pro in PATH, or GORELEASER_KEY for
|
|
|
342
349
|
|
|
343
350
|
Contributor guidance, commit conventions, and the agent skill dispatch protocol live in [`CLAUDE.md`](CLAUDE.md) and [`AGENTS.md`](AGENTS.md).
|
|
344
351
|
|
|
352
|
+
## 🤖 Official Agent Skill
|
|
353
|
+
|
|
354
|
+
`skeeper` ships its own first-party agent skill at [`skills/skeeper-project/SKILL.md`](skills/skeeper-project/SKILL.md). LLM agents working in this repository should load it before reading or modifying code — it captures the workflow, project rules, and verification gates that aren't obvious from the source alone, and points to `references/domain-map.md` and `references/repo-contract.md` for package boundaries and change rules.
|
|
355
|
+
|
|
345
356
|
## 🤝 Contributing
|
|
346
357
|
|
|
347
358
|
Contributions are welcome. Open an issue to discuss larger changes, or send a pull request for fixes and small improvements. All commits follow [Conventional Commits](https://www.conventionalcommits.org/) (`build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `test`), enforced by `commitlint`.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@compozy/skeeper",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"description": "Sidecar Git versioning for spec artifacts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"postinstall": "node install.js",
|
|
@@ -27,63 +27,63 @@
|
|
|
27
27
|
},
|
|
28
28
|
"archives": {
|
|
29
29
|
"darwin-arm64": {
|
|
30
|
-
"name": "skeeper_0.1.
|
|
31
|
-
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.
|
|
30
|
+
"name": "skeeper_0.1.1_darwin_arm64.tar.gz",
|
|
31
|
+
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.1/skeeper_0.1.1_darwin_arm64.tar.gz",
|
|
32
32
|
"bins": [
|
|
33
33
|
"skeeper"
|
|
34
34
|
],
|
|
35
35
|
"format": "tar.gz",
|
|
36
36
|
"checksum": {
|
|
37
37
|
"algorithm": "sha256",
|
|
38
|
-
"digest": "
|
|
38
|
+
"digest": "8b1f41d35c843099df08c3f43b503fc2163dd0ffb77846be14f3b997e0742d9c"
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"darwin-x64": {
|
|
42
|
-
"name": "skeeper_0.1.
|
|
43
|
-
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.
|
|
42
|
+
"name": "skeeper_0.1.1_darwin_x86_64.tar.gz",
|
|
43
|
+
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.1/skeeper_0.1.1_darwin_x86_64.tar.gz",
|
|
44
44
|
"bins": [
|
|
45
45
|
"skeeper"
|
|
46
46
|
],
|
|
47
47
|
"format": "tar.gz",
|
|
48
48
|
"checksum": {
|
|
49
49
|
"algorithm": "sha256",
|
|
50
|
-
"digest": "
|
|
50
|
+
"digest": "f8e895b2a2206b15041dfd796d6c2df23e24f84a6272dae030ae929b62165a5a"
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"linux-arm64": {
|
|
54
|
-
"name": "skeeper_0.1.
|
|
55
|
-
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.
|
|
54
|
+
"name": "skeeper_0.1.1_linux_arm64.tar.gz",
|
|
55
|
+
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.1/skeeper_0.1.1_linux_arm64.tar.gz",
|
|
56
56
|
"bins": [
|
|
57
57
|
"skeeper"
|
|
58
58
|
],
|
|
59
59
|
"format": "tar.gz",
|
|
60
60
|
"checksum": {
|
|
61
61
|
"algorithm": "sha256",
|
|
62
|
-
"digest": "
|
|
62
|
+
"digest": "711dbee658801c1c388d7c87d5b0ab1e39035c872266768d4ddef6edfa7e2912"
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"linux-x64": {
|
|
66
|
-
"name": "skeeper_0.1.
|
|
67
|
-
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.
|
|
66
|
+
"name": "skeeper_0.1.1_linux_x86_64.tar.gz",
|
|
67
|
+
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.1/skeeper_0.1.1_linux_x86_64.tar.gz",
|
|
68
68
|
"bins": [
|
|
69
69
|
"skeeper"
|
|
70
70
|
],
|
|
71
71
|
"format": "tar.gz",
|
|
72
72
|
"checksum": {
|
|
73
73
|
"algorithm": "sha256",
|
|
74
|
-
"digest": "
|
|
74
|
+
"digest": "76e72d20d8486e484b9789df69c19a327ad0307051554eaf7db078474a3cbbac"
|
|
75
75
|
}
|
|
76
76
|
},
|
|
77
77
|
"win32-x64": {
|
|
78
|
-
"name": "skeeper_0.1.
|
|
79
|
-
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.
|
|
78
|
+
"name": "skeeper_0.1.1_windows_x86_64.zip",
|
|
79
|
+
"url": "https://github.com/compozy/skeeper/releases/download/v0.1.1/skeeper_0.1.1_windows_x86_64.zip",
|
|
80
80
|
"bins": [
|
|
81
81
|
"skeeper.exe"
|
|
82
82
|
],
|
|
83
83
|
"format": "zip",
|
|
84
84
|
"checksum": {
|
|
85
85
|
"algorithm": "sha256",
|
|
86
|
-
"digest": "
|
|
86
|
+
"digest": "b445168f2811e1a2948f434cc03c91fbe2bff9c0ae1bd64677dfec393ed02559"
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|