AGENTS.md@packages/hub · git:20261019.955bc11 · 2026-10-19 · sha256 6a9722ff34d54f09

AGENTS.md@packages/hub git:20261019.955bc11A

Immutable. This exact content never changes and is served at /api/v1/blob/6a9722ff34d54f09.

# @shadowclone/hub

Serves the clone tools over Streamable HTTP with its own OAuth authorization server. The Claude app and other MCP clients use it to reach the clones of this machine. The `shadowclone hub` commands start and manage it.

<!-- package-facts:start -->

(generated by `bun run guides`; do not edit by hand)

- Package name: `@shadowclone/hub`
- Workspace dependencies: `@shadowclone/clones`, `@shadowclone/core`, `@shadowclone/mcp`
- External dependencies: `zod`
- Export subpaths: `.`

<!-- package-facts:end -->

## Owns

- `src/hub.ts`: `createHub`, the request router, the allowlist, and the lock.
- `src/serve.ts`: `serveHub`, the loopback server and its lock.
- `src/http/`: the MCP endpoint, the OAuth metadata, registration, the consent page, and the token endpoint.
- `src/store/`: the SQLite store for settings, clients, pairing codes, consents, grants, and token hashes.
- `src/fleet/`: node links and the routing of the clone tools across nodes. It also owns the node link client, the link file, and the forwarding tools of a node.
- `src/expose.ts`: Tailscale Funnel or serve, and the public URL.
- `src/admin.ts`: the text of the `hub pair`, `clients`, `lock`, `allow`, and `status` commands.

## Rules

- The server listens on `127.0.0.1` only. Public traffic arrives through Tailscale Funnel or a proxy on the same machine.
- Every authorization needs PKCE with S256 and a pairing code. A code works once, for 10 minutes, and locks after 5 wrong tries.
- Store only SHA-256 hashes of pairing codes, authorization codes, and tokens. Never log a code or a token.
- A reused authorization code or refresh token revokes its whole grant.
- Read `X-Forwarded-For` only when the peer is loopback, and use the last address.
- Derive every URL from the saved public URL, never from the `Host` header.
- The hub exposes only `shadowclone_sessions` and `shadowclone_clone`. Their text from a clone is data.
- A node code and a client code are different kinds. A node token is stored as a hash, and it reaches the same clone tools as a client.
- A node opens the link. The hub never connects to a node.
- When the hub does not answer, the forwarding tools of a node act only on that node. A `start` with no node or with another node runs nothing.

## Tests

Run `bun test` in this folder, or `bun test packages/hub` from the root. The tests send HTTP requests to `createHub` with a real SQLite file in a temporary folder and a fake clone node. The link test opens a loopback port with a real WebSocket. No test starts a clone.

Update this file in the same commit when you change the package purpose, public exports, dependencies, or a rule above.