Repository navigation
Releases: OAraLabs/Prometheus
Release list
Prometheus v0.9.20
Prometheus 0.9.20 — beta
0.9.20 fixes a security issue: a file tool could be redirected through a link to a file the permission gate protects. It also:
- turns off memory learning from chats with one switch;
- connects to MCP tool servers over HTTP;
- lets the operator hold a device to a profile;
- keeps addresses out of
/anatomysent through a chat service.
Security
- A file tool opens exactly the path the gate checked (GHSA-wgcv-xw9m-9q9q).
- Before: the file tools (
write_file,edit_file,read_file,notebook_edit,download_file,image_generate,tts,youtube_transcript,video_generate,grep,lsp, and the coding run's view, edit and create tools) run inside the daemon, outside the shell floors. The permission gate checked a tool's path, resolved; the tool then opened the path again by name, following links. A folder in the workspace swapped for a link to a protected folder between the two, by a shell or task running at the same time, sent the write or read to the protected file. A hard link to a protected file inside the workspace passed the gate with no race at all. - Now: the path the gate checked travels with the call, and the tool refuses, naming both paths, when its own resolution differs. The file is opened one folder at a time from
/without following any link, so a link that appears after the check fails the open. Writes go to a temporary file in the same folder and replace the target atomically, keeping its read, write and execute bits; a reader never sees half a file. A file with more than one link is not read when it is one of the files the gate refuses to read. A tool called with no gate (a script, a test) still checks the floor itself. - Behaviour change: a link that already exists when the gate checks still works, and a write to a symlinked file still writes its target. A write now replaces the file instead of rewriting it, so a file that has other hard links gets a new file under the name you wrote, and its other names keep the old contents; its owner, extended attributes and ACLs are those of a new file. A file this user may not write is refused as before. A single file bind-mounted into a container, which cannot be replaced, is rewritten in place.
- Before: the file tools (
Also
/anatomysent through Telegram, Discord or Slack no longer shows hostnames, IP addresses, URLs or the names and addresses of your tailnet peers. Those services keep every message on their servers. The reply keeps what the machines can do, and counts the peers. In the terminal and in Beacon/anatomyshows everything, as before.anatomy.include_addresses_in_chat: trueshows everything on chat too. (#885)- When a model server runs on another machine and no SSH user is set to read its GPU,
/anatomy, the model's Infrastructure section and doctor now say the GPU is "not configured". Before, every scan logged a warning that the probe failed,/anatomycalled the GPU unreachable, and doctor reported no GPU and running on CPU. (#885) memory.extraction.enabled: falsestops memory being learned from chats. The fact extractor, the wiki compile after it, the SENTINEL insight writer, the agent'smemorytool andwiki_query's saving of questions are not built or started. Recall,/noteand the memory editor are unchanged.prometheus doctorreports the switch. (#889)- MCP servers can be remote: a
urlconnects over streamable HTTP (transport: streamable-http) or SSE (the default). Before, aurlserver was always marked failed as "not yet implemented". The server's storedheadersare sent on every request to it and are never shown or logged. The server store now refuses aurlthat isn'thttp://orhttps://, and a header name or value that could break the request. (#892) - Devices: the operator can hold a device to a profile (
PUT /api/devices/{id}/profile). Every run under that device's sessions is offered only the profile's tools and refused any other at the call, with no fallback that widens it, and the device cannot lift or change the hold. One instance can then serve its owner with every tool beside a server-to-server caller that stays read-only. (#893)
Upgrading from 0.9.19
- Nothing to do beyond the upgrade. A file tool that now refuses a path names both the path it checked and the one it found; a refusal like that means a link changed under it.
- Linux with the AppArmor profile: if you have not yet installed 0.9.18's profile, do it now (see the 0.9.18 notes); 0.9.20 adds no new rules.
Prometheus v0.9.19
Prometheus 0.9.19 — beta
0.9.19 is a small patch release. Its fix: file_watch tasks never fired with watchdog 7 (fresh pip and Homebrew installs of 0.9.18). It also:
- installs watchdog from a wheel on a Mac with Python 3.14, so file_watch is event-driven there again;
- names the model that answered on every chat response (
served_by); - sends a keyed llama.cpp server its key from
oara doctor, the anatomy scan and the terminal chat; - keeps hostnames and addresses out of what the model is told about your machines.
The fix
- Tasks: a
file_watchtask fires again when watchdog 7 is installed. watchdog 7.0 (2026-10-31) matches a handler's patterns against the whole path, so*.jsonstopped matching/dir/result.jsonand the task waited until its timeout. 0.9.18 allows watchdog 7, so a fresh pip install on Linux or on a Mac with Python 3.13 or older, and the Homebrew formula, got it; installs from the lock (the Mac app,scripts/deploy.sh) kept 6.0.0. The file's name is now matched against the pattern the same way the check for a file that is already there does.
Also
- Install: watchdog is a base dependency on every platform again, from 7.0, the first release with macOS wheels for Python 3.14. 0.9.18 skipped it on exactly that platform; a Mac on Python 3.14 now installs it from a wheel and gets event-driven
file_watchinstead of polling. Polling stays for an install without watchdog. - Models:
oara doctor's Inference row, the anatomy scan and the terminal chat now ask a llama.cpp server started with an API key with that key, so a keyed server no longer shows as not responding and the chat can read its model and chat template. The key is the model's own (model.api_key_env), read from the environment and then the env file. A named variable that is set in neither is reported by name instead of as "not responding". - The model is no longer told where your machines are. The Infrastructure section of its prompt and the
anatomytool's answers keep what the machines can do (CPU, RAM, GPU and VRAM, the model, its engine, context window and vision) and leave out hostnames, IP addresses, URLs, the tailnet peer list and the folder a model file sits in, on local and hosted models alike. Before, a reply could quote the model server's address or list your tailnet peers.anatomy.include_addresses: truerestores the old text. The/anatomycommand you run yourself is unchanged. - Each chat response names the model that answered:
served_byonPOST /api/chatand on thechat_doneframe, andprometheus.served_byon/v1/chat/completions(on the final chunk when streamed). When a fallback answers instead of the configured model,served_bynames the fallback./v1'smodelstill echoes the key you asked for.
Upgrading from 0.9.18
- Nothing to do beyond the upgrade. If a
file_watchtask never fired on 0.9.18, it fires on 0.9.19; re-create any that timed out. - Linux with the AppArmor profile: if you have not yet installed 0.9.18's profile, do it now (see the 0.9.18 notes); 0.9.19 adds no new rules.
Prometheus v0.9.18
Prometheus 0.9.18 — beta
0.9.18 fixes two security issues: a model's shell and file tools could read this machine's private keys and change what the daemon starts at boot, and an agent profile's tool list hid tools from the model without stopping it calling them. It updates authlib, dnspython, joserfc, pyasn1 and graphql-core for published advisories. It also:
- lets a paired app check it reached the Prometheus it paired with before it sends its token;
- lets voice use a speech server on another machine, with local fallback;
- uses a llama.cpp server started with an API key;
- says which local AI app answered setup's look, and why none is usable;
- keeps your account name, your machine's layout and a purged chat's facts out of what the model is sent and keeps;
- fixes five computer-use problems on Linux desktops;
- installs on a Mac with Python 3.14 without a compiler.
Security
- A model's shell and file tools can't read the node keys or change what starts the daemon (GHSA-9ff8-vhh2-r2cw).
- Before: the floors from GHSA-wq93-7fvg-53pj (the macOS sandbox profile, the Linux AppArmor profile, the permission gate's always-denied list) left out the node keys (
node/node.keyandnode/instance.key, which paired apps pin), the MCP server store (data/mcp_servers.json, started at boot), the xAI sign-in tokens (xai_oauth.json), the cron jobs' PATH shims (data/job-python/),lcm.db(each conversation's workspace and profile),config_pins.yaml, the file checkpoints, the custom agent profiles, and what starts Prometheus: its LaunchAgent plist, its systemd unit and drop-in folder, and the install it runs from. Your cron jobs, the daemon's worker and coding-run launches and command hooks ran as login shells, outside the floors, so a login file a model's shell had written ran there. - Now: the keys, the MCP store and the xAI tokens can't be read or written, and the rest can't be written, by a shell or a file tool, wherever
PROMETHEUS_NODE_DIR,PROMETHEUS_DATA_DIRorPROMETHEUS_CONFIG_DIRput them. A file tool's write to a profile asks the owner. The startup files covered are the plist, the unit and its drop-ins, the deploy's venvs and clone (~/prometheus-venvs,~/prometheus-deploy/scriptsandsrc), a pipx oruv toolinstall, and the install the daemon runs from. Reading and running them still works. Each stored MCP server is checked again before it starts, and one that fails is skipped and named in the log. A checkpoint never copies a link or Prometheus's own files into its store. A restore writes only inside the conversation's own workspace, never through a link, never into Prometheus's own files and never with setuid, setgid or sticky bits. - Behaviour change: your cron jobs, worker and coding-run launches and command hooks run
bash --noprofile --norc -c, andBASH_ENVandENVare dropped, even from a hook'senv_allowlist. A job or hook that relied on its login profile for PATH or a variable must set that up itself, for example withsource ~/.profileat the start of the command. A stored MCP server saved before a check was added may need saving again. - Known limit: files your own programs read later (your shell's login files, an editor's or another tool's config and plugins) are yours, not Prometheus's, and the floor does not cover them.
- Linux: install the new AppArmor profile and reload it (
sudo cp deploy/apparmor/prometheus-bash /etc/apparmor.d/prometheus-bashthensudo apparmor_parser -r -W /etc/apparmor.d/prometheus-bash). Until you do, the shell keeps its old floor and the daemon reports the profile as stale at startup, with that command. An install outside the profile's default places is named at startup. macOS needs nothing.
- Before: the floors from GHSA-wq93-7fvg-53pj (the macOS sandbox profile, the Linux AppArmor profile, the permission gate's always-denied list) left out the node keys (
- An agent profile limits what a conversation can run (GHSA-qgfv-m38j-2c6w, #860). Before, a model that named a tool its profile left out (
researchhas no file writes;exclude_tools: [bash]drops bash) ran it, under the same approvals and floors as thefullprofile. Now such a call is refused with an error naming the profile. A subagent gets only the tools both its type and the conversation's profile allow,task_createruns a shell command (local_bash,poll) only when the profile includesbash, and a profile that leaves any tool out starts no worker process (task_createlocal_agent,sessions_spawn); its subagents keep the limits instead. Deferred tools the profile allows, and tools left out only bymax_tool_schemas, still run. - Dependencies in the lock, for published advisories: authlib 1.9.1 and dnspython 2.9.0 (#867; CVE-2026-96760, CVE-2026-114614 to CVE-2026-114618, CVE-2026-114620, CVE-2026-114605), joserfc 1.7.7 (#875; CVE-2026-119284), pyasn1 0.6.5 (CVE-2026-119194 to CVE-2026-119197) and graphql-core 3.3.1 (CVE-2026-119286). All reach Prometheus only through the
evalsextra, and pyasn1 also through thegoogleprovider.
Identity and pairing (#864, #865, #866)
- Identity check:
POST /api/identity/challengelets a paired app check it reached the Prometheus it paired with before it sends its token. The daemon signs the app's 32-byte nonce with its node key, binding the instance id, the node key, and on the TLS port the certificate's SPKI digest. No token, no cookie, nothing written; hello's rate limit. FOUNDATION is now Version 4: the node key may sign identity challenges, and is still never proof of the user (the bearer token is). - Pairing: every route a device joins through (an approved request, an owner code, same-Mac pairing) now hands it
instance_idandnode_pub, the key it pins for the identity check. A request that sendsmatch_code_version: 2gets a 4-digit code that also covers the node key, so the owner's check confirms it; requests that don't send it get the same code as before. Contractpairing/0.2. - Status:
GET /api/statusgainsnameandfp, the same valuesGET /api/helloanswers, besidenode_pubandinstance_id, so a client paired with several Prometheus instances can tell them apart. Additive only;/healthstill carries no identity.
Voice on another machine (#862, #876)
- Speech-to-text and text-to-speech can use a voice server on another machine. Set
stt.url(an OpenAI-compatible/v1/audio/transcriptionsserver) ortts.url(/v1/audio/speech); naming just the server (http://127.0.0.1:8001) is enough, andwhisper.urlis accepted forstt.url. The key comes from the variable named inapi_key_env, elsePROMETHEUS_STT_API_KEY/PROMETHEUS_TTS_API_KEY, read from the environment or the env file and never fromprometheus.yaml. Withtts.voiceempty, now the default, the server picks its own voice. - If the server can't be reached, that request runs on the local engines and leaves one log line. A refused key or a 400 (an unknown voice or model) also falls back to local, but logs an ERROR.
oara doctorshows whether each configured server answers. With no url set, voice runs locally as before. This covers Telegram and Discord voice notes, Telegram voice replies,oara --voiceand thettstool.
Models and setup
- llama.cpp with an API key (#877): a llama.cpp server started with
--api-keycan be used as the main model, in a router rule or fallback, and as a named backend. Name the variable that holds the key inapi_key_env(the key itself goes in the env file); it is sent as a bearer token on every request, including the probes, and never logged. A named variable that is not set is an error naming it. With no key set nothing changes. Anapi_key_envon an Ollama entry is still refused, since Ollama takes no key. - Setup says what it found (#868): when Prometheus looks for an AI app on this computer (
GET /api/setup/detect) or on one you name (POST /api/setup/probe), it says which app answered (Ollama, LM Studio, llama.cpp, vLLM or another OpenAI-compatible app), which models it serves, and why none is usable when none is: too short a context window, nothing loaded, no chat model, needs a key, or no answer. Configure checks the chosen model the same way. A model needs a window of at least 24,576 tokens.GET /api/setup/statuslistslocal_probeinfeatures. - Doctor (#861): the Config check looks for
prometheus.yamlwhere the daemon does (--config, then the checkout'sconfig/prometheus.yaml, then$PROMETHEUS_CONFIG_DIR, default~/.prometheus) and names the file it found. Before, a daemon running on~/.prometheus/prometheus.yamllogged "config/prometheus.yaml not found" at every start. - Config (#873): five keys nothing read are gone from the shipped
prometheus.yaml:model.fallback_providerandmodel.fallback_url(a fallback model is set undermodel.fallback), andinfrastructure.gpu_host,mini_hostandmini_port.oara setupno longer writesmodel.fallback_url, and the env fileoara initwrites no longer suggestsPROMETHEUS_TELEGRAM_CHAT_IDS; the chats Telegram answers in aregateway.allowed_chat_ids. An existing config with these keys keeps working.
What the model is sent and what is kept
- No account name or machine layout in every prompt (#853, #856): hosted models are sent paths under your home folder as
~/…instead of absolute paths, and tool descriptions no longer name a person (the brain-vault tool says "the owner's second brain"). They no longer receive this machine's hardware, services and network (the anatomy section, which could include tailnet peer names) in every prompt; they get a pointer to theanatomytool and call it when a task needs the layout.anatomy.include_in_hosted_prompt: truerestores the old behaviour. Local models are unchanged. - A purged chat's facts go too (#854): purging a chat now also retracts what was learned fro...
Prometheus v0.9.17
Prometheus 0.9.17 — beta
0.9.17 fixes two security issues: chat gateways let anyone in an allowed group approve tool calls and change what the agent remembers, and a shell command the model ran could rewrite the files Prometheus trusts as its own. It pins the Mac app's bundled Python at 3.12.15 (OpenSSL 3.5.9), and updates opentelemetry, filelock and setuptools for published advisories. It also:
- warns when the web API token sits where the agent's shell can read it;
- asks before a file tool writes a project instruction file, and refuses invisible text in skills and memory;
- keeps the memory extractor from skipping messages when its model call fails;
- makes computer use work with SENTINEL off, and type into GTK4 text fields;
- keeps genuine user requests in self-improvement evidence (#788, by @sepehrtaji-dev).
Security
- Only a chat gateway's owner approves and teaches (GHSA-c3c2-8vrj-x346).
- Before: the Telegram, Slack and Discord gateways went by which chat a message came from, not who sent it. In an allowed group chat, Slack channel or Discord server, any member could approve or deny the agent's tool calls (including
/approve alwaysand/gate off), have their message run as if the owner had typed it, and add to memory, skills and self-improvement data. Approval prompts and the daemon's own notices that had no chat of their own went to the first allowed chat, so a group listed first saw them. - Now: each gateway has an owner. Only the owner approves tool calls or uses the owner-only commands. Members can still chat: their messages are recorded as theirs, any tool their message asks for waits for the owner, and nothing they say goes into memory, skills, self-improvement or training data. Approval prompts, cron-failure notices and background-task notices go only to the owner's private chat.
- Not affected: Telegram with only your own private chat allowed, and Beacon and the REST and WebSocket API, which authenticate devices rather than chats.
- Before: the Telegram, Slack and Discord gateways went by which chat a message came from, not who sent it. In an allowed group chat, Slack channel or Discord server, any member could approve or deny the agent's tool calls (including
- A model's shell can't rewrite Prometheus's trusted state (GHSA-wq93-7fvg-53pj).
- Before: none of the shell's floors (the macOS sandbox profile, the Linux AppArmor profile, the permission gate's always-denied list) covered the device registry, the config file, the identity files,
MEMORY.mdandUSER.md, skills, or the scheduled-jobs files. A shell command the model was talked into running could create a trusted device token, rewrite the config, plant lasting instructions, or plant a cron job that runs as the owner. Mainly macOS, where the shell has no write floor. - Now: these files are under the same floors as your keys. Writing, appending, replacing, deleting, linking, planting a side file and renaming their folders are refused; reading still works, and so do Prometheus's own writers. The file tools refuse the device registry, the config file and the scheduled-jobs files, and ask before writing the identity files, memory or skills. The daemon tests the floor at startup and reports a stale AppArmor profile at ERROR.
- Before: none of the shell's floors (the macOS sandbox profile, the Linux AppArmor profile, the permission gate's always-denied list) covered the device registry, the config file, the identity files,
- The Mac app's build pins CPython 3.12.15 and OpenSSL 3.5.9 (#843). The 0.9.16 app was rebuilt with them by hand; from 0.9.17 every build gets them. They fix CVE-2026-19445 and CVE-2026-19553 (ssl), CVE-2026-82049, CVE-2026-19672 and CVE-2026-87910 (tarfile), CVE-2026-15310 (zipfile), CVE-2026-15806 (urllib) and CVE-2026-17084 (StringPrep). The unused libpython dylib is no longer shipped.
- opentelemetry 1.45.1 and arize-phoenix-otel 0.17.2 (#844) fix CVE-2026-114603, in the
evalsextra only. filelock 4.2.4 and setuptools 84.2.1 (#857) fix CVE-2026-112940, CVE-2026-112913 and CVE-2026-112907 (filelock) and GHSA-xmj3-9gf7-h52w (setuptools). Onlyuv.lockchanges.
The API token's location is checked
- What changed. At startup, in
GET /api/statusand inoara doctor, Prometheus says so loudly when the web API token sits where the agent's shell can read it even with the bash read floor on:web.api_tokenis set inprometheus.yaml;PROMETHEUS_API_TOKEN_FILEnames a file outside~/.config/<name>/*env;- the env file holding the token was moved out of that pattern by
PROMETHEUS_ENV_FILEorXDG_CONFIG_HOME.
- What to do. Move the token to
~/.config/prometheus/envasPROMETHEUS_API_TOKEN=<token>(oara token showprints it), then remove the setting that held it, and restart. - Without an active read floor (it is off, or the daemon runs in a container) every location is readable alike, so nothing is said. The warning never names the token or the token file's path.
Hardening shipped with GHSA-wq93-7fvg-53pj
- Project instruction files ask first. A file tool's write to a project instruction file asks the owner, even inside the workspace, with approvals off or under a saved grant. These are the files the prompt assembler loads from the session's workspace upward (
PROMETHEUS.md,AGENTS.mdand the other convention files the README lists) and.prometheus/rules/*.md. - Skills and memory refuse invisible text. Characters that hide text from a person reading it are refused: tag characters, bidi embeddings, overrides and isolates, the zero-width space, the word joiner, invisible operators, a byte-order mark mid-text, and the supplementary variation selectors. The zero-width joiner and non-joiner, LRM and RLM, the emoji variation selector and a leading byte-order mark stay allowed.
Memory extraction (#841, #842)
- A failed model call no longer loses messages (#842, from #832 by @sepehrtaji-dev). An outage, rate limit or timeout used to look the same as "nothing to remember", so the extractor's cursor moved past the batch. Now the cursor stays where it was and the next pass retries the batch.
- JSON-shaped output with no facts is logged (#841, from #807 by @lijinhongucl-pixel). A reply that looks like JSON but yields no facts logs a WARNING. Prose with no brace,
[]and{"facts": []}stay quiet.
Self-improvement keeps genuine user requests (#788, by @sepehrtaji-dev)
- GEPA's request evidence no longer drops a message whose
provenanceisuserjust because its trust flag is false. Untrusted messages from other sources are still withheld.
Computer use (#845, #846)
- The desktop cockpit works with SENTINEL off (#845), the shipped default. Before, Beacon never saw its own app pick, any step, the end of a task or a thumbnail, because only SENTINEL built the signal bus the cockpit rides.
- A GTK4 app's text fields can be set (#846). GTK4 reports them as "text box", a role the candidate table did not offer, so a task could never type into GNOME Text Editor or any other GTK4 field.
Upgrading from 0.9.16
- Linux with the AppArmor profile: reload it BEFORE restarting the daemon. Until you do, the daemon reports a STALE PROFILE at ERROR:
sudo apparmor_parser -r -W /etc/apparmor.d/prometheus-bash - Telegram: if you allow only your own private chat, nothing changes. If you allow a group, set
gateway.owner_user_idsto your Telegram user id. - Slack: set
gateway.slack.owner_user_ids. Until you do, nobody on Slack can approve, and Slack messages don't add to memory. - Discord: the owner of the bot's Discord application is the owner unless you set
gateway.discord.owner_user_ids. - Telegram notices: approval prompts with no chat of their own, cron-failure notices and task notices go to
gateway.briefing_chat_idwhen it is a private chat, else to your private chat, else nowhere. A groupbriefing_chat_idis not used for them, with a warning. - File-tool writes to identity files, memory, skills and project instruction files now ask you, even with approvals off or under a saved grant.
- API clients:
GET /api/statusgains a top-levelwarningslist of{code, level, message, fix}.
Prometheus v0.9.16
Prometheus 0.9.16 — beta
0.9.16 makes a fresh setup listen on this machine only until you choose otherwise, and turns on the context compactor that installs made by oara setup, setup mode and Beacon's first run never had. It updates certifi and Pillow for published advisories. It also:
- makes Beacon's model list show whether your own AI is reachable, and name it;
- makes
oara doctorand the boot check look for your model server where the config says it is; - removes the
CancelledErrortraceback that every shutdown and restart logged; - makes
oara pair --ownerfit a Beacon on this Mac as well as one on another computer.
Security
- Setup mode listens on this machine only unless you choose otherwise (#833).
- Before: a daemon started with no config and no
--bind(pip, brew, source,oara install-service) listened on every interface until setup finished. Anyone on the same network could try the six-digit pairing code. A right guess (5 tries in a million per start, within the code's 15 minutes) returned the daemon's API token, and five wrong guesses locked the owner out until a restart. - Not affected: the Mac app (always loopback), the container image (it sets
PROMETHEUS_WEB_BINDon purpose), and anyone who ranoara setupfirst. - Now: to set up a headless box from another computer, start it with
oara daemon --bind 0.0.0.0. Setup mode then listens on every interface, and so does the daemon it becomes.
- Before: a daemon started with no config and no
- certifi 2026.10.19 and Pillow 13.0.0 (#839). They fix PYSEC-2026-4320 (certifi) and CVE-2026-112395, -112397, -112400, -112404, -112895, -112896, -112897 and -112899 (Pillow). Only
uv.lockchanges; the floors inpyproject.tomlare unchanged. - The Mac app now bundles Python 3.12.15 with OpenSSL 3.5.9, which includes the CPython SSL fixes CVE-2026-19445 and CVE-2026-19553.
The context compactor is on for installs Prometheus set up (#834)
- What went wrong. No config written by
oara setup(interactive or--fast), by setup mode, or by Beacon's first run turned the compactor on. Withoutcompaction.enabledit is not built, so those installs have run without it since it shipped in June. The template ships it on. LCM still summarised history between turns, but nothing kept a long multi-round tool turn inside a small local window. - What changed.
- Every writer now writes
compaction: {enabled: true}. - At start, a config with no
compaction.enabledfollows the template, turns the compactor on, and logs a warning naming the line to write. The file is not edited. - An explicit
compaction.enabled: falsestays off.
- Every writer now writes
Beacon's model list tells the truth about your own AI (#835)
- The Local row's
availablefollows the last probe of the primary. It was alwaystrue. GET /api/modelsre-probes the primary when that probe is older thanbackend_probe.ttl_s.- The row is labelled with the engine and the model it serves, for example "llama.cpp · Qwen3.8-27B", instead of "Local".
- A primary the registry does not probe (LM Studio, vLLM, a cloud primary) stays available, as before.
Doctor probes the configured address (#836)
- What went wrong. The boot check and the chat
/doctorusedmodel.base_urlonly for llama.cpp. For every other provider they probedmodel.fallback_url, by defaultlocalhost:11434. So an Ollama, LM Studio or vLLM server at any other address, and any cloud model, was reported "not responding".oara doctordefaulted every local provider to:8080, and asked/v1/v1/modelsfor a base ending in/v1. - What changed.
- Every check probes the address the provider is reached at:
model.base_url, else its base-URL variable, else its default. - Ollama is asked
/api/tags. The OpenAI-shaped servers are asked/v1/models, once. - A cloud primary gets an info row instead of a probe.
- Every check probes the address the provider is reached at:
Clean shutdown (#837)
- What went wrong. Stopping or restarting the daemon logged a
CancelledErrortraceback at ERROR. The daemon cancelled the web server's task, so uvicorn never ran its own shutdown, and its shutdown steps (withdrawing the network announcement, stopping the pairing sweeper) ran only as the process exited. - What changed. The web server now shuts down properly when it is stopped. It waits at most 5 seconds for open requests.
oara pair --owner fits this Mac and another computer (#838)
- The code banner and the expiry line no longer say "the other computer".
- When the code is used, the terminal says whether that Beacon was on this Mac or on another computer, from what the daemon saw. A relay on this machine, such as Tailscale serve or cloudflared, counts as another computer.
- The
owner_codeframe'sredeemed_bygainsthis_host. - The example device name in the owner-code tests and docs is "Alex's MacBook Pro".
Upgrading from 0.9.15
- Setup from another computer: start the daemon with
oara daemon --bind 0.0.0.0(or setPROMETHEUS_WEB_BIND). Without either, setup mode now listens on this machine only. - Compactor: an install whose config has no
compaction.enabledgets the compactor at its next start, with a warning naming the line to write. To keep it off, writecompaction.enabled: false. - Beacon and other API clients: the Local row of
GET /api/modelsis labelled with the engine and the model it serves, and carriesdetail(the served path) when the primary was probed. Itsavailablecan now befalse. - No migration.
Known issues
- The known issues listed for 0.9.13 still apply.
Prometheus v0.9.15
Prometheus 0.9.15 — beta
A small maintenance release.
- Dependency security update. The minimum aiohttp version is now 3.14.4 (with yarl 1.25.1), picking up upstream security fixes. Only the optional Discord and Slack gateways use aiohttp; Prometheus's own web server does not.
- Slack extra fixed.
pip install 'oara-prometheus[slack]'now installs everything the Slack gateway needs. - Docs and tests use a generic example device name.
No config, service or deploy changes since 0.9.14. Upgrade with Homebrew, or pip install -U oara-prometheus.
Prometheus v0.9.14
Prometheus 0.9.14 — beta
Two small fixes for installs that aren't a git checkout of Prometheus, such as Homebrew and pip.
- No more false "new code on disk" notice. On Homebrew and pip installs,
/api/statusnow reportsnot_checkoutwith no commit SHAs instead of comparing against a repo that isn't there. (#827) - Git fetches only happen in a Prometheus checkout. The update check now fetches from origin only when Prometheus is running from its own git checkout. (#826)
No config, service or deploy changes since 0.9.13. Upgrade with Homebrew, or pip install -U oara-prometheus.
Prometheus v0.9.13
Prometheus 0.9.13 fixes tool calling on local models: a local turn can now call every tool, where since late July it could reach only the dozen or so always sent to it.
Highlights
- Every tool is callable on local turns (#819). On a 27B model, the right tool was picked 12 of 12 times, with correct arguments first try 11 of 12.
- Smaller first request on local turns (#820): about 19.2k → 13.8k tokens.
- llama.cpp reply cap back to 4096 (#813), so 32k sessions don't compact early.
- Beacon shows the text of turns the loop ends itself (#811).
- Ollama gets the context window Prometheus plans for (#815), with no more silent front-truncation.
- Startup warnings for guessed context windows and overrides that match nothing (#814).
- Hardening on Linux (#825): the daemon process is non-dumpable, and the service unit no longer passes keys through the environment.
Upgrading
pip install -U oara-prometheus, or update the Mac app.- Linux service installs: an upgrade doesn't rewrite the installed unit. If you installed it with
oara install-service, runoara install-service --force, thensystemctl --user restart prometheus.service(the old unit is backed up toprometheus.service.bak). If you wrote your own unit, just delete itsEnvironmentFile=line, thensystemctl --user daemon-reloadand restart. - Read "Upgrading from 0.9.12" in the CHANGELOG for config changes.
Prometheus v0.9.12
Prometheus 0.9.12 — beta. Compaction now counts in the server's own tokens and, when a server says the prompt is too long, compacts and retries once instead of ending the turn (#805). Beacon sessions can use subagents: the agent tool always failed from Beacon before (#806). Each model gets its own reply-size cap instead of a flat 4096, and a tool call that the cap cut off is refused with an explanation instead of running with empty arguments (#806). web_search names its error and retries once, and Beacon no longer badges every assistant reply "untrusted" (#806). Coding mode sees files at the root of a repo: code_glob and code_grep read **/ as "any number of directories, including none" (#802, fixes #801; first tagged as 0.9.11, which was never published).
Upgrading from 0.9.10: local sessions will compact more often, because the 80% line is now measured in the server's tokens rather than a low estimate; the reply cap changed for every request (llama.cpp models ask for up to 8192 tokens, known cloud models get their own value, unknown models keep 4096); context.model_overrides.<model>.max_output_tokens pins one model's cap. No config change is needed. The lock also moves pydantic-ai-slim to 1.107.7 for eight advisories; it is used only by the evals extra, not by the daemon, the Mac app or the Docker image. Full list in CHANGELOG.md.
Known issues
- A tool call cut off three times in a row ends the turn (#809). The circuit breaker counts the cut-off refusals like malformed calls, and its recovery (a stricter adapter tier) does nothing about length.
- A daemon started with
--config <path>outside the search path does not hand that path on (#799, #800): managed coding runs refuse with "coding mode is disabled", and the daily-briefing cron job reads its config from the search path. - The memory extractor can save no facts, silently, when the model pretty-prints its JSON (#798). Seen with a 7B model on Ollama; the log line
MemoryExtractor: persisted 0 memories from N messagesis the only sign.
Install
- Mac (Apple Silicon, macOS 13 or later):
Prometheus-mac-arm64.zipbelow, signed and notarized by Apple; Beacon can install it for you. - pip:
pip install 'oara-prometheus[full]', orpip install oara-prometheusfor the base install. PyPI
Prometheus v0.9.10
Draft release for v0.9.10 — publish manually after review.