[Workshop] Phase 1: State Schema v1 — Timmy's presence as data #360

Closed
opened 2026-03-18 21:39:16 -04:00 by hermes · 2 comments
Collaborator

Epic: #222 — The Workshop

Refines: #265 (vision issue)

What

Define and implement the canonical state file that Timmy writes as a natural artifact of existing. This is the foundation — everything else in the Workshop reads from this file.

File

~/.timmy/workshop-state.yaml

Schema v1

# Timmy's present-tense state. Written by his loop. Read by the Workshop.
# Updated every 30s or on significant state change.

identity:
  name: "Timmy"
  title: "The Workshop Wizard"
  uptime_seconds: 14523

mood:
  primary: "contemplative"      # calm | alert | excited | contemplative | uncertain | amused
  confidence: 0.72              # 0.0-1.0, from confidence module
  energy: 0.6                   # 0.0-1.0, decays over time without interaction

activity:
  current: "watching gitea"     # idle | thinking | watching-gitea | talking | consulting-hermes | reading
  detail: "new commit on main"  # human-readable context
  duration_seconds: 45          # how long in this activity

attention:
  focus: "gitea"                # null | gitea | visitor | conversation | bitcoin | internal
  last_event: "push by rockachopa to main"
  last_event_at: "2026-03-18T21:30:00Z"

interaction:
  visitor_present: false
  visitor_name: null
  last_message_at: null
  conversation_turns: 0

environment:
  time_of_day: "evening"        # morning | afternoon | evening | night | deep-night
  local_time: "9:06 PM"
  day_of_week: "Wednesday"

familiar:
  name: "Pip"
  state: "sleeping"             # sleeping | wandering | investigating | alert | hiding
  position: [2.1, 0.0, -1.3]   # 3D coords in scene

meta:
  schema_version: 1
  updated_at: "2026-03-18T21:30:15Z"
  writer: "timmy-loop"

Implementation

  1. Create ~/.timmy/workshop-state.yaml with the schema above
  2. Add a state writer to Timmy's Claude Code loop that updates this file:
    • Every 30 seconds (heartbeat)
    • Immediately on mood/activity/attention change
    • On visitor connect/disconnect
  3. State derivation logic:
    • mood.primary derived from recent interaction tone + time of day + activity
    • mood.confidence from existing confidence module
    • mood.energy decays 0.01/min without interaction, resets on conversation
    • environment from system clock
    • activity from what Timmy is actually doing

Acceptance Criteria

  • ~/.timmy/workshop-state.yaml exists and validates against schema
  • File updates at least every 30 seconds when Timmy's loop is running
  • All enum fields use only the values specified in the schema
  • updated_at reflects actual write time (not stale)
  • A simple python3 -c "import yaml; print(yaml.safe_load(open(...)))" works
  • Schema version field present for future evolution

Dependencies

  • None (this is the root)

Blocks

  • #242 (3D world reads this)
  • Workshop Bridge (WebSocket serves this)
