Repository navigation
Releases: Hocsman/Relayer
Release list
v0.8.19
Patch release that shows an operator the shell command a Claude Code prompt asks to run, in the desktop application and in the web gateway: since v0.8.18 the prompt had an honest title and no command, which had to be read in the terminal. The command is redacted line by line, keeping what follows a masked value, bounded, and never sent to a viewer. A shell-command prompt no longer carries a tool-call badge, which could have carried the rest of the command to viewers, and the modal's terminal tail loses its escape sequences. The command is read from the agent's screen and the redaction knows common credential forms only, so check it against the terminal before you allow anything.
Added
-
The decision modal shows the command a prompt asks about. For a shell command Claude Code asks to run, the title was honest since v0.8.18 but the command itself reached no screen: the prompt's summary is a constant, and the command the adapter read was kept in the event and shown nowhere. The core's prompt view now carries it, in the desktop application and in the web gateway, and the modal draws it in its own block under the summary. Only the Claude Code shell-command prompt has one: the generic adapter's
command, a quoted fragment of the question such as a file name or the wordyes, is read by the policy and is not shown. Each line is redacted as the journal redacts values and keeps the text after a masked value, soTOKEN=x curl ... | shreadsTOKEN=[REDACTED] curl ... | shrather than stopping at the mask; the line breaks are kept, and the command is cut at eight lines of 200 characters, with a mark where it was cut. A bidi override or a zero-width character shows as a replacement character instead of reordering or hiding what is read. A prompt that is a secret (marked sensitive, or a credential) carries none. The redaction knows common credential forms only: a flag whose argument is the secret (mysql -pSECRET), a password piped to a command and a bare key with no known prefix are shown. The command is read from the agent's screen by rules that fit the layouts seen, so it is advisory: check it against the terminal before you allow anything. The TUI does not show it. The command is never written to the audit journal. -
A viewer is never sent the command. The gateway removes it from every frame and every state a viewer receives, as it removes the host's version and the journal's path. With the terminals shown, a viewer can still read the command where the agent printed it;
--viewer-terminals hiddencloses that. An operator's copy is left as it was.
Fixed
-
A shell command Claude Code asked about could become a tool-call badge that every client was shown. The badge is read from the same screen text as the prompt, so a command that names
mcp__a__bfollowed byhost=...produced a badge whose parameters held the rest of the command, redacted but otherwise as the agent typed it, in the prompt card of every client, viewers included. A Claude Code shell-command prompt asks about a command, not a tool call, and no longer carries a badge. A genuine MCP tool-call prompt keeps its badge, with its redacted, bounded parameters, for viewers too, as the web gateway documents. -
The gateway sent the unmasked frame to any role but a viewer. There are only two roles, so nothing reached a client it should not have; the choice now fails closed, and an operator alone is sent the frame with the command in it.
-
The last lines of output in the decision modal were the terminal's raw text. For a Claude Code shell command they carried colour codes, cursor movements and window-title strings, which the modal printed as stray characters or let split a word into two. They are now taken out before the lines are cut and redacted, so a secret that an escape sequence split in two is one text again when it is redacted. A cursor move to the right becomes spaces, since Claude Code spaces its words that way; the other moves are dropped, so a screen the agent painted by positioning the cursor reads as the text it wrote, not as the grid a terminal shows. A line is cut at a character, not through an emoji, and the redaction is run on at most 1,024 characters of a line: the URL pattern is quadratic in a long run of letters and digits, and 256 KiB of them an agent prints would have frozen the window.
Full commit list: v0.8.18...v0.8.19
v0.8.18
Patch release built with Go 1.26.9, which fixes the standard library advisories in net/http, crypto/tls, net/textproto and mime/multipart that every earlier release carried. A high-risk prompt, such as a shell command Claude Code asks about, is no longer masked as confidential, and a URL that does not parse no longer prints its credentials, a leak the move to Go 1.26 exposed.
Fixed
-
A high-risk prompt was displayed as a confidential one. The display mask covered every high-risk event, so a shell command Claude Code asks about showed the title "Confidential input required", a masked answer field and no command — the command had to be read in the terminal. Masking now covers only what is a secret: an event the adapter marked sensitive, or a credential prompt. A high-risk prompt keeps an honest label and takes a normal, visible answer, in the decision modal and in the TUI, whose notifications now carry the summary the prompt is shown with rather than the adapter's raw text. The decision modal also shows the last lines of the agent's output, redacted and cut; for a Claude Code shell command they are the terminal's raw text, escape sequences included. The command itself is still not in the prompt's summary, which for Claude Code is a constant: read it on the agent's card. A prompt whose text contains
token,secret,passwordorotp, even inside a longer word such asfootprint, is still marked sensitive and still masked. The audit journal is unchanged: a high-risk entry is still recorded sensitive, with the constantsensitive_eventsummary. -
A URL that does not parse no longer prints its credentials. The redaction that every summary, notification and journal entry goes through returned a URL it could not parse unchanged. Go 1.25 parsed
https://bot:secret@host:443:443/repo.gitand masked its user and password; Go 1.26, which Relayer is now built with, refuses a host with an extra colon, so the password stayed in clear. The text up to the last@of a URL that does not parse is now masked, whatever the URL would have meant.
Security
- Relayer is built with Go 1.26.9. The Go standard library has advisories in
net/http,crypto/tls,net/textprotoandmime/multipart(GO-2026-6603, GO-2026-6607, GO-2026-6608, GO-2026-6613 and GO-2026-6617 among them;govulncheckreported at least seven) that are fixed in Go 1.26.9 and in Go 1.27.2. Go 1.27.0 and 1.27.1 are affected. The 1.25 series, which every release was built with (1.25.13 from v0.1.1-alpha to v0.8.17, 1.25.8 for v0.1.0-alpha), is no longer supported and gets no fix. The web gateway servesnet/http, and the desktop's update check and the webhooks speak HTTP and TLS as clients. Building from source needs Go 1.26.9, or 1.27.2 or newer. Moving thegoline to 1.26 also changes the defaults of threeGODEBUGsettings: TLS clients offer two more hybrid ML-KEM key exchange groups, andurl.Parserefuses a host with an extra colon (see the fix above).
Full commit list: v0.8.17...v0.8.18
v0.8.17
Patch release that lets Relayer see the prompts Claude Code asks before it runs a shell command or creates a file (2.1.285 and 2.1.286) or edits one (2.1.285), which an agent waited at unseen until now, and that makes a panic while reading one agent's output end that agent's session instead of the whole process. A person answers those prompts: Allow and Deny are not offered for Claude, since no answer to them has been checked against a real Claude Code, and the rules rest on 2.1.285 cases of unconfirmed provenance and on 2.1.286 test strings. The desktop application and the gateway also flag an agent whose version they were not verified against; the probe that finds the version runs only the agent's own binary, inside its deadline and outside the gateway's state lock.
Added
-
The Claude adapter recognizes the prompts Claude Code asks before it runs a shell command, creates a file and edits a file. The adapter knew only the workspace-trust and environment-key prompts of 2.1.59, so an agent stopped at any of these waited for an answer nobody was asked for. The shell-command and create-file prompts of 2.1.285 and 2.1.286 and the edit-file prompt of 2.1.285 are now raised as events: the shell command as a high-risk
permissioncarrying a best-effort reading of the command Claude Code displays, the other two asconfirmations of unknown risk. A person answers all three at the terminal. The desktop and web decision modal take a typed answer too, but for the shell command it shows the title "Confidential input required", the agent, adapter, risk and rule, and a masked field, but not the command, the terminal output or the options, so read the command in the terminal. Create and edit are unknown risk, not low, so no policy allows them by itself: what Claude Code is asked to write decides what runs next (.github/workflows,.claude/settings.json, apackage.jsonscript), and the guardrails only partly cover that. A deny a policy would give is handed back to a person, since the adapter has no verified deny byte. Allow and Deny buttons are not offered in the modal; the TUI still lists F2 and F3, which write nothing and bring the prompt back. No answer to these prompts is backed by a stored capture of its effect: Enter is expected to take the highlighted option, which Relayer does not read, so answer at the terminal. The 2.1.285 cases have unconfirmed provenance and the 2.1.286 layouts are test strings, not fixtures; the 2.1.59 workspace-trust and API-key rules also recognize the unnumbered menu Claude Code draws in 2.1.286, from test strings only. Other prompts Claude Code asks (overwriting an existing file, a PowerShell command, a web fetch, an MCP tool) have no rule and no stored capture: one is raised only if its text happens to match one of the five rules or an intercept_pattern, and otherwise the agent waits unseen. -
The desktop application and the gateway flag an agent whose version they were not verified against. When a run starts, each vendor agent's own binary is run as
--version, and an agent whose version is not one its adapter's patterns were captured against is marked "unverified version" on its card and in the decision modal, since its prompts and the answers it expects may differ from what the adapter knows. It is informational and stays that way deliberately: it changes no policy, an unverified version does not refuse an automatic decision, and nothing is written to the audit journal. The TUI andrelayer doctordo not run it. See the security model. -
RELAYER_NO_VERSION_CHECK=1turns the version probe off for every user of a machine, asRELAYER_NO_UPDATE_CHECKturns off the desktop's release check: nothing is executed and no badge is shown. It is an environment variable rather than a configuration key because the probe runs a child process on the host — a machine-level concern, an endpoint agent that flags process spawns or a network home directory — whileconfig.yamlis per-project, strict-schema and travels through version control. A probe's answer is now cached per executable path until that file's modification time or size changes, so restarting a run does not run every vendor tool again; an upgrade changes the file and asks the new binary.
Fixed
-
A panic in the goroutine that reads an agent's output ends that agent's session, not Relayer. Nothing recovered a panic there, so a bug in an adapter, or output an agent chose to make it trip, ended the whole process and with it the supervision of every other agent, in the TUI, the desktop application and the gateway. The reader now returns the panic as the error that ends that session, like any other processing failure, with the runtime error's message (numbers and type names, never text from the agent) or, for any other panic value, only its type, and the place it came from. A PTY agent's terminal is closed with its reader, as after any reader failure; with tmux the pane keeps running with nobody reading it, so stop it from the interface. A panic in the same adapter code reached when a policy answers a prompt, or when a gateway call delivers an answer, is still not recovered and ends the whole process. In the TUI, Bubble Tea catches such a panic (a policy answer, a tmux re-synchronization), prints it, restores the terminal and ends the TUI, and with it the supervision of every agent.
-
A very small browser terminal could blank a Windows agent's screen. A terminal pane that had not been laid out yet, or a phone-sized one, sent a resize of a few columns, and the Windows pseudo-console could blank the screen it kept. The gateway now raises any resize to at least 40 columns by 15 rows, the browser terminal reports no size under 20 by 8, and the terminal pane has a minimum height of 250 px, so a narrow pane gets a wider PTY than it shows. The desktop application's own resize call is not clamped.
-
The version probe replayed the command line it was told to run. Starting a run executes each vendor agent's own binary as
--version, to compare its version with the ones its adapter's patterns were captured against. Forsh -candcmd /cit rejoined the configured arguments, appended--versionand ran the whole script again, so a configured command's side effects happened twice per start — a marker file the script wrote was written once by the probe and once by the agent. A launcher (npx,node,python,docker) reported its own version as the agent's, and an agent configured withshell:and no argv probed whateverclaudethePATHhappened to resolve. The probe now runsargv[0]alone, with none of the configured arguments, and only when its base name — without a Windows.exesuffix — is exactly the adapter's own executable (claude,codex,aider,goose,interpreter); anything else is not probed, and shows no version and no badge. On Windows,sh.exeandcmd.exefail that test by name. -
The probe's 2.5s timeout did not bound the probe. Killing the process left the wait for its output pipes, which a grandchild that inherited stdout — a daemon the tool spawned, a pager, a hung child — held open for as long as it lived. Every agent was probed in turn, and on
relayer servethat ran under the gateway's state lock, so one such tool stalledgetStatefor every connected operator and viewer. The wait is now bounded 500ms past the process, a run's probes run in parallel within a 4s budget, and the gateway runs them before taking its state lock. What a probe reads is bounded at 64 KiB, and is stdout alone, on the line that names the product: a banner or a launcher's own version no longer becomes "the agent's version" that every client saw. -
A viewer received the host's tool version.
installedVersionand the reason text that quotes it crossed to viewers with the rest of the state, as the startup notices carrying the same reason did not. A viewer now receives the unverified flag alone — that an agent's version is not one this build was verified against is supervision information, and a viewer watching a prompt should have it — and neither the version nor the reason: which build of a tool a machine runs is host tooling state, like the notices and the journal's path thatgetStatealready hid. -
An agent whose adapter the configuration left empty was never warned. The probe tested the configured adapter, so
command: [claude]with noadapter:— which the run resolves to the Claude adapter — showed nothing whatever its version, while an adapter the registry resolved away to generic was probed on the configured name alone. The check now uses the adapter the run resolved. -
The version warnings were in French, while every other string a run shows an operator is English: the reason a version is unverified, the startup log's
Avertissement, and the desktop badge'sversion non vérifiée.
Full commit list: v0.8.16...v0.8.17
v0.8.16
Patch release whose Aider, Open Interpreter and Goose adapters read the questions those agents actually ask, captured from real sessions, and answer with bytes observed to do what they say. Goose's deny, n and Enter, would have allowed the tool call on Goose's real menu; it now picks Deny. A web gateway can keep the agents' terminals from its viewers with --viewer-terminals hidden, and a keystroke to an agent that reads nothing now gives up after five seconds on macOS, the BSDs and Windows as it did on Linux.
Fixed
- The Aider adapter read the questions Aider asks, not questions it was guessed to ask. Its patterns were written by hand from documentation and never checked against Aider. Captured from Aider 0.86.2 in a PTY, against a stand-in model and a disposable repository, half of them turned out to be questions Aider never asks ("Apply changes?", "Commit changes?", "Push to remote?", "Add files to git?"), while "Add .aider* to .gitignore (recommended)?" went undetected and "Add command output to the chat?" and "Allow edits to file that has not been added to the chat?" were both reported as adding a file to the chat, the second one a file edit shown as a low-risk question. The adapter now reads the six questions captured, each answered with
yand Enter and withnand Enter and its side effect checked, and nothing else: an Aider question not among them falls back to the configuredintercept_patterns. The fixtures are ininternal/adapters/testdata/aider. - The Open Interpreter adapter read the questions Open Interpreter asks. Its patterns were written by hand from documentation. Captured from Open Interpreter 0.4.3 in a PTY, against a stand-in model, it asks two questions, "Would you like to run this code? (y/n)" and, under
--safe_mode ask, "Would you like to scan this code? (y/n)", and nothing before installing a package or saving a file; the hand-written "run the following code" and "run this command" wordings were never printed. It also prints the question, then two line breaks and the indentation it reads the answer on: written in one piece, the question was two lines above the line the adapter looked at, and was seen only when a repaint happened to precede it. The adapter now reads the two captured questions, each answered withyand Enter and withnand Enter and its side effect checked, on the line above the answer line too. The fixtures are ininternal/adapters/testdata/interpreter. - The Goose adapter's deny would have allowed the tool call. Its patterns were written by hand from documentation, as
(y/n)questions answered withyornand Enter. Captured from Goose 1.52.0 in a PTY, against a stand-in model, Goose asks no such question: it asks before a tool call with a menu (Allow, Always Allow, Deny, Cancel), whereyandndo nothing and Enter picks the highlighted option, Allow.nand Enter was observed to run the command. None of the patterns matched Goose's output, so the adapter never sent it, and no Goose question was ever detected either. The adapter now reads the two menus Goose draws, "Goose would like to call the above tool, do you allow?" and "Do you allow this tool call?" (drawn when a check attached a notice, as for extension management), in Unicode and ASCII, and answers with the keys that pick Allow or Deny wherever the highlight is:kto the top,jdown, Enter. Each answer was typed into Goose and its effect checked. Manual input namesallow,denyorcancel. The fixtures are ininternal/adapters/testdata/goose. - A question drawn over several lines could be lost when a read ended inside a line break or a character. Before the screen took over detection, a read that ended between the
\rand the\nof a line break erased the line it ended, and one that ended inside a UTF-8 character had its bytes replaced. Goose's menu read a byte at a time left nothing of itself to detect. The detection window now holds either back for the next read. - A web keystroke to an agent that reads nothing could block for good on macOS, the BSDs and Windows. Once such an agent's terminal input buffer is full, a write waits for room. On Linux the gateway's keystrokes gave up after five seconds; elsewhere the write blocked until the agent read again or exited, and held the session's write slot, and the run's end, with it. On macOS and the BSDs the terminal is now written through the runtime's poller, as on Linux, which the five-second bound and a Stop both end; on Windows a timer cancels a console write still blocked at its deadline.
TestAKeystrokeWriteToAnAgentThatReadsNothingEndsWithItsContextnow runs on macOS, andTestAKeystrokeWriteToAWindowsAgentThatReadsNothingEndsWithItsContexton Windows.
Added
relayer serve --viewer-terminals hiddenkeeps the agents' terminals from viewers. A viewer token was a token to read every terminal: the snapshots carry each screen verbatim, so a secret an agent echoed reached every viewer, and the only choice was not to hand viewer tokens out. With the option, a viewer's state and snapshots carry each agent's status, exit code and prompt card but no output, a recording's contents are refused to it, and its interface says why in place of each terminal. Operators are unaffected, and the default,shown, keeps the behaviour as it was.
Full commit list: v0.8.15...v0.8.16
v0.8.15
Patch release whose desktop application says when a new version is out. At launch it asks GitHub for the latest release and offers its download in a banner; the check is on by default and turned off in the settings. The desktop binaries now carry their version, so this release is the first that can tell a newer one apart: the banner appears from the next release on. As PID 1 in a container without an init, Relayer also reaps the orphans a stopped agent leaves behind.
Added
- The desktop application tells you when a new version is out. At launch it asks GitHub for the repository's latest release and, when it is newer than the running one, shows a banner with a Download button: on Windows it downloads the new installer, elsewhere it opens the release page. Not now sets that release aside until the next. The request carries nothing but the running version; the check is turned off in Settings → Notifications, or for every user of a machine with
RELAYER_NO_UPDATE_CHECK=1. A link only ever leads to a release of this repository, whatever the response names, and Relayer installs nothing by itself. Until now a user had to watch the Releases page. The desktop binaries of a release now carry its version, which the check compares; they saiddev. The README's privacy section says so.
Fixed
- Relayer running as PID 1 left every stopped agent's orphans in the process table. In a container started without an init, Relayer adopts every orphan, and nothing but Relayer can reap them. v0.8.14 stopped counting those zombies when it confirmed a stop, but left them behind, so each Stop of an agent whose shell had started a child added one for good. When a stop leaves an agent's process group with nothing but zombies, Relayer now waits for those that are its own children. It waits only for members of that group and never blocks, so it cannot take the exit status of a process it waits for elsewhere; a process that left the group, or anything else in the container, is still left to an init, which
docs/web-gateway.mdstill asks for.TestStopIsConfirmedWhenAnOrphanIsLeftAsAZombienow also fails against v0.8.14.
Full commit list: v0.8.14...v0.8.15
v0.8.14
Patch release that stops a zombie from blocking an agent. Where orphans are reaped late or not at all (Relayer as PID 1 in a container without an init, the Kubernetes default, or an init that reaps on a timer), stopping an agent whose shell had started a child was reported as unconfirmed, which blocked its next run. On Linux, Relayer now confirms a stop whose process group is left only with zombies; relayer-capture had the same fault and is fixed too.
Fixed
- A Stop was reported as unconfirmed when the agent's shell had started a child, wherever orphans are reaped late or not at all: in a container where Relayer is PID 1 without an init, the Kubernetes default, and under an init that reaps on a timer, as some sandboxes do. The shell dies without waiting for its child, which is killed with the group and stays in it as a zombie until whoever adopted it reaps it; Relayer probed the group by number, found the zombie, and reported every such Stop as unconfirmed, which blocks the agent's next run. A zombie runs nothing and holds no descriptor, the terminal included, so on Linux the check that follows the forced kill now reads the group's members in
/procand confirms a group left only with zombies. A process counts as a zombie only once it is down to its last thread. The group counts as running whenever/procmight not show all of it: mounted from another PID namespace, or withhidepid. Other systems check as before.relayer-capturewaited for the same zombies after killing a capture's process group, and failed the capture when that wait ran out, after about two seconds, or six with tmux, which waited twice; it now counts them as the session does.TestStopIsConfirmedWhenAnOrphanIsLeftAsAZombie, andTestACaptureEndsWhenAnOrphanIsLeftAsAZombiewith its timed-out and tmux counterparts, fail against v0.8.13.docs/web-gateway.mdstill asks fordocker run --init: Relayer does not reap the zombies, it only no longer counts them.
Full commit list: v0.8.13...v0.8.14
v0.8.13
Patch release that gives Windows an installer. relayer-desktop_0.8.13_windows_amd64_setup.exe installs Relayer for the current user, without administrator rights, with a shortcut on the desktop and in the Start menu; the zip remains for those who prefer it. The Windows executable now carries the release's version.
Added
- A Windows installer,
relayer-desktop_<version>_windows_amd64_setup.exe, next to the zip. It installs Relayer for the current user in%LOCALAPPDATA%\Programs\Relayer, without administrator rights, with a shortcut on the desktop and in the Start menu, installs the WebView2 runtime when Windows lacks it, offers to start Relayer when it ends, and registers an uninstaller in Settings → Apps that leaves the configuration in%APPDATA%\relayerin place. Until now Windows users extracted a zip and had to make their own shortcut. The installer is built on every change by the GUI workflow, whose run keeps it as an artifact, and published with the release, included in the desktop checksums, their signature and the provenance attestation. The executable and the installer now carry the release's version; they said 1.0.0. The installer is not code-signed, so SmartScreen may ask to confirm it.
Full commit list: v0.8.12...v0.8.13
v0.8.12
Patch release that makes the desktop app usable again: since v0.8.9 at least, it opened on an empty window. An idle application sent its agents to the interface as null, and the interface stopped before drawing anything. The web gateway was not affected. Release pages now show this CHANGELOG's section for the tag rather than the raw commit list.
Fixed
- The desktop app opened on an empty window, on every launch, in v0.8.9, v0.8.10 and v0.8.11 at least. An application that has just started is idle and has no agents; the copy of its state that
GetStatereturns turned that empty list into a nil slice, which reaches the interface as"agents": null, and the interface read it as a list before its first render, so nothing was drawn but the window's background. The state's lists are now always lists, and the interface takes a null list as empty.TestAnIdleApplicationSendsItsListsAsListsand arelayerStatetest fail against v0.8.11. The web gateway builds its lists another way and was not affected. Found by the v0.8.11 trial on Windows.
Full commit list: v0.8.11...v0.8.12
v0.8.11
Changelog
- d26244c Revert "chore(release): fold the unreleased fixes into v0.8.10"
- 4a4a5d8 build(web): rebuild the embedded interface
- c2a60e2 chore(release): fold the unreleased fixes into v0.8.10
- 843f8e6 chore(release): prepare v0.8.11
- ef014c4 fix(config): a notifications save keeps the block as written
- 9482b1a fix(config): a replaced webhook is a new entry, a blank severity is rewritten
- 4e52959 fix(config): switching from strict to permissive keeps the root relative
- 4d7897d fix(gui): a click on a settings tab switches the tab
- aa4e15d test(settings): the Windows trial in sequence, on both front ends
v0.8.10
Patch release that stops a settings save from losing configuration. A save from the web interface rebuilt every agent from the form alone, so it dropped every agent's environment variables and shell script, and "Restart the agents" did so even when nothing was edited, restarting the agents without their environment; on both front ends a save reformatted agents it had not changed, and the security tab dropped settings it did not show. A save now writes only what was edited, and a save that changes nothing leaves the file as it was.
Fixed
-
A save from the web interface lost every agent's environment variables and shell script, and has since
relayer servewas introduced in v0.5.0. The gateway rebuilt each agent from the form alone, and the form carries neither: every save of the Agents tab wrote each agent back without itsenv, API keys included, and turned ashell:agent intocommand: [<id>], a program named after the agent. It also wrote the catalogue's adapter over a blankadapter. "Restart the agents" sends the agents even when nothing was edited, so a plain restart did the same, and the agents came back without their environment. The gateway now shows and saves agents through the desktop's resolver, now shared (internal/agentprofile), asdocs/configuration.mdalways said it did:- an agent with environment variables, a shell script or an adapter the form does not know is read-only in the editor, and every save copies it exactly as the file has it. A save that leaves it out, or sends its ID as a new agent or with a command, is refused and writes nothing;
- an existing agent keeps its command and adapter; the form changes its name, working directory and backend, and replaces its command only as a whole;
- an agent removed and added again under the same ID is a new agent and inherits nothing from the one it replaces, its environment included;
- the interface sends
preserve, which the gateway read aspreserveOnSaveand so never saw; - a configuration written by hand often could not be saved from the web interface at all: the gateway named no catalogue entry for a custom command or a shell agent and showed a blank adapter as blank, which the form refuses, so Save and Restart stayed disabled. Every profile now names a catalogue entry and the adapter the agent runs with.
TestAWebRestartKeepsEachAgentsEnvironment,TestAWebSaveKeepsEveryAgentItDidNotChange,TestAWebSaveCannotDropOrReplaceAReadOnlyAgentandTestTheWebProfileViewShowsNothingItCannotRoundTripfail against v0.8.9. A file edited while the editor is open is refused as stale on both front ends, so a save can neither drop an environment variable added in the YAML nor bring back one removed there (TestAnEnvironmentEditedWhileTheWebEditorWasOpenIsNeitherLostNorRevivedand its desktop counterpart). Found by the v0.8.9 acceptance pass; v0.8.8 did the same. -
Saving the agents rewrote every agent in the file, on the desktop and the web gateway alike, since the agent editor was introduced in v0.1.0-alpha: a desktop save that changed one agent, and on the gateway every save of the Agents tab and every "Restart the agents", rebuilt every entry. Every agent lost its comments, flow sequences became block lists, a shell script's quoting changed, and every agent that inherited the file's
backendwas pinned to it withbackend: pty, so a later change of the file's backend no longer reached it. A relativecwdcame back as an absolute path naming the user's home directory for an agent added again under a new ID. An agent a save did not change now keeps its entry as written, its values, comments, flow sequences and quoting; a changed agent keeps every field it did not change where it was, and a changed field keeps its comment (TestAReplacedCommandKeepsItsComment); a new agent in a directory another entry already names gets that entry's relative text; the file keeps its Windows line endings and byte-order mark, where a rename in a CRLF file changed every line (TestASaveKeepsTheFilesLineEndingsAndByteOrderMark); and a save that changes nothing writes nothing: the revision stays, and no open editor has to reload. A save that writes still re-encodes the whole file, so blank lines between entries, folded and multi-line plain scalars, escape sequences, the spacing before a comment and the%YAMLand---markers are normalized wherever they are;docs/configuration.mdlists them. Every value loads back the same. Both front ends also issued a new revision token after every save, written or not, so after one tab saved without a change, or restarted the agents, another tab's next save was refused as stale and the interface replaced that tab's unsaved edits with the file; a token is now issued only when a save writes the file. The writer also refuses to publish a file that would not load back as the agents requested.TestSavingOneAgentLeavesTheOthersAsWritten,TestRenamingOneAgentOnTheDesktopLeavesEverythingElseAsWritten,TestAWebRenameLeavesEverythingElseAsWritten,TestAWebRestartWithNothingEditedWritesNothing,TestASaveThatChangesNothingLeavesEveryOpenEditorCurrentandTestADesktopSaveThatChangesNothingLeavesTheRevisionAsItWasfail against v0.8.9. -
A security save rewrote the whole
policiesblock, on the desktop and the web gateway alike, since the settings editor was introduced in v0.3.0: the block was rebuilt from the effective policy, which drops what that rebuild does not write. A save that only toggled dry-run, or changed nothing, removedprofile: customand every guardrail set tofalse, and lost the block's comments and flow lists; since v0.8.6, which resolves a relativeworkspace_rootwhen loading, it also wroteworkspace_root: ./workspaceback as an absolute path naming the user's home directory. The block is now edited: a field whose value the file already gives keeps its text, a changed field is written where it is, a profile the file names stays as the base of the fields it does not set, and a save that changes nothing writes nothing. An absolute or rootedworkspace_rootkeeps its text too: the loader now cleans it as the save does, so a save no longer rewrites/srv/wsas\srv\wson Windows, which Linux does not read as that directory, so that with a configuration shared with Linux every path an agent named there was outside the workspace, or drops a trailing separator (TestASecuritySaveKeepsAnAbsoluteWorkspaceRootAsWritten). Turning the workspace guardrail on in a file that names no root writes only the guardrail: the save also wrote the root the guardrail defaults to, the configuration's directory, as an absoluteworkspace_root, which then no longer followed the file when it moved (TestTurningTheWorkspaceGuardrailOnWritesOnlyTheGuardrail). When the editor switches to a preset and the file names a profile, the file names that preset, also when a field was adjusted after the preset was chosen: the writer recognized only a preset the policy matched exactly, so choosingstrictand then setting the rate limit dropped theprofileline and its comments and wrote every field ofstrictout (TestAPresetChosenThenAdjustedIsNamedWhereTheFileNamesAProfile,TestAWebPresetChosenThenAdjustedIsNamedInTheFile,TestADesktopPresetChosenThenAdjustedIsNamedInTheFile). The writer refuses to publish a file whose policy would not load back as requested.TestASecuritySaveChangesOnlyWhatItChanged,TestAWebSecuritySaveKeepsThePolicyAsWrittenandTestADesktopSecuritySaveKeepsThePolicyAsWrittenfail against v0.8.9. Found by the v0.8.9 acceptance pass; v0.8.8 did the same. -
Turning the workspace guardrail on from the web interface guarded a directory that does not exist when
relayer servewas given a relative--config, since v0.8.6. With the root field left empty, the root is the configuration's directory; the gateway passes that directory as its command line gave it,cfg, and the save resolved it against itself, writingworkspace_root: <cwd>\cfg\cfg, so every path an agent named was outside the workspace. The default root is now resolved once, against the configuration's directory. The desktop passes an absolute directory and was not affected.TestAWebGuardrailOnARelativelyAddressedConfigurationGuardsItsDirectoryandTestTheDefaultWorkspaceRootOfARelativelyAddressedConfigurationIsItsDirectoryfail against v0.8.9.
Changed
- The web gateway no longer sends an agent's existing command line to operators, as the desktop never has: an argument can be a credential, and every operator token received it. The Agents tab shows each agent's executable label and argument count, and Replace the command starts a new argv from the catalogue's default. A client that saves agents through the gateway's API must send an existing agent back with
preserveand noargv, and a new one with its cataloguepresetIDand an adapter that profile supports, as the interface does. A read-only agent sent back withpreservekeeps the file's name, working directory and backend; any sent with it are ignored.
Full commit list: v0.8.9...v0.8.10