Install the latest Relay beta
Relay beta releases are prerelease builds for testing new Relay features before they reach the standard Obsidian community plugin release.
There are two ways to install the latest Relay beta:
- Use a local agent. This is the easiest path if you already run Claude Code, Codex, Cursor, or another local shell-capable agent on the same computer as your Obsidian vault.
- Use BRAT. Use this if you want to install from inside Obsidian yourself, do not have a local agent, or are on mobile.
Use a local agent
Have your agent install the beta if it can read and write files inside your Obsidian vault. It can select the latest release candidate, verify GitHub release digests, back up replaced files, preserve Relay settings, and reload Relay when possible.
If your agent can read web pages, have it use this page. Otherwise copy the full self-contained instructions:
Agent install instructions
You are a local coding agent running on the same computer as the user's Obsidian vault. Install the newest Relay beta release candidate for the Obsidian community plugin id system3-relay.
Before you start
Relay beta releases are published at No-Instructions/Relay releases. This install copies verified release files into the user's vault at <vault>/.obsidian/plugins/system3-relay.
Only modify:
<vault>/.obsidian/plugins/system3-relay<vault>/.obsidian/.relay-beta-backups
Procedure
-
Get the absolute path to the user's Obsidian vault. If the user does not provide it, inspect Obsidian's local vault registry and then ask the user to confirm the selected vault before writing. Common registry locations:
- macOS:
~/Library/Application Support/obsidian/obsidian.json - Windows:
%APPDATA%\Obsidian\obsidian.json - Linux:
~/.config/obsidian/obsidian.jsonIf multiple registry entries exist, prefer the one markedopen: true, then confirm the selected vault with the user. Reason: the install target is inside that vault, and users may have more than one vault.
- macOS:
-
Verify
<vault>/.obsidianexists. Stop if it does not. Reason: this prevents writing plugin files into the wrong directory. -
Query
https://api.github.com/repos/No-Instructions/Relay/releases?per_page=50. Reason: the GitHub Releases API contains the release metadata, asset URLs, and SHA-256 digests. -
Select the newest release where
draftis false,prereleaseis true, the tag ends in-rcN, and assets includemain.js,styles.css, andmanifest-beta.json. Reason: Relay beta installs should use release candidates, not plain staged version tags like0.8.0. -
Read the
digestfield formain.js,styles.css, andmanifest-beta.json. Reason: GitHub's digest is the source of truth for verifying each downloaded file. -
Prepare
PLUGIN_DIR,BACKUP_ROOT,BACKUP_DIR, andSTAGING. Reason: explicit paths make the install auditable and keep writes within the allowed locations. -
Check whether the official Obsidian CLI is available with
command -v obsidian. Reason: Obsidian must reload plugin code after the file install, and checking for the CLI now prevents defaulting to a manual reload later. -
Show the user the selected release, publish date, vault path, plugin path, backup path, expected SHA-256 digests, file list, and whether Obsidian CLI reload is available. If the CLI is available, say the install will try
obsidian plugin:reload id=system3-relayafter the files are written and will fall back to manual reload if that fails. If the CLI is not available, say manual reload will be needed. Do not write anything until the user explicitly approves. Reason: this is a prerelease install that modifies files in the user's vault. -
Download
main.js,styles.css, andmanifest-beta.jsoninto a temporary directory. Reason: failed downloads must not leave the installed plugin half-updated. -
Verify each downloaded asset's SHA-256 against the expected digest from the API. Stop on any mismatch. Reason: a mismatch means the downloaded file is not the expected release asset.
-
Verify
manifest-beta.jsonhasidset tosystem3-relay. Reason: this prevents installing the wrong plugin manifest. -
Rewrite the downloaded
manifest-beta.jsonso itsversionfield equals the selected release tag, then save the rewritten file asmanifest.json. Reason: Relay's beta release manifests intentionally carry the previous stable version to keep normal Obsidian installs from auto-updating to betas, but Obsidian reads the local plugin folder'smanifest.jsonto report the installed version. -
If
PLUGIN_DIRalready exists, createBACKUP_DIRand copymain.js,styles.css,manifest.json, anddata.jsoninto it, skipping any that are not present. Reason: rollback only needs the files being replaced plus settings, anddata.jsonmust be preserved. -
Create
STAGINGinsidePLUGIN_DIR. Copy verifiedmain.js, verifiedstyles.css, and rewrittenmanifest.jsonintoSTAGING. Reason: staging keeps the final write step small and avoids a plugin folder with a mix of downloaded and missing files. -
Move
main.js,styles.css, andmanifest.jsonfromSTAGINGintoPLUGIN_DIR. Reason: this completes the direct plugin install. -
Confirm
data.json, if present, was not replaced. Reason:data.jsoncontains existing Relay settings. -
Reload Relay in Obsidian. If step 7 found the official Obsidian CLI, first try
obsidian plugin:reload id=system3-relay. Do not assume a running Obsidian app is enough; the user may need to enable the CLI in Obsidian settings first. Use theid=prefix;obsidian plugin:reload system3-relayis not valid. If the CLI is unavailable or reload fails, tell the user to disable then re-enable Relay in Community plugins, or runReload app without savingfrom the command palette. Reason: Obsidian must reload plugin code before the new beta is active, and the CLI is the preferred activation path when available.
Reference implementation
This shell script is not required. The agent may use other tooling as long as it follows the contract above. If using the script, run it first with RELAY_DRY_RUN=1 to preview the selected release, expected writes, and digest verification. After the user approves, run with RELAY_CONFIRM=INSTALL to skip the interactive prompt.
# Agents: set VAULT to the absolute path of the target Obsidian vault before running.
VAULT="/absolute/path/to/your/vault"
REPO="No-Instructions/Relay"
set -euo pipefail
if [ "$VAULT" = "/absolute/path/to/your/vault" ]; then
echo "Set VAULT to the absolute path of the Obsidian vault before running." >&2
exit 1
fi
if [ ! -d "$VAULT/.obsidian" ]; then
echo "Refusing to continue: $VAULT does not contain a .obsidian folder" >&2
exit 1
fi
for tool in curl jq; do
if ! command -v "$tool" >/dev/null 2>&1; then
echo "Missing required tool: $tool" >&2
exit 1
fi
done
if command -v sha256sum >/dev/null 2>&1; then
SHA256_CMD="sha256sum"
elif command -v shasum >/dev/null 2>&1; then
SHA256_CMD="shasum -a 256"
else
echo "Missing SHA-256 utility: need sha256sum or shasum" >&2
exit 1
fi
sha256_of() {
$SHA256_CMD "$1" | awk '{print $1}'
}
PLUGIN_DIR="$VAULT/.obsidian/plugins/system3-relay"
BACKUP_ROOT="$VAULT/.obsidian/.relay-beta-backups"
STAMP="$(date +%Y%m%d-%H%M%S)"
BACKUP_DIR="$BACKUP_ROOT/system3-relay-$STAMP"
TMPDIR="$(mktemp -d)"
STAGING=""
cleanup() {
[ -n "${TMPDIR:-}" ] && rm -rf "$TMPDIR"
[ -n "${STAGING:-}" ] && [ -d "$STAGING" ] && rm -rf "$STAGING"
return 0
}
trap cleanup EXIT
DRY_RUN="${RELAY_DRY_RUN:-0}"
RELEASES_JSON="$TMPDIR/releases.json"
curl -fsSL "https://api.github.com/repos/$REPO/releases?per_page=50" -o "$RELEASES_JSON"
VERSION="$(jq -r '
map(select(.draft == false and .prerelease == true))
| map(select(.tag_name | test("^[0-9]+\\.[0-9]+\\.[0-9]+-rc[0-9]+$")))
| map(select(
([.assets[].name] | contains(["main.js"]))
and ([.assets[].name] | contains(["styles.css"]))
and ([.assets[].name] | contains(["manifest-beta.json"]))
))
| .[0].tag_name // empty
' "$RELEASES_JSON")"
if [ -z "$VERSION" ]; then
echo "No -rcN prerelease found with required Relay beta assets" >&2
exit 1
fi
PUBLISHED_AT="$(jq -r --arg version "$VERSION" '
(.[] | select(.tag_name == $version) | .published_at) // "unknown"
' "$RELEASES_JSON")"
asset_digest() {
local asset_name="$1"
jq -r --arg version "$VERSION" --arg asset "$asset_name" '
(.[] | select(.tag_name == $version) | .assets[] | select(.name == $asset) | .digest) // empty
' "$RELEASES_JSON"
}
EXPECTED_DIGEST_MAIN="$(asset_digest main.js)"
EXPECTED_DIGEST_STYLES="$(asset_digest styles.css)"
EXPECTED_DIGEST_MANIFEST="$(asset_digest manifest-beta.json)"
for pair in "main.js:$EXPECTED_DIGEST_MAIN" "styles.css:$EXPECTED_DIGEST_STYLES" "manifest-beta.json:$EXPECTED_DIGEST_MANIFEST"; do
digest="${pair#*:}"
asset="${pair%%:*}"
if [ -z "$digest" ] || [ "${digest#sha256:}" = "$digest" ]; then
echo "Missing or non-sha256 digest for $asset: '$digest'" >&2
exit 1
fi
done
echo "Relay beta release: $VERSION"
echo "Published: $PUBLISHED_AT"
echo "Vault: $VAULT"
echo "Plugin folder: $PLUGIN_DIR"
echo "Backup folder: $BACKUP_DIR"
echo "Expected digests:"
echo " main.js $EXPECTED_DIGEST_MAIN"
echo " styles.css $EXPECTED_DIGEST_STYLES"
echo " manifest-beta.json $EXPECTED_DIGEST_MANIFEST"
echo "Will write: main.js, styles.css, manifest.json"
echo "Will preserve: data.json"
if [ -d "$PLUGIN_DIR" ]; then
echo "Will back up (selective, only these files if present):"
for f in main.js styles.css manifest.json data.json; do
[ -f "$PLUGIN_DIR/$f" ] && echo " $PLUGIN_DIR/$f"
done
else
echo "Will back up: nothing (fresh install)"
fi
if [ "$DRY_RUN" = "1" ]; then
echo "RELAY_DRY_RUN=1; downloading and verifying without writing to the plugin folder."
elif [ "${RELAY_CONFIRM:-}" = "INSTALL" ]; then
echo "RELAY_CONFIRM=INSTALL detected; proceeding without interactive prompt."
else
printf "Type INSTALL to continue: "
read -r CONFIRM
if [ "$CONFIRM" != "INSTALL" ]; then
echo "Cancelled."
exit 1
fi
fi
BASE="https://github.com/$REPO/releases/download/$VERSION"
curl -fsSL "$BASE/main.js" -o "$TMPDIR/main.js"
curl -fsSL "$BASE/styles.css" -o "$TMPDIR/styles.css"
curl -fsSL "$BASE/manifest-beta.json" -o "$TMPDIR/manifest-beta.json"
verify_digest() {
local file="$1"
local expected="$2"
local expected_hex="${expected#sha256:}"
local actual
actual="$(sha256_of "$file")"
if [ "$actual" != "$expected_hex" ]; then
echo "SHA-256 mismatch for $(basename "$file"):" >&2
echo " expected $expected_hex" >&2
echo " actual $actual" >&2
exit 1
fi
echo "Verified $(basename "$file") $actual"
}
verify_digest "$TMPDIR/main.js" "$EXPECTED_DIGEST_MAIN"
verify_digest "$TMPDIR/styles.css" "$EXPECTED_DIGEST_STYLES"
verify_digest "$TMPDIR/manifest-beta.json" "$EXPECTED_DIGEST_MANIFEST"
jq --arg expected "$VERSION" '
if .id == "system3-relay"
then .version = $expected
else error("Unexpected plugin id: \(.id)")
end
' "$TMPDIR/manifest-beta.json" > "$TMPDIR/manifest.json"
echo "Verified id=system3-relay; rewrote manifest.json version to $VERSION"
if [ "$DRY_RUN" = "1" ]; then
echo "DRY RUN: all assets downloaded and verified. Would have installed:"
echo " $PLUGIN_DIR/main.js"
echo " $PLUGIN_DIR/styles.css"
echo " $PLUGIN_DIR/manifest.json"
echo "Plugin folder was not modified. No backup was taken. Exiting."
exit 0
fi
if [ -d "$PLUGIN_DIR" ]; then
mkdir -p "$BACKUP_DIR"
echo "Backing up to $BACKUP_DIR:"
for f in main.js styles.css manifest.json data.json; do
if [ -f "$PLUGIN_DIR/$f" ]; then
cp "$PLUGIN_DIR/$f" "$BACKUP_DIR/$f"
echo " $f"
fi
done
else
echo "Fresh install: no existing plugin folder, no backup taken."
fi
STAGING="$PLUGIN_DIR/.relay-install-staging-$STAMP"
mkdir -p "$STAGING"
cp "$TMPDIR/main.js" "$STAGING/main.js"
cp "$TMPDIR/styles.css" "$STAGING/styles.css"
cp "$TMPDIR/manifest.json" "$STAGING/manifest.json"
mv -f "$STAGING/main.js" "$PLUGIN_DIR/main.js"
mv -f "$STAGING/styles.css" "$PLUGIN_DIR/styles.css"
mv -f "$STAGING/manifest.json" "$PLUGIN_DIR/manifest.json"
rmdir "$STAGING"
STAGING=""
echo "Installed Relay $VERSION in $PLUGIN_DIR"
if [ -d "$BACKUP_DIR" ]; then
echo "Backup of replaced files is in $BACKUP_DIR"
fi
echo "This did not replace Relay settings stored in data.json."
if command -v obsidian >/dev/null 2>&1; then
(
cd "$VAULT"
obsidian plugin:reload id=system3-relay
) && echo "Reloaded Relay via Obsidian CLI." && exit 0
echo "Obsidian CLI exists, but plugin reload failed. It may not be enabled, Obsidian may not be running with this vault open, or Relay may not be enabled yet." >&2
fi
echo "In Obsidian, disable then re-enable Relay in Community plugins (or run 'Reload app without saving' from the command palette)."
Roll back an agent install
If the direct agent install is not usable, restore the files from <vault>/.obsidian/.relay-beta-backups/system3-relay-<timestamp>/ back into <vault>/.obsidian/plugins/system3-relay/. Run the commands below for the timestamp you want to restore, skipping any file the backup directory does not contain:
BACKUP_DIR="<vault>/.obsidian/.relay-beta-backups/system3-relay-<timestamp>"
PLUGIN_DIR="<vault>/.obsidian/plugins/system3-relay"
[ -f "$BACKUP_DIR/main.js" ] && cp "$BACKUP_DIR/main.js" "$PLUGIN_DIR/main.js"
[ -f "$BACKUP_DIR/styles.css" ] && cp "$BACKUP_DIR/styles.css" "$PLUGIN_DIR/styles.css"
[ -f "$BACKUP_DIR/manifest.json" ] && cp "$BACKUP_DIR/manifest.json" "$PLUGIN_DIR/manifest.json"
[ -f "$BACKUP_DIR/data.json" ] && cp "$BACKUP_DIR/data.json" "$PLUGIN_DIR/data.json"
After restoring, disable then re-enable Relay in Community plugins, or run Reload app without saving, so Obsidian picks up the previous code.
Report problems
Use the Obsidian command Relay: Send bug report when available. If that does not work, post in the new-sync-beta channel in the Relay Discord.
Manual install: use BRAT
BRAT (Beta Reviewer's Auto-update Tool) is an Obsidian plugin that can side-load other plugins. Use BRAT if you want to install the beta yourself from inside Obsidian.
- In Obsidian, open Settings -> Community plugins.
- Browse for
BRATand install it. - Enable BRAT.
- Open the command palette. On macOS, press
Command-P. On Windows or Linux, use your command palette shortcut. - Run
BRAT: Plugins: Add a beta plugin with frozen version based on a release tag. - Enter:
- Repository:
No-Instructions/Relay - Release version tag:
checking latest beta... - Enable after installing: checked
- Repository:
- Click
Add Plugin. - Reload Obsidian, or disable and re-enable Relay in Community plugins.
The release tag is pinned. To move to a newer Relay beta later, repeat these steps with the newer release tag.
If the latest tag does not load here, open Relay releases and choose the newest non-draft prerelease tag ending in -rcN, such as 0.8.0-rc11.