A

Autonomous Agents Agentic Workflow

Self Update — Autonomous Agents Agentic Workflow

Sync every repo in a workspace, upgrade the SideButton CLI, and reinstall skill packs

Available free v1.32.0 Browser
$ sidebutton install agents
Download ZIP
ops

Operational housekeeping that brings one agent and its workspace fully back in sync with upstream. It walks every git repository in the selected workspace (its entry path), resets each to its remote default branch, runs sidebutton registry update so the account's knowledge-pack registry picks up any pushed modules, and runs sudo sb-self-update to bring the agent's own SideButton install up to date.

Run it at the start of a shift, after an upstream release, or whenever an agent behaves as if it is running stale code or outdated knowledge. It is idempotent — already-current repos resolve to no change, and every update step is change-gated to a true no-op when nothing moved. Since KAN-205 it is also unattended-safe: a repo is only reset when its tree is clean, it sits on the remote default branch, it has an upstream it is not ahead of, and it hosts no linked worktree; anything else is left exactly as it is and reported as left: <reason>. Repos that meet all four conditions still lose nothing but already-pushed history, so the job remains a sync, not a rescue — unpushed work is preserved but not published.

sudo sb-self-update is a narrow root-owned wrapper provisioned by agent-runners and the only privileged action in the job. It does three change-gated things: upgrades the SideButton CLI/server to @latest (restarting only on a version change), refreshes the agent's base artifacts (Claude hooks, timers, helper scripts) from agent-runners, and reinstalls the universal agents ops pack from the catalog so default workflows added or changed since this agent was provisioned become dispatchable. On an agent that predates the wrapper the step is skipped with a notice rather than failing the run.

Steps

  1. 1.
    Open a terminal
    title
    Agent: Self Update
    cwd
    {{entry_path}}
    terminal.open
  2. 2.
    Run a terminal command
    cmd
    |
    terminal.run

Workflow definition

schema_version: 1
id: agent_self_update
title: "Self Update"
description: "Sync every repo in a workspace, upgrade the SideButton CLI, and reinstall skill packs"
overview: |
  Operational housekeeping that brings one agent and its workspace fully back in sync with upstream. It walks every git repository in the selected workspace (its entry path), resets each to its remote default branch, runs `sidebutton registry update` so the account's knowledge-pack registry picks up any pushed modules, and runs `sudo sb-self-update` to bring the agent's own SideButton install up to date.

  Run it at the start of a shift, after an upstream release, or whenever an agent behaves as if it is running stale code or outdated knowledge. It is idempotent — already-current repos resolve to no change, and every update step is change-gated to a true no-op when nothing moved. Since KAN-205 it is also unattended-safe: a repo is only reset when its tree is clean, it sits on the remote default branch, it has an upstream it is not ahead of, and it hosts no linked worktree; anything else is left exactly as it is and reported as `left: <reason>`. Repos that meet all four conditions still lose nothing but already-pushed history, so the job remains a sync, not a rescue — unpushed work is preserved but not published.

  `sudo sb-self-update` is a narrow root-owned wrapper provisioned by agent-runners and the only privileged action in the job. It does three change-gated things: upgrades the SideButton CLI/server to `@latest` (restarting only on a version change), refreshes the agent's base artifacts (Claude hooks, timers, helper scripts) from agent-runners, and reinstalls the universal `agents` ops pack from the catalog so default workflows added or changed since this agent was provisioned become dispatchable. On an agent that predates the wrapper the step is skipped with a notice rather than failing the run.

category:
  level: pipeline
  domain: engineering

metadata:
  agent: true
  role: ops

params:
  agentic_app:
    type: string
    default: "cc"
    description: "Agent-app slug selecting the per-run env file ~/.agent-env.d/<slug> (AAP-C); 'cc'/subscription clears provider vars"
  entry_path:
    type: string
    default: "~/workspace"
    description: "Workspace directory to sync"

