kramme-cc-workflow/skills/kramme:code:deprecate/SKILL.md
Plan and execute deprecation of code, features, APIs, or modules, treating code as a liability. Covers the decision to deprecate (5-question checklist), Hyrum's Law risk assessment, Advisory vs Compulsory deprecation paths, Strangler / Adapter / Feature-Flag migration patterns, and a four-step workflow: build replacement → announce → migrate incrementally → remove old. Emits SIMPLICITY CHECK, NOTICED BUT NOT TOUCHING, UNVERIFIED, and ASK FIRST markers. Use when removing legacy systems, sunsetting features, retiring API versions, or cleaning up zombie code with unknown owners.
npx skillsauth add abildtoft/kramme-cc-workflow kramme:code:deprecateInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Plan and execute the removal of code, features, APIs, or modules. Removing code safely requires the same rigor as adding it: the same risk assessment, the same phased rollout, the same verification gates. A skill that is missing here turns into deprecate and abandon — a notice goes up, nobody migrates, and the old path accretes users while labeled "dead".
kramme:code:migrate — when a framework migration finishes, the old framework's entry points need a deprecation workflow.kramme:code:refactor-pass.Before Step 1, classify what kind of surface is being deprecated. The dependent audit, announcement path, and completion gates depend on this choice.
Use the strongest evidence that matches the surface. Do not require runtime telemetry for compile-time-only removals, and do not accept compile-time-only evidence for public or runtime surfaces.
"With a sufficient number of users of an API, all observable behaviors of your system will be depended on by somebody, regardless of what you promise in the contract."
Implication for removal: every observable behavior is part of the contract — including bugs, timing quirks, field ordering, log line formats, and undocumented side effects. Callers may depend on any of them. Plan the removal as if every incidental detail is load-bearing, because some of them are.
This changes the default question from "does anything still call this?" to "what behavior might callers still depend on, even if nobody explicitly imports this function?" The dependent audit in Step 1 answers the first question; the replacement-coverage check in Step 4 answers the second.
"If you own the infrastructure being deprecated, you are responsible for migrating your users — or providing backward-compatible updates that require no migration."
Ownership means the migration is your work, not theirs. "We announced deprecation six months ago" is not coverage for a removal if callers still exist — the announcement did not migrate anyone. Either migrate them, ship a backward-compatible shim that makes migration invisible, or do not remove.
This rule forbids deprecate and abandon. It is the reason this skill has a four-step workflow instead of a one-step "put a notice and delete later".
Four markers anchor this skill's output. Emit them inline during the steps below.
SIMPLICITY CHECK: <the smallest coherent removal that reaches the goal>
State the smallest unit of removal before planning phases. A deprecation that tries to remove three related-but-separable things in one pass compounds risk. If "deprecate the old billing module" can be split into "remove read path" and "remove write path", split.
NOTICED BUT NOT TOUCHING: <what you saw>
Why skipping: <out-of-scope / unrelated / deferred>
Use during Step 1's dependent audit when grep turns up adjacent code that also looks dead. Log it as a candidate for a follow-up deprecation — do not silently fold it into the current workflow. Silent scope creep makes rollback harder and reviews worse.
UNVERIFIED: <assumption that has no source>
Flag anything you accepted without checking: "no one imports this module anymore" (did you check the build graph, tests, and config?), "no one uses this endpoint" (did you read access logs?), "this flag is off in production" (did you query the flag service?), "the documented contract covers all observables" (Hyrum's Law says no). Verifying that something is dead is the removal's whole purpose.
ASK FIRST: <which boundary you're about to cross>
Plan: <what you intend to do>
Use before: deprecating a public API, removing an externally-consumed endpoint, deprecating code whose owner is unknown (see zombie-code gate below), or compressing the announcement window on a Compulsory deprecation.
Create or update DEPRECATION_PLAN_<slug>.md in the repository root before Step 1 finishes, where <slug> is derived from the deprecation target (symbol / feature / API name) normalized as:
-- trimmedExamples: Billing v1 API → billing-v1-api, LegacyAuthAdapter → legacyauthadapter. Reject the input and abort if the slug is empty after normalization. Per-target naming keeps concurrent deprecations from colliding on one plan file.
This is the working artifact for the deprecation workflow; after the deprecation closes, delete it or archive the final decision in durable project docs.
Minimum template:
# Deprecation Plan: <symbol / feature / API>
Owner: <team or person>
Surface: <Compile-time / internal-only | Runtime / internal | External / public>
Classification: <Advisory | Compulsory | TBD>
Replacement: <new surface>
Migration pattern: <Strangler | Adapter | Feature Flag Migration>
Target removal date: <YYYY-MM-DD or TBD>
Current step: <Step 1 | Step 2 | Step 3 | Step 4.1 | Step 4.2 | Step 4.3 | Step 4.4 | Complete>
## Call Sites
- <known dependent or audit source, with evidence checked>
## Migration Log
- <date>: <slice migrated / verification result>
## Decisions
- <checklist answer, exception, or ASK FIRST outcome>
## Open Markers
- UNVERIFIED: <assumption still needing proof, owner, and clearance evidence>
- ASK FIRST: <boundary surfaced, confirmer, and date>
- NOTICED BUT NOT TOUCHING: <follow-up candidate and why it stays out of scope>
## Step Status
- [ ] Step 1 decision checklist answered and recorded.
- [ ] Step 2 classification recorded.
- [ ] Zombie-code gate cleared or escalated to owner.
- [ ] Step 3 migration pattern recorded.
- [ ] Step 4.1 replacement built and verified.
- [ ] Step 4.2 announcement and migration guide published.
- [ ] Step 4.3 active callers migrated to zero.
- [ ] Step 4.4 old code, tests, docs, and notices removed together.
## Completion Gates
- [ ] No references remain in code, tests, docs, or config.
- [ ] Deprecation notices and migration guide removed or archived with a date.
- [ ] Dependent audit confirms zero active consumers with surface-appropriate evidence.
- [ ] Observation window elapsed without incident.
On re-invocation, list all DEPRECATION_PLAN_*.md files in the repository root first. If exactly one matches the current target's slug, read it; if several plans exist and the target is ambiguous, list them and ask the user which deprecation to resume. Then use ## Step Status, ## Open Markers, and ## Completion Gates to find the earliest incomplete exit criterion across Step 1 through Step 4.4 and the overall completion gates, then resume there. If an existing plan lacks a status field for a required gate, treat that gate as incomplete until the evidence is recorded. Do not jump straight to removal because a previous session announced the deprecation.
Answer the five-question checklist. Extended signals and a decision tree live in references/decision-checklist.md.
UNVERIFIED only when a required evidence source for that surface has not been checked.kramme:code:migrate pattern (Strangler / Adapter / Feature Flag).Emit SIMPLICITY CHECK: <smallest coherent removal> once the answers are in.
Record the five answers in DEPRECATION_PLAN_<slug>.md under ## Decisions.
Every deprecation is one of:
Compulsory deprecations trigger ASK FIRST if the announcement window is under 30 days or the affected surface is a public API.
Ambiguous cases default to Advisory — then reclassify if a specific forcing function surfaces (new CVE, vendor EOL notice).
If Step 1 question 2 returns "nobody appears to own this" but other code still depends on it, you have zombie code. This is a deprecation-blocking state, not a risk to proceed with.
Do not remove zombie code. Do not proceed past this step. Instead:
ASK FIRST: zombie code with no owner and wait for confirmation before any further step.The reason: zombie code is often load-bearing in non-obvious ways (the original author knew something the callers don't, and the knowledge is lost). Removing it speculatively violates Hyrum's Law at industrial scale.
Pick one named pattern and record it in DEPRECATION_PLAN_<slug>.md's header. Short descriptions inline; full examples + phasing guidance in references/migration-patterns.md.
Default: Feature Flag for runtime-risky deprecations; Strangler for long-lived legacy systems; Adapter when a codemod can mechanically port callers.
Execute in order. Do not compress or overlap — each step has distinct exit criteria.
Ship the replacement first. The replacement must cover the documented contract and the observable behaviors Hyrum's Law says callers may depend on: field ordering, error messages, timing characteristics, edge-case inputs, the exact shape of logs that ops depends on. Map each observable to either "replacement covers it" or "replacement intentionally changes it — communicated in Step 4.2".
Exit criterion: the replacement is merged and verified. For runtime or public surfaces it is also deployed and monitored; for compile-time / internal-only surfaces it is exercised by the CI/build/test flows that cover dependents. In both cases, a contract test or characterization test asserts feature parity for every observable on the map.
Publish: the deprecation notice, the timeline, the migration guide or upgrade note, and the rollback path. Surfaces depend on the audience:
@deprecated, Python DeprecationWarning, etc.), CHANGELOG or migration note, and any package-level upgrade docs callers rely on.Deprecation: true, Sunset: <date>), versioned documentation.When the Step 3 pattern is Feature Flag, the flag service itself acts as a per-cohort announcement channel in addition to the surface-appropriate notices above — see references/migration-patterns.md.
Exit criterion: every dependent surface for the chosen surface type has received the announcement or upgrade note it actually uses, and the migration guide has been rehearsal-validated against at least one representative caller when caller migration is required before rollout begins.
Apply the Step 3 pattern. Migrate callers in slices — by team, by cohort, by path — with verification between slices. The Churn Rule says you own this migration: if callers are not migrating, you do the migrations yourself (codemods, PRs against consuming services, batch-updates).
The first migrated slice is the guide's real-world validation. If the guide is wrong or incomplete, fix it before moving to the next slice.
Every migrated slice must pass the same verification gate as the replacement: observable parity, no regression in test suite, and no new regression signal in the verification surface that applies (CI/build/test for compile-time internal code, telemetry for runtime/public surfaces).
Exit criterion: zero active callers of the old path. "Active" means references still present in the import/build/test/config graph for compile-time / internal-only surfaces, or runtime callers / published consumer surfaces still pointing at the old path within the rollback window for runtime or public surfaces.
Remove together: the old code, its tests, its docs, and the deprecation notices. Leaving any one behind is a rollback trap — deprecation notices on code that no longer exists confuse future readers; tests of removed code waste CI.
Before executing this step, resolve every open UNVERIFIED from any step. If any is still open, emit ASK FIRST: removing with open UNVERIFIED markers and do not proceed.
Exit criterion: the four overall-completion gates in the next section are all true.
The deprecation is not done until all four are true:
The observation window depends on surface + classification: compile-time / internal-only deprecations hold through at least one green CI cycle and, if the artifact is published outside the repo, one release-candidate or consumer-update window. Runtime Advisory deprecations hold for a release cycle after Step 4.3 completion; runtime or public Compulsory deprecations hold for at least one on-call rotation to catch pages.
kramme:code:migrate — the migration-toward-new side. When a framework or library migration completes, the old framework's call sites are deprecation candidates. kramme:code:migrate may cover Step 4.1 and parts of Step 4.3, but it does not replace Step 4.2's announcement path or the surface-appropriate observation-window / zero-active-caller checks in this skill. Before Step 4.4, verify those gates are satisfied and recorded; if they are not, continue from the earliest incomplete deprecation step instead of jumping straight to removal.kramme:code:api-design — for deprecating public API surfaces, the replacement's contract design belongs there. Hyrum's Law also appears in that skill because it governs both sides of the API lifecycle; each skill inlines its own copy.kramme:code:refactor-opportunities — discovery mechanism. A scan that reports "dead code / unused exports" produces deprecation candidates for this skill to evaluate. Do not remove directly from a refactor report; pass each candidate through Step 1 first.kramme:verify:run — verification gate between slices in Step 4.3 and after Step 4.4.Each of these is a version of "skip the checklist". Correct response follows.
| Rationalization | Reality |
| --- | --- |
| "Nobody uses it anymore." | UNVERIFIED until the dependent audit runs against the evidence required for the chosen surface. For compile-time / internal-only code that usually means import/build/test/config references; for runtime or public surfaces it includes telemetry. "I grepped and didn't see callers" still misses dynamic imports, reflection, and external API callers. |
| "It's tiny, leaving it is fine." | Code is a liability — tests, docs, patches, and mental overhead scale with surface, not lines. The "tiny" framing is usually wrong once the maintenance cost question (Step 1, question 5) is answered. |
| "We'll delete it after the next release." | This is the deprecate-and-abandon failure mode. The Churn Rule says migration is your work; "after the next release" without a migration plan means the deprecation never completes. |
| "The announcement was six months ago." | Announcement is not migration. If callers still exist, either migrate them now or reclassify the deprecation as Advisory and extend the window. |
| "We can skip the replacement — it's just a delete." | Then the decision is "delete the feature", not "deprecate". Different workflow, different announcement, different stakeholder set. |
| "It's internal-only, we don't need a migration guide." | Internal callers rely on documented migration paths too. Internal scope changes the surface, not the obligation. |
| "The old tests still pass, so the replacement is fine." | Old tests assert old behavior. The replacement needs characterization tests that capture the observables Hyrum's Law says callers depend on. |
If you see any of these, stop and re-author:
ASK FIRST.Before declaring the deprecation complete, self-check:
DEPRECATION_PLAN_<slug>.md.DEPRECATION_PLAN_<slug>.md.UNVERIFIED marker resolved; every NOTICED BUT NOT TOUCHING logged; every ASK FIRST confirmed.If any box is unchecked, the deprecation is not done. Fix the gap or split it into a tracked follow-up before closing the workflow.
development
Runs kramme:pr:code-review as a closeout review loop for local or PR branch changes before commit, ship, or final response. Use when the user asks for autoreview, second-model review, or a final code-review pass after non-trivial edits. Not for UX, visual, accessibility, or product review.
development
Guides topic-level understanding verification for a PR, branch, feature, document, spec, design decision, bug fix, or other concrete subject. Use when the user asks to confirm, quiz, drill, teach-and-check, or verify that they understand a topic. Maintains a topic-specific checklist artifact and requires demonstrated understanding before marking the topic complete. Not for ordinary explanations without verification, end-of-session summaries, or code/test correctness checks.
testing
Design a CI/CD pipeline with quality gates, a <10-minute budget, feature-flag lifecycle, and an exit checklist. Use when adding a new CI pipeline, changing gate configuration, or planning a rollout for a new service. Complementary to kramme:pr:fix-ci (which fixes failures in an existing pipeline). Covers gate ordering, secrets storage, branch protection, rollback mechanism, and staged-rollout guardrails — not a rollout-execution runbook.
tools
--- name: kramme:visual:demo-reel description: Capture local demo evidence for observable product behavior: screenshots, before/after image sets, browser reels, terminal recordings, and short GIF/video proof. Use when shipping UI changes, CLI features, or any change where PR reviewers would benefit from visual or behavioral evidence. argument-hint: "[what to capture] [--url <url>|auto] [--tier static|before-after|browser-reel|terminal-recording]" disable-model-invocation: true user-invocable: tr