Releases: HarperZ9/relay
Release list
Relay 0.7.0
- Opt-in local-first cascade:
relay.cascade.Cascadeasks a local classifier a yes-or-no question first and calls your model endpoint only when the classifier abstains. Each answer goes to the session ledger with who answered it. The bundled "is this test failure flaky?" classifier missed both bars set before the run. On 81 held-out failure tails it decided 23% of questions, under the 50% bar, at 0.89 accuracy, under the 0.95 bar. The default threshold, 1.0, therefore sends nearly every question to the endpoint. A shuffled-label control reached 0.79. A substring defect found after the first run is fixed, and both runs are recorded. Details, the bar and the limits:docs/CASCADE.md. - The Claude plugin folder now carries the server code at
client-plugin/server/src/relay/, limited to the modules the plugin launch can import.python scripts/build_client_package.py --sync-vendoredrewrites that copy fromsrc/, and a test fails when it drifts. The remote server's modules, which name its OAuth secrets, are no longer shipped in the folder or the source ZIP. - The Claude manifest passes
--no-cli-tiers, so the plugin never builds a claude or codex CLI backend and uses one credential, the API key setting. It adds the plugin directory listing fields and a 1024 px icon, and takes the project folder, the write and exec grants and an optional hosted model fromuserConfig. The client adapter clears hosted-model keys, gateway URLs and model names from its starting environment and sets only the provider the launch names. - Every MCP tool carries a title,
readOnlyHintanddestructiveHint. README and PRIVACY list the launch command, every network destination, every file written and every environment variable the server reads. - Release checksum files are written with LF line endings on every OS, and the release workflow refuses a checksum file that contains a CR byte.
- The native release gate sends its loopback fixture through the hosted-model launch settings a user fills in. The first 0.7.0 tag failed this gate before anything was published: the launcher now clears ambient gateway URLs, and the gate still set the fixture gateway in the environment, so the granted write found no backend. The same gate now runs through
python serve.pyin ordinary CI on every platform, so a launcher change that breaks it fails before a release.
Source version metadata is not release availability proof; release availability is established only by the accepted Git tag, uploaded GitHub Release assets, and matching hash readback. Do not publish or recommend the bare PyPI name relay-agent; it belongs to another project.
Relay 0.6.0
- Adds default-off file-change and command-execution switches to MCPB setup. Strict boolean launch arguments retain the existing grants; native fixture workflows check both enabled permissions and refusals without a real model.
- Fixes a Windows restart-read race: completed background runs no longer replace their durable record again after publishing the terminal state. Failed final persistence reports an error and preserves the request binding when that error record can be written.
- Adds portable, Claude and Codex client manifests, a scoped skill, privacy guidance and troubleshooting.
- Adds deterministic source plugin ZIPs and self-contained Windows x64 ZIP/MCPB candidates with runtime licenses, checksums and dependency provenance. Source ZIPs still require Python.
- Requires an explicit absolute RELAY_MCP_ROOT binding. Ambient environment variables cannot grant write or execution access. Explicit --allow-write and --allow-exec launch flags preserve the existing permission model; exec implies write and is not an OS sandbox. Synthetic tests cover an approved bounded file write and denied execution. Native model-driven runs remain unverified and require a user-owned endpoint.
- Adds clean, tag-bound release packaging for .0 versions. Linked inputs, untracked release payloads, state files and credential file types are refused. The release workflow attaches checked client packages alongside the product release.
- Real Windows stdio checks cover identity, source/version parity, discovery and permission refusals without a model account. Installed-client compatibility, clean-OS compatibility, signing and marketplace admission remain open gates. No publisher backend, model, network listener or service is installed.
Source version metadata is not release availability proof; release availability is established only by the accepted Git tag, uploaded GitHub Release assets, and matching hash readback. Do not publish or recommend the bare PyPI name relay-agent; it belongs to another project.
Packaging note (2026-10-01): The bundled README's generic “development bytes” paragraph describes the packaging template's development mode. The attached versioned client packages were built in release mode from this release's exact tag. QUALIFICATION.json records the source commit and release qualification; the published checksum files identify the downloadable bytes. Code signing, client GUI acceptance and marketplace listing are not established by these build receipts.
relay 0.5.0
0.5.0, 2026-09-27
A program planted in a project folder no longer runs through a PATH entry that
reaches that folder. 0.4.0 started its children through safe_spawn 1.0.0,
which skipped only relative PATH entries. This release vendors safe_spawn
1.0.1 and hands it the folder each child works in.
This was prepared as a 0.4.1 patch. It takes the minor number instead because
it changes what existing setups do, the rule 0.3.0 set for a pre-1.0 break: a
run, test_cmd or check command, or a git hook or filter during
--auto-commit, no longer finds a program through a project folder on PATH,
such as .venv/bin or node_modules/.bin, unless that folder holds the
interpreter relay runs on. A pin such as ~=0.4.0 excludes this release;
widen it to take the fix. The MCP tool names, the relay.mcp-run-request/v2
binding and the shapes of relay.status and relay.doctor are unchanged.
Source version metadata is not release availability proof; release availability
is established only by the accepted Git tag, uploaded GitHub Release assets, and
matching hash readback. Do not publish or recommend the bare PyPI name
relay-agent; that public namespace belongs to an unrelated project and is not
the HarperZ9 Relay distribution.
Security
- An absolute
PATHentry could reach a folder a child works in: the server's
folder, the root of arun,test_cmdorcheck, the project a bisect
check copies, or the repository--auto-commitcommits to. The entry could
name the folder or a folder below it, spell it another way, or lead there
through a junction or symlink. On Windows a quoted entry such as
"C:\proj"\binreached it too, because cmd.exe drops the quotes. A program
planted there ran in place of the installedclaude,codexorgit,
including the--versioncheck thatrelay.doctorstarts under exec, and a
shell child found it by bare name. Affected: every release through 0.4.0.
0.4.0 closed the direct search of the server's folder and left these routes
open. gititself ran with thatPATH, so a program git starts by bare name ran
from the repository: a clean filter the repository selects in
.gitattributes, orgpgwhen commits are signed. Affected: every release
through 0.4.0.- On Windows a drive-relative name such as
C:claudenamed a file in the
current folder of drive C:. relay's own tiers use fixed names, so this needed
a caller that builds aCliBackendwith such a name. It is now refused with
BAD_PATH.
Changed
- The vendored
safe_spawnis 1.0.1 (src/relay/_vendor/safe_spawn.py,
SHA-256 recorded inVENDORED.sha256). It drops everyPATHentry that
reaches the server's folder or the folder named for the child, from the
lookup and from the child'sPATH. Folders are compared by name and by file
identity after links are resolved. run,test_cmdandcheckhand their root to the helper. A bisect check
runs in a fresh copy of the project, so it hands the helper the project it
copied.--auto-commitresolvesgitwith the repository as the named folder, and
starts it with aPATHguarded the same way. git keeps the rest of its
environment (HOME,GNUPGHOME,SSH_AUTH_SOCK, itsGIT_variables). One
lookup serves every git call of a commit.- A command in
run,test_cmdorcheckthat found a program through a
folder inside the root or the server's folder, such as a project's
.venv/binornode_modules/.bin, now needs that program's path
(.venv/bin/pytest). So does a git hook or filter that found a program that
way during--auto-commit. The folder that holds the interpreter relay runs
on stays onPATH, so starting relay from the project's virtual environment
keeps that environment's tools (.venv/bin, or.venv\Scriptson Windows).
Tools in other folders inside the project, such as a Windows conda
environment'sScriptsandLibrary\bin, need their path. On Windows the
Windows, System32 and SysWOW64 folders also stay. - A child's
PATHnames each kept folder as its real folder, with links
resolved, so a link repointed after the check cannot change what starts. On
merged-/usr Linux,/binreaches a child as/usr/bin. - On Windows,
PATHis read the way cmd.exe reads it, quotes included. An entry
whose folder name holds;is left out, since Windows programs disagree on
how to read it. - On POSIX, a
PATHthat the filter leaves empty reaches the child as
/bin:/usr/bin, because an emptyPATHmeans the current folder there.
Limits
- When the server's folder or a run's root is a filesystem root, or holds the
home folder, only an entry naming that folder itself leaves. The tool folders
below home, such as~/.local/bin, stay. - The check reads the filesystem before the start. Swapping the program file,
or a folder inside a kept folder, between the two still wins. That needs write
access to a folderPATHalready trusts. - On a filesystem without file indices, such as some network shares, every
PATHentry on the working folder's device leaves. A CLI there needs
RELAY_CLAUDE_CLIorRELAY_CODEX_CLI, and a shell tool there needs its
path. - Each start reads every
PATHentry, a step that took under 1 ms on 0.4.0.
On Windows, with 58 entries, one read took about 11 ms. Under WSL with the
WindowsPATHappended (67 entries, 58 of them under/mnt) it took 0.5 to
1.3 s, and under 1 ms with the/mntentries removed. Every shell child and
every CLI tier start pays at least one read. An--auto-commitreadsPATH
once for all its git calls, about 1.3 s there against 12 ms on 0.4.0. - The new tests ran on Windows 11 and on Linux (Ubuntu 24.04 under WSL2).
macOS was not run.
relay 0.4.0
The session store stays inside itself, and every program relay starts gets an
environment allowlist and, for the claude and codex tiers, a proven isolation
profile. This was scoped as a 0.3.1 patch. It takes the minor number instead
because it changes what existing setups do, the rule 0.3.0 set for a pre-1.0
break:
run,test_cmdandcheckno longer inherit the server's whole
environment. A command that reads a variable outside the allowlist, such as a
test suite that needsDATABASE_URLor a provider key, sees it unset until
RELAY_CHILD_ENVnames it.- On Windows a shell no longer finds a program in the root by bare name. Call it
as.\tool. - The
claudetier runs with--tools ""and thecodextier with a read-only
sandbox, both in a new empty folder. A setup that used either tier as a
sub-agent acting on the project gets a model reply only. - With
RELAY_SESSION_DIRunset,local_agent_sessionsreads a per-user folder
instead of the folder the server started in. local_agent_sessionsrefuses asession_idthat is not a bare name.- MCP file tools refuse writes into agent and editor configuration folders.
The MCP tool names, the relay.mcp-run-request/v2 binding and the shape of
relay.status are unchanged. relay.doctor and the session listing gain
fields.
Source version metadata is not release availability proof; release availability
is established only by the accepted Git tag, uploaded GitHub Release assets, and
matching hash readback. Do not publish or recommend the bare PyPI name
relay-agent; that public namespace belongs to an unrelated project and is not
the HarperZ9 Relay distribution.
Security
local_agent_sessionsjoined the caller'ssession_idonto the session
store with no check."../outside/private"or an absolute path returned the
transcript of any ledger file the server's user could read, with no grant.
Affected: 0.2.0 through 0.3.0. Fixed: asession_idis a bare name, and a file
whose real path leaves the store is neither opened nor listed.- The
claudeandcodexCLI tiers started the CLI by bare name from the
server's folder, with every variable and no isolation flags. Aclaude.exe
planted in that folder ran instead of the installed one, and a
.claude/settings.jsonthere could run its hooks. Reaching a tier needed the
exec grant. Affected: every release through 0.3.0. Fixed below. run,test_cmd,checkand bisect checks inherited every provider key, so a
model with exec could print them into the ledger it returns. Affected: every
release through 0.3.0.
Changed
- The CLI tiers start through a vendored copy of
safe_spawn1.0.0
(src/relay/_vendor/safe_spawn.py, SHA-256 recorded inVENDORED.sha256): an
absolute executable, a new empty working folder, an environment allowlist, the
prompt on stdin, and the isolation profile the probes proved. Forclaude
2.1.251 that is--setting-sources user --strict-mcp-config --tools "". For
codex0.144.6 it isexec --ignore-user-config --ignore-rules --ephemeral --skip-git-repo-check --sandbox read-only --disable hooks --disable plugins --disable memories --disable apps -c project_doc_max_bytes=0 -c skills.include_instructions=false.RELAY_CLAUDE_CLIand
RELAY_CODEX_CLIoverride the executable and must be absolute paths. The
codextier now runs on a stock Windows npm install, where 0.3.0 could not
findcodex.cmd. The tiers still need exec. - A CLI tier whose isolation profile is not proven is refused with
EXEC_NOT_GRANTEDunless the launch also names it inRELAY_ALLOW_EXEC_CLI.
No such tier ships today. relay.doctoraddscli_tiers, one row per CLI tier:PASSonly when the
CLI resolves, exec is granted, the profile is proven and--versionreports
the tested version, andWARNwith a setup code (CLI_NOT_FOUND,
EXEC_NOT_GRANTED,CLI_PROFILE_UNPROVEN,CLI_VERSION_UNTESTED,
CLI_VERSION_UNKNOWN) otherwise. It starts--versiononly under exec and
never reports the resolved path.- Shell children get the platform base, a fixed set of toolchain variables
(VIRTUAL_ENV,JAVA_HOME,CARGO_HOMEand similar) and the names in
RELAY_CHILD_ENV.PATHkeeps absolute entries only, and on Windows
NoDefaultCurrentDirectoryInExePath=1stops cmd.exe searching the root. RELAY_CHILD_ENV,RELAY_ALLOW_EXEC_CLI,RELAY_CLAUDE_CLIand
RELAY_CODEX_CLIare launch-only. The remote entrypoint never takes them from
its env file and names any it finds there.- The session store defaults to a per-user folder:
%LOCALAPPDATA%\relay\sessions
on Windows,~/Library/Application Support/relay/sessionson macOS, and
$XDG_DATA_HOME/relay/sessionsor~/.local/share/relay/sessionselsewhere.
MCP runs cannot write it. - The session listing skips a file that will not load, a dangling link or a
name that is not a valid id, and counts them inskipped. A missing session
carries"code": "NOT_FOUND"beside its error text. - The
local_agent_sessionsdescription andsession_idschema say the id is
a bare name. - The stdio
relay.doctorreads an env file only whenRELAY_ENV_FILEnames
one. The remote entrypoint still reads.envfrom its folder. - MCP file tools refuse writes into
.claude,.codex,.cursor,.vscode,
.gemini,.agents,.opencodeand.mcp.json. --auto-commitresolvesgitto an absolute path, so agit.exein the
working folder never runs.
Limits
- The profiles are proven for the tested CLI versions only, by one probe run per
scenario on Windows. The Linux half of the probes has not run. codexhas no flag that removes its shell tool. Under the profile it can still
run read-only commands in its empty folder. Whether the CLI tiers become
model-only backends that no longer need exec is an open decision.- The shell is still not path-confined, and write is still a route to code
execution outside the refused folders.
flywheel-relay 0.3.0
Write, exec and the working root for the MCP servers move from tool arguments to
launch configuration. This changes what existing MCP calls and setups do, so it
is a minor release rather than a patch. Relay is pre-1.0, where a breaking change
takes the minor number. The breaks:
- A client that sends
allow_write: trueorallow_exec: trueto a server
started without that grant now runs with it off. - A run's
rootmust resolve inside the server's launch root. A call that names
any other directory is refused withROOT_NOT_GRANTED. checkand the onlinecodexandclaudeCLI tiers need exec.- The remote entrypoint no longer reads
RELAY_ALLOW_WRITE,RELAY_ALLOW_EXEC,
RELAY_ALLOW_REMOTE_EXECorRELAY_MCP_ROOTfrom its.envfile. In 0.2.5 a
RELAY_ALLOW_REMOTE_EXECline there was honored; set it in the environment
that starts the server instead. RELAY_ALLOW_REMOTE_EXECacceptsonandoff, and an unrecognized value
now stops the remote server instead of reading as off.
An omitted allow_write or allow_exec still means off, as in 0.2.5.
Source version metadata is not release availability proof; release availability
is established only by the accepted Git tag, uploaded GitHub Release assets, and
matching hash readback. Do not publish or recommend the bare PyPI name
relay-agent; that public namespace belongs to an unrelated project and is not
the HarperZ9 Relay distribution.
Changed
relay --mcpandpython -m relay.local_mcptake write and exec from their
launch:--allow-writeand--allow-exec, orRELAY_ALLOW_WRITEand
RELAY_ALLOW_EXEC. Both are off by default. The launch root comes from
--rootorRELAY_MCP_ROOTand defaults to the working directory. An
unrecognized value or a root that is not a directory stops the server at
launch, including a direct call toserve(), which now returns 2 with a
message instead of raising.- A run gets what it asks for and the launch granted, both.
allow_write: true
andallow_exec: trueask; an omitted argument asks for nothing. Asking for
exec also asks for write, andallow_write: falseturns exec off. - A run's
rootresolves under the launch root, and links are followed before
the check, so neither..nor a link steps outside it. - An MCP run's file tools never read the server's env file (
RELAY_ENV_FILE,
default.env), and never write it, the run store (RELAY_RUN_ROOT), the
session store (RELAY_SESSION_DIR) or anything under a.gitdirectory. On
Windows they refuse a name ending in a dot or a space, or naming a stream,
since it opens another spelling of a file. checkruns a shell outside the tool gate, so an MCP run that sets it needs
exec and is refused withEXEC_NOT_GRANTEDotherwise. Before this release a
caller could reach a shell throughcheckwith exec off.- The online
codexandclaudeCLI tiers start an agent with its own shell.
Without exec,local_agent_chat,local_agent_healthand auto routing leave
them out, and naming one is refused withEXEC_NOT_GRANTED. - On the remote surface, exec needs both
RELAY_ALLOW_EXECand
RELAY_ALLOW_REMOTE_EXEC, and write needsRELAY_ALLOW_WRITEon its own:
RELAY_ALLOW_EXECalone grants the phone nothing. The server configures only
what the surface allows, so its banner andrelay.statusreport what runs
get, and it still refuses exec per request as a second layer. - The remote entrypoint reads the grant variables from its process environment
only, because a run allowed to write could otherwise edit.envand give
itself exec on the next restart. It names any such line it finds at startup,
and the remote readout lists them asenv_file_ignored. .envvalues may carry an inline comment after whitespace (KEY=value # note).
Before this release the comment became part of the value, so the shipped
.env.examplefailed to start as documented.- The request binding is
relay.mcp-run-request/v2. It adds
granted_allow_write,granted_allow_exec,granted_root,
requested_root,grant_shortfall,remote_exec_refusedandprotected,
and reportsrequested_allow_writeandrequested_allow_execasnull
when omitted. relay.statusandrelay.doctorreport the launch grants and root. The
remote readout reports the grants the surface would configure as
start_grants, and addsremote_exec_in_effectnext to
remote_exec_allowed.
Limits
- The shell is not path-confined: with exec granted,
run,test_cmdand
checkstart in root and can reach any path the server's user can. - Write is a route to code execution. A file written under the root runs the
next time something executes it there, such as a build script, a test, or a
shell profile when the root is a home directory. Launch the server over a
workspace its callers may edit. - Background runs keep the gate and root they started with. Changing the grants
needs a server restart.
Assets
The wheel and sdist attached here are the exact files published to PyPI by the release workflow for this tag (run 36256084495). SHA256SUMS.txt lists their SHA-256 digests; verify before installing, as docs/GITHUB-ONLY-INSTALL.md describes. PyPI also carries PEP 740 attestations for both files.
Relay v0.2.3
Changes
- Align package, CLI/MCP and release metadata at 0.2.3.
- Add a release metadata guard to CI and the source archive.
- Provide a GitHub-pinned installation recipe that verifies the wheel checksum and stops on missing, mismatched or duplicate entries.
Install the attached wheel after checking SHA256SUMS.txt. The bare relay-agent name on PyPI belongs to an unrelated distribution; this release does not publish to PyPI.
Validation and limits
404 local tests passed. Fresh installed validation covered CLI, injection-probe and MCP stdio behavior, and independent review exercised the documented installation recipe with a mocked installer. Local serve/ollama endpoints were unavailable during that acceptance run, so this release does not claim a live model workflow result.
Relay 0.2.2
Relay 0.2.2 preserves witnessed partial progress from background agent runs when the server restarts. Reloaded partial runs remain marked interrupted. Final result writes and running checkpoints are serialized so an older checkpoint cannot overwrite a completed record.
A partial checkpoint does not establish task completion, rollback, or acceptance. The result becomes done only after the final record persists.
Install from the attached wheel or the pinned GitHub source. The PyPI name relay-agent belongs to an unrelated distribution; do not use it to install this project.
Source: a1f7f55. Its source tree matches the reviewed package source at 1f7506b. Check the attached SHA256SUMS.txt before installing.
Validation: 377 local tests passed, with package installation checks and CI across Windows, macOS, and Ubuntu on Python 3.11, 3.12, and 3.13. This does not establish acceptance on a physical mobile device.
Relay 0.2.1
Relay 0.2.1 is a GitHub-only patch release for the MCP stdio error hardening merged after 0.2.0.
Do not install Relay with bare pip install relay-agent. The public PyPI namespace
elay-agent is not the HarperZ9 Relay distribution. This release is distributed only from https://github.com/HarperZ9/relay.
Source commit: $sha
Source tree: $tree
Fixed
- MCP stdio returns JSON-RPC parse, invalid-request, and invalid-params errors for malformed input, invalid request ids, and non-object ools/call params without echoing rejected input or stopping the server.
Install
Pinned source install from this GitHub tag:
bash python -m pip install "relay-agent @ git+https://github.com/HarperZ9/relay.git@v0.2.1"
Offline wheel install after verifying SHA256SUMS.txt:
bash python -m pip install --no-index ./relay_agent-0.2.1-py3-none-any.whl
Validation
- GitHub CI on main commit $sha passed: package plus Python 3.11, 3.12, and 3.13 on Ubuntu, Windows, and macOS.
- Local pytest passed: 369 passed in 11.75s with --basetemp D:/fw-ship-sweep-20260910/pytest-relay-0.2.1-rerun.
- Release assets were rebuilt from $sha, and a clean venv installed the wheel and ran
elay --help successfully.
SHA256
``text
4180a429bc1a067540dacda4f25881bc3d277c614a99820e613baff87ccb1b2b relay_agent-0.2.1-py3-none-any.whl
f752aaaad0138e9ffc8dd64d9af3dac9768265931b043dc14c62da28afc29586 relay_agent-0.2.1.tar.gz
``
Relay 0.2.0
Relay 0.2.0 is a GitHub-only release of the MCP parity surface for the local Relay coding agent.
Do not install Relay with bare pip install relay-agent. The public PyPI namespace relay-agent is not the HarperZ9 Relay distribution. This release is distributed only from https://github.com/HarperZ9/relay.
Source commit: 9efdd82a6ea47ea37b4771315529aa4a8b04de1b
Source tree: 63749153af4d9a7ca35b3a537add06d514c7c133
Install
Pinned source install from this GitHub tag:
python -m pip install "relay-agent @ git+https://github.com/HarperZ9/relay.git@v0.2.0"Pinned source install from the exact release commit:
python -m pip install "relay-agent @ git+https://github.com/HarperZ9/relay.git@9efdd82a6ea47ea37b4771315529aa4a8b04de1b"Wheel install from the release assets after verifying the SHA-256 digest:
python -m pip install --no-index ./relay_agent-0.2.0-py3-none-any.whlWhat changed
local_agent_runandlocal_agent_startnow expose the CLI route and acceptance dials:backend,model,max_tokens,check,test_cmd, andcompact_budget.- Blocking and background MCP runs return a
relay.mcp-run-request/v1request binding with admitted backend/model/root, requested and effective write/exec authority, token/step budgets, and hashes for goal/check/test command text. - Background run status/result/list preserve request bindings, including restart reload when
RELAY_RUN_ROOTis configured. - A background result does not report
donebefore the final result record is durable. - MCP results report the last witnessed assistant route with receipt id,
model_ref, and ledger sequence when available. - MCP scalar validation now rejects coercive string integers, booleans in integer fields, floats, non-string route fields, and negative limits.
local_agent_runs.limitis strict and rejects string, boolean, float, and negative values.
Release assets
7b7f04ee9f393df2ec520110799ecd662033251b9dfcfaf1dad1d5727c717cee relay_agent-0.2.0-py3-none-any.whl
202c8ad1028eb1b2b45aa28801717246254ad837e7a5b1e37b26f1dc92d006c3 relay_agent-0.2.0.tar.gz
The release includes SHA256SUMS.txt with the same two artifact lines.
Verification
- GitHub PR CI passed all 10
cijobs for PR #17. - GitHub main CI passed for
9efdd82a6ea47ea37b4771315529aa4a8b04de1b. - Local build from an LF git archive produced the uploaded wheel and sdist.
- Artifact inspection matched wheel Python modules and sdist source/docs/tests to git source bytes at
9efdd82a6ea47ea37b4771315529aa4a8b04de1b. - Clean no-index wheel install passed
relay --helpand installed MCP controls for schema parity, denied write, denied exec/test command, unsupported backend typed error, strictlocal_agent_runs.limit, and durable background request binding.
No PyPI publication was performed for this release.