Skip to content

Release Notes

A curated, reverse-chronological summary of user-facing changes in vornik. Each entry highlights what changed for you as an operator — new features, behavior changes, and notable fixes. Internal-only changes are omitted.

Upgrading

New configuration keys are additive and default to the previous behavior, so upgrades generally require no config changes. Always take a backup before upgrading. A few releases ask you to restart the daemon to pick up new behavior; those are called out below.


2026.10.8

Unreleased draft.

2026.10.7

Upgrade requirements

  • Existing installs: give the database its own password. A fresh quickstart generates a per-install database password. An install that kept a volume with no known password now stops and writes nothing, instead of continuing on the shipped default, and the bundled compose files refuse to start without POSTGRES_PASSWORD. Three doctor checks report a weak, reused or network-exposed database credential: db_credential_strength, db_listen_exposure and credential_reuse.
  • The operator surface needs an admin-class key (403 OPERATOR_CAPABILITY_REQUIRED). This covers config reads and reload, the memory firewall, operator profiles, the operator audit, control-plane changes, setup and the project wizard. Add any api.api_keys entry that needs them to admin.allowed_keys. Auth-off installs and the quickstart key are already admin-class.
  • Logs and error text follow the key's scope. A project-scoped key reads a scrubbed view of its own project's logs, explain output and error fields. An unscoped key that is not admin-class reads none (403 PROJECT_SCOPE_REQUIRED).
  • Agent keys reach only the routes the agent image calls, and get 403 AGENT_KEY_NOT_OPERATOR on every other route.
  • Operator-typed URLs dial through the SSRF guard, redirects refused: the MCP Test probe, MCP OAuth, the GitHub App API base and broker fetches. Add a LAN or loopback server's hostname to integrations.allowed_hosts.
  • With auth off, the daemon answers only its own names. When api.auth_enabled is false (including api.auth_dry_run), the HTTP listener refuses, with 403, a request whose Host is not an IP address, localhost, host.containers.internal, the host of server.public_base_url or auth.external_base_url, or a name listed in the new server.accepted_hosts. This stops a web page from reading daemon answers through DNS rebinding. A cross-site POST is refused too, and Sec-Fetch-Site: none no longer counts as same-origin. If you reach an auth-off daemon by a LAN name, for example the machine's hostname or a router DNS name, add that name to server.accepted_hosts. Installs with auth on are unchanged.
  • Generic webhook sources accept only the project's own repositories. Set webhooks.sources[].repos to choose; ["*"] accepts every repository. An event from another repository is answered 200, filtered, and recorded as repo_not_in_scope.
  • A tool the MCP classifier calls mutating is never approved as a read, and an approved read tool whose server later marks it as changing things is suspended until you approve it again on the device. Agent read servers are listed again every mcp.agent_read_relist_interval (default 15m).
  • Agent containers get no swap (--memory-swap equals --memory). Raise runtime.agent_memory_limit if a role needs more memory. Pull or rebuild the vornik-agent image: its local MCP fallback is removed, and MCP tools are discovered only through the daemon.
  • Companion notes no longer verify themselves. A companion's remember of a decision or spec is stored unverified, with a finite lifetime. A companion-delegated ingest is verified when its bytes match the committed file at the same path on the repository's trusted branch (its default branch unless the project names another). List the hash ids of your own admin keys in admin.operator_key_ids so the tasks they start count as yours.
  • Derived copies of transcripts expire: black-box traces after 1 day, project gists after 7 days, and of vornik-update.sh database dumps the newest 2 are kept (keys under retention.*). Copy any dump you want to keep before upgrading.
  • The console no longer loads a third-party CDN, and it sends a Content-Security-Policy that allows no source outside its own origin.
  • vornikctl task list shows 20 tasks by default and says so; use --limit, --all, --offset or --active. /ui/tasks pages past 100 rows.
  • Building from source needs Go 1.26.10.

