attckdigital/smith/smith-update

Claude Code and agent skill by attckdigital/smith

Trust tier 2
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Update Smith to the latest upstream version. Compares the installed commit SHA against https://github.com/ATTCKDigital/smith main, prompts to update if behind, and refreshes global install (~/.claude/skills, ~/.claude/hooks, ~/.smith) plus per-project artifacts (.specify/scripts, .claude/commands/smith.*, CLAUDE.md / constitution.md via migrate-templates, optional manifest sidecar bootstrap). Workflow-gate compliant.

Install

npx vskill@latest install attckdigital/smith/smith-update

SKILL.md

Smith — Update to Latest

End-to-end skill for keeping Smith up to date. Detects local-vs-upstream commit drift, prompts to update, and runs the existing installer plus per-project refresh steps when invoked inside a Smith-initialized project.

Arguments: $ARGUMENTS (no positional args; reserved for future flags like --check / --no-project)

When to Use

  • "is smith out of date?" / "update smith" / "let's update smith"
  • After learning of a new Smith feature you want to adopt
  • After an old project's .smith/index/ was generated against an earlier manifest schema and needs regeneration

Vault Logging

Throughout this action, log significant events to the vault session log. Read the session log path from .smith/vault/.current-session. If the file is missing or the vault is not initialized, skip all logging silently.

Timestamps are UTC. HH:MM:SS comes from date -u +%H:%M:%S — never a local clock, never a time from memory. The append already runs through a shell, so read the clock in that same command (TS=$(date -u +%H:%M:%S)) and spend no extra tool call. Substitute the resulting value: an unexpanded $(...) reaching the log is a known regression and will not parse. Every hook-written stamp in this log is date -u, so a local-clock entry lands hours away from its neighbours and skews the workflow window hooks/workflow_summary_lib.py derives from them.

Format:

### [HH:MM:SS] /smith-update <event>
**User Request:**
> <verbatim user message that triggered this action>
**Synthesized Input:** <brief summary>
**Outcome:** <what happened>
**Artifacts:** <files created/modified>
**Systems affected:** smith-update (smith-repo distribution)

Log at: invocation, after version detection (with SHAs + commits-behind), after global update, after per-project update, on completion.

Natural Language Triggers

If the user says any of these (or similar), treat as invoking this command:

  • "update smith"
  • "let's update smith"
  • "is smith out of date"
  • "smith is behind"
  • "pull the latest smith"

Phase 0: Activate Workflow Tracking (Workflow-Gate Compliance)

/smith-update writes many files: install.sh's destructive cp -R of skills, the version file, settings.json merge, per-project script copies, etc. The PreToolUse workflow-gate hook (PR #20) would deny all of these without an active marker. So create the marker first.

