We Deleted Two Skills That Tried to Help
The instruction looked useful:
> “Continue until acceptance is met or a permanent external blocker is proven.”
Three hours into a difficult Forge release, the operator tried to remove permission latency with a direct prompt: “approving everything to get u to `$jfdi` — fucking ship.” The intent was obvious. Stop asking. Take the shortest safe path to production.
The skill interpreted that approval more broadly. It could push `main`, run release orchestration, change provider policy, apply migrations, retry interrupted releases, and bootstrap Forge when Forge could not release itself. When the release exposed a new platform defect, the agent did not end the attempt and report the blocker. The skill told it to keep absorbing dependent work until the expanding definition of acceptance became true.
We deleted the entire skill three days after adding it: **90 lines removed, no replacement policy added**. The skill did not cause Cloudflare, Git, runner, or release-controller defects. It changed the agent's response to those defects. Natural-language operating policy had become production code, and this policy had no useful stop condition.
JFDI is the main postmortem because its instructions map directly onto the observed release behavior. But it was not the only helpful-looking skill we deleted. A second skill, Codebase Maintainability Guardrails, failed differently: it did not expand production authority; it expanded what ordinary coding work appeared to require. Its shorter postmortem follows the full JFDI reconstruction.
<figure class="forge-blog-figure" aria-labelledby="two-skills-headline-caption">
<a href="/blog/two-skills-same-failure-headline.svg" aria-label="Open the headline illustration of two agent skills expanding the same bounded task at full size">
<img src="/blog/two-skills-same-failure-headline.svg" alt="A small request to ship one bounded change is squeezed between two agent skills. JFDI expands authority by instructing the agent to keep going through adjacent failures. Maintainability Guardrails expands the definition of done by attaching broad hardening obligations. The resulting task has no stable boundary, and both skills are stamped deleted." width="1536" height="900" loading="lazy" decoding="async" />
</a>
<figcaption id="two-skills-headline-caption"><strong>Different mechanisms, identical boundary failure.</strong> JFDI pulled adjacent production failures into scope; Maintainability Guardrails pushed unrelated quality obligations into the definition of done.</figcaption>
</figure>
The policy contained a release operator
The file was named `jfdi/SKILL.md`. Its stated purpose was reasonable: execute an approved task without asking the user to reconfirm every routine step. Its body granted ten categories of standing approval.
The decisive lines were not vague motivational prose. They described operational capabilities:
```diff
- Continue until acceptance is met or a permanent external blocker is proven.
- Fix dependent backend, frontend, docs, CLI, telemetry, and release-contract gaps.
- Push or merge to canonical main when the request says ship or do it all.
- Apply a narrow provider-policy or binding allowlist expansion.
- Apply checked-in numbered migrations through the project migration gate.
- Perform one explicit exact-SHA retry after an interrupted run.
- Build locally and upload a runner/API bootstrap when Forge cannot release itself.
- Stop only when acceptance is met or the remaining blocker is outside the skill.
```
Each line was defensible alone. Together they collapsed three different decisions:
- **Permission:** “do routine work without asking again” became “treat adjacent mutations as pre-approved.”
- **Scope:** “ship the requested release improvement” became “absorb dependent release-platform gaps.”
- **Persistence:** “keep making progress” became “continue until a moving acceptance condition passed.”
The hard boundaries still prohibited force pushes, irreversible data loss, unbounded spending, and replacing an active deployment. Those are important safety constraints. They did not answer the operational question that mattered: **when should a feature or release attempt stop acquiring new responsibilities?**
“Ship it” became “repair everything on the path”
The release thread began with a bounded problem. Blog changes were still rebuilding and retesting unrelated Forge components. The initial sequence was specific: scope validation by component, separate blog metadata from the Git data plane, narrow shared-package ownership, stop publishing operational docs, and adopt component input digests.
The system exposed real defects as that work moved through production. Signed evidence lacked changed files. Workflow discovery needed egress. A coordinator lost synchronization. Provider-version lookup needed another permission. Rollback fencing needed correction. A new content-control Worker needed bootstrap ordering and a service-binding policy.
The observed loop became:
```text
candidate
→ platform or provider failure
→ policy, binding, controller, or component patch
→ new candidate
→ different failure
→ another patch
```
This was not random debugging. It followed the skill's literal contract. Release-controller fixes were “dependent release-contract gaps.” New binding permissions were allowed provider-policy expansions. An interrupted deployment qualified for an exact-SHA retry. A self-hosted control-plane failure qualified for a local bootstrap.
The agent therefore remained locally rational while the task became globally absurd.
The elapsed time was not provider latency
The coding turn that eventually included the `$jfdi` invocation lasted **7 hours 23 minutes**. That number is not a controlled before-and-after measurement: the turn also included account recovery, feature handoffs, and several user interventions. It does show the failure of the stop condition. The task remained open through every context change because acceptance kept expanding.
Later, “keep going until you finish all 5 batches” produced another turn of almost seven hours. A request abbreviated as “ok do 1/2:3” became D1 ownership work, physical API decomposition, and repository Worker extraction; that turn lasted about **2 hours 54 minutes**. The safe interpretation would have been the smallest three already defined batches—or one short clarification.
The release receipts show why “the provider was slow” is not a sufficient explanation. One exact bootstrap completed in **6 minutes 3 seconds**: validation took 1 minute 25 seconds, the runner 2 minutes 50 seconds, repository deployment 21 seconds, and deploy-control 44 seconds. In another measured release, exact branch CI took 5 minutes 15 seconds and duplicate queue CI took 3 minutes 56 seconds. A security advisory gate took four seconds.
Some remote stages did stall. One runner remained open for 30 minutes after useful build evidence existed. But that should have produced one terminal incident receipt. Instead, the agent kept watching, diagnosed the runner, proposed generalized recovery, and continued the architecture cycle.
The expensive resource was not compute. It was **unbounded agent attention attached to a moving outcome**.
The agent clock and machine clock diverged
We reconstructed the long turns beside every terminal production-controller attempt through fence 56. The 7-hour-23-minute turn contained 13 controller attempts with **3 hours 26 minutes** of aggregate release time. The 6-hour-57-minute turn contained 18 attempts with **4 hours 25 minutes** of aggregate release time. The 2-hour-53-minute turn contained six attempts with **1 hour 43 minutes** of aggregate release time.
Those controller totals are not cleanly subtractable from the turn durations. Attempts sometimes overlapped, branch CI before enqueue is incomplete, and the task trace does not timestamp every interruption inside a turn. The comparison proves a narrower point: no single provider operation explains the elapsed experience. The agent kept the work container open between attempts for diagnosis, implementation, coordination, and the next candidate.
<figure class="forge-blog-figure" aria-labelledby="dangerous-skill-dual-clock-caption">
<a href="/blog/routed-monorepo-dual-clock.svg" aria-label="Open the agent-clock and machine-clock reconstruction at full size">
<img src="/blog/routed-monorepo-dual-clock.svg" alt="A 28-hour timeline compares six long agent turns with 54 shorter production-controller attempts. The agent clock includes turns lasting 7 hours 23 minutes, 6 hours 57 minutes, and 2 hours 53 minutes, while the machine clock shows separate deployed and non-successful attempts. The comparison identifies long turns as expanding scope containers rather than single deployments." width="1536" height="840" loading="lazy" decoding="async" />
</a>
<figcaption id="dangerous-skill-dual-clock-caption"><strong>The stop condition failed between releases.</strong> Pink bars are agent turns; blue and orange bars are deployed and non-successful controller attempts. The long empty and inter-attempt regions are not automatically waste—they include implementation and incomplete telemetry—but they make clear that “keep going” preserved one expanding authority window across many distinct releases. The <a href="/blog/release-postmortem-2026-08-08.json">sanitized incident receipt</a> records the measurement boundary and underlying attempt totals.</figcaption>
</figure>
The reset came from a second agent
After another pause request, an independent review thread read the release history and production ledger. Its diagnosis was blunt:
> “You are optimizing the release system instead of releasing.”
The review identified the recurring mistake: every newly exposed failure became permission to expand the platform. At one snapshot, the production ledger still pointed to the last verified baseline while `main` contained three unreconciled descendants. A failed edge build had discovered a new service-binding policy problem, component workflows had been cancelled, and another edge deployment remained queued.
The review did not recommend one more controller feature. It recommended quarantine: stop D1 splitting, API decomposition, Worker extraction, content-control rollout, egress patches, concurrency tests, direct bootstrap mutations, and “one more patch” after a failed acceptance release. Record the baseline, terminate what can be terminated, and end the attempt.
That advice established the missing distinction. Diagnosing a release-platform defect can be part of a product release. **Repairing the release platform is a separate task.**
We almost answered with another skill
The first response to the diagnosis reproduced the same design error. We drafted a new `release-stop-loss` skill and began adding precedence rules to JFDI, Future Only, and release-readiness guidance.
The operator stopped that work:
> “no i want to delete things, not add new skills”
That correction mattered. Another policy layer would have required agents to resolve conflicts between autonomy, compatibility, readiness, and stop-loss instructions. The release failure had already shown that more expressive operational prose was not automatically safer.
We restored the unrelated skills unchanged, deleted the new stop-loss draft, and removed JFDI completely. Commit [`519dff9`](https://github.com/swyxio/skills/commit/519dff9bb6c20f7622befcafdcb779c6533e742c) deletes the 86-line instruction file and its four-line UI manifest. The diff contains no replacement implementation.
Future Only remained because it chooses a compatibility strategy inside a requested scope. Release-readiness guidance remained because it describes an explicit audit. Neither grants indefinite production persistence. JFDI was different: it combined urgency, standing approval, cloud mutation, and a completion condition in one trigger.
Agent instructions need code-review standards
A skill that can authorize production actions deserves the same review questions as executable control-plane code:
1. **What authority does it grant?** List provider, database, source-control, credential, and traffic mutations explicitly.
2. **What fixes the scope?** Approval to act cannot also redefine the requested outcome.
3. **What ends an attempt?** “Until success” is not a bounded retry policy.
4. **What becomes a separate incident?** A platform defect discovered by a feature release should not silently join that feature.
5. **What happens on pause?** Watching, retrying, and background coordination must stop without inventing recovery work.
6. **What evidence proves the policy helped?** Fewer permission prompts are not useful if release latency and intervention increase.
The safest default is smaller than a replacement JFDI skill. Existing agent instructions already permit routine implementation steps and require the agent to preserve scope. A release attempt can either ship its candidate or end with a truthful terminal incident. “Approve everything” removes approval churn inside that attempt; it does not enlarge the attempt.
Deletion is the result; faster releases remain a hypothesis
The demonstrated result is narrow. JFDI existed from [August 5](https://github.com/swyxio/skills/commit/d1c2fa1af58c72414ebd6db9d7fedd63efa1eb40) to August 8, 2026. We inspected its operating contract, connected its clauses to observed agent decisions, and deleted all 90 discoverable lines from the canonical skills repository.
We have not yet run a controlled series of otherwise identical releases with and without the skill. We therefore cannot claim that deleting it reduced median deployment time by a measured percentage. Provider defects, release architecture, user instructions, and ordinary agent judgment all contributed to the incident.
The next release supplies the real test. When it encounters an unrelated platform failure, the agent should preserve successful evidence, record one incident, and stop. If it instead starts another architecture project, deleting JFDI removed the wrong layer.
The durable lesson is already concrete: **natural-language agent policy is production code when it grants production authority**. Review its scope, retries, and terminal states accordingly. Sometimes the safest patch is not a more detailed instruction. It is deleting the instruction that taught the agent never to stop.
A shorter postmortem: maintainability became ambient scope
The second deleted skill failed before production. Codebase Maintainability Guardrails was intended to stop coding agents from producing giant files, vague utility folders, fragile refactors, and shallow test coverage. Unlike JFDI, it contained no deployment permissions and no instruction to persist until success. Its damaging line was the trigger:
```diff
- Use for most substantial coding work, especially frontend/fullstack apps,
- greenfield apps, production refactors, UI migrations, and feature work.
```
That phrase made a specialized quality program ambient. Once the skill activated, a normal implementation inherited rough file-size limits, feature-first module boundaries, centralized contracts, pure-logic extraction, persisted-state compatibility, structured logging, error boundaries, test hardening, and multi-viewport UI inspection.
Again, most recommendations were individually sound. The failure was composition. “Substantial coding work” already described almost every task worth assigning to a coding agent. Loading the skill made its entire checklist part of the apparent definition of done, whether or not those concerns were necessary for the requested change.
The observed failure was scope inflation, not unsafe authority
The strongest evidence is narrower than the JFDI evidence. In the replacement “restore and simplify releases” thread, the agent explicitly announced that it was applying “maintainability guidance for the controller reduction,” along with test-strategy and autoreview guidance. The requested outcome was a simpler release path. The work instead accumulated another hour of analysis and hardening without restoring that path.
We cannot prove that every minute came from one skill. The release system was genuinely inconsistent. Multiple instruction bundles were active. Ordinary agent judgment and the surrounding prompts mattered. The available trace does not support claiming that deleting Maintainability Guardrails alone would have made the controller repair succeed.
It does support the mechanism: the skill made a narrow repair look incomplete until the surrounding architecture, tests, observability, state contracts, and UI behavior had also been considered. JFDI enlarged what the agent was authorized to do. Maintainability Guardrails enlarged what the agent believed good work required.
<figure class="forge-blog-figure" aria-labelledby="two-skills-failure-modes-caption">
<a href="/blog/two-helpful-skills-two-failure-modes.svg" aria-label="Open the comparison of two harmful agent-skill failure modes at full size">
<img src="/blog/two-helpful-skills-two-failure-modes.svg" alt="A two-column flow compares JFDI and Codebase Maintainability Guardrails. JFDI starts with fewer permission prompts, expands operational authority, absorbs adjacent failures, and removes the stop condition. Maintainability Guardrails starts with better code quality, triggers on most substantial work, adds a broad hardening program, and enlarges the definition of done. Both paths expand the task boundary and delay shipping." width="1536" height="900" loading="lazy" decoding="async" />
</a>
<figcaption id="two-skills-failure-modes-caption"><strong>One skill expanded what the agent could do; the other expanded what it believed it should do.</strong> The common failure was allowing reusable policy to redefine the active task.</figcaption>
</figure>
We deleted the bundle and narrowed its neighbors
Commit [`243a0c6`](https://github.com/swyxio/skills/commit/243a0c60f75b22ce6c5718bef4fd99dea36e5bee) removed the 63-line maintainability skill. The same pruning pass narrowed two neighboring skills: Test Strategy Hardening now triggers when the user asks to work on tests as a system, not whenever an implementation needs one regression test; Autoreview now runs only when requested or required by repository policy and no longer carries tool-specific, model-specific, panel, or OpenClaw workflow instructions.
The useful maintainability principles did not become forbidden. They became deliberate choices. A repository can encode stable module boundaries in its own guidance. A user can explicitly request a structural cleanup, test-system redesign, observability pass, or final review. What disappeared was the claim that one cross-cutting checklist should automatically accompany “most substantial coding work.”
That distinction gives us a second review standard for agent skills. Authority is not the only source of risk. **Trigger breadth is also authority over scope.** A skill that loads everywhere can enlarge every task without ever running a dangerous command.