add protocol specification
This commit is contained in:
845
PROTOCOL.md
Normal file
845
PROTOCOL.md
Normal file
@@ -0,0 +1,845 @@
|
||||
# Yonexus Protocol Specification
|
||||
|
||||
Version: draft v0.3
|
||||
Status: planning
|
||||
|
||||
---
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This document defines the built-in Yonexus communication protocol used between:
|
||||
- `Yonexus.Server`
|
||||
- `Yonexus.Client`
|
||||
|
||||
The protocol covers:
|
||||
- connection setup
|
||||
- pairing
|
||||
- authentication
|
||||
- heartbeat
|
||||
- status/lifecycle events
|
||||
- protocol-level errors
|
||||
- transport of application rule messages over the same WebSocket channel
|
||||
|
||||
Important security rule:
|
||||
- pairing codes must **not** be delivered to `Yonexus.Client` over the Yonexus WebSocket channel
|
||||
- pairing codes must be delivered out-of-band to a human administrator via Discord DM
|
||||
|
||||
---
|
||||
|
||||
## 2. Transport
|
||||
|
||||
Transport is WebSocket.
|
||||
|
||||
- `Yonexus.Server` listens as WebSocket server
|
||||
- `Yonexus.Client` connects as WebSocket client
|
||||
- protocol frames are UTF-8 text in v1
|
||||
- binary frames are not required in v1
|
||||
|
||||
Client connects to configured `mainHost`, which may be:
|
||||
- `ws://host:port/path`
|
||||
- `wss://host:port/path`
|
||||
- or raw `host:port` if normalized by implementation
|
||||
|
||||
Recommended canonical config:
|
||||
- prefer full WebSocket URL
|
||||
|
||||
---
|
||||
|
||||
## 3. Message Categories
|
||||
|
||||
## 3.1 Builtin Protocol Messages
|
||||
|
||||
Builtin messages always use:
|
||||
|
||||
```text
|
||||
builtin::${json_payload}
|
||||
```
|
||||
|
||||
`builtin` is reserved and must not be registered by user code.
|
||||
|
||||
## 3.2 Application Rule Messages
|
||||
|
||||
Application messages use:
|
||||
|
||||
```text
|
||||
${rule_identifier}::${message_content}
|
||||
```
|
||||
|
||||
When `Yonexus.Server` receives a rule message from a client, it must rewrite it before dispatch to:
|
||||
|
||||
```text
|
||||
${rule_identifier}::${sender_identifier}::${message_content}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Builtin Envelope
|
||||
|
||||
Builtin wire format:
|
||||
|
||||
```text
|
||||
builtin::{JSON}
|
||||
```
|
||||
|
||||
Canonical envelope:
|
||||
|
||||
```ts
|
||||
interface BuiltinEnvelope {
|
||||
type: string;
|
||||
requestId?: string;
|
||||
timestamp?: number; // UTC unix seconds
|
||||
payload?: Record<string, unknown>;
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- `timestamp` uses UTC unix seconds
|
||||
- `requestId` is used for correlation where needed
|
||||
- `payload` content depends on `type`
|
||||
|
||||
---
|
||||
|
||||
## 5. Builtin Message Types
|
||||
|
||||
## 5.1 Session Setup
|
||||
|
||||
### `hello`
|
||||
Sent by `Yonexus.Client` immediately after WebSocket connection opens.
|
||||
|
||||
Purpose:
|
||||
- declare identifier
|
||||
- advertise current auth material state
|
||||
- announce protocol version
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"hello",
|
||||
"requestId":"req_001",
|
||||
"timestamp":1711886400,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"hasSecret":true,
|
||||
"hasKeyPair":true,
|
||||
"publicKey":"<optional-public-key>",
|
||||
"protocolVersion":"1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `hello_ack`
|
||||
Sent by `Yonexus.Server` in response to `hello`.
|
||||
|
||||
Possible `nextAction` values:
|
||||
- `pair_required`
|
||||
- `auth_required`
|
||||
- `rejected`
|
||||
- `waiting_pair_confirm`
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"hello_ack",
|
||||
"requestId":"req_001",
|
||||
"timestamp":1711886401,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"nextAction":"pair_required"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5.2 Pairing Flow
|
||||
|
||||
## 5.2.1 Pairing Design Rule
|
||||
|
||||
`Yonexus.Server` must never send the actual `pairingCode` to `Yonexus.Client` through the Yonexus WebSocket channel.
|
||||
|
||||
The pairing code must be delivered to the configured human administrator using:
|
||||
- `notifyBotToken`
|
||||
- `adminUserId`
|
||||
|
||||
Specifically:
|
||||
- `Yonexus.Server` sends a Discord DM to the configured admin user
|
||||
- the DM contains the client identifier and pairing code
|
||||
- the human relays the code to the client side by some trusted out-of-band path
|
||||
|
||||
## 5.2.2 Pairing Request Creation
|
||||
|
||||
When pairing is required, `Yonexus.Server` generates:
|
||||
- `pairingCode`
|
||||
- `expiresAt`
|
||||
- `ttlSeconds`
|
||||
|
||||
The admin DM must include at minimum:
|
||||
- `identifier`
|
||||
- `pairingCode`
|
||||
- `expiresAt` or TTL
|
||||
|
||||
Example DM body:
|
||||
|
||||
```
|
||||
Yonexus pairing request
|
||||
identifier: client-a
|
||||
pairingCode: ABCD-1234-XYZ
|
||||
expiresAt: 1711886702
|
||||
```
|
||||
|
||||
### `pair_request`
|
||||
Sent by `Yonexus.Server` to `Yonexus.Client` after pairing starts.
|
||||
|
||||
Purpose:
|
||||
- indicate that pairing has started
|
||||
- indicate whether admin notification succeeded
|
||||
- provide expiry metadata without revealing the code
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"pair_request",
|
||||
"requestId":"req_002",
|
||||
"timestamp":1711886402,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"expiresAt":1711886702,
|
||||
"ttlSeconds":300,
|
||||
"adminNotification":"sent",
|
||||
"codeDelivery":"out_of_band"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Allowed `adminNotification` values:
|
||||
- `sent`
|
||||
- `failed`
|
||||
|
||||
If notification failed, pairing must not proceed until retried successfully.
|
||||
|
||||
### `pair_confirm`
|
||||
Sent by `Yonexus.Client` to confirm pairing.
|
||||
|
||||
Purpose:
|
||||
- submit the pairing code obtained out-of-band
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"pair_confirm",
|
||||
"requestId":"req_002",
|
||||
"timestamp":1711886410,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"pairingCode":"ABCD-1234-XYZ"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `pair_success`
|
||||
Sent by `Yonexus.Server` after successful pairing.
|
||||
|
||||
Purpose:
|
||||
- return generated secret
|
||||
- confirm trusted pairing state
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"pair_success",
|
||||
"requestId":"req_002",
|
||||
"timestamp":1711886411,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"secret":"<random-secret>",
|
||||
"pairedAt":1711886411
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `pair_failed`
|
||||
Sent by `Yonexus.Server` when pairing fails.
|
||||
|
||||
Typical reasons:
|
||||
- `expired`
|
||||
- `invalid_code`
|
||||
- `identifier_not_allowed`
|
||||
- `admin_notification_failed`
|
||||
- `internal_error`
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"pair_failed",
|
||||
"requestId":"req_002",
|
||||
"timestamp":1711886710,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"reason":"expired"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5.3 Authentication Flow
|
||||
|
||||
After pairing, reconnect authentication uses:
|
||||
- stored `secret`
|
||||
- 24-character random nonce
|
||||
- current UTC unix timestamp
|
||||
- client private key
|
||||
|
||||
## 5.3.1 Proof Construction
|
||||
|
||||
Logical proof content:
|
||||
|
||||
```text
|
||||
secret + nonce + timestamp
|
||||
```
|
||||
|
||||
Implementation recommendation:
|
||||
- use canonical serialized object bytes for signing
|
||||
|
||||
Recommended logical form:
|
||||
|
||||
```json
|
||||
{
|
||||
"secret":"...",
|
||||
"nonce":"...",
|
||||
"timestamp":1711886500
|
||||
}
|
||||
```
|
||||
|
||||
## 5.3.2 Signature Primitive
|
||||
|
||||
Recommended primitive:
|
||||
- digital signature using client private key
|
||||
- verification using stored client public key on server
|
||||
|
||||
### `auth_request`
|
||||
Sent by `Yonexus.Client` after pairing or on reconnect.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"auth_request",
|
||||
"requestId":"req_003",
|
||||
"timestamp":1711886500,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"nonce":"RANDOM24CHARACTERSTRINGX",
|
||||
"proofTimestamp":1711886500,
|
||||
"signature":"<base64-signature>",
|
||||
"publicKey":"<optional-public-key-if-rotating>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Server validation:
|
||||
1. identifier is allowlisted
|
||||
2. identifier exists in registry
|
||||
3. client is in paired state
|
||||
4. public key matches expected key if provided
|
||||
5. signature verifies successfully
|
||||
6. proof contains correct secret
|
||||
7. `abs(now - proofTimestamp) < 10`
|
||||
8. nonce has not appeared in recent nonce window
|
||||
9. handshake attempts in last 10 seconds do not exceed 10
|
||||
|
||||
### `auth_success`
|
||||
Sent by `Yonexus.Server` on success.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"auth_success",
|
||||
"requestId":"req_003",
|
||||
"timestamp":1711886501,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"authenticatedAt":1711886501,
|
||||
"status":"online"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `auth_failed`
|
||||
Sent by `Yonexus.Server` on auth failure.
|
||||
|
||||
Allowed reasons include:
|
||||
- `unknown_identifier`
|
||||
- `not_paired`
|
||||
- `invalid_signature`
|
||||
- `invalid_secret`
|
||||
- `stale_timestamp`
|
||||
- `future_timestamp`
|
||||
- `nonce_collision`
|
||||
- `rate_limited`
|
||||
- `re_pair_required`
|
||||
|
||||
### `re_pair_required`
|
||||
Sent by `Yonexus.Server` when trust state must be reset.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"re_pair_required",
|
||||
"requestId":"req_004",
|
||||
"timestamp":1711886510,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"reason":"nonce_collision"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5.4 Heartbeat
|
||||
|
||||
### `heartbeat`
|
||||
Sent by `Yonexus.Client` every 5 minutes after authentication.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"heartbeat",
|
||||
"timestamp":1711886800,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"status":"alive"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `heartbeat_ack`
|
||||
Optional response by `Yonexus.Server`.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"heartbeat_ack",
|
||||
"timestamp":1711886801,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"status":"online"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5.5 Status / Lifecycle Notifications
|
||||
|
||||
### `status_update`
|
||||
Sent by `Yonexus.Server` when client state changes.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"status_update",
|
||||
"timestamp":1711887220,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"status":"unstable",
|
||||
"reason":"heartbeat_timeout_7m"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `disconnect_notice`
|
||||
Sent by `Yonexus.Server` before deliberate close.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
builtin::{
|
||||
"type":"disconnect_notice",
|
||||
"timestamp":1711887460,
|
||||
"payload":{
|
||||
"identifier":"client-a",
|
||||
"reason":"heartbeat_timeout_11m"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5.6 Errors
|
||||
|
||||
### `error`
|
||||
Generic protocol-level error.
|
||||
|
||||
Recommended builtin error codes:
|
||||
- `MALFORMED_MESSAGE`
|
||||
- `UNSUPPORTED_PROTOCOL_VERSION`
|
||||
- `IDENTIFIER_NOT_ALLOWED`
|
||||
- `PAIRING_REQUIRED`
|
||||
- `PAIRING_EXPIRED`
|
||||
- `ADMIN_NOTIFICATION_FAILED`
|
||||
- `AUTH_FAILED`
|
||||
- `NONCE_COLLISION`
|
||||
- `RATE_LIMITED`
|
||||
- `RE_PAIR_REQUIRED`
|
||||
- `CLIENT_OFFLINE`
|
||||
- `INTERNAL_ERROR`
|
||||
|
||||
---
|
||||
|
||||
## 6. State Machines
|
||||
|
||||
## 6.1 Client State Machine
|
||||
|
||||
Suggested `Yonexus.Client` states:
|
||||
- `idle`
|
||||
- `connecting`
|
||||
- `connected`
|
||||
- `pairing_required`
|
||||
- `pairing_pending`
|
||||
- `paired`
|
||||
- `authenticating`
|
||||
- `authenticated`
|
||||
- `reconnecting`
|
||||
- `error`
|
||||
|
||||
Typical transitions:
|
||||
|
||||
```
|
||||
idle
|
||||
-> connecting
|
||||
-> connected
|
||||
-> (pairing_required | authenticating)
|
||||
|
||||
pairing_required
|
||||
-> pairing_pending
|
||||
-> paired
|
||||
-> authenticating
|
||||
-> authenticated
|
||||
|
||||
authenticated
|
||||
-> reconnecting
|
||||
-> connecting
|
||||
```
|
||||
|
||||
On `re_pair_required`:
|
||||
|
||||
```
|
||||
authenticated | authenticating -> pairing_required
|
||||
```
|
||||
|
||||
## 6.2 Server-Side Client State
|
||||
|
||||
Per client trust state:
|
||||
- `unpaired`
|
||||
- `pending`
|
||||
- `paired`
|
||||
- `revoked`
|
||||
|
||||
Per client liveness state:
|
||||
- `online`
|
||||
- `unstable`
|
||||
- `offline`
|
||||
|
||||
---
|
||||
|
||||
## 7. Security Windows and Replay Protection
|
||||
|
||||
## 7.1 Nonce Requirements
|
||||
|
||||
Nonce rules:
|
||||
- exactly 24 random characters
|
||||
- fresh per auth attempt
|
||||
- must not repeat within recent security window
|
||||
|
||||
## 7.2 Recent Nonce Window
|
||||
|
||||
Server stores for each client:
|
||||
- the last 10 nonces seen within the recent validity window
|
||||
|
||||
If a nonce collides:
|
||||
- authentication fails
|
||||
- server marks condition unsafe
|
||||
- client must re-pair
|
||||
|
||||
## 7.3 Handshake Attempt Window
|
||||
|
||||
Server stores recent handshake attempt timestamps.
|
||||
|
||||
If more than 10 handshake attempts occur within 10 seconds:
|
||||
- authentication fails
|
||||
- server marks condition unsafe
|
||||
- client must re-pair
|
||||
|
||||
## 7.4 Time Drift Validation
|
||||
|
||||
Server validates:
|
||||
|
||||
```text
|
||||
abs(current_utc_unix_time - proofTimestamp) < 10
|
||||
```
|
||||
|
||||
If validation fails:
|
||||
- auth fails
|
||||
- no session is established
|
||||
|
||||
---
|
||||
|
||||
## 8. Rule Message Dispatch
|
||||
|
||||
All non-builtin messages use:
|
||||
|
||||
```text
|
||||
${rule_identifier}::${message_content}
|
||||
```
|
||||
|
||||
Client to server example:
|
||||
|
||||
```text
|
||||
chat_sync::{"conversationId":"abc","body":"hello"}
|
||||
```
|
||||
|
||||
Server rewrites before matching:
|
||||
|
||||
```text
|
||||
chat_sync::client-a::{"conversationId":"abc","body":"hello"}
|
||||
```
|
||||
|
||||
Dispatch algorithm:
|
||||
1. parse first delimiter section as `rule_identifier`
|
||||
2. if `rule_identifier === builtin`, route to builtin protocol handler
|
||||
3. otherwise iterate registered rules in registration order
|
||||
4. invoke the first exact match
|
||||
5. ignore/log if no match is found
|
||||
|
||||
Processor input:
|
||||
- on client: `${rule_identifier}::${message_content}`
|
||||
- on server for client-originated messages: `${rule_identifier}::${sender_identifier}::${message_content}`
|
||||
|
||||
---
|
||||
|
||||
## 9. Connection Rules
|
||||
|
||||
Server should reject connection attempts when:
|
||||
- identifier is absent
|
||||
- identifier is not in configured allowlist
|
||||
- protocol version is unsupported
|
||||
- hello/auth payload is malformed
|
||||
|
||||
Recommended v1 policy:
|
||||
- only one active authenticated connection per client identifier
|
||||
- terminate old connection and accept new one after successful auth
|
||||
|
||||
---
|
||||
|
||||
## 10. Persistence Semantics
|
||||
|
||||
## 10.1 Yonexus.Server Persists
|
||||
|
||||
At minimum:
|
||||
- identifier
|
||||
- public key
|
||||
- secret
|
||||
- trust state
|
||||
- pairing code + expiry if pending
|
||||
- pairing notification metadata
|
||||
- last known liveness status
|
||||
- metadata timestamps
|
||||
|
||||
May persist or reset on restart:
|
||||
- recent nonces
|
||||
- recent handshake attempts
|
||||
|
||||
Recommended v1:
|
||||
- clear rolling security windows on restart
|
||||
- keep long-lived trust records
|
||||
|
||||
## 10.2 Yonexus.Client Persists
|
||||
|
||||
At minimum:
|
||||
- identifier
|
||||
- private key
|
||||
- secret
|
||||
- optional last successful pair/auth metadata
|
||||
|
||||
---
|
||||
|
||||
## 11. Versioning
|
||||
|
||||
Protocol version is advertised during `hello`.
|
||||
|
||||
Initial version:
|
||||
|
||||
```text
|
||||
1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Canonical JSON Shapes
|
||||
|
||||
```ts
|
||||
interface HelloPayload {
|
||||
identifier: string;
|
||||
hasSecret: boolean;
|
||||
hasKeyPair: boolean;
|
||||
publicKey?: string;
|
||||
protocolVersion: string;
|
||||
}
|
||||
|
||||
interface PairRequestPayload {
|
||||
identifier: string;
|
||||
expiresAt: number;
|
||||
ttlSeconds: number;
|
||||
adminNotification: "sent" | "failed";
|
||||
codeDelivery: "out_of_band";
|
||||
}
|
||||
|
||||
interface PairConfirmPayload {
|
||||
identifier: string;
|
||||
pairingCode: string;
|
||||
}
|
||||
|
||||
interface PairSuccessPayload {
|
||||
identifier: string;
|
||||
secret: string;
|
||||
pairedAt: number;
|
||||
}
|
||||
|
||||
interface AuthRequestPayload {
|
||||
identifier: string;
|
||||
nonce: string;
|
||||
proofTimestamp: number;
|
||||
signature: string;
|
||||
publicKey?: string;
|
||||
}
|
||||
|
||||
interface HeartbeatPayload {
|
||||
identifier: string;
|
||||
status: "alive";
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Example Flows
|
||||
|
||||
## 13.1 First-Time Pairing Flow
|
||||
|
||||
```
|
||||
Client connects WS
|
||||
Client -> builtin::hello
|
||||
Server sends Discord DM to configured admin with identifier + pairingCode
|
||||
Server -> builtin::hello_ack(nextAction=pair_required)
|
||||
Server -> builtin::pair_request(expiresAt, adminNotification=sent, codeDelivery=out_of_band)
|
||||
Human reads DM and relays pairingCode to client side
|
||||
Client -> builtin::pair_confirm(pairingCode)
|
||||
Server -> builtin::pair_success(secret)
|
||||
Client stores secret
|
||||
Client -> builtin::auth_request(signature over secret+nonce+timestamp)
|
||||
Server -> builtin::auth_success
|
||||
Client enters authenticated state
|
||||
```
|
||||
|
||||
## 13.2 Normal Reconnect Flow
|
||||
|
||||
```
|
||||
Client connects WS
|
||||
Client -> builtin::hello(hasSecret=true)
|
||||
Server -> builtin::hello_ack(nextAction=auth_required)
|
||||
Client -> builtin::auth_request(...)
|
||||
Server -> builtin::auth_success
|
||||
Client begins heartbeat schedule
|
||||
```
|
||||
|
||||
## 13.3 Unsafe Replay / Collision Flow
|
||||
|
||||
```
|
||||
Client -> builtin::auth_request(nonce collision)
|
||||
Server detects unsafe condition
|
||||
Server -> builtin::re_pair_required(reason=nonce_collision)
|
||||
Server invalidates existing secret/session trust
|
||||
Server sends fresh Discord DM pairing notification on next pairing start
|
||||
Client returns to pairing_required state
|
||||
```
|
||||
|
||||
## 13.4 Heartbeat Timeout Flow
|
||||
|
||||
```
|
||||
Client authenticated
|
||||
No heartbeat for 7 min -> server marks unstable
|
||||
No heartbeat for 11 min -> server marks offline
|
||||
Server -> builtin::disconnect_notice
|
||||
Server closes WS connection
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. Implementation Notes
|
||||
|
||||
## 14.1 Parsing
|
||||
|
||||
Because the wire format is string-based with `::` delimiters:
|
||||
- only the first delimiter split should determine the `rule_identifier`
|
||||
- for `builtin`, the remainder is parsed as JSON once
|
||||
- message content itself may contain `::`, so avoid naive full split logic
|
||||
|
||||
## 14.2 Discord DM Notification
|
||||
|
||||
When pairing starts on `Yonexus.Server`:
|
||||
- use configured `notifyBotToken`
|
||||
- send DM to `adminUserId`
|
||||
- include only required pairing data
|
||||
- if DM send fails, surface pairing notification failure
|
||||
|
||||
Sensitive values that must never be logged in plaintext:
|
||||
- `secret`
|
||||
- private key
|
||||
- raw proof material
|
||||
|
||||
---
|
||||
|
||||
## 15. Open Clarifications
|
||||
|
||||
1. Exact signing algorithm: Ed25519 is a strong default candidate
|
||||
2. Secret length and generation requirements
|
||||
3. Pairing code format and length
|
||||
4. Is human code relay enough for v1, or should admin approve/deny controls be added later?
|
||||
5. Should `heartbeat_ack` be mandatory or optional?
|
||||
6. Should client reconnect use exponential backoff?
|
||||
7. Should duplicate active connections replace old sessions or be rejected in stricter modes?
|
||||
|
||||
---
|
||||
|
||||
## 16. Reserved Builtin Types
|
||||
|
||||
Reserved builtin `type` values:
|
||||
- `hello`
|
||||
- `hello_ack`
|
||||
- `pair_request`
|
||||
- `pair_confirm`
|
||||
- `pair_success`
|
||||
- `pair_failed`
|
||||
- `auth_request`
|
||||
- `auth_success`
|
||||
- `auth_failed`
|
||||
- `re_pair_required`
|
||||
- `heartbeat`
|
||||
- `heartbeat_ack`
|
||||
- `status_update`
|
||||
- `disconnect_notice`
|
||||
- `error`
|
||||
|
||||
These names are reserved by Yonexus and must not be repurposed by user rules.
|
||||
30
README.md
30
README.md
@@ -0,0 +1,30 @@
|
||||
# Yonexus.Protocol
|
||||
|
||||
This repository contains the **shared communication protocol specification** for the Yonexus system.
|
||||
|
||||
It is referenced as a git submodule by both `Yonexus.Server` and `Yonexus.Client`.
|
||||
|
||||
## Contents
|
||||
|
||||
- `PROTOCOL.md` — full protocol specification
|
||||
- TypeScript type definitions (planned: `src/types.ts`)
|
||||
- Canonical JSON shape references
|
||||
|
||||
## Purpose
|
||||
|
||||
Yonexus is a cross-instance communication system for OpenClaw, split into:
|
||||
- `Yonexus.Server` — the central hub plugin
|
||||
- `Yonexus.Client` — the client plugin
|
||||
- `Yonexus.Protocol` — the shared protocol definition
|
||||
|
||||
Both server and client implementations must conform to the protocol defined in this repository.
|
||||
|
||||
## Version
|
||||
|
||||
Current protocol version: **draft v0.3**
|
||||
|
||||
## References
|
||||
|
||||
- [Yonexus umbrella repository](https://git.hangman-lab.top/nav/Yonexus)
|
||||
- [Yonexus.Server](https://git.hangman-lab.top/nav/Yonexus.Server)
|
||||
- [Yonexus.Client](https://git.hangman-lab.top/nav/Yonexus.Client)
|
||||
|
||||
Reference in New Issue
Block a user