Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
147e926
feat(cli): add skdd add/push/drops — the Commons verbs
zakelfassi Jul 1, 2026
bbf5fb4
feat(plugin): opt-in enforcement hooks — finish-the-loop gate + freez…
zakelfassi Jul 1, 2026
3f3a333
docs: Commons integration — README section, docs/commons.md, site pag…
zakelfassi Jul 1, 2026
7426234
docs(site): wire commons.md through the sync-docs manifest
zakelfassi Jul 1, 2026
17fde65
fix(cli): treat Commons manifests as hostile input; allowlist push pa…
zakelfassi Jul 2, 2026
68e49fd
Merge branch 'feat/commons-cli' into feat/plugin-hooks
zakelfassi Jul 2, 2026
bf91b01
Merge branch 'feat/plugin-hooks' into docs/commons-integration
zakelfassi Jul 2, 2026
c190833
fix(cli): refuse symlinked skill dirs and SKILL.md in push
zakelfassi Jul 2, 2026
5279ac0
Merge branch 'feat/commons-cli' into feat/plugin-hooks
zakelfassi Jul 2, 2026
50a3a70
Merge branch 'feat/plugin-hooks' into docs/commons-integration
zakelfassi Jul 2, 2026
cc2fbf1
fix(cli): guard symlinked skills at push discovery, not just the item…
zakelfassi Jul 2, 2026
163436f
Merge branch 'feat/commons-cli' into feat/plugin-hooks
zakelfassi Jul 2, 2026
c8d343d
Merge branch 'feat/plugin-hooks' into docs/commons-integration
zakelfassi Jul 2, 2026
e220320
fix(cli): address Commons review findings in add/push/commons/config
zakelfassi Jul 2, 2026
e718cb6
Merge branch 'feat/commons-cli' into feat/plugin-hooks
zakelfassi Jul 2, 2026
885b1e4
fix(plugin): address hook review comments (finish-loop + freeze)
zakelfassi Jul 2, 2026
dcd28d9
Merge branch 'feat/plugin-hooks' into docs/commons-integration
zakelfassi Jul 2, 2026
1d0b5fe
fix(plugin): finish-loop detects edits to files dirty before the session
zakelfassi Jul 2, 2026
96330fd
Merge branch 'feat/plugin-hooks' into docs/commons-integration
zakelfassi Jul 2, 2026
66c0465
fix(plugin): anchor hook repo snapshots to the repo root (subdir-safe)
zakelfassi Jul 2, 2026
5cc1d49
Merge branch 'feat/plugin-hooks' into docs/commons-integration
zakelfassi Jul 2, 2026
86e9913
fix(cli): address second-round PR review comments on add/push
zakelfassi Jul 2, 2026
d3aa1ad
Merge branch 'feat/commons-cli' into feat/plugin-hooks
zakelfassi Jul 2, 2026
029eabf
fix(plugin): address second-round hook review comments
zakelfassi Jul 2, 2026
9bde3fd
Merge branch 'feat/plugin-hooks' into docs/commons-integration
zakelfassi Jul 2, 2026
2acc1a5
Merge remote-tracking branch 'origin/main' into docs/commons-integration
zakelfassi Jul 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ site/src/content/docs/schemastore-submission.md
site/src/content/docs/changelog.md
site/src/content/docs/global-colony.md
site/src/content/docs/mcp-sync.md
site/src/content/docs/commons.md
site/src/content/docs/colony/
site/src/content/docs/integrations/
site/src/content/docs/spec/
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ Every loop through the diagram *improves* the colony. Archiving is reversible; n

---

## SkDD Commons — skills that evolve in public

