# Anchored Install

> Use this skill for checkpointed retries of substantial, multi-step shell install/setup/provisioning workflows: cache successful steps and resume after failure or interruption without repeating completed work. Trigger when the user asks for checkpoint/layer caching or resume-after-failure, names `anchored-install`, the `ai` command, or `#ai`, asks to author, edit, convert, plan, run, or debug an `#ai` manifest, or reports frequent/repeated installation failures or interruptions, especially when reruns redo completed work. Also trigger proactively when the user's task is to author a new install/setup/provisioning script whose planned side-effecting steps are costly, slow, or risky to repeat, even if caching is unstated. Initial execution of an existing vendor/third-party script, package command, or one-off installer error stays native; generic setup, idempotency, or rerun wording and a cheap or merely long/flaky script are not enough.

- Skill: `openghz/anchored-install` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add openghz/anchored-install`
- Raw SKILL.md: https://api.skillmd.com/api/skills/openghz/anchored-install/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: openghz (https://skillmd.com/u/openghz)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/openghz/anchored-install

---


# anchored-install (`ai`)

`anchored-install` runs a plain list of shell commands and **caches every step
that succeeds**. When a run fails, you fix the problem and re-run — already-succeeded
steps are skipped and execution **resumes from the first unfinished step**, instead
of starting over from the top every time. Think Dockerfile layer caching, but for
an ordinary shell script.

A manifest is just a normal shell script: the caching markers are `#ai` comments,
so `bash install.sh` runs the exact same file natively, with or without `ai`
installed. This is the tool's core appeal — keep one file, get caching for free.

## When to reach for this

Once the trigger condition above is met, reach for anchored-install for
**checkpointed retries**:
completed shell steps should be cached and a failed or interrupted run should
resume without repeating them. This also applies when an existing installation
has already failed repeatedly and the user wants to preserve its completed
progress. The payoff is biggest for long, effectful sequences such as installing
packages, cloning and building repos, downloading large artifacts, running
migrations, or provisioning a machine.

When the task is to author a new install/setup/provisioning script, infer the
need proactively when restarting from the top would make several expensive or
failure-prone steps run again, even when the user did not say “cache” or “resume.”
Add the `#ai` markers from the beginning; do not wait for the first failure. This
inference applies to a script we are designing, not to wrapping or executing an
existing vendor/third-party installer.

For a plain first-time vendor/third-party installer, package-manager command, or
short script, use the ordinary installation workflow. After repeated
interruptions, move to `ai` when rerunning would redo completed work, even if the
user did not name the tool. A single installer error is an ordinary debugging
task; it does not by itself establish a need for `ai`. Caching overhead and
on-disk snapshots are not worth adding when rerunning everything is cheap.

## The mental model (read this before authoring)

Three ideas explain everything the tool does:

1. **Each non-comment logical line is one step.** Steps are the unit of caching.
2. **Cache keys are chained (Dockerfile-style).** A step's key folds in the
   previous step's key:
   ```
   key[i] = sha256(key[i-1] + "\n" + normalized(step[i].text))
   ```
   So **editing step _i_ invalidates step _i_ and everything after it**, while
   steps `0..i-1` stay cached. Appending new steps at the end re-uses all earlier
   caches. This is why **step order matters** — see "Order steps for cache reuse".
3. **Environment carries across steps, even cached ones.** `cd` and `export`
   persist between steps because after each success `ai` snapshots the *delta* it
   made to the environment and working directory. When a cached step is skipped,
   its delta is replayed, so later steps still see the right `$VARS` and `pwd`
   even though the step didn't actually re-run.

Only step **text** feeds the hash. Comments and blank lines are stripped before
hashing, so reformatting or rewording a comment **never** busts the cache.

## Authoring a manifest

Write commands one logical step per line. Give the file its **native shell
extension** (`.sh` on Linux) so it stays a runnable bash script. The parsing rules:

- **One logical line = one step.** A trailing `\` continues a line, so a single
  step can span physical lines:
  ```bash
  echo "downloading..." && \
    curl -fsSL https://example.com/x.tar.gz -o x.tar.gz && \
    tar xzf x.tar.gz
  ```
- **Comments (`# ...`) and blank lines are ignored** and never affect the cache.
- **Multi-line shell constructs must be wrapped in a block.** An `if`, `for`,
  `while`, `case`, or heredoc spans several lines that together form *one* step —
  collapse them with `#ai >>>` … `#ai <<<`:
  ```bash
  #ai >>>
  if ! command -v node >/dev/null; then
    curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
    sudo apt-get install -y nodejs
  fi
  #ai <<<
  ```
  Without the block, each physical line would be parsed as its own step and the
  construct would break. **Whenever you write a multi-line construct, wrap it.**
