Use when deploying updates to this machine: pull, sync deps, verify, restart services. Triggered by 'update', 'deploy', 'pull and restart', or after git pull.
Scanned 9/2/2026
Install to Claude Code
npx -y skills add tomcounsell/ai --skill update --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Update?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/tomcounsell-update)More formats (shields.io, HTML) on the badges page.
---
name: update
description: "Use when deploying updates to this machine: pull, sync deps, verify, restart services. Triggered by 'update', 'deploy', 'pull and restart', or after git pull."
disable-model-invocation: true
---
# Update & Restart
Bring this machine to latest main: deps synced, environment verified, services restarted and healthy. The orchestrator does the work — your job is to run it, read its output, and report every warning or error.
## Instructions
**PREREQUISITE: Must be on latest main branch before running.**
```bash
cd ~/src/ai && git checkout main && git fetch origin main && git merge --ff-only origin/main
```
Fetch-then-merge-a-named-ref rather than `git pull` (#2650): `.git/FETCH_HEAD` is shared by every worktree of the repo, so with concurrent lanes on this machine a peer's fetch can retarget a bare pull's merge.
If there are local changes, stash them first: `git stash`. The update orchestrator also handles this, but being on main is required.
Run the full update orchestrator and report the results:
```bash
cd ~/src/ai && .venv/bin/python scripts/update/run.py --full
```
The orchestrator will:
- Pull latest changes (with automatic stash/unstash)
- Sync `.claude` hardlinks and audit skill hooks
- Check for pending critical dependency upgrades; sync dependencies if pyproject.toml changed; verify critical versions
- **Verify machine identity** — reads `scutil --get ComputerName`, matches against the `machine` field in `~/Desktop/Valor/projects.json`, reports which projects this machine handles
- Check/pull Ollama summarizer model; verify CLI tools and SDK authentication
- **Validate `projects.json` (green-light gate)** — runs `bridge/config_validation.py::validate_projects_config` over the full config (Step 4.6). Enforces that every bridge-contact identifier (DM contact id, Telegram group, email contact, email domain wildcard) resolves to exactly one machine. On failure: log the error, skip the service restart, leave the running bridge serving on the previously-validated config. See [Single-Machine Ownership](../../../docs/features/single-machine-ownership.md).
- Install/restart services (skipped if the validation gate failed): bridge, worker, the reflection-scheduler subprocess (`com.valor.reflection-worker` — installed right after the worker so at most a brief zero-scheduler window; issue #1828), nightly-tests, caffeinate, and log-rotate
- Set up global calendar hook and generate config; verify MCP server registration (memory Step 4.8, BYOB Step 4.9 — idempotent, self-healing)
- **Best-effort agent-judgment catchup (strictly last step)** — see below
After running, report the result. List every warning or error clearly.
**Warning channel (#2845):** the `--cron` summary format (`up to date at <sha> (N warnings)` / `update failed at <sha>` plus their bullets) is what both the Telegram reply and any auto-spawned fix session detect against — not a handful of legacy prefixes. `gws auth` and `env-completeness` warn once per state transition rather than every cycle (via `warn_state`); when any of those are currently suppressed, a `suppressed: ...` line appears in the reply naming them, with `python -m scripts.update.warn_state` and a full (non-`--quick`) `python -m tools.doctor` run as the on-demand answers for what is suppressed right now. See [`/update Warning Channel`](../../../docs/features/update-warning-channel.md) for the full producer/consumer contract.
**First-install backfill reminder (markitdown):** the first run that installs the `[knowledge]` extra appends a one-time tip to the Telegram summary: `run 'valor-ingest --scan ~/work-vault/' to backfill existing binary files into sidecars` (gated by `~/.cache/valor/markitdown-backfill-reminded`). If the user asks why pre-existing vault PDFs/docs aren't indexed, point them at that command — the watcher only picks up files modified after it starts.
**Log rotation:** every `--full` run installs the user-space LaunchAgent `com.valor.log-rotate.plist` (content-idempotent, no sudo) which rotates any `logs/*.log` over 10 MB every 30 minutes. A stale root-era `/etc/newsyslog.d/valor.conf` is removed via non-interactive `sudo -n rm`; if sudo needs a password, cleanup is skipped with a warning and retried next run.
**Obsolete launchd-job sweep (Step 1.56):** every run boots out and deletes LaunchAgents for features that have been fully removed from the codebase, so a deleted feature's plist doesn't keep loading and failing on already-provisioned machines forever. The list of removed jobs lives in `scripts/update/service.py::OBSOLETE_SERVICE_SUFFIXES` — this is the launchd analog of `RENAMED_REMOVALS` in `hardlinks.py`: **when you delete a launchd-backed feature (its install script + code), add its label suffix there** so `/update` cleans up the stale job on every machine. The sweep is idempotent and fail-soft (a machine that never had the job is a no-op); removals are logged and reported in the run summary. Runs unconditionally alongside the plist-PATH heal (Step 1.55), not gated on the service-restart step.
**Session cleanup (Step 5.5):** corrupted sessions are deleted and indexes rebuilt; running/pending sessions older than 120 min with no live process transition to `killed`; terminal sessions are preserved for reflections (which handles its own 90-day expiry).
### Agent-Judgment Catchup (strictly last step)
The **final** action of `run_update` invokes the `valor-catchup` CLI (issue #1709, see [Agent-Judgment Catchup](../../../docs/features/agent-judgment-catchup.md)): it reads each owned chat's recent thread, asks an LLM judge which inbound human messages are genuinely unanswered, and enqueues recovery sessions only for those.
**Best-effort contract — the step never blocks or fails `/update`:**
- **Health gate.** Runs only when BOTH bridge and worker report running AND `do_service_restart` is set (verify-only and follower-skip runs never trigger recovery enqueues). Otherwise it logs `catchup: skipped — ...` and returns.
- **Subprocess + tight timeout.** Runs as a subprocess with `CATCHUP_STEP_TIMEOUT_SECONDS` (90s); a hung Telethon connect or stalled LLM call is killed on expiry.
- **Failure swallowed.** Any failure, non-zero exit, or timeout is logged (`catchup: ... (swallowed)`) and never flips `UpdateResult.success`.
The CLI propagates via `pip install -e .` during the dependency-sync step (`[project.scripts]` entry) — no extra wiring.
### Auto-Bump Critical Dependencies
Every run checks PyPI for newer `anthropic` and `claude-agent-sdk` versions (only the lockfile-maintainer machine runs auto-bump; others skip to avoid racing). When a newer version is available:
1. Bumps the pin in `pyproject.toml`
2. Runs `uv sync` to install the new version
3. Runs a smoke test (import check + `pytest tests/unit/test_docs_auditor_substrate.py -x -q`)
4. If smoke test passes: commits and pushes the bump
5. If smoke test fails: rolls back `pyproject.toml` and re-syncs old versions
### Critical Dependency Handling (git-driven changes)
When `pyproject.toml` changes via git pull with critical dep version changes (telethon, anthropic, claude-agent-sdk), the cron job (`remote-update.sh`) writes `data/upgrade-pending`; running `/update` manually applies the upgrade with proper verification.
If `data/upgrade-pending` exists:
```bash
# Check what's pending
cat ~/src/ai/data/upgrade-pending
# After /update applies the upgrade and verifies the bridge starts:
rm ~/src/ai/data/upgrade-pending
```
### Verification Only
To check the environment without making changes:
```bash
cd ~/src/ai
.venv/bin/python scripts/update/run.py --verify
```
### Reinstall Launchd Services
After update, reinstall launchd plists to pick up any template changes. The reflection scheduler runs in its own launchd subprocess (`python -m reflections`, label `com.valor.reflection-worker`) — out-of-process from the worker since issue #1828 — so three installers cover the set:
```bash
cd ~/src/ai
./scripts/install_worker.sh
./scripts/install_reflection_worker.sh
./scripts/install_sdlc_reflection.sh
```
`install_reflection_worker.sh` self-gates on worker role (any project's `machine` matches this host; fail-open) and removes its stale plist on non-worker machines. Verify with `python -m reflections --dry-run` (loads the registry, exits 0) and `tail -f logs/reflection_worker.log`. Install scripts substitute `__PROJECT_DIR__` and `__HOME_DIR__` placeholders, so plists work on any machine without hardcoded usernames.
## When to Load Sub-Files
| Sub-file | Load when... |
|----------|-------------|
| `references/troubleshooting.md` | An update run fails or the environment misbehaves afterward (venv, deps, calendar, machine identity, bridge/worker/reflection-scheduler won't start) |
| `references/modules.md` | Debugging orchestrator internals or calling a `scripts/update/` module directly (git.py, deps.py, verify.py, gws_auth.py, calendar.py, MCP registration, service.py) |
## Node toolchain (soft prerequisite)
Machines that run the `do-design-system` skill also need Node + npm (for `npx @google/design.md`). `remote-update.sh` runs `npm ci --omit=dev` guarded by:
```bash
if [ -f "$PROJECT_DIR/package.json" ] && command -v npm >/dev/null 2>&1; then
( set +o pipefail; cd "$PROJECT_DIR" && npm ci --omit=dev ) \
|| echo "[update] npm ci failed (non-fatal); continuing"
fi
```
The non-pipefail subshell + `|| echo` trailer guarantee a missing `npm` or a transient install failure never aborts the parent update. Machines without Node skip the block silently; design-system tooling falls back to Python-only emission (`--generate --no-node`). Lint and DTCG / Tailwind exports still require Node. See `docs/features/design-system-tooling.md`.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!