Observability

The Observability System

Last synced: Jul 11, 2026

The Observability System

You can’t steer a Life OS you can’t see (LIFEOS/DOCUMENTATION/LifeOs/LifeOsThesis.md). Observability is the raw sensory feed behind the Life Dashboard — every tool call, agent, and failure as inspectable events, so both the principal and the DA can verify the hill-climb is actually climbing.

Single-source local event pipeline for LifeOS tool activity, voice events, subagent lifecycle, and tool failures. Pulse is the only consumer; it reads JSONL from local disk on demand.

Infrastructure: The observability HTTP server (localhost:31337) runs as a module inside the unified Pulse daemon (~/.claude/LIFEOS/PULSE/Observability/observability.ts). There is no separate observability server process — Pulse serves all local HTTP endpoints on port 31337.

Architecture

JSONL Sources (local disk)
  ├─ tool-activity.jsonl (100)
  ├─ tool-failures.jsonl (50)
  ├─ voice-events.jsonl (50)
  └─ subagent-events.jsonl (50)


   Pulse (Observability/observability.ts)
   localhost:31337
   └─→ /api/events/recent  (read-on-demand from JSONL)
   └─→ /api/agents
   └─→ /api/observability/{tool-failures,voice-events,subagent-events,config-changes}

Data Flow

  1. Emitters — PostToolUse hooks write structured JSONL to MEMORY/OBSERVABILITY/
  2. Read-on-demand — Pulse endpoints read the last N lines per source, merge, sort newest-first, cap at 200, and serve over HTTP
  3. Display — The Observatory dashboard polls Pulse every 3s

Event Sources

SourceJSONL PathPer-Source CountHook
Tool activityMEMORY/OBSERVABILITY/tool-activity.jsonl100EventLogger.hook.ts (PostToolUse, catch-all)
Tool failuresMEMORY/OBSERVABILITY/tool-failures.jsonl50EventLogger.hook.ts (PostToolUseFailure)
Voice eventsMEMORY/VOICE/voice-events.jsonl50Voice notification server
Subagent eventsMEMORY/OBSERVABILITY/subagent-events.jsonl50AgentInvocation.hook.ts (PreToolUse:Agent / PostToolUse:Agent)
Agent watchdogstdout (Monitor notifications)Tools/AgentWatchdog.ts via Monitor tool. Reads tool-activity.jsonl + subagent-starts.json; alerts on 90s silence with active agents. Auto-triggered by Pulse agent-guard hook on background agent spawn.
Effort routing (retired 2026-07-11)MEMORY/OBSERVABILITY/effort-router.jsonlTheRouter.hook.ts (retired/merged 2026-07-11) — mode/tier classification abolished, no successor writes this stream. The MemoryReviewTrigger MINIMAL-skip gate that read its tail is also gone.
ISA reworkMEMORY/OBSERVABILITY/isa-rework.jsonlISASync.hook.ts Resume-After-Complete path (Algorithm v6.9.0, 2026-05-22). One row per auto-rewind: ts, session_id, slug, prev_phase, new_phase, prev_iteration, new_iteration, body_delta_bytes.
Frame driftMEMORY/OBSERVABILITY/frame-drift.jsonlAlgorithm VERIFY-phase emitter (v6.8.0). T1/T2/T3 boolean tests per ISA at VERIFY entry.
Reviewer runsMEMORY/OBSERVABILITY/reviewer-runs.jsonlMemoryReviewer.ts (autonomic memory). One row per reviewer execution: runId, transcript path, exchanges read, inference_duration_ms, parse_ok, dispatch_summary { total, by_type, succeeded, failed, failures }.
Reviewer firesMEMORY/OBSERVABILITY/reviewer-fires.jsonlMemoryReviewFire.hook.ts (Stop). Audit of when reviewer would fire if subprocess were unavailable.
Memory writes (Tier A)MEMORY/OBSERVABILITY/memory-writes.jsonlMemoryWriter.ts. One row per set-overwrite to _MEMORY.md hot-layer files. Tracks evictions.
Tier-B writesMEMORY/OBSERVABILITY/tier-b-writes.jsonlMemorySystem.add() routing. Audit row per logged-append to PROJECTS / CONTACTS / KNOWLEDGE / IDEAS (timestamp, type, bytes, path).
Pending proposals (Tier C queue)MEMORY/OBSERVABILITY/pending-proposals.jsonlMemorySystem.add() for type:proposal. Status lifecycle: pending → sent → accepted/rejected/edited. Surfaced by LIFEOS/PULSE/lib/telegram-proposals.ts as Telegram yes/no/edit #id replies.
Identity proposals (archive)MEMORY/OBSERVABILITY/identity-proposals.jsonlLIFEOS/PULSE/modules/telegram.ts surfacer. Archive of sent/accepted/rejected/edited proposals.
Proposal repliesMEMORY/OBSERVABILITY/proposal-replies.jsonlLIFEOS/PULSE/modules/telegram.ts reply handler. Records Telegram yes/no/edit interactions.
Memory retrievalsMEMORY/OBSERVABILITY/memory-retrievals.jsonlMemoryRetriever.getRelevantContext() (ISC-107..112; not yet populated as of 2026-05-23; infrastructure ready). Per-turn BM25 audit.

