Nodal-Agents

Changelog

Notable releases of Nodal-Agents, newest first.

Notable releases, newest first — this page is the repository's CHANGELOG.md, generated at build time. Pre-1.0: minor versions can carry breaking changes. Every release is published to npm as nodal-agents and tagged on GitHub — upgrade in place with nodal-agents update (your data is preserved).

v0.9.9 — Nov 2, 2026

A release about files, and about what comes back to you. A file sent to an agent on Telegram, or an image on Discord, now reaches it, and the platform records it as that job's own. An agent can move a file, read a PDF the way it reads an image, and file a document with a method that ships with Nodal. Settings → Safety shows the sandbox as it is on your machine and lets you set it. A job started through the MCP server can finally be read back. Eighteen pull requests, three database migrations.

Upgrading: what changes for you

  • The sandbox is still Windows only. The macOS and Linux sandbox that 0.9.8 announced for this release is not in it. There, commands run unconfined, as in 0.9.8, and every command result still says sandbox: { confined: false, code: "SANDBOX_NOT_IMPLEMENTED" }. The new Sandbox section says so in plain words and disables its controls on those systems. (#877)
  • Three database migrations (0153 to 0155), applied on the next start:
    • 0153 adds two columns to your workspace: the sandbox switch (on, the value the runner already applied) and your changes to the allowed folders (none). Nothing changes for anyone until they use the new section.
    • 0154 gives file_move the decision you already took on file_write: every approval rule on file_write (block, ask or auto-approve, for one agent or for everyone, with its folder condition) is copied to file_move. A read-only agent that blocks file_write therefore cannot move files the day it upgrades. A rule you had already set on file_move is kept. (#881)
    • 0155 adds two columns to the table that holds the proof of each file a job must deliver, so that a move can be told from a deletion (removed and moved_to_key). Both start empty and nothing is rewritten. (#919)
  • An agent that answers in prose is done. A job turn that ends without a tool call is the job's answer, and the second model call that used to check it is gone. You get the answer sooner, and the agent no longer repeats an action it had already done: in a month of real runs, that check made an agent send the same review twice, delegate the same copy twice and create a second print request. The limit: an agent that only announces ("I'll delegate to X.") now ends completed with that sentence as its answer. A failed delivery, a declared file that is missing and an approval still pending are judged on facts, as before, and still stop the job. The chat keeps its check. (#890)
  • Claude models on OpenRouter now use the prompt cache. Anthropic does not cache by itself, and Nodal only asked for it on the direct Anthropic route: over 30 days, none of 852 calls to a Claude model through OpenRouter read from the cache, and each paid the whole prompt, about 30,000 tokens for a root agent. It is now asked for on the ten Claude models of the catalog, whatever the route. Every other model is unchanged, and so is the direct Anthropic route. A model of OpenRouter that is not in the catalog sends no marker. The cache setting turned off still disables it everywhere. (#888)

Files

  • A file sent on Telegram reaches the agent. A PDF, a document, an audio file, a voice message, a video, a video note or an animation used to be dropped, and neither you nor the agent learned that anything had been sent. Now the file is saved in the shared folder under its own name, and the agent is told its path, its name, its type and its size, and that it is kept 30 days. A file that could not be fetched or saved is said to the agent too, with the reason, so that it tells you; the other files of the message still go through. A file sent without a caption becomes a job, and in a group so does a file whose caption is only the bot's mention. A name that Windows refuses is made safe, and a file already there is never overwritten. Photos go through the same intake. (#902)
  • On Discord, a received image goes through the same intake. An image Discord would not let through, a failed download or a full inbox used to leave the agent answering without knowing an image had been sent. It is now told, with the reason. Other kinds of file on Discord, and files on Slack and WhatsApp, are not received yet. (#911)
  • The path the agent is shown is the path that exists. A received file now lives in the shared folder, under the channel (shared/telegram, shared/discord), in a folder named after the job. It first lived under the conversation, and the model saw that conversation's handle where the folder carried the real chat number, so file_read answered "File not found" and the agent could not file the document. Folders of the first layout are cleaned up by age, like the current ones. (#911)
  • A file the platform saves for a job is that job's. Moving a file you had just sent asked for an approval although the tool was set to autonomous, because the file counted as someone else's. A received file, and the images and PDFs a tool hands to the model, are now recorded as written by the job they were saved for. A file another job wrote, a file you edited, or a received file that another job rewrote afterwards still asks. (#918)
  • file_move moves or copies one file inside the agent's folders. It has the perimeter of file_write: the agent's folders and the shared folder, links that escape refused. The destination is a file path, or a folder where the file keeps its name; missing folders are created on request. Replacing an existing file, or removing from the shared folder a file another run wrote, asks for approval like an overwrite. The bytes never go through the model, and the undo checkpoint covers the move. The run feed, the delivered files and the approval cards say "moved A to B" or "copied A to B". The shared workflow templates stay read-only: they can be copied, not moved away. Known limit: the delivered-files list shows a move between two folders of a workspace by its new name only. (#881)
  • A file the agent moved is no longer checked at its old place. The check of a job's deliverables used to ask the source of a file_move whether it still existed, after the move had removed it: the destination was green, the job was red, and the agent had to tell you that "the check fails because it checks the old location". The old place is now proved as "moved to" the new one, and the file that arrives is checked itself: if it disappears or changes later, that check turns red. A move counts only when file_move confirms it did it. A move that failed, a mv in a shell, a copy followed by a deletion and an rm stay red, as before. A file that comes back to the old place turns the check red again. (#919)
  • A PDF reaches a model that can read one. file_read hands a PDF to the model as the document, like an image, where it used to return undecodable text. A model that cannot read PDFs is told so, with its name, and never receives the bytes. A PDF is limited to 10 MiB, and each page counts as one image of the 20 a request may carry; a longer PDF is read by windows of 20 pages. The models that take PDFs are listed from what their own route says, never guessed: 36 on 31 October. A native OpenAI model is not on that list while the sources do not say it reads PDFs. A PDF inside an MCP tool's result is still only recorded, not passed on. (#905)
  • A "File filing" skill ships with Nodal. It is a method, not a tree: where a document goes comes from a "Your folders" section that you fill in on the skills screen. The method tells an agent to read a document before placing it and to ask when it cannot. Every file whose place is clear is moved without a question, however many files there are: fifteen documents with fifteen clear places are filed in one go. Only the files whose place is not clear go into a single question, with a plan for them and a proposal. While "Your folders" is empty, no place is clear, except a destination you named in the request. The method also names a file that has no meaningful name YYYY-MM-DD Subject, never replaces a file (a second one becomes "(2)"), never deletes, and reports every file moved and every file left in place, with the reason. It loads only when you ask to file, sort or put something away. Assign it to the agents that file your documents. (#895, #925)
  • If you edited the skill, your copy keeps the text it had. Nodal never overwrites a skill you changed: on an upgrade it refreshes only the default text that "Reset to default" restores. Filling in "Your folders" is such an edit, so a copy that carries your folders still asks for your go when several files are involved, as the first version of the method said. To get the rule above, copy that sentence in by hand, or use "Reset to default", which also removes your folders. A copy you never edited is updated at the next start. (#925)

The sandbox, in Settings → Safety

  • A Sandbox section shows the sandbox as it is on this machine: active, or unavailable with its code and a sentence that says why, the engine, and the known limits of each. Three cards give the perimeter with your own paths: the folders a command may write in (each agent's folders, the shared folder and your allowed folders), Nodal's data, which a command cannot read, and the network, open to the internet and to local services over HTTP and HTTPS, with Nodal's own ports refused. (#877)
  • One switch per workspace. Turning the sandbox off asks you to confirm and says what follows; turning it on asks nothing. While it is off, unavailable or unreadable, a banner stays in the dashboard. The setting is read again at every command, so a change applies from the next one and a command already running is not touched. Off, a command runs unconfined and says sandbox: { confined: false, code: "SANDBOX_DISABLED" }. A setting that cannot be read is never taken for on or off: the command is refused (SANDBOX_SETTINGS_UNREADABLE). (#877)
  • The allowed folders are yours to edit. Each says where it comes from (Nodal, found for a tool such as ComfyUI or Ollama, added by you, or not found and skipped). You can add one, remove a detected one and allow it again; a folder installed later appears by itself, and the tool cache cannot be removed. Adding a whole disk, your home folder or a folder that holds Nodal's data asks you to confirm and names the consequence. Adding Nodal's data folder, or any folder under it, is refused with the reason. Two tabs changing the list at the same time both keep their change. (#877)
  • Agents that run outside the sandbox are named. An agent whose runtime runs its commands itself, such as the Claude Code and Codex runtimes, gets a warning on the screen. The Knowledge section of an agent's page says that its commands can only write in its folders and in the allowed folders. (#877)

MCP

  • get_task reads back a job that run_task started. run_task returns a receipt, a job id, and nothing could read the answer: it was visible only on the Runs page. get_task takes the job id and returns the status, the agent's result or error, the files it declared with their proof, and any question or approval waiting for you, with the request quoted. It reads the whole run, delegations and continuations included, and reports it finished only when nothing is left running. waitSeconds (0 to 60) holds the call until the run finishes or needs you. It reads and writes nothing. It answers for the jobs that this MCP server's workspace started, and refuses any other id with the same message, whether the job does not exist or belongs elsewhere. A waiting question is still answered on the dashboard. (#889)

v0.9.8 — Oct 23, 2026

A release about what your agents can touch and what they leave behind. On Windows, the commands an agent runs are now fenced by the operating system. A job owns every process it starts, so Stop and the end of a job really end them. A run budget covers the whole run, delegations included. Agents whose model sees can look at images, and the model no longer receives your e-mail address or a conversation's phone number. Node 24 is now the minimum. Forty-four pull requests, six database migrations.

Upgrading: what changes for you

  • Node 24 or newer is required. The install command is the same, npm install -g nodal-agents; the prerequisite is not. On an older Node, nodal-agents and the runner stop at start with one line that says so. Node 22 loses its support in April 2027, and the Windows sandbox needs 24. Install Node 24 first. (#751)
  • On Windows, a command an agent runs can only write where its job lives. The folders of the job (its workspaces, the shared folder, the folder attached to the request) and a few folders computed from your machine stay writable: Nodal's tool cache, the models and output of ComfyUI, the models of Ollama, the caches of Hugging Face, the image store of Docker. Everything else is read-only; reading and the internet stay open. Details below. This is for Windows only: on macOS and Linux, commands are not confined in this release. Every proof command an agent declared for a deliverable asks for approval once more. (#753)
  • A job owns every process it starts. Stop and the end of a job kill what a command left running, including processes that detached themselves. Details below. (#834)
  • The run budget now covers the whole run. This changes what Settings → Run budget means for delegation. Before, each delegated job started over with the whole cap. Now a run, the job you started, everything it delegated and the continuation its inbox starts when it finishes, shares ONE cap, checked before every model call. A run without delegation is unchanged. A delegated run that used to stay under the cap job by job can now stop earlier, at the cap. (#836)
  • Your e-mail address never reaches the model. When you answer a card from the dashboard, the agent is told who answered by account id, not by address. (#820)
  • A conversation is named to the model by an opaque handle (conv_ and ten letters), never by the channel's own id. A WhatsApp conversation id is a phone number: it no longer reaches the model provider. The send tools accept the handle; a raw numeric id is still accepted, so ids an agent stored in its memory keep working. (#826)
  • nodal-agents down tells the truth, and exits 1 when something is still running. Details below. nodal-agents reset refuses to delete the data folder under a database it cannot prove is not its own. (#831)
  • Six database migrations (0147 to 0152), applied on the next start. Five add a table or a column. One, 0151, removes agent_jobs.original_task, a column that no code ever wrote, and adds the hand-off note described below.
  • nodal-agents up --detach keeps the database running. The embedded database was a child of the launcher and stopped with it, so the runner and the web app went on running against a dead database. It is now started detached from the launcher and outlives it; nodal-agents down stops it. If the database package ever stops starting the database the way Nodal expects, a detached start fails with EMBEDDED_POSTGRES_SPAWN_NOT_DETACHED rather than looking healthy, and that package is now pinned to one exact version so a new release of it cannot slip in unnoticed. A foreground up is unchanged: Ctrl+C still stops everything. (#835, #856)

The Windows sandbox

  • Commands run in a Microsoft MXC container, one per job. The first command of a job opens it (about half a second); the next ones add around ten milliseconds. The network works through a filter Nodal holds on your machine: the internet and third-party local services such as ComfyUI or Ollama answer over HTTP and HTTPS, and Nodal's own services (the runner, the web app and the database) are refused. Nodal's data folder, with its master key, its settings and its database, cannot be read by a confined command. (#753)
  • It is an optional package. nodal-agents takes nodal-agents-sandbox-windows as an optional dependency. npm installs it on Windows and skips it everywhere else, so Linux and macOS install nothing and compile nothing. The sandbox also downloads, once, the Node 24 build that runs its broker, and checks its SHA-256 at every launch. (#753)
  • When the sandbox is absent, nothing is silent. If the package is missing (SANDBOX_BACKEND_MISSING) or the Windows build is not supported (SANDBOX_PLATFORM_UNSUPPORTED; only machines with the base-container isolation are accepted), commands run as they did before, and every result says so with sandbox: { confined: false, code }. The runner logs one [sandbox] line at start. If the sandbox is available but a container cannot start, the command is refused (SANDBOX_START_FAILED); it never runs outside the fence in its place. (#753)
  • Known limit: the sandbox confines on Windows only. On macOS and Linux, commands run unconfined in 0.9.8, as they did before. The runner logs [sandbox] SANDBOX_UNAVAILABLE at start, with the code SANDBOX_NOT_IMPLEMENTED, and every command result says sandbox: { confined: false, code: "SANDBOX_NOT_IMPLEMENTED" }. The macOS and Linux backends come in 0.9.9. (#753)
  • Named limits. A non-HTTP client (raw TCP) has no route to a local service. A server one job starts on 127.0.0.1 is reachable by a command of another job through the filter, since the machine's loopback is shared. A folder created in Nodal's data folder while a container runs is refused only at the next open. (#753)

A job owns every process it starts

  • Stop and the end of a job kill everything the job started, on Windows, macOS and Linux, with or without the sandbox: shell commands, skill scripts, proof commands, code_task, the CLI runtimes (Claude Code, Codex) and stdio MCP servers. A process that detached itself from its parent (start /b, setsid, a double fork) is killed too. What a command leaves running stays alive for the next commands of the same job and dies with the job. (#834)
  • Stop reaches a proof command and a code_task at once, where it used to wait for their own timeout, up to 10 minutes and an hour. A job whose runner died is cleaned up by the runner that reclaims it. (#834)
  • A process Nodal could not kill is logged as JOB_PROCESS_KILL_FAILED, with its pid and how it was tried. On Windows the job's processes are held by a Job Object, made through koffi, an optional dependency; without it a command is refused (JOB_OBJECT_FAILED) rather than run outside its job. (#834)
  • An MCP server started through npx or uvx ends with its job. Only the direct child used to. (#834)
  • Stopping a command never ends an unrelated program. On Windows, a process number is handed to a new process within seconds of its holder exiting. Stopping a command that has already exited, or whose host process has died, now sends nothing, where it could end whatever program had taken the number. (#857)

down and reset

  • nodal-agents down stops runner, web and database right after a fresh up. It used to refuse (KILL_REFUSED code=IDENTITY_NOT_RECORDED), because the identity of a started process was written only after the health checks, and it never stopped Postgres at all: the stop it used did nothing from another process. The identity is now recorded the moment a service starts, and Postgres is stopped with pg_ctl. (#831)
  • It never signals a process it cannot prove is its own. A refused service is named, with a command to look at it and, for Postgres, the exact pg_ctl command to stop it yourself if you recognise it. down ends with a list of what is still running, never "Nodal-Agents stopped", and exits 1. Scripts that call down and read its exit code will see 1 in that case. (#831)
  • reset decides from the reason. It blocks, with the commands, when a service of the install may still be running or cannot be confirmed (macOS has no proof yet). It goes on past a Postgres a reading proved is not its own, and never touches it. It sets the whole home folder aside in one rename before deleting it, so a file held by an antivirus can no longer leave a half-deleted home; if the old folder cannot be fully deleted, it names it and exits 1. (#831)

Agents and what they see

  • The chat front hands your request on as you wrote it. A worker used to receive what the front retyped, and an addition of the front's could pass for your request. The task is now your own message; what the front adds is a separate note, labelled "Agent's note" on the run page. A dashboard worker also gets the earlier turns of the conversation, as channel workers always did. (#808)
  • What you write on any card of a run reaches its head. Your note when you reject an approval, your answer to a question, your reply to an MCP form: the agent running your request receives it, not only the agent that held the card. If the head has already finished, you are told where you answered. (#799)
  • An agent whose model sees can look at the images it can read. file_read returns an image file to the model, and so do images in an MCP tool's result, within the limits of the request. A model that cannot see is told why, and never receives bytes. The team block now states facts, not a capability the model alone seemed to promise. (#798)
  • Approval cards keep one order when several are created in the same millisecond, instead of swapping between refreshes. (#803)
  • The print skill follows your settings. An agent prints with the print tool your settings allow, the preview or the direct one, and when one is refused it tries the other before giving up. It never says it printed before the tool says the job was accepted. (#768)
  • Claude Code and code_task with Claude load only your settings, never the .claude settings of the folder they run in. A workspace's CLAUDE.md files (root to the working folder, imports kept inside the folder) are read by Nodal and handed to Claude as text. (#782, #788)
  • NODALAI_HOME sets the folder Nodal keeps its data in, in place of ~/.nodalai. Two installs side by side no longer share a configuration, a master key or a database. A relative or empty value is refused at start. (#787)

Security and dependencies

  • HTTP MCP servers no longer follow cross-origin redirects, and the stdio message size is capped at 100 MiB (MCP_STDIO_MAX_MESSAGE_BYTES changes it). An HTTP MCP server that redirects to another origin now fails to connect with a message naming the redirect; it used to be followed, credentials included. This is the MCP SDK 1.32, which fixes GHSA-6prh-2h8m-c8cw and GHSA-22jm-h49p-29qw. (#848)
  • undici 7.30.1, discord.js 14.27 and zod 4.6 carry the fixes for the Snyk advisories open on them. The Discord channel can take an optional apiBaseUrl for a Discord-compatible proxy. (#818, #819, #741)
  • A .gitignore planted as a dangling link can no longer make the web app write outside a project on Windows. The file is created in a way no link can redirect. (#763)

Under the hood

  • What each tool call read and wrote is recorded, with the real path and a hash of the bytes: tables tool_call_reads and tool_call_writes. Deliverable checks can then say who wrote a file. Nothing in the dashboard shows them yet. (#780, #783)
  • Creating a stdio MCP server never reports success when nothing was saved. From the Connectors screen, from the catalog and from create_mcp, an insert that returns no row is now an error, where it used to look like a success that attached nothing. (#855)
  • The build and its checks. The pack smoke test and the Windows tests got several reliability fixes, a Windows test run that loses a worker now says which file never reported, a CI check refuses a private name in what a push, a pull request or the pack adds, and tests that waited on a real npx no longer do. (#772, #800, #809, #811, #813, #833, #838, #847, #850, #854, #857)
  • Everything from 0.9.7 is included: Nodal installs without git, the database starts with an old Visual C++ runtime, and WhatsApp pairing shows its QR code. (#766)

v0.9.7 — Oct 16, 2026

A hotfix: 0.9.6 could not be installed on a machine without git, its database could crash on first start on Windows, and WhatsApp pairing never showed a QR code.

Upgrading: what changes for you

  • Nodal installs without git again. On 0.9.6, npm install -g nodal-agents stopped with npm error syscall spawn git wherever git was not installed. A library behind the WhatsApp channel was fetched from a git repository. It now ships inside the app, and npm no longer fetches it.
  • npm 11.6 or newer is needed. Since a package was published upstream on 15 October 2026, older npm versions crash during the install with Cannot read properties of null (reading 'edgesOut'). This hits 0.9.6 as well. Node 22, and Node 24 up to 24.7, ship such an npm: run npm install -g npm@latest first.
  • The database starts on Windows machines with an old Visual C++ runtime. On 0.9.6, nodal-agents up could stop with Postgres init script failed … terminated by exception 0xC0000005: the database needs the Visual C++ runtime 14.40 or newer, and Windows had an older one. Nodal now carries Microsoft's runtime and places it next to the database, so there is nothing to install. If it cannot, and the system's runtime is too old, up stops with VC_RUNTIME_OUTDATED and the link to Microsoft's installer.
  • No install script to approve. Recent npm versions skip install scripts until you approve them (npm warn allow-scripts). Nodal needs none: on Linux and macOS, nodal-agents up now creates the database's library links that the skipped script would have created, and stops with HYDRATION_FAILED if it cannot. The npm approve-scripts step in the docs is gone.
  • WhatsApp pairing shows its QR code. The dashboard asked the runner on a path it does not serve, and WhatsApp refused the version the library announced (405 Connection Failure). The socket now announces the current WhatsApp Web version. When that version cannot be fetched, pairing stops with whatsapp_version_unavailable instead of trying a version WhatsApp refuses.

Under the hood

  • The pack no longer lists @whiskeysockets/baileys as an npm dependency. The runner bundle already carried it, and the dashboard loads it only when a WhatsApp socket opens, which it never does. If the library is missing where a socket opens, the error is coded whatsapp_library_unavailable.
  • pino is declared in the pack. The dashboard needs it, and it only resolved because baileys brought it in.
  • The pack smoke test (CI and release:check) installs the tarball with git unavailable to npm and boots that install. It also refuses a dependency resolved through git anywhere in the installed tree. CI runs it with the npm of the current Node 24 LTS and with npm latest, and checks the 11.6.0 floor.
  • A test checks that every runner route the dashboard calls is one the runner serves.

v0.9.6 — Oct 14, 2026

A release about trust in what your agents do on their own. Connector operations that send, share, delete or run something now ask you first, by default. An agent no longer redoes an action it has already done. The shell check reads more of what a command really does, including the script it runs. Fonts ship with the app. Twenty-three pull requests, no database migration.

Upgrading: what changes for you

  • 26 connector operations now ask for approval by default. Sending, replying to or forwarding an email (Gmail and Outlook), deleting, archiving, sharing a Drive file, running an Apify actor and deploying a Cloudflare site. The Approvals tab shows "ask" for each of them. They run without asking only under full autonomy, with an "Always allow" rule, or in Yolo. Under "ask only for destructive actions", they ask too, except the site deploy, which is not destructive. (#738, #745)
  • An agent no longer redoes an action already done after a re-check or a repair. A message it sent, a post, a print or a delegation counts as done. (#740)
  • A Markdown deliverable without a # title is no longer refused. Nothing else about Markdown is checked, as for a .txt file. (#737)
  • Fonts are self-hosted. The app and the docs no longer fetch Google Fonts when they build or start, so they work offline and a font outage can no longer break a build. (#713)
  • The shell asks in more cases under the default policy. Opening a program, printing or sending a message from a command has its own row in the shell checklist, "Open programs, print or send", set to ask. This includes agents whose shell kinds were all set to allow before this release. Deleting with erase or ri, installing with msiexec, dpkg or snap, and a script whose lines delete or install also ask now. (#682, #683, #710)
  • An allowed kind asks when the command does not say what it acts on. Agents whose shell kinds are set to allow ask a little more, and only in those cases. (#730)
  • No database migration. Nothing to apply on upgrade.

Connectors that ask before they act

  • One descriptor decides a connector tool's risk and whether it asks. There is no per-adapter list any more, so a tool can no longer disagree with what the Connectors tab shows. A tool with no descriptor fails loudly. (#738)
  • Replying to or forwarding an email asks, as sending does, on Gmail and Outlook. (#738)
  • Sharing a Drive file and running an Apify actor ask. Sharing can notify someone or make a file public. An actor is an arbitrary program. Searches and scrapes that send nothing outside do not ask. (#745)
  • The Approvals tab shows the real default. A connector row no longer reads "Run without asking" when the operation asks. (#738)

Agents that do not repeat themselves

  • The re-check of a reply sees what the run already did. It reads a record of every tool call since your request, with its outcome, before judging whether the reply promised something. (#740)
  • The repair turn repairs the deliverable and nothing else. It no longer says "deliver again", and it tells the agent how many repair turns remain. (#740)
  • A review verdict reaches the agent that asked for it, through any number of delegations, and a task that delivered only a verdict is no longer shown as "no result". (#712)
  • When Nodal knows a model's output limit and the request leaves room for it, the request states it, and a turn that reaches it is refused even when the provider does not say it was cut. (#571)

Shell commands read for what they do

  • A command that runs a script is judged by the script. A Python file that runs pip install now asks, as the same command typed in the shell would. (#683)
  • Opening a program, printing and sending mail from the shell ask first. The agent is told to use a tool that asks you, when it has one. (#682)
  • One delete list and one table of installers per system. erase, ri, rsync --delete, package managers whose verb is an option, and removals and upgrades are covered. (#710)
  • PowerShell parameters are read the way PowerShell binds them: shortened names, values after a colon, any dash. Remove-Item -Recurse -Fo is no longer missed. (#709)
  • A folder change made by a child process no longer moves the command line, and a script in the same process leaves the line where it ends. (#721)
  • A device such as /dev/null is never read as a place, and a path is never cut inside a word. (#681)

The web app

  • The "+" next to Projects in the sidebar opens the project creation window in place, on any page. (#700)
  • A "New Chat" row opens the list of Nodal chats. It leads to the empty conversation screen. (#702)
  • Five new OpenRouter models: Claude Sonnet 5.5, Claude Haiku 5.5, Mistral Large 4, Qwen 3.8 Max Prime and Qwen 3.8 Flash, with Mistral models grouped under "Mistral". (#707)

Build and quality

  • The web build no longer walks your home folder. It needed about 24 GB of memory and 16 minutes on Windows. It now stays near 3 GB. (#680)
  • A failing test run can no longer exit green on Linux CI. (#699)
  • Two flaky tests are fixed: the embedded Postgres log and a prompt check that matched random digits. A read of the chat id that nothing paired is removed from the approval path. (#679, #684, #696)
  • The review rules are written down: an important finding is fixed then reviewed again, minor ones go to a backlog, and a platform card keeps its fixed frame. (#677)

v0.9.5 — Oct 5, 2026

A release about the MCP servers you connect, and about conversations that keep up with you. An MCP server can now ask you a question in the middle of a call, on the web or on the Telegram, Slack or Discord conversation where you made the request, and gets your filled form back. Its instructions reach the agent that holds its tools, and the agent reads every block of its results. A print request is answered with a print preview you approve. A message you send while the work runs is never left unanswered. An agent saves new files in its own folder without asking where. Nineteen pull requests, seven migrations (0140 to 0146).

Upgrading: what changes for you

  • Each MCP server is connected once on the first job after the upgrade, to read the instructions it publishes. Later jobs connect it only when one of its tools is called, as before.
  • An agent no longer holds two MCP servers whose tool names overlap. Attaching the second one is refused, with a message naming both and the way out. A new server's short name follows one grammar: lowercase letters and digits, single hyphens. An existing pair keeps working as long as its servers lend different tools.
  • An MCP tool's description reaches the model whole, up to 50,000 characters. MCP_DESCRIPTION_CHAR_CAP no longer exists.
  • An agent asks no more where to save a document: new files go in the job's folder, else its own folder, and it says where it put them.
  • Time spent waiting for your answer to an approval or to a server's question no longer counts toward a run's time budget.

Questions from MCP servers

  • An MCP server can ask you a question during a call: a form (choices, numbers, switches, text) with images if it joins some, such as a print preview. The run keeps going while you think, and the server gets exactly what you filled in. (#660)
  • The question comes where you made the request: in the run, on the Approvals page and in the bell for a request made on the web, or as a card to fill in place on Telegram, Slack and Discord. Each button sets one value, and you type a number or a text in reply to the card. The accept button carries the server's own label, such as "Print". (#664)
  • A question that cannot be answered says why: no answer in time, the run stopped, or the server withdrew it. A form too large for the channel, or an image that could not be sent, points to the dashboard with the reason. (#660, #664)
  • A server's words stay in their frame on every channel: quoted line by line, never formatted, and they notify nobody. (#664)

MCP servers your agents understand

  • A server's instructions reach the agent that holds its tools, framed as third-party guidance, capped, and refreshed at every connection. (#659)
  • The agent reads every block a server returns, in order, and the run's log keeps the whole result, including when the call fails. (#665)
  • One tool name designates one server inside a job. (#663)

Printing

  • A print request is answered with a print preview you approve, laid out by the agent you asked, inside the printable area your print server reports, on the number of pages you asked for. A new magazine page skill gives a proven one-page or several-page layout. Both are system skills. (#670)
  • A tool call without a name no longer kills a job: the request leaves without it, and the agent is told to call a tool by its exact name. (#670)

Conversations that keep up

  • A message sent while the work runs is answered, on every channel and on the web. The agent can pass your words to the running work, or stop and restart it. It is never assumed to be about that work. (#642, #651)
  • A request's answer goes back where it came from. A request made through MCP is answered by its result, never by your Telegram. (#657)
  • An approval card follows its request on every channel, whatever settles it: an answer elsewhere, expiry, a cancelled run. (#639)
  • A replayed conversation turn carries its date, on every channel and on the web. (#652)

Agents and teams

  • An orchestrator holds the tools you switched on for it. The root's tool groups (spreadsheet, documents, shell…) were dead on orchestrators, and now work. (#641)
  • An agent reuses workflows, scripts and templates, never a past request's deliverable, and its prompt names folders instead of past files. (#640, #658)
  • The team roster says what each teammate's connectors and MCP servers do, and an assign_* tool names its teammate. (#653, #655)
  • The baseline every job carries says each rule once, for every model, in under 5,000 characters. (#656)
  • The shell gate never reads /dev/null as a place, and a command whose starting folder does not resolve goes back to the agent instead of asking you. (#670)

Quality

  • The QA portal shows every test by part of the product, with the last five runs. (#633)
  • A workflow bench replays the same everyday requests on the real stack, judged on facts, nightly and across versions. (#634)

v0.9.4 — Sep 30, 2026

A release about runs that finish, and finish when you say so. It closes the incident of 28/09, where a Telegram request was relaunched thirty times and Stop did nothing: a job now acts only while its row authorizes it, /stop from any channel ends every run of the conversation without asking a model, and the model is never forced to call a tool. LLM calls no longer share one HTTP/2 connection, the cause of calls that took minutes inside the runner and seconds outside it. A job's prompt is lighter: it names only the tools the job holds and reads their full schemas when it needs them. An autonomous agent downloads into its workspace and runs code without asking. Sixty-eight pull requests, ten migrations (0129 to 0138).

Upgrading: what changes for you

  • Agents with no shell checklist of their own now download and run inline code without asking: downloading into their workspace and running code written in the command or in a script. Deleting files, installing software, stopping programs, system settings and downloading outside the workspace still ask. An agent whose checklist you set keeps it unchanged. The reading of a command is a net, not a wall (see the Shell commands doc).
  • "Start with this machine" (Settings) replaces the scheduled task of earlier installs on Windows: the task is removed when you turn the setting on or off. If Windows refuses (a task created as administrator), the message gives the exact command.
  • A provider call that brings no deadline of its own stops after 300 s of waiting for its headers or of silence in its body, never on a total. Override with NODAL_PROVIDER_CALL_TIMEOUT_MS.

Runs that stop

  • A job acts, on every runtime, only while its row authorizes it: no zombie after a reap, a stop or a re-claim, and a stop from the conversation reaches every run. (#575)
  • /stop from any channel ends every run of the conversation, without asking a model. (#605)
  • A job held by a live runner beats from its claim until it lets go: no reaper fails it mid-run. (#569)
  • A job survives a runner restart and resumes at its last saved turn, when nothing but reads ran since. (#547)
  • The run page shows the call in progress, and Stop keeps the partial as the result. A streamed call says what it is producing while it produces it. (#624, #623)

Turns that behave

  • The model decides whether to call a tool on every turn, for every model. The forced first-turn tool call is gone; it was what made some models loop through hundreds of calls. A turn that ends in prose announcing an action is re-read once. (#604)
  • A turn with more tool calls than the per-turn budget is refused whole, and a turn cut on the output-token cap is refused: none of their calls runs. (#568, #555)
  • Every tool_use leaves with its tool_result, whatever the exit; the unavailable-tool budget counts turns, not calls. (#577, #573)
  • Replayed history never puts runner-written lines in the agent's mouth. (#576)
  • LLM calls never share a connection, and an abandoned call releases its response. (#609)
  • A hosted model waits the hidden-thinking floor for its first token, at any effort. (#585)

Lighter prompts

  • A job reads the schemas it needs and keeps its whole whitelist callable: common tools are sent in full, the others are listed and loaded on demand. (#616)
  • A job's prompt names only the tools that job holds. (#570)
  • A channel job's prompt states its channel's facts from the adapter, and no rule the runner contradicts. (#615)

Delegation

  • An explicit request for a teammate's specialty goes to that teammate; a question that only wants an answer stays with the agent asked. (#603)
  • A question about Nodal is answered by the agent it was asked of, on every surface and runtime. (#455, #544)
  • A failed delegation gets one targeted retry of the same agent, another agent only when its roster shows the means. (#543)
  • A working folder attached to a request travels down the whole delegation tree. (#546)
  • assign_ and create_task hand work to the same agents*, within the delegation depth left. (#545)
  • A stopped child hands its parent what it wrote, and a file a delegate wrote is its root's to deliver. (#535, #589)
  • Each agent's entry in the team block shows its folders, runtime and shell as its run gets them. (#536)
  • While this conversation's work is still running, run_task is refused and the model is shown that work. (#541)

Shell, files and proof

  • A command is filed by what it does: fetching files is a download, not a software install. (#582, #552)
  • The Claude Code runtime's shell follows one owner setting and the brake, on every CLI path. (#551)
  • A file the agent declares as delivered is proven before the run can succeed. (#523)
  • A shell write is constated in a workspace no git repo covers, against its checkpoint snapshot. (#591)
  • A file this run wrote in a shared folder is re-written without asking; anything else still asks. (#533)
  • A call the owner rejected in this run is answered from that decision while nothing has changed. (#530)
  • Every tool that starts a process says how it addresses files. (#593, #595)

Screens

  • Questions are answered inline, and "Something else" sends the typed text as the answer. (#622)
  • A run opens in the section it belongs to. (#621)
  • The Delivered card's cost is the cost of the whole tree. (#620)
  • MCP server: Settings sets up Claude Code and Claude Desktop at once, with the command of this install. (#625, #520, #521)
  • Settings: Start Nodal when this machine starts, without admin rights on Windows. (#627)
  • Skills catalog: Comfy's official skills replace the ComfyUI port and keep their official name once installed; a skill whose name is in the workspace shows as installed. (#548)
  • Every Copy button works over http on a LAN IP. (#550)
  • Every agent is told which Nodal-Agents version it runs. (#539, #542)

Quality

  • release:check names what failed and keeps the full output. CI steps are bounded from their measured duration. Tables share one cell vocabulary. Timing-sensitive tests no longer depend on the machine's load. (#519, #557, #526, #525, #599, #598, #597, #587)

v0.9.3 — Sep 25, 2026

A release about long runs and about who decides. A turn no longer dies on a 300 s wall clock: it streams under two silence clocks, resumes from what it had written, and Stop really stops it, in a job as in the chat. What a run may cost and how long it may work is now set by the workspace, and each agent has its own budget, API providers and coding CLIs counted together; a run stopped by a budget delivers what it wrote instead of losing it. A shell command is judged per kind of action, and the owner answers an approval without leaving the conversation. Agents can also write audio files from text, and the Delivered card now shows, plays and downloads a delivered image, track or video. Twenty pull requests, six migrations (0123 to 0128).

Upgrading: what changes for you

  • MAX_COST_PER_JOB_USD is no longer read. The ceiling of one run lives in Settings, Safety, Run budget (default $2, the value the runner applied until now; 0 means none). A runner that still has the variable logs max_cost_env_ignored.
  • The coding-CLI daily budget becomes the agent's daily budget, and only for agents it applied to (CLI runtime or code-task tool). It now also counts the agent's API calls. Agents on the Codex runtime were exempt before and now get an active ceiling ($10 a day by default): check their Settings, Budget.
  • "Run commands" is no longer a Yolo switch. It has the three choices of every other tool (run without asking, ask, block), and each agent has a shell checklist per kind of action. Agents that were on Yolo keep running every kind without asking (migration 0125).

Long runs

  • A turn streams under two silence clocks instead of one 300 s wall clock: the wait for the first token (120 s, longer on a large context or a high reasoning effort) and the silence between tokens (60 s). Reasoning counts as activity; a local endpoint has neither clock. A turn cut mid-writing resumes from its partial text instead of being replayed identically. (#449)
  • Stop stops. In the chat, Send becomes Stop while the agent answers, and Stop ends the answer, including on the Claude Code and Codex runtimes. (#459)
  • Chat replies run under the same clocks as a job turn and leave their llm_calls row, so a long reply is observed and a mute one ends. (#466)
  • A page opened while the agent is answering shows the answer as it is written, instead of hiding it until it is finished. (#502)
  • An error the provider sends as a plain object keeps its message and code: it is retried when it should be, and never said as "[object Object]". (#479)

Budgets

  • The workspace sets what a run may cost and how long it may work (Settings, Safety, Run budget). A stop on a budget delivers what the run wrote, then a line saying why it stopped. An agent can set its own wait for the first word. (#495)
  • One budget per agent, daily and monthly, in the agent's Settings, with a warning threshold. API providers and coding CLIs are counted together, in the workspace time zone. (#496)

Control

  • A shell command is judged per kind of action read from the programs it runs: inline code, deleting files, installing software, downloading, stopping programs, system settings. Each kind is allowed, asked or never, per agent. It is a reading of the command, not a sandbox: it does not follow what a script does once it runs. (#476, #497)
  • "Run commands" has the three choices of every other tool. (#481)
  • A pending approval is answered in the conversation, with the same card as the Approvals page. (#482)
  • "Never for this agent" on an approval card refuses the call and sets that kind of action to Never, once confirmed. (#486)

Files and media

  • Agents write audio files from text with the new generate_speech tool (Gemini 3.8 Flash TTS and Flash Lite TTS through OpenRouter, WAV output). It is switched on per agent in the Tools tab and uses the workspace OpenRouter key. The delivery proof reads a WAV by its header. (#488, #489)
  • The Delivered card shows, plays and downloads a delivered image, audio or video file. The file is served only if that run wrote it, inside the workspace folders, from a closed list of types. (#493)
  • Choosing a folder in Browse… adds it to the agent at once; no second Add click. (#467)
  • A run opened from the MCP folder keeps the sidebar on Work. (#500)

Under the hood

  • The .pg test files share one Postgres per run, one fresh database each, so the full suite no longer fails at random. (#499)
  • A test that compared a Windows short path with a real path is fixed; the Windows CI is green again. (#503)
  • A shared link to the docs site shows a preview image. (#460)

v0.9.2 — Sep 23, 2026

A release about saying the right thing. A run whose agent answered through Telegram and acknowledged with a status showed, under its own header, a delegation line replayed from a turn of a week earlier: the page repeated the last thing said in the transcript instead of the answer that was delivered. Both halves of that are fixed, in the runner and on the page. The model catalogue catches up with what OpenRouter actually serves, fourteen models in and three dead identifiers out of the picker; an agent already set to one of those three keeps getting a 404 until its owner picks a model that is served. And the documentation now says the words a person types, which is what the in-product search scores on. Fourteen pull requests, one migration (0122_entities_drop_memory_curation_enabled).

Models

  • Fourteen models join the OpenRouter catalogue. Xiaomi MiMo V2.6 Flash, Pro and Pro UltraSpeed, GLM 5.3 FlashX, Grok 4.6 and 4.7, DeepSeek V4 Pro and V4.1 Flash, GPT-5.6 Sol, Sol Pro and Terra, GPT-6 Astra and Astra Pro, and Claude Fable 5.1. Every window, price, modality and capability is read off OpenRouter's own API rather than typed, and each entry says in a comment which call answered it. (#413, #430)
  • Three Anthropic identifiers OpenRouter does not serve leave the catalogue. claude-opus-4.7-fast, 4.8-fast and 5-fast were offered in the picker and returned a 404 to any agent set to one: OpenRouter lists none of them and serves no endpoint for them. The three choices are gone from the picker; an agent already set to one still gets a 404 until its owner chooses a model that is served. Their non-fast siblings stay, and a test pins both facts. (#429)

Runs and pages

  • A run's result comes from its own turn. A turn that answers through a messaging tool and acknowledges with a status writes no text of its own, and the reader that fills an empty result took the last assistant text in the transcript, which starts with the replayed thread history. Since 15 September a Telegram turn of that shape could inherit an older delegation ledger line as its result. Both readers now work on the slice of the transcript that belongs to the current turn. (#427)
  • The run page reads the delivered result, not the last announcement. The page was never given the result to read, so it fell back to the last prose of the run. On a run that published its answer and then said "I'm posting it now", the reply is what reads under the header and the announcement stays in the activity. (#431)
  • The Memory page says what its agent chips do: Written by. The row filters by the agent that wrote the fact, and read as an assignment. The default chip says Anyone. (#428)
  • History group headers and project shelf rows use the tighter spacing they were designed with. 8px of vertical padding instead of 12; the base padding used to override what each row asked for. (#433)

Files and projects

  • The first manifest of a new repository makes it a code project. Writing a package.json into an empty folder left it classified as a plain folder until something else was written, because only the folder's existing contents were read. The file being written is now read too. (#435)
  • The workspace probe and the checkpoints resolve git before spawning it. Two callers still launched git by its bare name over a folder agents write in. Both resolve the binary the way the rest of the product already does. With no git on the machine, the probe declines and renders nothing, and the snapshot store fails loud with the message the owner already saw. (#436)

Documentation and site

  • The documentation says the words a person types. The in-product nodal_docs tool scores on the vocabulary of the pages themselves, so "remember something for later" and "how do I approve a command" reached the wrong page or none. The memory concept page, the shell-commands guide and the dashboard reference now carry those phrasings in their own headings and leads, rather than a synonym list hidden in the tool. (#437)
  • The changelog page of the site is this file. It was a hand-kept copy that stopped at 0.9.0 while the repository carried 0.9.1, because a release had to write the same entries twice. The page is now generated from CHANGELOG.md before every docs build, like the reference pages. (#432)

Upgrade

  • One migration, 0122_entities_drop_memory_curation_enabled. The memory curator loses a per-workspace switch no screen ever exposed; the global kill-switch and the per-fact pin remain the two ways to hold it back. nodal-agents update applies it, and there is nothing to do by hand. (#418)

Under the hood

  • Two end-to-end assertions catch up with decisions already shipped, and the documentation site is measured like every other package. (#407, #408)

v0.9.1 — Sep 21, 2026

A release about the product knowing itself. Asked on a fresh install whether Telegram could be configured, the agent answered that Telegram was not supported and offered to build an MCP server, while Telegram ships with its own tab in that agent's settings. The documentation is now a knowledge base every agent can read, with the reflex to read it before calling anything impossible, and the prompt names the four messaging channels and the two kinds of automation.

The rest is about seeing what is happening and being able to stop it. A Stop button sits on the three screens where a person actually watches a run, the rail carries a dot while something is live, a delivered file waiting for an eye is counted in the attention pill, and a command that left nothing observable is said rather than passed over in silence. Settings shows what a workspace weighs and how long its last safety snapshot took, before a refusal rather than after, and the launcher refuses to serve a database a migration was skipped on and can repair it. Twenty-one pull requests, two migrations (0118_agent_jobs_deliverable_check_due and 0119_job_checkpoints_snapshot_ms).

A release about approvals, and about what the product says of its own work. On 21 September an owner answered "Always for this server" and the tool kept asking, because a narrower rule was deciding without any screen saying so. The approval card now shows the rules that decided, in the order the gate reads them, and they are changed right there. A request with no stated reason is not posed at all. A rule written during a run applies to the run it was answered on. A request nobody answers expires, and its job goes back to work. And a red proof reopens the run for one repair turn instead of ending on a failure nobody could act on.

Later the same day, thirty-eight more pull requests and two migrations, in the same release.

Approvals

  • An approval request with no stated reason is not posed at all. (#359)
  • The approval card shows the rules that decided, and lets you change them there. (#360)
  • An approval card opens when it waits, and folds away once decided. (#365)
  • The approval shield is warn coloured, and one caret folds the whole card. (#368)
  • An approval rule written mid-run applies to the run it was answered on. (#374)
  • The approval card has two states, Open and Close, and nothing between. (#381)
  • An unanswered approval request expires, and its job goes back to work. (#384)
  • The Approvals tab speaks to the owner, not to the model. (#387)
  • A rule confined to a folder says which folder, and says what saving costs. (#390)
  • A rule can be set on one tool of an MCP server, not only on the whole server. (#393)
  • Trusting an MCP server says what it costs a folder-confined rule. (#403)
  • Answering an approval clears the rail's count at once. (#339)
  • The Approvals page follows the bar instead of going stale. (#348)

Delivery inset

  • Stop where the person looks, a delivery inset that says Stopped, and no Open run to the page you are on. (#335)
  • Working in the running colour while the job runs, and Stop at the top right of the box. (#337)
  • Checks are counted while the run works, "no file change seen", and Open run is a button on the right. (#342)
  • Each command in the delivery inset says why it ran. (#376)
  • The delivery inset shows the diff of each created or modified file. (#380)
  • The proof verdict is a word, not the colour of the check mark. (#383)
  • The delivery inset says the proof passed after a repair, and counts the last try only. (#389)
  • The file diff plates in the delivery inset run edge to edge. (#396)
  • The "+N -M" of a file counts the diff the plaque draws, from one engine. (#397)
  • Every command in the delivery inset says how it ended. (#398)

Runs and proof

  • A red proof reopens the run for one repair turn before it completes. (#379)
  • The repair turns after a failed proof are a workspace setting, next to what else bounds a run. (#392)

Projects

  • The Projects page is called Projects, and a removed project is not on it. (#367)
  • A hidden project can be forgotten, and its folder stays where it is. (#378)
  • A forgotten project stays forgotten: its folder is excluded from detection. (#388)

Sidebar and rail

  • The reading density toggle is gone: a thread opens folded, a run page opens unfolded. (#341)
  • The rail's live dot moves to the right edge, beside the count. (#345)
  • The Logs cell carries no live dot, and the count behind it goes too. (#351)
  • No numbered badge on a channel folder. (#353)
  • The unread dot takes the colour of activity, and red keeps what must be answered. (#355)
  • The rail says Scheduled and Runs, with the icons the owner drew. (#400)

Quality portal

  • The jobs in flight are cards in a Running column, not a strip. (#343)
  • The Running column reads GitHub in the browser, not at build time. (#366)

Site

  • Homepage: the hero's nav and column sit in the page container, only the picture bleeds. (#334)
  • Homepage: the hero on the design's width with three pillars, a titled screens band, and one claim style on every section. (#336)

Upgrade

  • Two migrations, 0120_excluded_project_paths and 0121_entities_proof_repair_attempts. nodal-agents update applies them, and there is nothing to do by hand.

The agent knows the platform it runs in

  • The documentation ships with the product, and a tool reads it. nodal_docs answers a question with the two or three sections of the manual that address it, each with its page, its heading and a link. The index is built from the committed pages and travels inside the package next to the migrations, so a fresh clone answers without building anything first. The match is lexical, offline and deterministic, because this runs inside a model turn. The Telegram guide is corrected on the way: the bot token goes on the Channels tab, and the page that could not say where to click was the one the question was about. (#319)
  • The reflex to consult it, and channels and automations in the prompt. A baseline skill, platform-support, tells an agent that it runs inside Nodal-Agents and to read the documentation before declaring anything unsupported, impossible or in need of being built. It is injected only when the agent actually holds the tool it names, and it fails closed. The discoverability block now lists the messaging channels the agent is not yet bound to and the two kinds of automation, so "I cannot run on a schedule" stops being the answer to a question that has a screen behind it. An existing install needs nothing but a restart. (#329)

Watching a run, and stopping it

  • A Stop button where a person watches a run. Cancelling used to mean finding /jobs/[id], which is not where anyone watches work. One button now sits on the run page, on the thread while a turn is running and on a code session. It confirms in the product's own dialog and says what stopping means rather than promising a kill: the run and everything it delegated stop at the next check, and a model call already in flight finishes on its own. (#325)
  • The rail says what is running. Logs carries a beating dot while any run is live, Work carries one while any conversation it lists is live, and the cell's name carries the count for a reader who does not see colour. Both read the snapshot the sidebar already polls, on its own cadence: no second query, and no second truth. (#314)
  • A deliverable waiting for a look is counted in the attention pill. The pill counted an approval pending and a question asked, and stopped there, because no column said that a deliverable awaited a human eye. One does now, written by the runner in the same transaction as the terminal status, so a crash cannot leave a run that delivered with nothing saying so. The wait is carried by the head of the chain, the run a person opens, and only opening that run or its thread clears it: a message that left on Telegram made nobody look at anything. Migration 0118. (#317)
  • A command nobody saw is said. A turn whose only action was a shell command with no constated write rendered nothing at all: no delivery inset, because it is not work, and no note, because nothing was unclassified. The inset now follows that turn too, names the command and marks it nothing observed, and its header reads Ran instead of Delivered. Not "did nothing": what is missing is the observation, and the wording says that. (#327)

The product carries its own marks

  • One logo, everywhere. The collie on the N replaces the letter tile of the rail and the mobile bar, the diamond of the first-run screen, and the terminal prompt on the login page, which told a person arriving at the product that it was a command-line tool. Three marks for one product became one, drawn by one component from one file, and the browser tab points at that same file. (#322)
  • An empty section never ends with "See all", and PROJECTS gets a "+". "No Project Yet" followed by "See all" announced seeing all of nothing. The row is dropped only when the read answered that there are no rows; loading and a failed read keep it, which is exactly when opening the page by hand helps. The path to create is the "+" on the section title, the same one CRON and WEBHOOKS carry. (#315)
  • The "+" on CRON and WEBHOOKS opens the creation form. It pointed at the page one was already looking at, so the click changed nothing. It now says which form to open, the page opens it on arrival, and closing the form drops the parameter so a reload does not reopen it. (#302)
  • A row folds when it is narrow. In the "Skills attached" grid of an agent's Overview tab, a two-word name overflowed its column and drew its second line over the slug and the Open button; the connector rows of the same tab ran into the "on" pill the same way. The rule belongs to the row component rather than to each caller, and a browser journey measures the boxes. (#318)

What the owner sees before a refusal

  • A workspace says what it weighs, and how long its last snapshot took. On the evening of 19 September a shared folder reached 3.3 GB, the safety snapshot blew its budget, every write was refused, and nothing on any screen had said the folder was growing. Both facts now sit under each workspace name in Settings, from the same measure the refusal uses, never a second one. A snapshot that succeeds leaves its duration behind now, which is the case worth seeing coming. A folder that does not exist yet, one that cannot be read and a snapshot that was never timed each get their own sentence instead of a zero. Migration 0119. (#324)
  • The launcher refuses to serve a database a migration was skipped on. Drizzle's migrator compares each entry against the last applied row, so a migration merged after a more recent one is skipped in silence and for good. That is how a table lost a column on 20 September with nothing at boot saying why. At every boot the journal is now read against the applied history: any gap is named, Postgres is stopped, and the refusal carries the exact command to repair. nodal-agents up --repair-migrations applies the missing entries in order, each in its own transaction, and reads the check again rather than assuming it worked. (#323)

The site, and the documentation

  • The homepage opens on a hero band. The illustration fills a full-bleed section, with the version pill, the two-line title, the install terminal and the two buttons held to the left so the picture keeps its right half, and the nav sitting on the illustration as the handed-over design composes it. Every value that design states lands at 1440 and travels by clamp() on other widths. The version on the pill is read from the published package and never typed. The site also took the new logo, and the two product screenshots were retaken on 0.9.0 at the same size. (#305, #307, #309, #320)
  • The documentation is brought back up to the product. It had not moved since 0.8.6, and six releases had landed since. Thirty-one hand-written pages were read sentence by sentence against the code, twenty-seven were corrected, and two concept pages were added for what was documented nowhere: what proves a run, and what a project is. Five reference sections that answered 404 now have an index, written by the generator from its own output, so the list cannot go stale. (#304)

The CI, and the quality portal

  • The CI is split, and a pull request answers in eight minutes. One sequential job needed twenty-three minutes to reach the build and was then cancelled by its own budget on a green tree. It becomes checks, five test shards and a build, each with its own cache lineage and a budget set at twice its measurement, so "the build broke" and "the suite grew" are two different red marks. The Windows job moves to pushes on main and a nightly, having cost twenty-nine minutes on every pull request without ever finding a fault the Linux job had missed. Wall clock, first job started to last job finished: eight minutes twenty. (#312)
  • A deploy of main is never dropped, and the portal says when the site was last deployed. GitHub keeps one pending run per concurrency group, so the deploy of a merge was cancelled by the run of that same pull request closing, and nothing said so. The one gate that could lose a deploy for good is removed, with the reasoning written beside it. The portal now carries a line saying when the site was last deployed, from which commit and by which event, and what happened to the runs since. The commit is named only for a push run, the only event whose recorded head is the commit that was built. (#313, #321)
  • The quality portal shows the jobs in flight. The board is derived from issues and pull requests, so a morning with every issue closed showed nothing while three review passes, six CI watchers and a forty-minute release:check were running. A strip above the Kanban now names each job, where it runs, since when and what it waits for. A source that did not answer says so, and is never rendered as nothing running: an empty strip means the machine is idle only when every source spoke. (#326)

v0.9.0 — Sep 20, 2026

A release about the shape of the product. The sidebar became a rail of the owner's five boards with a panel for the active one, settings became a list where each setting opens beside it, a project opens on its conversations with its folder docked to the right, and the screen the product opens on is now an empty conversation rather than a dashboard. Back links were taken out everywhere, by the owner's decision, because the sidebar already says where you are.

Underneath, a run's delivered files are read from git rather than from what the agent said it wrote, a run records how its own result was produced, a reviewer's own commands are recorded as proof of the work they reviewed, and two guards were added against work the product was paying for twice. Thirty-seven pull requests, seven migrations (0111_agent_may_change_team through 0117_agent_jobs_result_kind).

The sidebar, and the screens it opens onto

  • A rail of five boards, each opening its own panel. The single column of 0.8.11 becomes a rail whose cells are the owner's five boards, Work, Agents, Run, Approvals and Settings, each opening a 300px panel; Logs navigates and Help opens the documentation. The active board is derived from the route and from nothing else, so two tabs on the same address show the same panel and a shared link opens what it promises. The sections that exist only in the database are read through one bounded shared reader on the sidebar's single cadence, and a project in the list says whether it carries an unread conversation. (#235, #279)
  • "See all" outlives an empty list, wherever a section carries it permanently: on a fresh install the workspaces page was reachable from nowhere. And a settings row lights up when its own setting is the one open. The four rows point at one path with different query parameters, so comparing on the path lit all four and comparing on the whole address lit none; the rule reads the path, then every parameter the entry writes. (#279)
  • An inspector docked to the right edge, which pushes the page. DockedPanel is a third pattern next to Drawer and Modal: no backdrop, no trap. The list on its left stays visible and stays clickable, so a reader walks from one row to the next without closing anything. (#233)
  • Settings is one list, and each setting opens in the panel. Eleven stacked blocks become a filterable list in four families, Access, Safety, Workspace and Advanced. Nothing is edited on the page itself. The open setting is carried in the address (/settings?open=network), and Cancel and Save sit at the bottom of the panel without a single form changing its logic. (#237)
  • A new conversation opens a centred empty thread, and that is the default screen. The root route renders a conversation that has not started. No conversation row is written before the first message, and none survives a failed one, so a thread opened and closed without a word no longer sits in the inbox forever. The Dashboard is unchanged and lives at /dashboard. (#250)
  • Back links are removed everywhere. The owner's decision of 2026-09-19: "Remove the back buttons EVERYWHERE." The work bar now carries context and actions only, and you move through the product by the sidebar. (#243)
  • One Switch, one look. The MCP server toggle read as disabled when it was on, because the component owned the geometry and every caller passed its own colours. Two colour languages coexisted; the component owns the look now. (#238)

Work is a folder you open

  • Workspaces is the only projects page. One list, two kinds of row: a registered project, and a folder an agent wrote in that nobody declared, which can be registered or hidden. The row shows the four facts that help you find a project and nothing else. A registered row is dated by the day it entered the registry, not by the day its row happened to be written. (#225)
  • A project opens on its activity, and its folder sits beside it. Opening a project used to land in one conversation and hide every other story, including the runs started from the CLI or from an MCP client. It now opens on one sorted list of conversations and sessions. "Files & proof" stopped being a second screen: it is a docked panel, open by default, and /code goes to Workspaces. (#226)
  • An automation opens on its own page. One route serves a schedule and a webhook alike. Header, settings card of five rows, the last ten runs with their cost over thirty days, and what a routine has remembered. "Scheduled" leaves the menu. (#224)
  • Nodal can initialise git in a project folder. An option, off by default, offered in the New project form and in the project's settings. Nothing touches a folder without it. It exists because the git constat below is the only reading that sees what a command wrote without naming it, and someone who starts a project from Telegram has no repository to read. (#244)

What a run really wrote, and what really proved it

  • A run says how its result was produced. agent_jobs.result held the text a run delivered and nothing on the row said where that text came from, so two screens guessed, each in its own way and each wrong in a case already seen. The runner writes the fact when it writes the text, and both screens read it: a result_kind column with two values and no default, because the terminal gates do not hand over the same kind of text, and a default would have filed an orchestrator's compiled tasks under the same mark as an agent's own words. Migration 0117. (#276)
  • Writes are constated by git when the project is a repository. The runner reads git status --porcelain before a shell command or a harness run and again after it, and the delta is the constat. A run_command that writes ten files without naming one used to produce, for the product, nothing at all. The Files block shows that list, the constat is stored rather than dying with the call, and the per-file label is git's own word, which can say "deleted" where a tool name could not. (#227)
  • A reviewer's verifications are recorded, and the verdict sits next to "Delivered". On one run a reviewer ran six real browser scenarios and verification_runs held zero rows for the job; the only proof kept was the developer's own check that the JavaScript parses. A reviewer's commands now carry over to the work they reviewed. (#228)
  • The failure hint is persisted, so the screen reads the runner's own word. The runner already named the gesture a failure calls for as a typed field, and it died in memory for want of a column. The screen re-derived it from the error code, which worked while the mapping lived in two places. (#272)
  • The thread's tool rows go through the audit-row redaction gate. The run page's rows had gone through it since 0.8.11; the thread masked two fields of three and let the tool input travel raw. The field is masked at the door rather than at the use, so a field added tomorrow is covered without anyone thinking about it. (#270)
  • Every dot in the thread was grey. A server-rendered view read its colour tables from two 'use client' modules, where an export is a client reference and not a value, so the fallback colour took over in silence. The unit tests imported the real modules and rendered green in front of it. (#268)
  • The thread's chat-or-work verdict reads the constated write. A terminal card counted a turn as work by the mere fact of existing. A card proves a command ran, never that it wrote anything, and that was the last place this reader still believed a declaration. It reads the constated rows now, and a command with none no longer decides work on its own. (#283)
  • A review verdict is masked before it reaches a screen. Both readers of the recorded verdict parsed the tool output raw and let the reviewer's own free text travel unmasked onto four screens, while the same secret in the same row was masked everywhere else. A reviewer who quotes a failing command or a config path had put a bearer token on screen in clear. (#289)
  • A refused command names the checkpoint's real cause. A checkpoint that cannot finish still refuses the write, which is the whole contract; what changes is what it tells the reader. The refusal carries a typed code and the facts measured at that moment, the workspace size, its file count and the limit, instead of one sentence for every cause. (#262)
  • A write raises the project epoch, not only the intent. A proof was judged stale by comparing a project's epoch and its manifest on both sides of it, and neither witness saw the sequence where one job captures the epoch, proves the tree as it stands, and a second job writes invalid content in between. (#269)

Threads carry a person, and an answer as it is written

  • An unread state per person and per thread. The product kept no read state at all, so the dot in front of a thread could only mean "waits for you, or running". A read belongs to whoever read: the thread the owner just opened is not read by a teammate. The marker is written when a thread is opened on the dashboard, and never because a message went out on a channel. (#223)
  • The chat reply is shown as it is written. A dashboard turn returned its whole reply at once; it now appears word by word while the turn runs, through a route handler that repeats the server action's checks, because a server action cannot relay a stream. (#221)
  • The thread's prose verdict rule reads the line after "Verdict". The rule claimed to read a verdict written on the line below that word, and read a renderer that returns only the first readable line of the first block, so the branch never fired. A reviewer who titles a section and puts the sentence under it had said their verdict, and hiding it was a lost line, not caution. It is only the fallback for delegates that recorded nothing, so repairing it costs nothing where a typed verdict exists. (#278)

Two guards against paying twice, and one record that travels whole

  • The delegation outcome travels typed, not as text. A delegation record was typed between a parent and its own child and free text everywhere else, so a grandchild's failure reached the grandparent only as prose. The sub-tree's outcome now travels as a map written by the harness from its own bookkeeping, specialist by specialist, and a repair made elsewhere in the tree clears a failure that had travelled up. The sentence a reader sees is a rendering of that map, never a source anyone reads back. (#275)
  • A second review of the same thing is refused, not run. A delegation is refused only when the same reviewer is asked for the same target and nothing completed in between. Every condition is read on rows, none on text similarity, and no recognisable target means no guard. An orchestrator that has a PR reviewed, has the findings fixed and asks again is asking about a target that changed, and goes through. (#220)
  • An agent does not recompose its own team. A per-agent setting, may_change_team, off by default: with it off the three team meta-tools are not in the list the runner computes, so the model never sees them. Every agent that already exists is turned off by the migration, including the orchestrator that rearranged two teams overnight on 2026-09-15. (#222)

Installing, and building

  • The install names npm's script gate before it bites. npm skips the install scripts of @embedded-postgres/<platform>, the package carrying the Postgres binaries Nodal boots. The install page, the docs landing, the CLI reference, the self-hosting guide and the README now say what the warning block means and give the command; up says it after the fact. (#257)
  • The web build's heap floor follows a measurement again. The floor doubled to 24 576 MB on 19 September because the build died and the number was raised until it stopped. The need had not doubled: the measured local peak is 13 069 MB, and the whole pack build fits on a 16 GB CI runner with no override at all. Every pack build now reports its own peak, so the next jump is visible the day it happens. (#277)
  • Delegating expires the parent's cache, and the run says what that costs. A sequential delegation always outlasts a provider's prompt cache, so the parent re-pays its whole prefix at fresh-input rate on every resume, by construction, about a fifth of a run's bill. Nothing billed changes. The cost is read from the call itself, on six conditions, never estimated, and shown. Resuming a parent without resending its context is a separate ticket. (#266)

Chores, and the quality portal

  • The minor findings of the #88 reviews, sorted and closed. The sixteen minor findings of the fourteen after-the-fact reviews, plus two the owner left as comments. Every line was found again by content on main rather than by the line number the report gave: several had moved and two no longer existed. (#273)
  • apps/qa is linted like every other package. Turbo runs a package's lint task only when the package declares one, and the portal declared none, so it was filed as nonexistent and passed over without a word. It held an ESLint error nobody saw. A guard now requires every workspace package to declare the script. (#253)
  • The root ESLint config and apps/web can no longer say two things. One is what a person runs by hand, the other is what CI runs, and they disagreed in both directions: the root config found 100 errors on the app where the package's own lint found none. A rule only one of them applies is a rule nobody sees. (#274)
  • A package left out of the coverage measurement says which, and why. A deliberate exclusion and a measurement that failed rendered identically, as an empty column. They are now four named states, the exclusion and its reason live in one place, and a failed measurement leaves a marker instead of vanishing. (#259)
  • The browser journeys hold on to anchors, not to paint. Thirteen journeys still aimed at a layout class or a rendered word, and on 10 August one rounded corner becoming a rounder one turned eight of them red at once, silently, without a single feature being broken. Every element they aim at now carries a stable anchor, and the gestures that reach them are written once. It also repairs the screen proof of talking to an agent, red since the 19 September measurement. (#293)
  • The ci job gets the same 35-minute budget as ci-windows. It had 25, and spent 23 of them before the build step started, so a run whose unit tests drifted by two minutes died on its own clock with every check green. (#294)

v0.8.11 — Sep 19, 2026

A release about reading a run without opening a chat. A run now has a page of its own, the same one whether it came from a schedule, from the Code screen or from an MCP client, and the thread reads a delegated review from the record the reviewer wrote rather than from a guess at its prose. The sidebar was redrawn on the owner's own list, and fourteen pull requests merged without a review in September were read after the fact; the four findings that still held are fixed here. No new capability; every change went through Reviewer C, and every finding was closed by a test that failed first.

A run is a board to follow, not a thread to read

  • One page for every run. /scheduled/<id>, /jobs/<id> and /code/<id> render the same page: a header card with the request, the agent, the origin, the model and seven figures (cost, duration, tokens in and out, cache reads, files changed, activity), then what was delivered, the review, the verification, the files of a code run, and the whole activity, always open. A run opens at the top and never scrolls itself. The old Code process detail and its private components are gone; the Code list links to the run page.
  • The run says which run it is. The full identifier sits under the header, selectable, with a copy button, on all three routes.
  • The review is read once. The same run showed its verdicts from the Code screen and none from the MCP folder, because two loaders read two things. They now share one reader, ordered by the sequence the tool wrote in, parsed by the orchestration's own parser. A verdict carries the reviewer's full report, rendered in the Review block. When a run carries a recorded verdict, its own reply is not repeated above the block: the review is the answer.
  • Audit rows are masked at the gate. The card, the raw output and the input of every tool row go through one redaction before any screen or summary sees them, on the run page and in the conversation thread alike.
  • Real zero, real title. A cost or a duration that is genuinely zero prints 0; a dash means absent. The header title is the first line of the request, cut at sixty characters, whole on hover.

The thread reads the verdict the reviewer recorded

  • A delegation's head says the recorded verdict. Since the review_verdict tool writes a typed record, the thread reads that row instead of the first line of the child's prose, which could say the opposite. The head reads Approved, or Changes requested · 2 blockers, 1 minor, only the severities that exist; the recorded summary sits in the body. A refusal after a success leaves the delegate with no verdict, as the reviewer meant. A row that breaks its own contract is logged and skipped, never a truncated verdict.
  • A child job carries its verdict and its redaction together. The delegate's result and error are masked like the parent's.

Channels, as drawn, and the sidebar on the owner's list

  • An MCP folder in Channels. Runs started from outside Nodal, through the MCP server or the API, get their own folder, paged fifty at a time, with multi-select delete that refuses to orphan a live delegation. A task sent from the dashboard no longer lands there.
  • The sidebar. Three hundred pixels wide, written once. "Spaces" reads "Workspaces", "Home" reads "Dashboard". LLM provider leads the Operate group, Settings follows Logs. The bottom group is "About Nodal-Agents", with Documentation, Join Discord (the Discord icon, the link icon to the right) and a link to the public quality board. The Code entry left the rail; its pages stay reachable by link. Channels folds with a chevron; each folder folds too, and open shows its five latest threads, bounded in SQL, with a "See all" arrow to the full list. A dot in front of each thread is red when the thread waits for you or has a run in progress, grey otherwise; there is no read state, and the dot does not pretend one. Every row of the rail has one shape, hover and selection running edge to edge, chevron included, and Channels and Nodal chats no longer share an icon.
  • The Files block of a code run is the feed's file block. One diff plate, budgeted at eighty lines, with the redaction applied before the diff is extracted: a key written into a file no longer shows in Files.
  • Unfolding never moves the view. A block opened by the reader grows in place, whatever its size; the follow-the-bottom mode switches off only if the reader has not scrolled since the gesture. Proven in the browser.

A failed run says the gesture it calls for

  • A provider refusal names its remedy. When a provider rejects a request for a model, the failure carries a typed hint and the screen says "Try another model for this agent", on the run and in the delegation block. The code, its prefix and the hint live in one shared module. A job's error is redacted at the feed gate like its result.
  • A restart never leaves a job processing with nobody on it. Jobs whose runner stopped answering are reclaimed after a liveness window and marked runner_restarted; a parent is woken only if the child it waited for is the one that died.
  • A late timeout keeps the turns already done. A single-turn timeout is replayed instead of discarding the whole job, and a provider failure that hides a timeout is recognised as one.
  • Gemini gets the schema subset it accepts, on every route. Tool schemas are sanitised by model family on the OpenRouter route too.
  • A 429 that asks to retry is transient. OpenRouter's "could not verify available credits" was read as an exhausted quota; the classifier now names its cases.
  • A harness reports its writes, the disk confirms them. Files a CLI harness reports as written are checked on disk and scoped to that run; a deletion is confirmed by absence; a run that times out confirms nothing.
  • A directory target no longer counts as a write.
  • A recorded verdict is the job's deliverable. Tool calls carry a write sequence, and the delegation outcome carries the verdict the reviewer recorded, so the parent reads it instead of the prose.

The quality portal

  • The board says where a review stands, read from the review-pass comments of each pull request, with what it could not parse said aloud.
  • Done is a seven-day window, merged pull requests included, and the two dates are in UTC and say so.
  • Every card says which release it belongs to, and the release chip filters the board; the chip now hides the cards it sets aside (the card rule's display:flex used to beat the hidden attribute).
  • The scope journey says which dialog it proves, and the unfold journey proves in the browser that a reader's scroll is kept.

Fourteen pull requests read after the fact

Merged on September 13 without a review when the quota was exhausted, they were read by Reviewer C against today's main. Ten held. Four findings still stood and are fixed here: a file write classified twice, before and after the hook, so a project declared in between left its verification state unfindable; the portal's guard against </script> in embedded JSON replaced < by <; a capability or a journey that wavered without a single red had no link to the run that holds its trace (the finding as reported, a link to a wrong run, did not exist); a side-effect import swallowed a journey's header. The minor findings are filed for 0.9.0.


v0.8.10 — Sep 16, 2026

A release about trust in what Nodal tells you. The launcher no longer kills a process it cannot identify, Postgres keeps a log so a crash can be read instead of guessed, an agent's work is credited only when the file on disk really changed, and the quality portal reports what nobody verified rather than painting it green. Every one of the six changes went through review passes before merging, and every finding was closed by a test that failed first.

The launcher stops what is yours, and nothing else

  • No recorded pid is killed unproven. up and down used to signal the numbers they had written down at the last start. Windows recycles numbers, so a process that took the place of a dead worker could be killed in its stead. A pid is now signalled only when a fresh reading of the process table agrees on its name and its creation time. When the table cannot be read, nothing is signalled and the line says so.
  • A Postgres that is not yours survives a tree kill. A service Nodal started can start a Postgres of its own; the tree kill now walks around it.
  • up refuses to kill a healthy stack it did not start. A live install on the configured ports was treated as leftovers to clean up. It is now named, with its pids, and up stops there.
  • Postgres keeps a log. ~/.nodalai/logs/postgres/, one directory per data directory, rotated daily. A backend crash can now be read instead of attributed by guesswork.
  • down never sits silently. The graceful stop has a budget; past it, down reports what the postmaster is still doing and the exact command to end it, for a pid it confirmed. A wrong database password fails at once instead of waiting three minutes with a live cluster left behind.

An agent's work is credited when the disk says so

  • A write is recognised by its content. The fingerprint of a file carried its size and a timestamp whose resolution depends on the filesystem, up to two seconds on FAT. It now carries a hash of the content: a rewrite of the same size in the same second is seen.
  • A refused read is not an absent file. A file the runner cannot open after the tool ran is neither credited nor invented; the line says it could not read it.
  • A project is a project everywhere. Six places decided whether a folder was a code project; some asked for the manifest, some for the marker. They now share one rule, and a job is attached to the project the agent meant to write in, never to a registered subfolder of it. A folder you hid from the Code screen stays hidden in the agent's context too.
  • The chat states how delegation happens instead of ordering it. The system prompt of the chat no longer contains an imperative the chat cannot carry out.

The quality portal says what nobody verified

  • The portal checks the release itself. It reads what npm serves, what the repository carries, and names the gap, prerelease versions included. When npm does not answer, it says "unreachable at <time>" rather than showing a stale figure.
  • A card opened by an agent must carry proof. Any issue or pull request that bears the agent footer and no ## Verified section with a command and its output is flagged, so "done" always comes with evidence.
  • A journey nobody plays is red, not grey. The portal reads the CI workflows themselves, comments excluded, to know which end-to-end journeys actually run; a journey no workflow plays is red, and a workflow the portal cannot read is said to be unreadable rather than counted as green. Two journeys only one machine could ever play were retired.
  • The homepage reads the nightly measurement. The figures on the docs homepage were typed by hand and compared to the live snapshot, which turned main red after every nightly measurement. They are now derived from the snapshot at build time, rounded down, and a missing or absurd figure stops the build naming the field.
  • release:check refuses to run over a live dev stack. Building in place used to overwrite the running dashboard and empty the package folder. The check now probes the configured ports first, on both address families, and fails loud on an unreadable configuration instead of falling back to defaults.

Fixes

  • End-to-end journeys clean up their own credentials, and only their own. A journey deleted every test credential of its type, including those of a run on another machine sharing the database. Each run now marks what it creates and removes only that.
  • A delegated job that produced nothing is a failure, not a completed job. The parent no longer tells you the work is "launched" when the specialist returned no deliverable; the failure is delivered, in the harness's own words.

v0.8.9 — Sep 9, 2026

Nodal now proves what it builds. Until this release its verification engine had never run once — not in your install, not in any install. Agents also gained a purpose you choose at creation, and the chat thread stopped lying about which conversation it was in.

Your agents prove their own work

  • Verification had never run. Not once. The engine existed, the screen existed, and the table that records proof had been empty since day one — in every install. The reason was a question no one wanted to answer: Nodal asked you which commands prove your project. You don't know, and it isn't your job to know. The agent that built the thing now declares how to check it, and Nodal runs that check when the work ends. A project turns green or red with the command that decided it, and the output that explains it.
  • What an agent already ran is what it declares. These are not new powers: the syntax check, the build, the request against a server it started — it ran them while working. They were simply never recorded. Declaring them is now subject to the same approval rules as running them, so nothing slips past the gate you set.
  • A deliverable is what was aimed at. A finished app used to be listed with twenty unverified deliverables, including archive folders it never touched — because a shell declares everything it could write. The guard stays that wide; the screen no longer does.

Every agent gets a purpose, at creation

  • "What should this agent do?" Creating an agent starts from what you want it for, not from an empty form. Recipes pre-fill the model, the tools and the autonomy that fit — and everything stays editable, because nothing exists in the database until you click.
  • Connectors are recommended, never imposed. A recipe suggests what it would use; you decide what it gets.

The chat thread tells the truth

  • A chat row now opens the thread your next message will land in. It could open another one: the screen picked the most recently touched thread while the runner picks the most recently opened one. Typing /new, then having earlier work finish, was enough to split them.
  • Channels and dashboard conversations are two lists. One row per chat — named after the person or room at the other end, not after the first message ever sent in it. A ten-day-old Telegram thread no longer carries the title of the app you asked for at its start.
  • Threads scroll like a messenger. A thread opens at its last message and follows new ones, but only if you were already at the bottom — reading back through history stays put.
  • An agent's own send is no longer mistaken for your reply. Sending a message returned an identifier that the model sometimes read as if you had typed it, and answered.

Scheduled runs remember what they did

  • A routine keeps its own state. It used to store "what I last announced" as a memory, searched back in plain language — and a memory that got cleaned up made it announce a release twice on a public Discord. State is now a value it owns, read and written without a model.
  • Memories stop filling with logbook entries. More than a third of an agent's memory was routine reports. Memory is what an agent knows about you.

Projects, and the folder they live in

  • A project can no longer contain another project. Creating one on a folder that already holds projects produced two entries for the same work, one swallowing the other. Junctions and simultaneous creations are covered too.
  • Naming a project's folder is optional. Leave it empty and it takes the project's name.

Faster, cheaper conversations

  • A chat turn costs about half of what it did. Every turn silently made a second full-size call to re-ask a question whose answer depended on none of the context it was sending — roughly nine thousand tokens, on every message, including "hello". It now sends what the question actually needs.

Fixes

  • Signing in over the local network works again. The dashboard answered 500 in LAN mode since v0.8.7.
  • A chat turn's token count is no longer zero. Turns that don't go through a job had nothing to attribute their model calls to.

v0.8.8 — Aug 28, 2026

Your bot tokens stop being readable in the database, a Slack bot that loses its connection comes back on its own, and a database outage no longer destroys the log that would explain it.

Every credential is now encrypted at rest

  • Bot tokens leave the clear. The Discord, Slack, WhatsApp and Telegram credentials — and the secret that authenticates your inbound webhooks — were the last values stored readable in the database. They are now encrypted with the same key as your API keys and OAuth credentials. Existing installs are migrated on the next start, in place, with nothing to do.
  • Reading the database is no longer enough to use them. A webhook secret is compared after decryption, so a copy of your database does not let anyone fire your agents.
  • A credential that cannot be decrypted says so. Restoring a backup without its key used to look exactly like "no bot configured here". It now fails loudly, naming the file to restore.

A Slack bot that drops comes back

  • A revoked or rotated token no longer leaves an agent silently offline. When the connection died for good, nothing brought it back — the bot simply stopped answering, with a single line in a log nobody was reading. The connection is now re-established on its own, with the credentials as they stand at that moment, so rotating a token is enough to recover.
  • Retries slow down instead of hammering. A token that is wrong forever is retried on a widening interval rather than every 30 seconds, and stops writing a line each time.

A database outage no longer erases its own explanation

  • Repeated failures collapse. With the database unreachable, seventeen places wrote the same failure every 30 seconds — one real log had 7 412 such lines out of 61 359. Since logs rotate, a long outage pushed out the earlier lines that said why it started. The first failure is still logged in full, repeats are counted, and recovery says how many there were.
  • Failures say what actually went wrong. A failing query used to be logged with the SQL and nothing else. The underlying reason — connection refused, authentication failed, a missing table — now appears with it.

Also

  • GLM 5.3 Flash joins the model catalogue: a larger context than GLM 5.3, roughly nineteen times cheaper, and it can read images.

v0.8.7 — Aug 27, 2026

Your agents work in the folder you gave them, the Code tab shows what they actually built, and a coding CLI can now be an agent — Codex as well as Claude Code.

An agent writes where you told it to

  • The folder you attach is the folder it uses. Four runs in a row had delivered into the shared hand-off area while a real project folder sat attached and unused. The cause was not disobedience: the system prompt announced ## Workspace, singular, while the tools saw two — so the agent wrote to the only one it knew about, then reported a path that existed nowhere. The prompt now lists exactly what the tools have.
  • The shared workspace is named for what it is — the hand-off area between agents, not the place your deliverables go. Every agent keeps it: taking it away from agents that have their own folder would cut them off from the rest of the team.
  • Git awareness reaches the right folder. The repository probe pointed at the shared area instead of the attached project.

The Code tab stops guessing

  • It shows the folders your agents wrote in — and gives you two gestures: rename and hide. Seven different definitions of "real code" were tried and dropped, each breaking on a real case: file extensions, the agent's skills, a package.json at the root, a checkbox on the agent, a checkbox on the folder. What replaces them is not an eighth guess.
  • Hiding reaches the agents too. A hidden project leaves the ## Runtime block of every agent in the workspace — not just the screen. The folder on disk is never touched, and one click brings it back.
  • The name you choose travels. Rename a project and your agents hear it under that name; "modify the client portal" finally designates something.
  • A deleted folder stops producing a ghost project. Its session stays, under "Other sessions" — it did happen.

An agent can be a coding CLI — Codex included

  • Codex is selectable next to Claude Code (agent → Overview → Model). The whole turn is served by that CLI: Nodal keeps the perimeter — folders, budget, approvals, channels — and relays its answer verbatim.
  • Write mode works on Windows. It silently did nothing: --sandbox workspace-write was passed, the turn completed normally, and the model answered "the environment forbids all writing" with no error anywhere. Codex has no default confinement mechanism on Windows and must be told which one to use — a setting that lives in your own config, which Nodal deliberately ignores to keep your personal MCP servers out of its runs. Measured over four runs, one variable at a time; the confinement itself was re-measured before shipping the fix, and still refuses to write outside the working directory.
  • Codex reports no cost, and the screen says so instead of offering a dollar cap that cannot bound anything.

Agents stop reporting work they did not do

  • An orchestrator announced "app delivered and reviewed by Reviewer C (2 passes)" four times in one day, naming the reviewer and the number of passes. No delegation, no write, no file. It was not lying — it was completing a pattern, because nothing in its history distinguished a real hand-off from an invented one. Delegation now leaves a structural trace on the turn that made it, so a turn without delegation carries no line at all — that contrast is what was missing. The most useful case is no tool used: the delegation happened and produced nothing, where prose can claim otherwise.

Hardening — twenty-eight review passes, twenty-four findings

The most serious ones were not in this release's new code. They were asleep in code that runs every day, and the new work brought them to light:

  • Tool output was written to the audit trail in clear text — the content of every file a CLI session read, tokens included. The tool path had redacted it from the start; the runtime path never had, for Claude as well as Codex.
  • A tool restriction could be lifted by switching harness. An agent with tools explicitly removed got them back when moved to a provider that cannot enforce that kind of ban. It now refuses the turn and says why.
  • The single-writer lock could be bypassed by spelling. C:/Common and c:\common produced two separate locks, so two write sessions could edit the same files at once.
  • The anti-loop guard undercounted parallel tool calls — six simultaneous calls counted as one, so the more a model parallelised, the less budget it consumed.
  • Also: locks leaking when prompt assembly failed, a killed turn reporting success, a failed file change counted as a changed file, and a session resuming with the other CLI's session id after a harness switch.

v0.8.6 — Aug 23, 2026

Your terminal can now hand work to your agents, and the dashboard follows you to your phone — without either path being able to brick your install.

Nodal as an MCP server, connectable in one line

  • claude mcp add nodal -- nodal-agents mcp serve. That is the whole setup. The new mcp serve CLI command resolves the database from your own install's config — no DATABASE_URL to know, no secret pasted into a client config, and it works on any npm install, not just a dev checkout. Settings shows the exact command with a Copy button.
  • One tool, run_task. An external MCP client (your terminal, a coding agent) hands a request to your root agent — or a chosen agent by slug. The job runs through the normal loop: approvals, audit, budgets, and it can never touch the configuration tools. Off by default; a switch in Settings turns it on, and turning it off also cuts clients that are already connected.
  • Jobs start immediately. run_task wakes the worker on creation like every other channel — measured before the fix, an MCP job waited ~2½ minutes for the periodic sweep.
  • The server exits when your client disconnects. Closing stdin used to leave an orphan process holding Postgres connections; now both launchers close the pool and exit cleanly.

LAN access that cannot dead-end

  • The LAN toggle keeps your config bootable. Switching to LAN used to be able to write a config the CLI refuses to start (network bind + no-password mode) — bricking the stack until a manual edit. The toggle now enables sign-in in the same write and says so.
  • An existing install gets a claim screen, not a dead login. An install born without a password that switches to sign-in used to hit a wall: no password to sign in with, sign-up closed because the owner already exists. The login page now detects that state and offers Create your account — attached to the existing owner, so agents, settings and history stay exactly as they are. Validated end-to-end on a real migrated install, phone included.
  • Copy buttons work over plain-HTTP LAN. The clipboard API is blocked on http; copy blocks now fall back so the button works exactly where LAN users need it.

Hardening

  • The MCP job path was reviewed adversarially: the worker wake-up uses 127.0.0.1 (never localhost, which can silently resolve to IPv6 on Windows), rejected notifications are reported instead of swallowed, a deactivated agent is refused on every call, and a job insert that cannot report its id fails loud instead of answering success.
  • ~30 vulnerable transitive dependencies pinned to patched versions across the workspace (hono, fast-uri, brace-expansion, js-yaml, nanoid, postcss, qs, body-parser, ip-address, vite, turbo) — and the pnpm overrides that were silently ignored since pnpm 10 moved to pnpm-workspace.yaml, where they actually apply.

v0.8.5 — Aug 21, 2026

Fixes a package that broke itself weeks after it was published. If you installed 0.8.0 or 0.8.1, upgrade — a fresh install of either is dead on arrival today.

  • Every install since Aug 3 got a dashboard that crashed before it rendered. The published package ships a pre-compiled Next.js bundle, but declared 43 of its 46 runtime dependencies as floating ^ ranges. The day next@16.3.0 was published, npm started pairing a 16.3 runtime with a 16.2.6 build, and the server died on TypeError: Cannot read properties of undefined (reading 'validationLevel') before any application code ran. Installs of 0.8.1 made before Aug 3 were unaffected.
  • A pre-compiled bundle now ships pinned to the exact versions it was built against. build-pack rewrites all 46 runtime dependencies to their exact installed versions and fails the build if any range survives. A published package can no longer re-resolve its own runtime months later.
  • Next.js 16.3. The workspace, the pack and the docs site all move to 16.3.0, and the pack was booted from an isolated install before release — every dashboard page served, not just /api/health.

Coding under your subscription

  • Agents can delegate development work to a coding CLI. A new code_task tool hands a scoped task to Claude Code or Codex running under your own subscription, streams the work back, and records what was actually changed. Which CLI provider an agent uses is set per agent.
  • A Code tab. Mission control for everything your agents write: files touched, the diff of the selected file, the activity trail per turn, and token accounting broken down per model.
  • Inference is now traceable. Every LLM call and tool call is persisted and wired to the transcript, so a run can be read back after the fact instead of guessed at.

Connectors and skills

  • Cloudflare connector. Deploy what your agents build straight to Workers, with the compatibility date pinned on every deploy.
  • ComfyUI in the MCP catalog, via the official local comfy-mcp server.
  • The review loop closes. Agents can request a review of their own work, and the verify-before-done skill picked up what the community version did better.

Security — the audit is fully closed

  • A stranger can no longer take over your bot. A bot's username is public, and whoever messaged it first used to become its owner — so between pasting the token and sending your own first message, anyone who had found the bot could take your place, task your agent, and receive its approval cards. The first message now only requests ownership; you approve it from the dashboard. Telegram, Discord, Slack and WhatsApp.
  • You see a skill update before it reaches your agents. Updating a community skill used to show a category ("content changes") for text that goes straight into the system prompt of every agent holding it. You now get the actual diff, and the install refuses if upstream changed after you read it — consent applies to the text you saw, not to whatever the repo holds at click time.
  • Narrower Google access, and honest about the rest. Google Calendar no longer asks for permission to delete your calendars. Drive, Sheets and Docs still need full access for their tools to work at all — so the product now says exactly how far that reaches, in plain language, before Google's consent screen.
  • Command injection through cmd.exe closed — prompts are passed over stdin, never through a shell argument. Two independent reviews were run to closure.

Reliability

  • Office tools, one format at a time. Spreadsheet, Document and Presentation editing are now separate skills. An agent that only touches workbooks stops carrying the Word and PowerPoint tool definitions — roughly 3,000 tokens off every turn, and 5,800 for a documents-only agent. The all-formats skill still exists.
  • A failed start now tells you what failed. When a service doesn't come up, the CLI names which one it is still waiting for, how long it has waited, and prints the tail of that service's own log — where the actual cause has been sitting all along. down also verifies Postgres actually stopped before saying it did, and an orphaned Postgres is detected by its data directory rather than by an open port, which is the only way to see one that crashed during startup.
  • Ctrl+C is honoured from the moment Postgres starts, not five minutes later — interrupting a slow first boot no longer leaves a database running behind.
  • Interrupting the dev server no longer strands a Next.js process on :3000. Ctrl+C under a .cmd launcher makes Windows destroy the whole process group at once, the CLI's own cleanup included, mid-run — so cleanup cannot live there. The process tree is now recorded while the services are healthy, and the next start sweeps whatever survived, matching each process by creation time so a recycled PID is never mistaken for one of ours. It also reaches the deepest Turbopack worker, which holds no port and was therefore invisible to any port scan.
  • up refuses to kill a process it did not start. A port it wants may be held by your own dev server; it now says so and stops, instead of freeing the port by destroying someone else's work.
  • down stopped crying wolf about Postgres. pg_ctl stop returns when the signal is delivered, not when the postmaster is gone, so a stuck-database warning was firing on a database that was merely still on its way out.
  • Upgrades are tested against the real published package. A new smoke test installs nodal-agents@0.8.1 from npm, configures it, then installs this build over the top and checks it boots, serves a real page, keeps pg-data, and leaves the master key byte-identical — a changed key would make every stored credential permanently unreadable, silently. Fresh installs were already covered; the upgrade path, which is the one most people take, was not.
  • Windows is now in CI, alongside the Linux suite, the Playwright smoke and approvals specs, and the packaging smoke. Every finding from the 0.8.1 audit is closed.

v0.8.1 — Jul 31, 2026

Fixes a broken 0.8.0 package: on a fresh machine the dashboard could not render at all. If you installed 0.8.0, upgrade.

  • Every dashboard page returned HTTP 500 on a fresh install. The published 0.8.0 tarball was missing 7 of the 40 server chunks its own pages require — the Next.js standalone output dropped them while copying the build, and nothing in the release pipeline compared what the build asks for against what ships. The home, agents, jobs, memories, settings, logs, MCP, automations, approvals, connectors, skills and onboarding pages were all affected. /api/health kept answering 200 throughout, so the CLI reported the runner as healthy.
  • The pack now ships the real build, and proves it. build-pack copies the build's own .next/server over the standalone copy, then fails loudly if any page still requires a chunk that isn't there. verify-install runs the same check against an installed copy, and both are covered by tests that now run in CI.

v0.8.0 — The Office Release · Jul 22, 2026

Your agents step into the workplace: they can now read your Outlook mail and author real Office documents, choose how hard they think, and the platform got a deep reliability pass — a remote tool server that hangs can no longer freeze an agent, and a stuttering agent can no longer flood your workspace with duplicates.

Highlights

  • Microsoft 365, connected. A native Microsoft OAuth connector plus an Outlook mail toolset — your agents authenticate to M365 and work your mailbox, alongside the existing Google/Notion/Airtable connectors.
  • Agents that author documents. A local office-authoring toolset builds real .docx, .pptx, and .xlsx files — multi-section documents, slides, spreadsheets with charts and pivots — with loud, honest failures when something can't be produced (no silent half-files).
  • Choose how hard your agent thinks. Each agent gets a reasoning-effort setting (Auto / Off / low → max). The dashboard only offers the levels a model actually supports, and the choice applies per link of the fallback chain.
  • Community skills, kept in sync — on your terms. Installed skills track upstream updates with a badge and a notification bell. Updates are a true three-way merge: if you've edited a skill's scripts locally and upstream also changed, you get a "Keep your version" option instead of a silent overwrite — and script authorization is revoked before any new file is written, so an update can never run un-vetted code. Skills also show where they came from (provenance) and a redesigned Tools view makes capabilities ON/OFF the primary control.
  • Rate limits handled gracefully. LLM 429/529 responses are retried with a capped Retry-After backoff, and fast-failover to a fallback model when one is configured — no more a single provider hiccup killing a job.

Reliability & fixes

  • A hung MCP server can't freeze your agent. Each remote tool-server connection gets its own network dispatcher, so one server whose event stream hangs no longer starves every tool call behind it (previously froze the whole agent for a minute per call).
  • No more duplicate connectors. Creating a connector is now idempotent — an agent that stutters can't register the same connector eight times; a same-name duplicate fails loudly, while genuinely different instances (two accounts, same provider) still work.
  • Delegated workers stay in their lane. A sub-agent no longer speaks on your channels or self-publishes status cards — delivery is the orchestrator's job — and it can no longer overwrite shared workflow templates in place.
  • Routines get a safety net. Creating a scheduled routine that references a tool the agent doesn't have (or an ambiguous non-capability like "your state") now surfaces a warning at creation time.
  • Honest delivery. A Telegram send that times out is no longer blindly retried (the message was likely delivered) — it's reported as ambiguous instead of duplicated.
  • Leaner and faster. A pre-0.8 audit dropped dead tables and columns, added a missing index, batched N+1 queries, tightened fetch timeouts, and hardened process-level error handling. Typography moved fully onto the design-system token scale, and a new Table primitive standardizes data tables across the dashboard.

v0.7.95 — The Living Design System Release · Jul 16, 2026

The design system stopped being a snapshot and became a loop: the Figma library and the code are now mechanically tied together, checked by machine in both directions, and the last stock-browser UI (the select dropdown) was brought under the system.

Highlights

  • Figma ↔ code, closed loop. All 73 shared UI components are mapped to the Figma library via Code Connect. A drift detector (figma:drift) fails when a component, variant, or mapping diverges between the file and the repo, a DS lockfile (figma:ds-lock/ds-diff) captures the library state, and a lint guard blocks any arbitrary text size from sneaking past the type ramp.
  • The select menu finally speaks DS. Dropdowns use the new customizable-select standard (appearance: base-select, Chrome/Edge): the open menu renders the design-system panel — paper surface, popover shadow, hover/selected states, the DS caret and check glyphs — with grouped options getting real section headers (styled <optgroup> legends). Other browsers keep their native picker, cleanly. Placeholders now grey out like every other field, and the field is pixel-checked against the Figma spec by machine (47 automated conformance checks).
  • Agents page, redesigned. Orchestrators are cards with their workers inside; dragging a worker across cards reassigns it. Delete moved to a type-to-confirm danger zone in Settings, and channel connections live in an in-page Channels tab.
  • Pick where notifications land. Schedules and webhooks gained a "Notify via" selector — results go to the channel you chose (Telegram, Discord, Slack), and if that channel isn't connected the run fails loudly instead of falling back silently.
  • Docs, audited page by page. Ten pages corrected against the real code, four end-to-end channel connection guides (Discord, Slack, WhatsApp, event triggers), and the README now documents the dev command that actually boots the stack.
  • Fixes. Multichannel transport resolves the reply channel per conversation; incoming webhooks moved to /wh/v1; an MCP server failing to load its tools no longer kills the whole job; sidebar labels no longer clip letter descenders; segmented controls no longer render a phantom empty segment; the dead "+ New connector" button is gone.

v0.7.9 — The Design System Release · Jul 13, 2026

The entire dashboard was brought under one enforced design system: every interactive element is now a shared component, consistency is guaranteed by CI rather than vigilance, and the whole thing was verified page by page in both themes. Plus the Google Gemini provider was rebuilt.

Highlights

  • One visual language, enforced. Buttons, inputs, selects, badges, pills, menus, and modals were all migrated onto a set of shared UI primitives (245 hand-styled raw elements replaced). A lint rule now makes any raw button/input/select/textarea outside the component library fail the build, so the consistency can't silently drift back. Verified route by route, modal by modal, in light and dark.
  • Edit is always a modal. List editing no longer expands an inline accordion that pushes the page around; every edit opens a non-dismissable dialog (backdrop and Escape inert, Save/Cancel only), with one canonical footer template used site-wide — never zero, never two action rows.
  • One row-action grammar. Per-row actions are icon-only squares with a mandatory tooltip; one concept = one verb = one icon; Delete/Disconnect/Uninstall is always last; no kebab menus for standard actions.
  • End-to-end channel connection guides. Connecting an agent to Discord, Slack, WhatsApp, or Telegram now has a step-by-step guide — app/token setup, the ownership DM, the invite, and a "verify it works" check — written from the real handler code and shown in a cleanly formatted modal.
  • Google Gemini, rebuilt. Native and OpenRouter Gemini paths were reworked: thought-signature round-tripping on tool-call parts (native returns a hard 400 without it), native thinking config, and a 3.x-only native catalog — so tool-calling agents run correctly on Gemini.
  • Polish. The Settings page body was widened to match every other page (it had been a third narrower). Learned Skills now reuses the Skills page's per-agent assign/unassign toggle list, so you can finally unassign a learned skill. Slack logs a clear line on connection, and the file-sending tools resolve relative paths against the workspace.

v0.7.8 — The Everywhere Release · Jul 12, 2026

Your agents now live everywhere you already talk: Discord, Slack, and WhatsApp join Telegram. Plus event-triggered automations, agents that can no longer misstate what they did, and a new LLM provider. (Versions 0.7.6 and 0.7.7 were never published; their work ships here.)

Highlights

  • Four messaging channels. Connect any agent to Discord (server mentions — including the role mentions Discord's autocomplete really inserts — DMs, and tappable approval buttons), Slack (Socket Mode, with a ready-to-paste app manifest right in the dashboard), and WhatsApp (QR pairing; unofficial-API caveat shown up front), alongside Telegram. Same security model everywhere: the first private conversation claims ownership, every other conversation needs your explicit approval, one owner per agent per channel — guaranteed by the database.
  • Channels your agents actually know. Each agent sees which platforms it's connected to and can list the real servers, channels, and conversations it has access to (and which are approved) instead of denying a connection it has.
  • Event triggers. Scheduled watchers know exactly "what's new since last run", carry a daily budget, and never overlap themselves; inbound webhooks let an external service start a job directly — timing-safe token check, payload isolation against prompt injection, rate-limited, managed from the dashboard.
  • Agents can't deny their own actions anymore. Every exchange carries a structural record of the actions it performed; a delegating agent's thread shows what its sub-tasks actually did (tools called, result); and an agent that tries to assert platform state without checking gets stopped by the runtime and made to verify first.
  • No more silent replies. The delivery guard that kept Telegram jobs honest now covers Discord and Slack too: a job physically cannot complete without its reply reaching your channel.
  • Moonshot/Kimi, native. Kimi K2.6 and K2.7 Code as a first-class provider (thinking handled correctly, temperature managed server-side, and a strict tool-schema sanitizer that also protects Kimi models routed through OpenRouter). Model pickers now show which models can use tools, and a model that can't is blocked from the orchestrator role.
  • Onboarding, revamped. The get-acquainted interview no longer shows up in your Chats afterwards, and setup ends with a real choice of messaging channels (brand icons, not emojis).

Approval authority (from the unpublished 0.7.6)

  • Approval cards always go to the bot owner. When someone you've authorized to talk to your bot (a guest chat) triggers an action that needs approval, the ✅/❌ card now lands in your private chat with the bot — never in the guest's. Previously a guest authorized via a private DM could tap ✅ on their own gated action and self-approve; that hole is closed, and guest-triggered approvals in groups no longer leak the card into the group either. Your own actions are unaffected. (Per-guest capability profiles — restricting which actions a guest can even request — are designed and coming next.)
  • Scheduled reports and Telegram deliveries reach you, not a group. A cron's success summary (and the dashboard's "send result via Telegram") used to target the last chat the agent was spoken to in — which a group message silently overwrote, so a report could leak into a group the moment someone @-mentioned the agent there. These now always deliver to the owner's private chat. A schedule can still be given an explicit target chat when you deliberately want it to post somewhere specific.
  • Redesigned chat page. The conversation view is rebuilt from the ground up: messages in a centered column, agent replies with a lime avatar and a clean name/text layout, dark bubbles for your messages, a floating rounded input, and a distinct Conversations panel. Same speed, same features — just far nicer to look at, in both light and dark themes.

Communication security (full audit — 11 findings, all fixed)

  • Agents can only message chats you've approved. Every Telegram send tool (messages, images, files, media) now verifies an explicit target chat against your approved-chats list — an agent can never message an arbitrary chat id it learned or guessed, and a delegated worker using the entity's bot token is held to the same list. Sends are also hard-capped per job, so a runaway loop can't spam you.
  • Files an agent sends are confined to its own space. send_file/send_image used to read any path on the machine — a prompt-injected agent could exfiltrate config or credential files. Sources are now confined to the agent's workspaces, the skill store, and the temp dir; remote fetches are size-capped while streaming and blocked from link-local/metadata addresses, including via redirects. (Localhost stays available — your ComfyUI flow is untouched.)
  • /ask respects each agent's own guest list. Relaying a message to a sibling agent (/ask finance-bot …) now requires the chat to be approved for the target agent — otherwise the owner gets a confirmation card naming that agent. A relay can never claim bot ownership.
  • One owner per bot, guaranteed. A database constraint makes duplicate owner claims impossible (a race between two first contacts could previously mint two co-owners); requester names on approval cards are sanitized against impersonation tricks; group mentions only trigger on exact @username matches and on replies to this bot.

Scheduled runs got smarter

  • Cron jobs know "since when". Every scheduled run now carries its schedule's previous fire time in context ("Previous run of this schedule: …"), so a watcher-style agent can reliably act only on what's new — no more re-announcing old items or depending on fragile memory. The groundwork for event-triggered automations.
  • Silent schedules can still speak up. A schedule with success-notifications off now lets its agent message you (the owner) when it decides something is worth saying — check a feed every 15 minutes, stay silent when nothing changed, ping you the moment something new appears.
  • Freshly attached MCP servers work on their first job. Tool caches are stored complete at install time, and a server that fails to spawn is logged loudly instead of silently contributing zero tools.

v0.7.5 — The Trustworthy Orchestrator · Jul 8, 2026

A deep security-hardening wave, and a rebuilt approval & delegation experience — born from a forensic audit of real jobs that were slow, noisy, and occasionally wrong.

Approvals you can actually read — and that don't stall your job

  • Approval cards now lead with the WHY. Three levels: the agent's stated purpose, then a plain-language impact line computed by the platform from the same classifiers the security gate uses (Runs `rm` — destructive or heavy… / Runs `curl` → `head` — no destructive pattern detected), then the full technical detail. Identical on Telegram and the dashboard.
  • Approving is instant now. When you approve within ~2 minutes, the job continues in-process — no more full restart per approval (which cost 80-105 s each, MCP reconnections included). Approvals that take longer still suspend safely and resume as before.
  • MCP servers connect lazily. A job no longer spawns every attached MCP server at startup — the toolset builds from a cache and a server is only spawned the first time one of its tools is actually called.

Delegation that delivers

  • Delegated workers can deliver to you directly. A worker generating your image now inherits the entity's Telegram delivery tools and sends it itself — and the orchestrator is told [livraison effectuée] so it never re-delivers or mislabels a delivered job as failed.
  • Orchestrator discipline, built in. Every orchestrator now carries intrinsic rules: pass parameters in the brief (don't do the worker's prep), never edit a shared template to smuggle in run parameters, never prescribe a tool the target agent doesn't have. Briefs naming an unavailable tool get an immediate warning.
  • Shared files are protected. Overwriting an existing file in the shared workspace now requires approval (in both gated autonomy modes) — your saved templates can't be silently corrupted anymore. Your own attached workspaces (e.g. an Obsidian vault) are never gated, and creating new files never asks.
  • Memory that corrects itself. Every agent must now mark a memory fact outdated the moment it proves false in practice (and save the verified correction); workers save durable discoveries before finishing; and "lessons" that micromanage other agents or ban discovery can no longer be saved.

Jobs page: conversations, not noise

  • A 10-message chat with your agent is now one expandable 💬 row (exchanges, time range, aggregated cost) instead of ten identical job rows. Real work — tools, delegations — stays as full rows. Your existing history is regrouped automatically on upgrade.

Security hardening (full audit remediation)

  • Secrets stay secret. MCP stdio subprocesses no longer inherit the full process environment (a third-party server could read your keys); API keys are redacted from tool-call audit logs; a CI secret-scanner blocks hardcoded credentials from ever reaching the repo again.
  • Context windows respected per model. The runner now knows each model's real context window (catalog, stored value, or auto-probed from LM Studio) instead of assuming 128K — small local models no longer die silently mid-conversation, and overflow fails loud instead of corrupting.
  • Plus: credential helpers moved out of the server-action surface, create_mcp/attach_mcp gated as code execution, SSRF guards on MCP URLs, timeouts on all Google clients, security headers, signup closed once an owner exists, bounded results across a dozen adapters, and memory injection that finally counts as usage (your useful facts stop being archived by the curator).

v0.7.2 — Platform Audit Fixes · Jul 7, 2026

Twelve security and reliability fixes from an external-grade platform audit.

Highlights

  • Delegation can't run away. Depth/fan-out caps enforced at the delegation point, cost-cap checkpoints mid-job, and cancellation is respected everywhere — a cancelled job stays cancelled.
  • Authorization tightened. Approval endpoints check entity ownership (no cross-tenant IDOR), bearer tokens are entity-scoped, and the code-execution master switch is owner-only on LAN installs.
  • Runtime hygiene. Child processes run with a scrubbed environment; per-model context limits and cost accounting checkpoints keep long jobs honest.

v0.7.0 — Scalable Memory · Jul 2, 2026

Memory that stays fast and relevant as it grows.

Highlights

  • Full-text search inside agent memory. Facts are indexed (Postgres FTS + GIN) and ranked by real relevance to the task at hand, not just recency — the agent surfaces the right fact even with hundreds stored.
  • A memory curator. A bounded background pass distills oversized facts, merges near-duplicates, archives what's provably unused, and re-scores importance from actual usage. On by default, per-entity switch.
  • Pin what matters. Star a fact in the dashboard to lock its importance — the curator can never archive or down-rank what you pinned.

v0.6.8 — First-Run Experience · Jul 1, 2026

A fresh install lands on a capable agent that can search the web and matches the autonomy you asked for.

Highlights

  • Web search out of the box. web_search is now a real, always-on tool: it uses your Tavily or Firecrawl connector if you have one, and otherwise falls back to a free, best-effort DuckDuckGo search — so a brand-new install can look things up immediately. If the free path is rate-limited or blocked, it says so and guides you to add a Tavily key for reliable results (and switches to it automatically once you do).
  • Onboarding sets your autonomy for real. The get-acquainted interview's "should I take initiative or stick to exactly what you ask?" answer now drives the agent's actual autonomy level — three modes (Take initiative / Balanced / Ask first), shown on a confirmation screen you can adjust, changeable anytime in Settings → Autonomy. It used to only land in memory. And the first agent now arrives with its ROOT powers enabled, not locked down — capable from minute one instead of asking to confirm everything (a local/personal install; the autonomy level is the guard-rail).
  • Built-in tools, documented. A new auto-generated reference lists all 51 built-in tools (web_search, file ops, memory, dashboard_publish, the ROOT meta-tools…) with each one's risk level and how it's unlocked — generated from the tool registry so it can't drift.

v0.6.7 — Boot Regression Fix · Jul 1, 2026

Undoes a 0.6.5 packaging change that broke nodal-agents up on fresh installs.

Highlights

  • Fixed: the runner failed to start on a fresh install. 0.6.5 bundled the node-fetch chain into the tarball to silence one last benign deprecation notice — but node-fetch@3 is ESM-only, and frozen into the package it displaced the CommonJS node-fetch@2 that the Notion SDK loads via require(), crashing the runner at import (Cannot find module 'node-fetch') so it never became healthy. Now only exceljs is bundled (CommonJS, self-contained): the scary warnings (glob "security", inflight "memory leak") stay gone, and the one benign node-domexception notice returns — a fine trade for a runner that actually boots. The generous 5-minute first-run health budget from 0.6.6 stays.

v0.6.6 — Fresh-Machine Boot Fix · Jul 1, 2026

A fresh install on a clean machine could time out on its first launch — fixed.

Highlights

  • First run no longer times out on a clean machine. The runner's health-check budget was 60s, but the very first nodal-agents up on a fresh machine is heavy — embedded-postgres fetches its ~70MB binary at runtime (more so when npm script-approval blocks its postinstall), and the runner loads a large module graph off a cold disk cache — which could blow past 60s and tear the stack down (did not become healthy within 60000ms). The cold-start budget is now 5 minutes and env-overridable (NODALAI_RUNNER_HEALTH_MS / NODALAI_WEB_HEALTH_MS). If it ever still times out, a retry runs warm (binary cached, modules loaded) and comes up fast — and the error message now says exactly that.

v0.6.5 — The Frictionless Release · Jul 1, 2026

Install and first run, cleaned up: a silent install, a browser-first setup with no account, and a welcome chat that never traps you.

Highlights

  • A silent install. npm install -g nodal-agents no longer prints the scary npm warn deprecated lines — glob "widely publicized security vulnerabilities", inflight "leaks memory", and the rest. They were stale transitive deps of exceljs (not reachable vulns, just upstream cruft); since npm overrides don't reach a global install, the fix bundles exceljs and the tiny fetch chain inside the published tarball. Same bytes a user downloads, zero warnings.
  • Browser-first first run. A fresh nodal-agents up asks nothing in the terminal. It boots with a sensible default and opens the dashboard straight to a guided setup — connect a model, create your first agent, meet it. nodal-agents init still exists for LAN / auth / terminal setup and Docker.
  • No account by default. Local installs run in local-trust on loopback — no sign-up wall. Auth is opt-in, for LAN / multi-user.
  • A welcome chat that never traps you. At the end of the get-acquainted interview, the Continue button now appears as soon as you've answered the questions (it no longer waits on a done-marker that smaller/local models forget to emit), and a Skip for now button is always visible so a slow model can't strand you.

v0.6.4 — Onboarding Restored · Jul 1, 2026

A fresh install no longer locks you out — the real first-run flow is back.

Highlights

  • Fixed: every fresh install was locked out. A workspace with no agents yet (the default state right after install — no agent is seeded by design) was redirected to an unfinished onboarding placeholder ("Migration WIP") and trapped there, with no way to reach the dashboard or create an agent. The real guided first-run flow is restored and wired back in: connect a model → create your first agent → a short welcome interview where the orchestrator introduces itself, gets to know you (your name, where you're based, what you want help with), and saves that to memory. It had been built and tested but parked on a side branch and excluded from a past release for lint errors; those are fixed and it's merged.
  • Documentation, greatly expanded. A full reference pass: auto-generated catalog references (every connector and its tools grouped by read/write/destructive, MCP servers, models with vision/reasoning flags, ROOT grants — generated from the catalogs so they can't drift), plus new pages for connecting tools (per-connector OAuth/API-key setup), troubleshooting/FAQ, the CLI, the dashboard, operating & observability, the HTTP API, and workspaces. Several inaccuracies vs the code corrected.

v0.6.3 — The Design Pass · Jun 30, 2026

Every screen now wears the same skin — one header, one toolbar, one set of rules.

Highlights

  • One header, one toolbar, everywhere. Every page renders a single shared shell: a full-width navbar (page title + lede on the left; global search, notifications, theme on the right; a bottom rule), and beneath it a consistent toolbar — filter tabs + search + a single create button. Create buttons follow one colour convention (agents = lime, skills = coral, connectors = blue, everything else = white), always top-right, always labelled "New …". No more per-page drift.
  • Runs, as a delegation tree. The Runs page is now a delegation-aware table: each orchestrator sits directly above the runs it delegated, role colour-coded by a left accent, with trigger icons (cron / Telegram / dashboard), abbreviated token counts, and the real provider-reported cost.
  • Skills, rebuilt. Two views — Assigned (a management table) and Library (the whole catalog as uniform tiles), filtered by content category (Development, Finance, Office, Media, Design…) instead of the old source split. Category pills on every tile; one-click install from any community source.
  • Long lists collapse. OAuth scope URLs, required built-ins, and "used by" connectors now show as a compact "N items" pill you hover to expand — no more columns blown off the table. Credentials moved from cards to a matching table.
  • Know when to update. The sidebar shows your running version and, when npm has a newer one, an "Update available" badge with the one-line nodal-agents update command.
  • All-English UI. The community-skill catalog and connector descriptions are fully translated.
  • Also: Poyo image connector + VidIQ added to the catalogs · the full Telegram media surface (send_file / send_video / send_audio / send_voice, not just images) · a Weekly ⇄ Daily toggle on the home activity chart · a copy button + shortened path for the shared workspace in Settings · the unused Billing menu removed · the sidebar widened to 244px.

v0.6.2 — The Recall Release · Jun 28, 2026

Your agents remember — within a conversation, and across everything they've ever done.

Highlights

  • Conversations that hold the thread. Session memory now measures a pause from when the agent's reply was delivered, not from when the job started — so a slow task (a render, a deep research run) no longer makes your quick follow-up look like an hour of silence that wipes the conversation. The idle reset widened (30 min → 4 h), the history budget grew, the reply's tail (its conclusion / next-step) is kept instead of chopped, and a job that failed but spoke to you stays in the thread. Measured on a real 122-message conversation: amnesia dropped from 39% to 13% (the rest are genuinely new sessions).
  • Two-tier memory. Injected memory is now ranked by relevance to the task at hand — not just global importance — so the budget surfaces facts about this request. Every job's transcript is full-text searchable on demand via the new always-on search_history tool: durable recall of anything the team has ever done, at zero standing context cost. And a background memory curator distills oversized facts, merges duplicates, and prunes the stale — never touching what you entered by hand.
  • 3D & creative connectors. Blender, Unity, Unreal Engine, KeyShot, and Photoshop (cross-platform) join the MCP marketplace under a new Creative category — each with a real brand icon.
  • A longer MCP tool timeout (heavy tools like renders no longer time out at 60 s), and a fix for an order-dependent CI flake.

v0.6.1 — The Vision Release · Jun 27, 2026

Send a picture on Telegram and your agents can actually look at it.

Highlights

  • Inbound images. A photo sent on Telegram now starts a job — it was silently dropped before (the handler only read text, never the caption). The image is saved to your shared workspace (telegram/<chat>/<job>.<ext>), reachable by the agent's file tools, and handed to the model — so "describe this image" works.
  • Vision routing, by real capability. Each model's image support is read from the providers themselves (OpenRouter's /api/v1/models + models.dev) and surfaced in the orchestrator's team view. A text-only orchestrator routes the picture to a vision-capable teammate — the image travels with the delegation — or tells you plainly if none can see it. No guessing, refreshable with one script.

v0.6.0 — The Clarity Release · Jun 25, 2026

Approvals that explain themselves, chat hand-offs that stay faithful, and session memory that knows when a conversation is over.

Highlights

  • Approvals in plain language. Every gated action (shell command, skill script, bundle write) now leads with the agent's own one-line explanation of what it's doing and why — plus a ⚠️ impact line when it deletes, installs, or spends — instead of a wall of raw shell. On Telegram and in the dashboard.
  • Faithful chat hand-offs. When the dashboard chat escalates your request to a worker, your exact words now travel with it — no more silently reworded instructions. A 30-minute idle gap starts a fresh conversation, so a thread you return to hours later doesn't drag yesterday's context into a new request.
  • Role-aware delivery. Delegated workers hand results back to their orchestrator instead of double-delivering to you; the "how to structure and where to send" lives in a reusable skill, so a bare "research X" is enough.
  • A shared workspace link in Settings, and a complete README rewrite.

v0.5.5 — The Autonomy Release · Jun 23, 2026

Real autonomy levels, a curated community catalogue, and agents that stop making things up.

Highlights

  • Three real autonomy levels per workspace ROOT — propose-confirm, destructive_gate (auto-run ordinary work, still gate anything destructive), and fully_autonomous — enforced at execution time, not just in the UI.
  • A 40-skill Community catalogue — install any of them with one click, every path verified.
  • Google Calendar connector, and an entity-scoped skill store.
  • Anti-confabulation team blocks — orchestrators describe their real team instead of inventing teammates, and delegated sub-agents suspend/resume cleanly across an approval.

v0.5.0 — The Self-Improving Release · Jun 15, 2026

A closed learning loop, native frontier-OSS endpoints, and one orchestrator that does both delegation styles.

Highlights

  • A closed learning loop (opt-in). After a substantial job an agent reflects and writes itself a reusable skill; a weekly curator consolidates and prunes them. Review, assign, or revoke every learned skill from the dashboard.
  • Native DeepSeek & MiniMax endpoints alongside OpenRouter — pick the route per key, with reasoning round-tripped across tool calls so reasoning models don't degrade mid-task.
  • Unified orchestrator — every orchestrator gets both delegation styles and commits to one per request: route to a specialist and resume on its result, or fan work out to a parallel task board and compile it.
  • Install any community SKILL.md from GitHub, skills.sh, or ClawHub — pure HTTPS, SSRF allow-list, zip-slip guard, scripts flagged and never run.
  • A real-dollar cost cap per job (from the provider's actually-billed cost), plus a no-false-success guard that refuses to report "done" when an action failed.

v0.4.4 — The Context Release · Jun 4, 2026

Long jobs stay inside the window, failures become diagnosable, and delivery only happens when there's somewhere to deliver.

Highlights

  • Context compaction — stale tool output is evicted before the window overflows, keeping the recent turns intact.
  • Real provider errors — failures surface the actual upstream message and persist the full transcript, instead of an opaque "provider returned error."
  • Channel-aware delivery — an agent only reaches for telegram_send_message when there's a resolvable recipient, killing phantom sends on dashboard/API jobs.

v0.4.3 — The Reasoning Release · Jun 3, 2026

Highlights

  • Reasoning models, round-tripped. A reasoning model's hidden chain-of-thought is now replayed across tool calls (via the official OpenRouter SDK), so MiniMax M3, DeepSeek, and friends keep reasoning on multi-turn tasks instead of stalling.
  • Fixed an orchestrator that would narrate an action without performing it (poisoned history — escalations are now replayed with their run_task).

v0.3.7 — The Root Agent Release · May 30, 2026

Highlights

  • A self-extending ROOT agent. Designate your first orchestrator as the workspace ROOT and let it create skills, create agents and assign them, and stand up MCP servers + connectors on your behalf — each gated by a per-grant toggle and an autonomy level.
  • Provisioning verifies before it writes (an MCP server is connected and its tools listed first); skill authoring is grounded in the workspace's real tools.

v0.3.0 — The Workspaces Release · May 28–29, 2026

Highlights

  • Multiple isolated workspaces on one install (personal vs work), switchable from the sidebar — each with its own agents, skills, connectors, jobs, and memory.
  • Office files — edit Excel in place, create Word & PowerPoint, inside the agent's workspace.
  • One-command upgrade (nodal-agents update) with a boot version notice.
  • A reworked Skills library (Assigned / Custom / Built-in) and a richer connector + MCP marketplace.

v0.1.0-beta — First public beta · May 13, 2026

The first published build: a local-first, multi-agent platform on embedded Postgres — team orchestration, per-agent models, persistent memory, Telegram, and connectors, in two commands.


For the full commit-level history, see the GitHub releases.

On this page

v0.9.9 — Nov 2, 2026v0.9.8 — Oct 23, 2026v0.9.7 — Oct 16, 2026v0.9.6 — Oct 14, 2026v0.9.5 — Oct 5, 2026v0.9.4 — Sep 30, 2026v0.9.3 — Sep 25, 2026v0.9.2 — Sep 23, 2026v0.9.1 — Sep 21, 2026v0.9.0 — Sep 20, 2026v0.8.11 — Sep 19, 2026v0.8.10 — Sep 16, 2026v0.8.9 — Sep 9, 2026v0.8.8 — Aug 28, 2026v0.8.7 — Aug 27, 2026v0.8.6 — Aug 23, 2026v0.8.5 — Aug 21, 2026v0.8.1 — Jul 31, 2026v0.8.0 — The Office Release · Jul 22, 2026v0.7.95 — The Living Design System Release · Jul 16, 2026v0.7.9 — The Design System Release · Jul 13, 2026v0.7.8 — The Everywhere Release · Jul 12, 2026v0.7.5 — The Trustworthy Orchestrator · Jul 8, 2026v0.7.2 — Platform Audit Fixes · Jul 7, 2026v0.7.0 — Scalable Memory · Jul 2, 2026v0.6.8 — First-Run Experience · Jul 1, 2026v0.6.7 — Boot Regression Fix · Jul 1, 2026v0.6.6 — Fresh-Machine Boot Fix · Jul 1, 2026v0.6.5 — The Frictionless Release · Jul 1, 2026v0.6.4 — Onboarding Restored · Jul 1, 2026v0.6.3 — The Design Pass · Jun 30, 2026v0.6.2 — The Recall Release · Jun 28, 2026v0.6.1 — The Vision Release · Jun 27, 2026v0.6.0 — The Clarity Release · Jun 25, 2026v0.5.5 — The Autonomy Release · Jun 23, 2026v0.5.0 — The Self-Improving Release · Jun 15, 2026v0.4.4 — The Context Release · Jun 4, 2026v0.4.3 — The Reasoning Release · Jun 3, 2026v0.3.7 — The Root Agent Release · May 30, 2026v0.3.0 — The Workspaces Release · May 28–29, 2026v0.1.0-beta — First public beta · May 13, 2026