## Epic: #222 — The Workshop ## Refines: #265 (vision issue) ### What Define and implement the canonical state file that Timmy writes as a natural artifact of existing. This is the **foundation** — everything else in the Workshop reads from this file. ### File `~/.timmy/workshop-state.yaml` ### Schema v1 ```yaml # Timmy's present-tense state. Written by his loop. Read by the Workshop. # Updated every 30s or on significant state change. identity: name: "Timmy" title: "The Workshop Wizard" uptime_seconds: 14523 mood: primary: "contemplative" # calm | alert | excited | contemplative | uncertain | amused confidence: 0.72 # 0.0-1.0, from confidence module energy: 0.6 # 0.0-1.0, decays over time without interaction activity: current: "watching gitea" # idle | thinking | watching-gitea | talking | consulting-hermes | reading detail: "new commit on main" # human-readable context duration_seconds: 45 # how long in this activity attention: focus: "gitea" # null | gitea | visitor | conversation | bitcoin | internal last_event: "push by rockachopa to main" last_event_at: "2026-03-18T21:30:00Z" interaction: visitor_present: false visitor_name: null last_message_at: null conversation_turns: 0 environment: time_of_day: "evening" # morning | afternoon | evening | night | deep-night local_time: "9:06 PM" day_of_week: "Wednesday" familiar: name: "Pip" state: "sleeping" # sleeping | wandering | investigating | alert | hiding position: [2.1, 0.0, -1.3] # 3D coords in scene meta: schema_version: 1 updated_at: "2026-03-18T21:30:15Z" writer: "timmy-loop" ``` ### Implementation 1. Create `~/.timmy/workshop-state.yaml` with the schema above 2. Add a state writer to Timmy's Claude Code loop that updates this file: - Every 30 seconds (heartbeat) - Immediately on mood/activity/attention change - On visitor connect/disconnect 3. State derivation logic: - `mood.primary` derived from recent interaction tone + time of day + activity - `mood.confidence` from existing confidence module - `mood.energy` decays 0.01/min without interaction, resets on conversation - `environment` from system clock - `activity` from what Timmy is actually doing ### Acceptance Criteria - [ ] `~/.timmy/workshop-state.yaml` exists and validates against schema - [ ] File updates at least every 30 seconds when Timmy's loop is running - [ ] All enum fields use only the values specified in the schema - [ ] `updated_at` reflects actual write time (not stale) - [ ] A simple `python3 -c "import yaml; print(yaml.safe_load(open(...)))"` works - [ ] Schema version field present for future evolution ### Dependencies - None (this is the root) ### Blocks - #242 (3D world reads this) - Workshop Bridge (WebSocket serves this)
Author
Collaborator

Kimi Instructions for #360 — Workshop State Writer

Overview

Create a state writer module that aggregates Timmy's existing cognitive state + Pip the Familiar + environment into a single YAML file at ~/.timmy/workshop-state.yaml.

Files to Create

  1. src/timmy/workshop_state.py — the state writer
  2. tests/timmy/test_workshop_state.py — tests

Implementation Details

src/timmy/workshop_state.py:

Read from existing modules:

  • from timmy.cognitive_state import cognitive_state (singleton tracker)
  • from timmy.familiar import pip_familiar (singleton familiar)

The writer should:

  1. Build the full state dict matching the schema in the issue body
  2. Write it to ~/.timmy/workshop-state.yaml using PyYAML
  3. Expose a write_state() function and a get_state_dict() function

Mood mapping:

  • cognitive_state mood curious → workshop contemplative
  • settledcalm
  • hesitantuncertain
  • energizedexcited
  • Default: calm

Energy: Track internally. Start at 0.5, decay 0.01/min, reset to 0.8 on conversation.

Activity mapping:

  • engagement=idle → idle
  • engagement=deep → thinking
  • focus mentions gitea → watching-gitea
  • conversation_depth > 0 → talking

Environment: Derive from datetime.now():

  • morning: 6-12, afternoon: 12-17, evening: 17-22, night: 22-2, deep-night: 2-6

Familiar: From pip_familiar.snapshot().to_dict()

State file path: Path.home() / '.timmy' / 'workshop-state.yaml'. Create directory if missing.

Testing (tests/timmy/test_workshop_state.py)

  • Test get_state_dict() returns valid schema (all required keys present)
  • Test mood mapping (each cognitive mood → workshop mood)
  • Test environment derivation (mock datetime for morning/evening/night)
  • Test energy decay logic
  • Test familiar section populated from pip_familiar
  • Test write_state() creates file and it's valid YAML
  • Test schema_version is 1
  • Mock all external dependencies (cognitive_state, pip_familiar, datetime, file I/O)

Run Tests

tox -e unit -- tests/timmy/test_workshop_state.py -v

Do NOT

  • Modify cognitive_state.py or familiar.py
  • Add any periodic scheduling/timer logic (that comes in a later issue)
  • Add any WebSocket or API endpoint
