feat: add RADAR governance visualisation with Vela NPC - #258
feat: add RADAR governance visualisation with Vela NPC#258ktkorpela-prog wants to merge 20 commits into
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detects mcp__radar__radar_assess in JSONL tool_use blocks and emits agentRadarStart/agentRadarVerdict messages. Extracts verdict (PROCEED/ HOLD/DENY), tier (1=rules, 2=LLM), riskScore, triggerReason, and recommended from tool_result. Parse failure defaults to HOLD. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Simple queue managing visitor seat access at the RADAR desk. Supports enqueue (with duplicate detection), dequeue, remove (terminal close), and clear (desk removed). Pure functions, no side effects — integration in OfficeState follows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vela is the first NPC — a permanent character tied to the radar_desk furniture. She spawns when radar_desk exists, despawns when removed. Stamp animation: stamp_up → stamp_down → stamp_hold → idle. T2 (LLM) assessments hold stamp_up longer (0.6s vs 0.4s) so Vela visibly "thinks" before stamping. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New CharacterState.CONSULT: agent sits at RADAR desk visitor seat using typing animation while awaiting verdict. Walk state detects arrival at visitor seat and transitions to CONSULT. Active repath skipped during radar consultation to prevent seat redirect. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rkle Canvas-drawn overlays for RADAR verdicts: - Stamp mark (8×8): circle (PROCEED), pause bars (HOLD), X (DENY) - Verdict badge (6×6): same shapes above agent's head - T2 sparkle: white diamond indicator when verdict used LLM assessment (vs T1 rules-only). Positioned top-right of stamp/badge. Both fade over 0.5s via alpha interpolation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wires together all RADAR governance modules: - NPC manager synced on layout rebuild (Vela spawn/despawn) - Radar queue with visitor seat detection - handleRadarStart: enqueue agent, walk to desk or wait nearby - handleRadarVerdict: deliver verdict, start countdown - Verdict timer in update loop: return-to-seat + queue promotion - Vela stamp triggered when queue agent arrives at CONSULT state - Queue cleanup on removeAgent and radar_desk removal - getCharactersForRender includes Vela in render list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Integration commit connecting all RADAR modules: - renderer.ts: verdict badge overlay on characters, CONSULT sitting offset - useExtensionMessages.ts: handle agentRadarStart, agentRadarVerdict, npcSpritesLoaded messages - spriteData.ts: NPC palette (-1) loads Vela sprites, amber hue fallback - assetLoader.ts: loadVelaSprite() for vela.png with graceful fallback - PixelAgentsViewProvider.ts: send Vela sprites after character sprites All 135 existing tests pass. No regressions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Add RADAR_DESK_FRONT furniture asset (manifest.json + placeholder 32x32 PNG with amber/dark colour scheme, backgroundTiles=1) 2. Add vela.png placeholder sprite (copy of char_0.png — drop-in replacement designed, no code changes needed for final art) 3. Connect getCharactersForRender() in OfficeCanvas so Vela renders 4. Wire drawStampMark into renderer pipeline via StampMarkState passed through renderFrame → renderScene 5. Fix tier timing: Vela starts stamping without tier, tier updated via setTier() when verdict arrives (tier comes with verdict, not with start) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
extractRadarVerdict (18 tests): - Verdict extraction: status field, verdict fallback, preference, unknown values - Tier extraction: T1, T2, missing, wrong type - Extra fields: riskScore, triggerReason, recommended with type validation - Error handling: invalid JSON, empty text, null/missing content, string content radarQueue (11 tests): - FIFO enqueue/dequeue ordering - Deduplication (current + waiting) - Remove from queue (current promotes next, waiting splice, unknown returns false) - Clear returns all evicted agent IDs - isInQueue membership check Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
First placeholder had a 4px dark bar at the top of the desk that covered Vela's face when she sat at the desk. Reduced to a thin 2px back lip so it still hints at 3D depth without blocking the character. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Design fix for real-world layout: users only need to place ONE chair adjacent to the radar desk (the visitor seat). Vela now positions herself at the back row of the desk (the backgroundTiles area) — no chair required. Fixes: previously Vela claimed the only chair, leaving no visitor seat, and handleRadarStart silently returned. Changes: - npcManager: syncWithLayout positions Vela at desk back, no seat - npcManager: exports VELA_NAME and VELA_ROLE constants - officeState.getCharacterAt: includes Vela in hit detection - officeState.handleRadarStart: logs warning when no visitor seat - ToolOverlay: shows "Vela — Risk Architect" on hover - findVisitorSeat: accepts any adjacent seat (not just unassigned) All 153 tests still pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Vela uses IDLE state (standing pose) when not stamping — prevents "typing in midair" visual when no chair is under her - Vela switches to TYPE state during stamp animation for proper stamp_up/stamp_down frame rendering - ToolOverlay uses new getCharacterById() that finds NPCs too — fixes broken hover tooltip on Vela - Added permanent "RISK ASSESSMENT" label above the radar desk, rendered in ToolOverlay with pixel-panel styling Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously her feet were 8px above the desk top, which looked like she was floating. Now her feet are at the desk top line so she visually stands right behind the desk. Z-sort still keeps her behind the desk's solid front face. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Vela pixel y positioned so her charZY < desk zY, rendering her behind the desk's solid front face. Her head and shoulders visible above the back lip, legs hidden behind the desk. - RISK ASSESSMENT banner moved from 20px above desk top to 44px above, clearing Vela's head. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chair tiles are blocked for all characters except their own assigned seat. This prevented agents from pathfinding to Vela's visitor chair (findPath returned empty because destination was blocked). Now temporarily unblocks the visitor seat tile during: - Outbound walk (handleRadarStart → walkAgentToVisitorSeat) - Return walk (verdict timer expires → walk back to own seat, agent is currently ON the blocked visitor seat) This lets BFS find a valid path in both directions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Logs at parser detection, webview message receipt, and handleRadarStart entry to help diagnose why the animation isn't firing when radar_assess is called. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Stamp mark: 8x8 -> 14x14 with white outline circle for contrast - Verdict badge: 6x6 -> 14x14 with white outline circle - New verdict text label (PROCEED/HOLD/DENY) above agent during the verdict window — bold, coloured, much more visible - Fix timer bug: timer was decrementing during walk, often expiring before agent reached CONSULT. Now timer only starts when agent enters CONSULT state with a verdict already set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build was looking for hook source at providers/file/hooks/ but the actual location is providers/hook/claude/hooks/. The mismatch caused buildHooks() to silently skip, leaving dist/hooks/claude-hook.js missing — which led to "Cannot find module" errors when Claude Code tried to invoke the hooks installed in settings.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Hey @ktkorpela-prog, this is genuinely exciting work :D That's going to cause meaningful rebase conflicts here, especially around the parser, character state, the hook-script paths etc. I'd really like to help you rebase this and work through the conflicts together! I'll also spend some time thinking about how we can integrate this as a plugin/extension surface rather than a closed built-in feature, NPCs and governance overlays feel like exactly the kind of thing that should live alongside HookProvider, TeamProvider, Client, Adapter as a composable extension point (something like NPCProvider or OverlayProvider). That way you keep ownership of Vela and the core stays lean. Let me sync after I take a closer look at the diff :) |
Summary
Adds visual governance to Pixel Agents: when a Claude Code agent calls the
radar_assessMCP tool, the agent character walks to a Risk Assessment desk where Vela — the first NPC in the system — delivers a verdict (PROCEED / HOLD / DENY) with a colour-coded animation.Demo flow
radar_deskin the layout editor → Vela auto-spawns behind the deskradar_assess→ walks to visitor seatWhat's included
Core
mcp__radar__radar_assess(extracts verdict, tier, riskScore, triggerReason, recommended)CONSULTcharacter state + walk arrival detectionradarQueue.tswith deduplication and seat managementnpcManager.ts) — Vela lifecycle, stamp animation, T1/T2 visual distinctionBonus fixes for upstream
esbuild.jswas pointing toproviders/file/hooks/claude-hook.tsbut the file is atproviders/hook/claude/hooks/claude-hook.ts— fixed. The hook script was silently failing to build, causingCannot find moduleerrors when Claude Code invoked hooks.Dependencies
radar_deskplacementradar_desk= no Vela = feature dormant@essentianlabs/radar-mcpTests
extractRadarVerdict(18 tests),radarQueue(11 tests)radar_assesscallsPlaceholder assets
vela.pngandRADAR_DESK_FRONT.pngare placeholders — designed for drop-in replacement. A pixel artist contribution is welcome (no code changes needed).Test plan
radar_deskand adjacent chair in layoutradar_assessfrom a Claude Code agentradar_deskplaced: feature fully dormant, no errors@essentianlabs/radar-mcpinstalled: feature fully dormant, no errorsBackward compatibility
Fully backward compatible — all changes additive. New
CONSULTstate, NPC system, message types, and furniture entry don't affect existing behaviour.🤖 Generated with Claude Code