Skip to content

Add the Tirma interface: chat, live memory panel, pixel athlete - #2

Open
JorgeRdg wants to merge 1 commit into
mainfrom
feat/tirma-ui
Open

Add the Tirma interface: chat, live memory panel, pixel athlete#2
JorgeRdg wants to merge 1 commit into
mainfrom
feat/tirma-ui

Conversation

@JorgeRdg

Copy link
Copy Markdown
Collaborator

A web front end for the coaching agent, served by the same FastAPI app. Three
panes: session history, the conversation, and a context panel holding the
client's memory store next to an athlete drawn from it.

Built by team Tirma. Brand tier TAM-50, piece type proto — every
decision and every deviation is written down in ui/tam-decision.yml.

Run it

ANTHROPIC_API_KEY="sk-ant-..." uvicorn api.main:app --reload

Then http://127.0.0.1:8000/. The REST API and /docs are unchanged. Without a
key, TIRMA_DEMO=1 uvicorn api.main:app --reload runs a scripted coach.

The athlete is the argument, not decoration

Everything about the pixel figure is derived from the memory store in
api/ui_state.py — build from the sessions the coach logged, wrist wraps because
an injury entry names the wrist, sleeves because one names the knee. Clicking a
trait chip finds the memory entry that put it there.

Two rules keep it honest, and they are the coach's own rules from its system
prompt rather than something invented for the UI:

  • A constraint stays in force until something clears it, resolved per
    section, so one file holding wrist + knee + lower back can close one and keep
    the others.
  • A partial clearance clears nothing. "Cleared for neutral grip up to 16 kg,
    loaded wrist extension still contraindicated" keeps the wraps on.

Reading a partial clearance as a general all-clear is the exact failure the agent
exists to avoid, so the drawing must not commit it either.

The coaching turn is untouched

api/ui.py sits on top rather than beside. It relays Coach's own SSE frames
verbatim and appends two once the store has been re-read — memory.updated and
athlete.updated — so the panel and the figure change because the store changed,
never because the browser guessed.

It adds only the two things a browser needs and the agent does not: conversation
scrollback (the coach runs a fresh session per message, so it has no thread of
its own) and the derived athlete.

DemoCoach

Interface-compatible with Coach: same methods, same frames, real memory writes.
api/ui.py never branches on which one it holds, so the demo and live paths
exercise the same code. It exists so the interface could be built without burning
tokens, and so a stage demo has a floor if the network has a bad day.

Changes to existing files

api/main.py only — the coach is selected via TIRMA_DEMO, the lifespan demands
ANTHROPIC_API_KEY only outside demo mode, and the interface is mounted. Nothing
else in api/ was modified.

Two-minute demo

Start on the right panel: seven sessions on record, two live constraints, an
athlete already in wrist wraps and knee sleeves because memory says so. Send
"physio says the knee is fully cleared now" and watch the coach read the
training file, close the knee entry while leaving the wrist alone, and the
sleeves come off the athlete. The wraps stay on.

Checked

Dark and light, 1440×900 and 1280×720, prefers-reduced-motion on and off,
keyboard-only through every control. Session history, memory panel and athlete
survive a reload. A failed turn puts the typed message back in the box rather
than losing it.

ui/sprite-lab.html renders the sprite outside the app — every tier, every frame
of the rep, every accessory. It caught two bugs worth catching: plates clipping
off the canvas at lockout, and shoulder tape drawn under the arm.

Not verified

Listed under warnings in the sidecar rather than left implied:

  • No real mobile device. surface_scope is desktop_first; the sub-900 breakpoint
    is untested on hardware.
  • Contrast ratios were reasoned from token values, not measured. The greys are
    TAM's own AA-validated values, but the violet-on-basalt pairing should go
    through a checker before this is called done.

One brand-system conflict, resolved rather than papered over

generators/proto.md v0.2 says TAM-50 proto takes the with_wordmark_image
signature; tiers/TAM-50.design.md v0.4 fixes product_logo_plus_tam_text for
the whole tier and makes it a condition of tier membership. The tier doc is
followed, since proto.md states it is not the SSOT. Probably worth a PR upstream
to theam/brand-system.

🤖 Generated with Claude Code

A web front end for the coaching agent, served by the same FastAPI app.
Three panes: session history, the conversation, and a context panel
holding the client's memory store next to an athlete drawn from it.

The athlete is the argument, not decoration. Everything about the pixel
figure is derived from the memory store in api/ui_state.py — build from
the sessions the coach logged, wrist wraps because an injury entry names
the wrist, sleeves because one names the knee. Two rules keep it honest,
and they are the coach's own rules from its system prompt:

  · a constraint stays in force until something clears it, resolved per
    section, so one file holding wrist + knee + lower back can close one
    and keep the others;
  · a partial clearance clears nothing. "Cleared for neutral grip, loaded
    wrist extension still contraindicated" keeps the wraps on.

Reading a partial clearance as a general all-clear is the exact failure
the agent exists to avoid, so the drawing must not commit it either.

The coaching turn is untouched. api/ui.py relays Coach's own SSE frames
and appends two once the store has been re-read — memory.updated and
athlete.updated — so the panel and the figure change because the store
changed, never because the browser guessed.

Also adds DemoCoach: interface-compatible with Coach, no API key, real
memory writes. api/ui.py never branches on which one it holds, so the
demo and live paths exercise the same code. It exists so the interface
could be built without burning tokens, and so a stage demo has a floor.

Brand: TAM-50, piece type proto. IBM Plex only by proto role, Carbon
icons used verbatim, TAM spacing and radii, no shadows, product palette
with role discipline, product_logo_plus_tam_text signature in the footer.
Every decision and every deviation is written down in ui/tam-decision.yml,
including a conflict between proto.md v0.2 and TAM-50.design.md v0.4 over
which signature variant this tier takes.

ui/sprite-lab.html renders the sprite outside the app — every tier, every
frame, every accessory. It caught two bugs worth having caught: plates
clipping off the canvas at lockout, and shoulder tape drawn under the arm.

Not verified: a real mobile device, and measured contrast ratios. Both
are listed under warnings in the sidecar rather than left implied.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant