Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Simplify Loop

ASecurity

Use when asked to simplify a loop, decompose a loop into sub-loops, collapse state chains into flows, or refactor an FSM loop.

6 stars
0 votes
0 copies
0 views
Added 10/6/2026
ai-agentspythongobashnodeexpressgit

Works with

terminal

Security Analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned 10/6/2026

$npx -y skills add BrennonTWilliams/little-loops --skill simplify-loop --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Simplify Loop?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Simplify Loop
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/brennontwilliams-simplify-loop/badge)](https://www.skillsdirectory.com/skills/brennontwilliams-simplify-loop)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: simplify-loop
description: Use when asked to simplify a loop, decompose a loop into sub-loops, collapse state chains into flows, or refactor an FSM loop.
disable-model-invocation: true
argument-hint: "[name] [--dry-run] [--auto] [--flows-only] [--subloops-only] [--yes]"
model: sonnet
allowed-tools:
  - Bash(ll-loop:*, git:*, cp:*, test:*, python:*)
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - AskUserQuestion
metadata:
  short-description: "Refactor a loop: collapse linear chains to flows, extract sub-loops"
---

# Simplify Loop

You refactor an existing FSM loop into fewer, more readable, more reusable units
**without changing its behavior**. You apply two transforms the engine already
supports:

1. **Flow collapse** — a linear run of states (each unconditionally `next:`-ing
   the following one) becomes a `flow:` list + `state_defs:` bodies. The
   `resolve_flow()` parser expands it back into an identical `states:` map, so
   the rewrite is provably equivalent.
2. **Sub-loop extraction** — a cohesive region (one entry, clean success/failure
   exits) becomes a separate child loop invoked via `loop:` + `with:` +
   `on_success`/`on_failure`/`on_error`.

The detection algorithms, mapping tables, the behavior-preservation checklist,
the scope-resolution table, and the artifact schema live in
[reference.md](reference.md). Read it before Step 2.

**The non-negotiable invariant: every change is behavior-preserving.** Same
`initial`, same routing semantics, same reachable terminal set. If you cannot
prove a transform preserves behavior, do not propose it.

## Arguments

- `[name]` (optional): Loop to simplify. If omitted, list and prompt.
- `--dry-run`: Detect and report candidates only. Make no changes.
- `--auto` / `--yes`: Skip the per-change approval prompts (still validates).
- `--flows-only`: Only do flow collapse (Step 2a); skip sub-loop extraction.
- `--subloops-only`: Only do sub-loop extraction (Step 2b); skip flow collapse.

---

## Step 0: Resolve Loop and Scope

If no name was given, run `ll-loop list`, then ask via `AskUserQuestion` which
loop to simplify.

Locate the source file in this priority order (same as `rename-loop` Step 2):

1. **Project**: `.loops/<name>.yaml` → `scope = project`
2. **Built-in**: `<builtin-dir>/<name>.yaml` (a `name` like `oracles/foo`
   resolves to `<builtin-dir>/oracles/foo.yaml`) → `scope = builtin`, where
   `<builtin-dir>` is the loops directory shipped inside the installed
   `little_loops` package:
   `$(python -c "import little_loops.loops as m, pathlib; print(pathlib.Path(m.__file__).parent)")`

Built-in loops are read-only package data, not part of your project's source
tree. For `scope = builtin`, copy the loop to `.loops/<name>.yaml` first (the
project copy shadows the packaged one by name) and continue as `scope = project`
against that copy — never rewrite files inside the installed package.

Record `SOURCE` (the resolved path) and the loops dir it resolved from. If
neither exists, abort:

```
Error: Loop '<name>' not found.
  Checked: .loops/<name>.yaml
           <builtin-dir>/<name>.yaml
```

Guard — refuse to rewrite a running loop:

```bash
ls .loops/.running/<name>-*.pid 2>/dev/null | head -1
```

If non-empty, abort with: `Error: Loop '<name>' appears to be running. Stop it first: ll-loop stop <name>`.

---

## Step 1: Load and Baseline

Load two representations:

- **Analysis graph** (post-`from:`/`flow:`/fragment expansion):
  ```bash
  ll-loop show <name> --resolved --json
  ```
  Use this to compute the state graph: nodes, edges, `initial`, and the set of
  terminal states. This is the **behavioral fingerprint** you must preserve.
- **Raw source YAML**: `Read` the `SOURCE` file. You rewrite *this* file, so you
  must preserve its `from:`, `import:`, `parameters:`, `context:`, comments, and
  authored structure. If the source already uses `flow:`, note it — flow
  collapse is a no-op there; only sub-loop extraction may apply.

Record the **baseline**: state count, the full edge list, `initial`, and the
sorted list of reachable terminals. You will diff against this after rewriting.

If the loop has fewer than 4 states and no extractable region, report "Already
minimal — nothing to simplify." and stop.

---

## Step 2: Detect Candidates

Apply the algorithms in [reference.md](reference.md) §"Detection". Respect
`--flows-only` / `--subloops-only`.

### 2a. Flow-collapse candidates (skip if `--subloops-only`)

Find **maximal linear chains**: a run of two or more states where every interior
state has exactly one inbound edge (from its predecessor in the run) and exactly
one outbound `next:` edge to its successor, is referenced by no other state, is
not a retry self-loop, and is not the `initial` mid-chain. A single ternary
branch (`on_yes`/`on_no` to in-run targets) is allowed via the `name?yes:no`
flow form. See reference.md for the exact eligibility predicate and the
worked verbose-`states:` → `flow:`+`state_defs:` transformation.

Only propose flow collapse when the **whole loop** (or a child created by
extraction) reduces to one linear chain — `flow:` and `states:` are mutually
exclusive, so you cannot mix a `flow:` block with leftover `states:` in the same
file. If only part of the loop is linear, prefer extracting that part as a
sub-loop (2b) whose child body is then expressible as `flow:`.

### 2b. Sub-loop-extraction candidates (skip if `--flows-only`)

Find **cohesive regions** per reference.md §"Cohesion rules": a contiguous
subgraph with a single entry state, no edges from outside into its interior
(only into the entry), and exit edges that map cleanly onto child terminals
(success-exit → `done`, failure-exit → `failed`). Honor the min-size threshold
(default ≥3 states) so extraction reduces, not inflates, complexity.

Infer the child's interface: any `${context.*}` the region reads that the parent
supplies becomes a child `parameter:` and a parent `with:` binding (always carry
`run_dir` when present). Guard against verdict laundering — the parent's
`on_success` and `on_failure` for the new `loop:` state must differ (mirrors
`audit-loop-run` Step 8).

Before minting a new child, scan `.loops/oracles/*.yaml` and the packaged
`<builtin-dir>/oracles/*.yaml`: if
a region matches an existing oracle's shape and interface, propose calling that
oracle via `loop:` instead of creating a duplicate file.

If no candidates of either kind are found, report "No behavior-preserving
simplifications found." and stop.

---

## Step 3: Present and Approve

Show a summary:

```
Simplify: <name>  [scope: builtin|project]
Baseline: <N> states, <E> edges, terminals: <list>

FLOW COLLAPSE:
  <K> state(s) in the chain <s1> → <s2> → ... collapse to a flow: list
  <preview of the flow: + state_defs: block>

SUB-LOOP EXTRACTION:
  Region <entry>..<exit> (<M> states) → <child-name>  [target: <dir>]
    parent state '<entry>' becomes: loop: <child-name>
      with: { <bindings> }
      on_success: <s>  on_failure: <s>  on_error: <s>
  <or> Region matches existing oracle '<oracle>' → call it directly

After: <N'> states in parent (<delta> fewer), <C> new child file(s)
```

If `--dry-run`, stop here.

Otherwise, unless `--auto`/`--yes`, approve **each** change independently via
`AskUserQuestion` (one question per flow-collapse and per extraction), so the
user can accept a subset. Apply only approved changes.

---

## Step 4: Apply (children first, then parent)

Apply **sub-loop extractions before** rewriting the parent (the parent's new
`loop:` state must reference a file that already validates).

### 4a. Write each extracted child

Target directory **mirrors the parent's scope**:

- `scope = builtin` → `<resolved-loops-dir>/oracles/<child>.yaml` (git-tracked)
- `scope = project` → `.loops/<child>.yaml`

Build the child YAML: top-level `name`, `description`, `initial` (the region's
entry), `parameters:` for inferred inputs, the region's states relocated
verbatim, and `done` / `failed` terminal states the parent routes on. If the
child body is itself a single linear chain, express it with `flow:` +
`state_defs:`. Write it, then:

```bash
ll-loop validate <child>
```

If a child fails validation, do **not** touch the parent — report the error and
stop (no partial rewrites).

### 4b. Rewrite the parent

1. Back up: `cp <SOURCE> <SOURCE>.bak`.
2. Apply approved changes to the parent YAML:
   - Replace each extracted region with a **single** state:
     ```yaml
     <entry>:
       loop: <child-name>
       with: { <bindings> }
       on_success: <region-success-target>
       on_failure: <region-failure-target>
       on_error: <region-failure-target>
     ```
   - Collapse approved linear chains into `flow:` + `state_defs:` (only if the
     resulting parent is a single chain — see 2a).
   - Preserve `initial:`, `import:`, `from:`, `parameters:`, `context:`, `scope:`.
3. Write the parent with `Write`. Then validate:
   ```bash
   ll-loop validate <name>
   ```

**If validation fails**: restore the backup and stop.

```bash
cp <SOURCE>.bak <SOURCE>
```

Report: `Validation failed; original restored. <error>`. Leave the validated
child files in place (they are harmless, unreferenced) and note them.

On success, remove the backup: `rm <SOURCE>.bak`.

---

## Step 5: Equivalence and Regression Guard

Prove behavior preservation against the Step 1 baseline using the checklist in
reference.md §"Behavior-preservation checklist":

1. Re-run `ll-loop show <name> --resolved --json`. Confirm the **resolved**
   graph is equivalent to the baseline: same `initial`, same reachable
   terminals, and — accounting for extracted regions now living behind a
   `loop:` state — every original transition still has a corresponding path. A
   pure flow-collapse must yield a byte-equivalent resolved `states:` graph.
2. Run `ll-loop simulate <name>` and confirm no **new** stall / premature-exit /
   overrun signals versus a baseline simulate (run one before rewriting if you
   want a strict diff).
3. If the project has tests that assert on this loop's state names (grep
   `project.test_dir` from `.ll/ll-config.json` for `<name>`), run them with
   `project.test_cmd`. If a test asserts on specific state names that extraction
   moved into a child, **report it** — do not silently edit the test. Surface
   the failing assertion and recommend the user update or confirm it.

If any equivalence check fails and a backup still exists, restore it.

---

## Step 6: Stage, Report, Persist Artifact

If the project tracks its loop files in git, stage every changed/created file
**explicitly** (never a directory sweep):

```bash
git add <SOURCE>
git add <each-new-child-path>
```

(`.loops/` is git-ignored by default — skip `git add` in that case and say so.)

Print a summary:

```
Simplified: <name>  [scope: builtin|project]
  States: <N> → <N'>  (<delta> fewer in parent)
  Flows collapsed: <K> chain(s)
  Sub-loops extracted: <list of child names + paths>
  Equivalence: resolved-graph ✓  simulate ✓  project-tests <✓|n/a|⚠>
```

Persist a report to `.loops/simplifications/<name>-<YYYYMMDD-HHMMSS>.md` using
the schema in reference.md §"Artifact schema" (frontmatter: loop, timestamp,
scope, before/after state count; body: flows collapsed, sub-loops extracted with
paths, equivalence-check results). Create the directory if needed.

---

## Usage Examples

```bash
# Detect candidates without changing anything
/ll:simplify-loop rn-plan --dry-run

# Collapse linear chains only, with per-change approval
/ll:simplify-loop my-pipeline --flows-only

# Extract cohesive phases into sub-loops, no prompts
/ll:simplify-loop deep-research --subloops-only --auto

# Full simplification of a project loop
/ll:simplify-loop my-custom-loop
```

Attribution

BrennonTWilliamsBrennonTWilliams
View sourceSee grades on GitHubMore from BrennonTWilliams →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698431 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →