Repository navigation
feat(installer): the installers end on a running page and rebuild what moved on - #476
Conversation
…assets Three changes to install.sh, mirrored in install.ps1. The last step is now `raven web --stop && raven web --foreground` in place of the capability summary and the closing hint. The install finishes on the page open in a browser rather than on a command to go and type, so a first run is walked through by the page's own onboarding. The summary, the upgrade versus first-run wording, and the config.json probe that fed it all go with it. build_web_assets now compares each artifact against its sources instead of only testing that it exists. An editable install relinks Python and nothing else, so ui-tui/dist/entry.js and ui-web/dist/index.html kept serving whatever the tree held at first install while every .py beside them moved on. The page watches i18n/ as well, since ui-web/build.py inlines the shared catalogue. node_modules, dist and .modern are pruned from the walk: npm ci rewrites the first on every build, and the other two hold the artifact being judged. A node packaged without npm now fetches a private runtime that carries one. Debian and Ubuntu split the two packages, so a system node >= 22 satisfied ensure_node and the build then found no npm, with no private runtime ever provisioned. The download body is split out as provision_private_node and called from the build probe too, subshelled so a failure there is a skipped build rather than a failed install. Verification: uv run pytest tests/ --ignore=tests/integration (21807 passed), make check-source-language, make check-large-files, sh -n install.sh. install.ps1 is reviewed by eye only: no pwsh on the machine this was written on, and CI has no PowerShell step. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
README.zh-CN.md still carried the one-paragraph EverMind ecosystem blurb that the English README had replaced with a three-group table: Products, Research and Evaluation, Integrations. Six projects were named where there are now thirteen, with SkillCorpus, MSA, OpenClaw, Hermes, DeepSeek Harness and Dify appearing nowhere. The table is translated, with project names, URLs and markup kept verbatim. The stray back-to-top badge inside that section goes with it: the English README has none there, and it was left over from when the one-liner was the whole section. Every other section compared clean. The line-count gap between the two files is CJK being more compact than wrapped English prose, not missing content. Both READMEs also gain the clone install under Quick Start, which was documented nowhere. The paragraph names the part that is otherwise invisible: `./install.sh` and a piped run do not do the same thing from inside a clone, because local mode requires $0 to be a real file, and RAVEN_LOCAL_SRC is the opt-out for a piped run. It is worded to stay true on main as well, so it claims nothing about the rebuild-on-change and npm behaviour this branch adds. Verification: uv run pytest tests/test_docker_runtime.py tests/test_cli_onboard_commands.py (331 passed), make check-source-language, make check-large-files. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
The English README moves Quick Start below the agent sections, moves Core Systems, Launch WebUI and Command Reference below Self-Hosting, and drops the Onboard and run section, the Upgrade section, and the RAVEN_* table in Configuration. The Chinese README follows it exactly: same 21 headings in the same order, same three sections gone, and the three back-to-top badges still sitting after Core Systems, Documentation and Architecture. The Docker variables stay documented in docker/README.md, which that section already links to. Dropping the Onboard and run heading broke the pin that required it in both files. That pin had already lost its subject twice over: the installers no longer close with a first-run hint, and now neither README carries the section it was reading. Rather than delete the guard, it is repointed at what the README and the installer do still have to agree on, which is the clone install: `./install.sh` and a piped run behave differently from inside a checkout, since local mode requires $0 to be a real file, and RAVEN_LOCAL_SRC is the opt-out. A reader who cannot see that from the README installs the release wheel believing they installed their tree. Verification: uv run pytest on every test module that reads a README (test_cli_onboard_commands, test_docker_runtime, test_install_script, test_readme_scope_canon, test_living_docs, test_external_consumer_surface, test_shell_approval, test_rpc_skillhub, test_agents_research_flow_parity, test_agents_code_flow_project_files, test_coverage_gate): 701 passed. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
Brings 39 upstream commits onto this branch, among them the everos memory plugin moving out of raven/cli and raven/config into plugins-dist, the knowledge sources work, the provider marks, and the default models getting a page of their own (#398). Both READMEs conflicted. This branch's structure wins: the reordered sections and the three removals stay. Upstream's own README change is carried into that structure rather than dropped -- `Start the server from source` moves to the end of Self-Hosting, and the `Settings > Models` to `Settings > Model Providers` rename lands exactly where upstream put it, which is the source section in English and the Compose section in Chinese. That per-file split is upstream's, not this merge's, and is left as found rather than normalised here. Verification: uv run python -m pytest tests/ --ignore=tests/integration on the merged tree, 23161 passed and 109 skipped. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
Removing the RAVEN_* table from Self-Hosting left "committed file. " with a space on the end of the line, which the trailing-whitespace pre-commit hook fails the PR on. No other tracked file in the diff carries one. Verification: git grep -n ' $' finds nothing tracked; every file in the PR diff ends in exactly one newline. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: the stop/relaunch sequence can start a page-only process while the old gateway is still shutting down.
I reviewed the current github/main...HEAD diff, the installer callers and raven web lifecycle, relevant history, backward compatibility, test changes, and the repository rules/context. The inline finding is the only blocker I found.
Verification: uv run pytest tests/test_install_script.py -x passed (27 tests); uv run --with-editable ./plugins-dist/everos-memory python -m pytest tests/test_cli_onboard_commands.py -x passed (332 tests); sh -n install.sh, the source-language check, and the large-file check passed. The initial combined pytest invocation did not collect because the fresh environment lacked raven_everos; supplying that local plugin produced the passing result above. PowerShell is unavailable in this environment, so install.ps1 was reviewed by inspection.
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: the previously reported stop/relaunch lock race remains unchanged.
This head only merges the latest main; the PR's six-file diff, including the installer sequence covered by the open thread, is unchanged from the prior revision. I reviewed the merge delta, the current PR diff and history, the relevant architecture/context constraints and callers, backward compatibility, repository rules, and whether the tests were weakened. I found no new issues, but the existing blocker still applies and its thread remains open.
Verification on this merged tree: uv run --frozen --python 3.12 --all-extras pytest tests/test_install_script.py tests/test_cli_onboard_commands.py -x passed (359 tests); sh -n install.sh, the source-language check, and the large-file check passed.
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: the previously reported stop/relaunch lock race is still present.
The only delta from the prior reviewed head removes trailing whitespace in README.md; neither installer nor its tests changed, so the existing open finding remains applicable. I reviewed the revision delta, the current PR diff and history, callers and architecture/context constraints, backward compatibility, repository rules, and test integrity. I found no new issues and am leaving the existing thread open.
Verification on this head: uv run --frozen --python 3.12 --all-extras pytest tests/test_install_script.py tests/test_cli_onboard_commands.py -x passed (359 tests); sh -n install.sh, the source-language check, and the large-file check passed.
_stop_resident sent SIGTERM and returned, so "stopped" meant "signalled". The gap is visible to the very next command: the gateway's lock is an flock the kernel holds until that process exits, and _gateway_argv reads that lock to choose between `gateway` and `serve`. A caller that stops and relaunches back to back -- `raven web --stop && raven web --foreground`, which is what install.sh now runs -- read the lock of the process it had just signalled, took the `serve` branch, and served the page from an engine with no ChannelManager for the whole session: no adapter to start, no sign-in code mintable, every enabled entrance reading "state unknown". It only bit where a gateway was already up, which is every re-install. Each signal is now waited out, bounded at 20s. Waiting for the supervisor before signalling the gateway also replaces the 0.4s guess at how long it takes to stop restarting things. A process that outlives the deadline fails the stop rather than being reported as stopped, which is what makes the installer's `&&` short-circuit instead of launching into the wrong engine. Waiting on the pid settles the lock too: the kernel drops the flock when the holder dies, so there is no second thing to poll. Verification: uv run python -m pytest tests/ --ignore=tests/integration, 23173 passed and 109 skipped. Both new tests were mutation-checked: removing the wait turns them red. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
install.sh and install.ps1 are two files at the repository root, so no directory scan in the scope enum reaches them, and a change confined to the pair had to fall back on `*`. The enum gains a ROOT_SURFACES entry for them, beside the trees and the wheel distributions it already names. AGENTS.md section 3.1 still describes the scope set as raven/ subpackages, which it already was not; that wording is left for a separate pass. Verification: the pull request title check and commitlint both accept `feat(installer): ...` and still reject an undeclared scope. tests/test_dependabot_scope_canon.py and tests/test_readme_scope_canon.py pass. Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
The stop path now waits for the processes it signalled, fails closed on timeout, and therefore covers both installers through their shared raven web --stop call. I verified the resident supervisor topology with real processes: stop returned 0 after teardown, the gateway lock was gone, and the next launch selected the full gateway child. I replied to and resolved my prior thread.
I reviewed the revision delta and current PR diff, relevant history and callers, repository rules and context/architecture constraints, backward compatibility, and test integrity. No new findings remain.
Verification: uv run --frozen --python 3.12 --all-extras pytest tests/test_install_script.py tests/test_cli_onboard_commands.py tests/test_cli_serve_commands.py -x passed (437 tests); shell syntax, source-language, large-file, commit-message, PR-title, and diff-whitespace checks passed.
|
**Not a blocker -- the staleness check is right, and I tried hard to break it. One line throws away the only channel the step it guards uses to report failure.
|
| shim behaviour | installer exit | what the user saw |
|---|---|---|
| stop rc=0 | 0 | the start line, then the page |
stop rc=1, message on stdout (what typer.echo does) |
1 | the start line, and nothing else |
| stop rc=1, same message on stderr | 1 | error: still running after 20s: ... survives |
The stdout/stderr pair is the control: the loss is caused by the redirect, not by set -e. And a probe of the real _stop_resident() (with _pid_alive forced true, os.kill a no-op, no process signalled) put the message on STDOUT with exit 1, so the stream is not an assumption either.
install.ps1:650-654 turns the same non-zero into Write-Warn "could not clear the gateway a previous install left running; start the page with 'raven web'". So today the two installers disagree about whether the reader is told anything at all.
Dropping the redirect, or sending it to stderr, restores the channel. Nothing else in the step needs to change.
Related, same line: nothing pins the &&. A test that asserts --foreground does not run when --stop fails would catch both this and a future edit that turns it into ;.
What I could not break
The staleness rule. install.sh:200-210 claims mtime is the right question because git stamps every file it rewrites. I built the input designed to refute that -- a checkout that moves a source file backwards in history, where the content is older than the artifact by every measure except mtime -- in a throwaway git repo, driving is_stale extracted verbatim:
after building on the tip: FRESH
after checking out the OLD content: STALE <- mtime caught the backwards move
artifact rebuilt: FRESH
checkout of an unchanged file: FRESH <- git rewrote nothing, no needless rebuild
checkout restoring CHANGED content: STALE
Both halves hold. The input set is right too: ui-web/build.py:37 reads i18n/messages.json, which is why install.sh:250 and install.ps1:352 add $src/i18n to the page's sources; the TUI does not need it because ui-tui/src/i18n/messages.generated.ts is committed and arrives with any catalogue change.
On commitlint.config.cjs
I came to this one expecting to find a repo-wide rule relaxed so this PR's own commits would pass, and it is not that. The addition is
const ROOT_SURFACES = ["installer"];with a comment giving the reason, and it follows a pattern the file already established: TOP_LEVEL_TREES has carried ui-web for a long time, and PRODUCTS and the wheel distributions are not raven/ subpackages either. One entry in an existing shape, with its rationale written down, is not moving the goalposts.
Worth saying while we are here, and not this PR's debt: AGENTS.md:172 still reads "scope -- a top-level subpackage of raven/", which stopped describing this config several scope groups ago. The file, not the doc, is what CI enforces.
Two things I am not filing, recorded so they are not lost
install.ps1's staleness walk does not prune below depth 1, soui-tui/packages/hermes-ink/node_modules(28 entries inpackage-lock.json) gets walked whereinstall.sh:187-196prunes those names at any depth. I have no PowerShell on this machine and will not guess Windows behaviour; the consequence points at an unnecessary rebuild, never a stale page.install.shdrops the~/.local/binPATH warning with no replacement, whileinstall.ps1:671kept an actual fix (Add-ProcessPath) that works there becauseirm | iexruns in the reader's own session. A POSIX script cannot edit its parent shell's PATH, and the installer now ends by running the page, so the immediate need is gone -- but the nextravenin a fresh terminal is on the reader to find.
…lease list (#588) ## Summary The one-line installers are served from `main` and install the latest published release, so an ending on `raven web` (PR #476) shipped against v0.1.13, which has no `web`: since 2026-09-17 every `curl raven.evermind.ai/install.sh | sh` has ended in `No such command 'web'` with exit code 2. This PR fixes that class of failure and the upgrade defect behind the next release. - **Probe rule.** Every `raven <sub>` call in `install.sh` and `install.ps1` is preceded by `raven <sub> --help`. When the probe fails the install ends on the one command every release has (`raven`), and neither the stop nor the page's own exit code becomes the script's. `RAVEN_NO_LAUNCH=1` skips the launch (CI, Dockerfiles); the PATH hint the launch displaced is back. - **The release says what it ships.** `release.yml` writes `raven-plugins.txt`, one `name @ url` line per plugin wheel it just built, beside the wheel and the constraints. Both installers derive every URL from the release page redirect and hand the list to `uv tool install --with-requirements`. No GitHub API call, no grepping asset names out of its JSON. A release without a list (0.1.13 and older) installs raven alone, as it effectively did before. - **Upgrade keeps the plugins.** uv replaces a tool's requirement set with what one command names, so the old helper (`raven[channels]` only) uninstalled every plugin the installer had put in. The helper now installs from the same list, descends one loss at a time (engines, then the memory plugin, then the channel extras), and refuses to run without the list rather than install raven alone. `raven upgrade` on an up-to-date install whose list names a plugin it lacks reinstalls the version with its plugins. The helper also moves a beta wheel URL's deploy token into the request header (urllib reads `user:token@host` as a host name) and copies it onto the list's URLs for uv. - **Gates.** CI installs the latest release with the PR's scripts, piped, on ubuntu and windows whenever an installer changes. The release job installs itself from `dist/` with `install.sh` before the draft is created and asserts the three plugin packages and `web` on the result. The beta publisher builds and lists the same three plugin wheels. A contract test holds the release workflow, the beta publisher, both installers (remote list and local clone mode) and the helper to one plugin list. Decisions, for the reviewer: the plugins are not published to PyPI and no names are reserved there; the list carries direct URLs, so no plugin is ever resolved by name against an index. The LibreOffice and chromium steps in the scripts are unchanged. The three hosted-memory plugins (mem0, zep, memos) are built and uploaded as before but stay off the default list. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification All installs below ran piped (`cat install.sh | sh`) in isolated directories (own HOME, UV_TOOL_DIR, UV_TOOL_BIN_DIR, UV_CACHE_DIR, RAVEN_HOME) with `RAVEN_MINIMAL=1`. - `main`'s `install.sh` against the live latest release (v0.1.13): exit 2, `No such command 'web'`. This branch's `install.sh`, same environment: exit 0, `Raven installed. Open a new terminal ... then run: raven`; `raven --version` prints 0.1.13. With `RAVEN_NO_LAUNCH=1`: exit 0. - A local release directory built by `scripts/publish_beta.py` (`_build` at 0.1.14b1: raven wheel, three plugin wheels, constraints, list): this branch's `install.sh` with `RAVEN_WHEEL_URL=file://...` installs raven 0.1.14b1, `python -c "import raven_everos, raven_design, raven_ppt"` succeeds in the tool venv, and the uv receipt lists raven plus the three plugins. - The release workflow's two new step bodies (`Write the plugin list`, `Install the release from dist with install.sh`) extracted and run locally against that build: exit 0; removing one plugin wheel makes the list step exit 1. - The script's ending against the 0.1.14b1 install: `raven web --help` exit 0, `raven web --stop` exit 0 with nothing to stop, `raven web --foreground --port 18999` answers `GET /` with HTTP 200 after about 20 seconds. - `uv run raven upgrade` and `uv run raven upgrade --check` from the checkout against live GitHub: `Raven 0.1.13 is up to date.`, exit 0. - `uv run pytest tests/integration/test_cli_upgrade_real_uv.py`: 2 passed. The test now installs the old fixture `--with` a companion wheel and asserts the companion survives the upgrade; against `main`'s helper the same test fails on that assertion. - `uv run pytest tests/test_install_script.py tests/test_release_plugin_list.py tests/test_updates_upgrade.py tests/test_publish_beta.py tests/test_cli_smoke.py`: all pass (37 + 6 + 188 on the last run of each). - `uv run pytest` (full suite, before the last installer rewrite): 23543 passed, 121 skipped, 4 failed. The 4 (`test_agents_oncall_launcher`, `test_agents_code_launcher`, `test_agent_loop_token_budget`, `test_ppt_engine_image_search`) fail identically on plain `github/main` in a separate worktree. - `uv run ruff check` and `uv run ruff format --check` on every touched Python file: clean. `sh -n install.sh`, `bash -n install.sh`: clean. Both workflow files parse. - Not run here: the new CI job's Windows leg and the release gate inside GitHub Actions (this PR is their first run). `install.ps1` has no local PowerShell to execute it; its changes mirror `install.sh` and are pinned by the text tests. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed ## Risk User-visible changes: the installers no longer fail on a release without `web`; they print the plugins they install and a warning when a release carries none; `raven upgrade` refuses to proceed when the target release's plugin list cannot be fetched (previously it would install raven alone and drop the plugins), and repairs an up-to-date install that lacks listed plugins. The beta channel's next publish carries the three plugin wheels and the list; a beta upgrade to a build published before this change will refuse for lack of a list, and rerunning the beta installer is the remedy. Rollback: revert the commit. Releases published with `raven-plugins.txt` keep working with the old scripts, which ignore the file. - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A --------- Co-authored-by: Claude (claude-fable-5-1) <noreply@anthropic.com>
## Summary `raven web --stop` computed one `time.monotonic` deadline and passed the same stamp to both of its waits. Those waits run in sequence, and they have to: the supervisor restarts the gateway, so it must be confirmed gone before the gateway is signalled. A shared stamp therefore charges the gateway for however long the supervisor took, down to no wait at all, while the failure it prints still names the whole 20s budget. The result is a failure reported on a successful stop. Observed against a gateway that had been up for hours with live sessions: `--stop` printed `error: still running after 20s: gateway (pid ...)`, and that process was gone by the next poll. It does not reproduce on a fresh instance, which stops in 1.8s in total, and `--supervise` exists precisely to keep one resident. The fix is in the parameter rather than in a reset. `_await_exit` now takes a duration and derives its own deadline, so there is no stamp to share and the defect is unreachable rather than corrected. The two sibling wait helpers in the same file, `_bound_port_of` and the attach wait, already took a duration and derived the deadline internally; this one was the only deviation, and the only site where the sharing could happen. The number the message reports is now true by construction, because every process it names was given that long, and `_STOP_WAIT_S` documents the per-process contract and the resulting worst case of two budgets. Checked and deliberately not changed: the installers run `web --stop` and continue into `web --foreground` whether or not the stop succeeded, so the refusal this code raises is swallowed. That was verified rather than assumed. `_run_foreground` starts `_gateway_argv`, which returns `serve` while the old flock is held, and `serve` builds no ChannelManager. It is narrower than it looks, because `web` attaches to a gateway that still answers before it reaches that path, so reaching it needs a process wedged enough not to answer and alive enough to hold the lock. Making the installers stop on a failed stop reverses the deliberate decision in #476 that they end on a running page, which is a product call rather than part of this fix. With the timeout corrected that refusal stops being mostly false positives, so it is worth deciding on its own. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification Both regressions were written first and watched fail against the unfixed code. One assertion was then corrected, because the poll loop overshoots its deadline by up to one poll, so the corrected pair was re-run against the unfixed code as well to confirm the looser bound is still load-bearing. With only `raven/cli/serve_commands.py` reverted to `main`: `test_the_gateway_gets_a_wait_of_its_own` raises `typer.Exit` printing `error: still running after 20s: gateway (pid 222)`, the same message the bug produces, and `test_both_processes_it_names_waited_the_time_it_reports` measures a 20.0s total wait against the 40.0s the message claims for the two processes it names. Both pass with the fix. The tests drive a virtual clock that advances only when the code under test sleeps, so two 20s budgets are measured in no real time. Commands and results: - `uv run --frozen --python 3.12 --all-extras pytest tests/test_cli_serve_commands.py -q` gives 95 passed. - `uv run --frozen --python 3.12 --all-extras pytest -q` gives 1 failed, 25181 passed, 113 skipped in 420s. The failure is `tests/test_install_script.py::test_resolve_node_dir_answers_each_case_it_exists_for`, a local node-directory probe. With both changed files reverted to `main` the same id fails identically, so 0 failures are introduced. - `make lint-python` gives ruff check clean and ruff format clean over 2046 files. - `make lint-imports` gives 10 contracts kept, 0 broken. - `make lint-types` gives all checks passed. - `scripts/check_commit_messages.py`, `scripts/check_large_files.py`, `scripts/check_source_language.py` and `npx commitlint` all exit 0. `make lint` does not complete as a whole because `lint-ui` needs a `node_modules` install that was not available. This change is Python only and touches no UI file. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed The docs box is left unchecked because nothing needed updating: no page under `docs/` or `docs-site/` states a stop budget, and the message wording is unchanged. ## Risk A `raven web --stop` that has to wait out both processes can now take up to two budgets, 40s, instead of one, and it refuses in fewer cases, because a gateway that used to be reported unresponsive after a short remainder now gets a full 20s of its own. Nothing that stopped cleanly before behaves differently: a fresh instance still stops in about 1.8s, and the exit code, the message wording and the order the two signals are sent in are all unchanged. Rollback is a revert of the single commit; the change is confined to one private helper and its only caller. - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A Co-authored-by: Claude (claude-opus-5[1m]) <noreply@anthropic.com>
…t moved on (#476) ## Summary The installers stop telling you what to run and run it. `install.sh` ends with `raven web --stop && raven web --foreground`, so a finished install is the page open in a browser rather than a hint to go and type something; first-run setup is walked through by the page's own onboarding. The capability summary, the upgrade-versus-first-run wording and the config.json probe that fed it go with it. `install.ps1` mirrors all of this, with one deliberate divergence: a non-zero page exit only warns there, because under `irm | iex` that is the reader's own interactive PowerShell and Ctrl-C, the ordinary way to end a foreground page, returns non-zero. Two gaps that only bite a source install are closed on the way: - `build_web_assets` compares each artifact against its sources instead of only testing that it exists. An editable install relinks Python and nothing else, so `ui-tui/dist/entry.js` and `ui-web/dist/index.html` kept serving whatever the tree held at first install while every `.py` beside them moved on. The page watches `i18n/` too, since `ui-web/build.py` inlines the catalogue. `node_modules`, `dist` and `.modern` are pruned: `npm ci` rewrites the first on every build, and the other two hold the artifact being judged. - A node packaged without npm now fetches a private runtime that carries one. Debian and Ubuntu split the two packages, so a system node >= 22 satisfied `ensure_node` and the build then found no npm with no private runtime ever provisioned. The download body is split out as `provision_private_node` and called from the build probe as well, subshelled so a failure there is a skipped build rather than a failed install. It stays lazy rather than moving into `ensure_node`, so a wheel install that never runs npm does not pay for a 50 MB download it has no use for. Both READMEs are reordered and the clone install is documented under Quick Start, where it was missing: `./install.sh` and a piped run do different things from inside a checkout, because local mode requires `$0` to be a real file, and `RAVEN_LOCAL_SRC` is the opt-out. The Chinese README also picks up the EverMind ecosystem table the English one had already moved to. One test changed rather than being deleted. `test_readme_quickstart_matches_the_installer_hint` required an `Onboard and run` heading in both READMEs; the installers no longer close with a first-run hint and neither README carries that section, so the pin had no subject left. It is repointed at what the two must still agree on, which is the clone install. `install.ps1` has not been parsed or executed. There is no pwsh on the machine this was written on and no PowerShell step in CI, so every Windows change here is reviewed by eye and pinned by text tripwires only. A real Windows run before release would be worth it. ## Type - [ ] Fix - [x] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification `uv run python -m pytest tests/ --ignore=tests/integration` on the merged tree: 23161 passed, 109 skipped. `uv run pytest tests/test_install_script.py`: 27 passed, including a functional test that extracts the real `is_stale` and `resolve_node_dir` from `install.sh` and runs them under `sh`. `is_stale` is checked across missing artifact, fresh artifact, touched page source, touched catalogue, and build output touched; `resolve_node_dir` across system node with npm, node without npm, node without npm and a failed fetch, and no node at all. Both were mutation-checked: removing the fallback line from `install.sh` turns the new tests red. `sh -n install.sh`, `make check-source-language`, `make check-large-files`, `ruff check`, `ruff format --check`: all clean. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [x] User-facing docs or screenshots are updated when needed ## Risk User-visible: a finished install now holds the terminal on a running page instead of returning to the prompt. That also means the installer's exit code is the gateway's, so on a clone where the page build only warned, `install.sh` now exits 1 with "No page is built" where it used to exit 0 with a working TUI. A re-run over a checkout that has moved on will rebuild the frontend, which costs an `npm ci` it used to skip. Rollback is per commit: the launch, the rebuild-on-change and the npm fallback are independent edits to `install.sh` and `install.ps1` and can be reverted separately. No runtime code outside the installers changed. - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A --------- Co-authored-by: admin <admin@SH-HuKai.local> Co-authored-by: Claude (claude-opus-5) <noreply@anthropic.com>
…lease list (#588) ## Summary The one-line installers are served from `main` and install the latest published release, so an ending on `raven web` (PR #476) shipped against v0.1.13, which has no `web`: since 2026-09-17 every `curl raven.evermind.ai/install.sh | sh` has ended in `No such command 'web'` with exit code 2. This PR fixes that class of failure and the upgrade defect behind the next release. - **Probe rule.** Every `raven <sub>` call in `install.sh` and `install.ps1` is preceded by `raven <sub> --help`. When the probe fails the install ends on the one command every release has (`raven`), and neither the stop nor the page's own exit code becomes the script's. `RAVEN_NO_LAUNCH=1` skips the launch (CI, Dockerfiles); the PATH hint the launch displaced is back. - **The release says what it ships.** `release.yml` writes `raven-plugins.txt`, one `name @ url` line per plugin wheel it just built, beside the wheel and the constraints. Both installers derive every URL from the release page redirect and hand the list to `uv tool install --with-requirements`. No GitHub API call, no grepping asset names out of its JSON. A release without a list (0.1.13 and older) installs raven alone, as it effectively did before. - **Upgrade keeps the plugins.** uv replaces a tool's requirement set with what one command names, so the old helper (`raven[channels]` only) uninstalled every plugin the installer had put in. The helper now installs from the same list, descends one loss at a time (engines, then the memory plugin, then the channel extras), and refuses to run without the list rather than install raven alone. `raven upgrade` on an up-to-date install whose list names a plugin it lacks reinstalls the version with its plugins. The helper also moves a beta wheel URL's deploy token into the request header (urllib reads `user:token@host` as a host name) and copies it onto the list's URLs for uv. - **Gates.** CI installs the latest release with the PR's scripts, piped, on ubuntu and windows whenever an installer changes. The release job installs itself from `dist/` with `install.sh` before the draft is created and asserts the three plugin packages and `web` on the result. The beta publisher builds and lists the same three plugin wheels. A contract test holds the release workflow, the beta publisher, both installers (remote list and local clone mode) and the helper to one plugin list. Decisions, for the reviewer: the plugins are not published to PyPI and no names are reserved there; the list carries direct URLs, so no plugin is ever resolved by name against an index. The LibreOffice and chromium steps in the scripts are unchanged. The three hosted-memory plugins (mem0, zep, memos) are built and uploaded as before but stay off the default list. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification All installs below ran piped (`cat install.sh | sh`) in isolated directories (own HOME, UV_TOOL_DIR, UV_TOOL_BIN_DIR, UV_CACHE_DIR, RAVEN_HOME) with `RAVEN_MINIMAL=1`. - `main`'s `install.sh` against the live latest release (v0.1.13): exit 2, `No such command 'web'`. This branch's `install.sh`, same environment: exit 0, `Raven installed. Open a new terminal ... then run: raven`; `raven --version` prints 0.1.13. With `RAVEN_NO_LAUNCH=1`: exit 0. - A local release directory built by `scripts/publish_beta.py` (`_build` at 0.1.14b1: raven wheel, three plugin wheels, constraints, list): this branch's `install.sh` with `RAVEN_WHEEL_URL=file://...` installs raven 0.1.14b1, `python -c "import raven_everos, raven_design, raven_ppt"` succeeds in the tool venv, and the uv receipt lists raven plus the three plugins. - The release workflow's two new step bodies (`Write the plugin list`, `Install the release from dist with install.sh`) extracted and run locally against that build: exit 0; removing one plugin wheel makes the list step exit 1. - The script's ending against the 0.1.14b1 install: `raven web --help` exit 0, `raven web --stop` exit 0 with nothing to stop, `raven web --foreground --port 18999` answers `GET /` with HTTP 200 after about 20 seconds. - `uv run raven upgrade` and `uv run raven upgrade --check` from the checkout against live GitHub: `Raven 0.1.13 is up to date.`, exit 0. - `uv run pytest tests/integration/test_cli_upgrade_real_uv.py`: 2 passed. The test now installs the old fixture `--with` a companion wheel and asserts the companion survives the upgrade; against `main`'s helper the same test fails on that assertion. - `uv run pytest tests/test_install_script.py tests/test_release_plugin_list.py tests/test_updates_upgrade.py tests/test_publish_beta.py tests/test_cli_smoke.py`: all pass (37 + 6 + 188 on the last run of each). - `uv run pytest` (full suite, before the last installer rewrite): 23543 passed, 121 skipped, 4 failed. The 4 (`test_agents_oncall_launcher`, `test_agents_code_launcher`, `test_agent_loop_token_budget`, `test_ppt_engine_image_search`) fail identically on plain `github/main` in a separate worktree. - `uv run ruff check` and `uv run ruff format --check` on every touched Python file: clean. `sh -n install.sh`, `bash -n install.sh`: clean. Both workflow files parse. - Not run here: the new CI job's Windows leg and the release gate inside GitHub Actions (this PR is their first run). `install.ps1` has no local PowerShell to execute it; its changes mirror `install.sh` and are pinned by the text tests. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed ## Risk User-visible changes: the installers no longer fail on a release without `web`; they print the plugins they install and a warning when a release carries none; `raven upgrade` refuses to proceed when the target release's plugin list cannot be fetched (previously it would install raven alone and drop the plugins), and repairs an up-to-date install that lacks listed plugins. The beta channel's next publish carries the three plugin wheels and the list; a beta upgrade to a build published before this change will refuse for lack of a list, and rerunning the beta installer is the remedy. Rollback: revert the commit. Releases published with `raven-plugins.txt` keep working with the old scripts, which ignore the file. - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A --------- Co-authored-by: Claude (claude-fable-5-1) <noreply@anthropic.com>
## Summary `raven web --stop` computed one `time.monotonic` deadline and passed the same stamp to both of its waits. Those waits run in sequence, and they have to: the supervisor restarts the gateway, so it must be confirmed gone before the gateway is signalled. A shared stamp therefore charges the gateway for however long the supervisor took, down to no wait at all, while the failure it prints still names the whole 20s budget. The result is a failure reported on a successful stop. Observed against a gateway that had been up for hours with live sessions: `--stop` printed `error: still running after 20s: gateway (pid ...)`, and that process was gone by the next poll. It does not reproduce on a fresh instance, which stops in 1.8s in total, and `--supervise` exists precisely to keep one resident. The fix is in the parameter rather than in a reset. `_await_exit` now takes a duration and derives its own deadline, so there is no stamp to share and the defect is unreachable rather than corrected. The two sibling wait helpers in the same file, `_bound_port_of` and the attach wait, already took a duration and derived the deadline internally; this one was the only deviation, and the only site where the sharing could happen. The number the message reports is now true by construction, because every process it names was given that long, and `_STOP_WAIT_S` documents the per-process contract and the resulting worst case of two budgets. Checked and deliberately not changed: the installers run `web --stop` and continue into `web --foreground` whether or not the stop succeeded, so the refusal this code raises is swallowed. That was verified rather than assumed. `_run_foreground` starts `_gateway_argv`, which returns `serve` while the old flock is held, and `serve` builds no ChannelManager. It is narrower than it looks, because `web` attaches to a gateway that still answers before it reaches that path, so reaching it needs a process wedged enough not to answer and alive enough to hold the lock. Making the installers stop on a failed stop reverses the deliberate decision in #476 that they end on a running page, which is a product call rather than part of this fix. With the timeout corrected that refusal stops being mostly false positives, so it is worth deciding on its own. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification Both regressions were written first and watched fail against the unfixed code. One assertion was then corrected, because the poll loop overshoots its deadline by up to one poll, so the corrected pair was re-run against the unfixed code as well to confirm the looser bound is still load-bearing. With only `raven/cli/serve_commands.py` reverted to `main`: `test_the_gateway_gets_a_wait_of_its_own` raises `typer.Exit` printing `error: still running after 20s: gateway (pid 222)`, the same message the bug produces, and `test_both_processes_it_names_waited_the_time_it_reports` measures a 20.0s total wait against the 40.0s the message claims for the two processes it names. Both pass with the fix. The tests drive a virtual clock that advances only when the code under test sleeps, so two 20s budgets are measured in no real time. Commands and results: - `uv run --frozen --python 3.12 --all-extras pytest tests/test_cli_serve_commands.py -q` gives 95 passed. - `uv run --frozen --python 3.12 --all-extras pytest -q` gives 1 failed, 25181 passed, 113 skipped in 420s. The failure is `tests/test_install_script.py::test_resolve_node_dir_answers_each_case_it_exists_for`, a local node-directory probe. With both changed files reverted to `main` the same id fails identically, so 0 failures are introduced. - `make lint-python` gives ruff check clean and ruff format clean over 2046 files. - `make lint-imports` gives 10 contracts kept, 0 broken. - `make lint-types` gives all checks passed. - `scripts/check_commit_messages.py`, `scripts/check_large_files.py`, `scripts/check_source_language.py` and `npx commitlint` all exit 0. `make lint` does not complete as a whole because `lint-ui` needs a `node_modules` install that was not available. This change is Python only and touches no UI file. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed The docs box is left unchecked because nothing needed updating: no page under `docs/` or `docs-site/` states a stop budget, and the message wording is unchanged. ## Risk A `raven web --stop` that has to wait out both processes can now take up to two budgets, 40s, instead of one, and it refuses in fewer cases, because a gateway that used to be reported unresponsive after a short remainder now gets a full 20s of its own. Nothing that stopped cleanly before behaves differently: a fresh instance still stops in about 1.8s, and the exit code, the message wording and the order the two signals are sent in are all unchanged. Rollback is a revert of the single commit; the change is confined to one private helper and its only caller. - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes ## Related Issues N/A Co-authored-by: Claude (claude-opus-5[1m]) <noreply@anthropic.com>
Summary
The installers stop telling you what to run and run it.
install.shends withraven web --stop && raven web --foreground, so a finished install is the pageopen in a browser rather than a hint to go and type something; first-run setup
is walked through by the page's own onboarding. The capability summary, the
upgrade-versus-first-run wording and the config.json probe that fed it go with
it.
install.ps1mirrors all of this, with one deliberate divergence: anon-zero page exit only warns there, because under
irm | iexthat is thereader's own interactive PowerShell and Ctrl-C, the ordinary way to end a
foreground page, returns non-zero.
Two gaps that only bite a source install are closed on the way:
build_web_assetscompares each artifact against its sources instead of onlytesting that it exists. An editable install relinks Python and nothing else,
so
ui-tui/dist/entry.jsandui-web/dist/index.htmlkept serving whateverthe tree held at first install while every
.pybeside them moved on. Thepage watches
i18n/too, sinceui-web/build.pyinlines the catalogue.node_modules,distand.modernare pruned:npm cirewrites the firston every build, and the other two hold the artifact being judged.
Debian and Ubuntu split the two packages, so a system node >= 22 satisfied
ensure_nodeand the build then found no npm with no private runtime everprovisioned. The download body is split out as
provision_private_nodeandcalled from the build probe as well, subshelled so a failure there is a
skipped build rather than a failed install. It stays lazy rather than moving
into
ensure_node, so a wheel install that never runs npm does not pay for a50 MB download it has no use for.
Both READMEs are reordered and the clone install is documented under Quick
Start, where it was missing:
./install.shand a piped run do different thingsfrom inside a checkout, because local mode requires
$0to be a real file, andRAVEN_LOCAL_SRCis the opt-out. The Chinese README also picks up the EverMindecosystem table the English one had already moved to.
One test changed rather than being deleted.
test_readme_quickstart_matches_the_installer_hintrequired an
Onboard and runheading in both READMEs; the installers no longerclose with a first-run hint and neither README carries that section, so the pin
had no subject left. It is repointed at what the two must still agree on, which
is the clone install.
install.ps1has not been parsed or executed. There is no pwsh on the machinethis was written on and no PowerShell step in CI, so every Windows change here
is reviewed by eye and pinned by text tripwires only. A real Windows run before
release would be worth it.
Type
Verification
uv run python -m pytest tests/ --ignore=tests/integrationon the merged tree:23161 passed, 109 skipped.
uv run pytest tests/test_install_script.py: 27 passed, including a functionaltest that extracts the real
is_staleandresolve_node_dirfrominstall.shand runs them under
sh.is_staleis checked across missing artifact, freshartifact, touched page source, touched catalogue, and build output touched;
resolve_node_diracross system node with npm, node without npm, node withoutnpm and a failed fetch, and no node at all. Both were mutation-checked: removing
the fallback line from
install.shturns the new tests red.sh -n install.sh,make check-source-language,make check-large-files,ruff check,ruff format --check: all clean.Risk
User-visible: a finished install now holds the terminal on a running page
instead of returning to the prompt. That also means the installer's exit code is
the gateway's, so on a clone where the page build only warned,
install.shnowexits 1 with "No page is built" where it used to exit 0 with a working TUI. A
re-run over a checkout that has moved on will rebuild the frontend, which costs
an
npm ciit used to skip.Rollback is per commit: the launch, the rebuild-on-change and the npm fallback
are independent edits to
install.shandinstall.ps1and can be revertedseparately. No runtime code outside the installers changed.
Related Issues
N/A