Skip if no `.smith/` directory exists in the current working directory (the gate naturally exits silent in that case per PR #20, so no marker is needed). Otherwise create the marker via the shipped helper — the gate exempts create-active-workflow.sh by basename (per spec/31-workflow-gate-bootstrap) and deliberately blocks raw redirection into active-workflows/ to prevent forged markers, so a cat > marker.yaml heredoc here would be DENIED when no marker exists yet:

bash
TS=$(date -u +"%Y-%m-%dT%H-%M-%SZ")
PROJECT_DIR=$(pwd)
if [ -d "$PROJECT_DIR/.smith" ]; then
~/.smith/scripts/create-active-workflow.sh \
--branch "update-${TS}" \
--workflow smith-update \
--slug "update-${TS}" \
--worktree "$PROJECT_DIR"
# (Falls back to scripts/create-active-workflow.sh in repo-dev layouts.)
# remember marker path for cleanup at end
MARKER_PATH="$PROJECT_DIR/.smith/vault/active-workflows/update-${TS}.yaml"
fi

The marker is removed in Phase 6 cleanup (or on exit-with-no-changes paths). Use the shipped helper so it works under a Bash(rm:*) deny rule:

bash
[ -n "${MARKER_PATH:-}" ] && [ -f "$MARKER_PATH" ] && \
"$PROJECT_DIR/.specify/scripts/bash/clear-active-workflow.sh" "update-${TS}" 2>/dev/null || true

Phase 1: Detect Upstream and Installed Versions

bash
UPSTREAM_REMOTE="https://github.com/ATTCKDigital/smith.git"
SMITH_HOME="$HOME/.smith"
VERSION_FILE="$SMITH_HOME/.installed-version"
# Upstream SHA (network call — graceful on failure per Q4)
UPSTREAM_OUT=$(git ls-remote "$UPSTREAM_REMOTE" refs/heads/main 2>&1)
if [ $? -ne 0 ]; then
echo "Unable to reach upstream — $UPSTREAM_OUT" >&2
# cleanup marker, exit cleanly
exit 0
fi
UPSTREAM_SHA=$(echo "$UPSTREAM_OUT" | awk '{print $1}')
# Installed SHA (per Q2-D: handle absent file by establishing baseline)
if [ -f "$VERSION_FILE" ]; then
INSTALLED_SHA=$(cat "$VERSION_FILE" | tr -d ' \n\r')
else
# First invocation since /smith-update shipped. Establish baseline silently.
mkdir -p "$SMITH_HOME"
echo "$UPSTREAM_SHA" > "$VERSION_FILE"
echo "Smith is up to date — version baseline established at ${UPSTREAM_SHA:0:7}."
# cleanup marker, exit
exit 0
fi

Phase 2: Compute Commits-Behind

Per Q5-A: gh first, shallow-clone fallback.

bash
COMMITS_BEHIND=""
if command -v gh >/dev/null 2>&1; then
COMMITS_BEHIND=$(gh api "repos/ATTCKDigital/smith/compare/${INSTALLED_SHA}...${UPSTREAM_SHA}" --jq '.ahead_by' 2>/dev/null)
fi
if [ -z "$COMMITS_BEHIND" ] || ! [[ "$COMMITS_BEHIND" =~ ^[0-9]+$ ]]; then
# Fallback: shallow-clone the upstream and use git rev-list --count.
TMPCLONE=$(mktemp -d -t smith-update-XXXXXX)
trap 'rm -rf "$TMPCLONE"' EXIT # extended at Phase 6 to include marker cleanup
if ! git clone --quiet "$UPSTREAM_REMOTE" "$TMPCLONE/smith" 2>/dev/null; then
echo "Unable to reach upstream — clone failed." >&2
exit 0
fi
COMMITS_BEHIND=$(git -C "$TMPCLONE/smith" rev-list --count "${INSTALLED_SHA}..${UPSTREAM_SHA}" 2>/dev/null || echo "?")
fi
# Up-to-date short-circuit
if [ "$COMMITS_BEHIND" = "0" ]; then
echo "Smith is up to date (commit ${UPSTREAM_SHA:0:7})."
exit 0
fi
# Prompt
echo "Smith is $COMMITS_BEHIND commits behind. Update? (y/n)"
read -r REPLY
case "$REPLY" in
[yY]|[yY][eE][sS]) ;;
*) echo "Update declined."; exit 0 ;;
esac

Phase 3: Snapshot (Q7-A Rollback Safety)

Before any destructive work, snapshot the global install state. On non-zero exit from install.sh, restore.

bash
BACKUP_ROOT="$SMITH_HOME/.backups"
BACKUP_DIR="$BACKUP_ROOT/update-${TS}"
mkdir -p "$BACKUP_DIR"
# Snapshot the three writable areas
cp -R "$HOME/.claude/skills" "$BACKUP_DIR/skills" 2>/dev/null || true
cp -R "$HOME/.claude/hooks" "$BACKUP_DIR/hooks" 2>/dev/null || true
cp "$HOME/.claude/settings.json" "$BACKUP_DIR/settings.json" 2>/dev/null || true
# GC: keep last 3 (Q7-A keep-last-N policy)
ls -t "$BACKUP_ROOT" 2>/dev/null | tail -n +4 | while read -r old; do
rm -rf "$BACKUP_ROOT/$old"
done
# Restore function — invoked if install.sh fails
restore_snapshot() {
echo "Update failed — restoring from $BACKUP_DIR" >&2
rm -rf "$HOME/.claude/skills" "$HOME/.claude/hooks"
cp -R "$BACKUP_DIR/skills" "$HOME/.claude/skills" 2>/dev/null || true
cp -R "$BACKUP_DIR/hooks" "$HOME/.claude/hooks" 2>/dev/null || true
cp "$BACKUP_DIR/settings.json" "$HOME/.claude/settings.json" 2>/dev/null || true
}

Phase 3.5: Stop a Running Activity Daemon

scripts/install.sh refreshes ~/.smith/scripts/activity/ in place. A daemon started by /smith-activity has already imported the old server.py, state.py and friends into a long-lived Python process; rewriting the files underneath it leaves a process running code that no longer exists on disk, and any module it imports lazily afterwards comes from the new tree. That mix is worse than either version alone, and it survives until something happens to restart it.

So: stop it before Phase 4, and do not restart it afterwards. An update silently bringing a background listener back up is exactly the surprise OOS-4 rules out — the operator started that daemon deliberately and is the one who decides it comes back.

bash
# Was a daemon running before we touched anything? Record it for the summary.
ACTIVITY_WAS_RUNNING=0
ACTIVITY_CLI="$SMITH_HOME/scripts/activity/smith-activity.sh"
ACTIVITY_PIDFILE="$SMITH_HOME/activity/activity.pid"
if [ -f "$ACTIVITY_PIDFILE" ]; then
ACTIVITY_PID=$(cat "$ACTIVITY_PIDFILE" 2>/dev/null)
if [ -n "$ACTIVITY_PID" ] && kill -0 "$ACTIVITY_PID" 2>/dev/null; then
ACTIVITY_WAS_RUNNING=1
echo "Stopping /smith-activity daemon (pid $ACTIVITY_PID) before refreshing its code..."
# Use the CLI so the pidfile, port file and token are cleaned up the
# same way a normal stop cleans them. Fall back to the signal only if
# the CLI is missing — a half-installed tree is exactly when this
# matters most.
if [ -x "$ACTIVITY_CLI" ]; then
"$ACTIVITY_CLI" stop >/dev/null 2>&1 || kill "$ACTIVITY_PID" 2>/dev/null || true
else
kill "$ACTIVITY_PID" 2>/dev/null || true
fi
fi
fi

With the daemon down, hooks/activity-emitter.sh is an unconditional no-op — no port file means it exits 0 before any network call — so nothing else in the update needs to know about it.

Phase 4: Global Update

Clone smith-repo to a temp dir (or reuse the one from Phase 2's fallback), run installer, write version file.

bash
if [ -z "${TMPCLONE:-}" ] || ! [ -d "$TMPCLONE/smith" ]; then
TMPCLONE=$(mktemp -d -t smith-update-XXXXXX)
trap 'rm -rf "$TMPCLONE"' EXIT
git clone --quiet "$UPSTREAM_REMOTE" "$TMPCLONE/smith"
fi
# Q1-D settings.json dedupe BEFORE running install.sh, so the installer's
# jq merge doesn't compound onto existing duplicates. Dedupe ONLY Smith-owned
# hook entries (those referencing ~/.claude/hooks/<known-name>.sh).
"$TMPCLONE/smith/scripts/dedupe-settings.sh" "$HOME/.claude/settings.json" 2>/dev/null || true
# Run the installer
if ! "$TMPCLONE/smith/scripts/install.sh" -y; then
restore_snapshot
echo "install.sh failed. Restored from snapshot at $BACKUP_DIR." >&2
exit 1
fi
# install.sh now writes $SMITH_HOME/.installed-version itself (this PR adds that),
# but write it again here defensively in case install.sh was pre-versioning.
echo "$UPSTREAM_SHA" > "$VERSION_FILE"

Phase 5: Per-Project Update (Conditional)

Only runs if $PROJECT_DIR/.smith/ exists. Refresh Smith-owned files; never touch user files; offer manifest bootstrap if .smith/index/ is absent.

5.1 Refresh .specify/scripts/bash/ and .claude/commands/smith.*

Smith-owned files. Safe to overwrite. Detect orphans first (Q6-A + Q8-B unified pass).

bash
if [ -d "$PROJECT_DIR/.smith" ]; then
# Collect orphans before copying new files.
UPSTREAM_SCRIPTS="$TMPCLONE/smith/skills/smith/scripts"
LOCAL_SCRIPTS="$PROJECT_DIR/.specify/scripts/bash"
ORPHAN_SCRIPTS=()
if [ -d "$LOCAL_SCRIPTS" ]; then
for f in "$LOCAL_SCRIPTS"/*; do
name=$(basename "$f")
[ -f "$UPSTREAM_SCRIPTS/$name" ] || ORPHAN_SCRIPTS+=("$name")
done
fi
UPSTREAM_CMDS="$TMPCLONE/smith/skills/smith/commands"
LOCAL_CMDS="$PROJECT_DIR/.claude/commands"
ORPHAN_CMDS=()
if [ -d "$LOCAL_CMDS" ]; then
for f in "$LOCAL_CMDS"/smith.*.md; do
[ -e "$f" ] || continue
name=$(basename "$f")
[ -f "$UPSTREAM_CMDS/$name" ] || ORPHAN_CMDS+=("$name")
done
fi
UPSTREAM_HOOKS="$TMPCLONE/smith/hooks"
LOCAL_HOOKS="$HOME/.claude/hooks"
ORPHAN_HOOKS=()
if [ -d "$LOCAL_HOOKS" ]; then
for f in "$LOCAL_HOOKS"/*.sh; do
[ -e "$f" ] || continue
name=$(basename "$f")
[ -f "$UPSTREAM_HOOKS/$name" ] || ORPHAN_HOOKS+=("$name")
done
fi

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
41
Repository forks
6
7-day trend score
19

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/attckdigital/smith/smith-update/badge)](https://verified-skill.com/skills/attckdigital/smith/smith-update)

Something wrong with this skill or its page? Tell us.