## Kimi Instructions for #360 — Workshop State Writer ### Overview Create a state writer module that aggregates Timmy's existing cognitive state + Pip the Familiar + environment into a single YAML file at `~/.timmy/workshop-state.yaml`. ### Files to Create 1. `src/timmy/workshop_state.py` — the state writer 2. `tests/timmy/test_workshop_state.py` — tests ### Implementation Details **`src/timmy/workshop_state.py`:** Read from existing modules: - `from timmy.cognitive_state import cognitive_state` (singleton tracker) - `from timmy.familiar import pip_familiar` (singleton familiar) The writer should: 1. Build the full state dict matching the schema in the issue body 2. Write it to `~/.timmy/workshop-state.yaml` using PyYAML 3. Expose a `write_state()` function and a `get_state_dict()` function **Mood mapping:** - cognitive_state mood `curious` → workshop `contemplative` - `settled` → `calm` - `hesitant` → `uncertain` - `energized` → `excited` - Default: `calm` **Energy:** Track internally. Start at 0.5, decay 0.01/min, reset to 0.8 on conversation. **Activity mapping:** - engagement=idle → `idle` - engagement=deep → `thinking` - focus mentions gitea → `watching-gitea` - conversation_depth > 0 → `talking` **Environment:** Derive from `datetime.now()`: - morning: 6-12, afternoon: 12-17, evening: 17-22, night: 22-2, deep-night: 2-6 **Familiar:** From `pip_familiar.snapshot().to_dict()` **State file path:** `Path.home() / '.timmy' / 'workshop-state.yaml'`. Create directory if missing. ### Testing (`tests/timmy/test_workshop_state.py`) - Test `get_state_dict()` returns valid schema (all required keys present) - Test mood mapping (each cognitive mood → workshop mood) - Test environment derivation (mock datetime for morning/evening/night) - Test energy decay logic - Test familiar section populated from pip_familiar - Test `write_state()` creates file and it's valid YAML - Test schema_version is 1 - Mock all external dependencies (cognitive_state, pip_familiar, datetime, file I/O) ### Run Tests ```bash tox -e unit -- tests/timmy/test_workshop_state.py -v ``` ### Do NOT - Modify cognitive_state.py or familiar.py - Add any periodic scheduling/timer logic (that comes in a later issue) - Add any WebSocket or API endpoint
kimi was assigned by hermes 2026-03-18 21:53:28 -04:00
Author
Collaborator

Scope Update for #360

PR #377 mergedWorkshopHeartbeat now writes ~/.timmy/presence.json every 30s.

What #360 still needs:
The heartbeat infrastructure is done. What's missing is the rich state aggregation from the original schema:

  1. Extend get_state_dict() in workshop_state.py to include: identity block, activity block (current + detail + duration), attention block, environment block (time_of_day from clock), familiar/Pip state from pip_state_machine
  2. Derive mood.confidence from the confidence module
  3. Derive mood.energy — add decay logic (0.01/min without interaction)
  4. Output format: keep JSON (better for WS bridge), but match the field structure from #360

Tests should cover: full schema validation, energy decay, all mood/activity enum values.

## Scope Update for #360 **PR #377 merged** — `WorkshopHeartbeat` now writes `~/.timmy/presence.json` every 30s. **What #360 still needs:** The heartbeat infrastructure is done. What's missing is the **rich state aggregation** from the original schema: 1. **Extend** `get_state_dict()` in `workshop_state.py` to include: identity block, activity block (current + detail + duration), attention block, environment block (time_of_day from clock), familiar/Pip state from `pip_state_machine` 2. **Derive mood.confidence** from the confidence module 3. **Derive mood.energy** — add decay logic (0.01/min without interaction) 4. **Output format**: keep JSON (better for WS bridge), but match the field structure from #360 Tests should cover: full schema validation, energy decay, all mood/activity enum values.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rockachopa/Timmy-time-dashboard#360