← Back to documentation

Bridge Protocol Specification

Version: 0.1 (Draft)
Date: March 2026
Status: Proposal
Depends on: Edge Contract Spec, Visual Primitives Spec, Stroke Format Spec
Used by: Tutor, Edge (via embedded Bridge library)


1. Overview

The Bridge Protocol defines how Tutor communicates with Edge. It translates Tutor's semantic intent into Edge's visual primitives and streams Edge's stroke data back to Tutor.

Bridge is NOT a hosted service. It is:

  1. A protocol (this spec)
  2. A library embedded in each Edge app
  3. A thin adapter in the Tutor app
┌─────────────┐                           ┌─────────────┐
│   TUTOR     │                           │    EDGE     │
│             │                           │             │
│  Semantic   │◄─── Bridge Protocol ────►│  Primitives │
│  Commands   │      (WebSocket)          │  + Strokes  │
│             │                           │             │
└─────────────┘                           └─────────────┘

1.1 Design Goals

Goal Implication
Semantic abstraction Tutor says "highlight the error", not pixel coordinates
Capability adaptation Bridge adapts output to Edge capabilities
Low latency Direct WebSocket, no intermediate service
Offline resilience Graceful degradation, reconnection, replay
Debuggable Human-readable message format in development

1.2 Non-Goals


2. Architecture

2.1 Component Placement

┌─────────────────────────────────────────────────────────────────┐
│               TUTOR DEVICE (Phone / Computer / Browser)         │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                    Tutor Core                              │  │
│  │  • Session logic                                          │  │
│  │  • Behavior engine                                        │  │
│  │  • Voice processing                                       │  │
│  └────────────────────────┬──────────────────────────────────┘  │
│                           │ Semantic commands                    │
│                           ▼                                      │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                  Bridge Adapter                            │  │
│  │  • Translate semantic → primitives                        │  │
│  │  • Manage WebSocket connection                            │  │
│  │  • Handle capability adaptation                           │  │
│  └────────────────────────┬──────────────────────────────────┘  │
│                           │                                      │
└───────────────────────────┼──────────────────────────────────────┘
                            │ WebSocket (WSS)
                            │
┌───────────────────────────┼──────────────────────────────────────┐
│                           │                                      │
│  ┌────────────────────────▼──────────────────────────────────┐  │
│  │                  Bridge Library                            │  │
│  │  • Parse incoming primitives                              │  │
│  │  • Adapt to device capabilities                           │  │
│  │  • Batch stroke data                                      │  │
│  └────────────────────────┬──────────────────────────────────┘  │
│                           │                                      │
│  ┌────────────────────────▼──────────────────────────────────┐  │
│  │                    Edge Core                               │  │
│  │  • Native rendering                                       │  │
│  │  • Stroke capture                                         │  │
│  └───────────────────────────────────────────────────────────┘  │
│                        EDGE (Tablet)                            │
└─────────────────────────────────────────────────────────────────┘

2.2 Responsibility Split

Component Responsibilities
Tutor Core Pedagogical decisions, session orchestration
Bridge Adapter (on Tutor) Semantic → primitive translation, connection management
Bridge Library (on Edge) Primitive parsing, capability adaptation, stroke batching
Edge Core Native rendering, stroke capture

3. Connection Lifecycle

3.1 Discovery & Pairing

First-time pairing:

┌─────────┐                              ┌─────────┐
│  Tutor  │                              │  Edge   │
└────┬────┘                              └────┬────┘
     │                                        │
     │  User opens Tutor app                  │
     │  "Scan QR or enter code"               │
     │                                        │
     │                    User opens Edge app │
     │                    Shows: QR + 6-digit │
     │                    code + local IP     │
     │◄───────────────────────────────────────│
     │                                        │
     │  User scans QR or enters code          │
     │                                        │
     │  PAIR_REQUEST {code, tutorId}          │
     │───────────────────────────────────────►│
     │                                        │
     │  PAIR_ACCEPT {edgeId, publicKey}       │
     │◄───────────────────────────────────────│
     │                                        │
     │  Store pairing: edgeId ↔ tutorId       │
     │                                        │

Subsequent sessions (auto-pair):

