Skip to content

feat: friendly peer names, self-id, pretty channel content, quieter default port#2

Merged
nnemirovsky merged 4 commits into
mainfrom
friendly-names-v3-final
May 20, 2026
Merged

feat: friendly peer names, self-id, pretty channel content, quieter default port#2
nnemirovsky merged 4 commits into
mainfrom
friendly-names-v3-final

Conversation

@nnemirovsky
Copy link
Copy Markdown
Owner

@nnemirovsky nnemirovsky commented May 20, 2026

Summary

Five focused fixes for v0.3.0:

  1. Friendly peer names. channel.UniqueName() now mints <adjective>-<noun>-<3-char-base36> (e.g. wild-wasp-3kx) instead of cc-<host>-<pid>-<rand>. Two curated ~200-word lists live in internal/channel/wordlist.go; combined with the suffix the keyspace is ~1.86 billion. PEERBUS_NAME is honoured verbatim as an operator override.

  2. Collision safety. Same-token collisions are essentially impossible given the keyspace. Different-token rejection (the only case the broker treats as a real conflict) is now surfaced as the typed adapter.ErrNameClaimed (mapped from the broker's StatusPolicyViolation + name claimed under a different token close reason). The cc adapter probe-registers before starting the resume loop and rotates the name on ErrNameClaimed up to 6 attempts. ResumingClient.connect short-circuits the redial backoff on a permanent rejection so a misconfig cannot spin forever. PEERBUS_NAME is never rotated.

  3. Self-identification. Two-part fix, both required by the design:

    • On every successful register the cc adapter emits ONE notifications/claude/channel system push: content: "📡 connected as <self-name>", meta: {kind: "system", self: "<self-name>"}. Appears in turn 1 of the session. (Claude Code's UI already prefixes the notification with the MCP server name, rendered as peerbus: <content>, so the word "peerbus" is dropped from the body to avoid duplicated noise.)
    • bus.peers returns { self, peers } (self filtered out of the peers list). Plumbed through mcp.Bus.Peers and channel.OutboundBus.Peers (signature widened to (self, peers, err)). No separate bus.whoami tool — the structured result + startup push fully cover it.
  4. Single-line channel content. Replaces the raw-JSON content body with a compact one-liner:

    📨 <kind> from <from>: "<decoded body>"
    

    <kind> is msg or broadcast. Single-line by design: Claude Code's renderer collapses embedded newlines into spaces and then truncates with an ellipsis, so the earlier multi-line From: / Type: / Content: block was wasted vertical space (observed live in a 2-session test). Claude Code's UI also prefixes the line with the MCP server name (rendered as peerbus: <content>), so the word "peerbus" is dropped from the body to avoid duplicated noise. Body-decoding rules in order: (i) JSON string -> unwrap; (ii) JSON object with text / message / content field -> use that; (iii) compact JSON fallback. kind is plumbed through channel.Inbound.Kind and also surfaced as a meta attribute on the notification.

  5. Quieter default broker port. 127.0.0.1:8080 -> 127.0.0.1:47821. Verified clear of /etc/services on macOS, well below the OS ephemeral range, and not a 'tutorial-already-running' default like 8080. Updated: internal/broker/config.go, Dockerfile EXPOSE, deploy/compose.yml ports + PEERBUS_LISTEN, deploy/peerbus-broker.run, README.md, docs/integrations/generic-adapter.md, CLAUDE.md. Tests use ephemeral httptest ports — no test broke.

Also: scrubbed migration / v0.1.0 / peerbus-broker / peerbus-adapter chatter from README.md, source-file comments (cmd/peerbus/*.go), and docs/integrations/generic-adapter.md. Pre-1.0 — version history stays in docs/plans/completed/. Compose service key (peerbus-broker:) and deploy/peerbus-broker.run filename intentionally kept (role / service identifier, not version chatter).

Local-test recipe

git checkout friendly-names-v3-final
go install ./cmd/peerbus
# Restart the broker against the new default port (or your own PEERBUS_LISTEN).
# Re-register the cc adapter:
claude mcp remove peerbus  # if previously added
claude mcp add peerbus -- peerbus adapter --adapter=cc
# Open two Claude Code sessions wired to this MCP server; each should:
#   - print '📡 connected as <friendly-name>' on turn 1 (the UI itself prefixes it with 'peerbus:'),
#   - see {self, peers} from bus.peers,
#   - render incoming messages as '📨 msg from <from>: "<text>"' (or 'broadcast from ...').

Validation

go build ./...           OK
gofmt -l .               clean
gofumpt -l .             clean
go vet ./...             OK
go test ./...            170 passed
go test -race ./...      170 passed
go test -count=3 ./internal/channel    63 passed
golangci-lint run ./...  0 issues
make build               OK (bin/peerbus)
make deploy-validate     OK (compose config -q)

Do not merge — user wants to install + smoke-test via go install before merging.

…efault port

- channel.UniqueName mints `<adjective>-<noun>-<3 base36>` (e.g. wild-wasp-3kx)
  in place of cc-<host>-<pid>-<rand>. ~200 adj * ~200 noun * 46656 suffixes
  ≈ 1.86 billion combos; same-token collision is essentially impossible.
  PEERBUS_NAME is honoured verbatim as operator override.
- cc adapter probe-registers before starting the resume loop and rotates
  to a fresh name on ErrNameClaimed (different-token rejection), up to 6
  attempts. PEERBUS_NAME override is NOT rotated.
- New typed ErrNameClaimed in internal/adapter; Client.Connect maps the
  broker's StatusPolicyViolation + "name claimed under a different token"
  close reason onto it. ResumingClient.connect short-circuits rather than
  spinning redial backoff on a permanent rejection.
- bus.peers now returns {self, peers}: self filtered out of the peers
  list. mcp.Bus.Peers / channel.OutboundBus.Peers signature widened to
  (self, peers, err).
- cc adapter emits ONE `notifications/claude/channel` system-kind
  notification on startup announcing the bound name so the Claude session
  knows its identity from turn 1 (channel.Server.AnnounceSelf).
- Pretty channel content: 📨 banner + From/Type/Content lines (mirrors
  cc2cc render). decodeBody unwraps JSON-string bodies, then text/message
  /content fields on object bodies, falling back to compact JSON. Kind
  (msg/broadcast) plumbed through Inbound.Kind into meta.
- Default broker listen address 127.0.0.1:8080 -> 127.0.0.1:47821
  (clear of /etc/services on macOS, well below the ephemeral range).
  Dockerfile EXPOSE, compose.yml ports/listen, deploy/peerbus-broker.run,
  README/CLAUDE/docs all updated.
- Strip migration / v0.1.0 / peerbus-broker / peerbus-adapter chatter
  from README.md, source-file comments, and docs/integrations
  (pre-1.0, history kept only in docs/plans/completed/ archive).
- Tests: friendly-name shape + PEERBUS_NAME override, startup self-
  announcement, three-branch pretty-content decoding, bus.peers {self,
  peers} shape (mcp + channel + integration), ErrNameClaimed surface,
  ResumingClient short-circuit + Name() + filterSelf, default port
  constant + env override. -race + count=3 all green; coverage 67.4%.
@nnemirovsky nnemirovsky merged commit a579db8 into main May 20, 2026
3 checks passed
@nnemirovsky nnemirovsky deleted the friendly-names-v3-final branch May 20, 2026 16:58
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.

1 participant