Skip to content

Publish a lifecycle and compatibility policy, checked in CI - #134

Merged
richardmhope merged 2 commits into
mainfrom
claude/codebase-review-o7y3i9
Sep 25, 2026
Merged

richardmhope merged 2 commits into
mainfrom
claude/codebase-review-o7y3i9

Conversation

@richardmhope

Copy link
Copy Markdown
Collaborator

What & why

Adds docs/lifecycle.md, one contract for how skilldeck changes. It covers:

  • what package and skill version bumps mean, before and after 1.0:
    • a patch release only fixes things;
    • while a skill is 0.x, a breaking change bumps its minor version;
  • the deprecate → notice → remove path for skills, agents and formats:
    • a release tag must ship the deprecation at least 90 days before the removal (180 days from 1.0);
    • both periods are marked as maintainer policy choices;
    • a rename is a new skill plus a deprecation of the old one;
  • what status, update and uninstall actually do with installed copies of a removed skill, or of a skill that dropped an agent;
  • how meta.yaml, the catalog, install stamps and future lockfiles (Add organization bundles and reproducible skill lockfiles #71) may change;
  • which output is a stable contract;
  • the urgent security-fix path, with a 7-day release target that SECURITY.md now also states.

A new scripts/check_lifecycle.py runs in the lint job with --base origin/<target>. It requires CHANGELOG notes, in sections the PR adds and naming things in backticks, for:

  • removed skills. The skill must be deprecated at the base, and a reachable release tag's own meta.yaml and CHANGELOG must have shipped the deprecation at least the notice period earlier. The only exception is a Removed bullet marked **Security:** together with a Security entry naming the skill;
  • new deprecations;
  • agents dropped from a skill;
  • removed adapters;
  • new major skill versions;
  • catalog schema_version bumps.

It also rejects a patch release that removes, deprecates or breaks anything, and prepare_release.py applies the same rule before writing any file. Until the first release is tagged, the check prints a note that the notice-period rules are skipped.

This PR also puts back the ### Added heading that #53 dropped from [Unreleased]. Eleven Added bullets had ended up under ### Security, which would have exempted four skills from the deprecation rules. It also moves the internal get_skill bullet from Removed to Changed, since ### Removed is now reserved for removals from the public surface.

No new metadata field is needed: the notice period is measured from release tags.

Tests:

  • walk through a skill rename, an agent removal and a stamp-format migration;
  • pin the current stamp format;
  • check that the catalog can represent every lifecycle state;
  • keep the independent review's probes as regression tests: retrofitted or back-dated deprecations, a published section reused as a note, a Security mention used as an exemption, and adapter-removal matching.

Closes #78

Tracking: #94

Type of change

  • Bug fix
  • New feature
  • New or updated skill
  • Docs only
  • Refactor / internal

Checklist

  • Ran uv run --extra dev ruff check . && uv run --extra dev ruff format --check . && uv run --extra dev mypy && uv run --extra dev pytest (958 passed, also with -W error::EncodingWarning and --resolution lowest-direct)
  • Added or updated tests
  • Updated docs where relevant
  • Added a CHANGELOG.md entry under ## [Unreleased]
  • For a skill change: bumped that skill's version in meta.yaml (no skill content changed)

🤖 Generated with Claude Code

https://claude.ai/code/session_01HtiCGzpikMrkDYBkfQG5CX


Generated by Claude Code

docs/lifecycle.md is the contract for change. It covers:
- package SemVer before and after 1.0 (a patch release never removes,
  deprecates or breaks anything);
- skill SemVer with no 0.x exception, and how it meets status/update;
- the deprecate -> notice -> remove path for skills, agents and formats
  (published in a tagged release at least 90 days before removal, 180
  from 1.0), renames, and what happens to installed copies;
- metadata, catalog, stamp-format and future lockfile evolution;
- stable vs human CLI output, and the urgent security path.

scripts/check_lifecycle.py, run by the lint job with --base, requires
CHANGELOG notes, named in backticks, when compatibility changes:
- a removed skill needs a Removed entry, a deprecation at the base and a
  published, old-enough Deprecated entry (a Security entry skips the
  last two);
- a new deprecation needs a Deprecated entry;
- an agent dropped from a skill, or a removed adapter, needs a Removed
  entry;
- a major skill version needs a Changed entry giving the version;
- a catalog schema_version change needs a Breaking entry.
It also rejects a patch release with removals, deprecations or breaking
entries. prepare_release.py now applies that rule before writing
anything.

Tests walk through a skill rename, an agent removal and a simulated
stamp-format migration, pin the v1 stamp byte for byte, and show that
the catalog represents every lifecycle state. No new metadata field:
the notice clock comes from the CHANGELOG and release tags.

Closes #78

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtiCGzpikMrkDYBkfQG5CX
CHANGELOG: restore the Added bullets that #53 left under Security in
[Unreleased], and file the internal get_skill removal under Changed, so
Removed means public-surface removals only.

check_lifecycle.py:
- the urgent security path now needs a Removed entry marked
  **Security:** plus a Security entry naming the skill; a passing
  mention no longer exempts a removal;
- only sections the PR adds count: [Unreleased], or a dated section the
  base's CHANGELOG lacks; a published section no longer does;
- the notice period comes from release tags reachable from the base:
  the tag's own meta.yaml and CHANGELOG must deprecate the skill, counted
  from the later of the section date and the tag date, so it can't be
  retrofitted or back-dated;
- an adapter removal needs a Removed entry of its own naming no skill;
- with no release tags it prints a note and skips the notice rules;
- an impossible CHANGELOG date is a clean error, here and in
  prepare_release.py.

Policy:
- skills keep SemVer's 0.x exception;
- new features ship in minor releases;
- the 90/180-day notice periods and the 7-day security target are
  marked as maintainer choices, and SECURITY.md states the target;
- eval run records follow their own schema_version;
- the lockfile section is trimmed to rules.

Tests reuse the reviewer's probes A-E and G as regressions. The catalog
schema validator moves to tests/_schema.py.

Closes #78

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtiCGzpikMrkDYBkfQG5CX
@richardmhope
richardmhope merged commit dfea760 into main Sep 25, 2026
17 checks passed
@richardmhope
richardmhope deleted the claude/codebase-review-o7y3i9 branch September 25, 2026 03:32
richardmhope added a commit that referenced this pull request Sep 25, 2026
* Define and enforce a skill capability manifest

Every skill's meta.yaml now carries a required, versioned `capabilities`
block (schema 1): files read (none/diff/repo) and edited (none/repo),
commands it may run, network use and why, credentials, agent tools, and
files it may create. Anything undeclared is not requested; the declaration
is for review, not enforcement.

- skilldeck.capabilities validates the block (unknown or missing keys,
  other schema numbers, commands given as paths or with shell operators,
  artifact paths that are absolute, name a drive or home, use backslashes
  or have ./.. components).
- The registry enforces the bundle rules: exactly regular meta.yaml and
  skill.md, rejecting symlinks (including a symlinked skill directory),
  subdirectories, undeclared executables (script suffix, execute bit,
  #!, binary headers) and any other file, plus skill.md links to files the
  skill cannot ship. provenance --verify and catalog apply the same rules.
- Every adapter appends a "Declared capabilities" section to a skill that
  asks for more than reading files; the adapter contract skill declares its
  `git diff`, so the fixtures pin that section (contract sha256:d8b7d4463e84).
- `skilldeck show <skill> --summary` and `skilldeck install --dry-run`
  preview a skill's source, build, digest check, deprecation and declared
  capabilities; the dry run also reports what installing would do and
  writes nothing.
- `skilldeck catalog --json` reports `capabilities` (additive; schema_version
  stays 1).
- All 13 bundled skills declare what their instructions ask for, with patch
  version bumps; plugin tree and content manifests regenerated.

Closes #73

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtiCGzpikMrkDYBkfQG5CX

* Address review of the capability manifest (#73)

- Render the "Declared capabilities" notice only for skills that ask for
  more than a read-only review (an edit, a credential, an agent tool, an
  artifact, or a command beyond read-only git); the ten read-only review
  skills install byte-for-byte as before. Reword the notice for the agent
  ("Beyond reading the repository, this skill asks you to: ... It asks for
  nothing else.") and rename Capabilities.beyond_reading to
  beyond_review_baseline. The contract skill now declares
  <the project's test command>, so the fixtures still pin the notice
  (contract sha256:7c21e0856472).
- Loading ignores OS and editor leftovers (.DS_Store, Thumbs.db,
  desktop.ini, __pycache__, ._*, .#*, *~, #*#, Vim swap files) so one stray
  file no longer breaks every command; provenance --verify and catalog
  still report them as unexpected files, with main's wording. .DS_Store is
  gitignored.
- install --dry-run checks the nearest existing folder on the way to each
  destination and reports the error a real install would hit.
- test-review runs a regression test against pre-change code only in a
  temporary git worktree (declared); dependency-review runs pip-audit only
  as `pip-audit --disable-pip` on fully pinned files, per pip-audit's
  security model, and declares reading package registry pages.
- The link check matches src/href only inside HTML tags, skips indented
  code blocks, and checks autolinks.
- The structure test knows common CLIs, so a new undeclared scanner, curl
  or test run is caught; spans a skill only quotes are listed per skill.
- Declared commands reject interpreters given a script or inline code;
  Windows junctions count as links; the catalog docs say a new capability
  schema is a breaking catalog change; summary wording points to
  provenance --verify and docs/verifying-releases.md.

Part of #73

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtiCGzpikMrkDYBkfQG5CX

* Version the capability changes under the lifecycle policy (#73)

docs/lifecycle.md (#134) defines skill SemVer and what is breaking for skill
authors; apply it to this branch:

- dependency-review goes to 0.5.0, a minor bump: running pip-audit only on
  fully pinned files and adding registry-page lookups changes how it gathers
  evidence, which can change what it reports. test-review stays at 0.3.1, a
  patch: the temporary-worktree step only spells out a safe way to do what
  it already asked, and what it reports is unchanged. Both CHANGELOG entries
  say why.
- Requiring `capabilities` and limiting a skill directory to meta.yaml and
  skill.md tightens rules existing metadata could fail, which the policy
  calls breaking for skill authors: add a **Breaking:** Changed entry.
- docs/lifecycle.md's meta.yaml section mentions `capabilities`: its own
  schema number, and how a declaration change versions a skill.

Part of #73

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtiCGzpikMrkDYBkfQG5CX

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish a deprecation and compatibility lifecycle policy

2 participants