Raven 0.2.0 (2026-09-23)
Raven 0.2.0 is the first minor release since 0.1.13, and much of what it carries is new to a 0.1.13 install: a Web UI that raven web serves in the browser (rail, composer, transcript, settings dialog, Agent Connector and a desk with file, agent and task panes), permission modes at the tool-dispatch door, four built-in agents under agents/, the playbook engine, the ACP and A2A surfaces, the three plugin wheels the release publishes, and a Dockerfile with a Compose file that run the whole of it in one container. It also retires and moves several things. The built-in deep_research tool goes, with its raven deep-research command group and tools.deepResearch config section, in favour of the research agents; the tracing module's begin_attempt / end_attempt / current_attempt functions go with the span-level attempt.id, attempts now being grouped after recording with raven trajectory merge; and the installers finish by opening Raven in the browser and holding the terminal on raven web --foreground (export RAVEN_NO_LAUNCH=1 before a non-interactive install to exit as before). Conversations are gated by a new permission mode, smart by default; a turn the model loop gives up on now fails instead of answering and raven agent -m exits 3 when an action needed an approval nobody could give; a streamed model call that fails before any reply text is retried on a new ladder (agents.defaults.llmErrorRetryDelays, default 15/30/60 s) where 0.1.13 answered with the first failure, and one that fails after output is retried only where agents.defaults.llmRetryAfterOutput says so; the sub-agent memory block, the EverOS role settings and the retired embedding shape move, most of them with load-time migrations, and tools.toolSearch.enabled is now on by default. On the page, a four-step wizard and a cold-start import replace the terminal first run; the frontend follows the Figma design, with a settings dialog that absorbs skills, plugins, schedules, channels and memory, an Agent Connector, a desk task pane, a composer that starts a conversation in a folder of your choosing and sends a message into a running turn, and typeset mathematics. The provider catalogue grows from 21 to 55, Raven speaks Agent2Agent 1.0, the model can drive the shared browser, playbooks include a many-round stint mode, WhatsApp and WeChat pair from Settings > Channels, raven trajectory gets an interactive browser and a bug-report flow, and a bilingual documentation site takes over the README's reference sections.
Highlights
- Breaking: The built-in
deep_researchtool is retired: theraven deep-researchcommand group, the MiroThinker HTTP tool and its unconfigured stand-in, thetools.deepResearchconfig section, the settings row with its MiroThinker key panel and the deep-research entry in the ACP command menu are all gone. Research keeps two surfaces, the Raven-Research agent and the MiroThinker sub-agent preset. An existing config losestools.deepResearch/tools.deep_researchthrough a load-time migration that prints one notice (#717) - Breaking:
install.shandinstall.ps1finish by holding the terminal open onraven web --foreground, which opens the browser, instead of exiting after a hint: after probingraven web --helpthey runraven web --stopand thenraven web --foreground, so a non-interactive install -- a CI job, a DockerfileRUNstep, any piped install with no TTY to Ctrl-C -- hangs unlessRAVEN_NO_LAUNCH=1is exported first, which restores the exit-after-install behaviour. A piped install against a release without that subcommand ends onravenitself instead of exiting 2 withNo such command 'web'(#476, #588) - Breaking: Tool dispatch is gated. Permission modes are new in 0.2.0 --
permissions.modetakesask,smartorfulland defaults to"smart"-- so a turn now stops and asks where 0.1.13 ran straight through. Smart mode states what ordinary work is -- reading and writing files in the workspace, building, testing, formatting, installing project dependencies with a package manager, committing, pushing a branch -- and escalates by effect: sending files, secrets or conversation content off the machine, touching credentials and keys, changing shell startup files, system services or permission settings, deleting user data outside the workspace, force-pushing or rewriting shared history, dropping databases. The reviewer takes a verdict only from its ownreport_permission_reviewcall; a timeout, a raising provider or a prose answer escalates to the human (#585, #631, #645) - Breaking: Failures fail instead of answering. A model call the loop gives up on -- a first-byte or idle timeout, a stream cut before its terminal chunk, an error from the non-streaming fallback, or an exhausted empty-response recovery -- raises
AnswerlessTurnError: the turn is saved with statusfailedand the error's own words as its reason, the page and the TUI draw "Turn failed - ",raven agent -mno longer exits 0 with the explanation as its reply, a node of arun_subagent_daggraph is recorded as failed rather than counted as finished, and a cron job record carries the turn's own failure sentence rather than a generic one (#666, #705, #675).raven agent -mlists the actions it refused after the reply and exits 3 (EXIT_ACTIONS_REFUSED) when an action needed an approval nobody could give -- a refusal from a deny rule is listed but leaves the status at 0, and--permission-mode fullrestores a clean exit -- andraven trajectoryrun with no subcommand on a non-interactive stream prints "Re-run with: raven trajectory list" and exits 2 (#708, #370) - Breaking: Config keys and defaults move, most of them with a load-time migration. A sub-agent's memory block is spelled
memory--subagents.agents[].memoryinconfig.json,memoryin an agent folder'ssubagent.json-- and a row still using the oldeverosspelling keeps working, read under the new name (#414); EverOS's four roles (llm, embedding, rerank, multimodal) are configured in Raven's own config as a model pin plus the vendor serving it, never a credential, reach EverOS asEVEROS_<ROLE>__*environment variables on every spawn, and Raven now writes only[api]intoeveros.toml(#614); a config still holding the retired embedding endpoint shape is adopted onto the configured provider that answers at that address, or dropped with the address named in the log, instead of breaking every command that reads the extension blocks (#453); a sub-agent row still carrying the stock command of a retired Codex or Claude Code adapter pin is moved onto the current one (#752).tools.toolSearch.enablednow defaults to true: at or belowtools.toolSearch.compactionThreshold(default 50) live tools nothing changes; above it most tool schemas are withheld and reached throughtool_searchandtool_call, a pair reserved fromtools.disabledTools(#616). A model no catalogue knows falls back to 200,000 context tokens instead of 65,536, logged once with the hint to pinagents.defaults.contextWindowTokens(#634) - Breaking:
trace.begin_attempt,trace.end_attemptandtrace.current_attempt(raven.tracing.trace, shipped in v0.1.13) and the span-levelattempt.idattribute are removed, with no shim. Group attempts after recording instead, withmerge_attempts()fromraven.trajectoryorraven trajectory mergeon the CLI; existing logs carrying a span-levelattempt.idstay addressable through the reader fallback and need no data migration (#370) - Raven has a Web UI.
raven webstarts a supervisor and a resident gateway that serve a page in your browser -- rail, composer, transcript, settings dialog, Agent Connector and a desk with file, agent and task panes -- fromui-web/distor the wheel's packaged copy,raven web --stopends them, and the installers finish by opening the page. 0.1.13 shipped no served page and nowebcommand; the TUI stays, and bareravenstill opens it the wayraven tuidoes. Also new since 0.1.13 are permission modes at the tool-dispatch door, the four built-in agents underagents/(raven-code, raven-design, raven-oncall, raven-research;raven-pptsits beside them as a hidden engine that Raven-Design routes.pptxwork to, not a fifth agent on the roster), the playbook engine, the ACP and A2A surfaces, the three plugin wheels the release publishes, and nine commands or command groups:raven a2a,raven acp,raven agents,raven mcp,raven ops,raven playbook,raven plugin,raven serveandraven web(#476, #588, #612) - The settings dialog absorbs Skills, Plugins, schedules, channels and memory, each drawn in a shared two-pane frame; there is no separate Skills, Plugins, Knowledge or Playbooks page, and Knowledge has no page, CLI command or agent tool at all. The memory section has no delete control and the RPC has no
memory.delete, because no store behind it could honour one --memory.statsandmemory.listare what it reads -- and atasks.listrow is the dot, the summary, the duration line and the error tag, with no playbook chip (#501, #591, #602, #610) - Some surfaces the prototype carried are deliberately absent from the shipped page. A published deck is delivered as the
.pptxalone, with no PDF copy beside it and one tile in the transcript; a.pptxtakes the same header bar as every other file, so there are no deck-only Download and Reveal pill buttons; there is no docked dag sheet, no second graph or node panel inside an orchestration card and no live conversation or tail inside a spawn card -- a running graph is named in the strip above the composer, and that strip, the card's task cell and the spawn card's task row all open the run in the desk's task pane; and there is no input box under a task node, no per-turn "Files changed this turn" card under each reply and no desktop-notification switch in Settings > General, whose side-channel asks never announced anything (#575, #665, #538, #611, #733, #643, #740, #758) - The installers also do less on a re-run, and the release carries its plugins: a re-run rebuilds only the TUI and page bundles whose sources moved, a node without npm triggers a private Node download, and the release publishes
raven-plugins.txt(threename @ urllines: everos-memory, design-engine, ppt-engine), which both installers andraven upgradehand touv tool install --with-requirements. The installer exportsUV_COMPILE_BYTECODE=1so bytecode compiles during the install rather than inside the first session, passes-qtouv export, andmake build-uiassembles the page throughuv run --frozen --python $(PYTHON_VERSION)instead of a stock/usr/bin/python33.9.6 that failed onwrite_text(newline=). The gateway sendsCache-Control: no-cachewith the page, so a rebuilt or upgraded page reaches the tab without a hard reload, and a source checkout whoseui-web/distis older than its sources answersX-Raven-Page-Behind: sourcesand raises a rail-foot notice namingmake build-ui.raven upgradeandraven upgrade --checkrecognise an editable source checkout before comparing release versions and report the checkout path, how many commits it is ahead of and behindorigin/mainas last fetched, and the remedygit pull && ./install.sh; the quick start gains an Update Raven section per install kind, and both READMEs open Quick Start with a one-line prompt any agent that can read a web page and run shell commands can follow to install or update Raven (#476, #588, #630, #727, #599, #584, #725, #711, #726) - Raven runs in a container. A
Dockerfileanddocker/docker-compose.ymlship in the repository, where 0.1.13 had neither:cd docker && docker compose up --buildbuilds the page and the Python environment into one image that runs nginx and the engine, publishes it on127.0.0.1:18793(RAVEN_WEB_PORT, kept clear of a host install's 18792) and, withRAVEN_AUTO_LOGIN=1(the default indocker/.env), signs the browser in on that page;docker compose up --no-buildruns the configured image (RAVEN_IMAGE, defaultevermindshanda/raven:latest) instead. The build takesRAVEN_EXTRAS(defaultchannels,tools),RAVEN_PLUGINS(defaulteveros-memory) andRAVEN_OFFICE(default 1: LibreOffice for deck rendering and office previews; 0 for a smaller image without either); config, workspace, sessions, logs and the memory store live in araven-datavolume; the engine starts with no provider configured and picks up one saved under Settings > Model providers on the next turn; and the documentation site carries a Docker page in both languages. The container, its Compose file and the published-image switch reached main without a pull request, as commits 4a4a3fe1 and f60bab31 (#551) raven web --stopescalates: SIGTERM, a 20-second grace per process (_STOP_WAIT_S = 20.0, no longer one budget shared between supervisor and gateway), then SIGKILL to the target's process group, still exiting 1 if something outlives it; the supervisor ends its gateway inside 15 seconds and removesweb.jsononly afterwards, and whenserve.jsonnames a live gateway that did not answer the attach,raven webreports that pid as still running instead of starting a second supervisor. On Windows the stop finds the running supervisor and gateway by asking the OS whether a pid is alive (OpenProcess plus a zero-timeout WaitForSingleObject) instead ofos.kill(pid, 0), which CPython implements there as TerminateProcess. With no free port in the 8765..8784 span the gateway takes an OS-assigned control-plane port instead of failing to start, soraven webruns on a Windows host whose winnat reservations cover the span.raven gateway,raven tuiandraven agentexit cleanly on SIGTERM instead of dying with SIGSEGV (shell code 139) from the skill file watcher (#712, #681, #458, #454, #490)- First-run setup happens in the browser: a four-step onboarding wizard -- Model, Search, Agent Connector, Data sync -- opens on a first run and reopens with
?onboard=1; its model and search steps are the settings dialog's own controls, its agents step the Agent Connector's own rows (a refused connect stays on the row in red with Retry), the model picker opened from a role pill is lifted above the wizard, and a machine with nothing to import counts the sync step as finished. A fresh install can set its model from the page and chat with no gateway restart:config.setfor the model key checks the credential directly, asks the host to assemble the serve stack a first run came up without, and reportsneeds_restartonly when this process still cannot run a turn; a refused live model pick rolls the chip back with the detail. Connect saves the key first and tests on the side, an OpenRouter key is checked against/keyrather than the public/modelslist, a refused environment proxy is reported asproxy_unreachable, a key that cannot go in an HTTP header answersinvalid_key, andmodel.fetch_modelstakes an optionalverify(default false) (#523, #524, #537, #587, #594, #751) - The cold-start import runs from the web over
import.scan,import.run,import.statusandimport.stop, the wire twins ofraven import. A row in the rail's foot follows it through scanning, the message pass, the two post-import phases (the profile mirror and the skill install, now on the CLI path too), pause and finish; it shows how far the run is into the source it is on (clamped to 99% until every source settles), survives a reload or a gateway restart, and a settled run earns a row only when the click can still act on it or this page followed the run. Batches are 10 messages rather than the 100 of 0.1.13 (_BATCH_MSG_LIMIT = 10, the 30,000-character bound unchanged), a batch the memory service refuses is retried after 30, 60 and 120 seconds before the source counts as failed, and a finished import can be dismissed (remembered per run in localStorage underraven.importSync.dismissed). Where EverOS cannot run,import.scananswersready: falsewith the platform note, so the wizard does not offer a stepimport.runwould refuse (#570, #598, #586, #615, #750) - The Web UI frontend is rebuilt:
ui-web/srcis organised into feature domains with import-direction, state-layering and domain-shape gates, and the rail, composer, settings nav and chat view follow the Figma design -- a dark user bubble with file tags inside it, replies as flat white cards, boxed tables with a grey head row, code listings with a language header coloured with Shiki (measured by the PR as growing the built page from about 1.69 MB to 2.90 MB), a one-line turn fold carrying the turn's duration, a small folded thinking card, a centred date line between two questions more than thirty minutes apart, and delivered files as compact cards with open, download and open-in-panel actions. Mathematics in an answer is typeset -- LaTeX to MathML via temml, so the browser sets the glyphs and nothing ships a typeface, with the money case excluded by the markdown rule and unreadable TeX left as written -- instead of shown as its source (#612, #701, #710, #664) - The composer bar carries four things -- a
+for uploading a file or picking a deck template, the workspace chip (drafts only), the permission chip and the model chip -- and the sub-agent tier becomes a row in the model picker. A conversation starts in a folder of your choosing: the folder chip lists the default, the folders recent conversations ran in, and either the host's own folder dialog (fs.pick_dir, which takes the menu down while it is up and brings it back only with something to report) or a walk of the gateway's directories from home (fs.dirs: directories only, dotfiles omitted, capped at 500, each marked with theokverdictsession.createwould give); the pick rides the first message'ssession.createasworkdir, is fixed at creation, and is then said once as a tag beside the conversation's title, and the rail no longer groups by folder. The permission menu reads Approve each step / Smart mode / Full access, Escape closes the permission, plus and workspace popovers beneath every layer that covers the bar and above the turn interrupt, and the bar never wraps: its chips take equal shares and end in an ellipsis, then drop whole in priority order (the usage line and the folder/permission words, the folder chip, the context ring, the permission chip) while the plus, the model and send never go (#669, #542, #623, #671, #693, #721, #732) - Conversations keep their thread. A message typed while a turn is running is sent into that turn (
turn.sendwithbusy: "inject") instead of queued for a fresh one; adjacent mid-turn arrivals are folded into one user message under a bracketed header at the model call, amessage.injectedevent and amid_turnflag redraw the bubble on reload, and a malformedturn.sendis answered-32602. A conversation is listed from the moment its first turn starts,session.list,session.resumeandturn.subscribeanswerrunningfor the conversation's own lane only (a reload while a sub-agent's direct chat is in flight no longer arms the main composer with a stop button that cancels the wrong lane), and a conversation opened on another surface resolves to its real transcript instead of splitting into a second file. Archiving holds:session.archiveappends one metadata patch instead of rewriting the record from a stale copy, every metadata write names the key it means and merges with what is on disk so a save from another client cannot un-archive, the rail keeps a row while the archive is only pending, redraws after a restore, and draws an empty group as its heading alone. Files staged in the composer belong to the conversation they were staged in and survive a slash command; a reloaded message that carried pictures or documents reads back as the words typed plus its file chips, a picture sent with no words is still a picture, and the copy and branch buttons under an answer appear on hover again (#622, #621, #639, #455, #585, #589, #597, #704, #619, #629, #638, #649, #593) - The settings dialog is rebuilt on the v0.2 prototype with twelve sections -- general, usage, provider, model, skills, tools, plugins, channels, cron, memory, archive, about -- and opens on General, whose settings each get a title and a subtitle and whose theme is three window miniatures under Appearance. Model providers is a two-column page listing every provider
model.optionsreturns with a search box and a six-entry filter (All, Connected, Direct vendors, Aggregators, Browser sign-in, Local); Model settings holds eleven role slots -- chat, curator, title, memllm, skill gate, embedding, rerank, multimodal, image, speech, video -- each storing the model with the provider serving it and offering only models of its own kind. The add-model popover lists only models not yet added and writes the ticked set in onemodel.add_modelscall; the tools, plugins and chat-parameter drawers are the same table indented one step, the plugin drawer showing the credential, the address, the tool names and the connection manager's own error text; the schedules pane saves as you leave a box, with an eleven-entry frequency dropdown (hourly intervals included) and two clock dropdowns; each channel draws its own app icon (eleven marks, mail as an envelope, an unmarked entrance plain) and a name in both languages; the memory section's detail header drops the coloured initial tile, so a title -- a Chinese one included, which had no initial to show -- lines up with the section under it; the Skills section removes a market skill whichever installer stamped it, andraven skill blockno longer writes a secondskillForgekey beside askill_forgeone, which maderaven agent,raven gatewayand the TUI refuse to start whileraven statuslooked healthy. Every section draws its own skeleton while it waits, controls share one standard (a 38x22 switch, 32px-tall dialog controls), and a filled mini button sizes to its label. The confirm sheet is redrawn on the settings dialog's blurred scrim at 420px with 32px buttons, andconfirm.asktakes a tone --danger(the default every destructive caller keeps),primaryfor the upgrade prompt, whose body is now '{from} to {to}. The Raven service restarts.', andnotice, which hides cancel for the 'turn still running' and 'rebuild the page' notices; the rail's update-available card becomes a plain 32px amber row that lines up with the settings row (#494, #565, #398, #707, #700, #628, #696, #724, #464, #500, #682, #606, #741, #740) - Settings take effect in the running process. The eight keys that used to answer "Saved. Applies after the next gateway reload or restart." are read where they are used --
context.curatorModel/curatorProviderandskillForge.llmGateModel/llmGateProviderper call,agents.defaults.maxToolIterationsandagents.defaults.contextWindowTokensper turn -- andagents.defaults.reasoningEffort,agents.defaults.enablePersonalization,memory.memoryTopK,tools.exec.timeoutand thetools.webvendor keys are read once per turn (agents.defaults.temperatureand the LLM timeouts still need a restart). The timezone control actually writes (validated withzoneinfo), a settings write no longer waits on the model catalogue and no longer repaints the conversation's model chip with the default, a permission mode picked before a conversation exists is staged onto the first message, turning auto-archive on (sessions.autoArchiveAfterDays) sweeps at once,run_subagent_dag,cancel_dag,dag_statusandresolve_dag_nodeare switchable throughtools.disabledToolswhile the built-intool_search/tool_callswitch loses its 'Built in' label and the note reading 'switched on by the tool-search setting, not here', and answers a click with a toast, and the usage page draws cost only when at least one call in the range came back priced (#543, #548, #506, #513, #596, #601, #540, #653, #561) - The bundled provider registry grows from 21 to 55 providers -- Western labs and inference hosts (xAI, Mistral, Together AI, Fireworks AI, Perplexity, Cerebras, Hugging Face, Poe), CN vendors, resale gateways and self-hosted servers such as GPUStack and OpenVINO Model Server -- each drawing the vendor's own brand mark. Serply joins
web_searchas an eighth vendor (tools.web.providers.serply.apiKeyorSERPLY_API_KEY; the default staysserper). The page compares model identifiers the way the backend does through each account'sroute_names, sozhipu/glm-4.6,zai/glm-4.6andglm-4.6are one model; the conversation-scoped and default-scoped provider lists are separate, so opening settings no longer moves the conversation's tick to the wrong vendor; a model added in settings reaches the picker without a reload and a vendor-qualified id is sized from the vendor's own catalogue; the picker row carries its capability glyphs and context-window badge again and reads to a screen reader as radio rows.raven gatewayandraven webstart the litellm import on a background thread at boot (the source records the old 3 to 5 second wait when saving a provider key), metadata lookups no longer reach huggingface.co when the caller asked not to fetch (the PR measuredmodel.optionsat about 1965/1709/1725 ms before and 349/243/241 ms after for the same 55 providers), building the catalogue no longer redoes LiteLLM setup per model, and the page shares one in-flightmodel.optionscall at boot instead of asking three times (#393, #389, #677, #604, #634, #679, #718, #428, #515, #738) - The agents page becomes the Agent Connector: a tabbed card grid (All / Connected / Available / Not installed, the last two shown only when they hold cards) with one corner control per card and a detail sheet holding the agent's description (saved on blur), its API key where one is needed, the install command and site for an absent agent, a Test button with a Stop control and a model pill, each field drawn by whether it can be changed. Test and Connect mean the same thing for every kind except builtin -- one real prompt, an answer required, bounded at 120 s for an explicit Test and at 60 s for a Connect, which is on the path of the settings switch -- so an agent that defers its credential to the first model call is no longer reported ready; a command that does not resolve on PATH shows Not Installed and a credential refusal shows Unauthorized, neither pressable; a Connect press holds its row while the write is in flight, so a second press during the readiness gate no longer retires the first press's connection and fails it at the click interval, and the readiness ping runs on a connection pool of its own, so pinging an agent that is serving a real run no longer takes that run's connection with it; a refused connect names the fix in the agent's own words and hands it over as data (
sign_in,setuporapi_key, with the command to copy:claude auth login,codex loginornpx -y @openai/codex login,hermes model), carried ondata.remedyand remembered on the row aslast_test_remedy. A row of Raven's own reportsmodel_source: "raven"and draws the host's live catalogue instead of its launch-time handshake, and the pinned adapters move to@agentclientprotocol/codex-acp 1.13.1and@agentclientprotocol/claude-agent-acp 0.81.1, so the Codex picker offers the current GPT-6 models, and the page takes the composer's own column width, at most four cards a row and none under 200px (#559, #697, #654, #554, #691, #702, #730, #731, #685, #620, #752, #707) - Sub-agents, on the page and underneath it. A
+on a roster row creates the conversation, starts the instance and opens it instead of doing nothing, a roster row carries a permanent retire control, a pane header shows how long the instance has been on its current turn (turnStartedAtMs, published only while a turn runs), and an instance can be put on a model of its own throughsubagents.instance.set_model, pushed over ACPsession/set_config_optionwithconfigId: "model", held per instance and not persisted, with a chip on one of Raven's own agents drawing the composer's catalogue. A result that lands during shutdown is logged with its conversation and stays recoverable from its record, andraven serve, the TUI and the gateway cancel sub-agents before tearing the turn spine down; a cancelled run is announced to its parent with a header, its reason and its working directory; a run whose model call failed is recorded as failed (error.md, no out.md) and skips its dependents instead of completing with the error text as its answer; two conversations running a spawn under the same model-chosen id no longer share one live account; a sub-agent of Raven's own is told the parent's model binding on every route in, andPerModelProviderno longer bills another account derived from the model id's head. Every lane records the files its run created, changed and removed from a bounded working-directory listing (up to 20000 entries, machinery directories skipped), so files a shell command produced are recorded too; an empty, unstamped~/.raven/agentsno longer shadows the shipped agent tree; and one plugin that fails to activate is rolled back alone and named in one notice (Plugin '<id>' did not load and is off for this session: <cause>, which also namesplugins.disabledas the way to stop loading it) while the rest load, withraven plugins(a command 0.1.13 already had, distinct from the newraven plugingroup) showing it as failed instead of crashing (#399, #401, #405, #408, #706, #528, #569, #642, #577, #685, #670, #722, #703) - Playbooks ship with three modes,
dag,promptandstint; amode: stintplaybook declares roles instead of nodes and the driver compiles one sub-agent graph per round (default 10 rounds), with roles handing over through an append-only journal, stray writes outside a role's boundary undone and kept underviolations/,verify[]running real commands and handing a failure back to the role that caused it up tomaxHandbacks, one approval at the start, a stint that survives a gateway or machine restart, and eightraven playbook stintscommands (list, get, stop, pause, answer, extend, sweep, resume) beside sevenplaybooks.stints.*RPC methods. Withplaybooks.agentHarnessset togenerate(defaultdefault), the generated per-turn Worker Table is exposed tospawn,run_subagent_dagandresolve_dag_node, so a generated worker can be delegated to by name, and generated agents can carryintake,advise,judgeandsalvageparticipant functions checked againstraven/playbook/harness_generation.json. A gateway client can also change the library:playbooks.set_enabled,playbooks.validate,playbooks.delete(a builtin refuses with " is a builtin and cannot be deleted; disable it instead"),playbooks.run(which requires achannel:chat_idsession_keyso progress lands in the calling conversation) andplaybooks.create(which refuses a non-kebab-case or already-taken name before any model time is spent) (#499, #558, #562, #411, #419, #429) - Raven speaks Agent2Agent 1.0 in both directions: an inbound face with a public and an extended agent card plus a JSON-RPC endpoint mounts on the gateway when
a2a.server.enabledis set, or runs standalone withraven a2a serve(defaults--host 127.0.0.1 --port 8710);raven a2a enablemints a missing bearer token withsecrets.token_urlsafe(32)and writes config.json owner-only, and outbound is onea2a_sendtool registered only whena2a.peersis non-empty. The model can drive the same shared Chromium the browser panel shows through eightbrowser_*tools (navigate, snapshot, screenshot, click, type, press, scroll, tabs) with no MCP hop, so a person can take the keyboard mid-task; reading and moving sit on the allow tier, click, type and press are asked about once per site per conversation,tools.browser.headfulOnAgentUsedefaults to false, and a market catalog entry addsmacos-mcp0.4.6 (#446, #578) - The gateway API grows. Fourteen
knowledge.*methods take material into a knowledge base four ways -- an uploaded file, a walked folder, a typed note, a fetched URL -- with recall search and per-base settings, though no page, CLI command or agent tool reaches them yet.session.usagereports from telemetry: a 14-field object withcost_usd(null when no call reported a price) and context figures, summed over the session's root key so a conversation's panel includes what the agents it dispatched spent; every model call outside the turn loop (the heartbeat decision, the sentinel planner, memory consolidation, session titles, the permission judge, the curator) now reaches the usage log once, and a heartbeat on an untouchedHEARTBEAT.mdtemplate makes no model call. A refusal that carries structured data keeps its sentence on the wire, so the page shows the reason instead of a bareconfig_validation_error(#426, #652, #715, #560) - The desk gains a tasks tab drawn from a new
tasks.listRPC -- a task is aspawnor arun_subagent_daggraph, a playbook run being one of those, with a first-match status ladder of failed, interrupted, running, cancelled, completed -- and a pill above the composer reading "{n} running" that opens it. A node panel left open on a running node re-reads its record on a 1000 ms beat and overlays live usage and tool counts, so steps, tokens and the closing message appear without reopening; it holds the end the reader dragged to (Safari's phantom scroll included), draws node cards where the layout put them on WebKit, keeps selection and running cues inside the card's clip, tags a multi-node graph "graph", reads a result-less call on a settled node as "no result", splits a run with no reasoning text into one step per thing said, folds file chips to two lines with a+Nchip, and lists every file a task's nodes wrote or edited under Task changes (a created file draws+) while deliverables lists only whatdeliver_fileshanded over; a spawn caught between its pending and running frames is no longer two rows. A file pane opens at half the shared width with a 320px floor instead of a fixed 960px, agent and task panes at 440px, and a width the reader dragged to outranks both (#509, #607, #567, #684, #641, #689, #605, #660, #651, #655, #636, #694, #656, #732) - In the transcript a finished turn's steps fold away the moment its answer lands, behind a row reading Done with the turn's clock, and a conversation reopened from history arrives with every turn folded, the last one included, instead of with its final trail spread out; an orchestration card's state row reads the graph rather than the tool call -- running while any node has not stopped, with "{ok}/{n} done" and "{n} to go" -- and a delegated result re-entering the conversation is drawn inside the card in arrival order, each answer with its own copy footer; an empty card no longer stands at the head of a turn while the model thinks, a card restored from history resolves its row by the call's
node_id, and a picture inside a delegation or tool card fits its column. The transcript fades out across a 40px ramp above whatever is docked over it instead of being cut mid-glyph, the fold, its rows and mid-turn narration read at the answer's 14px, and the header band that drew white over an off-white page is gone (#659, #626, #662, #644, #733, #539, #658, #742, #756, #667, #707) - Files and decks in the Web UI. The attachment upload ceiling is 100 MB (
MAX_UPLOAD_BYTES); the viewer's own limit is 25 MB, so a file between the two can be attached to a turn but not previewed, and the WebSocket frame ceiling is derived from the upload constant. An HTML preview says that scripts do not run in it and offers Run it here, which reloads that one.html,.htmor.svgfile through a route sandboxed withallow-scriptsand noallow-same-origin, remembered nowhere. A delivered deck is shown as pictures of its pages (render=page&p=N, the count onX-Raven-Pdf-Pages, page 1 eager and the rest lazy) so it draws on WebKit too, a delivered PDF gets a first-page thumbnail, and a backticked workspace path chip carries the path exactly as written so clicking it opens the file. The composer's Deck template button opens a sheet of the ten templates the deck engine ships, shown by their cover pages in the reader's language (an 843-entry English phrasebook beside the.pptxfiles, translated text re-fitted to its box), lets you page through a template's slides and attaches the pick to the turn like an uploaded file, overdeck.templates.list,deck.templates.pagesanddeck.templates.pick; the covers are baked into the ppt-engine wheel as one JPEG per template per language, so starting a gateway no longer launches LibreOffice to draw them, and a host without the deck engine says so in the sheet (#549, #437, #438, #678, #624, #615, #573, #661, #699) - Approvals and questions. An
ask_userbatch renders as one form the reader steps through -- step chips, Back, Skip and Next per step, the recommended option marked, a single Submit that waits until every step is answered or skipped -- and a question can bemulti_select(check boxes, labels joined with ", "); a disabled Next is painted grey. An approval request is typed on the wire (kindofshell.exec/file.write/mcp.call,family,origin,evidence), no pending approval expires (the broker's hard timeout is 24 hours instead of 35 seconds),approval.pendingredraws open requests after a reload andapproval.revokeundoes the rule one grant wrote; the sheet offersallow_sessionwhere no rule can be saved (a file write or an MCP call), the confirmation lines after an answer are gone except where something is left to undo, the prompt reads as the action being asked about (a value over 60 characters elided from the middle with its size named) rather than the call's serialised arguments, the TUI names the sub-agent that asked, and the page stops drawing the smart-mode reviewer's status line (#672, #749, #617, #632, #436, #650, #739) - A host deny rule binds what the host dispatches:
permissions.toolsdeny entries andtools.exec.extraDenyPatternsare merged into every product render, strictest wins, and the ACP approver reads the command asession/request_permissionnames (toolCall.rawInput.command, plus every codexcommandActionsentry) against the deny list and answers a match with the agent's reject option. Withrestrict_to_workspaceon, the shell tool expands parameters with the child's own allowlisted environment before scanning, socat $HOME/.ssh/id_rsaandcat ${PWD%/*}/outside.txtare refused as "path outside working dir" andcd ..,pushd ..andcd /-- through env/sudo/command wrappers and a nestedsh -c-- as "directory change outside working dir".formatis recognised by shell token rather than by regex, so&format=jsonin a URL passes whileformat c:stays hard-denied, and malformedask_userJSON is reported with the parser's line and column (#698, #527, #714) - Agent tools.
execno longer inherits the agent's stdin (stdin=DEVNULL;sshwithout-norcatreads EOF instead of eating another session's approval frames -- 18 of 183 lost in one measured process), returns when the shell exits rather than when a background child closes the pipes (server & curl ...no longer hangs to the timeout and takes the service down), and a background launch waits 0.9 s for the process to contradict it, reporting a command that died at once as ended with its exit code and log tail andok=Falseon a nonzero exit.find,list_dirand grep share one bounded tree walk that prunesnode_modulesand.git, runs off the event loop and stops at a 20-second budget with aPARTIAL resultclause instead of a clean "No files found".web_fetchreads JSON, XML and text/plain from the origin directly (2 MiB, 10 s) and hands only HTML to the reader; a reader answering 401/402 or a search vendor answering 401/402/403 is paused for 600 s with the identical<Vendor> refused the key (HTTP <status>)string so the loop's stop-repeating nudge fires and the detail names the key slot to fill; media tools and URL-gate refusals report a shorterrorwith the variable part indetail, and a failure returned as a JSON envelope counts as a tool failure, so a repeatedly failing endpoint trips the nudge at 2.raven doctorand the capability report say image search is switched off whentools.web.search.imagesis off rather than offered or missing a key. Shell commands in the main conversation report the files they wrote (file_written, withcreated,sizeandlines) and removed (file_removed) to the desk's changed-files rows, and a file a run deletes draws a red D beside A and M (#550, #646, #720, #566, #723, #572, #502, #410, #463, #692, #657) - Model streams and their failures. 0.1.13 never retried a streamed model call -- its stream path had no retry, so the first failure was the turn's answer. 0.2.0 retries a stream that fails before any reply text reached a watcher on a per-turn ladder,
agents.defaults.llmErrorRetryDelays(default[15, 30, 60]seconds; an empty list disables it), with content, reasoning and tool-call slots reset per attempt, and does not ask again once output has started unlessagents.defaults.llmRetryAfterOutput(default false; the Raven-Design and Raven-PPT agents ship it true) says so, so a late cut fails the turn once, with the words that streamed kept above the failure row, instead of re-streaming the same paragraph up to three times (the ladder and the switch arrived in commit 7eb42303, which reached main without a pull request). While the runtime waits out a failed call it says so: anllm_retrynotice carrying only the error category, drawn as a status line on the page and patched onto the TUI status bar. The failure sentence is built once asError calling LLM (<category>[@<provider>]): <detail>with the detail cut to 200 characters after classification, and a chat channel is told the category and endpoint instead of the vendor's body, which for an auth failure carried a masked key and could quote the prompt back. Thought deltas go over the ACP wire coalesced (200 ms or 512 characters), a failed turn names its exception class instead of a bareturn_failed, a replayed blocked or failed turn shows the live notice wording, and the system prompt names the model the turn actually reaches after a switch. In-turn transcript compaction is new and off by default (agents.defaults.compaction.enabled, false): switched on, once the last observed context size crosses the trigger, older tool-result bodies are pruned before a model call and, if that is not enough, the transcript head is replaced by a summary taken on the turn's own model while a recent tail stays verbatim, and an overflow retry that finds nothing left to elide takes the summary path instead of failing; the built-in Raven-Code, Raven-Design and Raven-PPT agents ship with it on (commit 387c94bd, which reached main without a pull request) (#467, #673, #688, #687, #571, #674, #472) - Raven-Design and Raven-PPT. Each design session gets its own working directory under
designs/(a session slug plus 16 hex characters of the key's sha256;plugins.config["design-engine"].workdirPerSession: falserestores the shared directory), its reply ends with "Design session directory: " so the spawning turn resolves relative paths against it, the design agent settles language, audience, length (about 20 pages) and ground from the request, memory and its defaults and asks withask_userat most once, and image search sits behindtools.web.search.images(default false), which the design launcher turns on for its own run. The route to the Raven-PPT engine opens on an attached.pptx(a route's newneedsFilesuffix, besideneedsandminTier) rather than on the max tier. Chinese in a deck draws instead of boxes: on Linux the LibreOffice offer installsfonts-noto-cjkor a pinned Noto Sans SC, on macOS the Mac's own Han faces are linked into every LibreOffice profile Raven prepares (the default profile included, which reaches upgrades without a reinstall), and a Mac without Homebrew fetches LibreOffice 26.8.0. The ppt engine finds a Homebrew or MacPorts libcairo soppt_fetchrasterises a fetched SVG on Apple silicon and refuses one it cannot draw,raven doctorgains aCairo:row andexternal_tools.cairoin--json, and the deck lane inherits everytools.web.providers.<vendor>.apiKeythe host fills and downloads with araven-ppt/<version>user agent instead of httpx's default, which wikimedia answered with 403. Binding a deck template no longer re-measures every other bundled template's menu: the measured-menu cache holds 32 entries (_MENUS_MAX = 32, a hit moved to the back) against the ten templates that ship, where the old cap of 8 evicted what the next bind needed and cost about 3 s of font measurement per bind on a laptop (#431, #648, #451, #574, #668, #719, #736, #413) - Raven-Research, Raven-Code, Raven-Design and Raven-Oncall ship as built-in agents, new since 0.1.13; Raven-PPT ships beside them as a hidden engine that Raven-Design routes
.pptxwork to, so it is not a fifth entry on the roster. Raven-Research caps its replies at 60000 characters like every other lane, re-asks its question within its turn budget when a turn ended on the model's own prose, and records verbatim search and fetch results whenRAVEN_VERBATIM_SINKnames a file. Raven-Code serves the three skill tools its menu advertises (read_skill,use_skill,find_skill) and ships with the EverOS memory backend enabled like the other agents. Raven-Oncall files a machine the owner describes through a newops_connection_addtool -- reached before anything is written,ssh -Gand~/.ssh/confighonoured, the key path stored and never the key -- instead of sending the owner to a terminal, and a campaign's spend is counted from its own ledger, so a sibling under a shared rounds directory is no longer billed against it (a round with a 130-minute budget read 125.6 minutes spent instead of its own 34.6, and stopped with 142 real minutes unspent) (#533, #410, #493, #545, #553) - Memory and EverOS. The memory subsystem talks to backends only through the
MemoryBackendcontract, so a memory plugin installs without host edits,raven doctorandraven importprint a backend's own readiness checks, and the memory and settings pages say why they are empty instead of showing four zeros. The gateway starts the memory service detached and serves without waiting for it. A rotated provider key reaches the running EverOS service: the spawn records a digest of the role credentials and re-spawns when it differs, and settings-page key writes restart the service at once. An HTTP 500 no longer marks the service unresponsive for the rest of the run, a non-final append's write budget is 10 s plus 0.5 s per message, a recalled case carries the approach it was solved with, clearing a required role is refused at every door (so Skip in the wizard no longer empties the embedding endpoint), a role moved to another provider borrows that provider's base URL instead of keeping the previous one, and at shutdown a write already handed to the service is reported as unsettled rather than lost. On native Windows Raven says long-term memory is not supported there yet instead of reporting EverOS unreachable, and stops retrying writes that cannot land. The onboarding recommendations move toqwen/qwen3.8-flash,qwen/qwen3-reranker-8bandgoogle/gemini-3.7-flash, the Azure OpenAI default becomesgpt-5.6-sol, and an EverOS spawn on Linux is gated on inotify headroom (#414, #630, #713, #415, #483, #633, #512, #544, #737, #372) - Channels. Enabling WhatsApp from Settings > Channels produces a QR code: when
bridge_urlnames this machine and nothing is listening, the adapter builds the Node bridge once intoRAVEN_HOME/bridgeand runsnode dist/index.jsas its own child, rebuilds it when the packaged source's sha256 fingerprint changes (staged in a sibling directory and swapped in only after a successful build), draws a row as paired only on the bridge'sstatus: connectedframe, and after WhatsApp logs the device out discards the stored credentials and pairs again at once. WeChat pairs again in place when iLink answerserrcode -14(waitingSESSION_RELOGIN_GRACE_S = 60seconds after a fresh scan) and drops a dead QR when login gives up. Flipping a channel's switch re-reads its status andchannels.configureanswersoutcome(started, already, stopped, absent, disabled, deny_all, missing_dep, bad_config, unknown, no_manager, or unreachable when no gateway answered); a channel whose start raised reads "not started" instead of green, saving a corrected credential restarts the adapter, a channel enabled while the gateway runs receives its inbound dispatch and joins the cron partition so a due reminder fires at once, and Feishu reconnects with exponential backoff from 5 s to 300 s instead of hammering the auth endpoint. The bundled bridge picks up sharp 0.35.4 and protobufjs 7.6.6 (#746, #757, #753, #748, #744, #745, #485, #747, #375, #386) - Localization and the TUI. Strings that lived as English literals in the TUI and Web UI come from the shared catalogue (102 keys added, "Subagent" as the one spelling); a page that never hears
config.languagefrom a gateway falls back to the browser's preferred language and rewrites<html lang>; the no-script notice is bilingual and rises above the splash after 3 s; the served first frame reads English throughout, with the permission chip's fallback as "Smart mode". In the TUI the copy-on-select confirmation is one transient line above the input that clears after 3 seconds instead of a permanent transcript row, a cancelled turn ends with "Stopped by user" (plus "- the output above is kept" when there was output) instead of a bareinterrupted, and a failed direct chat reads "Turn failed - " instead of the rawturn_failedcode (#392, #683, #686, #728, #366, #676) raven trajectorygets an interactive browser:mergeandsplitgroup traces into one attempt through anattempts.jsonsidecar (pins migrate with them), a two-line help block sits under every screen, Space opens a full-screen conversation viewer with scrolling,scollapse, a%label filter andhhelp,mopens multi-select merge, and Esc walks one level up while Ctrl+C quits.raven trajectory report-bugproduces a redacted<report-id>.tar.gzunder the trace directory'sbugreports/with acleanorneeds_reviewverdict; leftover findings are adjudicated per item on a TTY (k keep / r replace / c cancel) or through the mutually exclusive--keep-findings/--redact-findings, with--accept-riska separate authorization--yesdoes not imply.raven trajectory replay --jsonemits aschema_version 1report and exits 2 on a halt, andraven trajectory regression validate|initscaffolds and checks regression cases. The tracing viewer keeps spans with no session id under abackground:<YYYY-MM-DD>session instead of dropping them (#370, #379, #510, #380, #381, #471, #406)- A bilingual MkDocs Material documentation site ships under
docs-site/and publishes to GitHub Pages: 30 topics in English and Chinese, a landing page organised into Start here, Use Raven and Explore the documentation, a search index per language, jieba segmentation so Chinese pages are searchable by word, a search dialog whose clear button sits on the query line, paired and corrected Docker, sandbox, tracing-API and proactivity pages, a contents rail that follows the reader through a section longer than the screen, and the same favicon as raven.evermind.ai. Five README reference sections (self-hosting, the command reference, the documentation index, the repo layout, the architecture) move there, and both READMEs gain a benchmark figure, built-in agent sections and an eleven-run showcase (#507, #516, #518, #521, #551, #635, #734, #519, #480, #517) - Pinned Python dependencies rise to close all 33 Dependabot advisories on
uv.lock, the manifest a user's install is built from -- most of them with a reachable path in Raven, the mcp and cryptography ones taken so no alert is left standing: pillow 12.3.0, mistune 3.3.4, aiohttp 3.14.3, json-repair 0.63.4, mcp 1.30.0, cryptography 50.0.1, h2 4.4.1, hpack 4.2.0 and pip 26.2.1 (#448)
Install
New install on Linux, macOS, or WSL2:
curl -fsSL https://raven.evermind.ai/install.sh | bashNew install on native Windows, in PowerShell:
irm https://raven.evermind.ai/install.ps1 | iexWindows PowerShell 5.1 (the version built into Windows) rejects that URL with
Permanent Redirect; use the direct one instead:
irm https://raw.githubusercontent.com/EverMind-AI/Raven/refs/heads/main/install.ps1 | iexThe installer puts uv, Node.js 22, Raven and its plugins in place, downloads the
browser runtime, offers LibreOffice, and then finishes by opening Raven in your
browser. First-run setup happens on that page. The installer holds the terminal
while the page is up; press Ctrl-C to stop it, then start Raven again with:
raven webThat keeps Raven running in the background and opens the page; raven web --stop
stops it. Prefer the terminal? raven runs the same first-run setup and opens
the TUI, and raven onboard stays the explicit way to reconfigure later. Set
RAVEN_MINIMAL=1 to skip the browser and LibreOffice downloads, or
RAVEN_NO_LAUNCH=1 to have the installer return without opening the page.
Upgrade
Already running Raven? Upgrade in place -- configuration, sessions, and memory
are preserved. Stop the page first, then upgrade:
raven web --stop
raven upgradeOn Linux and macOS raven upgrade runs the install in the foreground and
returns when it is done. On native Windows it hands the install to a separate
helper and returns at once; wait for the helper's completion message. Then
start Raven again:
raven webraven upgrade installs the latest stable release together with the plugin
wheels it ships. It never picks up a pre-release unless this install has joined
the beta channel (a ~/.raven/beta.json that only the beta installer writes).
raven upgrade --check reports whether a newer release exists without
installing it. Editable source checkouts are never overwritten: raven upgrade
reports the checkout path and how far it is ahead of or behind origin/main,
and the remedy is git pull && ./install.sh in the checkout. Rerunning the
one-line installer also upgrades, and ends on the running page.
Release Status
- Version:
0.2.0 - Tag:
v0.2.0 - Stability: public preview minor
- Assets: the
ravenwheel and source distribution, the three plugin wheels
(everos_memory,design_engine,ppt_engine), the locked constraints file
raven-constraints.txt, and the plugin listraven-plugins.txt
Notes
- Raven is still pre-1.0; CLI surfaces, plugin contracts, and runtime internals may continue to evolve.
- PyPI publishing is not enabled yet; the supported public install path uses the GitHub Release wheel asset.