┌─────────┐                              ┌─────────┐
│  Tutor  │                              │  Edge   │
└────┬────┘                              └────┬────┘
     │                                        │
     │  Both apps open on same network        │
     │                                        │
     │  mDNS discovery / stored IP            │
     │───────────────────────────────────────►│
     │                                        │
     │  RECONNECT {tutorId, sessionToken}     │
     │───────────────────────────────────────►│
     │                                        │
     │  CAPABILITIES {...}                    │
     │◄───────────────────────────────────────│
     │                                        │
     │  SESSION_CONFIG {...}                  │
     │───────────────────────────────────────►│
     │                                        │

3.2 Connection Transport

Transport Use Case
WebSocket (WSS) Primary, real-time bidirectional
Local WebSocket Same WiFi, lower latency
Cloud relay Fallback when direct connection fails

Connection preference order:

  1. Local network (mDNS discovery)
  2. Direct via stored IP
  3. Cloud relay (Tutor → Cloud → Edge)

3.3 Session States

┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│    ┌─────────┐      Pair       ┌──────────┐                     │
│    │ UNPAIRED│────────────────►│  PAIRED  │                     │
│    └─────────┘                 └────┬─────┘                     │
│         ▲                           │                            │
│         │ Unpair                    │ Connect                    │
│         │                           ▼                            │
│    ┌─────────┐    Disconnect   ┌──────────┐     Start session   │
│    │  IDLE   │◄────────────────│CONNECTED │─────────────────┐   │
│    └─────────┘                 └──────────┘                 │   │
│         ▲                           ▲                       │   │
│         │                           │ Reconnect             │   │
│         │                           │                       ▼   │
│         │                      ┌──────────┐            ┌────────┐│
│         │                      │RECONNECT │◄───────────│ ACTIVE ││
│         │                      └──────────┘  Conn lost └───┬────┘│
│         │                                                  │     │
│         │                      End session                 │     │
│         └──────────────────────────────────────────────────┘     │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

4. Semantic Commands

Tutor speaks in semantic commands. Bridge translates to primitives.

4.1 Command Categories

SEMANTIC COMMANDS
├── Session
│   ├── START_SESSION
│   ├── END_SESSION
│   ├── PAUSE_SESSION
│   └── RESUME_SESSION
│
├── Exercise
│   ├── LOAD_EXERCISE
│   ├── NEXT_EXERCISE
│   └── PREVIOUS_EXERCISE
│
├── Annotation
│   ├── HIGHLIGHT_REGION
│   ├── HIGHLIGHT_ERROR
│   ├── HIGHLIGHT_SUCCESS
│   ├── POINT_AT
│   ├── CIRCLE
│   ├── BRACKET
│   └── STRIKETHROUGH
│
├── Feedback
│   ├── MARK_CORRECT
│   ├── MARK_INCORRECT
│   ├── MARK_PARTIAL
│   └── PULSE_ATTENTION
│
├── Hint
│   ├── SHOW_HINT
│   ├── HIDE_HINT
│   └── POINT_HINT
│
└── Control
    ├── CLEAR_ANNOTATIONS
    ├── CLEAR_HINTS
    └── CLEAR_FEEDBACK

4.2 Command Definitions

Session Commands

START_SESSION

{
  "command": "START_SESSION",
  "params": {
    "studentId": "stu_abc123",
    "courseId": "course_algebra1",
    "resumeFrom": "ex_4520"
  }
}

Bridge actions:

  1. Send SESSION_CONFIG to Edge
  2. Load student's last exercise (or first if new)
  3. Initialize stroke stream

END_SESSION

{
  "command": "END_SESSION",
  "params": {
    "reason": "completed",
    "saveProgress": true
  }
}

Exercise Commands

LOAD_EXERCISE

{
  "command": "LOAD_EXERCISE",
  "params": {
    "exerciseId": "ex_4521",
    "content": {
      "type": "equation_solve",
      "instruction": "Solve for x:",
      "equation": "3x + 5 = 14",
      "workZone": true,
      "answerZone": true
    }
  }
}

Bridge translates to primitives:

{
  "type": "LOAD_EXERCISE",
  "payload": {
    "exerciseId": "ex_4521",
    "primitives": [
      {"type": "TEXT", "id": "instr", "content": "Solve for x:", ...},
      {"type": "MATH_BLOCK", "id": "eq", "content": "3x + 5 = 14", ...},
      {"type": "INPUT_ZONE", "id": "work", "semantic": "work", ...},
      {"type": "INPUT_ZONE", "id": "answer", "semantic": "answer", ...}
    ]
  }
}

Annotation Commands

HIGHLIGHT_REGION

{
  "command": "HIGHLIGHT_REGION",
  "params": {
    "target": {"zone": "work", "strokeIds": ["str_042", "str_043"]},
    "intent": "focus"
  }
}