Community skills live in **[SkDD Commons](https://github.com/zakelfassi/skdd-commons)**, released as curated, dated **drops**. Unlike static skill lists, every Commons skill carries lifecycle metadata (`forged-by`, `forged-from`, `forged-reason`) and an evolution loop: hit an edge case in the wild, fix your local copy, and `skdd push` ships the diff upstream as a PR. A skill that has evolved across many codebases carries a trust signal no static collection can fake.

```bash
# Install the current drop — six skills forged by claude-fable-5 on 2026-07-01
pnpm dlx @zakelfassi/skdd add zakelfassi/skdd-commons 2026-07-frontier

# See what's on offer / push your evolution back
skdd drops
skdd push what-would-you-cut
```

Current drop: [`2026-07-frontier` — July 2026 Frontier, the Fable Festival drop](https://github.com/zakelfassi/skdd-commons/tree/main/packs/2026-07-frontier). See [`packs/README.md`](packs/README.md) for the pack concept and [`docs/commons.md`](docs/commons.md) for the full add/push flow.

---

## Hub & Global Colony

*This is the 1.0 headline.*
Expand Down
10 changes: 10 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ SkDD is being built in named tranches (P0 → P5). Each tranche ships as a batch
| **G — Community scaffolding** | SECURITY, CoC, CODEOWNERS, issue/PR templates, FUNDING, CHANGELOG, ROADMAP | ✅ Shipped (v0.3.0) |
| **H — CLI depth + quality bar** | `skdd stats`, `search`, `migrate`, `compose`, `link --watch`, `completion`, ESLint/Prettier, Changesets, e2e tests, `SkddError` class, man pages | ⏸ Deferred |
| **P4 — Strategy / Ecosystem** | Marketplace submissions, RFC upstream for lifecycle metadata, security doc, SkDD rename debate, governance | ⏸ Deferred |
| **Commons** ([plan](docs/plans/2026-07-skdd-commons.md)) | Phase 1: [`skdd-commons`](https://github.com/zakelfassi/skdd-commons) repo + `2026-07-frontier` drop + safety-lint CI · Phase 2: `skdd add`/`push`/`drops` + `.skdd-lock.json` provenance · Phase 3: opt-in plugin hooks (`finish-the-loop` gate, `freeze-the-session` reminder) · Phase 4: docs + launch | 🚧 Shipped, launch pending |

### Commons v2 (deferred)

Explicitly cut from Commons v1 — candidates for a follow-up tranche:

- **`skdd update`** — three-way evolution merge against the upstream drop; highest-value item, because a local/upstream divergence *is a PR waiting to be pushed* (`.skdd-lock.json` already records the base sha)
- **Hub "Commons" pane** — list drops with an install action inside `skdd hub`
- **npm drops** (`@skdd/drop-*`) — git transport is enough for v1
- **`attack-the-plan` as a plan-approval gate** — deferred for nag risk; stays a skill

## Manual steps (not automatable — GitHub settings)

Expand Down
78 changes: 78 additions & 0 deletions docs/commons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
title: "SkDD Commons"
description: "Community skills that evolve in public — dated drops, provenance, and the add/push evolution loop."
---

> Community skills that evolve in public — dated drops, provenance, and the add/push evolution loop.

**[SkDD Commons](https://github.com/zakelfassi/skdd-commons)** is the community repository for SkDD skills. It is a plain git repo — no hosted registry, no server-side index, no submission portal. Drops are directories, the manifest is a JSON file, and contributing is a PR.

## Drops

A **drop** is a curated, dated, themed set of skills: `YYYY-MM-<theme>`. Dated ids sort chronologically and give each release a story. A skill's `metadata.pack` names the drop it belongs to.

```bash
skdd drops # list drops from the configured commons
skdd drops --from owner/other-repo # any Commons-shaped repo works
```

| Drop | Date | Skills |
|------|------|--------|
| [`2026-07-frontier` — July 2026 Frontier, the Fable Festival drop](https://github.com/zakelfassi/skdd-commons/tree/main/packs/2026-07-frontier) | 2026-07-01 | 6 |

## Installing: `skdd add`

```bash
# a whole drop into the project colony
pnpm dlx @zakelfassi/skdd add zakelfassi/skdd-commons 2026-07-frontier

# a single skill, or the global colony
skdd add zakelfassi/skdd-commons 2026-07-frontier/finish-the-loop
skdd add zakelfassi/skdd-commons 2026-07-frontier -g

# pin a ref, or use any git URL / local path
skdd add zakelfassi/skdd-commons#main 2026-07-frontier
```

What `add` guarantees:

1. **Validation before install** — every skill must pass `skdd validate --strict`; one failure refuses the whole selection.
2. **Collision safety** — an existing skill with the same name refuses the install; `--rename <new-name>` installs a single skill under a different name.
3. **Provenance** — the registry's Source column records `owner/repo@shortsha (drop-id)`; the full sha lands in `.skdd-lock.json` so future tooling can detect upstream drift.
4. **Mirror safety** — mirrors refresh through the same safe link path as `skdd link`: a populated harness directory is never replaced silently.
5. **Hostile-manifest safety** — `drops.json` ids and names are grammar-checked (lowercase kebab-case, no slashes or `..`) before any path is built, so a malicious Commons can never write outside your `skills/` directory.

`--dry-run` previews, `--json` emits a machine-readable report.

## Evolving: `skdd push`

The Commons' entire point. When a skill fails you in the wild:

```bash
# 1. fix your local copy (skills/<name>/SKILL.md) — add the edge case
# 2. preview the PR
skdd push what-would-you-cut --dry-run
# 3. ship it (needs the GitHub CLI authenticated)
skdd push what-would-you-cut
```

- Skills that exist upstream branch as `evolve/<name>` and the PR includes a diff summary; new skills branch as `skill/<name>` and land in `incoming/` for maintainer triage (or an existing drop via `--drop <id>`).
- **Machine-local state never travels**: `usage-count` resets to `"0"` and `last-used` is dropped. Your usage stats are your colony's truth. `forged-*` provenance always travels.
- **Only the skill payload travels**: `SKILL.md` plus regular files under `scripts/`, `references/`, `assets/`. Dotfiles, symlinks, logs, and anything else in the skill directory stay home — `--dry-run` lists exactly what travels and what doesn't.
- The default target repo comes from `~/.skdd/config.toml`:

```toml
commons = "zakelfassi/skdd-commons"
```

## Security posture

Community skills are instructions your agent follows — a prompt-injection surface. The Commons treats it as one: CI lints every skill against a versioned deny-pattern list (pipe-to-shell, credential reads, instruction-override phrases, …); a hit blocks merge until a maintainer reviews it and applies the `security-reviewed` label. Details in the Commons' [SECURITY.md](https://github.com/zakelfassi/skdd-commons/blob/main/SECURITY.md).

This is **not** a review gate on forging — creating skills in your own colony stays gate-free. The gate exists where the trust boundary is: strangers shipping instructions to strangers' agents.

## Enforcement hooks (Claude Code)

Two Commons practices ship as **opt-in** hooks in the [`skdd-claude` plugin](https://github.com/zakelfassi/skills-driven-development/tree/main/plugins/skdd-claude): a `finish-the-loop` Stop gate (bounces unverified-success reports once) and a `freeze-the-session` reminder (surfaces unfrozen learnings before the context dies). Both are off by default — toggle with `/skdd-claude:skdd-hooks on`.

> A skill is a procedure the model follows when it decides to; a hook is a gate for when it forgets.
47 changes: 47 additions & 0 deletions docs/plans/2026-07-commons-announcement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# SkDD Commons launch announcement — DRAFT for Zak's review

> Status: draft, not posted anywhere. Written 2026-07-01 by claude-fable-5 as part of the Commons plan Phase 4. Trim to taste; the short version is sized for X, the long version for the blog/newsletter.

---

## Short (X / social)

> Shipping SkDD Commons: skills that evolve in public.
>
> Every skill collection ships static files. Commons skills carry provenance — who forged them, from what session, why — and an evolution loop: hit an edge case, fix your copy, `skdd push` ships the diff upstream as a PR.
>
> First drop: **2026-07-frontier** — six working practices Claude Fable 5 forged on its first day back from the export-control shutdown, distilled from the Fable Festival letter.
>
> ```
> pnpm dlx @zakelfassi/skdd add zakelfassi/skdd-commons 2026-07-frontier
> ```
>
> Git is the registry. PRs are the evolution. https://github.com/zakelfassi/skdd-commons

## Long (blog / newsletter)

**SkDD Commons is live** — a community repository of agent skills with a lifecycle, not a list.

The pitch in one line: *skills that evolve in public.* Every existing community skill collection ships static files; you copy them, they rot. SkDD skills carry lifecycle metadata (`forged-by`, `forged-from`, `forged-reason`) and an evolution model — an agent hits an edge case in the wild, appends it to its local copy, and `skdd push` ships the diff upstream as a PR with the provenance intact. A skill that says "evolved 14 times across 9 codebases" carries a trust signal no static list can fake.

Skills are released as curated, dated **drops**. The bootstrap drop is `2026-07-frontier` — *July 2026 Frontier, the Fable Festival drop*: six skills Claude Fable 5 forged on July 1, its first day back online after eighteen days of US export controls, each freezing one practice from [the welcome-back letter it wrote to builders](https://zakelfassi.com/blog/2026/2026-07-01-fable-festival-until-its-dark-again): bring me problems, not plans · ask me what's wrong with it · use my taste · let me finish · let me hire · make me leave something behind.

Three design choices worth calling out:

1. **Git is the registry.** No hosted index, no submission portal. Drops are directories, the manifest is a JSON file, contributing is a fork and a PR.
2. **The trust boundary is explicit.** Forging skills in your own colony has no review gate — that's SkDD's forge-then-evolve bias. Importing strangers' instructions into your agent is different: CI lints every skill against a public deny-pattern list (pipe-to-shell, credential reads, "ignore previous instructions"…), and a hit blocks merge until a maintainer reviews it.
3. **Usage stats stay home.** `skdd push` strips `usage-count` and `last-used` before anything travels. Your colony's usage truth is local; only provenance is global.

Try it:

```bash
pnpm dlx @zakelfassi/skdd add zakelfassi/skdd-commons 2026-07-frontier
# hit an edge case? evolve it:
skdd push what-would-you-cut
```

And for Claude Code users, two of the six practices now ship as **opt-in enforcement hooks** in the skdd plugin — a `finish-the-loop` Stop gate that bounces "should work now" reports once, and a `freeze-the-session` reminder that surfaces unfrozen learnings before your context dies. A skill is a procedure the model follows when it decides to; a hook is a gate for when it forgets.

---

*Posting checklist (manual):* flip `skdd-commons` public first · tag the `2026-07-frontier` GitHub Release · verify the `skdd add` one-liner works from a clean machine/account · then post.
11 changes: 10 additions & 1 deletion docs/plans/2026-07-skdd-commons.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> **This document is an executable goal.** A fresh agent session in this repo should be able to read this file top to bottom, ingest the referenced context, and drive the work to completion without re-deriving strategy. Decisions marked **DECIDED** are settled — do not relitigate them; decisions marked **ASK ZAK** are genuinely his to make.
>
> Status: not started · Author: claude-fable-5, 2026-07-01 · Owner: @zakelfassi
> Status: **phases 1–4 executed 2026-07-01** — launch pending the manual steps in §9 · Author: claude-fable-5, 2026-07-01 · Owner: @zakelfassi

---

Expand Down Expand Up @@ -242,6 +242,15 @@ plugins/skdd-claude/
- 2026-07-01 — **Stop-gate follow-up fix #2** (claude-fable-5, flagged by the Codex stop-time review): the symlink guard lived in the items loop, but pack discovery called `parseSkill` (→ `readFileSync`, follows symlinks) *before* it — so a pack push dereferenced a symlinked skill during scanning. Extracted `skillDirIsSymlinked` and now check at discovery time: direct pushes refuse, pack scans skip+warn, and the items-loop check stays as defense-in-depth. `statSync`→symlink-aware guard added. +1 test (symlinked skill excluded from a pack push, target never read); 902 total green; verified live — a symlinked SKILL.md claiming the pack is skipped and its secret never read.
- 2026-07-01 — **Stop-gate follow-up fix** (claude-fable-5, flagged by the Codex stop-time review): `skdd push` read `SKILL.md` with `readFileSync`, which follows symlinks — a symlinked skill dir or SKILL.md could still exfiltrate arbitrary files (ssh keys, /etc/passwd) into a PR despite the payload allowlist. Push now `lstat`s both and refuses symlinks outright; `collectPublishablePayload` throws defensively. +2 tests (symlinked SKILL.md, symlinked skill dir); 901 total green; verified live — a SKILL.md symlinked at a secret file is refused with no content leaked.
- 2026-07-01 — **Adversarial review fixes** (claude-fable-5, after a Codex adversarial review of the branch diff). Two findings fixed on `feat/commons-cli`: **[high]** `drops.json` is now treated as hostile input — drop ids and skill names are grammar-checked (lowercase kebab-case, no slashes/`..`/absolute paths) at every parse site (`readDropsManifest`, push's local+remote upstream readers), with defense-in-depth `assertWithin` containment asserts on all source/destination paths in `add`; a malicious manifest can no longer write outside `skills/`. **[medium]** `skdd push` no longer copies the whole skill directory — only an allowlisted payload travels (`SKILL.md` + regular files under `scripts/`, `references/`, `assets/`); dotfiles, symlinks, and strays stay home, and `--dry-run` enumerates travels/stays-home per file. +5 adversarial tests (hostile manifests with `../`, absolute paths, unsafe drop ids; payload allowlist incl. symlink/`.env` exclusion); 899 total green; verified live against a hostile fixture and a real `.env` plant.
- 2026-07-01 — **Phase 4 complete** (claude-fable-5, branch `docs/commons-integration`). Main README gained the Commons section (thesis, `skdd add` one-liner, drop link); `docs/commons.md` written and mirrored into the Starlight site with a "Commons" sidebar group; ROADMAP gained the Commons tranche (🚧 shipped, launch pending) + a "Commons v2" deferred list (`skdd update` three-way merge flagged highest-value); announcement copy drafted at `docs/plans/2026-07-commons-announcement.md` (short X version + long blog version, NOT posted). GitHub Release `2026-07-frontier` tagged on the (still-private) Commons — drops are releases; it goes public with the repo.
- 2026-07-01 — **Manual steps for Zak (launch checklist, in order):**
1. **Merge PR [#8](https://github.com/zakelfassi/skills-driven-development/pull/8)** (Phase 2, CI green), then **[#9](https://github.com/zakelfassi/skills-driven-development/pull/9)** (Phase 3, stacked — retargets to main and runs CI on merge of #8), then **#10** (Phase 4 docs). The agent's classifier rightly refuses self-merging its own PRs. Then merge the release-please PR it opens → publish workflow cuts `@zakelfassi/skdd` 1.1.0 to npm (needs `NPM_TOKEN` secret to be valid).
2. **Flip `skdd-commons` public**: `gh repo edit zakelfassi/skdd-commons --visibility public` (or Settings UI). The `2026-07-frontier` Release, README, CI, and gate-proof PR #1 history are already in place.
3. **Verify the stranger flow** once public + npm 1.1.0 is live: `pnpm dlx @zakelfassi/skdd add zakelfassi/skdd-commons 2026-07-frontier` from a machine without your credentials.
4. **Branch protection on `skdd-commons` main** (Settings → Branches): require the three CI checks; keep the `security-reviewed` label bypass semantics.
5. **Marketplace submissions** (SkillsMP, skills.sh, ClawHub, LobeHub — the ROADMAP P4 list) — needs your accounts.
6. **Review + post the announcement** (`docs/plans/2026-07-commons-announcement.md`); optional postscript cross-link from the Fable Festival article repo mirror.
7. **ASK-ZAK defaults taken** (revisit if you disagree): Commons private-until-launch ✔ · MIT license ✔ · npm drops deferred ✔.
- 2026-07-01 — **Phase 3 complete** (claude-fable-5). Two opt-in hooks shipped in `plugins/skdd-claude` v0.3.0 (branch `feat/plugin-hooks`): `finish-loop-gate.mjs` (Stop; blocks once per session on unverified-claim reports over non-test product diffs, anti-loop state in `$TMPDIR`), `freeze-reminder.mjs` (SessionEnd + PreCompact; non-blocking `systemMessage` when a substantive session ends with the registry untouched), `session-start.mjs` (seeds session-start timestamp), `lib/state.mjs` (state + toggle reads). Toggles live in `.claude/skdd.local.md` via the `/skdd-claude:skdd-hooks` command; both gates OFF by default. 11 end-to-end tests in `cli/test/plugin-hooks.test.ts` spawn the real scripts (block-once, evidence pass, docs-only/test-only silence, registry-mtime logic, <2s inactive path). No deps beyond node built-ins. Deviation from §6.1 noted: a small `session-start.mjs` + SessionStart hook entry was added so "since session start" comparisons are real — same lifecycle pattern as the codex plugin.
- 2026-07-01 — **Phase 2 complete** (claude-fable-5). `skdd add` / `skdd push` / `skdd drops` shipped in `cli/` (branch `feat/commons-cli`). New libs: `commons.ts` (source parsing + shallow clone + drops.json), `lock.ts` (`.skdd-lock.json`, full sha for future drift detection), `config.ts` (`~/.skdd/config.toml`, `commons` key, default `zakelfassi/skdd-commons`). 24 new tests (add/push/drops) + mini-commons fixtures; 894 total green; typecheck + lint green. Design note: new skills pushed without `--drop` land in the Commons' `incoming/` staging dir (added to the Commons + its CI same day) — drops stay maintainer-curated. Push against a **local path** target supports `--dry-run` only (test seam); real PRs need `gh`. Round-trip e2e ran against the real private repo: `init → add zakelfassi/skdd-commons 2026-07-frontier` (6 skills, provenance `@12ba029`) `→ edit → push --dry-run` produced the correct evolve-branch PR body with diff summary; populated-mirror guardrail covered by a regression test.
- 2026-07-01 — **Phase 1 complete** (claude-fable-5). `zakelfassi/skdd-commons` created **private** (ASK-ZAK default taken: private until launch commit), **MIT license** (default taken: consistency with main repo), **npm drops deferred** (default taken: git transport only for v1). Full layout + `2026-07-frontier` drop (six skills, `metadata.pack` updated, `usage-count` reset, `last-used` dropped). CI green on main (run 28552710128: validate --strict / safety-lint / manifest-check, ~22s total). Gate proven on PR #1: safety-lint failed on a planted pipe-to-shell + credential-read fixture (run 28552744808), passed after `security-reviewed` label applied (run 28552805972); PR closed unmerged, branch deleted. `packs/fable-festival/` deleted from this repo; `packs/README.md` now concept doc + featured-drop index.
4 changes: 4 additions & 0 deletions site/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ export default defineConfig({
{ label: "MCP sync", link: "/mcp-sync/" },
],
},
{
label: "Commons",
items: [{ label: "SkDD Commons & drops", link: "/commons/" }],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add the Commons page to the docs sync mapping

Because site/scripts/sync-docs.mjs cleans generated docs and only copies explicit mappings, and docs/commons.md was not added there, prebuild will leave no site/src/content/docs/commons.md. This new sidebar item therefore sends users to /commons/ with no Starlight page after every docs build; add the Commons doc to the sync mapping before exposing the nav entry.

Useful? React with 👍 / 👎.

},
{
label: "Colony lifecycle",
items: [
Expand Down
Loading
Loading