Per-source counts are configured inline in Pulse/Observability/observability.ts.

Event Format

All events conform to the LifeosEvent interface:

interface LifeosEvent {
  timestamp: string;     // ISO-8601 with timezone
  session_id: string;    // Claude Code session ID
  source: string;        // "tool-activity" | "tool-failure" | "voice" | "subagent"
  type: string;          // Event type (e.g. "tool_use", "voice_start", "subagent_start")
  [key: string]: unknown; // Additional fields per source
}

Read Timing

Pulse reads on demand. The Observatory dashboard polls /api/events/recent every 3s; each request reads JSONL tails from disk (no persistent in-memory cache; Bun fs is fast enough at 50-100 lines per source).

Key Files

FileRole
~/.claude/hooks/EventLogger.hook.tsConsolidated event writer (absorbed ToolActivityTracker + ToolFailureTracker + SkillExecutionLog + ConfigAudit + StopFailureHandler 2026-07-11). PostToolUse catch-all → tool-activity.jsonl (+ SKILLS/execution.jsonl on Skill); PostToolUseFailure → tool-failures.jsonl; ConfigChange → config-changes.jsonl; StopFailure → SECURITY stop-failures (log-only)
~/.claude/LIFEOS/PULSE/Observability/observability.tsObservability module inside unified Pulse daemon — serves events from JSONL at :31337
~/.claude/LIFEOS/PULSE/Observability/Next.js static dashboard — polls /api/events/recent

Dashboard Locations

DestinationURLData Source
LifeOS Observatorylocalhost:31337/ → Actions tabLocal JSONL via Pulse Observability/observability.ts

Observatory Dashboard

The LifeOS Observatory is the local observability UI — a Next.js 15.5 static export served by Pulse on localhost:31337.

Project Layout

ItemValue
Source~/.claude/LIFEOS/PULSE/Observability/
Build commandcd ~/.claude/LIFEOS/PULSE/Observability && bun run build (outputs to out/)
Serving mechanismDirect: ~/.claude/LIFEOS/PULSE/Observability/out (configured in PULSE.toml dashboard_dir)
URLhttp://localhost:31337/ (served by Pulse observability module)
Process managementPulse runs under launchd (com.lifeos.pulse) with auto-restart. Always use launchctl stop/start com.lifeos.pulse — never kill.

Dashboard Pages

PageURLPurpose
Agents/agents (default)Work dashboard — iterations, optimize, ideate, loops
Knowledge/knowledgeKnowledge archive browser
Security/securitySecurity system management — patterns, rules, events, hooks

Security Page (/security)

The security page provides full management of the LifeOS security system through four tabs:

TabFunction
PolicyEdit PATTERNS.yaml — blocked/alert/trusted commands, path protection tiers
RulesEdit SECURITY_RULES.md — natural language BLOCK/ALLOW rules, currently disabled (saved via POST /api/security/rules)
EventsRecent security events from MEMORY/SECURITY/YYYY/MM/
HooksHook health status with expandable descriptions

Additional features:

  • Architecture visual — Inspector pipeline flow diagram displayed at top of page
  • Injection defense — Shows InjectionInspector patterns and PromptInspector categories (injection, exfiltration, evasion, security_disable)
  • Live editing — All changes write directly to disk and take effect on next tool call

API Reference (all served by Pulse on localhost:31337)

All endpoints served by the Pulse daemon’s observability module (Observability/observability.ts) unless noted.

Core Observability

EndpointMethodPurposeSource
/healthGETPulse daemon health checkpulse.ts
/api/observability/stateGETCurrent session state (ISA, phase, progress)observability
/api/observability/statePOSTPush session state from hooksobservability
/api/observability/eventsGETRaw event dataobservability
/api/observability/eventsPOSTPush events from hooksobservability
/api/events/recentGETMerged recent events across all sourcesobservability
/api/observability/voice-eventsGETVoice event logobservability
/api/observability/tool-failuresGETTool failure logobservability

Algorithm & Sessions

EndpointMethodPurposeSource
/api/algorithmGETWork sessions — ISA metadata, ISC progress, phase historyobservability
/api/agentsGETSubagent events — start/stop/duration from JSONLobservability
/api/noveltyGETIdeate-run telemetry (UI removed 2026-07-08, archived as future work)observability
/api/ladderGETImprovement pipeline data (UI removed 2026-07-08, archived as future work)observability

Security

EndpointMethodPurposeSource
/api/securityGETCombined: PATTERNS.yaml + SECURITY_RULES.md + events + hooks + PromptInspector patternsobservability
/api/security/patternsPOSTMutate PATTERNS.yaml (add/remove/edit patterns and paths)observability
/api/security/rulesPOSTSave SECURITY_RULES.md contentobservability
/api/security/hooks-detailGETHook descriptions, events, blocking capabilityobservability

