Files
Timmy-time-dashboard/docs/protocol/morrowind-perception-command-spec.md
Perplexity Computer 215329146a
Some checks failed
Tests / lint (pull_request) Has been cancelled
Tests / test (pull_request) Has been cancelled
feat(morrowind): add Perception/Command protocol + SQLite command log (#859, #855)
Implement two foundational infrastructure pieces for the Morrowind integration:

1. Perception/Command Protocol (Issue #859):
   - Formal spec document with JSON schemas, API contracts, versioning strategy
   - Engine-agnostic design following the Falsework Rule
   - Pydantic v2 models (PerceptionOutput, CommandInput) for runtime validation

2. SQLite Command Log + Training Pipeline (Issue #855):
   - SQLAlchemy model for command_log table with full indexing
   - CommandLogger class with log_command(), query(), export_training_data()
   - TrainingExporter with chat-completion, episode, and instruction formats
   - Storage management (rotation/archival) utilities
   - Alembic migration for the new table

Includes 39 passing tests covering schema validation, logging, querying, and export.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 22:33:13 +00:00

12 KiB
Raw Blame History

Morrowind Perception/Command Protocol Specification

Version: 1.0.0 Status: Draft Authors: Timmy Infrastructure Team Date: 2026-03-21


1. Overview

This document defines the engine-agnostic Perception/Command protocol used by Timmy's heartbeat loop to observe the game world and issue commands. The protocol is designed around the Falsework Rule: TES3MP (Morrowind) is scaffolding. If the engine swaps, only the bridge and perception script change — the heartbeat, reasoning, and journal remain sovereign.

1.1 Design Principles

  • Engine-agnostic: Schemas reference abstract concepts (cells, entities, quests), not Morrowind-specific internals.
  • Versioned: Every payload carries a protocol_version so consumers can negotiate compatibility.
  • Typed at the boundary: Pydantic v2 models enforce validation on both the producer (bridge) and consumer (heartbeat) side.
  • Logged by default: Every command is persisted to the SQLite command log for training-data extraction (see Issue #855).

2. Protocol Version Strategy

Field Type Description
protocol_version string SemVer string (e.g. "1.0.0")

Compatibility Rules

  • Patch bump (1.0.x): additive fields with defaults — fully backward-compatible.
  • Minor bump (1.x.0): new optional endpoints or enum values — old clients still work.
  • Major bump (x.0.0): breaking schema change — requires coordinated upgrade of bridge and heartbeat.

Consumers MUST reject payloads whose major version exceeds their own.


3. Perception Output Schema

Returned by GET /perception. Represents a single snapshot of the game world as observed by the bridge.

{
  "protocol_version": "1.0.0",
  "timestamp": "2026-03-21T14:30:00Z",
  "agent_id": "timmy",
  "location": {
    "cell": "Balmora",
    "x": 1024.5,
    "y": -512.3,
    "z": 64.0,
    "interior": false
  },
  "health": {
    "current": 85,
    "max": 100
  },
  "nearby_entities": [
    {
      "entity_id": "npc_001",
      "name": "Caius Cosades",
      "entity_type": "npc",
      "distance": 12.5,
      "disposition": 65
    }
  ],
  "inventory_summary": {
    "gold": 150,
    "item_count": 23,
    "encumbrance_pct": 0.45
  },
  "active_quests": [
    {
      "quest_id": "mq_01",
      "name": "Report to Caius Cosades",
      "stage": 10
    }
  ],
  "environment": {
    "time_of_day": "afternoon",
    "weather": "clear",
    "is_combat": false,
    "is_dialogue": false
  },
  "raw_engine_data": {}
}

3.1 Field Reference

Field Type Required Description
protocol_version string yes Protocol SemVer
timestamp ISO 8601 datetime yes When the snapshot was taken
agent_id string yes Which agent this perception belongs to
location.cell string yes Current cell/zone name
location.x/y/z float yes World coordinates
location.interior bool yes Whether the agent is indoors
health.current int (0max) yes Current health
health.max int (>0) yes Maximum health
nearby_entities array yes Entities within perception radius (may be empty)
inventory_summary object yes Lightweight inventory overview
active_quests array yes Currently tracked quests
environment object yes World-state flags
raw_engine_data object no Opaque engine-specific blob (not relied upon by heartbeat)

3.2 Entity Types

The entity_type field uses a controlled vocabulary:

Value Description
npc Non-player character
creature Hostile or neutral mob
item Pickup-able world item
door Door or transition
container Lootable container

4. Command Input Schema

Sent via POST /command. Represents a single action the agent wants to take in the world.

{
  "protocol_version": "1.0.0",
  "timestamp": "2026-03-21T14:30:01Z",
  "agent_id": "timmy",
  "command": "move_to",
  "params": {
    "target_cell": "Balmora",
    "target_x": 1050.0,
    "target_y": -500.0
  },
  "reasoning": "Moving closer to Caius Cosades to begin the main quest dialogue.",
  "episode_id": "ep_20260321_001",
  "context": {
    "perception_timestamp": "2026-03-21T14:30:00Z",
    "heartbeat_cycle": 42
  }
}

4.1 Field Reference

Field Type Required Description
protocol_version string yes Protocol SemVer
timestamp ISO 8601 datetime yes When the command was issued
agent_id string yes Which agent is issuing the command
command string (enum) yes Command type (see §4.2)
params object yes Command-specific parameters (may be empty {})
reasoning string yes Natural-language explanation of why this command
episode_id string no Groups commands into training episodes
context object no Metadata linking command to its triggering perception

4.2 Command Types

Command Description Key Params
move_to Navigate to coordinates or entity target_cell, target_x/y/z
interact Interact with entity (talk, activate) entity_id, interaction_type
use_item Use an inventory item item_id, target_entity_id?
wait Wait/idle for a duration duration_seconds
combat_action Perform a combat action action_type, target_entity_id
dialogue Choose a dialogue option entity_id, topic, choice_idx
journal_note Write an internal journal observation content, tags
noop Heartbeat tick with no action

5. API Contracts

5.1 GET /perception

Returns the latest perception snapshot.

Response: 200 OK with PerceptionOutput JSON body.

Error Responses:

Status Code Description
503 BRIDGE_UNAVAILABLE Game bridge is not connected
504 PERCEPTION_TIMEOUT Bridge did not respond in time
422 SCHEMA_MISMATCH Bridge returned incompatible schema

5.2 POST /command

Submit a command for the agent to execute.

Request: CommandInput JSON body.

Response: 202 Accepted

{
  "status": "accepted",
  "command_id": "cmd_abc123",
  "logged": true
}

Error Responses:

Status Code Description
400 INVALID_COMMAND Command type not recognized
400 VALIDATION_ERROR Payload fails Pydantic validation
409 COMMAND_CONFLICT Agent is busy executing another cmd
503 BRIDGE_UNAVAILABLE Game bridge is not connected

5.3 GET /morrowind/status

Health-check endpoint for the Morrowind bridge.

Response: 200 OK

{
  "bridge_connected": true,
  "engine": "tes3mp",
  "protocol_version": "1.0.0",
  "uptime_seconds": 3600,
  "last_perception_at": "2026-03-21T14:30:00Z"
}

6. Engine-Swap Documentation (The Falsework Rule)

What Changes

Component Changes on Engine Swap? Notes
Bridge process YES — replaced New bridge speaks same protocol to new engine
Perception Lua script YES — replaced New engine's scripting language/API
PerceptionOutput NO Schema is engine-agnostic
CommandInput NO Schema is engine-agnostic
Heartbeat loop NO Consumes PerceptionOutput, emits Command
Reasoning/LLM layer NO Operates on abstract perception data
Journal system NO Writes journal_note commands
Command log + training NO Logs all commands regardless of engine
Dashboard WebSocket NO Separate protocol (src/infrastructure/protocol.py)

Swap Procedure

  1. Implement new bridge that serves GET /perception and accepts POST /command.
  2. Update raw_engine_data field documentation for the new engine.
  3. Extend entity_type enum if the new engine has novel entity categories.
  4. Bump protocol_version minor (or major if schema changes are required).
  5. Run integration tests against the new bridge.

7. Error Handling Specification

7.1 Error Response Format

All error responses follow a consistent structure:

{
  "error": {
    "code": "BRIDGE_UNAVAILABLE",
    "message": "Human-readable error description",
    "details": {},
    "timestamp": "2026-03-21T14:30:00Z"
  }
}

7.2 Error Codes

Code HTTP Status Retry? Description
BRIDGE_UNAVAILABLE 503 yes Bridge process not connected
PERCEPTION_TIMEOUT 504 yes Bridge did not respond within deadline
SCHEMA_MISMATCH 422 no Protocol version incompatibility
INVALID_COMMAND 400 no Unknown command type
VALIDATION_ERROR 400 no Pydantic validation failed
COMMAND_CONFLICT 409 yes Agent busy — retry after current command
INTERNAL_ERROR 500 yes Unexpected server error

7.3 Retry Policy

Clients SHOULD implement exponential backoff for retryable errors:

  • Initial delay: 100ms
  • Max delay: 5s
  • Max retries: 5
  • Jitter: ±50ms

8. Appendix: Pydantic Model Reference

The canonical Pydantic v2 models live in src/infrastructure/morrowind/schemas.py. These models serve as both runtime validation and living documentation of this spec. Any change to this spec document MUST be reflected in the Pydantic models, and vice versa.