Skip to content

feat(installer): the installers end on a running page and rebuild what moved on - #476

Merged
0xKT merged 8 commits into
mainfrom
feat/installation
Sep 17, 2026
Merged

0xKT merged 8 commits into
mainfrom
feat/installation

Conversation

@KevinHuSh

Copy link
Copy Markdown
Contributor

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
  • 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.

  • Relevant tests pass locally
  • Relevant lint / type checks pass locally
  • 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.

  • Security impact considered
  • Backward compatibility considered
  • Rollback path is clear for risky changes

Related Issues

N/A

admin and others added 4 commits September 16, 2026 17:02
…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>
@KevinHuSh KevinHuSh changed the title feat(*): the installers end on a running page and rebuild what moved on feat(installer): the installers end on a running page and rebuild what moved on Sep 17, 2026
KevinHuSh and others added 2 commits September 17, 2026 17:30
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 gloryfromca left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread install.sh Resolved

@gloryfromca gloryfromca left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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 gloryfromca left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

KevinHuSh and others added 2 commits September 17, 2026 17:46
_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 gloryfromca left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

@0xKT

0xKT commented Sep 17, 2026

Copy link
Copy Markdown
Member

**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.

install.sh:590 redirects away the message its own sibling says must not be swallowed

"$bin" web --stop >/dev/null && "$bin" web --foreground

raven web --stop reports on stdout (typer.echo), so >/dev/null discards exactly the two messages this new step cannot afford to lose. The contract is not something I am importing from outside -- it is written in this PR's own changed set, in raven/cli/serve_commands.py:

# Reported, not swallowed: a relaunch from here lands on serve and the page comes up without channels, which is worse than refusing to start. (:909-911)

and eight hundred lines earlier the same file names the caller it was written for:

A caller that stops and relaunches back to back -- raven web --stop && raven web --foreground, which is what install.sh runs (:867-869)

Two branches, and the second is the one that matters:

  • fatal (:912-913): prints error: still running after 20s: ..., exits 1. && short-circuits and set -eu (install.sh:26) ends the installer having printed nothing after Starting Raven -- your browser will open in a moment. The user gets a non-zero exit and no reason.
  • warning (:895, :907): prints warning: could not stop the supervisor/gateway (pid N): ... and still exits 0. && proceeds into --foreground, which finds the gateway that was not stopped, prints attaching to the gateway already running: ... and returns 0. The install ends on the previous build's page and claims success -- which is the exact outcome "rebuild what moved on" exists to prevent.

Measured, not argued. A harness running launch_web extracted verbatim from install.sh (sha of the copy matched git show HEAD:install.sh), with only $HOME, uv and a raven shim faked:

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, so ui-tui/packages/hermes-ink/node_modules (28 entries in package-lock.json) gets walked where install.sh:187-196 prunes 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.sh drops the ~/.local/bin PATH warning with no replacement, while install.ps1:671 kept an actual fix (Add-ProcessPath) that works there because irm | iex runs 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 next raven in a fresh terminal is on the reader to find.

@0xKT
0xKT merged commit de3870a into main Sep 17, 2026
20 checks passed
@0xKT
0xKT deleted the feat/installation branch September 17, 2026 13:21
gloryfromca added a commit that referenced this pull request Sep 21, 2026
…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>
LivXue added a commit that referenced this pull request Sep 23, 2026
## 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>
LivXue pushed a commit that referenced this pull request Oct 12, 2026
…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>
LivXue pushed a commit that referenced this pull request Oct 12, 2026
…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>
LivXue added a commit that referenced this pull request Oct 12, 2026
## 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>
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.

3 participants