Knowledge

EndpointMethodPurposeSource
/api/knowledgeGETKnowledge archive — domains, notes, MOC dataobservability
/api/knowledge/:domain/:slugGETIndividual knowledge note contentobservability
/api/knowledge/:domain/:slugPUTUpdate knowledge noteobservability

Wiki (LifeOS system docs + knowledge browser)

EndpointMethodPurposeSource
/api/wikiGETSystem doc indexmodules/wiki.ts
/api/wiki/searchGETFull-text search across system docsmodules/wiki.ts
/api/wiki/graphGETKnowledge graph data for visualizationmodules/wiki.ts

DA (Digital Assistant)

EndpointMethodPurposeSource
/assistant/healthGETDA subsystem healthAssistant/module.ts
/assistant/identityGETCurrent DA identity summaryAssistant/module.ts
/assistant/personalityGETDA personality traitsAssistant/module.ts
/assistant/personality/traitsPATCHUpdate personality traitsAssistant/module.ts
/assistant/avatarGETDA avatar imageAssistant/module.ts
/assistant/tasksGETUnified task view (DA + Pulse cron + CC triggers)Assistant/module.ts
/assistant/tasksPOSTCreate DA scheduled taskAssistant/module.ts
/assistant/tasks/:idDELETECancel DA taskAssistant/module.ts
/assistant/diaryGETRecent diary entriesAssistant/module.ts
/assistant/opinionsGETCurrent DA opinionsAssistant/module.ts

Voice & Notifications

EndpointMethodPurposeSource
/notifyPOSTSend TTS notification via ElevenLabspulse.ts
/notify/personalityPOSTPersonality-aware notificationpulse.ts
/voiceGETVoice statuspulse.ts

Hook Validation

EndpointMethodPurposeSource
/hooks/skill-guardPOSTValidate Skill tool calls (PreToolUse HTTP hook)modules/hooks.ts
/hooks/agent-guardPOSTValidate Agent tool calls (PreToolUse HTTP hook)modules/hooks.ts

Stubs (reserved, not yet implemented)

EndpointMethodPurpose
/api/loopsGETLoop system index
/api/loops/controlGET/POSTLoop control
/api/loops/startPOSTStart a loop

Deployment Checklist

  1. Edit source in ~/.claude/LIFEOS/PULSE/Observability/src/
  2. Build: cd ~/.claude/LIFEOS/PULSE/Observability && bun run build
  3. Restart Pulse: launchctl stop com.lifeos.pulse && launchctl start com.lifeos.pulse
  4. Hard refresh browser: Cmd+Shift+R

Session State Tracking

Distinct from the event pipeline above, session state (active sessions, phase, progress, criteria, ratings) flows through a single canonical file. Both the Pulse dashboard and the ULAdmin /agents page read the same file so they never drift.

Canonical source: $LIFEOS_DIR/MEMORY/STATE/work.json

Writers (atomic read-modify-write via isa-utils.ts:writeRegistry)
├─ SessionAnalysis.hook.ts      UserPromptSubmit → upsertSession (native or starting)
├─ EventLogger.hook.ts          PostToolUse → bumpLastToolActivity (30s debounced)
├─ ISASync.hook.ts              syncToWorkJson() → promote native entry to full ISA session
└─ ISAAutoName.hook.ts          updateSessionNameInWorkJson()

Readers (both use identical mapping)
├─ Pulse Observability          localhost:31337 → observability.ts handleAlgorithmApi
└─ ULAdmin daemon               localhost:4000  → server/src/algorithm-watcher.ts

Display lanes:

  • Mode starting → Algorithm tab, phase strip (OBSERVE/THINK/PLAN/BUILD/EXECUTE/VERIFY/LEARN).
  • Mode native → Native tab, no phase strip.

Classifier: SessionAnalysis.hook.ts:ALGO_ACTION_RE — narrow 8-verb regex (implement|build|create|architect|design|migrate|deploy|refactor). Everything else that passes the trivia filter (POSITIVE_PRAISE_WORDS, SYSTEM_TEXT_PATTERNS, MIN_PROMPT_LENGTH=3) is native. Do not broaden — see feedback_state_monitoring_requires_starting_gate.md.

Staleness thresholds: 5 min native, 10 min algorithm. Matched in both readers.

Loud-fail: algorithm-watcher.ts emits console.error on missing work.json at startup; /api/algorithm returns HTTP 503 with the resolved path. EventLogger.hook.ts logs exceptions via console.error so a silently-broken tracker shows up in session logs.

Self-healing: Both readers use Math.max(updatedAt, lastToolActivity) for the activity signal, so a fresh user prompt revives a stale session even if the tool-activity tracker is down.

See Also

  • ~/.claude/LIFEOS/DOCUMENTATION/LifeosSystemArchitecture.md — Master LifeOS architecture reference