Bridge calculates bounding box from stroke IDs, sends HIGHLIGHT primitive.

HIGHLIGHT_ERROR

{
  "command": "HIGHLIGHT_ERROR",
  "params": {
    "target": {"zone": "work", "stepIndex": 2},
    "message": "Check the sign here"
  }
}

Bridge translates to:

POINT_AT

{
  "command": "POINT_AT",
  "params": {
    "target": {"zone": "work", "position": {"x": 0.35, "y": 0.42}},
    "from": "above"
  }
}

Bridge translates to ARROW primitive.

Feedback Commands

MARK_CORRECT

{
  "command": "MARK_CORRECT",
  "params": {
    "target": {"zone": "answer"}
  }
}

Bridge translates to:

MARK_INCORRECT

{
  "command": "MARK_INCORRECT",
  "params": {
    "target": {"zone": "answer"},
    "showCorrect": false
  }
}

Hint Commands

SHOW_HINT

{
  "command": "SHOW_HINT",
  "params": {
    "content": "What operation undoes addition?",
    "anchor": {"zone": "work", "stepIndex": 1},
    "position": "above"
  }
}

Bridge translates to HINT_BUBBLE primitive.


5. Stroke Stream Processing

5.1 Stream Flow

Edge                    Bridge (on Edge)           Tutor
  │                           │                       │
  │  Raw strokes              │                       │
  │──────────────────────────►│                       │
  │                           │                       │
  │                           │  Batch + normalize    │
  │                           │                       │
  │                           │  STROKE_BATCH         │
  │                           │──────────────────────►│
  │                           │                       │
  │                           │                       │  Vision
  │                           │                       │  parsing
  │                           │                       │
  │                           │  STROKE_ACK           │
  │                           │◄──────────────────────│
  │                           │                       │

5.2 Stroke Enrichment

Bridge Library on Edge adds metadata before sending:

{
  "type": "STROKE_BATCH",
  "payload": {
    "sessionId": "sess_xyz",
    "seq": 42,
    "strokes": [
      {
        "id": "str_042",
        "ts": 1711670500000,
        "pts": [...],
        "zone": "work",
        "bounds": {"x": 0.12, "y": 0.35, "w": 0.18, "h": 0.06}
      }
    ]
  }
}

Added fields:

5.3 Stroke References

Tutor can reference strokes in commands:

{
  "command": "HIGHLIGHT_ERROR",
  "params": {
    "target": {"strokeIds": ["str_042", "str_043"]}
  }
}

Bridge maintains stroke → position mapping to calculate highlight bounds.


6. Capability Adaptation

6.1 Adaptation Rules

Bridge Adapter (on Tutor) adapts commands based on Edge capabilities:

Capability Adaptation
color: false Convert intent colors to patterns
refreshRate: slow Batch visual updates, skip animations
stylus: false Hide INPUT_GUIDE, adjust INPUT_ZONE

6.2 Adaptation Examples

Color → Grayscale:

Command: HIGHLIGHT_ERROR
│
├─► Edge has color
│   └─► HIGHLIGHT {intent: "error"} → Red fill
│
└─► Edge no color
    └─► HIGHLIGHT {intent: "error"} → Hatch pattern + thick border

Animation → Static:

Command: PULSE_ATTENTION
│
├─► Edge refreshRate: fast
│   └─► PULSE → Animated expanding circle
│
└─► Edge refreshRate: slow
    └─► PULSE → Single inverted flash

6.3 Graceful Degradation

When Edge can't render something:

  1. Edge sends ERROR with primitive ID
  2. Bridge logs and optionally notifies Tutor
  3. Tutor may fall back to voice: "Look at the second line..."

7. Error Handling

7.1 Connection Errors

Error Tutor Response
WebSocket disconnect Auto-reconnect (exponential backoff)
Edge unresponsive Voice: "I lost connection to your notebook"
Pairing lost Prompt re-pairing

7.2 Protocol Errors

Error Bridge Response
Unknown command Log, ignore
Malformed primitive Skip primitive, continue
Missing stroke reference Use fallback position

7.3 Edge Errors

Edge sends ERROR messages:

{
  "type": "ERROR",
  "payload": {
    "code": "RENDER_FAILED",
    "primitiveId": "math_001",
    "message": "Unsupported LaTeX: \\frac"
  }
}

Bridge Adapter can:

  1. Retry with simplified primitive
  2. Fall back to TEXT for math
  3. Report to Tutor for voice fallback

