-
Notifications
You must be signed in to change notification settings - Fork 0
harnessed update
harnessed update scans the active catalog for outdated pins and offers to bump them in place.
It writes the new version strings directly into recipe.yaml (for tools: entries) or reports
unresolvable pins for manual review. It never builds or launches anything — verification is a
separate, explicit step after accepting a bump.
Two categories of pins are discovered across every recipe in the catalog:
Resolvable tools: entries. Each entry is resolved against its backend:
| Spec prefix | Backend | Registry consulted |
|---|---|---|
npm:<pkg>@<ver> |
npm | registry.npmjs.org |
github:<owner>/<repo>@<ver> |
GitHub releases | api.github.com/repos/<owner>/<repo>/releases |
<tool>@<ver> (bare) |
mise | mise's own tool registry |
pipx:<pkg>@<ver> |
PyPI | pypi.org/pypi/<pkg>/json |
When a newer version is available and old enough (see below), harnessed update offers to rewrite
the tools: entry.
Opaque pins in scripts and Dockerfiles. Pins buried inside install.sh or a recipe
Dockerfile — typically VARIABLE=v1.2.3 assignments or GitHub archive refs — are extracted by
pattern but have no queryable backend. They are reported as unresolved with their current value
and the file location; they are never bumped automatically. Update them by hand, then re-run
harnessed update to verify nothing was missed.
A release younger than the minimum age window is not offered, even if it is the newest version.
This mirrors pnpm's minimumReleaseAge (same unit: minutes). The default is 7 days (10080
minutes) — chosen because a compromised or broken publish is typically yanked within days, and
declining to install anything younger closes that window at zero cost.
Unlike a naive gate, a too-fresh newest release does not mean "no update": the newest version that is old enough is offered instead, and the newer-but-too-fresh version is named alongside it so you know it exists.
tools: [npm:context-mode@1.0.169] — current
latest: 1.0.175 (3 days old — skipped by release-age gate)
offered: 1.0.173 (9 days old) ← this is what the command offers
Override the window with --minimum-release-age <minutes>. Pass 0 to disable the gate entirely.
A pin can be marked hold — listed for information but never entered into the bump set and never
counted by --check. Two hold sources:
-
install.hold: "<reason>"on a recipe'sinstall:block — holds all pins fetched by that install script. - The map form of a
tools:entry with ahold:key.
The motivating case is skill content: a skill is agent instructions executed with the agent's full
tool permissions. A compromised upgrade is prompt injection, not a CVE — nothing in osv/grype/trivy
detects it, and a human must read the diff before accepting it. The hold: reason string is shown
alongside the newer version so whoever decides whether to lift it has the context.
Held pins are always listed, never silently dropped:
HELD: superpowers/install.sh SUPERPOWERS_VERSION=v6.0.3 → v6.1.0
reason: skill content — prompt injection risk; review the diff before lifting
harnessed update # interactive — prompts for each offered bump
harnessed update --yes # accept every bump without prompting
harnessed update --check # CI mode: report and exit non-zero if any pin is outdated
harnessed update --minimum-release-age 0 # disable the age gate (all newest versions offered)
harnessed update --minimum-release-age 2880 # 2-day window instead of 7
--check writes nothing to disk. It exits non-zero when any resolvable, non-held pin is behind its
latest age-eligible release. CI runs this on a schedule — not as a PR gate — so a stale pin blocks
no PR and is surfaced as a scheduled job failure instead (harnessed-4xu).
harnessed update prints the exact commands to run after accepting bumps:
[INFO] Bumped: context-mode, ccstatusline
Affected stacks: claude_superpowers, claude_time
Verify before committing:
harnessed build claude_superpowers && harnessed test claude_superpowers
harnessed build claude_time && harnessed test claude_time
These commands are generated by update.affected_stacks and update.verify_commands. They cover
every stack in the active catalog that includes a bumped recipe. Run them before committing; an
unverified bump is worse than a stale pin.
The catalog is under the worktree → tests → PR rule (see CLAUDE.md). A bumped-pin commit is a code change like any other.
pnpm's minimumReleaseAgeExclude (per-package opt-out of the age gate) has no equivalent in
harnessed update yet. harnessed-69k tracks the open work. For now, use
--minimum-release-age 0 to bypass the gate for the whole run, or accept the offered intermediate
release and update to the newest manually after inspection.
-
src/harnessed/update.py— the resolver and report logic. -
src/harnessed/launcher.py—update_pinscommand entry point (search@app.command("update")). -
Recipe authoring —
tools:field andinstall.hold.
Start Here
Guides
- Recipe authoring
- Service authoring
- Stacks
- Extending stacks (proposed)
- Recipe catalog
- System prompt & rules (proposed)
- Secrets
- AWS SSO
- Pulumi (host login forwarding)
- Egress & exposing services
- Container filesystem
- Git hooks
- Troubleshooting
- Pin management (harnessed update)
Codebase Map
Planning & Roadmap
- open work: GitHub Issues
Research & Prompts
- research/ (home-folder requirements per harness, browse in-repo)
- prompts/ (reusable prompt templates, browse in-repo)