- **`#ai: always`** marks the *next* step to run on every invocation, even when
  everything else is cached. Use it for effects that don't gate later steps —
  logging, banners, timestamps, "current status" echoes.
- **`#ai: name <label>`** attaches a human-readable label to the next step, which
  shows up in `ai status` / `ai plan` output. Helpful for long manifests.

Directives attach to the next *step*, not the next *line* — intervening comments
and blanks are fine. Unknown `#ai:` directives are a hard error, as is an unclosed
`#ai >>>` block, so the only directives that exist today are `always` and `name`.

### Order steps for cache reuse

Because editing a step invalidates everything downstream, **put the stable,
slow-changing steps first and the volatile ones last.** Concretely:

- System packages and toolchain installs (rarely edited) go near the top.
- The line you're most likely to tweak (a build flag, a repo URL, an app-specific
  command) goes as late as possible, so editing it doesn't throw away the
  expensive earlier layers.
- Prefer appending new steps at the end; that re-uses every existing cache.

This is the single highest-leverage authoring decision — it's the difference
between a re-run that resumes near the end and one that rebuilds half the script.

### Starter template

A ready-to-edit manifest lives at `assets/template.sh` in this skill — copy it and
adapt rather than writing from scratch. It demonstrates a block step, a backslash
continuation, env carry-over, and an `#ai: always` step.

## Running a manifest

```bash
bash install.sh        # plain native run, no caching (the #ai markers are comments)

ai run    install.sh   # execute with caching; cached steps are skipped
ai status install.sh   # show which steps are cached vs pending
ai plan   install.sh   # dry-run: parsed steps + cache keys, nothing executed
ai clean  install.sh   # forget cached progress for this manifest
```

Start with `ai plan` to confirm the steps parsed the way you intended (this is the
fastest way to catch a multi-line construct that wasn't wrapped in a block — it'll
show up as several broken steps). Then `ai run`.

### The resume-after-failure workflow

This is the whole point of the tool, so lean into it:

1. `ai run install.sh` executes steps in order, printing `RUN` / `CACHED` per step.
2. On the **first failing step**, `ai` stops and tells you which step and the exit
   code. Everything before it is now cached.
3. **Fix the cause** (install the missing dependency, correct the command, set the
   env var) and run **the same `ai run install.sh` again**. Cached steps are
   skipped and execution resumes exactly at the step that failed.

Do **not** reach for `--no-cache` or `ai clean` after a normal failure — that
throws away good progress and defeats the purpose. Only rebuild from scratch when
the cached *state on the machine* is actually wrong (see Caveats).

### `ai run` flags

- `--no-cache` — ignore existing cache for this run (still records fresh results).
- `--from N` — force re-run from step _N_ (1-based) onward.
- `--workdir DIR` — starting directory (default: the manifest's own directory).
- `--shell PATH` — shell used to run steps (default: `$AI_SHELL` or `/bin/bash`).
- `--no-env-snapshot` — run each step as an independent subprocess; `cd`/`export`
  no longer carry across steps. Use this if you'd rather not persist env snapshots
  to disk (see secrets caveat below).

Cache lives under `~/.cache/anchored-install/<manifest-id>/` (mode `0700`), one
snapshot file per succeeded step.

## Caveats & gotchas (warn the user about the relevant ones)

- **Success is trusted — the cache is the state.** anchored-install has no "is it
  actually installed?" check; a step that exited 0 is considered done forever. If
  an external effect is later undone by hand (someone removes the package you
  installed), `ai` still skips that step. Rebuild with `ai clean` or
  `ai run --no-cache` when the real machine state has drifted from the cache.
- **`#ai: always` steps re-run but their text is unchanged**, so their cache key —
  and every downstream key — is identical. Downstream steps may still be served
  from cache. Use `always` only for effects that don't gate later steps (logging,
  banners), not to force a real rebuild.
- **A failing `&&`/`||` list at the end of a step is a failure.** A standalone
  step like `grep pattern file` (or any `&&` chain) whose final command returns
  non-zero stops the run. If a non-match is acceptable, append `|| true`.
- **Env snapshots touch disk and can contain exported secrets.** They're written
  under a `0700` cache dir, but if a step does `export TOKEN=...`, that value is
  persisted in the snapshot. Use `--no-env-snapshot` when that's a concern (you
  lose `cd`/`export` carry-over in exchange).

## Constraints

- Requires **Python ≥ 3.8** and a POSIX shell (`/bin/bash` by default). Zero
  third-party dependencies — pure standard library.
- Tested on **Ubuntu with bash**. Other shells/platforms (and parallel steps,
  remote/container backends, Windows/PowerShell, manifest `include`/templating)
  are planned but **not yet available** — don't promise them.
- Install with `pip install anchored-install` (provides both the `ai` and
  `anchored-install` commands).

