diff --git a/skills/ocx/SKILL.md b/skills/ocx/SKILL.md index f1f24b1b98..700a0c974b 100644 --- a/skills/ocx/SKILL.md +++ b/skills/ocx/SKILL.md @@ -103,6 +103,11 @@ replacement, and report only confirmation plus non-secret key/rotation IDs. Never ask for the plaintext key in chat or offer a pipe, redirection, or API workaround to perform the secret-returning step inside the agent session. +`ocx hub invite` has the same boundary: text and JSON output expose a plaintext pairing +grant or a command embedding it. Use the human-operated terminal handoff in +[recipe 10](references/03_recipes.md#10-invite-one-more-machine-onto-a-hub); never ask for +the grant or generated command in chat. Continue non-secret setup and verification normally. + Configuration confirmation is not approval to revoke the existing credential. Identify the existing key ID and obtain separate explicit revocation approval before committing an in-place rotation or removing an old, separately replaced key. @@ -132,10 +137,10 @@ cannot. **A hub is one port, and `ocx hub invite` writes the join command for you.** Remote machines dial `hostname:port` with their own per-client key; the hub's own processes dial `127.0.0.1:` with no credential, through the loopback companion listener -(`unauthenticatedLoopbackListener: {"enabled": true}`, no port). Run `ocx hub invite` on the hub -rather than assembling an `ocx connect` line: it mints a single-use code and prints the exact +(`unauthenticatedLoopbackListener: {"enabled": true}`, no port). Have the operator run `ocx hub invite` +on the hub outside the agent session rather than assembling an `ocx connect` line: it mints a single-use code and prints the exact command, with both origins already filled in. Its `--management-url` is a confirmation of -`hub.managementPublicOrigin`, not an override. Do not persist the code it prints. +`hub.managementPublicOrigin`, not an override. The operator transfers the command directly to the joining machine; keep it out of the transcript. Two consequences that look like bugs and are not. `ocx status` on a hub prints a `Hub:` block — read it before asking the operator anything about ports or tokens. And a hub does not rewrite its diff --git a/skills/ocx/references/03_recipes.md b/skills/ocx/references/03_recipes.md index 14c16cdf53..d89d829ed7 100644 --- a/skills/ocx/references/03_recipes.md +++ b/skills/ocx/references/03_recipes.md @@ -263,20 +263,19 @@ decision, not a broken connection. ## 10. Invite one more machine onto a hub -Run on the **hub**. This is the whole flow; do not assemble an `ocx connect` line by hand. +Inspect non-secret state on the **hub** first: ```bash ocx status # read the Hub: block first -- origins, listener, token source -ocx hub invite --json ``` -`--json` gives `{ code, expiresAt, dataUrl, managementUrl, command }` on stdout. Hand the -operator `command` to run on the other machine; it already carries the data origin, the -management origin and `--pairing-code-stdin`. The code is a secret with a five-minute TTL and -one use: do not persist it, do not put it in a file, and prefer letting the operator copy it -rather than keeping it in a transcript. +Have the operator run `ocx hub invite` in a human-operated terminal outside the agent session. +Both output modes expose a plaintext pairing grant or the command embedding it; `--json` +is not a safe agent-output alternative. The operator transfers the generated command directly +to the other machine. It already carries both origins and `--pairing-code-stdin`, so do not +assemble it by hand or ask for it in chat. The code is secret, single-use, and expires in five minutes. -**Also relay the `Bound browser origin:` line from stderr.** It is not in the JSON envelope, +**Ask only for non-secret confirmation, such as expiry and the `Bound browser origin:` line.** That line is on stderr rather than in the JSON envelope, and when the bound origin is not `http://localhost:10100` the joining machine has to already be running on that port or the exchange is refused and the code is spent. diff --git a/skills/ocx/references/05_remote_hub.md b/skills/ocx/references/05_remote_hub.md index 5fa086d5f4..0d8042fe61 100644 --- a/skills/ocx/references/05_remote_hub.md +++ b/skills/ocx/references/05_remote_hub.md @@ -201,11 +201,11 @@ stored as digests, and rate-capped at 8/min. They are secrets: do not persist on ## Inviting a machine (`ocx hub invite`) -Run on the **hub**. It prints the command for the other machine: - -```bash -ocx hub invite -``` +Have the operator run `ocx hub invite` on the **hub** in a human-operated terminal outside +the agent session, then transfer the generated command directly to the joining machine. +Both text and JSON output contain a plaintext pairing grant or a command embedding it; +do not run either mode through an agent tool or ask for its secret-bearing output in chat. +The placeholder below illustrates the operator's command, not a request to relay a live grant: ```text # Run on the other machine: @@ -224,7 +224,7 @@ other machine to dial itself and spends the code for nothing, so `invite` refuse the `hub.dataPublicOrigin` fix. An explicit override is never second-guessed: a loopback data origin is legitimate over an SSH tunnel. -Every successful invite prints a `Bound browser origin:` line on stderr. A grant is bound to +Every successful invite prints a non-secret `Bound browser origin:` line on stderr. The operator may report that line and the expiry for verification. A grant is bound to one origin and a remote `ocx connect` presents `Origin: http://localhost:`, so when the bound origin is not the default the other machine must already be running on that port. Relay that line; it is the difference between a working exchange and a spent