8. Sync & Consistency

8.1 State Ownership

State Owner Sync
Exercise content Tutor Push to Edge on load
Student strokes Edge Stream to Tutor
Annotations Tutor Push to Edge
Session progress Tutor Persist to Cloud

8.2 Conflict Resolution

Strokes are append-only. No conflicts possible.

Annotations are replace-only. Last command wins.

Exercise state is Tutor-authoritative. Edge never modifies.

8.3 Reconnection Sync

On reconnect:

  1. Edge sends current stroke count
  2. Tutor compares to last ACK'd count
  3. If mismatch, Edge replays missing strokes
  4. Tutor re-sends current exercise + annotations
// Edge reconnection message
{
  "type": "RECONNECT_STATE",
  "payload": {
    "sessionId": "sess_xyz",
    "exerciseId": "ex_4521",
    "strokeCount": 87,
    "lastSeq": 42
  }
}

// Tutor response if mismatch
{
  "type": "SYNC_REQUEST",
  "payload": {
    "replayStrokesFrom": 35,
    "resendExercise": true
  }
}

9. Performance Targets

9.1 Latency Budgets

Path Target Max
Stroke capture → Tutor 250ms 500ms
Tutor command → Edge render 150ms 300ms
Reconnection 2s 5s
Exercise load 500ms 1s

9.2 Throughput

Metric Target
Stroke batches/sec 5 (200ms interval)
Points/batch Up to 100
Commands/sec Up to 10
Concurrent sessions/Tutor 1 (single student)

9.3 Bandwidth

Scenario Bandwidth
Active writing ~10 KB/s
Idle <1 KB/s (heartbeat only)
Exercise load ~5-20 KB burst

10. Security

10.1 Transport Security

10.2 Session Security

10.3 Message Integrity


11. Message Reference

11.1 Tutor → Edge (via Bridge)

Message Purpose
SESSION_CONFIG Configure session parameters
LOAD_EXERCISE Load exercise content
PRIMITIVE Single visual primitive
PRIMITIVE_BATCH Multiple primitives
CLEAR Clear layer
STROKE_ACK Acknowledge strokes
SESSION_END End session
SYNC_REQUEST Request state sync

11.2 Edge → Tutor (via Bridge)

Message Purpose
CAPABILITIES Device capabilities
STROKE_BATCH Stroke data
GESTURE User gesture
HEARTBEAT Status update
ZONE_ACTIVITY Input zone enter/exit
ERROR Error report
RECONNECT_STATE State on reconnect

11.3 Semantic Commands (Tutor internal)

Command Translates to
START_SESSION SESSION_CONFIG + LOAD_EXERCISE
LOAD_EXERCISE LOAD_EXERCISE (with primitives)
HIGHLIGHT_REGION HIGHLIGHT
HIGHLIGHT_ERROR HIGHLIGHT + UNDERLINE + HINT_BUBBLE
MARK_CORRECT HIGHLIGHT + MARK
SHOW_HINT HINT_BUBBLE
CLEAR_ANNOTATIONS CLEAR {target: "annotations"}

Appendix A: Example Session Flow

Time  Tutor                          Bridge                         Edge
─────────────────────────────────────────────────────────────────────────
0.0s  START_SESSION ─────────────────►
                                      SESSION_CONFIG ─────────────────►
                                      LOAD_EXERCISE ──────────────────►
                                                                      Render
0.5s  Voice: "Let's continue          
      with algebra..."
                                                      ◄─── STROKE_BATCH
2.0s                                  Parse: "3x"     
                                      (wait, incomplete)
                                                      ◄─── STROKE_BATCH
3.5s                                  Parse: "3x + 5 = 14"
                                      (equation, wait for work)
                                                      ◄─── STROKE_BATCH
5.0s                                  Parse: "3x = 9" ✓
      (Tutor: correct step,
       stay quiet)
                                                      ◄─── STROKE_BATCH  
6.5s                                  Parse: "x = 3" ✓
      MARK_CORRECT ──────────────────►
                                      HIGHLIGHT ─────────────────────►
                                      MARK ───────────────────────────►
                                                                      Render ✓
      Voice: "Nice work!"

Appendix B: Capability Matrix

Capability BOOX reMarkable iPad Web
color ✓ (some)
refreshRate medium slow fast fast
stylusPressure
stylusTilt
audio ✓ (some)
haptics

Next spec: Vision API (strokes → structured math)