Skip to content

Self-update the plugin from its own SessionStart hook (PRDE-1161) - #10

Merged
Kshitij Jhunjhunwala (KJ-11) merged 1 commit into
masterfrom
kj/prde-1161-self-update
Jul 29, 2026
Merged

Kshitij Jhunjhunwala (KJ-11) merged 1 commit into
masterfrom
kj/prde-1161-self-update

Conversation

@KJ-11

Copy link
Copy Markdown
Contributor

What

A stale install of this plugin now converges to the latest published version within a day plus one session restart, with zero user or CLI involvement — the Claude Code/Codex "relaunch to update" model. The plugin owns its own freshness; the composio CLI is not involved (cross-artifact repair proposals were explicitly rejected on the ticket).

Linear: PRDE-1161

How

In session-start.sh, at most once per 24h (throttle state in ~/.composio/plugin-cc-self-update.json, stamped before running so it doubles as a poor-man's lock), a fully detached background job runs:

  1. claude plugin marketplace update composio — git-refreshes the marketplace checkout
  2. claude plugin update composio@composio — stages the newest cached version; active at next session launch

Constraints honored:

  • SessionStart has an 8s timeout and its stdout is parsed as JSON → the job is never waited on and has all fds redirected (( … ) >/dev/null 2>&1 </dev/null &). Hook latency is unchanged (~1.4s, dominated by the pre-existing auth/cache work).
  • claude plugin … subcommands don't fire hooks (verified with an instrumented hook) → no recursion.
  • Failure-silent everywhere: no claude binary, no network, read-only/corrupt/absent state file, unset HOME all degrade to "do nothing" without touching the hook's JSON output.
  • plugin.json bumped 0.2.3 → 0.2.4 (release-discipline CI from Enforce plugin version bumps in CI + tag releases on bump (PRDE-1152) #9).

One deviation from the plan: instead of comparing the marketplace checkout's plugin.json against the running version (the checkout's path differs between directory-source and git-source marketplaces), the job always runs claude plugin update, which does that comparison itself and no-ops locally with "already at the latest version" when current. Fewer failure modes, same behavior.

Verification (isolated home — CLAUDE_CONFIG_DIR=<scratch>, real ~/.claude untouched)

Premise checks:

  • Instrumented the hook with a firing marker; ran marketplace add, plugin install, marketplace update, plugin update → marker never appeared (no hook recursion).
  • Update-while-running: session on 0.2.4 stayed on 0.2.4; new version activates next launch.

End-to-end convergence ladder (scratch git clone as marketplace source):

  1. Installed 0.2.4 (this build) in the isolated home; advanced the marketplace to a 0.2.5 bump-only commit.
  2. Started a session (claude -p) → hook fired, emitted valid JSON, exited fast; the detached job survived the session process exiting (the session actually died immediately on a login error — the job still completed) and wrote {"lastAttempt":…,"lastResult":"updated"}; claude plugin list showed 0.2.5 staged.
  3. Second session → ran 0.2.5; throttle held (state file byte-identical, no re-attempt).

Adversarial battery (all emit valid hook JSON, all failure-silent):

  • No claude on PATH → no state file, nothing attempted.
  • Read-only ~/.composio → silent no-op.
  • Corrupt state file → treated as no-throttle, overwritten with valid JSON on next attempt.
  • Unset HOME → skipped.
  • Two simultaneous session starts, fresh state → state file valid JSON afterwards; worst case two idempotent runs (accepted on the plan).
  • Marketplace source unreachable (simulated no-network) → lastResult:"error", installed version untouched, retry naturally throttled to 24h.

shellcheck clean (it caught a real missing-argument bug in the state-write during development); make test green (49 unit tests + claude plugin validate on marketplace and plugin).

Bootstrap caveat (accepted on ticket): installs older than this release never gain self-update — one manual composio setup rerun; current pre-self-update base ≈ KJ.

🤖 Generated with Claude Code

A stale install now converges to the latest published version within a
day plus one session restart, with no user or CLI involvement: at most
once per 24h (state file ~/.composio/plugin-cc-self-update.json), a
fully detached background job runs `claude plugin marketplace update
composio` then `claude plugin update composio@composio`; the new version
activates at the next session launch.

The job is detached (never waited on, all fds redirected) because
SessionStart has an 8s timeout and its stdout is parsed as JSON.
`claude plugin ...` subcommands don't fire hooks, so no recursion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@KJ-11
Kshitij Jhunjhunwala (KJ-11) merged commit 7dfb14e into master Jul 29, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant