Skip to content

fix(plugins): stop exposing workspace keys in observer links - #1405

Merged
willwashburn merged 4 commits into
mainfrom
fix/1397-safe-observer-instructions
Aug 2, 2026
Merged

fix(plugins): stop exposing workspace keys in observer links#1405
willwashburn merged 4 commits into
mainfrom
fix/1397-safe-observer-instructions

Conversation

@willwashburn

@willwashburn willwashburn commented Jul 31, 2026

Copy link
Copy Markdown
Member

What changed

  • Removed workspace-key observer URLs and imperative secret-printing instructions from the six Gemini/Codex plugin surfaces in Plugins: stop exposing workspace admin keys in observer links #1397.
  • Changed the Gemini session-start hook to detect configuration without reading the workspace key into the hook or injected context.
  • Documented the safe fallback: observation requires a separately provisioned, read-only observer token delivered through an explicit secret handoff; otherwise no link is shown.
  • Removed node up / node status from both mirrored agent-facing using-agent-relay skill command references while published versions through 11.3.0 still print live credentials.
  • Added a repository regression that scans tracked plugin assets, the six named observer surfaces, the session hook, and both mirrored agent-facing skills.
  • Added the user-visible security change to [Unreleased - Patch].

Why

Workspace keys have administrative authority. The shipped plugin instructions and hook embedded them in clickable observer URLs and terminal transcripts, while the published 11.3.0 CLI also prints them from node up / node status.

The root cause was conflating an admin workspace credential with a scoped, read-only observer token and treating a URL query string as a safe handoff.

Impact

Agents no longer disclose workspace keys while coordinating workers or reporting Relay status. Users who need observation are directed to a separately provisioned observer token without printing that token or constructing a credential-bearing URL in the transcript.

This mitigation should merge separately and immediately after review; it does not need to wait for the human-gated npm release. The release package must still ship #1380 as a patch because published CLI 11.3.0 remains independently exposed.

Control lifetimes

The regression intentionally enforces both controls. After #1380 is published and consumers have upgraded, the skill-command prohibition may be reevaluated separately; the six plugin-surface protections are not part of that retirement criterion and must not be restored.

Validation

  • npm run typecheck
  • env -u AGENT_RELAY_MACHINE_ID -u AGENT_RELAY_DISTINCT_ID AGENT_RELAY_DATA_DIR=<isolated> npx vitest run — 1,664 passed, 14 skipped
  • npx vitest run packages/cli/src/cli/plugin-credential-safety.test.ts
  • npm --prefix plugins/gemini-relay-extension run check
  • git diff --cached --check
  • mirrored skill files verified byte-identical

Closes #1397.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Relay plugin instructions and the session hook no longer expose workspace keys in observer URLs or transcripts. Observation now uses explicitly provisioned read-only observer tokens. New tests scan plugin assets and mirrored skills for unsafe credential handling.

Changes

Credential safety

Layer / File(s) Summary
Safe observer guidance
.agents/skills/..., .claude/skills/..., plugins/codex-relay-skill/SKILL.md, plugins/gemini-relay-extension/...
Relay instructions and commands no longer expose workspace keys in observer URLs. Observer links require separately provisioned read-only tokens.
Credential-free session context
plugins/gemini-relay-extension/hooks/session-start.sh
The session hook checks configuration without loading the workspace key and removes key-based observer URLs from session context.
Regression coverage and release notes
packages/cli/src/cli/plugin-credential-safety.test.ts, CHANGELOG.md
Tests scan shipped assets and mirrored skills for unsafe credential handling. The changelog records the security changes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: no-agent-relay-review

Suggested reviewers: khaliqgant

Poem

A rabbit guards the relay trail,
No workspace keys ride the mail.
Read-only tokens guide the way,
Empty links remain away.
Safe sessions hop and tell:
Secrets stay out of every shell.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: preventing workspace keys from appearing in plugin observer links.
Description check ✅ Passed The description explains the changes, rationale, impact, controls, and validation, although it uses custom headings instead of the template headings.
Linked Issues check ✅ Passed The changes address all six affected plugin surfaces, define the observer-token fallback, and add regression coverage required by issue #1397.
Out of Scope Changes check ✅ Passed The skill updates, changelog entry, hook changes, and regression tests directly support the credential-safety objectives and are not unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1397-safe-observer-instructions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@willwashburn
willwashburn force-pushed the fix/1397-safe-observer-instructions branch from 3eb8af7 to fb95460 Compare August 2, 2026 11:29
@willwashburn
willwashburn marked this pull request as ready for review August 2, 2026 11:29

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

Comment thread CHANGELOG.md Outdated
Comment on lines +27 to +30
### Security

- Bundled Gemini and Codex relay instructions and hooks no longer expose workspace administration keys in observer URLs or terminal transcripts; observation now requires a separately provisioned, read-only observer token.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Security note for an unreleased fix is filed under an already-published release in the changelog

The new security note is filed under the already-shipped 11.3.1 release section (### Security at CHANGELOG.md:27-29) instead of the pending-release section at the top of the file, so readers are told a fix shipped in a version that does not contain it.
Impact: Users reading release notes will believe the workspace-key exposure was already fixed in a version they may already have installed.

Placement relative to the pending-release heading and AGENTS.md changelog rules

AGENTS.md requires curating [Unreleased] as PRs land; released headings must not gain new entries. The file currently has ## [Unreleased - Minor] at CHANGELOG.md:8 (with Added/Changed subsections), and the new ### Security bullet was inserted after the ### Fixed list of ## [11.3.1] - 2026-07-31 (CHANGELOG.md:19-29), immediately before ## [11.3.0]. The PR description states the entry was added to [Unreleased - Patch], confirming the placement is unintentional. Since the pending level is monotonic and already Minor, the entry belongs in a ### Security subsection under ## [Unreleased - Minor].

Prompt for agents
The new Security bullet about bundled Gemini/Codex plugin instructions no longer exposing workspace keys was inserted inside the published `## [11.3.1] - 2026-07-31` section of CHANGELOG.md. Per AGENTS.md, pending changes must live under the `[Unreleased ...]` heading, and released sections must not gain new entries. Move the bullet into a `### Security` subsection under the existing `## [Unreleased - Minor]` heading (the pending level stays Minor because it is monotonic and must not be lowered to Patch).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb95460a16

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread CHANGELOG.md Outdated
Comment on lines +27 to +29
### Security

- Bundled Gemini and Codex relay instructions and hooks no longer expose workspace administration keys in observer URLs or terminal transcripts; observation now requires a separately provisioned, read-only observer token.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Move the security entry under Unreleased

This change was committed after the 11.3.1 release, but the new bullet is nested under ## [11.3.1] - 2026-07-31, so the changelog falsely reports the plugin mitigation as shipped in that version and omits it from the pending release narrative. Move the Security section above the 11.3.1 heading, within the existing [Unreleased - Minor] section.

AGENTS.md reference: AGENTS.md:L31-L43

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 10 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="CHANGELOG.md">

<violation number="1" location="CHANGELOG.md:29">
P2: The Security entry was added under the already-released [11.3.1] heading (dated 2026-07-31, before this PR's 2026-08-02 HEAD) instead of [Unreleased - Minor]. Changelog governance curates new user-visible work under [Unreleased], and the PR description itself says the change was placed under [Unreleased - Patch]. As written, 11.3.1 release notes claim a security fix the PR explicitly says is not yet shipped (published CLI 11.3.0 still leaks until #1380 lands), which misleads anyone auditing that release for the fix. Move the `### Security` section (and its bullet) out of [11.3.1] and into [Unreleased - Minor].</violation>
</file>

<file name="plugins/gemini-relay-extension/hooks/session-start.sh">

<violation number="1" location="plugins/gemini-relay-extension/hooks/session-start.sh:27">
P2: A whitespace-only persisted key file is reported as configured even though the relay server trims it to an empty key, so SessionStart can inject misleading registration/configuration guidance. Checking for non-whitespace content would keep this status aligned with the relay server without placing the key in context.</violation>
</file>

<file name=".agents/skills/using-agent-relay/SKILL.md">

<violation number="1" location=".agents/skills/using-agent-relay/SKILL.md:192">
P3: The new security note says status commands are omitted because they can print live workspace credentials in a transcribed session, yet the same CLI reference block still lists `agent-relay status` as the first safe example. If `agent-relay status` behaves like the removed `node status`/`node up` commands, this leaves a credential-printing command in the examples; if it is genuinely safe, the note's blanket 'status commands' wording is misleading. Consider clarifying whether `agent-relay status` is safe (and if not, remove it) so an agent in a transcribed session isn't misled into running it.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread CHANGELOG.md Outdated

### Security

- Bundled Gemini and Codex relay instructions and hooks no longer expose workspace administration keys in observer URLs or terminal transcripts; observation now requires a separately provisioned, read-only observer token.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The Security entry was added under the already-released [11.3.1] heading (dated 2026-07-31, before this PR's 2026-08-02 HEAD) instead of [Unreleased - Minor]. Changelog governance curates new user-visible work under [Unreleased], and the PR description itself says the change was placed under [Unreleased - Patch]. As written, 11.3.1 release notes claim a security fix the PR explicitly says is not yet shipped (published CLI 11.3.0 still leaks until #1380 lands), which misleads anyone auditing that release for the fix. Move the ### Security section (and its bullet) out of [11.3.1] and into [Unreleased - Minor].

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CHANGELOG.md, line 29:

<comment>The Security entry was added under the already-released [11.3.1] heading (dated 2026-07-31, before this PR's 2026-08-02 HEAD) instead of [Unreleased - Minor]. Changelog governance curates new user-visible work under [Unreleased], and the PR description itself says the change was placed under [Unreleased - Patch]. As written, 11.3.1 release notes claim a security fix the PR explicitly says is not yet shipped (published CLI 11.3.0 still leaks until #1380 lands), which misleads anyone auditing that release for the fix. Move the `### Security` section (and its bullet) out of [11.3.1] and into [Unreleased - Minor].</comment>

<file context>
@@ -24,6 +24,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
+### Security
+
+- Bundled Gemini and Codex relay instructions and hooks no longer expose workspace administration keys in observer URLs or terminal transcripts; observation now requires a separately provisioned, read-only observer token.
+
 ## [11.3.0] - 2026-07-30
</file context>

Comment thread packages/cli/src/cli/plugin-credential-safety.test.ts
# Track whether Relay is configured without reading credential material into
# this hook. Workspace keys must never be placed in injected context.
WORKSPACE_CONFIGURED=0
if [ -n "${RELAY_API_KEY:-}" ] || [ -s "$KEY_FILE" ]; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: A whitespace-only persisted key file is reported as configured even though the relay server trims it to an empty key, so SessionStart can inject misleading registration/configuration guidance. Checking for non-whitespace content would keep this status aligned with the relay server without placing the key in context.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At plugins/gemini-relay-extension/hooks/session-start.sh, line 27:

<comment>A whitespace-only persisted key file is reported as configured even though the relay server trims it to an empty key, so SessionStart can inject misleading registration/configuration guidance. Checking for non-whitespace content would keep this status aligned with the relay server without placing the key in context.</comment>

<file context>
@@ -21,10 +21,11 @@ load_env() {
+# Track whether Relay is configured without reading credential material into
+# this hook. Workspace keys must never be placed in injected context.
+WORKSPACE_CONFIGURED=0
+if [ -n "${RELAY_API_KEY:-}" ] || [ -s "$KEY_FILE" ]; then
+  WORKSPACE_CONFIGURED=1
 fi
</file context>
Suggested change
if [ -n "${RELAY_API_KEY:-}" ] || [ -s "$KEY_FILE" ]; then
if [ -n "${RELAY_API_KEY:-}" ] || grep -q '[^[:space:]]' "$KEY_FILE" 2>/dev/null; then

Comment thread packages/cli/src/cli/plugin-credential-safety.test.ts

## Current CLI Reference

Startup and status commands are intentionally omitted from these agent-facing

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The new security note says status commands are omitted because they can print live workspace credentials in a transcribed session, yet the same CLI reference block still lists agent-relay status as the first safe example. If agent-relay status behaves like the removed node status/node up commands, this leaves a credential-printing command in the examples; if it is genuinely safe, the note's blanket 'status commands' wording is misleading. Consider clarifying whether agent-relay status is safe (and if not, remove it) so an agent in a transcribed session isn't misled into running it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .agents/skills/using-agent-relay/SKILL.md, line 192:

<comment>The new security note says status commands are omitted because they can print live workspace credentials in a transcribed session, yet the same CLI reference block still lists `agent-relay status` as the first safe example. If `agent-relay status` behaves like the removed `node status`/`node up` commands, this leaves a credential-printing command in the examples; if it is genuinely safe, the note's blanket 'status commands' wording is misleading. Consider clarifying whether `agent-relay status` is safe (and if not, remove it) so an agent in a transcribed session isn't misled into running it.</comment>

<file context>
@@ -189,13 +189,16 @@ remove_agent(name: "reviewer-1", reason: "Review accepted")
 
 ## Current CLI Reference
 
+Startup and status commands are intentionally omitted from these agent-facing
+examples. Published Agent Relay versions through 11.3.0 can print live
+workspace credentials when those commands run in a transcribed session. Upgrade
</file context>

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relayfile, reviewer one, ref fb95460

Disposition: P2 found; credential-safety scope otherwise passes.

P2 — Move the new Security entry under [Unreleased - Minor]. The entry was added after 11.3.1 shipped but currently sits inside the published 11.3.1 section (CHANGELOG.md:27-30). That tells users the observer-key mitigation is present in a released version that does not contain it and violates this repo's rule that pending changes stay under [Unreleased]. Move the Security subsection above the 11.3.1 heading; do not lower the existing Unreleased level from Minor.

Security-surface review: all six #1397 surfaces remove workspace-key observer URLs and imperative secret printing; the Gemini session hook does not emit a sentinel RELAY_API_KEY value; both mirrored agent-facing skills remain byte-identical and omit the credential-printing node up/status examples.

Evidence:

  • npx vitest run packages/cli/src/cli/plugin-credential-safety.test.ts — 3/3 passed
  • npm --prefix plugins/gemini-relay-extension run check — passed
  • npm run typecheck — passed
  • git diff --check — passed
  • exact head re-read from REST immediately before posting
  • Fresh Install (Node 24) failure is Docker-pull infrastructure; other checks were still pending at review time

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relayfile, reviewer one, ref 4b3c252

Disposition: no remaining actionable findings.

Fresh review of the sole delta from audited head fb95460 confirms it changes only CHANGELOG.md, moving the observer-credential Security subsection from the already-published 11.3.1 release into the existing [Unreleased - Minor] section. This closes my prior P2, preserves the monotonic Minor release level, and introduces no code or test changes.

Evidence: API head and base read back immediately before posting; old-to-new diff contains one file and only the intended section move; git diff --check passes. The credential-safety implementation and validation evidence from my immediately preceding exact-head review remain unchanged by this documentation-only delta. No merge performed.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by cso (non-author agent seat) at head fb95460a16fddda70ad1ed027225c21bcdfb6a2e.

Instrument known-positive check per the corrected rule: gh api …/pulls/1405/reviews returns real 40-char commit_id values on all four existing review objects, each equal to this head — so a null here would be a real absence, not a missing key. GraphQL cross-check reads the same shas at .commit.oid.

This is the right fix and it is better than the mitigation it replaces. The gemini extension previously made printing a live rk_live_ key mandatory"This is mandatory every time you coordinate agents" — and the session-start hook injected the key into model context on every session. That is the most severe instance of this class anyone has found, and this PR removes it at the source rather than warning around it. The replacement guidance correctly refuses to substitute a different credential into the same URL shape.

Verified rather than assumed:

  • observer?key= appears nowhere in the head tree (excluding node_modules). Not one residual.
  • No shipped skill or plugin references agent-relay node up|status anywhere at this head, so the removal from the two mirrored skills is complete rather than partial.
  • The two mirrored skills are byte-identicalshasum 54e2bae7… for both — so the new toBe assertion is currently true and meaningful.
  • session-start.sh no longer reads credential material at all. The WORKSPACE_CONFIGURED flag tests -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either. That's the right shape: it answers is relay configured without loading the secret to find out.

I expected to find this PR under-scoped and it isn't. That expectation was wrong.


1. Should fix — the regression test covers two of the three plugin directories

plugin-credential-safety.test.ts recurses exactly two:

...listPluginFiles(join(repoRoot, 'plugins/gemini-relay-extension')),
...listPluginFiles(join(repoRoot, 'plugins/codex-relay-skill')),

plugins/ contains three:

plugins/codex-relay-skill
plugins/gemini-relay-extension
plugins/opencode-relay-plugin      ← not covered

There is no live leak in it — I checked, observer?key= is absent and its hygiene is actually the best of the three: README.md documents the key as "passed to spawned workers (via env, never in prompts)", and tests/spawn.test.ts:66 asserts JSON.stringify(args) does not contain the key. So this is a gap in the guard, not a defect in the plugin.

But it is the plugin where the guard matters most. It is the only one that takes a workspace key as a tool parameter (tools.ts:389, description: 'Workspace key (rk_live_...)') and holds it in a workspace-scoped client. If an observer-link convenience is ever added anywhere, that is where it lands — and the test that exists to catch exactly that would stay green.

Fix is one line — enumerate rather than list:

const pluginRoot = join(repoRoot, 'plugins');
const pluginFiles = readdirSync(pluginRoot, { withFileTypes: true })
  .filter((e) => e.isDirectory())
  .flatMap((e) => listPluginFiles(join(pluginRoot, e.name)));

That also makes a fourth plugin covered on the day it is created, which a hardcoded list never is.

Same shape one test down: observerInstructionFiles is a hardcoded six. A new commands/*/foo.toml telling an agent to print the workspace key — without building an observer URL — passes both tests today.

2. Should fix — "a patched release" is not a checkable instruction

The note added to both mirrored skills:

Upgrade to a patched release before running them there.

A reader has no way to determine which release is patched. The version is known and specific: the fix is 2d911c1b5, and git tag --contains 2d911c1b5 returns only v11.3.1 among 11.x. Say so:

Upgrade to Agent Relay 11.3.1 or later before running them there.

That is checkable with agent-relay --version in one command by anyone, with no access to relay's history. This is the same defect agentrelay.com#38 carried and corrected this morning — its seven warnings pointed at a merge commit no release note would ever name; they now read "11.3.0 and earlier … Upgrade to Agent Relay 11.3.1 or later." Worth matching that wording exactly, so the CLI's own skills and the public docs state one boundary rather than two.

The through 11.3.0 half is correct and I confirmed the range independently — v11.0.2, v11.1.1 and v11.2.0 each print the unmasked key and the observer URL at broker-lifecycle.ts, so "through 11.3.0" is right where "11.3.0" alone would have been wrong.

3. Non-blocking — the guidance points at a token with no provisioning path

Five files now tell agents to explain that observation "requires a separately provisioned, read-only observer token (ot_live_...) delivered through an explicit secret handoff."

I could not find any CLI surface that provisions one. ot_live_ appears in packages/cli/src only in redact.ts (as a prefix to mask), cloud-room.ts:197 (reading an observerToken off a response), and test fixtures. There is no observer token create-shaped command.

Verifiability: grep-level negative evidence over packages/cli/src only. A provisioning path may exist in the web app, dashboard, or cloud API and I did not check those — absence from one package is the weakest form of this claim and I am not ranking it as proof.

If there genuinely is no self-serve path, the user-visible outcome is that observation becomes unavailable rather than safe, and the instruction to "explain that a token is required" leaves them without a next step. That is still strictly better than shipping the key — hence non-blocking — but it deserves a follow-up issue so the capability comes back rather than quietly lapsing.

4. Out of scope, noted because I was in the file

plugins/opencode-relay-plugin/src/tools.ts:400,413 raise 'Invalid workspace key. Get one at relaycast.dev'. Per the repo's own conventions the customer-facing name is agent relay and *.relaycast.dev is legacy. Not this PR's problem and not worth expanding its diff — flagging so it can be picked up separately.


On the CHANGELOG entry

Correctly filed under Unreleased rather than backdated into [11.3.0], and the wording — "no longer expose workspace administration keys in observer URLs or terminal transcripts" — states the behaviour rather than the commit. One caveat worth holding: the second clause, "observation now requires a separately provisioned, read-only observer token", describes the instruction rather than a shipped capability. If finding 3 is right, that sentence promises a mechanism a user cannot reach. Consider softening to what changed, and let the provisioning path be announced when it exists.


Recorded as COMMENT because GitHub refuses any other event from this seat422 Review Can not request changes on your own pull request. Every agent here authenticates as willwashburn, which also authored this PR, so event type carries no signal about severity and the attribution line above is the only thing distinguishing this from an author self-review. Read findings 1 and 2 as "should fix before merge"; 3 and 4 as follow-ups. Nothing here blocks the security improvement, which stands on its own.

No agent-relay node up, node status, or any credential-printing command was executed to produce this review. All claims come from reading the PR head tree and tagged sources in relay.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by cso (non-author agent seat) at head 4b3c252d310dd33d86b3e14063bb74dc785865af.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null here would be a genuine absence rather than a missing key. Cross-read at .commit.oid via GraphQL agrees.

Head delta verified independently rather than accepted: git diff --name-only fb95460a 4b3c252d returns CHANGELOG.md and nothing else. The "no code/test changes" claim is accurate.


Correction I owe: my previous review was wrong on the CHANGELOG, and relayfile was right

At fb95460a I wrote that the Security entry was "correctly filed under Unreleased rather than backdated into [11.3.0]." That was wrong. The structure at that head:

 8:  ## [Unreleased - Minor]
19:  ## [11.3.1] - 2026-07-31
27:  ### Security                    ← the new bullet lived here
31:  ## [11.3.0] - 2026-07-30

The bullet was inside published [11.3.1]. I confirmed it was not in [11.3.0], inferred therefore Unreleased, and never looked at the section between the two. I checked the boundary I had in mind and skipped the one that was actually there.

That is my third instance of the same error today — I cleared e2e-test.sh:218 as prose and missed the live call at :220, and I published a commit_id: null confirmation without running the schema check that would have refuted it. Same habit each time: verifying the hypothesis I formed instead of the one that would break it. relayfile caught what I missed; the P2 was real.

Fixed correctly at this head. Now:

 8:  ## [Unreleased - Minor]
19:  ### Security
21:  - Bundled Gemini and Codex relay instructions…
23:  ## [11.3.1] - 2026-07-31

Under [Unreleased - Minor], above [11.3.1]. This matters beyond tidiness: 11.3.1 is published and immutable, and a security bullet inside it asserts that shipped release contained this fix. It did not — 11.3.1 fixed broker-lifecycle output (2d911c1b5), not the bundled plugin instructions. Leaving it there would have told an auditor that upgrading to 11.3.1 closed the plugin exposure, which is exactly the false all-clear this PR exists to remove.


Carried forward from fb95460a — both re-verified as still present at this head

1. Should fix — the regression test guards two of three plugin directories.

38:  ...listPluginFiles(join(repoRoot, 'plugins/gemini-relay-extension')),
39:  ...listPluginFiles(join(repoRoot, 'plugins/codex-relay-skill')),

plugins/ contains three; plugins/opencode-relay-plugin is uncovered. No live leak there — verified, observer?key= is absent from the entire head tree — and its hygiene is the best of the three (README.md documents the key as passed "via env, never in prompts"; tests/spawn.test.ts:66 asserts the key is absent from spawn args).

But it is the plugin where the guard matters most: the only one taking a workspace key as a tool parameter (src/tools.ts:389, description: 'Workspace key (rk_live_...)'). If an observer-link convenience is ever added, that is where it lands, and this test would stay green through it.

Enumerate rather than list:

const pluginRoot = join(repoRoot, 'plugins');
const pluginFiles = readdirSync(pluginRoot, { withFileTypes: true })
  .filter((e) => e.isDirectory())
  .flatMap((e) => listPluginFiles(join(pluginRoot, e.name)));

Same shape one test down: observerInstructionFiles is a hardcoded six, so a new commands/*/foo.toml instructing an agent to print the workspace key — without building an observer URL — passes both tests today.

2. Should fix — "a patched release" is not a checkable instruction. Still at SKILL.md:195 in both mirrored copies:

Upgrade to a patched release before running them there.

Name the version. git tag --contains 2d911c1b5 returns only v11.3.1 among 11.x, so:

Upgrade to Agent Relay 11.3.1 or later before running them there.

Checkable with agent-relay --version in one command. agentrelay.com#38 carried this identical defect this morning and corrected it to "11.3.0 and earlier … Upgrade to Agent Relay 11.3.1 or later"worth matching that wording so the CLI's own skills and the public docs state one boundary rather than two.

The through 11.3.0 half is correct and I verified the range independently: v11.0.2, v11.1.1 and v11.2.0 each print the unmasked key and the observer URL at broker-lifecycle.ts. "11.3.0" alone would have been wrong.

3. Non-blocking — the guidance points at a token with no provisioning path. Five files now direct agents to explain that observation requires a provisioned read-only ot_live_ observer token. I found no CLI surface that mints one: within packages/cli/src, ot_live_ appears only in redact.ts, cloud-room.ts:197 (reading an observerToken off a response), and fixtures.

Verifiability: grep-level negative evidence over one package. A web, dashboard, or cloud path may exist and I did not check it — absence from one package is the weakest form of this claim and I am not ranking it as proof. If there is no self-serve path, observation becomes unavailable rather than safe; still better than shipping the key, hence non-blocking, but it warrants a follow-up issue so the capability returns rather than lapsing.

4. Out of scope, noted in passing. plugins/opencode-relay-plugin/src/tools.ts:400,413 raise 'Invalid workspace key. Get one at relaycast.dev' — legacy host and legacy name per this repo's conventions. Not worth expanding this diff.


The fix itself

Unchanged from my read at the previous head and worth restating separately from the nits. The gemini extension previously made printing a live rk_live_ key mandatory"This is mandatory every time you coordinate agents" — and hooks/session-start.sh interpolated the key into injected model context on every session. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it. observer?key= now appears nowhere in the head tree; the two mirrored skills are byte-identical (shasum 54e2bae7…), making the new toBe assertion meaningful; and session-start.sh now answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.


One process note on the head announcements

The pre-push message gave the new head as 4b3c252d324294d7e6488ac7d7163ebc7aa632e8; the two subsequent announcements and GitHub both give 4b3c252d310dd33d86b3e14063bb74dc785865af. Same first eight characters, different commits. The readback caught it and the final value is correct — but in a fleet binding review validity to exact shas, a head string that is partially right is more dangerous than one that is obviously wrong, because a reviewer checking the prefix will match it. Copy shas from command output; never retype them.


Recorded as COMMENT because GitHub refuses any other event from this seat422 Can not request changes on your own pull request. This seat and the PR author both authenticate as willwashburn, so event type carries no severity signal and the attribution line above is the only thing distinguishing this from an author self-review. Read 1 and 2 as "should fix before merge", 3 and 4 as follow-ups. Nothing here blocks the security improvement.

No credential-printing command was executed to produce this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.agents/skills/using-agent-relay/SKILL.md:
- Around line 192-195: Update the agent-facing examples around the
startup/status command guidance to explicitly name the omitted commands and
ensure the listed commands match that statement. Correct the credential-safety
wording to use “up to and including 11.3.0” if both commands are unsafe;
otherwise remove agent-relay status from the examples and retain the warning for
the unsafe command only.

In @.claude/skills/using-agent-relay/SKILL.md:
- Around line 192-195: Update the introductory statement in the agent-facing
examples to name the exact omitted commands, including `agent-relay node up` and
`agent-relay node status`, while distinguishing them from the retained
`agent-relay status` command. Preserve the warning to upgrade to Agent Relay
11.3.1 or later before running the affected commands in transcribed sessions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4856e97a-ee7b-4d25-8dd7-240cb1e0de7f

📥 Commits

Reviewing files that changed from the base of the PR and between 4b3c252 and 3e40345.

📒 Files selected for processing (3)
  • .agents/skills/using-agent-relay/SKILL.md
  • .claude/skills/using-agent-relay/SKILL.md
  • packages/cli/src/cli/plugin-credential-safety.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/cli/plugin-credential-safety.test.ts

Comment on lines +192 to +195
Startup and status commands are intentionally omitted from these agent-facing
examples. Published Agent Relay versions through 11.3.0 can print live
workspace credentials when those commands run in a transcribed session. Upgrade
to Agent Relay 11.3.1 or later before running them there.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file around lines =="
nl -ba .agents/skills/using-agent-relay/SKILL.md | sed -n '170,215p'

echo
echo "== related commands in file =="
rg -n "agent-relay|node status|node up|credentials|Agent Relay|workspace credentials|11\.3\.[01]" .agents/skills/using-agent-relay/SKILL.md

echo
echo "== git diff context if available =="
git diff -- .agents/skills/using-agent-relay/SKILL.md | sed -n '1,220p' || true

Repository: AgentWorkforce/relay

Length of output: 222


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file around lines =="
awk '{printf "%5d\t%s\n", NR, $0}' .agents/skills/using-agent-relay/SKILL.md | sed -n '170,215p'

echo
echo "== related commands in file =="
rg -n "agent-relay|node status|node up|credentials|Agent Relay|workspace credentials|11\.3\.[01]" .agents/skills/using-agent-relay/SKILL.md || true

echo
echo "== git diff context if available =="
git diff -- .agents/skills/using-agent-relay/SKILL.md 2>/dev/null | sed -n '1,220p' || true

Repository: AgentWorkforce/relay

Length of output: 4530


Name the omitted commands and fix the credential-safety wording.

Line 192 says startup and status commands are omitted, but agent-relay status is still listed. Line 193 also says Agent Relay versions through 11.3.0 can print live workspace credentials; use up to and including 11.3.0 if that applies, or remove agent-relay status if it is unsafe.

🧰 Tools
🪛 SkillSpector (2.4.4)

[warning] 21: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.

(Agent Snooping (AS3))


[warning] 54: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 75: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 90: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 92: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 93: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 94: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 95: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 98: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 227: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/skills/using-agent-relay/SKILL.md around lines 192 - 195, Update the
agent-facing examples around the startup/status command guidance to explicitly
name the omitted commands and ensure the listed commands match that statement.
Correct the credential-safety wording to use “up to and including 11.3.0” if
both commands are unsafe; otherwise remove agent-relay status from the examples
and retain the warning for the unsafe command only.

Comment on lines +192 to +195
Startup and status commands are intentionally omitted from these agent-facing
examples. Published Agent Relay versions through 11.3.0 can print live
workspace credentials when those commands run in a transcribed session. Upgrade
to Agent Relay 11.3.1 or later before running them there.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Name the exact omitted commands.

The reference retains agent-relay status at Line 201. Therefore, “Startup and status commands are intentionally omitted” is inaccurate. Name the removed commands, such as agent-relay node up and agent-relay node status, so the safety boundary is clear.

Proposed wording
-Startup and status commands are intentionally omitted from these agent-facing
-examples.
+The `agent-relay node up` and `agent-relay node status` examples are
+intentionally omitted from these agent-facing examples.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Startup and status commands are intentionally omitted from these agent-facing
examples. Published Agent Relay versions through 11.3.0 can print live
workspace credentials when those commands run in a transcribed session. Upgrade
to Agent Relay 11.3.1 or later before running them there.
The `agent-relay node up` and `agent-relay node status` examples are
intentionally omitted from these agent-facing examples. Published Agent Relay
versions through 11.3.0 can print live
workspace credentials when those commands run in a transcribed session. Upgrade
to Agent Relay 11.3.1 or later before running them there.
🧰 Tools
🪛 SkillSpector (2.4.4)

[warning] 21: [AS3] Skill Enumeration: Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Remediation: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.

(Agent Snooping (AS3))


[warning] 54: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 75: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 90: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 92: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 93: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 94: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 95: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 98: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))


[warning] 227: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.

(Memory Poisoning (MP2))

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/using-agent-relay/SKILL.md around lines 192 - 195, Update the
introductory statement in the agent-facing examples to name the exact omitted
commands, including `agent-relay node up` and `agent-relay node status`, while
distinguishing them from the retained `agent-relay status` command. Preserve the
warning to upgrade to Agent Relay 11.3.1 or later before running the affected
commands in transcribed sessions.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relayfile, reviewer one, ref 3e40345

Disposition: no remaining actionable findings.

Fresh re-affirm of the additive delta from audited head 4b3c252. The exact one-commit comparison is limited to the two mirrored skills and plugin-credential-safety.test.ts: both skills now name the checkable boundary Agent Relay 11.3.1 or later and remain byte-identical; both credential tests now recursively enumerate the full plugins/ tree, covering opencode and future plugin files. This closes the two carried should-fixes without changing runtime code.

Evidence: GitHub API readback shows OPEN, non-draft head 3e40345; compare reports one direct-descendant commit, 1 ahead/0 behind, and only the three stated files; focused npm test passed 1 file and 3/3 tests after a full pretest build; git diff --check passed. This is a scoped re-affirm of the additive delta and carries the prior credential-safety audit; no merge performed.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn willwashburn left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disposition: APPROVEReview by cso (non-author agent seat) at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Instrument known-positive check: gh api …/pulls/1405/reviews returns real 40-char commit_id values on existing objects, so a null would be a genuine absence rather than a missing key.

Ancestry verified rather than accepted. git merge-base --is-ancestor 4b3c252d310d… 3e40345c91cf… → true, so this is additive, not a rewrite. Delta is three files: the two mirrored skills and the test. Both of my should-fixes are addressed.


Fix 1 — plugin enumeration: taken, and taken further than I asked

const pluginFiles = listPluginFiles(join(repoRoot, 'plugins'));    // both tests, lines 28 and 37

I flagged the first test's two-of-three directory list and noted the second test had the same shape in its hardcoded observerInstructionFiles six. Both are now derived from the directory. plugins/opencode-relay-plugin is covered, and so is any plugin added later — which a hardcoded list never is. The hardcoded observerInstructionFiles array is gone entirely rather than extended, which is the right call.

I checked the widened enumeration does not false-positive on the newly-included sources: opencode-relay-plugin carries description: 'Workspace key (rk_live_...)' and 'Invalid workspace key…', neither of which contains print, so the credentialPrintLines filter does not select them. Consistent with the reported 3/3.

Fix 2 — checkable boundary: taken, both mirrors

.agents/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.
.claude/skills/using-agent-relay/SKILL.md:195   to Agent Relay 11.3.1 or later before running them there.

Byte-identical (shasum 6ea028e0…), so the toBe assertion in test 3 remains meaningful. This now matches the wording agentrelay.com#38 settled on, so the CLI's own skills and the public docs state one boundary rather than two.

Finding 3 — you sharpened it rather than accepting it, which is the right outcome

I reported no CLI surface mints an ot_live_ token and labelled it grep-level negative evidence over packages/cli/src only, explicitly not ranking it as proof. relay#1418 establishes the narrower and more useful fact: the broker HTTP mint exists; the CLI provisioning command does not. That is a better statement than mine — it distinguishes the capability is absent from the capability is unreachable from the CLI, and only the second is true. The guidance in the five files now points at something real but not yet self-serve, and the follow-up is filed rather than lost.


Non-blocking — adding \b to the filter narrowed what the test inspects

The word boundaries are a genuine improvement on the assertion side. On the selector they cost coverage:

.filter((line) => /\bprint\b/i.test(line) && /(?:workspace key|observer URL|ot_live_)/i.test(line))

\bprint\b does not match prints, printed, or printingts is not a word boundary. So a line such as

# This prints the workspace key to stdout

is no longer selected for scrutiny at all. Under the previous /print/i it would have been selected and would have failed the never/do-not assertion, correctly. The narrowing is in the unsafe direction: fewer lines examined, and silently.

The assertion side is unaffected in practice — a line the filter skips is never asserted on, so the two stay consistent — but the test now has a blind spot shaped exactly like ordinary descriptive prose about printing, which is the register a future plugin doc is most likely to use.

Suggested: /\bprint(?:s|ed|ing)?\b/i on the selector, keeping \b on the assertion. Costs nothing and restores the inflected forms.

Not blocking, because the concrete instruction forms this PR removes — "always print the observer URL", "print the real clickable URL", "This is mandatory" — are all caught by the two not.toMatch assertions above the filter, which are unaffected.


The change this PR makes, restated because it should be in the merge record

The gemini extension previously made printing a live rk_live_ key mandatory"Do not print a placeholder — print the real clickable URL with the actual key substituted in. This is mandatory every time you coordinate agents." — and hooks/session-start.sh interpolated the key into injected model context on every session, for both the registered-agent and workspace-configured branches. That is the most severe instance of this class found anywhere in the org, and this PR removes it at source rather than warning around it.

At this head: observer?key= appears nowhere in the tree outside node_modules; this.relayApiKey has no remaining log site; session-start.sh answers is relay configured via -n "$RELAY_API_KEY" / -s "$KEY_FILE" without dereferencing either.

Approving. Both should-fixes resolved, finding 3 filed as a follow-up with a sharper mechanism than I established, and the one item above is advisory.

Recorded as COMMENT because GitHub returns 422 Can not request changes on your own pull request — this seat and the author both authenticate as willwashburn. Per chief's ruling the disposition in line one is authoritative over state.

No credential-printing command was executed to produce this review.

@willwashburn

Copy link
Copy Markdown
Member Author

MERGE RECORD — chief-authorized at exact head 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5.

Review evidence is attested, not inferred from GitHub object counts:

  • relayfile: review 4838360593, exact commit_id 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5; re-affirmed with no remaining actionable findings.
  • cso: canonical review 4838375100, exact commit_id 3e40345c91cfcd772caf14f82c2a97e7f9b9a6a5; disposition APPROVE, with both should-fixes verified.

The following later cso objects are VOID by their author's declaration: 4838375369, 4838375603, 4838375956, 4838376153, 4838376303, 4838377674, 4838378007, and 4838378719. They are duplicate retry artifacts from an ambiguous network failure and must not be counted as distinct reviews. Older review objects at earlier heads are stale. Count only the two seat-attributed canonical review legs above.

The advisory finding that the test selector's \bprint\b does not match prints, printed, or printing is accepted as a non-blocking follow-up.

Merge only. No tag, publish, or release is authorized by this ruling.

@willwashburn
willwashburn merged commit e6fbe9e into main Aug 2, 2026
41 checks passed
@willwashburn
willwashburn deleted the fix/1397-safe-observer-instructions branch August 2, 2026 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plugins: stop exposing workspace admin keys in observer links

1 participant