ashlr-update

ashlr-update is a command for coding agents from ashlrai/ashlr-plugin. It costs 19 tokens per session (1,653 once invoked), scanned A, original, MIT.

A command that updates an installed ashlr-plugin from its Git repository. Git is a system for tracking project files and their history.

In plain words
What is it for?
Use it to update a development, legacy, or cached installation, or to identify when reinstalling is required.
Why use it?
It finds the plugin's actual installation location and updates it in place when it is installed as a Git checkout.

Command

Installs and runs on its own, but its text points at files inside its plugin — anything it tells you to read at a ${CLAUDE_PLUGIN_ROOT} path is only there once the plugin is installed. Installing the plugin gets both.

Part of the ashlr plugin — 11 skills, 36 commands, 5 agents, 7 hooks, 1 MCP server shipped together

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add commands/ashlrai/ashlr-plugin/ashlr-update
Clone the repo
git clone --depth 1 https://github.com/ashlrai/ashlr-plugin

Or install ashlr, the plugin that ships this one along with the rest of its 11 skills, 36 commands, 5 agents, 7 hooks, 1 MCP server.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for ashlr-update

README.md
[![agentmods](https://agentmods.dev/badge/commands/ashlrai/ashlr-plugin/ashlr-update.svg)](https://agentmods.dev/commands/ashlrai/ashlr-plugin/ashlr-update)
Your own site
<a href="https://agentmods.dev/commands/ashlrai/ashlr-plugin/ashlr-update"><img src="https://agentmods.dev/badge/commands/ashlrai/ashlr-plugin/ashlr-update.svg" alt="Measured on agentmods" height="20"></a>
Per session 19 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 1,653 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00019 $0.01653
Opus 5 $0.00010 $0.00826
Sonnet 5 $0.00004 $0.00331
Haiku 4.5 $0.00002 $0.00165

Measured 3d ago against content hash 595b581cfec1, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

ashlr-update scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 3d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

commands/ashlr-update.md · 156 lines

How it starts

The opening of the file, as written. The whole thing — 156 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Update the installed plugin in place.

The install location differs by Claude Code version:

  • New layout (most users): ~/.claude/plugins/cache/<marketplace>/ashlr/<version>/
  • Legacy layout: ~/.claude/plugins/ashlr-plugin/
  • Dev install: $CLAUDE_PLUGIN_ROOT (set when running from a local checkout)

Resolve the actual path before doing anything else.

Steps:

  1. Resolve the install path. Run via Bash, picking the first candidate that is a git checkout:

    PLUGIN_DIR=""
    for candidate in \
      "${CLAUDE_PLUGIN_ROOT:-}" \
      "$HOME/.claude/plugins/ashlr-plugin" \
      "$(ls -d $HOME/.claude/plugins/cache/*/ashlr/*/ 2>/dev/null | tail -1)"; do
      [ -z "$candidate" ] && continue
      if [ -d "$candidate/.git" ]; then PLUGIN_DIR="$candidate"; break; fi
    done
    echo "PLUGIN_DIR=$PLUGIN_DIR"
    
    • If PLUGIN_DIR is empty, tell the user: "ashlr-plugin is not installed as a git checkout. Re-run /plugin marketplace add (or reinstall from the marketplace) to upgrade, then restart Claude Code." Stop here.
    • If multiple cache directories exist (old 0.7.0/ plus a newer versioned dir), the tail -1 picks the most recent lexicographically — which is usually correct. If that turns out wrong, pass the path yourself.
  2. Capture the pre-update SHA:

    git -C "$PLUGIN_DIR" rev-parse --short HEAD
    
  3. Pull and reinstall. Run as a single bash block so the auto-recovery logic stays atomic:

    git -C "$PLUGIN_DIR" fetch --quiet 2>&1
    PULL_OUT=$(git -C "$PLUGIN_DIR" pull --ff-only 2>&1)
    PULL_RC=$?
    
    if [ $PULL_RC -ne 0 ] && echo "$PULL_OUT" | grep -q "would be overwritten by merge"; then
      # Conflict shape: "Your local changes to the following files would be
      # overwritten by merge:" + tab-indented file list + "Please commit ...".
      # Extract the file list, then split into:
      #   SAFE   — files that are gitignored at the upstream HEAD post-pull
      #            (proof the project no longer tracks them — runtime mutations
      #            are pure cruft, safe to discard)
      #   UNSAFE — anything else (real source-file conflicts the user must
      #            resolve themselves)
      CONFLICTS=$(echo "$PULL_OUT" | awk '/would be overwritten/{flag=1; next} /^Please/{flag=0} flag' | sed 's/^[[:space:]]*//' | sed '/^$/d')
      UPSTREAM_IGNORE=$(git -C "$PLUGIN_DIR" show "@{u}:.gitignore" 2>/dev/null)
    
      SAFE=""
      UNSAFE=""
      while IFS= read -r f; do
        [ -z "$f" ] && continue
        if echo "$UPSTREAM_IGNORE" | grep -qFx "$f"; then
          SAFE="$SAFE $f"
        else
          UNSAFE="$UNSAFE $f"
        fi
      done <<< "$CONFLICTS"
    
      if [ -n "$UNSAFE" ]; then
        echo "$PULL_OUT"
        echo ""
        echo "Files with local changes that aren't safe to auto-discard:"
        for f in $UNSAFE; do echo "  $f"; done
        echo ""
        echo "Resolve manually, then re-run /ashlr-update."
        exit 1
      fi
    
      echo "Auto-resetting runtime-only files (now gitignored upstream):"
      for f in $SAFE; do echo "  $f"; done
      git -C "$PLUGIN_DIR" checkout -- $SAFE
      git -C "$PLUGIN_DIR" pull --ff-only 2>&1 | tail -5
    elif [ $PULL_RC -ne 0 ]; then
      echo "$PULL_OUT"
      exit 1
    fi
    
    (cd "$PLUGIN_DIR" && bun install 2>&1 | tail -3)
    
    # Refresh ~/.ashlr/last-project.json so the next MCP tool call sees the
    # current project, not whatever stale value the SessionStart hook last
    # wrote (could be hours/days old, pointing at a different project). Without
    # this, even a successful pull leaves ashlr__read/grep/edit refusing every
    # call against the user's actual cwd until they restart Claude Code.
    if [ -n "${CLAUDE_PROJECT_DIR:-$PWD}" ]; then
      CLAUDE_PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}" \
        bun -e 'import("./hooks/session-start").then(m => m.writeProjectHint())' \
        --cwd "$PLUGIN_DIR" 2>/dev/null || true
    fi
    

    Why the auto-recovery: the plugin's own genome subsystem (PostToolUse genome-auto-propose + SessionEnd consolidator) appends to runtime files inside the plugin checkout. When the upstream commit moves those files into .gitignore, any locally-mutated copy will block git pull --ff-only even though the content is throwaway hook output. The whitelist is "in upstream's .gitignore" — that's the project's explicit signal that the file is not source content. Anything outside that whitelist still surfaces verbatim, so real conflicts (a user's hand-edits to the plugin code) never get clobbered.

Read the full file on GitHub · 156 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 3d ago First seen · 156 lines · 19 tokens per session scan A 595b581cfec1

Subscribe to this mod's changes

ashlr-update is a command published in the GitHub repository ashlrai/ashlr-plugin (3 stars, last pushed 3d ago), licensed MIT. It adds 19 tokens to every session and 1,653 once invoked, about $0.0001 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.