A security release, and memory you can trust across repositories.

  • Security.
  • Agent keys are confined to the agent routes, and an agent can no longer post as the operator or cancel and retry other tasks.
  • Logs, error text, step output and chat status tools serve a scrubbed view to non-admin callers. The scrubber sees through layered encodings.
  • The post-mortem explainer sends only the scrubbed log to its model provider.
  • Only a running task's own agent may summarize its thread, and a summary never hides an operator message. A conversation's author is the signed-in caller, never a client-supplied id.
  • The untrusted-content wrapper escapes in a form the model sees, and agent memory search wraps every writer-controlled field.
  • A memory correction from a companion can no longer refute the operator's own correction.
  • Control-plane crash recovery no longer mistakes an apply's own writes for drift, and every rollback holds the config-writer lock.
  • Every transcript write is scanned for secrets before it is stored, and vornikctl secrets scan-history covers task messages and step signals.
  • Memory.
  • Provenance verification works with no configuration for every repository a project ingests from on github.com, gitlab.com, bitbucket.org or codeberg.org. The daemon keeps its own blob-less clone of each one, and a repository it cannot clone keeps its earlier trust, labelled unavailable. A file ingested before it is pushed is checked again over the following hour.
  • Each companion recall hit carries a provenance label: verified, unavailable, or why it is unverified.
  • repo_scope holds on every recall path.
  • Damaged text never becomes a memory chunk, and the doctor's memory_text_damage check finds any already stored.
  • Knowledge-graph extraction no longer quarantines a chunk for a split character, an unknown resolver id or a transient provider error. vornikctl memory regraph --quarantined re-queues the quarantined ones.
  • Compliance.
  • The GDPR Art 15 transcript export covers every text column, withholds third parties' fields and redacts secrets.
  • An Art 17 erasure also evicts the black-box trace cache.
  • The doctor watches the Art 12(3) response deadline.
  • Reliability.
  • A retry after MODEL_UNHEALTHY waits until the model's circuit can admit a call.
  • Cancelling a parent ends every unfinished descendant, paused and awaiting ones included, and a resume that races a cancel does nothing.
  • A model provider that never answers no longer hangs its caller, and a CLI provider's timeout kills its whole process group.
  • Silent-failure sites in fifteen subsystems now log and count what they drop.
  • Deleting a project now removes its rows from every project table.
  • Scheduled work can start from the latest code. A project that sets workspace.refresh_before_work: true has its workspace reset to origin/<branch> before each task from a task-kind reminder, a broker schedule or autonomy, the same reset a forge task already gets. Commits that exist only in the workspace are kept in a refs/vornik/discarded/* ref. workspace.refresh_branch picks the branch (default: the workspace's current branch). Every attempt is counted in vornik_executor_workspace_refresh_total{project, source, outcome}. Off by default, and refused together with autonomy.mode: backlog, which refreshes on its own. See Autonomy.
  • Companions. Claude Code 0.47.4, Codex 0.43.2 and Hermes 0.22.1. The plugins ship develop-with-memory guidance that adapts to projects with few written designs. Outside a git repository they send no repository scope.
  • Operator commands and console. vornikctl task list pages, with a PARENT column. /ui/tasks pages past 100 rows. The task page shows Pause on desktop and Cancel on mobile. The footer links to these release notes. vornik-update.sh runs the doctor, as it said it did.

2026.10.6

Upgrade requirements

  • vornikctl subject resolve-kg needs --request <request-id> naming a verified request for the same subject.
  • Task input is staged only from the task's own project's artifacts. A deployment with no artifact store stages no task input.
  • A failed per-task key mint refuses the step instead of starting the agent with the static key.
  • Media extraction accepts 15 container formats (mov, matroska, ogg, mp3, wav, flac, aac, avi, asf, mpegts, mpeg, flv, aiff, amr, caf); any other format fails extraction.
  • Building from source needs Go 1.26.9 (go 1.26.0, toolchain go1.26.9).
  • retention.graph_quarantine_days (including -1, a legal hold) and memory_eviction_audit_days are now honoured. Before this release quarantined knowledge-graph rows were swept at 30 days and vornikctl retention --apply used 365 days for eviction-audit rows, whatever was configured.
  • Tool audit rows are kept at least 180 days. A lower retention.tool_audit_days behaves as 180 unless you set tool_audit_floor_override with tool_audit_floor_override_basis.
  • The skill distiller drafts a skill only from a task it can prove read no third-party content, so expect few or no automatic drafts.
  • New bounds: stdio MCP calls stop at the server's timeout_seconds (default 120 s); podman run and pull stop at runtime.image_timeout (default 15 m) and other podman verbs at 60 s; email and GitHub chat turns stop at 10 m, and the email is then marked seen.
  • scheduler.execution_timeout is now read as the ceiling for a workflow with no maxWallClock (empty means none).
  • The unix socket serves only the agent routes, POST /api/v1/doctor and daemon-scope fix-it sessions need an admin-class key, and A2A peers receive only the lifecycle view of live events.
  • Forge issue close and label writes need forge.issues.writes_without_approval: true.
  • Metrics: vornik_chat_requests_total{status="error"} no longer includes timeouts and cancels (now timeout and cancelled), and vornik_chat_model_health_trips_total gains a reason label.
  • Failure classes: MERGE_FAILED now comes only from the merge-back; new classes PROMPT_TOKEN_BUDGET, OUTPUT_CAP and wall_clock_exceeded.
  • Migrations 219–230 are applied automatically; SQLite gains the GDPR subject tables on the next start.
  • Rebuild the agent image for the sandboxed document_render helper, byte-correct tool-audit and shell-output caps, and the piper bundle's licence texts and source offer.
  • The agent image's piper bundle carries espeak-ng (GPL-3.0-or-later). Each release attaches its corresponding source archive, vornik-agent-third-party-source-piper-2023.11.14-2.tar with its .sha256; keep it available if you redistribute the image. The same archive is the corresponding source for the agent images of releases 2026.9.7 to 2026.10.5 and for images built from main since 2026-09-26, which shipped the same piper bundle without licence texts or a source offer.
  • Client cancels (companion, Hermes, REST, Telegram /cancel) now cancel tasks waiting for children, input or an external event, and REST also cancels PAUSED tasks; a task awaiting approval is still refused.
  • Bedrock clamps a requested max_tokens to the route cap, like every other provider.
  • SQLite: deletes now remove child rows as Postgres does, and the retention sweeper now deletes there, so the first sweep can remove a backlog of expired rows. Rows orphaned before this release are not cleaned up.
  • The skill distiller also checks where a task's goal was created; tasks created before the upgrade are never distilled.
  • Deleting a project now also deletes its OAuth tokens, memory audit rows, standing broker grants, tool grants, and workflow and integration approvals. Export any of these you must keep first. A project re-created under a deleted project's ID no longer inherits its grants or approvals.
  • SQLite: archived projects past their grace period are now wiped. Before this release the wipe failed and deleted nothing, so the first sweep after the upgrade deletes every such project.
  • Project delete-now waits for the outcome: the API answers deleted, deleted_with_errors (with a warning and residue_steps naming what remains: artifact files, or a registry reload the next sweep completes), DELETE_FAILED (500) or deletion_pending (202), and vornikctl project delete-now exits 0, 3 (removed with residue) or 1 (not deleted).
  • Companion tool calls that repeat an argument key are refused (compared case-insensitively). Two argument names a 2026.10.5 vornikctl bench sends are still accepted and counted in vornik_companion_legacy_argument_total; upgrade vornikctl.
  • A chat.timeout of 0s or less no longer leaves model calls unbounded; the 300 s default applies.
  • Metrics and outcomes: vornik_judge_evaluations_total no longer counts a failed judge call as ok, and a timed-out autonomy evaluation is the new outcome LLM_TIMEOUT instead of LLM_ERROR.
  • Companion bundles: Claude Code 0.46.1, Codex 0.42.1, Hermes 0.21.6.
  • The Hermes plugin reads its settings through Hermes, so a Hermes gateway serving several profiles gives each profile its own Vornik URL and keys.
  • The Hermes plugin no longer coaches a model to re-store a duplicate: a note refused as already stored now says so and that it must not be stored again, so a forgotten fact is not re-stored reworded; and a note carrying leaked tool-call syntax (a garbled call meant for another tool) is refused before it reaches Vornik.
  • Hermes's unattended sessions never reach the phone. Cron jobs, hermes chat -q and webhook or api_server sessions with no client that can answer follow Hermes's own approvals.*_mode settings, and hermes -z runs in YOLO mode, so hermes vornik approvals on does not reach them. This is the limit for this release; lifting it needs a change in Hermes.
  • With a small local model, "forget" can still be stored instead. A model that sends Hermes's memory removal to Vornik as a new note, with garbled arguments, is refused for the shapes the plugin knows, but not for every shape. After asking Hermes to forget something, check /vornik-memory and forget any stray note there. Newer tool-calling models make this mistake far less often.

A security, compliance and "no silent hang" release.

  • Security.
  • Task input staging is confined to the task's own project.
  • Step-output harvesting reads every file through one pinned directory.
  • Document renderers cannot read local files, fetch, or run script.
  • ffmpeg and ffprobe read only the uploaded file.
  • Live tool-call events carry the redacted audit row.
  • Broker artifact downloads are scanned byte for byte, and cached broker answers are tied to the account that produced them.
  • Gateway redirects stay on the same origin and are capped.
  • The skill distiller refuses goals that came from third-party surfaces.
  • A per-request max_tokens can no longer exceed the Bedrock route cap.
  • A project re-created under a deleted project's ID inherits none of its grants or approvals, and a deleted project's OAuth tokens are deleted.
  • Approver-device choice cards can be answered only with a choice.
  • A companion tool call that repeats an argument key is refused, so the audit row always shows the arguments that ran.
  • Compliance.
  • Every outbound send of agent-authored content carries the AI Act Art 50 notice; on Slack the notice and content go in one post.
  • GDPR Art 18 restriction (vornikctl subject restrict, lift-restriction) and Art 16 rectification run, and restriction also covers knowledge-graph reads.
  • A console page resolves a verified subject request, and the CLI applies the same gates.
  • The GDPR subject store and rights ledger work on SQLite, and the retention sweeper runs correctly there.
  • The agent image ships the licence texts and a source offer for its piper speech bundle.
  • Reliability. Podman verbs, stdio MCP calls, system steps, repository commands and chat turns are bounded, and a bound that fires is recorded with its cause. A config-blocked task is re-queued, failed merge work is kept on a preserved ref, and approval pauses say what releases them. A CLI model provider call returns at its timeout even if a child process holds its output, a failed or timed-out judge is no longer counted as a success, and project deletion reports a partial or failed wipe instead of claiming success.
  • Hermes and companions. Memory the user can see and forget, several accounts per provider, progress and result reuse, file reads from completed runs, and daemon-side GitHub issue triage. The paired approver device can install a read-only connector the operator has vetted, resolve an interrupted config apply, and shows requests the daemon withdrew; an assistant is told why its project is paused. The Claude Code bundle now names its tools as a plugin install exposes them, and the Claude Code and Codex bundles add an offline recall nudge (VORNIK_NUDGE=off disables it). A backlog deposit can record the level a bug was found at (found_at, --found-at).
  • Agent administration. Refused agent-admin calls are recorded without their inputs, counted, and shown on the assistants page. A daemon-side failure to record a change is no longer counted as the assistant's refusal, and a failed refusal read degrades the page instead of breaking it.
  • Operator commands. vornikctl daemon drain, undrain and inflight, and vornikctl control-plane journal list and resolve; vornikctl retention works on SQLite.
  • Console. Form controls meet WCAG 1.4.11 contrast in both themes. The cache-savings figures name their cache and window: the spend page's provider prompt-cache savings cover the page window and every role/model pair, and the response cache served by Vornik covers all cached entries.
  • Correction. Four items earlier listed under 2026.10.5 ship in this release; that section is marked. Five project keys carried a wrong "since" release: broker and companion_push shipped in 2026.10.1, and retention.memory_require_approval and retention.memory_idle_days in 2026.10.5.

2026.10.5

Upgrade requirements

  • Pairing and approving need HTTPS. /ui/pair and /ui/approve/ refuse plain http to a non-loopback host. Serve TLS, use a TLS proxy, or browse to http://localhost.
  • X-Forwarded-Proto counts only from a trusted proxy. Enable server.real_ip and list the proxy host's own addresses in server.real_ip.trusted_proxies as single addresses (/32, /128, 127.0.0.1/32), never a subnet that carries containers. The proxy must replace the header, not append to it. Behind a TLS proxy that is not listed, pairing and approving answer "HTTPS required". The daemon warns at startup when its public origin is https and server.real_ip is not configured.
  • Idle memory retention can require phone approval (opt-in). Set retention.memory_require_approval: true on a project and unused memory is no longer deleted automatically: after the idle window (retention.memory_idle_days, default 365) the daemon asks on the paired phone. Rejected or unanswered requests keep the data. Deploy this release before adding the key, then vornikctl config reload. Turning it off restores TTL and age-based deletion; back up first.
  • Skill review can name the revision. skill_approve and skill_reject accept expected_version; a superseded revision is refused.
  • The updater refuses a downgrade unless you pass --allow-downgrade, and --ref main uses the fetched origin/main.
  • Rebuild the agent image for the new document_render helper.
  • Migrations 216–218 are additive and applied automatically.
  • Hermes companion plugin 0.11.3 (from 0.11.1). (Corrected 2026-10-13: an earlier edit of this page named 0.20.0, which ships in 2026.10.6.)
  • vornikctl agent connect exits 1 with one refusal line. A script that matched "not connected" must match the new line or the exit code.

A brand, Hermes, approvals, memory and agent-admin release.

  • New brand. The console, app icons, favicons and the docs site move to the new Vornik mark and colour scheme. The new console colours meet WCAG AA contrast in both themes, and the console and docs site serve their fonts themselves instead of calling Google Fonts. The docs site gains a brand page.

  • Hermes.

  • Turning approvals on replaces a stale pin on a disconnected namespace.
  • Replacing a note with identical text no longer forgets it.
  • A note you forgot and add again is recallable again, when the forget came from Hermes's own forget path.
  • The admin skill reads the active definition of an owned workflow before editing it. Broker results accept only the declared output from an answer step in the latest execution. Older completed runs may need a fresh run; their files remain available through the artifact tools. (Ships in 2026.10.6, not 2026.10.5; corrected 2026-10-13.)
  • Agent admin.
  • list_recipes files the cover request every read owes.
  • agent connect states its refusal once.
  • Verbs accept a project's full id.
  • A credential already requested for a namespace serves the next project.
  • update_project changes a project's description or display name.
  • A role granted the document_render helper can convert staged Markdown to a PDF or HTML file.
  • Google document links are no longer redacted as high-entropy strings.
  • Adding an MCP server with an existing API name is refused (#286). (Ships in 2026.10.6; corrected 2026-10-13.)
  • Approvals and devices.
  • A lost pairing-poll response no longer unpairs the browser.
  • Paired devices get distinct default names, and the devices page shows the id, the last use and "never used".
  • vornikctl pair-device prints an https address and warns on plain http.
  • Standing grants. A live grant is never hidden behind dead ones, and dead grants no longer starve live grants' digests.
  • Fixes.
  • The updater prefers the fetched remote branch and refuses a downgrade.
  • Project removal is verified by the file's absence.
  • vornikctl backup explains a PostgreSQL client and server version mismatch.
  • The doctor checks agent models against your catalogue.
  • Guarded redirects stop after 10 hops.
  • Live task pages close dead websocket connections.
  • Skill reviews are bound to the revision they were shown.
  • Memory consolidation skips refuted and superseded notes (#298). (Ships in 2026.10.6; corrected 2026-10-13.)
  • Redirect discovery. A new skill investigates an unexpected public redirect and reports only what independent evidence supports. See Discover and validate redirects.
  • Runtime. A Codex response cut off at the output cap reports finish_reason: length.

2026.10.4

Upgrade requirements

  • Rebuild the agent image. It now contains the output-cap guard and the glob fix for a trailing **.
  • Broker workflow schemas may no longer use property names containing ., [ or ] in their input or proposal schemas. Rename such fields before you upgrade, or the workflow will not load.
  • Project APIs no longer follow redirects. Point base_url at the final endpoint.
  • The updater now replaces config files you never edited in canonical config directories, and lists each one it replaces. Files you edited are kept.
  • Migrations 212–215 are additive and applied automatically.
  • Plugins: Hermes 0.11.1, Claude Code companion 0.32.0, Codex companion 0.29.0.

A reliability and agent-admin release.

  • Paired phones stay paired.
  • A double tap, two open tabs, or a slow decision could sign an approver phone out while other devices still listed it as active. Requests already in flight now share one renewed sign-in, so concurrency no longer signs a phone out.
  • A phone that does sign out, because its last answer never arrived, is told why. A vornikctl pair-device code restores the same device.
  • Per-approval renewal is kept, so a copied sign-in still dies at the phone's next approval. A browser riding along on the phone's approvals raises an alert.
  • Recipes, document input, per-role models.
  • Agents can install tested recipe workflows: inbox digest, agenda and morning brief.
  • A workflow can take a text document as input, read-only.
  • An agent role may choose a model from the operator's catalogue. A remote destination needs one approval on the phone.
  • Setup clients see when a phone decision completes. list_my_setup carries content-free notifications for setup approvals.
  • Credential entry refuses blank secrets. Whitespace-only and invisible-only values are rejected; accepted values are stored exactly as entered.
  • Approvals.
  • Plain-language summaries and risk levels.
  • Batch review of a workflow's proposed writes.
  • Bounded standing grants for repeated broker writes.
  • Hermes's own safety prompts can be answered on the paired phone.
  • An approval link opened in an unpaired browser leads back to the approval after pairing.
  • Agent-built workflows.
  • Roles receive their instructions again.
  • A reply cut off at the output cap is never accepted as an answer.
  • A step that does not produce its handoff file fails instead of silently succeeding.
  • Failures keep their precise class for task explain.
  • Project APIs support auth.query_param.
  • Older uid-agnostic agent launches are fixed. With keep-id and no run_as_user, uid-agnostic agent images run as the daemon's UID and GID, and doctor reports the real shape.
  • Dependencies. The telemetry server uses undici 7.29.1; the docs use mkdocs-material 9.7.7.

2026.10.3

A patch release.

  • vornikctl for macOS (arm64, amd64) is attached to the release. 2026.10.2 withheld it: the check that runs it on a Mac before attaching it could never pass. The check is fixed and now also runs on every push.
  • Hermes companion plugin 0.4.0. hermes vornik connect connects Hermes to Vornik in one command (it runs vornikctl agent connect hermes and installs nothing itself); hermes vornik status shows what is configured, never a token's value. VORNIK_URL and the tokens are optional: an admin setup needs none of them. The plugin is ready for Hermes's plugin catalog.

2026.10.2

Upgrade requirements

  • Migrations 205–211 add the tables for agent credentials, approver devices and approval requests, and agent key columns. All additive.
  • Back up ~/.config/vornik/secrets/store.key once it exists. Vornik creates it the first time an assistant's credential is stored, and the stored credentials cannot be opened without it.
  • Deploy the new config assets once after this update. This update runs the previous release's vornik-update.sh, which does not yet deploy them: VORNIK_DEPLOY_REVISION=$(git -C ~/vornik rev-parse HEAD) ~/vornik/scripts/config-deploy.sh ~/.config/vornik. From the next update on, the updater does it. Vornik picks them up without a restart.
  • No agent image rebuild is needed for this release.

Vornik now lives at github.com/EaseIT-cz/vornik. The repository moved from grinco/vornik. Issues, releases and history came with it, and the old address redirects, so an existing checkout keeps updating.

  • The agent image is now ghcr.io/easeit-cz/vornik-agent, with every earlier tag copied unchanged.
  • If your configs still name ghcr.io/grinco/vornik-agent, they keep working: Vornik maps the old name. vornikctl doctor lists the files and the one-line command that updates them. Correction (2026-10-02): in 2026.10.2 and 2026.10.3 that doctor check does not run in vornikctl doctor (it was wired into the wrong report); it does from the next release. Until then, find the files with grep -rl ghcr.io/grinco/vornik-agent ~/.config/vornik/configs and update them with sed -i 's#ghcr.io/grinco/vornik-agent#ghcr.io/easeit-cz/vornik-agent#g'.

Let your assistant set up Vornik, with Vornik as its safety layer. Hermes, Claude Code (including the Claude desktop app's Code-tab routines), Claude Desktop and Codex connect with vornikctl agent connect. The assistant then sets up its own projects, workflows (with schedules), REST APIs and MCP servers through Vornik's MCP tools, and runs them. It never sees a credential: credentials are entered on your paired phone. Every new connection, every credential and every write the assistant wants to make is approved there, and it receives only results shaped by the schema you approved. See Let your assistant set up Vornik.

  • vornikctl pair-device pairs your phone. Do it yourself, never through the assistant.
  • --url https://… connects an assistant on another machine, for example a Mac, to your Vornik. vornikctl for macOS is now part of each release.
  • The console's Assistants page shows what each assistant has set up.

Fixes to vornik-update.sh:

  • After pulling the agent image, the update now tags it. Before, the image arrived untagged, so ghcr.io/easeit-cz/vornik-agent:latest named nothing, or the previous image, after an update that reported success. This fix applies on the update to this release.
  • The rollback record (STATE.txt) now names the commit that was installed, not the checkout's, and prints no rollback commit when it cannot tell. An install whose checkout already sits at the target is updated without --force. A backup written by an earlier release can name the wrong commit here; use <backup>/vornik.prev -version instead.
  • A missing skopeo is now named, rather than reported as "the registry could not be reached".
  • An interrupted image build removes the build containers it left; older leftovers are reported with the command that removes them.
  • Updates and re-run quickstarts now deploy config files a release adds, without changing any you have edited.

Releases carry binaries. Each Community release now attaches vornik and vornikctl for Linux (amd64, arm64) and vornikctl for macOS (arm64, amd64), with checksums, an SBOM and build provenance attestations. The macOS binary is not signed: check it against checksums.txt, then run xattr -d com.apple.quarantine vornikctl.

Correction (2026-10-02): 2026.10.2 itself shipped without the macOS vornikctl. The check that runs it on a Mac before attaching it had a defect and could never pass, so the release withheld both macOS binaries, as designed when that check fails. The Linux binaries are unaffected. The macOS vornikctl ships from 2026.10.3.

Also fixed: the task link in Slack and chat completion notices opened a "project not found" page; it opens the task.


2026.10.1

Upgrade requirements

  • Rebuild or pull the agent image with this release. The agent-side fixes below (the router, the prompt-token budget, the tool-result cap, request sizing and the memory-peak report) live in the image; with an older image none of them takes effect.
  • SQLite: the first start rewrites stored timestamps into one fixed-width form, once, one column at a time. Take a backup first. Postgres is not affected.
  • A workflow whose retry.on names a deterministic error class no longer loads. retry.on may name only unclassified, llm_call_failed, container_start_failed, container_wait_failed, container_killed and context_timeout; the error lists them. The shipped workflows already name only these.
  • Fresh quickstart installs require an API key (see Security). An existing install is not changed; re-running the quickstart over a config with api.auth_enabled: false prints a warning and leaves the file alone. If your install is reachable beyond your own machine with auth off, turn auth on.
  • Set broker: true on a project only after upgrading the daemon; an older daemon rejects a project file that carries it.
  • The config_template_drift doctor check can report findings it did not report before (a template value your deployment never took).
  • An MCP subscription by name only, with no matching server in config.yaml, is now withheld, and the doctor's mcp_project_connections row reports it as a warning.

Security fixes from an external scan, and safer quickstart defaults. An external scan of a deployment found three real problems:

  • GET /api/v1/config returned admin.allowed_keys and the S3 access_key_id values in plaintext to an operator-scope caller. The dump redacts by key name and these names matched none of its rules. They are redacted now, and a test checks every credential-shaped config field. What it does not cover: a secret stored under a name that contains none of key, pass, secret, token, cred or private.
  • The configuration assistant could pass a secret-named list (api_keys:, allowed_keys: written as a literal list in a project file) to the model. Such lists are now redacted whole, including lists of lists and lists of maps; a list of ${VAR} references stays editable. A secret reached through a YAML alias (api_key: *tok, with the value defined under a harmless key) also passed; the assistant now refuses to read such a file until the value is inlined or moved to ${VAR}. It also refuses a YAML file with more than one --- document, whose later documents were never screened.
  • /ui/static/, which is public so the login page can load, served a list of its files. Directory requests now return 404; the files themselves stay public.

The quickstart seed (also used by the Lima and macOS installers) listened on all interfaces with auth off. A fresh install now generates an API key into ~/.config/vornik/secrets/api.env (readable only by you) and requires it; log in to the UI with it, and source ~/.config/vornik/shell-env.sh for vornikctl. A fresh install also gets its own database password, but only when no database exists yet, so a re-run never locks you out.

Browser-login sessions can use the console again. Since 2026.9.6 every action that changed something (pausing a task, rechecking a channel) was refused with 403 for a session logged in through the browser, because the console never sent its CSRF token. It does now, and the 403 names the real cause instead of blaming Basic Auth.

Vornik as the broker for a front-end agent. A chat agent such as Hermes Agent can now hold no credentials at all: it delegates to workflows you write in a project marked broker: true, passes typed inputs, and reads back only one declared, schema-checked result document. Raw task content stays inside Vornik. A broker workflow can also propose a write (a mail reply, say); you approve it in /inbox, and Vornik executes exactly the arguments you approved, once, with no model in between. Writes are off until you set broker.writes: on. result can wait up to 25 seconds for a task to finish, and a harness with a webhook can be pushed task and action states instead of polling. vornikctl companion grant --no-delegate mints a memory-only key that cannot start tasks. The Hermes plugin in contrib/hermes-companion/ is at 0.2.2; earlier READMEs named the memory provider vornik, which selects nothing — it is vornik-companion. See the companion guide.

Agents stop spending tokens on work that cannot change the result.

  • The adaptive router step gets no tools and a fixed answer format. It used to be offered tools, and a correct first answer was re-prompted into exploring the workspace.
  • The retry ladder re-runs only transient failures. A schema violation used to be retried with identical inputs.
  • The prompt-token budget leaves room for the final answer instead of stopping a step after its research and losing the work.
  • A tool result enters the conversation capped at 32 KiB, with the full output kept for tool_result_read, which can now page through it.

MCP servers recover on their own. A project MCP server whose first connection failed (for example, its container was restarting) was dropped until the next restart, and every call to it failed with "not connected". It is now retried in the background, you are alerted if it stays down for 10 minutes, and the doctor's new mcp_project_connections row lists such servers. An unreachable server also no longer holds the API closed at startup, which closes the 2026.9.8 known issue; a step whose server is still starting waits up to 10 seconds for its tools.

New. vornikctl package upgrade upgrades an installed extension package file by file and refuses, with every reason, if you edited or deleted anything it contributed. Each step that runs in a fresh (non-warm) agent container now records that container's memory peak.

Fixes.

  • Opening a live task page no longer makes other open pages show finished steps as running again.
  • A config edit made while another reload was running is applied instead of silently skipped.
  • SQLite lease expiry and task update-time comparisons are exact; mixed timestamp formats made lease expiry wrong by up to a second and task update times compare wrongly by up to a day.
  • Chat replies no longer start with invented markers such as "[from your notes: not applicable.]"; the model had been copying them from its own earlier replies.
  • A fact you deliberately save to memory from chat or a companion needs three words, not 64 characters.
  • Secret findings in artifacts, webhooks, backlog deposits and container logs now appear in the task's scan history.
  • The spend page labels memory reranking instead of showing a raw value.

Known issues.

  • Ingesting HTML or EPUB files through the companion's RAG-ingest workflow stores markup and archive bytes rather than the extracted text.
  • Deleting or retiring memory does not yet remove the knowledge-graph entities and edges that only that memory supported.

2026.9.8

Claude Code no longer loses the vornik companion when the daemon restarts. Since Claude Code 2.1.282, every daemon restart dropped the companion from an open session, and its tools stayed gone until you ran /mcp.

The companion endpoint answered the MCP server-notification stream request with the wrong status, so Claude Code kept re-opening the stream and marked the server failed when a re-open landed during a restart. The endpoint now answers that request the way the MCP spec requires (405), Claude Code holds no stream, and a restart goes unnoticed between calls. Upgrade the daemon; nothing changes on the client side.

Fixes. Tests added in 2026.9.7 that failed only in the Community Edition tree now pass there.

Known issue. If one of your MCP servers is unreachable, a daemon restart can keep the API unavailable for about a minute while startup waits on it. The companion no longer disconnects over it; a fix is planned.


2026.9.7

Upgrade requirements

  • Rebuild or pull the agent image with this release. Document, image, video and audio extraction and voice transcription and speech now run inside the agent image, never on your host. With an older image, PDF, OCR, video, audio and voice all report "not available" — there is no fallback to host programs. The image is about 1.8 GB; models are not included.
  • Audio extraction changed engine. It no longer runs the Python whisper command; it runs whisper.cpp with the model at extractors.audio.model_path, falling back to voice.stt.model. With neither set, audio extraction is not available.
  • voice.stt.binary_path, voice.stt.ffmpeg_path, voice.tts.binary_path and voice.tts.ffmpeg_path are now ignored. The daemon warns at startup when they are set; you can delete them.
  • Host checks moved to vornikctl doctor. The doctor in the UI and REST API now shows a single host_checks row telling you to run vornikctl doctor for the container and image checks.
  • Stdio MCP servers can be added only by editing your config files on the host. The admin UI, proposals and the project editors refuse them. HTTP MCP servers are unaffected.
  • Workflow changes applied before this release can no longer be rolled back from the UI; rollback refuses them and names the file. Changes applied from now on roll back as before.
  • If a project declares dependencies:, run vornikctl deps install <project> before its tasks run; until then its steps fail and name that command.
  • Git: a globally installed git-lfs (or any global filter driver) is no longer used by the daemon's git; run git lfs install --local in the project's workspace instead. The new git_config_composition doctor row lists anything dropped.
  • If a project's workspace cannot get an isolated worktree for a task, the task now fails with WORKSPACE_UNAVAILABLE instead of running unisolated. A git hook that breaks git worktree add is the usual cause.
  • Roles with runtimePolicy: warm no longer see the project workspace; use ephemeral for any role that needs it. Swarms scaffolded from the basic, dev or research presets had a warm lead; the daemon warns about them on load.
  • After upgrading, re-run the config asset install from the same release so the new config_template_drift doctor check has a current baseline.

No request can make Vornik run a program on your host. Only vornikctl, run by you, starts host processes. Nothing that arrives through chat, the REST API, MCP, A2A or a webhook can make the daemon run one — not even a fixed command. Before this release, several paths could:

  • An admin form, the "add MCP server" form, proposals and the project editors could register a command-line MCP server the daemon would launch. They now refuse to. Stdio servers are added by editing the config files on the host.
  • The doctor ran container and system commands for its host checks, the support report included podman info, and diagnose read the system journal. These host checks now run only in vornikctl doctor, which merges them into the same report (pretty and --json). The support report no longer includes podman info, and diagnose no longer shows a journal tail.
  • Applying or rolling back a workflow change, and deleting an artifact, made git commits. They no longer do: the change history is in the database. Apply now records the file it replaces and refuses if it cannot, so every apply can be rolled back; rollback restores that file to both config trees. The control-plane mirror still writes your source checkout — you commit it.
  • render_document ran pandoc on the host. It now renders only in the agent image, with no network and no fallback, and gains a docx format.
  • Uploaded PDFs, images, video and recordings, and every voice note, were processed by programs on the host. They now run in the agent image.
  • Only one internal component may start a process at all, and it runs a closed set of five kinds: the agent container, control verbs on the daemon's own containers, git in a workspace, the git-over-HTTPS backend, and programs you named in your config files. Anything outside that shape is refused before it starts.
  • The daemon's own git no longer reads anything an agent can write. Git runs programs named by the repository and its config: hooks, file monitors, and filter drivers named in .gitattributes. Several paths let an agent's workspace choose them. The daemon now refuses to run a task unisolated, pins the repository it works in, and reads a global git config composed from yours that keeps your identity and credentials and drops every driver. Every git flow (pull-request review, issue fixes, pushes, merge-back, autonomy refresh) was tested against real git before and after the change, and on a live repository before release.

Every sandboxed tool run is bounded. Each run has no network, a read-only root filesystem, dropped capabilities, and a memory limit, CPU share, process limit, timeout and input size per feature (render, PDF, OCR, video, audio, speech-to-text, text-to-speech). Oversized input is refused before anything starts. Output is capped per feature, and enforced while the tool runs: no single file can exceed the cap, and the output directory is checked once a second. That is a sampled bound, not a disk quota, so a run can overshoot by about one second of writes before it is stopped. At most sandbox_tools.max_concurrent runs (default 2) happen at once, with one slot kept for voice so a batch of extractions cannot stall a voice note. Tune per feature with sandbox_tools.limits.<feature>, sandbox_tools.timeouts.<feature> and sandbox_tools.cpus.<feature>; sandbox_tools.max_input_bytes overrides every feature's input bound. These settings are read at startup, not on config reload. The startup memory check counts the sandbox pool; only limits you set yourself can refuse a boot. A new sandbox_tools doctor check runs each tool on a generated sample, and four metrics cover it: vornik_sandbox_tool_runs_total, vornik_sandbox_tool_duration_seconds, vornik_sandbox_tool_wait_seconds and vornik_sandbox_tool_remove_failures_total.

Re-ingesting a document now replaces its earlier versions. Every re-ingest used to add its chunks beside all earlier ones, all still live, so recall could serve a months-old section of a document you had since rewritten. A document is now identified by its path in its repository; the newest upload wins and older versions are retired. Each version is stored whole, so an unchanged section is never lost with the old version. Your agents' own output is never affected.

  • /rag-ingest in the companion plugin takes its scope from the files' own repository, not the directory you ran it in, and refuses an upload that mixes repositories.
  • vornikctl memory supersede-legacy-documents retires the name-only versions ingested before this release, once a document has been re-ingested under its path. It is a dry run unless you pass --apply, and leaves alone any name two files share. On our reference deployment it retired 2,980 stale chunks across 69 documents.
  • Documents over about 125 KB could not be ingested in 2026.9.6 — a size guard meant to protect an agent's context also blocked ingest, where no agent reads the file. Fixed.

Companion plugins 0.26.0 (Claude Code) and 0.23.0 (Codex) ship with this release: repository-scoped /rag-ingest and /upload, and backlog deposits that land in their own priority group.

The agent-quality benchmark measured the wrong thing, and v9 fixes it. Tasks ask the swarm to write new files, but the workspace kept earlier runs' output, so from the second run onward agents re-validated code that was already written. Every task now starts from a clean workspace, and four tasks are graded by acceptance tests the agents never see (reported alongside the score, not used as a gate). Harness v9 results are not comparable with earlier dev-swarm figures, including earlier baselines. The first graded v9 arm ran on a local Ollama host: a 35B mixture-of-experts model (about 3B parameters active) at 4-bit passed all four hidden acceptance suites. That is one run per task, on small single-file fixes, at 23 to over 90 minutes per task. It shows a locally served model can land correct fixes on this harness; it is not a claim about harder work or a statistical result.

On a slow backend. When scheduler.speed_aware_timeouts is enabled, the speed factor now stretches step timeouts, not only the task lease, which never limited anything. chat.optional_work.disabled and chat.optional_work.disabled_models switch off optional LLM work (narration, memory titles and summaries, reranking) for a model too slow to serve it beside tasks. Optional work hitting its own short deadline no longer marks the model unhealthy and fails your next tasks.

New operator tools.

  • A regulatory record page lists every data-subject request and security incident, with those near or past their GDPR deadlines first, and AI Act disclosure counts per channel. It shows identifiers, deadlines and hashes, never personal data. Available in both editions.
  • vornikctl leader-lock release clears an orphaned leader-lock row the doctor reports, and refuses a lock that is still held. The doctor no longer reports a lock nothing in your build would renew as an error.
  • vornikctl deps install and deps status install a project's declared dependencies inside the agent image, from pre-built packages only.
  • The config_template_drift doctor check tells you when a deployed config lacks a fix its shipped template has; vornikctl doctor ack declines one you do not want, and records who did.

Chat can no longer cancel or retry a task on its own. The model could cancel or retry a task without asking. Now it proposes, and you confirm in your own next message.

Fixes. The doctor's model routing check asks the live router, so it no longer calls working models "unrouted". A model is no longer blamed for failures caused by containers or mounts. orphan_fk_rows keeps your LLM cost history instead of offering to delete it. vornikctl doctor --json no longer drops fields. A step timeout above the workflow's maxWallClock now warns, since it can never take effect. A cancelled task no longer overwrites a task that finished at the same moment, and holds no lease. An explicit empty database.driver now means Postgres, which turns on features that were silently off under that setting.


2026.9.6

One agent can no longer take the host down. Agent containers ran with no memory limit and no CPU quota at all, so a single runaway step was a machine-level event rather than a task-level one. They are bounded now. The limit is derived from your host rather than shipped as a fixed number: a constant default beside the shipped max_concurrent_tasks would have refused to boot on any host under 8GiB, which would have turned a load-dependent risk into a certain outage caused by upgrading. Set runtime.agent_memory_limit to override, or to "none" to keep the old unbounded behavior. A limit you set that cannot arithmetically fit is refused at startup with the arithmetic in the message; one that merely exceeds currently-free memory warns and boots.

The adoption board stops reporting numbers it did not measure. Two customer-reported defects (#14):

  • Credentials were listed only if they had rows in three specific activity ledgers, so a key used for the REST API, the UI, chat or A2A was absent from the board however heavily it was used — and the board read as "nobody is using this". Rows now come from your credential list, with authentication itself as evidence of life. The same cause stalled the "last seen" column. The board also silently truncated to 20 rows; it now says how many it is not showing.
  • A row could show a credential's LLM call count beside "0 of 30 active days". The active-days column read one ledger while the counts beside it read another. It is now the union of all three: a credential that queried memory and spent on a model the same afternoon counts as one active day, not two, and the day boundary is UTC regardless of your daemon's timezone.

What is still not counted is now stated on the page rather than left to be inferred: a credential whose only traffic is REST or the UI shows a recent "last seen" beside zero active days, because a key's last-used timestamp is one instant, not a history.

A config tree your next restart would refuse is caught before it flaps. A deployed workflow naming a step error class the installed binary rejects takes the daemon down on restart — and restarts it, forever, under Restart=on-failure. vornikctl doctor now reports it, and the same check runs against the new binary during vornik-update.sh, before the swap. Two other doctor checks that could never have passed are fixed: image_freshness compared a Community label against an Enterprise daemon, and agent_image_uid outlived the constraint it tested.

Community edition gains browser login — a credential exchanged for a bounded session, not a password. Revoking a key ends the browser sessions that key minted.

Our release pipeline was publishing inconsistently, and that reached you. Three repositories sat at three different versions on the same day, and the Community edition had a 2026.9.5 tag with no release attached to it. The causes were all the same shape — a step that worked because someone remembered to do it. Creating the Community release is now automatic on a version tag, the installers are checked against the version being released (they had been pinned two releases behind for five days, so fresh installs quietly took an older tree), and a weekly audit verifies each release actually produced the versioned agent image it promised. Every release from 2026.7.2 onward now has a matching tag and release entry.

Fixes. A step prompt of 128 KiB or more is no longer silently dropped. pricing.yaml now reloads instead of reporting success and continuing to bill the old rates — this one was called out in 2026.9.5 as restart-only. A registry reload no longer drops a project the daemon is serving. A Slack command the daemon does not answer is no longer invisible. The agent image runs under any uid. Five dependency alerts on the Community repository are closed.


2026.9.5

Your memory knows what is current. Retrieval now ranks by freshness, and a recurring series supersedes its own older members — so a daily digest answers today's question instead of yesterday's. The decay half-life is read per row, which lets one store hold fast-moving news beside reference material that never goes stale. Nothing is filtered out; freshness is a ranking signal. Existing rows are untouched: absent series membership means "not part of a series", which is what everything written before this release is.

Self-hosted inference stops being billed at a made-up rate. If you run a model through vLLM or a LiteLLM proxy, its cost metrics were almost certainly wrong — an unpriced model falls through to a default rate, and the table carried no prompt-cache tier at all. On our own benchmark that was a 7.3× overstatement: $40.51 recorded against $7.12 actually billed. Both the proxy and direct spellings of a model are priced now, because lookup is exact-match.

A new doctor check, pricing_drift, reports prices that disagree with a pinned snapshot of LiteLLM's published table. It reports and never applies — your operator-verified rate is often the better one — and it tells you how many prices it could actually compare rather than implying it checked them all. vornikctl pricing sync-upstream refreshes the snapshot and prints the diff. Nothing fetches at runtime: prices drive budget enforcement.

Fixes you may have hit. Telegram commands did nothing in group chats (/cmd@botname never dispatched), and everyone in a group was treated as the same speaker. An agent path that lost its leading slash resolved nowhere. A backtick in an /upload prompt aborted the upload silently, with no error and no task id.

Restart required for pricing changes. vornikctl config reload reports success on a pricing.yaml change it does not apply — the table is read once at startup. Restart the daemon after editing rates.


2026.9.4

Forge can read your CI, and it will not approve a red commit. Turn on forge.ci.enabled and Forge records what each Actions run concluded — the conclusion, the jobs, the timing — against the commit it tested, and puts it in front of the reviewer. A failed run triggers a review (six workflows finishing together still produce one); a failure on a commit already reviewed gets a short factual comment instead, written by no model. With block_approval_on_failure (default on) forge.post_review will not submit an APPROVE while a run it recorded for that commit is red — the review posts as a comment led by the failing workflow's name. A commit with no recorded runs is not treated as a failure. To get content in — a terraform plan, a test report — have your pipeline upload it as an artifact and name it in ci.artifact_name; Forge reads artifacts, never job logs. Your GitHub App needs Actions (read) and the workflow_run event, asked for only when the feature is on. You may name the review workflow as the success workflow, so a completed run — not the push — triggers the review: a workflow that needs a pull request runs only for runs that have one, and a green push to your default branch is recorded without starting anything. See the Forge guide, Reading CI outcomes.

A reviewer no longer approves code it never read. When a pull request's head had not moved since its last review, the reviewer still ran — on a one-sentence diff — and could post a confident review of a different pull request as a real approval. forge.post_review now refuses to post a review of an already-reviewed head, and a workflow can skip the model call entirely because a system step can route on its own result. Two related fixes: an agent now receives every preceding system step's output rather than only the last (a second system step had been overwriting the diff), and a CI-triggered review checks out the pull request's head rather than the base branch.

Rate what an automated change produced, and see it where you approve. Thumbs up or down on any execution — vornikctl execution rate <id> up|down [--reason ...], or the control on the task page. Ratings roll up per skill (vornikctl knowledge rollup, /api/v1/skills/{id}/rating-rollup, a column in the skills admin) and appear on the Telegram card, the Slack blocks and the MCP skill_get/skill_list an approver reads, so re-approving an edited skill is informed by ratings on that body. Kept for retention.execution_ratings_days (default 400).

Boot no longer races the database. The systemd unit waited only for the network, so a reboot could start the daemon before the containerized Postgres accepted connections and spin it through hundreds of restarts. The unit now waits for podman-restart and for the database port (bounded, 120s), and an absent database fails once with a message naming the cause. The updater does not rewrite unit files — copy the new deployments/podman/systemd/vornik.service into place and systemctl --user daemon-reload.

vornikctl doctor reads better. fallback_rungs now says whether a dead fallback rung was refused by an open circuit (the breaker doing its job — look at why the model's circuit opened) or called and failed upstream (the model or its provider); the two were reported as one and pointed at credentials for a model that worked elsewhere. And doctor --offline no longer migrates the SQLite database it is diagnosing.

Also fixed: pausing a task read a stale status and could leave a container running behind a PAUSED row — pause now asks the executor first and never flips a running task it could not stop; deleting a project now evicts the cached embeddings computed from its text; on SQLite, the entities view lists a mention's chunks newest-first, as on Postgres; verifier refusals ("claimed a file that is not on disk", "cited a commit that does not exist") are classified instead of landing in unclassified; install-enterprise can replace a running daemon (Text file busy); the public release tag is created by the pipeline, so every release ships a version-tagged agent image; and the Community repository's CI, red since the 2026-09-07 export on two tests that only pass against the Enterprise tree, is green again.

Upgrading: migrations run on start; new keys are additive and default to the previous behaviour, except that with forge.ci enabled a red pipeline withholds approvals by default. Re-install the systemd unit as above.

2026.9.3

If vornik-update.sh has ever reported "Checkout already at target commit. Nothing to do." after a failed run, read this first. The updater checked out the new release while bash was still reading the script file, so on any upgrade where the script changed size the run died just after the checkout — with a confusing error like line 200: F: command not found — and everything after it silently never ran: the binary build, the image refresh, the sidecar recreate, the restart. Because the checkout had already moved, running it again reported "Nothing to do" and exited successfully. An install that was never updated, reporting success.

Check whether yours is affected:

vornik --version                    # the installed binary
git -C ~/vornik describe --tags     # what the checkout claims

If they disagree, or vornikctl doctor reports image_freshness drift, run ./vornik-update.sh --force. --force is needed precisely because the checkout already matches, which is what made the failure invisible.

Note that the fix cannot repair the update that delivers it — your host runs its own copy of the old script. Expect the first update to 2026.9.3 to fail on an affected host, then run it again; the second run works. From then on the script runs from a private copy, so the file it reads cannot change underneath it.

The agent image is now pulled instead of built. It is published to ghcr.io/grinco/vornik-agent, and the updater fetches it by digest rather than building a container on every host, so an ordinary update no longer spends several minutes on it. Images that are not published — the cluster pair, and the sidecar images — are still built locally, exactly as before.

Air-gapped and offline installs are unaffected. With no reachable registry the updater builds locally as it always did. And a host that already pulled an image and later loses its network keeps that image rather than rebuilding over it: it cannot know the target, so it changes nothing and says so, and vornikctl doctor continues to report the real state.

vornikctl doctor now says how you obtained each image — for example Obtained: 1 pulled, 6 built locally. Neither an image's digest nor its build label can tell you this after the fact, so the update path records it at the moment it knows.

Also fixed: vornik-update.sh --no-build failed with VERSION: unbound variable whenever an image needed refreshing.

2026.9.2

The agent's file and git tools moved from bash into a small Go helper inside the agent image. Behaviour was recorded before anything moved and the port was checked against that recording, so what a tool returns is unchanged for valid UTF-8 content. You need the rebuilt agent image for this; the updater builds it.

Four tool-boundary escapes found by a code audit are closed. A dangling symlink let file_write create a file outside the workspace, a planted temporary-file symlink let file_edit overwrite one, recursive grep could read one through a leaf symlink, and a git revision beginning with - was taken as an option. All four are fixed, each with the reproduction as a test. Exploiting any of them needed a role granted the tool plus a crafted argument or a planted link; none is a container escape. Alongside: reads no longer allocate the whole file before truncating, non-ASCII glob patterns match, grep's head_limit must be at least 1, and read_many_files counts characters again and never cuts a multibyte character in half.

If vornik-update.sh has been failing since late August, this fixes it. The updater could not build the agent image (image build failed for ghcr.io/grinco/vornik-agent:latest) because of how it read the image list; nothing was half-applied, but nothing updated either. Rerun it. It now also recreates the long-running sidecar containers (the scraper, and any other compose- or unit-run service built from a manifest image) when their image was rebuilt — previously they kept running the old image after every update, and nothing reported it. --no-recreate-sidecars opts out. The public agent image also gets a version tag on GHCR from this release on (ghcr.io/grinco/vornik-agent:2026.9.2); earlier releases only ever published :latest.

You can read what a step was told and what it handed back. vornikctl execution prompt <exec> <step> shows the system prompt, user content and tools the step's model saw at its first request; execution input and execution result show the task.json the daemon wrote for the container and the result.json it wrote back. All three are stored after secret redaction and pruned with the step outcome that references them. A project can also opt in to recording every model exchange of its steps (recording: {llm_exchanges: true}, off by default because it costs storage) and export them with vornikctl execution exchanges <exec> <step> --export — the recording a replay test consumes.

vornikctl config show --provenance says where every resolved value came from — file, environment, default or reload — and --trees indexes the registry the daemon is actually running.

Also in this release: the Community vornikctl support-report collects the bundle locally and states the edition it really is; vornikctl doctor runs every check on SQLite; four SQLite-only persistence defects found by new shared backend tests are fixed; a model fallback gets one attempt and a slow model can trip its own breaker; pull-request review commands are gated on the author's standing in the repository, and a push during a review is no longer lost; grpc 1.83.1 closes a HIGH advisory.

Upgrade notes. Migrations 174–178 apply on start, all additive. Rebuild the agent image (the updater does). The updater now recreates sidecar containers before restarting the daemon; a tool call in flight against one fails at that moment, inside the same window the restart already interrupts.


2026.9.1

A workflow's system step now hands its output to the next agent. This is a customer-reported bug and it is the reason for this release. When a workflow ran a system step (for example forge.fetch_diff) and the next step was an agent, the agent received empty previous-step context — in every workflow, for every system step that succeeded. The failure path already reported itself; only success was silent. If you have an agent prompt that says "the previous step provided X", it now actually has X. Injected output is capped at 256 KiB, and a truncation says so inside the text the agent reads.

Pull requests get reviewed again after you push. Previously only pull_request.opened triggered a review, so there was no way to get a fresh one after addressing feedback. Reviews now also fire on new commits, reopen and ready-for-review, and you can ask for one directly:

Comment Effect
@<bot> review review now, covering what changed since the last review
@<bot> full review review the whole pull request
@<bot> pause stop reviewing this pull request automatically
@<bot> resume resume automatic review

A comment that mentions the bot without matching a command still gets an ordinary conversational reply.

Three things keep the cost sane: a push burst coalesces into one review of the final state, a re-review reads only what changed since the last one, and drafts are not auto-reviewed. Every uncertainty resolves toward more review — a missing baseline, a force-push that rewrote it, or an unreadable state row all fall back to the complete diff, because a wrongly narrowed review silently omits code nobody will look at again.

Two things to set before you upgrade if you use the forge reviewer:

  • Set your mention handle. mention_handle defaults to this project's own App slug. You install your own GitHub App under your own name, so set it to your App's slug or commands will not match. An empty value matches nothing, deliberately — a handle that happens to be somebody's real account notifies a stranger every time anyone addresses the bot, which is a bug this release fixes rather than a naming preference.
  • Review volume goes up on active repositories. On a project configured with github_app:, github_app.auto_review_on_push: false restores the previous first-review-only behaviour. On the generic webhooks.sources ingress that key did not exist in this release; use the per-pull-request pause command. (Closed since: forge.auto_review_on_push applies on both ingresses, and the github_app: spelling now reaches both too. See the Forge feature page.)

Only people with standing in the repository can run review commands — the owner, organisation members, and invited collaborators. A review is real model spend, so on a public repository an unguarded command is a way for a stranger to run up your bill. Outside contributors are deliberately excluded.

A permanent forge failure no longer burns the retry budget. A pull request that does not exist, a deleted one, a renamed repository or a revoked installation used to consume all three attempts on identical 404s and then report UNKNOWN, whose guidance is "try again". Those now fail immediately with a class that says what happened. Rate limits and outages are unchanged — a 429 or a 5xx keeps its full retry budget.

A review quotes the request it is answering. Comments get deleted; reviews are durable. A comment-triggered review now opens with an attributed quote of what was asked.

vornikctl doctor tells you more than it could before.

  • pricing_coverage used to report "all N models have pricing entries" while examining only swarm role models. It now also reads role fallbacks, project judge models, chat and router models, the embedding model, the narrator, wizard and fixit — and it reports what it examined instead of "all models". It may now surface gaps it previously could not see; an unpriced model was always silently inheriting the default rate.
  • Model-circuit failures are classified as MODEL_UNHEALTHY instead of landing in the unclassified bucket, where they were the large majority of it. The unclassified_step_failures threshold is re-calibrated from 15% to 5% as a result — the old value could not fire once those failures were named. A migration reclassifies historical rows so the check is not stuck warning for a month while they age out.

A sustained latency breach now proposes a change you can apply, instead of an observation telling you to go run Diagnose yourself. The proposal names a specific model for a specific role and validates it against your configured model universe before offering it. It deliberately does not pick the model from latency data alone: the fastest model on a fleet is usually the smallest, and that trade would swap output quality nobody is measuring for a number everybody is. The rationale says so, so you read the trade-off before approving.

Stored artifacts are no longer rewritten by heuristic secret rules. The two heuristic rules (entropy and generic key/value) could replace ordinary text — test identifiers, hashed filenames — with [REDACTED:…] markers, and redaction is one-way, so the original bytes were gone. Across two production surfaces those rules produced roughly 7,000 findings and zero true positives. Detection is unchanged; every finding is still found, counted and logged. Only the rewrite narrows, and the log now distinguishes "found but not rewritten" from "nothing found".

Output-guard findings name the rule that produced them, not just the category — two different patterns can produce the same category, which was enough to decide redaction but not enough to triage a false positive. The metric gains a rule label.

The agent container image is published for arm64. It was being built for the release runner's architecture only, while arm64 packages were shipping — so an arm64 install named an image it could not pull and discovered it at the first agent run.

Correction, 2026-09-03: this section originally also said packaged installs carry an image provenance record again. The record's schema shipped, but the packaging step that writes it aborted every build, so 2026.9.1 produced no packages and no record. Fixed after the release; the next release carries it.

MCP audience checks accept equivalent spellings of the same URL. Host case, a longhand default port (:443 on https), a trailing dot, and the Unicode form of an internationalised host all used to mismatch, so a correctly configured endpoint could be refused with "needs reconnect". Genuinely different endpoints — a non-default port, the other scheme's default port, a different host — are still different, and credentials embedded in a URL never count as the host.


2026.9.0

vornikctl doctor no longer reports OK for a check it never ran. Thirty checks returned OK from paths that meant not evaluated — no database, no config directory, metrics not wired. They now report SKIPPED. If your doctor output gets less green after upgrading, nothing broke: those checks were never running.

Step retry: blocks now work. If you have workflows with a retry: block (on, max_attempts, backoff, initial_delay), it was being silently dropped and the executor used three fixed values instead. It now takes effect — so review any retry: you have configured before upgrading, because this release is the first time it will actually run. Defaults are unchanged for steps with no block. The retryPolicy: spelling never worked and has been removed; vornikctl workflow validate will now tell you if you have it, along with any other unknown key in a step — those used to be dropped in silence.

Check your role permission keys. A role written permissions.allowed_tools instead of allowedTools used to parse cleanly and produce an empty tool allowlist, which the MCP gate treats as "unrestricted". That misspelling is now a load error. If a swarm fails to load after upgrading, this is likely why — and that role has been running without its tool restriction.

MCP tool results are now scanned for injection attempts and credential leakage. Detect-only in this release. Content from Jira, Sentry, scrapers and other MCP servers was previously not scanned at all; only the daemon's own fetch tool and the chat path were.

MCP connectors that lose OAuth authentication now fail visibly. A connector whose token expired could 401 for hours while its tasks reported COMPLETED, with the error visible only inside the task's result payload. Tokens are also now refreshed per call rather than frozen at connection time. Additional hardening: secrets are no longer replayed on redirects, insecure OAuth endpoints are refused, and a grant issued for one resource path is no longer presented to a sibling path on the same host — if you use a server whose audience is path-scoped, reconnect it after changing its URL path.

The documented update path now rebuilds container images by default. If you have been following UPDATING.md, you may not have received an updated agent image for some time — the rebuild was opt-in. Parts of each release ship inside that image, so an update that swapped only the daemon delivered half of it.

The image_freshness check now works at all. It previously compared two different SHA formats and could never pass, on any host. It now reports honestly whether your images and daemon were built from the same commit — and compares in both directions, so a package upgrade you have not restarted into yet is reported rather than passing silently.

Correction, 2026-09-01: this entry originally also said packaged (rpm/deb) installs can verify their images against a record shipped in the package. They cannot — the EE package does not ship that record, and did not in this release. The record is built from images that exist on the machine doing the build, which a cross-architecture package build does not have. On a packaged host the check reports that it cannot verify, rather than reporting a pass. Hosts that build their images locally (the quickstart and make install-enterprise paths) are unaffected and get the full check.

The agent image is published to GHCR, so hosts pull it rather than building it. Air-gapped hosts continue to build locally under the same name.

New doctor check: unclassified_step_failures, reporting the share of step failures with no named cause over a trailing 30 days and warning above 15%. Counts of fail-open events in the secret-redaction path are now published too, so "no findings" can be distinguished from "never scanned".

Agents recover better from two common failure modes. A step killed for looping now keeps its output if it had already satisfied its contract, instead of discarding the work and failing the pipeline. And a call to a tool that does not exist now returns the available tools and the nearest match instead of a bare error.

Benchmarks: this release publishes the first scored agent-quality figures (30 tasks, 100% task success, $0.74/task — with the 9.7% of steps that produced no output stated alongside it), and restores the memory-benchmark track record with an explanation of the axis change that broke it. See Benchmarks.

2026.8.9

A stuck execution no longer dies at an unrelated step. A step result that was not valid JSON was stored as-is and failed at the next checkpoint, so an execution died several steps away from the cause with a confusing failed to marshal execution checkpoint error. Such a result is now stored as a readable diagnostic that keeps the original text, and the execution continues.

Delegations and checkpoints survive a deleted ancestor task. If a parent task had been pruned by retention or removed with its project, the lineage walk failed instead of stopping — surfacing as delegation cycle check failed: not found. A missing ancestor now simply ends the chain.

The watchdog no longer re-reports the same stuck execution every sweep when its task has already been deleted, and the stuck-execution counters now include those cases instead of under-counting them.

Scheduled reports deliver the work, not the routing. A scheduled task that delegates to a child produced its output on the child, and delivery only looked at the parent — so the attached files could be internal routing transcripts rather than the report. Delivery now collects the whole task tree and leaves per-step transcripts out.

vornikctl mcp connect tells you when it asks for fewer scopes than the server offers. A daemon-level connection deliberately does not inherit write scopes — that is unchanged — but it now prints a WITHHELD: block listing what was not requested and the two ways to grant it. Previously the narrowed request was invisible, which made a read-only grant look like a server with no write tools.

New metric: vornik_mcp_gate_unrestricted_total{path,reason}. Counts MCP calls that applied no role allowlist, with the reason named (no_task_id, deps_unwired, role_not_found, role_declares_none, and others). These calls were always permitted by design; they were simply not visible. A rising number means roles are not resolving — not that something was blocked.

Right-to-erasure now removes derived data. Erasing a subject's content previously deleted the stored chunks and left the knowledge-graph entities, edges and quarantined pre-ingest copies derived from them — all of which are on the retrieval path. Erasure now settles those too and records what it removed. Retention, which is a separate legal basis, parks that graph data instead of deleting it, with a horizon you can disable for a legal hold (retention.graph_quarantine_days: -1).

Agent tool advertisement follows execution on every path. A third advertisement path could offer a tool to a role's model that the execution gate would refuse. Roles now see only what they can call.


2026.8.8

Action required if you allowlist outbound URLs. Anonymous telemetry now reports to https://telemetry.vornik.io instead of https://telemetry.vornik.io/v1/collect.json. The collector still accepts the old path, so an older release keeps reporting, but egress rules that match the full URL need updating. What is collected has not changed: aggregate counts of a fixed set of values, a request body that is never parsed or stored, and the same retention windows. See Telemetry and privacy.

vornik telemetry sample now shows you the real request. It previously rebuilt the payload for display, which could in principle drift from what was actually sent; it now prints the request itself. Contributed by @vmindru.

A reporting step could fail after doing the work. The step that writes a feature's changelog was asked to identify the relevant commits before writing the file. On a repository whose history offers no clear boundary — no tags, no merges — that search has no end, and the step could exhaust its tool budget without ever writing the file it was required to produce. It now writes the changelog first from information it already has, then enriches it with a bounded look at history. An inconclusive search can now cost detail in the changelog; it can no longer cost the step.

Agent steps could fail for work they had actually done correctly. Before storing a step's result, the daemon scans it for anything that looks like a credential and masks what it finds. That masking was applied before the result was checked against the step's declared output fields — and because it replaces text without regard for the surrounding JSON, masking an identifier could leave the result unreadable. The step was then failed for "missing required fields" that were present all along, and its tool-call counts were recorded as blank.

Ordinary output triggered it: test-case ids, commit hashes, generated identifiers. The check now runs on the result as the agent wrote it, while masking still governs everything that is stored, displayed or forwarded — no change to what counts as a credential or what is kept. Measured on a benchmark deployment, the affected failures went from 10 in 14 reporting steps to none, with masking still occurring on the steps that now pass.

If you have historical step-failure data, treat "missing required fields" counts recorded before this release as an upper bound rather than a measurement.

Steps could be recorded under the wrong failure reason. Two related issues: a step that exhausted its wall clock while stuck repeating itself was recorded as a timeout rather than as a stuck step, and text appearing in an agent's own log output could influence how a failure was categorised. Both are corrected. This matters if you act on failure categories — a stuck step is not fixed by granting it more time, which is what a timeout label implies.

A review decision could be ignored. A workflow condition read a field that the agent was not actually required to produce, so the condition could never be satisfied and work was rejected downstream. The field is now required where it is read.

A failure that should have stopped a task could send it in a loop. Two gate-failure paths did not honour the strict-failure setting and instead routed into recovery. They now terminate as configured.

Failed steps carry more diagnostic detail. The log excerpt kept with a failed step previously retained only the beginning of the step's output, which is rarely where the problem is. It now keeps both the failure message and the end of the log.

2026.8.7

Two roles were failing most of the time because we asked them to restate something the system already knew. Both are fixed, and both were measured before and after on a benchmark deployment. Neither was a model limitation.

A tester could claim tests passed without listing what it checked. The rule requiring the list of validated cases was enforced after the fact, but the machine-readable contract the model is decoded against marked that list optional — so the model was doing exactly what it was permitted to do, and the work was rejected afterwards at the cost of a retry. The list is now required where it binds. Measured on the same deployment: the failure went from 37 in 50 attempts to none, and the retry ladder stopped being entered at all.

A step could fail for not mentioning a file it had just written. Where a step declares an output file, the daemon verifies it against the real filesystem. That check passed — and then the step was failed anyway because the agent's own summary of what it produced was empty. A verified file now settles the question; the agent's omission is still recorded, but no longer fails the step. This does not weaken the opposite check: an agent claiming a file it never wrote is still caught. Measured: first-attempt success rose from 36% to 100%, and the work took one model call per step instead of 2.3.

Field descriptions in an output schema now reach the model. They were dropped on the way to the prompt, so agents saw field names with no explanation of what belonged in them.

A daemon whose configuration fails to load now stops instead of serving. Previously it kept running with a synthetic fallback, so a task naming a workflow that no longer existed could still report success — having never run that workflow. Relatedly, the pedantic setting now actually takes the strict path it describes.

Agents are told when their checkout is read-only. They were looping on writes that could never succeed, which accounted for most of the stuck-agent reports.

New: output-contract scoring for workflows. Workflows that declare an output file are now scored on whether they delivered it, across nine shipped workflows. This measures delivery, not correctness — a workflow that writes a valid but empty file scores full marks — so treat it as a regression guard for "this workflow stopped producing its output", not as a quality score.

Other fixes: adaptive workflows now record a terminal outcome for each step; a parent task waiting on children no longer needs a restart to unstick; a tool call that a provider flattens into a single argument string is split back apart; a refused tool grant explains why; deduplicated deliverables are surfaced; published HTML is preserved when the page host fails; scheduled task attachments are delivered; and workflow timeout proposals are scoped globally.


2026.8.6

Upgrade if you run any role on Bedrock with a declared output schema — those steps have been failing outright. The agent's final turn deliberately offers no tools, but the conversation still carried tool records, and Bedrock rejects that pairing. The step produced no result at all. Fixed by converting those records to plain text on the final turn.

A failed step now tells you why it failed. Previously almost every agent failure was recorded as "the container exited non-zero", collapsing four distinct faults into one label. Failures are now recorded with their actual cause — a stuck tool loop, an exhausted tool budget, a context overflow, or a broken output rule.

Agents are now shown the output rules they are judged against. A role can require that, say, a claim of passing tests is accompanied by the list of cases checked. Those rules were enforced after the fact and never communicated, so work was rejected for a contract the agent had never seen. The rules are now part of the agent's instructions and are checked before it finishes, with one chance to correct.

An agent that repeats itself is warned before the step is ended, and an agent that runs out of tool calls now produces its best answer instead of nothing. The record still shows the budget was exhausted, so this improves the output without hiding the cause.

A fallback model gets its own time budget. When a primary model was unavailable, the replacement inherited a timeout sized for the original and could not finish in it — so failover reliably failed. It now gets a budget of its own.

The daemon no longer refuses to start when a container-runtime check is merely slow, and benchmark runs now verify the model's real context window against the endpoint instead of trusting configuration.

No configuration changes are required. If you pin per-model context windows, confirm they match what your endpoint actually serves.


2026.8.5

Upgrade if your tasks ever retry — retried work has not been billed to anything. A workflow step's spend was stored under an id that did not name the execution, so when a task retried, the retry overwrote the row of the attempt it retried. On a measured ledger, 24.8% of step-spend rows were missing, and 98.9% of those were this collision. Budget enforcement, the spend dashboard and per-key attribution all understated by the cost of every retry. Historical rows cannot be recovered — the figures were overwritten, not merely hidden — but new spend records correctly from this release.

Cached prompt tokens are counted on streamed calls. Streamed completions were not asking for usage, so cache hits recorded nothing. Prefix caching on self-hosted servers was already working and simply invisible.

New: an adoption dashboard at /ui/insights/adoption. Shows how much of the product each team has actually exercised — companion usage, RAG queries, memory writes and channel activity, not just task counts — and names the capabilities nobody has tried yet. Designed to be useful on deployments that have not enabled auth, where everything is attributed to nobody.

Security. Slack interaction responses are now pinned to Slack's own host, so a forged payload cannot redirect a response elsewhere. Go 1.26.6 picks up fixes for 7 standard-library CVEs.

Rebuild your agent image (make build-agent). The degenerate-loop diagnostic used to assert the context window was exhausted; a measured run found a loop at 17% of context, so an operator following that text would raise a limit that was never the constraint. It now reports the measured figure and says plainly when context is not the cause.


2026.8.4

Upgrade if you run open-weight models on your own hardware — agentic work did not function at all. Vornik sent a response_format directive alongside its tool definitions. Any server implementing that with guided decoding then constrains the model to emit schema-shaped JSON, so it can never emit a tool call. Hosted APIs tolerated the combination; self-hosted endpoints did not. Agents answered in a few tokens of prose, the loop recorded success, and the step then failed its output contract. The directive is now withheld whenever tools are offered.

Timeouts no longer assume fast inference. New optional speed_aware_timeouts and default_step_timeout settings; both default to previous behavior.

Dashboard failures are counted by when they failed, not by when their task was created, so a spike lands on the day it happened.

Rebuild your agent image (make build-agent) — the response_format, finalization and nudge fixes live in the container, not the daemon.


2026.8.3

Upgrade if you use Bedrock embeddings — semantic search has been silently keyword-only. The query vector was never computed on that transport, so hybrid search ran with no semantic arm while memory/stats still reported 100% embedded and nothing was logged. Recall changes noticeably after upgrading, and reranker cost appears where it previously did not.

Embedding spend now appears in your spend rollups. It was never recorded before, on any provider — re-embedding a mid-sized corpus is roughly $0.60–0.75 on a hosted embedder and was reported as $0.00. This is not new spend; it is spend that was always happening and never billed. Look for the role Memory · Embedder on /ui/spend. A ~ before a token count means the provider reported no token count and the total is derived from text length rather than measured.

New: vornikctl bench memory — a retrieval-quality benchmark with a pinned dataset, an LLM judge and a per-run journal. It is what found the defects above, plus two more: recall was not reproducible (ranking ties broke arbitrarily), and the embed queue could lose chunks across a restart, leaving them permanently unretrievable by semantic search.

The main dashboard gains a Learning tile — skill-store maturity and the count of proposed skills waiting on your review, which nothing else on the landing page surfaced.

Also: filter memory on when content happened rather than when it was stored, Cohere embeddings on Bedrock, memory reembed --only-missing for cheap gap repair, answer a steering checkpoint from a Slack button, and near-duplicate detection when a skill is proposed.

Migrations apply automatically and are additive; no configuration changes.


2026.8.2

Upgrade if you use vornik in Slack direct messages. 2026.8.0 stopped a Slack bot answering DMs entirely — silently, with no reply and no visible error. Both 2026.8.0 and 2026.8.1 are affected.

  • Fixed: Slack direct messages were dropped when channel_allowlist was empty. 2026.8.0 correctly made an unconfigured channel_allowlist deny rather than admit every channel in your workspace. But that new check ran before the long-standing rule that a channel allow-list never applies to a direct message, so it answered first and the DM rule never got a chance to.

    An empty channel_allowlist is not a mistake — it is the normal setup for a bot people talk to in DMs. Slack creates a DM's channel id the first time each person writes to the bot, so you cannot list it in advance; sender_allowlist is what controls a DM. Every deployment set up that way lost every DM, on messages, /vornik, file uploads and voice memos alike. Because both allow-list checks drop a message before doing any work, nothing appeared in Slack and no task was created — the bot simply went quiet.

    Direct messages are now exempt from channel_allowlist whether it lists channels or is empty. This does not loosen anything: sender_allowlist still gates DMs, and it also denies by default as of 2026.8.0, so a message from someone you have not listed is still refused.

    If you worked around this by setting allow_unlisted_senders: true, remove it. On an installation with an empty channel_allowlist, that flag also admits every channel in the workspace. You never needed it for DMs: with a populated sender_allowlist, it is not consulted there.

  • Fixed: the App Home tab promised channel access the bot did not have. With no channel_allowlist configured, the Where I answer section said "any channel I have been added to" — which stopped being true in 2026.8.0, when an empty list started denying every channel. The first page a Slack user opens was telling them the bot would answer in places it silently ignored them. It now says what is actually configured, and what to ask an admin for.

  • Clarified: group DMs are not supported. The direct-message exemption covers one-to-one DMs only. Adding the bot to a group DM produces silence rather than an answer; the App Home tab and the Slack guide now both say so, instead of leaving you to find out.

If a chat bot ever goes quiet

Both Slack allow-list checks log a warning and stop before any model is called, so a refused message leaves no trace in Slack and no task behind. Searching the daemon log for not on installation allowlist distinguishes an allow-list refusal from a genuine failure.


2026.8.1

A security fix worth upgrading for. Four built-in agent tools were available to every role regardless of the tool allow-list configured for it, plus fixes for a class of problem where a task finished successfully and its result never reached you.

  • Security: four agent tools ignored per-role tool permissions. memory_search, skill_fetch, get_conversation_window and summarize_thread were offered to, and usable by, every role — even roles whose allowedTools did not list them. All four are read-only (project memory, skills, conversation history), so this granted broader read access than you configured rather than any ability to run commands or write data. If you rely on role tool allow-lists to keep a role away from project memory, upgrade. Deliberately ungated tools are now recorded explicitly with a reason, so the distinction between "ungated on purpose" and "ungated by accident" is visible.
  • Fixed: a finished task whose result never arrived, permanently. The record linking a task back to the chat it came from could be lost when a conversation turn ran long. Once lost, the completion message and the Send button both concluded the task had never come from a chat — and nothing ever repaired it. That record is now written independently of the turn's own timing.
  • Fixed: a delegated task's output was invisible on the task that requested it. When a request was routed to a sub-task, the page you opened showed only the routing step's own small files and hid the actual deliverable. Output now appears on the requesting task, and can be sent from there. Artifacts stay strictly within their own project.
  • Fixed: an unhelpful error when a result could not be delivered. "This task wasn't started from a chat channel" was shown even for tasks that plainly were. The message now distinguishes a task that genuinely has no chat origin from one whose origin record is missing, and offers a download link either way.
  • Fixed: Community Edition was told to run an Enterprise-only command. vornikctl report pointed every reporter at vornikctl support-report, which Community Edition does not include. It now explains what Community collects and what to attach instead.
  • Fixed: PDF output is now guaranteed by tests. The agent image ships the PDF toolchain and role prompts rely on it, but nothing verified it. A regression test now renders a real PDF, including non-ASCII text.

See docs.vornik.io for the full documentation.


2026.8.0

Vornik can authenticate to a remote MCP server on its own. Connect a tool server by granting consent in the browser instead of pasting a token that expires. Plus a batch of fixes for things that were reporting success while doing nothing.

  • New: OAuth 2.1 for MCP servers. A remote MCP server that requires authentication is now connected by clicking Connect on the MCP tab (or vornikctl mcp connect). Vornik discovers the server's authorization requirements, registers itself, runs the consent flow, and refreshes the token as needed — telling you when a revoked grant needs reconnecting. Servers that use a static header or a subprocess credential are supported through the same auth: block. Verified against the published discovery behaviour of eighteen well-known MCP servers.
  • New: ask another Vornik a question. A synchronous consult tool lets one deployment put a question to another and wait for the answer.
  • New: write to memory from a conversation. Ask the assistant to remember something and it will, behind an explicit confirmation step and an opt-in per channel. Personal-scope notes carry their own expiry.
  • New: richer Slack. Inbound images are understood, there is a real App Home tab, a turn that is thinking shows that it is working, threads can be followed up without a mention, /vornik works in a DM, and the slash-command name is per-deployment.
  • Behaviour change — chat allowlists now fail CLOSED. An empty allowed_users (Telegram) or sender_allowlist / channel_allowlist (Slack) used to admit everyone. Both bots are publicly addressable, so an unconfigured allowlist was an open door that looked like an unset field. If you rely on the old behaviour, set telegram.allow_unlisted_users: true or Slack's allow_unlisted_senders: true — deliberately, and for development only. Telegram logs at boot which way it will behave.
  • Fixed: the knowledge-graph extractor was discarding most of its input. A reasoning model was spending its whole token allowance thinking and returning nothing, and an empty answer was being recorded as "found no entities" and the chunk marked done — so the loss was permanent and silent. Truncation is now a distinct, counted outcome with bounded retries, and the graph stages request a low reasoning effort. If you raised the graph token cap to work around this, put it back: a bigger cap makes each failure more expensive, not less likely. Chunks already marked extracted do not self-heal — run vornikctl memory regraph --project <id> to reclaim them.
  • Fixed: email now tells you when a job finishes. Previously it only did so for tasks created a particular way, and never if the daemon restarted in between. The notice no longer depends on a working model to compose itself.
  • Fixed: the control-plane proposal diff. A configuration edit could render as a wall of deletions it was not making, because unrelated lines got reformatted and the diff had no positional pairing. It also had a size limit below the size of a real config.yaml, which made whole-file edits impossible to apply.
  • Fixed: adding an MCP server no longer needs a restart. The change applied and reloaded, but every consumer of the server list was still reading the boot-time configuration — so the server did not exist and could not be connected.
  • Fixed: GDPR erasure reaches entangled records. A memory chunk concerning several people can now be redacted and re-embedded rather than reported as deferred.
  • Fixed: cron mode ignored autonomy.workflow_id; MCP subscriptions pinned a transport and broke stdio servers; host-filesystem MCP tools were not treated as mutating; the "Test endpoint" button called an authentication-protected server unreachable.

New configuration keys

telegram.allow_unlisted_users, Slack allow_unlisted_senders. Both default to the safe value. See the configuration reference.


2026.7.7

The assistant can see. Send it a photo and it answers about the photo. Two legal obligations also moved from documented to enforced-in-code.

  • New: media perception. Images sent over any channel are now understood — answered directly when the dispatcher's model can see them, otherwise handed to a dedicated vision agent. Audio is transcribed; video yields a transcript plus sampled keyframes. Previously a photo produced an honest "I cannot see this", because the pixels were being discarded before they reached the agent.
  • Behaviour change: the dispatcher model is now minimax-m3. It is multimodal, tool-use tuned, and cheaper than the model it replaces. If you pin Bedrock models on swarm roles, check vornikctl doctor's model_route_coverage after upgrading — the default provider route moved, and Bedrock ids are now pinned explicitly rather than relying on it.
  • New: vornikctl erase artifact <id>. Performs a complete GDPR Article 17 erasure — the extraction rows, the memory chunks derived from them, and the stored files. Deleting an artifact alone never removed any of that: derived embeddings survived and merely lost the pointer back to their source. Shows you exactly what will go and asks before doing it.
  • New: AI-disclosure observability. Serve and failure counts for the EU AI Act Article 50 notice are now exported, so you can show the obligation is being met and notice if it ever stops.
  • Fixed: the disclosure record can no longer be pruned. It is the evidence that the notice was served; retention now refuses to touch it outright rather than merely omitting it from a list.
  • New: GDPR data-subject rights. vornikctl subject registers a person, records what is held about them, and produces an Article 15 access or Article 20 portability report. Identity verification is required before anything is produced — an export handed to whoever asked would disclose that person's data to a stranger. Records that also concern other people are listed but their content is withheld, under Article 15(4).
  • New: breach ledger. vornikctl incident records a personal-data breach and walks the Article 33/34 obligations, with the 72-hour clock running from when you became aware rather than when the breach happened. vornikctl doctor warns while there is still a day left and errors once the window closes.
  • New: retention guidance. The sweeper still ships off — enabling it on upgrade would delete data you never agreed to lose — but the doctor now tells you plainly that the deployment keeps personal data indefinitely, and a recommended profile ships alongside your config to copy from. It also warns when the sweeper is on with no windows, and when the memory-chunk window is missing: long-term memory is the longest-lived personal data in the system.
  • Fixed: a model was billing at the wrong rate. kimi-k3 was available but unpriced, so its spend accrued at the default rate — the most expensive model on that route was the one being mis-costed.
  • Fixed: AI disclosure now covers two surfaces that are not channels. The Article 50(1) notice was served on every chat channel, but two paths reach a person without being a channel and so bypassed it: code-review comments the platform posts on pull requests, and autonomous posts to a third-party API. Both now carry the notice. Review comments refuse to post if the disclosure is unavailable rather than publishing undisclosed, and a gateway provider can be marked as a publication surface — a write whose content lacks the notice is refused, with the exact wording to add, so the agent corrects itself and retries. Publication surfaces get their own wording, because "replies in this conversation" is untrue of something the system authored.
  • New: vornikctl subject erase. Carries out an Article 17 erasure for a verified request. It shows the plan and asks before destroying anything, names each record's treatment, and lists what is retained under an exemption with the legal ground — a subject told "erased" while records remain has been misled. The Article 17(1) ground you record decides what happens to records that also concern other people: under most grounds they are preserved, but under 17(1)(d) or (e) the controller has no discretion to retain and the record goes in full. Uploaded files are removed properly — the derived text, the memory built from it, the stored file, and the row. Known limitation, stated because it affects the response a subject receives: removing one person's data from a record shared with others is not yet automated. Those records are identified and reported, and the request is deliberately left open rather than closed as complete.
  • Docs: the records of processing and the DPA template were re-verified against the code. Both had gone stale in the direction that understates the platform — the processing record still said no data-subject identifier existed, and the DPA told a prospective controller that erasure was available only per project or per record. Corrected, along with what the platform still cannot warrant.

2026.7.6

A conversation-channels release. The bot now keeps its bearings in email and Slack. Two behaviour changes are visible to your users immediately — Slack reply placement and the shape of inbound email in the prompt. Read those two items before upgrading.

  • Behaviour change: Slack replies to a top-level message now land in the channel, not in a thread. A message sent inside a thread still gets an in-thread reply, so the bot mirrors wherever the person chose to speak. Deliberate: Slack threads become unfindable within days, so people follow up in the channel anyway, and burying every answer in a thread fought that. Expect a slightly busier channel and far less "where did the bot say that?".
  • Fixed: Slack conversations in a channel had no memory. Every top-level message opened a brand-new empty session, so the bot had no recollection of earlier threads — or even of the message someone typed a minute earlier. All top-level messages in a channel now share one continuous conversation; threads keep their own.
  • New: the bot can reach a channel's earlier threads. On a channel-level turn it sees a short digest of the channel's recent threads — opening question, latest answer, turn count, date — and can pull any one of them in full when the digest is not enough. Reads are scoped to the caller's own workspace and channel. Requires PostgreSQL; on SQLite, digests cover only the current process lifetime.
  • Behaviour change: inbound email now carries a From: and Subject: header on the model's turn. If you pin project prompts to an exact inbound email shape, re-check them. Other channels are unchanged.
  • Fixed: the email subject line never reached the model. An instruction written only in the subject — "add these books to rag", with the books attached and an empty body — was silently dropped, and the bot answered as if no instruction had been given.
  • Fixed: the bot read its own quoted replies as somebody else's words. Mail clients quote the message being replied to, and the whole trailer was handed to the model, which had no idea what its own address was. Reply someone said "4" to a numbered list and the bot asked them what they meant. Quoted trailers are now trimmed (Gmail, Apple Mail, Thunderbird, Roundcube, Outlook including localised forms, forwards, plain > quotes), and the bot is told its own address and that quoted text from it is its own earlier turn.
  • Fixed: multi-party email threads were unattributable. With two people on a thread the bot could not tell their messages apart. Each turn now records its sender.
  • Fixed: Slack retries no longer produce duplicate replies, and Slack slash commands are handled as first-class inbound.
  • Fixed: inbound Slack and GitHub webhook events could reach a channel with no receiver attached and land in logs only, when observability initialisation rebuilt the HTTP server after startup.
  • Fixed on Community edition: operator profiles. The operator memory page renders and saves — its storage and UI route were not fully wired.
  • New operator skills for the Claude Code / Codex companion: configure-vornik (find the tree the daemon actually reads, scaffold, then validate → reload → confirm), troubleshoot-vornik (route by symptom to the right diagnostic instead of improvising) and report-problem (file an anonymised upstream issue, with review before submit). These were described under 2026.7.5 but landed after that release was cut — 2026.7.6 is the first release that actually contains them.

Upgrading requires no configuration changes and adds no migrations. The Slack and email changes take effect when you restart the daemon.


2026.7.5

A security-and-governance release. Two full security audits — the ten-day contribution window and then the whole tree — found and fixed 37 issues, one critical in each pass. Upgrading is recommended. Alongside that, you get per-task spend caps, parallel workflow steps, and a safety net under automated cost tuning. This release also adds anonymous usage telemetry, enabled by default — read that item before upgrading.

  • New: anonymous usage telemetry, on by default. Vornik now reports two lifecycle events — a successful install, and a project creation — to telemetry.vornik.io. What goes out: the event type, the release version, an OS and architecture category, which Vornik-owned path created the project, and for a project the built-in template name (or custom) plus whether autonomy was switched on. Nothing else. No installation identifier, hostname, username, project name, path, repository, prompt, task content, config value, key, endpoint, model name, or error text — and no hashes of any of those. A build from source reports its version as dev rather than a commit, so the version can't single out one machine. The service sees your IP while handling the request, as any HTTPS service does; it is not part of the payload and is never stored alongside an event, so reports can't be linked to each other or to a machine. Only aggregate counts are retained.

    Turn it off at install time by answering n to the prompt, or VORNIK_TELEMETRY=off for an unattended install; afterwards set telemetry.enabled: false. An explicit config choice always beats the environment. Run vornikctl telemetry sample to print the effective setting and the exact request that would be sent, without sending anything. Full detail in the Telemetry and privacy reference. - Security: upgrade recommended. A ten-day contribution audit (21 findings) plus a whole-tree trust-boundary pass (10 findings) plus a review of those fixes (6 more) — all with root-cause fixes and regression tests. The two critical ones: the macOS installer could execute arbitrary commands inside the provisioned VM if an attacker controlled its environment variables, and archive extraction could write outside its target directory by following a planted symlink. Also closed: several safety gates that silently allowed work when they couldn't read their own inputs (per-task API budgets reset by a DB blip, task-cost forecasts proceeding while limits were blind, taint checks reporting "off" when unwired), incomplete SSRF blocklists in both the daemon and the scraper, unguarded browser subresource/WebSocket egress, and gateway errors that leaked full request URLs into agent-visible messages. - Cap what a single task can spend. A new per-task budget stops one runaway task from eating a project's allowance: the forecast at creation refuses a task that would breach its cap, ~80% emits a warning, and 100% parks the task for your decision (increase / reduce / abandon) instead of failing it. Spend accumulates across resumes. Set default_task_budget_usd on the project (with an optional per-task override and a max_task_budget_usd clamp) — 0 or unset leaves everything as it was. - Workflows can fan out in parallel. A new parallel step runs several branches at once and joins them with all, quorum:<n>, or best_effort, so a research or review stage no longer has to run serially. See configs/workflows/parallel-research.md for a worked example. - Memory search tells you how much to trust a result. memory_search now returns a trust verdict (high / medium / low) computed from stored confidence, validation status and freshness — not from an opaque relevance score. A low verdict automatically widens the search, and an aged result with no expiry is capped at medium so a stale decision can't be presented as current. - A safety net under automated cost tuning. After a cost-tuning change is applied, a canary compares quality and cost before and after, and automatically rolls the change back if it regressed — then holds that knob in a cooldown. With that guard in place you can optionally let proven changes apply without a human: only for knobs with a track record of passed canaries, and only when the last change there was made by a person. Off by default, and scoped by an explicit per-swarm allow-list that means none when left empty. - Autonomous writes can be gated on untrusted input. vornik now records whether each agent step consumed untrusted content and can hold a write whose lineage traces back to it, with the contributing sources attached for your review. Defaults to advisory (observe-only, no behavior change) so you can watch it before switching a project to enforce. - Report a problem without leaking your environment. vornikctl report builds an anonymized problem report and a prefilled GitHub issue for you to review before submitting — secrets, emails, home paths, IPs and hostnames are stripped at a single choke point. If it can't anonymize something, it refuses rather than guessing. The installer offers the same thing when a fresh install fails. - Fewer first-run surprises. A pass over a clean install fixed agent-LLM connectivity, unwritable rootless workspaces, the daemon not surviving logout, and Postgres not restarting after a reboot. The bundled demo project now ships with autonomy off so a fresh install can't burn tokens unattended, and vornikctl doctor gained checks for agent-LLM reachability, upstream API-key validity (with a live probe), and agent-image UID mapping. Three doctor checks also stopped reporting correct setups as problems — a router-based model config, a secret externalized to a file rather than an env var, and a prompt that tells an agent not to use a tool it was deliberately denied. - Fixed: vornikctl couldn't read its own config on a fresh install. Every config-loading command failed with database name is required while the daemon on the same host ran fine — the ${...} placeholders in config.yaml are filled from an environment file that the daemon got from systemd and the CLI did not. The CLI now reads the same files (vornik.env and secrets/env alongside the existing secrets/*.env), and if a placeholder genuinely has nothing to resolve to, the error names the variables instead of reporting the field as missing. - Fixed: no models listed when a model-fallback map was configured. vornikctl models list printed nothing — and the models API returned an empty list — for any deployment setting chat.router.model_fallbacks, because model discovery was lost inside the provider chain. The same gap blanked the Ollama-compatible /api/tags endpoint, the doctor's model-reachability check, and the template model picker, and quietly turned per-provider readiness probes into no-ops. The models API now returns 501 when nothing can enumerate models, so an empty list means empty rather than broken. - Fixed: an attached document could be reviewed from memory instead. A review delegated with a file attached could end up reviewing stale recalled chunks rather than the attachment, because extracting the upload at submit time suppressed staging the file for the agent. Workflows that declare they need input artifacts now always get the raw file. The Claude Code and Codex companion plugins ship as 0.13.0 and 0.11.0 with corrected guidance; installed clients pick that up on their next marketplace update. - New: your coding assistant can now configure and troubleshoot Vornik. Both companion plugins bundle an operator lifecycle triad — configure-vornik, troubleshoot-vornik, and the existing report-problem — so setup, diagnosis, and filing a bug each follow a guarded path over Vornik's own tooling instead of being improvised. configure-vornik leads with the configuration traps that fail silently: the config tree is found by a fallback chain rather than one environment variable, VORNIK_CONFIGS_DIR is ignored without complaint unless the directory already holds projects/, swarms/, and workflows/, and editing the wrong copy of a config is the usual reason a correct change does nothing. troubleshoot-vornik routes by symptom to the right diagnostic — doctor --offline when the daemon is down, the failure-class playbook when a task fails — and hands off to report-problem when it runs out of road. - Behavior changes to note. A web_fetch of a page with a blocked or unresolvable third-party asset now succeeds and lists what it refused in a new denied_subresources field, instead of failing the whole fetch. Inbound email that fails delivery five polls in a row is dropped with an error log rather than retried forever (this is what stops one bad message from blocking your inbox). If you override the macOS installer's quickstart URL it must now be https:// and have a published .sha256 alongside it.


2026.7.4

A model-resilience release. Your non-swarm LLM paths now fail over and recover automatically, tool budgets got safer defaults and clearer warnings, and model-health is fully visible in the doctor.

  • Automatic model fallback for non-swarm paths. A new chat.router.model_fallbacks map (primary model → fallback model) lets the chat/dispatcher/autonomy/wizard path and the built-in workers (narrator, memory consolidation, titler, classifier, judge, …) fail over to a configured twin when a model's circuit opens — and return to the primary automatically when it recovers. Previously only swarm-role agents had this; an upstream outage would stall the rest. Empty map = unchanged behavior.
  • Model health is fully observable. vornik doctor now reports both circuit breakers — the chat-router breaker (model_circuits) and the agent-container breaker (agent_model_circuits) — as separate checks, so an open circuit is visible where you look. The troubleshooting guide explains the two breakers and why an open agent circuit can leave the chat one showing closed.
  • Tool-budget refinements. An operator-started task keeps its full tool budget across a crash-and-resume (instead of dropping to the tighter autonomous cap); startup warns when a role's tool-budget config won't take effect (a warm role, or a role with no base limit); and the standard complexity tier now downscales to 0.5× of a role's configured budget (the base is reserved for genuinely complex work) — note this behavior change if you relied on standard running at the full configured budget.
  • Scheduled updates. Reminders can now run a task on a cadence and deliver its outcome, not just static text — ask the bot for a recurring digest or weekly plan ("every Monday at 7, plan my week") and it will spawn the task and message you the result when it's done. Pause and resume it from chat, the CLI, or the web UI's reminders table, and edit a recurring reminder's cadence or project in place from chat instead of recreating it. A slow run never overlaps itself, and an interrupted daemon can't lose or double-send an outcome. See vornikctl reminders and Observability for the new metrics.
  • macOS install. The one-liner curl -fsSL https://get.vornik.io | bash now works on macOS as well as Linux — the same command; the script detects your OS. On macOS it provisions a small Linux VM and runs the stack inside it, so the zero-egress agent isolation is preserved exactly as on Linux. See Getting started.
  • Control-plane: apply tuning changes without waiting for an idle window. A value-only workflow edit — e.g. reclaiming an over-provisioned step timeout — now applies even while tasks that use the workflow are in flight; only structural changes still wait for an idle window. Recommendations that go stale (their config target changed since they were drafted) now auto-retire instead of lingering as un-appliable, and the detector re-files a fresh one.
  • Control-plane hub is tidier. The proposals inbox hides closed (rejected / rolled-back) rows by default and paginates; the skills browser hides retired skills by default; system-retired rows carry a distinct label so they don't read as human rejections; and long MCP/dispatcher tool descriptions now collapse behind a toggle.
  • Safer rollback. Rolling back an applied change is refused when a later change overwrote the same target (or it was hand-edited), so a rollback can no longer silently clobber newer state — roll back the newer change first. The hub hides the rollback button on a proposal that's been superseded.

2026.7.3

A hardening + security release. The headline is a full security pass over the code base, alongside autonomy workspace-state hygiene, a manifest-driven config installer, wizard composition convergence, an Ollama Cloud chat provider, and a broad fix batch.

  • Security hardening. A sweep of the static-analysis backlog: path handling for user-supplied project/swarm/workflow identifiers is centralised on one confinement primitive; e-mail envelope addresses reject control-character injection; result pre-allocations are bounded; a webhook echo is HTML-escaped; admin redirects are constrained to same-origin; and session/chat cookies set Secure automatically when served over HTTPS (without breaking plain-HTTP deployments). Additional trust-scope and config-path hardening also landed.
  • Autonomy workspace hygiene. Failed/cancelled tasks no longer strand tracked-file residue in the shared workspace clone; the prelude auto-commit now attributes honestly (backlog: marker checkpoint / rescue: stranded tracked changes) instead of blaming the next task. Scripts grepping the old auto-commit: workspace-root prelude message must update. A new vornik_executor_residue_discard_total{project} metric flags workspace contract violations.
  • RAG-ingest quality gating. A task's output is ingested into memory only once the producing task succeeds, so failed runs no longer deposit garbage; vornikctl memory purge-producer-failed retro-cleans older residue. Backlog items are marked done at the success terminal, not at dispatch.
  • Agent LLM circuit breaker. Per-agent model calls now get the same circuit-breaker / fast fail-over as the chat router.
  • Manifest-driven config tree. A single manifest drives what installs into the deployed config tree, with drift-checking across all deployable subtrees.
  • Ollama Cloud provider. A new chat sub-provider for Ollama's hosted open-weight models, separate from the local Ollama route; pricing refreshed.
  • Wizard convergence. The project wizard normalises and repairs compositions (dropping undeclared params, defaulting required ones) and retains the last good build.
  • Quality-of-life. Progressive-disclosure skill injection; friendlier internal-role labels on the spend dashboards; the Fix-It Doctor link now works on every deployment; an inbox mobile pass; and a turnkey in-place update script for Community quickstart installs.

2026.7.2

The operator-experience release: describe an automation in plain language, watch tasks narrate themselves, and repair failures from a guided chat. This cycle is built for operators who never want to touch YAML — plus a control-plane copilot, a learning loop for knowledge skills, and an autonomous backlog-to-PR pipeline for those who do.

  • Automation Composer. Describe what you want automated in chat and the composer assembles a validated project — roles, workflow, schedule — grounded in your connected MCP servers and models, with a Plan/Graph/YAML preview before anything is committed. Ships disabled by default (composer.enabled) while quality gates soak; the classic wizard remains the default.
  • Narrated execution. Running tasks tell their story on the task pages, and can push progress to the chat channel that started them (opt-in per project). Completion is deliverable-first: output artifacts appear as cards you can send straight to chat.
  • Fix-It Doctor. Failed tasks open into a repair chat that gathers the failure context and proposes fixes; every applied action is deny-by-default, audited, and rollback-able.
  • "My requests" home. A new Outcome Inbox groups your work into request cards with status rollups and inline actions for anything awaiting you — and it is now the default home page for non-admin users.
  • Guided Integrations Hub (Community). Set up Telegram, Slack, email, GitHub App, and MCP integrations through guided forms that probe the credentials before saving, with recheck and assisted troubleshooting.
  • Control-plane copilot (Enterprise console). Detectors watch for tunable timeouts, failure-rate regressions, and self-healing incidents, and raise proposals you can inspect, apply (gated, atomic, rollback-able — live where non-disruptive), or withdraw, from the web console or vornikctl control-plane. A diagnose-from-logs engine turns incidents into ready-to-apply config changes.
  • Knowledge skills learn. Skills gathered from past work now carry usage signals and mature (or decay) automatically, with distilled new-skill proposals reviewed from Telegram, Slack, or the web inbox — and skills can be promoted to global, applying across every project.
  • Autonomous dev loop. Agents can deposit work items into a per-project backlog, and autonomy drives open items to draft pull requests through an adversarial review loop; failed items are blocked visibly instead of silently skipped.
  • Model-health circuit breaker. Unhealthy upstream models trip a breaker and tasks fail over immediately instead of grinding through the retry ladder. On by default with conservative thresholds; tune via chat.router.health.*.
  • Credential carryover. Tools that mint credentials during a task can have them captured (opt-in per tool) and surfaced to you at completion — redaction stays fail-closed throughout.
  • Telegram task control. /tasks, /status, /cancel, /retry, plus button-driven recovery steering and tap-to-copy command rendering.
  • Community contribution: AWS Bedrock embeddings. Native Bedrock embedding support for memory/RAG — the first inbound community contribution.
  • Quality of life. Config saves never hang (invalid saves are rejected; restart-required changes show a banner), a unified Artifacts panel, paused tasks can be cancelled, per-MCP-server timeouts, and mobile layout fixes.

Restart to pick up new behavior

The model-health circuit breaker and the new detectors start with the daemon; restart after upgrading. All new configuration keys are additive.


2026.7.1

A polish release: leaner large tool outputs, an end-to-end project-creation experience, and clearer edition boundaries. This follow-up to 2026.7.0 keeps big tool payloads out of the model's context, finishes the guided project-creation flow, and tightens the Community/Enterprise line.

  • Large tool outputs stay out of the context window. The daemon can now hold a large MCP tool result and hand the model a compact handle instead of the full payload, and the per-result size cap is configurable (default raised to 256 KiB). A new image-encoding helper fetches and downscales an image to an inline data URI, hardened against SSRF.
  • End-to-end project creation. Project templates gained list/multiselect parameters, dynamic option sources, and conflict-free ID suggestions, with new ready-made purpose templates (code reviewer, tool assistant, report pipeline, docs↔RAG sync). A per-project readiness page (/ui/projects/{id}/setup) runs config, schedule, secrets, MCP, model, and smoke checks and flags what is still incomplete, and the conversational project wizard now composes a project turn by turn from your live MCP servers and models, showing a summary before it commits.
  • Clearer edition boundaries. Community Edition returns a typed "Enterprise-only" response on Enterprise-gated admin routes, companion API-key minting is available in Community, and the Memory Firewall and project configuration are now Community features (cross-project context remains Enterprise).
  • Security & correctness. Fixes for a cross-project access-control gap in the UI, a server-side request-forgery path, and several query-efficiency improvements on hot paths.
  • Onboarding fixes. The setup flow now correctly recognizes router- and CLI-based chat providers as configured, clearing spurious "not configured" and session-authentication errors on the setup and wizard pages.

Restart to pick up new behavior

The configurable tool-result cap and media-handle behavior take effect after a daemon restart.


2026.7.0

A renamed, edition-aware platform with an AI-first install and a hardened memory/chat core. This release completes the rename to vornik, introduces a clean Community/Enterprise edition seam, publishes the docs site, and lands a broad reliability pass across memory/RAG, chat providers, onboarding, and deployment.

This release renames the product

vornik is now vornik and vornikctl is now vornikctl. Service names, command names, config paths, environment variables, and dashboards changed. Review your automation for the vornik → vornik migration before upgrading, and always take a backup first.

  • Vornik rename, end to end. Source, commands, environment variables, metrics, deployment files, Helm chart, Grafana dashboards, configs, and docs moved from vornik to vornik; vornikctl is now vornikctl.
  • Edition-aware builds. The codebase now has a clean Community/Enterprise seam: every feature carries a CE/EE tag (shown in the docs and enforced in code), and the Community Edition builds and ships independently under AGPL-3.0.
  • Published documentation. Public docs are now served at https://docs.vornik.io, with per-page edition markers and expanded onboarding, architecture, configuration, CLI, security, and support material.
  • AI-first install. AGENTS.md is now a runbook a coding agent can execute and verify end to end (install → LLM key → first task → its own persistent memory); the getting-started path makes the AI-assisted install the preferred route (short link: agents.vornik.io).
  • Sharper memory recall. Multi-term recall now uses a strict full-text query with a relaxed fallback and all-term matches ranked first; a reranker-gated, round-isolated retrieval path improves context assembly, scoped to non-interactive use so interactive recall stays fast. By-id correction is now the preferred way to fix a stale or wrong memory.
  • More resilient chat. Long conversations are summarized instead of dropped when context overflows, chat providers share a tuned HTTP transport, and persistent-timeout handling engages provider fallback faster.
  • Companion & MCP. A first-party Codex companion plugin joins the Claude companion; companion memory gained a memory_correct tool (including a surgical by-id refute mode) plus input-validation and reliability hardening.
  • Deployment quickstarts. A one-command, pgvector-backed local playground and a hardened installer (clean re-checkout, safe cleanup, literal DB port); PostgreSQL + pgvector is the recommended backend for memory/RAG.
  • Fixes & hardening. Rate-limit minute/hour buckets no longer cross-sum; no-JavaScript pages render one consistent color scheme; Postgres integration tests honor POSTGRES_PORT.

Restart required

Restart the daemon after upgrading to pick up the new behavior.

Enterprise-edition capabilities (packaging and installers, SSO and admin surfaces, clustering, and more) also advanced this release — see the Editions matrix for what's included where.


2026.6.1

A more visual control plane, safer to expose and support. This release consolidates a large body of work: the web UI's capability tracks, a security/operability hardening pass, git-over-HTTPS workspace access, and content provenance.

  • Edit workflows as a graph. A new graph view (/ui/workflows/{id}/graph) lets you wire steps visually — add/delete nodes, draw success/fail/gate edges, set the entrypoint — with every change validated and hot-reloaded like the form and YAML editors.
  • Bulk actions & clone. Multi-select on the Tasks list (bulk Cancel / Retry / Close) and the Executions list (bulk Cancel); clone a workflow to a new id from the editor.
  • Insight area. A Trends page (daily throughput, success rate, judge abstain rate, recovery, and LLM spend) and a Tool budget page (actual tool-use vs the configured complexity-tier budget, now with advisory over/under-provisioning flags).
  • Clone and push to a project workspace over HTTPS. A project's git-backed workspace can be cloned and pushed to with a per-project API key — no shell on the box. Exposure is opt-in per project (Project.Git.Enabled + server.public_base_url); push requires a key issued with --allow-push (keys are read-only by default) and is blocked while a task holds the workspace, so a push can't race a running job. Manage it from the new project Git-access panel or vornikctl key --allow-push.
  • Centralised log forwarding. A new subsystem ships vornik's structured logs and audit events to an external HTTP webhook (bearer-token) and/or syslog (TLS with a pinned CA). Forwarding is scope-filtered, best-effort, and never blocks the daemon; an empty or ship-all scope is refused.
  • Run safely behind a reverse proxy. Trusted-proxy real-client-IP resolution (server.real_ip) recovers the true client IP from a configurable header — trusted only when the immediate peer is in your trusted_proxies allowlist — so brute-force lockout, rate limiting, and audit no longer collapse every user to the proxy's address. Off by default.
  • One-command support bundle. vornikctl support-report --task <id> (or --since <window>) produces a single, redacted-by-default, self-contained diagnostic archive — lifecycle, audit, LLM usage, conversation, container and daemon logs, redacted config, a doctor diagnosis, and version/health — so you no longer hand-assemble evidence for a support thread.
  • Smarter content redaction. The output guard now knows whether scanned content is first-party (produced by vornik) or third-party, so vornik's own output is no longer over-redacted while untrusted content and secrets still are.
  • Structured recovery steering. When a step fails, the lead can be offered a typed recovery decision — re-route the workflow, fall back to a role's configured model, retry, or skip — and successful recoveries are recorded so they surface as a recovery trend.
  • Outbound email attachments. The email channel now sends replies as multipart/mixed, delivering send_artifact outputs as attachments on the threaded reply. File delivery is now channel-agnostic and shared with Telegram.
  • More vornikctl doctor checks. model_health (flags a model that is failing or returning degenerate output and recommends its fallback), config_crlf (detects — and with --fix repairs — CRLF line endings that cause phantom config drift), model_route_coverage (every role's model resolves to a route and has pricing), and scraper_profile_freshness (warns on stale scraper login sessions).
  • Clustering / fleet visibility. Lightweight multi-node awareness: heartbeat/relay logging and metrics, a probe library driven by an expected-endpoints config, and an opt-in, leader-gated endpoint monitor with operator alerting.

Notable fixes: a graceful restart no longer fails in-flight work and bounded graceful shutdown force-closes stuck connections so a long-lived chat request can no longer hang a restart into a SIGABRT (pair with TimeoutStopSec=90s); the Bedrock adapter recovers SDK panics on cancel-during-shutdown; document extraction is hardened against zip-bombs, XXE, and OCR hangs; schema-config saves normalise CRLF→LF (with a CI gate) to stop phantom config drift; the multi-step "file does not exist" artifact-handoff bug is resolved with store-backed staging and an end-to-end regression guard; and first-eval-after-reload chat no longer emits a spurious "LLM error". Under the hood, recovery exits are now recorded and several previously design-only observability metrics are emitted.

Upgrade

Restart the daemon to pick up the new behavior. Add TimeoutStopSec=90s to the systemd unit so the bounded shutdown has room to drain. Log forwarding, the support report, real-IP resolution, and git-over-HTTPS workspace access are all opt-in — existing deployments are unaffected until you configure them.


2026.6.0

Fix GitHub issues end-to-end. Label an issue (or open a pull request) and vornik can plan it, make the change across subtasks, review its own diff, and open a draft pull request for you to approve — hands-off, with the daemon doing the branch push and the review posting. Every automated PR is a draft, so nothing merges without you.

Other highlights:

  • Self-improving workflows. When a workflow starts failing or getting expensive, vornik can propose a repair, replay-test it against real past runs, score it against the current version, and apply it only when you approve — nothing changes on its own.
  • The swarm learns from itself. A new continuous-learning layer mines reusable, confidence-scored fixes from past runs and surfaces them as advice on failed tasks and to the planner. Advisory and opt-in.
  • Refreshed control-plane UI. A new translucent design with icon-rail navigation, first-class Swarms / Workflows / Executions list pages, and tidier per-page layouts.
  • Feature Doctor. A new command tells you which optional features are enabled, ready, or blocked — and can turn one on for you, with a backup, validation, and automatic rollback if anything is wrong.
  • Sign in with GitHub. Optional GitHub login for the web UI with per-project access scoping, plus the groundwork for single sign-on.
  • More model choices. Free-tier hosted models with automatic fallback, and per-role tool budgets that scale to task complexity so simple tasks stay cheap and hard ones get more room to work.
  • Public documentation is now live at docs.vornik.io.
  • Safer web fetching. The research browser follows shortened links (e.g. map short-URLs) to their real destination before applying your host allowlist, and refuses to reach private or loopback network addresses.
  • Security & safety hardening. A broad audit-remediation pass across access controls and memory-access policy.

Restart after upgrade

A few of these are read from the daemon config at startup, so restart the daemon after upgrading to pick them up.


2026.5.9

The conversational project setup wizard now works end-to-end: start a new project from a guided chat, resume or cancel a draft, and have it created and running just like a template-based project. You can pin the wizard to its own model independently of your default chat model.

Other highlights:

  • Official packages and binaries. Releases now ship prebuilt vornik and vornikctl binaries (Linux amd64 and arm64) plus RPM and DEB packages, attached to each GitHub release.
  • Stronger default network isolation for agents. New installs default to a zero-egress agent network: agents reach vornik for model and tool access but cannot reach the internet. Roles that genuinely need outbound access can opt in per role.
  • More resilient chat under rate limits. The model client now honors rate-limit retry hints and backs off automatically instead of failing the request.
  • Chat history loads on page open. The web chat view now shows your prior conversation immediately instead of starting blank.

Structured output is model-dependent

Features that need strictly structured model output (such as the wizard) are most reliable on models that honor structured-output requests. The wizard tolerates models that reply in prose, so it stays usable regardless.

2026.5.8

Two operator-facing capabilities landed alongside a large stability pass:

  • Counterfactual replay. Re-run any past task with a single variable changed — a different model or a different prompt — and compare the original and the new run side by side, including cost, latency, and per-step differences. Available from the command line and the web UI.
  • Memory policy controls. Every memory item now carries policy metadata (sensitivity, provenance, expiry, and access scope), and every retrieval is recorded for audit. Three modes let you choose how strictly policies are enforced: off, advisory (the default — nothing is blocked, but everything is logged), or enforce. The default is safe to adopt without changing existing workflows.

This release also closed a broad set of reliability and security fixes across task execution, scheduling, memory, and inbound channels.

2026.5.7

A large user-experience release.

  • New landing page with at-a-glance tiles (active tasks, active chats, today's spend, next autonomy run) and a cross-project activity feed.
  • Project template gallery. Browse a catalog of starter projects in the web UI (or via vornikctl init project --template <slug>) and create one from a simple form, filterable by domain.
  • Per-project home page with a readable summary card, autonomy status, and an effective data-retention panel that shows your actual pruning windows.
  • Friendlier error messages. Failed tasks now show a plain-language banner explaining what went wrong, with the technical detail tucked underneath.
  • Retry a failed task from the step that failed, directly in the UI.
  • Smarter memory recall, including optional date-range filtering ("what did we discuss last week") and a resilience cascade so memory search keeps working even if part of the search backend hiccups.
  • High-availability friendliness. If you run more than one vornik instance, polling channels now coordinate so a single inbound message is handled once, not duplicated.

Optional new settings

The client request timeout is now configurable for long-running commands, and projects gain optional description and retention settings that surface on the new home page.

2026.5.6

A guardrails and memory-quality hardening release.

  • Runaway-loop protection for adaptive workflows. A misconfigured router can no longer spawn an endless chain of child tasks; routing now caps its depth and fails clearly instead of looping. If a workflow previously relied on a silent fallback, review your candidate-workflow list (see the behavior note below).
  • More reliable memory classification, including an optional background pass that keeps newly ingested memory labeled without manual cleanup.

Behavior change

Adaptive routing no longer silently falls back to your project's default workflow when a step picks an out-of-list choice — it now fails loudly. If you depended on the old fallback, tighten your candidate list or disable strict mode. Restart the daemon to pick up the new behavior.

2026.5.5

A memory-quality release focused on retrieval precision.

  • Better recall through a set of ranking improvements (richer embedding context, reranking, result diversification, and time-to-live enforcement) that surface more relevant memory without any change to how you use it.
  • New memory maintenance commands: reclassify, re-embed (for model upgrades), and list prune candidates.
vornikctl memory reclassify --project <project>
vornikctl memory reembed     --project <project>
vornikctl memory prune-candidates --project <project>

2026.5.4

A reliability release.

  • Native AWS Bedrock support for chat and agents, removing a translation hop for Bedrock-hosted models.
  • Sturdier scheduling and recovery. Interrupted tasks recover faster, models that get stuck producing the wrong output shape are stopped instead of burning budget, and lease handling under heavy load is more robust.
  • Model-quality visibility. New dashboards surface which models are producing malformed output and how often retries recover, so you can spot a poorly behaving model and swap it.

Upgrade

Restart the daemon after upgrading. If you build the agent image yourself, rebuild it to pick up this release's runtime improvements.

2026.5.3

A reliability and output-correctness release.

  • Declarative output schemas. Agent roles can declare the exact shape of their output in one place, eliminating a whole class of "valid output, wrong shape" failures. vornikctl doctor flags mismatches before they cause a failed run.
  • Security hardening across container isolation, secret detection, webhook authentication, and API input validation.

Upgrade

Restart the daemon to activate the new schema enforcement.

2026.5.2

A reliability and observability release.

  • Per-task post-mortem explainer. Failed tasks now include a plain-language paragraph explaining why they failed, alongside the step outcomes and audit trail.
  • Security fixes, including requiring authentication on the web UI subtree and closing a cross-project access path.

2026.5.1

Cancelled tasks now show their accumulated LLM cost in the UI, and autonomy's duplicate-suppression now matches by topic similarity rather than exact text.

2026.5.0

The trustworthy-output release. A multi-phase hallucination-detection pipeline now runs across agents, chat replies, and the autonomy loop, flagging unsupported claims (a quoted URL that was never fetched, a referenced file that was never produced, a numeric claim with no source) and either failing the step for retry or surfacing the finding in the UI.

Also in this release: multimodal task input (image uploads through chat), an additional first-class chat provider, secret detection and redaction at every persistence point, and a larger operator UI (spend deep-dive, live tool-call audit stream, routing-decision panel).


Earlier releases (2026.4.x)

The 2026.4 series built vornik from its first stable release into a capable multi-agent platform. Notable user-facing milestones:

  • 2026.4.14 — A typed agent tool set (file_edit, grep, glob, and typed git inspection tools) with per-role allowlists; live task-log tailing in the CLI and UI; signed webhook ingress with audit history; a project onboarding wizard; and a browser-based project YAML editor with validation.
  • 2026.4.13 — Direct-API access to subscription-billed model backends (no CLI subprocess), a multi-backend chat router, a headless-browser fetch capability for agents, and an expanded vornikctl doctor with new schema, security, cost, and hygiene checks.
  • 2026.4.12 — Per-task cost drill-down, local-timezone budgets, tool-call rate limits, a per-project data-retention sweeper, and vornikctl backup / restore.
  • 2026.4.11 — First-class LLM spend tracking: per-step token and cost metrics, a per-project spend panel (24h / 7d / 30d / month-to-date with a per-role breakdown), and soft/hard USD budgets enforced before work starts. Introduced "effective cost" (spend per successful step) so a cheap-but-flaky model stops looking cheap. See Cost and caching.
  • 2026.4.10 — Per-user channel project scoping enforced on every action, per-project tool servers reached through the daemon (no per-agent credentials), and a deterministic git-backed workspace so "task completed" reliably means "output was saved."
  • 2026.4.9 — Per-task git worktree isolation, a swarm-agnostic adaptive workflow that works with any swarm, a runtime autopilot on/off toggle, and lenient registry loading so one broken project no longer takes down the rest.
  • 2026.4.8 — Per-role model overrides applied correctly to warm containers, an expanded vornikctl doctor, and additional conversation session controls.
  • 2026.4.7 — First stable release. The autonomous development pipeline, durable task queue and scheduler, the multi-step workflow engine, the server-rendered web dashboard, and the conversational bot interface.

For configuration details on anything mentioned here, see Configuration reference and the Guides.