* feat: warn on every command when the CLI is outdated
Every orx command now prints a warning to stderr when the running version
is behind the latest release, because the backend API is versioned and a
stale client can hit breaking changes. The message escalates with the gap:
a breaking (pre-1.0 minor / post-1.0 major) gap warns that commands can
start failing now; a smaller gap is a gentler upgrade nudge.
This reworks the existing interactive-only update nudge:
- Shows on every command (piped/scripted/CI too), not just interactive
terminals; ORX_NO_UPDATE_CHECK / NO_UPDATE_NOTIFIER /
OPENRESEARCH_CLI_DISABLE_UPDATE=1 silence it.
- Prints in start() before the command runs, so it shows even for commands
that std::process::exit on their own (e.g. the not-logged-in path).
- Latest version still comes from the cached prior check (instant, zero
latency); a fire-and-forget background task refreshes the cache, given a
brief grace window in finish() to commit before the runtime tears down.
- Cache write is now atomic (temp + rename) so concurrent orx processes
never read a torn file.
- Version comparison ignores build metadata (semver's Ord compares it, the
spec says it shouldn't) to avoid a false 'outdated' on local builds.
Excludes the version/update commands, which manage updates themselves.
* feat: bold the warning label on a TTY and set it off in its own block
The outdated-version warning now prints with a blank line above and below
so it reads as its own block, and bolds just the `Warning:` label
(gh/cargo-style) when stderr is an interactive terminal. Pipes, files, and
CI logs stay plain text — the ANSI is gated on `stderr().is_terminal()`
and honors NO_COLOR — so non-interactive output never gets raw escape codes.
Hand-rolled \x1b[1m/\x1b[22m (no color dependency, matching the codebase's
plain-text style); `render`/`bold` are pure and unit-tested.
* refactor: apply review findings (CI latency, label const, doc cleanup)
From the multi-agent code review:
- finish() now skips the 250ms refresh wait when stderr isn't a terminal.
In ephemeral CI (fresh config dir per run) the cache is always cold, so
the wait warmed a cache that's immediately discarded — pure per-call cost
across a pipeline. The refresh is still spawned; we just don't wait. The
warning still prints on every command. Interactive runs keep the wait so
the cache warms for the next command.
- Hoist a shared WARNING_LABEL const used by both warning_for (builder) and
render (styler), so the bolded label can't silently drift from the emitted
prefix on a copy edit.
- Drop the now-inaccurate "passive" framing from the module header, section
banner, struct doc, and main.rs wiring comment (the warning is always-on).
- s/nudge/update check/ in the version/update command comments.
- Add prerelease-axis tests for warning_for (rc-behind-final is soft, a
cross-minor prerelease is breaking, a local dev prerelease ahead is silent).
* simplify: drop the breaking/soft warning tiers, always show one message
Per request, remove the two-tier distinction entirely. The warning no longer
classifies the version gap as breaking vs. non-breaking — every outdated client
gets the same calmer message:
Warning: orx X is outdated (latest Y). A newer release is available; upgrade
to stay compatible with the API. Run `orx update` to upgrade.
Deletes `is_breaking_gap` (and its RE-CONFIRM-AT-1.0 note), the second message
arm in `warning_for`, and the tier-specific tests; collapses the gap-coverage
tests into one that asserts the single message fires for every kind of gap.
`precedence` (the build-metadata comparison guard) is unrelated and stays.
Two local git worktrees were accidentally committed under .claude/worktrees/
as gitlinks (mode 160000) with no backing .gitmodules entry. cargo-dist's
`plan` job checks out with --recurse-submodules, which fails hard on an
orphan gitlink:
fatal: No url found for submodule path '.claude/worktrees/delete-orx-diff'
The process '/usr/bin/git' failed with exit code 128
That gates the entire release workflow (announce / build-* / host all skip),
so every PR shows a failing check even when the code CI passes.
Remove both gitlinks from the index and gitignore .claude/worktrees/ so local
per-task worktrees can never be committed again.
* feat: add --provider to exp run and a standalone `orx instance create`
Two ways to spin up compute from any provider, not just RunPod:
- `orx exp run --provider <name>` provisions an experiment run on the
chosen provider (omit = server default, RunPod).
- `orx instance create <orgId> (--gpu ... | --cpu ...)` spins up a
standalone org-level instance via POST /sandboxes — the CLI equivalent
of the dashboard's "Spin up" panel (omit --provider = cheapest offer).
* chore: bump version to 0.1.29
Release the multi-provider `orx compute` (all providers/regions + DISK
column + --provider filter) from #15. Merging this cuts tag v0.1.26 via the
tag-on-bump release flow.
The backend `GET /compute/catalog` wire format changed: each offer's flat
`diskPerGbHour` became a nested `disk` discriminated union, `region` became
optional, and new `bandwidth*` fields were added. The CLI decodes strictly, so
the missing `disk_per_gb_hour` field broke `orx compute` (and `--cpu`) at JSON
decode. This fixes the deserialization and broadens the command:
- Add a `Disk` struct mirroring the backend `zDisk` union (keyed on the
`sizable` bool, optional payloads), replacing `disk_per_gb_hour` on both
`GpuOffer` and `CpuOffer`. Round-trip tests pin both disk shapes, a missing
region, and the ignored `bandwidth*` fields.
- Remove the RunPod-only filter so the catalog shows every configured provider
and region; add a case-insensitive `--provider` filter.
- Add a DISK column to the GPU and CPU tables.
`orx exp run` new instances remain RunPod-only server-side; docs clarify that
`orx compute` now browses all providers regardless.
* Add Cursor to install-skills
Cursor discovers skills under ~/.cursor/skills/<name>/SKILL.md using the
same Agent Skills format as Claude Code, so it reuses the existing shim.
Detected via ~/.cursor like the other agents, so login auto-install now
covers Cursor-only machines (previously they relied on Cursor scanning
~/.claude/skills, which only helps if Claude Code is also installed).
* 0.1.20
* Make the post-login skill install consent-based
orx login no longer writes into agent config dirs unprompted. When run
interactively it lists exactly what would be installed — file count and
name -> path per detected agent — and asks [Y/n]; nothing is written
without a yes. Non-TTY (CI, agents, pipes) skips the offer entirely.
Explicit orx install-skills is unchanged.
* Remove orx diff; compute run diffs locally via the cache-dir clone
- Delete the diff command and its client plumbing (the server endpoint
stays for the web UI).
- orx exp status now prints the node's branch, the parent's branch, the
latest run's full commit SHA, and a ready-to-paste local git diff
recipe (owner/repo resolved via a new find_project client helper).
- SKILL.md/README: the clone in ~/.cache/openresearch/repos is the
standard way to read, diff, and edit experiment code.
- Bump version to 0.1.17.
* Add clone-if-missing guard to local diff recipes
The diff recipe (SKILL.md and the one orx exp status prints) started at
git fetch, which fails on a cold cache. Prepend the same idempotent
guard the editing recipe uses.
Replace the tag-push release trigger with cargo-dist's dispatch-releases
mode. release-on-bump.yml (replacing tag-release.yml) dispatches release.yml
with tag=v<version> using the default GITHUB_TOKEN — workflow_dispatch is
the documented exception to GitHub's "GITHUB_TOKEN events don't trigger
workflows" rule, so no PAT or secret is required. Nothing pushes a tag
anymore: dist creates the tag implicitly when it publishes the GitHub
Release at the end of a successful run, so the tag can never exist without
its release (the v0.1.16 failure mode) and there is no credential to manage
or rotate.
release.yml regenerated with dist 0.32.0 (dist generate); dist plan passes.
tag-release.yml: on every push to main, mirror the package version into a
v<version> tag if one doesn't exist yet; the tag push triggers the existing
cargo-dist release workflow. The version is never invented or incremented
by CI — merging a PR that bumps Cargo.toml IS the release act. Refuses
(loudly, before tagging) when the RELEASE_TAG_TOKEN secret is missing,
because tags pushed with the default GITHUB_TOKEN don't trigger workflows.
ci.yml version-guard (PRs only): the version may only move forward, may not
reuse an already-released tag, and a bump must come with a regenerated
Cargo.lock — so a malformed bump can't reach main, where merging it would
be the release trigger. Closes the tag/manifest drift class that produced
v0.1.15 (tagged while main said 0.1.14) and v0.1.16 (tagged on a pre-merge
commit, shipping without the feature it was cut for).
- `orx --version` (clap) and `orx version [--check] [--json]`: prints the
CLI version and compares it to the latest GitHub release. `--json` is
the agent-facing form (stable stdout object, exit 0 either way).
- `orx update [--dry-run] [--force]`: updates in place by re-running the
cargo-dist release installer pinned to the existing install prefix
(CARGO_DIST_FORCE_INSTALL_DIR), the same mechanism as axoupdater/uv but
without the native-tls dependency that conflicts with our musl builds.
Guarded by the cargo-dist install receipt (refuses cargo-install copies,
path/version mismatches, Nix/Homebrew paths, unwritable bin dirs), an
exclusive flock against concurrent updates, and run via `sh script` so
noexec /tmp mounts don't break it.
- Passive nudge: at most one background latest-version check per 24h
(cached in the config dir), printed to stderr only on interactive
terminals, never in CI/pipes, never altering exit codes. Opt out with
ORX_NO_UPDATE_CHECK, NO_UPDATE_NOTIFIER, or OPENRESEARCH_CLI_DISABLE_UPDATE=1.
Latest-version discovery uses the releases/latest/download/dist-manifest.json
permalink (CDN redirect, no GitHub API rate limit) instead of the REST API,
whose 60 req/h/IP unauthenticated cap is routinely exhausted on the
datacenter IPs agents run from.
Prepares the release tag for the create-experiment API alignment. Tagging
v0.1.9 on main (after merge) triggers release.yml to build and publish the
GitHub Release artifacts.
Drop the --repo/--ref flags and the empty-baseline path. A project's repo is
now bound at project-creation time on the web, so create-experiment has two
shapes: a child off --parent, or a baseline materialized on the project's
already-bound repo. Replace CreateEmptyBaselineBody/import-from-repo wiring
with a simplified ImportBaselineBody (optional title/description plus
generateSuggestions).