SHARDWIRE
Advanced

Custom domain contracts (spike)

Architecture notes on app-defined RPC/events alongside Shardwire: why they are not first-class in core today, and what would have to be decided before they could be.

This page is a spike / ADR-style note for maintainers and advanced integrators. It answers: “Could Shardwire carry my own music.play actions like built-in Discord actions?”

Current charter: Shardwire is a Discord-first bridge—negotiation, manifests, scoped secrets, strict startup, and diagnostics are all Discord-catalog-shaped (Product boundaries, Capabilities & scoped secrets).

Proposal (external)

Allow arbitrary domain envelopes on the same wire, for example:

  • music.play, queue.updated, player.state
  • schema validation (e.g. Zod) and codegen
  • manifest + secret scope + strict startup extended to those names

That would move the product toward a generic split-process application bus.

Why this is not in core today

  1. Negotiation model — Today, negotiated events / actions are drawn from a fixed catalog aligned with Discord intents and bot-side execution. Arbitrary names require a second negotiation channel, versioning, and forward compatibility rules.

  2. Secret scope semanticsgenerateSecretScope and expectedScope express Discord capability minima/maxima. Mapping “secret allows music.seek” into the same SecretPermissions shape either overloads meaning or forks the type system.

  3. Strict startup and diagnosisdiagnoseShardwireApp encodes Discord-specific rules (intents, filter metadata keys, subscription vs manifest). Domain RPC would need a parallel diagnosis system or risk mixing incompatible issue codes.

  4. Security and abuse — Built-in actions ultimately map to audited Discord runtime code paths. User-defined RPC would require sandboxing, payload limits, authz between apps, and clear threat models—platform scope.

  5. Operational story — Replay, buffering, and resumable sessions (often requested with custom contracts) imply persistence and ordering guarantees Shardwire does not promise today.

  • Second channel for domain state — Keep Shardwire for Discord only; use HTTP, Redis, or a small dedicated WebSocket for music.* payloads between your dashboard and a co-located app or API. The music controller recipe shows this split.

  • Optional experimental package — If you prototype defineShardwireContract, do not reuse manifest.events / server.secrets.allow for non-Discord symbols until negotiation, auth, and codegen are specified in a standalone design doc.

If core ever adopts a subset

A minimal, charter-safe subset might look like: documented envelopes carried only after explicit opt-in at both ends, with no merging into generateSecretScope / strict startup until ADR sign-off. Anything broader should stay in a separate package and release cadence.

  • How Shardwire works
  • Optional @shardwire/react companion package in this repository (packages/react) for dashboard-facing hooks

On this page