Skip to content

feat: add self-update command and auto-update infrastructure#224

Merged
nikomatsakis merged 12 commits into
symposium-dev:mainfrom
nikomatsakis:auto-update
May 14, 2026
Merged

feat: add self-update command and auto-update infrastructure#224
nikomatsakis merged 12 commits into
symposium-dev:mainfrom
nikomatsakis:auto-update

Conversation

@nikomatsakis
Copy link
Copy Markdown
Member

What does this PR do?

Add cargo agents self-update which downloads prebuilt binaries from GitHub releases (falling back to cargo install), and startup auto-update checks gated by a new auto-update config (off/warn/on, default warn). Introduce state.toml to track the binary version and throttle update checks to once per 24 hours.

New config keys:

  • auto-update: off | warn | on (default warn)
  • self-update-source: binary | source (default binary)
Disclosure questions

AI disclosure.

  • The AI tool authored large parts of the code

Questions for reviewers.

nikomatsakis and others added 2 commits May 14, 2026 06:33
Add `cargo agents self-update` which downloads prebuilt binaries from
GitHub releases (falling back to `cargo install`), and startup
auto-update checks gated by a new `auto-update` config (off/warn/on,
default warn). Introduce `state.toml` to track the binary version and
throttle update checks to once per 24 hours.

New config keys:
- `auto-update`: off | warn | on (default warn)
- `self-update-source`: binary | source (default binary)

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude <claude@anthropic.com>
Copy link
Copy Markdown
Member Author

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to setup some kind of test infra. I would like to have integration tests and show that e.g. the re-exec works mid-command and also with hooks. The question is how to set that up in a way that is "mockable". At the worst, we can have some kind of env variables or other test flags.

Comment thread src/bin/cargo-agents.rs Outdated
plugins::ensure_plugin_sources(&sym, cli.update).await;

// Auto-update check (skip for hooks and self-update itself).
if !is_hook
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior around hooks is an interesting question. I think we should execute the check but only for hooks but add the warning as guidance to the agent to suggest to the human to run self-update. We can do the auto updates as normal.

nikomatsakis and others added 7 commits May 14, 2026 08:20
…vior

- Switch version check from crates_io_api to `cargo search` (respects
  registry config/mirrors/proxies).
- Extract `cargo_command()` helper (checks SYMPOSIUM_CARGO env, used
  across init, self_update, installation) so tests can mock cargo.
- Add unit tests for search output parsing, tarball extraction, and
  binary installation.
- Add integration tests for self-update command and state.toml.
- For hooks: auto-update = "on" still runs silently; "warn" is skipped
  (stderr isn't visible to the agent). Hook-context guidance is a
  follow-up.
- Add dedicated reference page for `cargo agents self-update`.

Co-authored-by: Claude <claude@anthropic.com>
Replace the process-global SYMPOSIUM_CARGO env var with a
`cargo_override` field on `Symposium` and a `cargo_command()` method.
Tests use `ctx.set_mock_cargo()` which writes a mock script and sets
the override on the test's isolated Symposium instance — no env var
mutation, so tests run in parallel safely.

Thread `&Symposium` through `find_workspace_root()`,
`self_update()` / `check_upgrade()` / `latest_version()`,
`install_cargo_crate()` / `install_cargo_crate_sync()`, and
`cargo_install()` so all cargo invocations use the override.

Co-authored-by: Claude <claude@anthropic.com>
Move the periodic update check from the binary into
`self_update::maybe_check_for_update()` and call it from `cli::run()`
so it's exercised by tests via `ctx.symposium()`. The binary only
retains the hook path (hooks bypass cli::run) and the re-exec step
(process-level concern).

New integration tests:
- sync_triggers_update_check: verifies sync runs the update check
  (mock cargo returns 99.0.0, state.toml records the check)
- sync_skips_update_check_when_throttled: verifies 24h throttle
- self_update_skips_check_when_disabled: verifies auto-update = off

Co-authored-by: Claude <claude@anthropic.com>
Add Output::capturing() mode that collects messages into a buffer
instead of printing.  Update ctx.symposium() to use it so tests can
inspect output.  Assert that sync_triggers_update_check sees the
"99.0.0 is available" warning and the self-update nudge.

Co-authored-by: Claude <claude@anthropic.com>
Use expect_test snapshots to verify exact output for both the
warn-enabled and warn-disabled cases:

- sync_triggers_update_check: snapshot includes the "99.0.0 is
  available" warning before normal init output
- self_update_skips_check_when_disabled: snapshot shows only normal
  init output with no update warning

Co-authored-by: Claude <claude@anthropic.com>
Add auto_update_on_re_execs_into_new_binary: runs the real binary as a
subprocess with auto-update = "on" and self-update-source = "source".
The mock cargo's install handler replaces the binary with a script
that prints "SURPRISE!". After auto-update + re-exec the test asserts
the new binary actually ran.

Also split maybe_check_for_update into two:
- maybe_warn_for_update (sync, used by cli::run for warn-only path)
- maybe_check_for_update (async, used by the binary for on + re-exec)

The binary now runs the full check for all commands (not just hooks),
so auto-update = "on" re-execs correctly for sync/init/etc.

from_environment() reads SYMPOSIUM_CARGO env var so subprocess tests
can inject mock cargo without touching process-global state in the
test runner.

Co-authored-by: Claude <claude@anthropic.com>
Extract AutoUpdateFixture helper for subprocess auto-update tests.
Add auto_update_re_execs_on_hook alongside the existing sync test:
pipes a SessionStart JSON payload into `cargo-agents hook claude
session-start` and asserts the mock-installed "SURPRISE!" binary ran
after re-exec.

Co-authored-by: Claude <claude@anthropic.com>
@nikomatsakis nikomatsakis marked this pull request as ready for review May 14, 2026 14:41
nikomatsakis and others added 3 commits May 14, 2026 10:50
When auto-update = "warn", the session-start hook now checks for a
newer version and includes the nudge in the hook output's
additionalContext field, so the agent can relay it to the user.
Previously the warn path was silently skipped for hooks.

The binary's startup check no longer runs the warn path for hooks
(to avoid consuming the throttle window before the hook runs).
The "on" re-exec path still runs for hooks in the binary.

New test: session_start_hook_warns_about_update_in_context verifies
the nudge appears in additionalContext via prompt_or_hook simulation.

Co-authored-by: Claude <claude@anthropic.com>
On Linux, overwriting a running executable with `cat >` fails with
ETXTBSY. Use a temp file + `mv -f` instead — atomic rename works
even while the binary is executing.

Co-authored-by: Claude <claude@anthropic.com>
… prompt

- Remove the binary download path entirely (UpdateSource enum,
  target_triple, download_release, extract_tarball, extract_zip,
  install_binary, cargo_bin_dir). Self-update now always uses
  `cargo install symposium --force`.
- Change auto-update default from "warn" to "on".
- Add interactive auto-update prompt to `cargo agents init`
  (Auto-update / Warn / Off, defaulting to auto-update).
- Update all docs and tests.

Co-authored-by: Claude <claude@anthropic.com>
@nikomatsakis nikomatsakis added this pull request to the merge queue May 14, 2026
Merged via the queue into symposium-dev:main with commit 26dc645 May 14, 2026
6 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