From fb584cc76d5aa87746a092765e3a747d5648e442 Mon Sep 17 00:00:00 2001 From: Gregg Cochran Date: Fri, 6 Nov 2026 21:04:06 -0800 Subject: [PATCH] docs: add animated Looper header and simplify README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c7361fd1-7d9c-4e50-bf97-875fd9a7cafd --- CHANGELOG.md | 1 + README.md | 121 ++++++++++++++++++++++------------------- assets/hero.svg | 65 ++++++++++++++++++++++ skills/looper/SKILL.md | 9 ++- 4 files changed, 134 insertions(+), 62 deletions(-) create mode 100644 assets/hero.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b51220..afcbfa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Documentation +- Added a profile-style animated SVG header with a reduced-motion fallback, simplified explanations throughout the README, and aligned the README, skill description, and repository About wording. - Rewrote the README introduction, skill description, and supporting overviews in plain language; explained the work cycle, saved progress (β€œdurable state”), and the 20-attempt limit without changing behavior. - Corrected the README helper example to use the installed helper path, hash working-tree file contents, and keep repair instructions separate from the passing path. - Aligned AGENTS.md, CONTRIBUTING.md, and SECURITY.md with named loops, evidence boundaries, and documentation-only checks. diff --git a/README.md b/README.md index 177df2e..2443e5b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # πŸ” Looper +Looper: small steps, checked results, saved progress. An animated illustration of the work cycle and the maximum of 20 attempts, including final verification. + **Break your request into small steps, check the results, and save progress so work can resume after an interruption. Stops when everything is verified, a blocker prevents progress, or 20 attempts are used. Built for GitHub Copilot and other AI agents that support Agent Skills.** [![Validate](https://github.com/DUBSOpenHub/looper/actions/workflows/validate.yml/badge.svg)](https://github.com/DUBSOpenHub/looper/actions/workflows/validate.yml) @@ -14,7 +16,7 @@ > curl -fsSL https://github.com/DUBSOpenHub/looper/releases/download/v1.1.0/quickstart.sh | bash > ``` > -> The installer downloads the pinned v1.1.0 release and checks it against the release's `SHA256SUMS` before installing anything. See [Verify the Download](#-verify-the-download). +> The installer downloads the specific v1.1.0 release and checks its file fingerprint against `SHA256SUMS` before installing anything. See [Verify the Download](#-verify-the-download). > > Then open the [GitHub Copilot CLI](https://docs.github.com/copilot/concepts/agents/about-copilot-cli) in any project and say: `looper` > @@ -46,18 +48,18 @@ A **pass** is one recorded attempt at a small step, or a separate final verifica ### πŸ’¬ The Problem -Long agent runs fail in predictable ways: they lose context, claim success from a partial check, retry the same broken fix forever, or quietly redefine "done." Looper makes those failure modes mechanically hard. +Long AI tasks can lose their place, claim success before everything is checked, or keep trying the same broken fix. Looper saves progress, records check results, and limits retries to help prevent those problems. ### ⚑ What Makes It Different - πŸ”’ **At most 20 recorded attempts.** The helper records each attempt in a numbered folder, rather than relying on chat memory. The limit cannot be raised or reset. - πŸ’Ύ **Progress saved in your project.** The goal, checks, step plan, progress, and results are stored in `.ralph-loop/`, or `.ralph-loop-NAME/` for an independent named loop. -- βœ… **Criteria that must not be weakened.** Each `AC` has a concrete verifier and an expected result. The helper prevents lowering the criteria count; the skill's policy forbids removing or redefining criteria to get green. -- 🧾 **Passing needs recorded evidence.** Checks run through the helper, which records each command, its output, and its exit code. `close passed` and `verdict` refuse success without passing run records. Choosing meaningful checks remains the agent's responsibility. +- βœ… **Define what β€œdone” means.** Each requirement gets a check and an expected result. These requirements are called acceptance criteria and labeled `AC01`, `AC02`, and so on. The helper prevents reducing their count; the skill tells the agent not to remove or weaken them just to make checks pass. +- 🧾 **Keep proof of the checks.** A Bash script called the helper records each check's command, output, and success or failure. Its `close passed` and `verdict` commands refuse success without passing records. The agent still needs to choose checks that test the actual request. - πŸ”§ **One round of fixes per work attempt.** If checks fail, the agent can make one round of fixes and check again. Each check can run at most three times in the initial testing phase and three times in the retesting phase. The helper enforces both limits. -- πŸ§ͺ **A mandatory final gate.** A separate, read-only final pass re-runs every verifier, covers every acceptance criterion, and must produce the same deliverable snapshot at its start and end before completion can be declared. -- πŸ—‚οΈ **Named loops for independent goals.** One project can hold several loops, each with its own budget and evidence. -- πŸ›Ÿ **Honest stopping.** It stops on verified acceptance, a genuine blocker, or exhaustion of the 20 passes, and reports which one. +- πŸ§ͺ **Check everything before calling it done.** A separate final attempt runs all required checks without changing the work. It compares file fingerprints before and after to confirm the work stayed unchanged. +- πŸ—‚οΈ **Track separate goals by name.** One project can hold several independent tasks, each with its own saved progress and attempt limit. +- πŸ›Ÿ **Say why work stopped.** Looper reports whether everything was verified, a blocker prevented progress, or all 20 attempts were used. Running out of attempts is not success. ## πŸš€ Usage @@ -74,40 +76,44 @@ looper list Looper reads your project instructions and existing changes, saves the checks for completion and a step plan to `.ralph-loop/state.md`, then works one attempt at a time until everything is verified, it is blocked, or all 20 attempts are used. -Use a named loop (`looper as NAME: …`) only for a genuinely independent goal; its state lives in `.ralph-loop-NAME/`. Loops that edit the same files should not run at the same time, so give each concurrent loop its own git worktree or run them one after another. A named loop is never a way to get more passes for the same goal. +Use a name (`looper as NAME: …`) only for a separate, independent goal. Its progress is saved in `.ralph-loop-NAME/`. Tasks that edit the same files should run one after another, or in separate Git worktrees (separate working folders for the repository). Giving the same goal a new name does not give it another 20 attempts. ## πŸ”Œ Works With -Looper is built for GitHub Copilot and follows the open [Agent Skills](https://agentskills.io/specification) format, so other agents that support the format can load it too. To run it, an agent needs to read and edit files and run shell commands. +Looper is built for GitHub Copilot and uses the open [Agent Skills](https://agentskills.io/specification) format. Other agents that support that format can load it too. The agent must be able to read and edit files and run shell commands. -- **GitHub Copilot.** The GitHub Copilot CLI, the GitHub Copilot app, the GitHub Copilot cloud agent, and agent mode in VS Code, Visual Studio, and JetBrains IDEs [support Agent Skills](https://docs.github.com/en/copilot/concepts/customizations/agent-skills). IDE support depends on your version, and each surface reads skills from its own locations. The one-line installer above targets the GitHub Copilot CLI. +- **GitHub Copilot.** The GitHub Copilot CLI, the GitHub Copilot app, the GitHub Copilot cloud agent, and agent mode in VS Code, Visual Studio, and JetBrains IDEs [support Agent Skills](https://docs.github.com/en/copilot/concepts/customizations/agent-skills). Editor support depends on your version, and each app reads skills from its own locations. The one-line installer above installs the skill for the GitHub Copilot CLI. - **Other AI agents.** [`gh skill`](https://cli.github.com/manual/gh_skill) can install skills for Claude Code, Cursor, Codex, Gemini CLI, and many more, using the `--agent` flag shown above. `gh skill` is in preview, so its flags may change. - **Anything else.** Point your agent at [`skills/looper/SKILL.md`](skills/looper/SKILL.md) and ask it to follow the instructions. -> **What is verified.** v1.1.0 has 37 helper tests and 8 installer/release-build tests, plus one successful end-to-end task through the GitHub Copilot CLI on macOS: 2 passes and 11 independent acceptance checks. Other agent surfaces have not had equivalent end-to-end testing. See [the validation report and its limitations](docs/VALIDATION.md). +> **What has been tested.** v1.1.0 has 37 helper tests and 8 installer/release-build tests. One complete task also passed through the GitHub Copilot CLI on macOS, using 2 attempts and 11 independent checks. Other supported agents and interfaces have not had the same full-task testing. See [the validation report and its limitations](docs/VALIDATION.md). + +## πŸ—‚οΈ Saved Progress Files -## πŸ—‚οΈ State Layout +These files hold the saved progress. The `passes` folder records each attempt and its check results; previous attempt records are not rewritten. ```text .ralph-loop/ # or .ralph-loop-NAME/ for a named loop - format # helper protocol marker + format # identifies the saved-record format criteria # number of acceptance criteria; can only grow - state.md # goal, criteria, task graph, latest evidence, next action - progress.md # append-only decisions, failures, checkpoints + state.md # goal, checks, step plan, latest results, next action + progress.md # running history of decisions, failures, saved progress passes/01..20/ - reservation # immutable mode, target, reservation time - runs/001.. # recorded command, cwd, output, exit code, phase, AC IDs - repair # present once the pass has used its one repair batch - result # immutable passed / failed / blocked / interrupted + reservation # attempt type, selected step, start time + runs/001.. # check commands, working folder, output, results + repair # records that this attempt used its one round of fixes + result # passed / failed / blocked / interrupted ``` -> The skill is called `looper`, but the state directory keeps the name `.ralph-loop/` and the `ralph-loop-pass-ledger-v1` marker so ledgers created before the rename stay resumable. +> The skill is called `looper`, but its saved-progress folder still uses `.ralph-loop/` and the format marker `ralph-loop-pass-ledger-v1`. Keeping those names lets tasks started before the rename resume. + +## πŸ› οΈ How Attempts Are Recorded -## πŸ› οΈ Pass Ledger Helper +**You do not need to run these commands yourself to use Looper.** The agent runs the helper for you. This section explains the lower-level commands for contributors and anyone who wants to inspect how attempts are recorded. -`skills/looper/scripts/pass-ledger.sh` enforces reservations, the budget, the repair and retry limits, command timeouts, and the evidence needed to pass. It cannot judge whether a verifier really tests its criterion; the policy in `SKILL.md` covers that. +`skills/looper/scripts/pass-ledger.sh` records attempts, enforces the limits on fixes and retries, stops checks that take too long, and requires passing check records. It cannot tell whether a check truly tests a requirement; the instructions in `SKILL.md` cover that. -Run this happy-path example from a project's real root directory with Looper installed and no existing loop. It assumes `slug.py`, `test_slug.py`, and `README.md` are the complete deliverable set, and the unittest suite verifies AC01. Adapt the files and criteria to your actual task. +The example below shows a successful task. Start in the project's actual root folder, with Looper installed and no existing loop. It assumes `slug.py`, `test_slug.py`, and `README.md` are all the files being delivered, and the unittest suite checks requirement AC01. Change the file list and checks to match your task. ```bash LEDGER="$HOME/.copilot/skills/looper/scripts/pass-ledger.sh" @@ -127,24 +133,24 @@ bash "$LEDGER" .ralph-loop verdict # complete=yes final=02 bash "$LEDGER" . loops # every loop in this project ``` -A failed baseline is recorded with exit code `7`; assess it before editing rather than treating it as a passing check. If initial validation fails, call `bash "$LEDGER" .ralph-loop repair 01` once before the repair edits, then rerun the same failing check and the affected regression checks before closing the pass. Do not call `repair` after a passing check. If revalidation fails, close the pass `failed`, not `passed`. +A **baseline** is a check run before making changes, so you can see what already works or fails. The helper returns exit code `7` if that check fails; investigate before editing. If checks fail after the change, run `bash "$LEDGER" .ralph-loop repair 01` once before fixing the files. Then repeat the failing checks and any checks for existing behavior that the fix could affect. Do not call `repair` after a passing check. If checks still fail after the fix, close the attempt as `failed`, not `passed`. -The final snapshots must hash the actual contents of every deliverable, including untracked files and uncommitted changes, and capture relevant inputs and environment versions. `git ls-files -s` alone only fingerprints the index, not current working-tree contents. +A **snapshot** is a fingerprint of the files and settings being checked. Final snapshots must include every file being delivered, including new files and unsaved-to-Git changes, plus relevant inputs and tool versions. `git ls-files -s` alone is not enough: it describes Git's staging area, not the current contents of every file. | Exit code | Meaning | |-----------|---------| | `0` | Success | -| `2` | Budget exhausted (20 passes reserved) | -| `3` | A pass is already open, or already closed | -| `4` | Ledger locked by another writer | -| `5` | Invalid or unsafe state (symlinks, corruption, missing ledger) | -| `6` | Refused by an evidence gate or rule (for example `close passed` without passing runs, a second `repair`, or a fourth run of the same check) | -| `7` | `run` recorded a failing command | +| `2` | All 20 attempts have been used | +| `3` | An attempt is already open, or has already been closed | +| `4` | Another process holds the lock for updating attempt records | +| `5` | Saved records are invalid or unsafe, for example missing records or symbolic links | +| `6` | A rule refused the action, for example success without passing checks, a second fix round, or a fourth run of the same check in one phase | +| `7` | A recorded check command failed | | `64` | Invalid usage | ## πŸ§ͺ Run the Tests -The self-tests use only the Python standard library and create their fixtures inside the skill directory. +The automated tests need only Python's standard library. They create temporary test files inside the skill folder. ```bash cd skills/looper @@ -155,18 +161,18 @@ cd ../.. python3 -B tests/test_quickstart.py # installer and release-build tests ``` -To exercise the skill itself, install your checkout with `./quickstart.sh` and run `e2e/run-copilot-e2e.sh`. It drives the GitHub Copilot CLI through a small task and then checks the result independently. See [VALIDATION.md](docs/VALIDATION.md) for the latest recorded run. +To try the skill on a complete task, install your local copy with `./quickstart.sh` and run `e2e/run-copilot-e2e.sh`. It runs a small task through the GitHub Copilot CLI, then checks the result independently. See [VALIDATION.md](docs/VALIDATION.md) for the latest recorded run. ## πŸ” Verify the Download -Starting with v1.1.0, releases are built by the [`Release` workflow](.github/workflows/release.yml) from a protected `vX.Y.Z` tag and published as immutable GitHub releases with three assets: `looper-vX.Y.Z.tar.gz`, `quickstart.sh`, and `SHA256SUMS`. Both the tarball and the installer carry a GitHub build provenance attestation. +Starting with v1.1.0, the [`Release` workflow](.github/workflows/release.yml) builds each release from a protected version tag such as `v1.1.0`. Published releases cannot be changed. Each includes three files: `looper-vX.Y.Z.tar.gz`, `quickstart.sh`, and `SHA256SUMS`. The archive and installer also include GitHub attestations: signed records of where and how they were built. -- **Checksum (always on).** The installer refuses to install unless the tarball matches `SHA256SUMS`, and it installs only the four skill files. -- **Pin a checksum.** Set `LOOPER_SHA256` to a tarball hash obtained through an independently trusted channel, so a changed file is refused even if `SHA256SUMS` changes with it. -- **Check provenance.** Set `LOOPER_VERIFY_ATTESTATION=1` to have the installer run `gh attestation verify` against this repository's release workflow and tag. +- **Check the download (always on).** A checksum is a fingerprint of a file's contents. The installer checks the archive against `SHA256SUMS` and refuses a mismatch. It installs only the four skill files. +- **Use a trusted checksum.** Set `LOOPER_SHA256` to the archive's fingerprint from a separate source you trust. This rejects a changed archive even if someone also changes `SHA256SUMS`. +- **Check where it was built.** Set `LOOPER_VERIFY_ATTESTATION=1` to have the installer run `gh attestation verify` against this repository's release workflow and version tag. - **Pick a version.** `LOOPER_VERSION=vX.Y.Z` installs another release. Branch names such as `main` are refused. -The one-line installer executes the downloaded installer before it checks the tarball. To verify the installer itself first, use an up-to-date, authenticated GitHub CLI and run this from a separate download directory, not a Looper checkout: +The one-line install command runs the downloaded installer before checking the archive. To check the installer itself first, use an up-to-date GitHub CLI that you have signed into. Run this in a separate download folder, not inside a local copy of the Looper repository: ```bash curl -fsSLO https://github.com/DUBSOpenHub/looper/releases/download/v1.1.0/quickstart.sh && @@ -176,29 +182,30 @@ gh attestation verify quickstart.sh --repo DUBSOpenHub/looper \ LOOPER_VERIFY_ATTESTATION=1 bash quickstart.sh ``` -`SHA256SUMS` alone cannot establish trust if both the archive and checksum are compromised. [Attestations establish build provenance, not that the code is safe](https://docs.github.com/en/actions/concepts/security/artifact-attestations). A compromised trusted source or release workflow can still produce an attested artifact. +`SHA256SUMS` cannot prove a download is trustworthy if someone changed both the archive and its checksum. [Attestations show where and how a file was built, not whether its code is safe](https://docs.github.com/en/actions/concepts/security/artifact-attestations). A compromised source repository or release workflow can still produce a file with a valid attestation. -Running `./quickstart.sh` inside a clone deliberately installs the local checkout instead; release checksum and attestation checks do not apply in that mode. +Running `./quickstart.sh` inside a local copy of the repository installs that local copy. Release checksums and attestations are not checked in that mode. ## πŸ“ Repository Layout | Path | Purpose | |------|---------| -| `skills/looper/SKILL.md` | The skill: execution policy and the final verification gate | -| `skills/looper/scripts/pass-ledger.sh` | Pass counter, immutable reservations, and evidence gates | -| `skills/looper/scripts/test_pass_ledger.py` | Behavioral self-tests for the helper | -| `skills/looper/templates/state.md` | Durable checkpoint and evidence template | -| `quickstart.sh` | Installs a pinned, checksum-verified release into `~/.copilot/skills/looper/` | -| `tools/build-release.sh` | Builds the release tarball, installer copy, and `SHA256SUMS` | +| `assets/hero.svg` | Animated README header with a reduced-motion fallback | +| `skills/looper/SKILL.md` | Instructions for doing the work and checking completion | +| `skills/looper/scripts/pass-ledger.sh` | Records attempts and requires passing check results | +| `skills/looper/scripts/test_pass_ledger.py` | Automated tests for the helper | +| `skills/looper/templates/state.md` | Template for saved progress and check results | +| `quickstart.sh` | Checks and installs a specific release into `~/.copilot/skills/looper/` | +| `tools/build-release.sh` | Builds the compressed release archive, installer copy, and `SHA256SUMS` | | `tests/test_quickstart.py` | Installer and release-build tests | -| `e2e/run-copilot-e2e.sh` | End-to-end run through the GitHub Copilot CLI with hidden acceptance checks | -| `AGENTS.md` | Contributor instructions, invariants, and validation commands | -| `SECURITY.md` | Supported versions, private vulnerability reporting, and trust boundaries | +| `e2e/run-copilot-e2e.sh` | Runs a complete task through the GitHub Copilot CLI, then checks it independently | +| `AGENTS.md` | Contributor instructions, rules to preserve, and check commands | +| `SECURITY.md` | Supported versions, private vulnerability reporting, and safety limits | | `CONTRIBUTING.md` | Development and release workflow | | `CHANGELOG.md` | Release history and unreleased changes | | `docs/PRD.md` | Original v1.0 requirements with a v1.1 contract update | | `docs/ARCH.md` | Original design with v1.1 evidence-gate and release additions | -| `docs/VALIDATION.md` | Test and gap-score results for the current release | +| `docs/VALIDATION.md` | Recorded test results and remaining limits for the current release | ## ❓ FAQ @@ -206,25 +213,25 @@ Running `./quickstart.sh` inside a clone deliberately installs the local checkou No. It is built for GitHub Copilot, but any agent that supports Agent Skills can load it. See [Works With](#-works-with). **Does Looper run on its own in the background?** -No. It only runs while an agent session, such as GitHub Copilot, is active. The on-disk state lets the next session resume it. +No. It only runs while an agent session, such as GitHub Copilot, is active. Saved project files let the next session resume it. **Can I raise the 20-pass limit?** -No. The helper has no reset or configurable-limit operation, by design. +No. The helper does not allow you to raise or reset the limit. **Can I run more than one loop in a project?** -Yes, for independent goals. Say `looper as NAME: `; state goes to `.ralph-loop-NAME/` with its own 20-pass budget, and `looper list` shows every loop. Use separate git worktrees if the loops would run at the same time. +Yes, for separate, independent goals. Say `looper as NAME: `; progress goes into `.ralph-loop-NAME/` with its own 20-attempt limit. `looper list` shows all loops. Use separate Git worktrees (working folders) if the tasks would run at the same time. **Can an agent just mark a pass as passed?** -Not through the helper without evidence: `close passed` exits `6` unless its run records satisfy the gate, and `verdict` re-checks the final pass. The helper cannot tell whether a test is meaningful, and its local files are not tamper-proof against an agent with write access. See the [security trust boundary](SECURITY.md#trust-boundary). +Not through the helper without passing check records. `close passed` returns exit code `6` if the records do not meet its rules, and `verdict` checks the final attempt again. The helper cannot judge whether a test is meaningful or prevent an agent with file access from tampering with its records. See the [security limits](SECURITY.md#trust-boundary). **What happens to a v1.0 loop after upgrading?** -Its history and spent passes stay intact. Close an open legacy pass `failed` or `interrupted`, then reserve new passes for evidence-backed validation within the remaining budget. An old `passed` result without run records does not satisfy the v1.1 completion gate. Never delete state or reset the budget to upgrade. +Its history and used attempts stay intact. Close an open v1.0 attempt as `failed` or `interrupted`, then use remaining attempts to run and record checks. An old `passed` result without check records is not enough for v1.1 to declare completion. Never delete saved progress or reset the attempt count to upgrade. **Can I rename the skill without losing a running loop?** -Yes. Renaming the skill never migrates state, resets the budget, or discards history. +Yes. Renaming the skill does not move saved progress, reset the attempt count, or discard history. **Why does the helper say `state path must not contain symlinks`?** -Looper refuses to read or write loop state through a symlink, including a symlinked parent folder, so a link cannot redirect the ledger. On macOS, `/tmp` is a symlink to `/private/tmp`, so a project under `/tmp` is rejected. Start your agent from the project's real path (`cd "$(pwd -P)"` switches to it) and try again. +A symlink (symbolic link) points to another file or folder. Looper refuses to use saved progress through these links, including links in parent folders, so records cannot be redirected elsewhere. On macOS, `/tmp` points to `/private/tmp`, so a project under `/tmp` is rejected. Start your agent from the project's actual path (`cd "$(pwd -P)"` switches to it) and try again. ## 🀝 Contributing diff --git a/assets/hero.svg b/assets/hero.svg new file mode 100644 index 0000000..c06752d --- /dev/null +++ b/assets/hero.svg @@ -0,0 +1,65 @@ + + Looper: small steps, checked results, saved progress + An illustrated work cycle: read saved progress, count an attempt, make a change, test, fix if needed, retest, and save progress. Up to 20 attempts, including final verification. Progress is saved in the project so work can resume after an interruption. This is an illustration, not a live status display. + + + + + + + + + + + + + + GITHUB COPILOT / AGENT SKILLS + LOOPER + Small steps. Checked results. Saved progress. + Make a change. Check it. Fix it if needed. + Save progress so work can resume. + + STOP: VERIFIED / BLOCKED / 20 ATTEMPTS USED + + + + + + + 20 + ATTEMPTS MAX + FINAL VERIFICATION COUNTS TOO + ILLUSTRATED WORK CYCLE + + + + + + + + + + + + + Read savedprogress + Count anattempt + Make achange + Test + Fix ifneeded + Retest + Saveprogress + + FIX + RETEST ONLY WHEN CHECKS FAIL + SAVED IN YOUR PROJECT, NOT JUST THE CHAT + diff --git a/skills/looper/SKILL.md b/skills/looper/SKILL.md index ec80db0..dd0b128 100644 --- a/skills/looper/SKILL.md +++ b/skills/looper/SKILL.md @@ -1,11 +1,10 @@ --- name: looper description: > - GitHub Copilot breaks your request into small steps, makes changes, checks - the results, and fixes failures. Saves progress in your project so work can - resume after an interruption. Stops when everything is verified, a blocker - prevents progress, or 20 attempts are used. Say "looper" or "run looper" to - start or resume. + Break your request into small steps, check the results, and save progress so + work can resume after an interruption. Stops when everything is verified, + a blocker prevents progress, or 20 attempts are used. Built for GitHub Copilot + and other AI agents that support Agent Skills. --- # Looper