steps:
  - type: terminal.open
    title: "Agent: Self Update"
    cwd: "{{entry_path}}"
  - type: terminal.run
    cmd: |
      source ~/.agent-env
      # AAP-C (SCRUM-1506) + AAP-17 (SCRUM-1653): clear EVERY provider var an agent-app can deliver so
      # none hijacks/poisons a subscription run. A stray global ANTHROPIC_MODEL / ANTHROPIC_SMALL_FAST_MODEL
      # needs no CLAUDE_CODE_USE_* flag, so the old ${!CLAUDE_CODE_USE_@} glob never caught it — it survived
      # into the run and 404-ed aux/small-fast calls against api.anthropic.com. This explicit list mirrors
      # AGENT_APP_ENV_KEYS 1:1 (the-assistant website/src/lib/cloud/agent-app-env.ts — the single source of
      # truth; a parity test in each repo guards the two from drifting). Explicit over a glob: the union has
      # non-ANTHROPIC_ members (AWS_REGION, AWS_PROFILE, CLOUD_ML_REGION, CLAUDE_CODE_MAX_OUTPUT_TOKENS) and
      # a ${!AWS_@} glob would over-clear unrelated creds. Then source the per-run app env by slug when it
      # exists; no file => subscription/default. base/19-secrets stages ~/.agent-env.d/<slug>.
      unset \
        ANTHROPIC_API_KEY ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN CCR_CONFIG_B64 \
        CLAUDE_CODE_USE_BEDROCK AWS_REGION AWS_PROFILE ANTHROPIC_MODEL \
        ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION ANTHROPIC_SMALL_FAST_MODEL CLAUDE_CODE_MAX_OUTPUT_TOKENS \
        CLAUDE_CODE_USE_VERTEX CLOUD_ML_REGION ANTHROPIC_VERTEX_PROJECT_ID ANTHROPIC_VERTEX_BASE_URL \
        CLAUDE_CODE_USE_FOUNDRY ANTHROPIC_FOUNDRY_RESOURCE ANTHROPIC_FOUNDRY_BASE_URL \
        ANTHROPIC_DEFAULT_OPUS_MODEL ANTHROPIC_DEFAULT_SONNET_MODEL ANTHROPIC_DEFAULT_HAIKU_MODEL
      if [ -f "$HOME/.agent-env.d/{{agentic_app}}" ]; then
        source "$HOME/.agent-env.d/{{agentic_app}}"
      fi
      claude --dangerously-skip-permissions "$(cat <<'SB_PROMPT'
      the current directory is your workspace. sync every git repo inside it to its remote default branch: for each, fetch, hard-reset to origin/main (or origin/master), and clean untracked files. then run `sidebutton registry update` to refresh the account knowledge-pack registry. then bring the agent's own SideButton install up to date: if `sb-self-update` exists, run `sudo sb-self-update` (one change-gated wrapper that upgrades the SideButton CLI/server to latest and restarts only on a version change, refreshes base artifacts from agent-runners, and reinstalls the universal `agents` ops pack from the catalog so newly published default workflows become dispatchable); if it does not exist, skip it and note it. report the SideButton version before and after, what `sb-self-update` changed (CLI / base artifacts / ops pack), and what changed in each repo.
      DECISION TABLE — evaluate this per repo BEFORE any destructive step; it overrides the sync instruction above wherever the two disagree. `git fetch --prune` is non-destructive and always runs, because the table needs accurate upstream data. Then, if ANY of these hold, leave that repo exactly as it is — no reset, no clean, no checkout, no stash — and report `left: <reason>`: the working tree is dirty, i.e. anything staged, modified or untracked => `left: dirty`; the current branch is not the remote default branch => `left: not default branch (<branch>)`; the branch holds commits its upstream does not => `left: diverged (N local commits)`; the branch has no upstream at all, or HEAD is detached => `left: no upstream`; `git worktree prune` followed by `git worktree list` still prints more than one entry => `left: worktree (<name>)`. Run that prune first and unconditionally: it only drops entries whose directory is already gone and never touches a live worktree, its branch or its commits, and without it a single scratch worktree deleted with `rm -rf` instead of `git worktree remove` lingers as a `prunable` entry and pins the repo at `left: worktree` for ever. That hosting rule is keyed on the worktree list and NOT on the repo's own tree on purpose: a repo whose own checkout is clean and current can still host a linked worktree holding unfinished work, and hard-resetting the shared checkout is how that work is lost. Evaluate the two worktree cases in this order so exactly one token can apply: a folder that is ITSELF a linked worktree (its `.git` is a file, not a directory) is never synced as though it were an independent repo => `left: worktree`, and the hosting rule is then not considered for it at all; every other folder takes the hosting rule above. Only a repo that trips none of these is hard-reset to its remote default branch and cleaned. If a fetch itself errors, report `left: fetch failed (<error>)` and continue with the remaining repos — never force a failed fetch into one of the other outcomes. The report must name EVERY repo you left alone and the reason for each. `sidebutton registry update` and `sudo sb-self-update` are the steps this job exists to run: execute them without confirming, whatever the table decided about the repos.
      UNATTENDED RUN — this is a dispatched job: nobody is watching this terminal and nobody will answer, so never call AskUserQuestion and never end your turn by putting a question to the operator. Apply the policy stated above and carry it out as written, including where carrying it out is destructive — the call to run this job was made when it was dispatched, and it is not yours to re-take. Where that policy leaves a genuine choice, make it yourself and keep going; only where it is genuinely SILENT, prefer the option that does not destroy work nobody can recreate. Say what you decided and what you skipped and why — but INSIDE the report this prompt already specifies: wherever a report shape, a token vocabulary or a last-line verdict is stated above, that format still binds exactly as written, and this clause adds no section, no token and nothing after the last line. Questions the deliverable is MEANT to contain are content, not an unanswered prompt. Asking does not pause the job either: an unanswered prompt is auto-answered from the option ordering once the unattended wait budget lapses (KAN-204), so asking only burns ~15 minutes of the run and hands a real decision to a default.
      SB_PROMPT
      )"