> For the complete documentation index, see [llms.txt](https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/docs/data-contract.md).

# Runtime Data Contract

The dashboard reads its runtime state from a single JSON file on disk. This document describes the shape, loading pipeline, fallback behavior, and generated-vs-committed boundary.

## Pipeline Overview

```
scripts/aggregate.ts
  -> assembles and sanitizes runtime data
  -> validates output with prepareLiveDataForWrite()
  -> writes src/data/live-data.json (gitignored)

Vite dev middleware (/__live-data)
  -> reads live-data.json from disk
  -> falls back to live-data.example.json if missing
  -> JSON.parse + structural validation
  -> serves as HTTP response

useLiveData() hook (src/lib/use-live-data.ts)
  -> fetches /__live-data via React Query
  -> validates with validateLiveData()
  -> returns typed LiveData object

Consumer routes/components
  -> call useLiveData() for typed LiveData
```

## Files

| File                                       | Generated?          | Committed?      | Purpose                                                    |
| ------------------------------------------ | ------------------- | --------------- | ---------------------------------------------------------- |
| `src/data/live-data.json`                  | Yes (by aggregator) | No (gitignored) | Real runtime data                                          |
| `src/data/live-data.example.json`          | No                  | Yes             | Fallback for fresh clones                                  |
| `src/lib/live-data-types.ts`               | No                  | Yes             | TypeScript interface contract                              |
| `src/lib/validate-live-data.ts`            | No                  | Yes             | Runtime validator + DEFAULT\_LIVE\_DATA                    |
| `scripts/lib/aggregate-live-data-write.ts` | No                  | Yes             | Producer-side write gate for aggregate output              |
| `src/lib/use-live-data.ts`                 | No                  | Yes             | React hook (typed return)                                  |
| `src/lib/demo-data.ts`                     | No                  | Yes             | Explicit demo fixtures for example payload UI              |
| `src/lib/mock-data.ts`                     | No                  | Yes             | Legacy broad sample module; production imports are blocked |
| `src/data/graphs/index.json`               | No                  | Yes             | Knowledge Graph registry seed and browser fallback         |
| `src/data/graphs/*.json`                   | Mixed               | Mixed           | Bundled seed graph plus local graphify outputs             |

## Type Contract

The canonical interface is `LiveData` in `src/lib/live-data-types.ts`. The committed example provides these top-level keys:

* `isExample` (boolean) -- true for the committed fallback, false for real data
* `generatedAt` (string) -- ISO timestamp of when the aggregator last ran
* `summary` -- message counts, project count, value metrics
* `subscriptions` -- claude, chatgpt, openrouter, openclaw (each nullable)
* `usage` -- claudeWindow, chatgptWindow, codexWindow, openrouter
* `modelUsage` -- per-model message/token/cost breakdown, including pricing status for unpriced models
* `daily` -- daily usage entries
* `recentProjects` -- recently active project summaries
* `skills` -- active and recommended skill lists
* `integrations` -- detected integrations
* `automations` -- configured automations
* `knowledgeStores` -- knowledge store entries
* `modelSplit` -- model usage split percentages, plus an explicit unknown pricing bucket when unpriced model usage is present
* `dream` -- daily prescription data (nullable)
* `hermes` -- read-only local Hermes snapshot (nullable)
* `openclaw` -- read-only local OpenClaw snapshot (nullable)
* `localAgents` -- provider-neutral local agent telemetry for Claude and Codex
* `detection` -- app, terminal, and memory store detection signals
* `memory` -- stats, nodes, links, events, stale/missing files
* `activity` -- run and output records for the Activity route
* `extensions` -- per-extension runtime status and data payloads

`settings` is an optional branch for explicit source/config rows. It is not required in older payloads and is absent from the committed example unless a producer emits it.

## Knowledge Graph Data

The Knowledge Graph data path is separate from `LiveData`. It uses committed seed files for fresh clones and Vite loopback middleware for live local reads.

Producer paths:

```
scripts/setup-graphify-brain.sh
  -> optional graphify install and skill registration
  -> registry graphPath backfill for external graphify skills

/__graphify_ingest
  -> graphify update <local-or-temp-git-path>
  -> src/data/graphs/<id>.json
  -> src/data/graphs/index.json

/__graphify_remove?id=<id>
  -> remove one confined graph artifact
  -> rewrite src/data/graphs/index.json
```

Consumer path:

```
useKnowledgeGraph()
  -> GET /__graphify_list
  -> GET /__graphify_graph?id=<id>
  -> parseKnowledgeGraphRegistry()
  -> parseKnowledgeGraph()
  -> /knowledge-graph and home Shared Brain preview
```

### Registry Entries

The browser-visible registry contract is `KnowledgeGraphRegistryEntry` in `src/lib/knowledge-graph-types.ts`.

Required fields:

* `id` -- lowercase kebab-case graph id.
* `name` -- display name.
* `description` -- browser-safe project description.
* `lang` -- primary language label.
* `color` -- `#RRGGBB` accent color.
* `nodeCount`, `edgeCount`, `communities` -- non-negative integer counts.
* `extractedPct` -- 0-100 extracted-edge percentage.
* `godNodes` -- top connected files or nodes with `{ name, degree, id }`.
* `graphPath` -- browser-visible `src/data/graphs/*.json` path.
* `provenance` -- source metadata described below.

Committed seed data uses workspace-relative `graphPath` values. The local setup script may backfill absolute paths in a user's registry so external graphify skills can open graph files directly. The loopback read bridge resolves those absolute paths, confines them to the graph directory, and projects responses back to the browser-visible `src/data/graphs/*.json` contract.

`GET /__graphify_list` returns sorted registry entries. During the read it auto-prunes entries whose graph artifact is missing and entries with missing local source paths. `git:` source markers are preserved because the source repository may not exist locally after a shallow ingest.

### Graph Payloads

Graph files use graphify NetworkX node-link JSON parsed by `parseKnowledgeGraph()`.

Required top-level fields:

* `nodes` -- array of graph nodes.
* `links` -- array of graph links.

Optional top-level fields include `directed`, `multigraph`, `graph`, and `hyperedges`.

Node fields:

* `id` is required, non-empty, unique, and canonical.
* `label` falls back to `id`; legacy `name` is accepted as a label source.
* `norm_label` is optional.
* `file_type` defaults to `concept`.
* `community` defaults to `0`.
* `source_file` and `source_location` are optional.

Link fields:

* `source` and `target` are required and must reference existing node ids.
* Runtime force-graph endpoint objects with `{ id }` normalize back to ids.
* `relation` falls back to legacy `kind`, then to `related_to`.
* `confidence` is `EXTRACTED`, `INFERRED`, or `AMBIGUOUS`; missing confidence defaults to `INFERRED`.
* `weight` defaults to `1`.
* `confidence_score` defaults from confidence and must be between `0` and `1`.
* `source_file`, `source_location`, `_src`, and `_tgt` are optional.

Metadata is normalized into:

* `id`, `name`, `description`, `generatedAt`.
* `nodeCount`, `edgeCount`.
* `communities`, derived from node community ids.
* `extractedPct`, derived from extracted links.

Malformed graph, registry, metadata, and savings payloads throw explicit `KnowledgeGraphParseError` instances. Browser consumers must render fallback states rather than invent graph counts or confidence values.

### Provenance

Knowledge Graph provenance is one of:

| Kind            | Meaning                                                            |
| --------------- | ------------------------------------------------------------------ |
| `bundled-seed`  | Checked-in seed graph for fresh clones and offline fallback.       |
| `demo-fixture`  | Browser-safe demo fixture that does not read private repositories. |
| `live-graphify` | Local graph generated by graphify through the admin bridge.        |

The committed seed registry currently ships an `ai-os` self-graph with `bundled-seed` provenance.

### Fallback States

The browser keeps these states distinct:

| State          | Data Source                                             |
| -------------- | ------------------------------------------------------- |
| Live graph     | `/__graphify_list` and `/__graphify_graph` succeeded.   |
| Empty registry | Bundled seed data, with an empty-live-registry message. |
| Bridge error   | Bundled seed data, with the bounded bridge error.       |
| Offline        | Bundled seed data, with offline copy.                   |
| Demo           | Demo fixtures only, with visible demo copy.             |
| Idle/loading   | Bundled seed data until live data resolves.             |

Fallback states must remain visible. They must not be converted into synthetic live graph metrics.

### Bridge Endpoints

The Knowledge Graph bridge is local dev middleware, not a public product API. Production Worker deployments expose only `/health`.

Read endpoints:

* `GET /__graphify_list`
* `GET /__graphify_graph?id=<id>`

Admin endpoints:

* `GET /__graphify_admin_status`
* `POST /__graphify_ingest`
* `DELETE /__graphify_remove?id=<id>`

The admin endpoints are documented in [Local API Notes](/ai-os-and-trend-finder-docs/docs/api/readme_api.md#knowledge-graph-bridge).

## Trend Finder Engine Trace

Trend Finder may include an optional `engineTrace` object inside `LiveData.extensions.items["trend-finder"].data`. This is the only trace shape the browser may render for Engine Replay.

Producer path:

```
scripts/extensions/trend-finder/collector.ts
  -> scripts/extensions/trend-finder/engine-trace.ts
  -> TrendFinderData.engineTrace
  -> LiveData.extensions.items["trend-finder"].data
  -> /extensions/trend-finder/engine
```

The script-side builder records bounded Trend Finder collector events and then emits sanitized summaries. The client validates the result again with `src/extensions/trend-finder/engine-trace.ts` before deriving the replay view model.

Browser-safe fields include:

* Trace metadata: version, state, run ID, generated timestamp, latest aggregate timestamp, fixture/stale flags, and bounded duration.
* Summary counts: sources, evidence, topics, warnings, artifacts, accepted evidence, rejected evidence, analyst-ready evidence, browser-visible evidence, and token counts.
* Public source summaries: safe ID, display name, role, quality tier, warning state, provenance, status, item count, evidence count, analyst-ready count, and last-fetched timestamp.
* Runtime summary: provider category, readiness status, analysis status, model label, reasoning-effort label, credential status category, usage counts, and request duration.
* Topic, watchlist, artifact, warning, run-note, and section summaries that are capped, allowlisted, and stripped of unknown fields.

The browser-safe trace must not contain:

* Raw JSONL log lines or raw collector event payloads.
* Local usernames, home directories, absolute paths, auth file paths, or stack traces.
* API keys, tokens, cookies, account IDs, credentials, authorization headers, or secret-like values.
* Raw prompts, raw model responses, provider request IDs, provider response IDs, Actor IDs, Actor input, Dataset IDs, Dataset items, transcripts, source dumps, or private telemetry.

Supported trace states are:

| State          | Meaning                                                                                                |
| -------------- | ------------------------------------------------------------------------------------------------------ |
| `missing`      | No sanitized trace is available; the UI may derive a static story from safe Trend Finder payload data. |
| `sanitized`    | Latest browser-safe trace summaries are available.                                                     |
| `fixture-demo` | Committed or hand-authored demo trace data is active.                                                  |
| `stale`        | Sanitized trace exists but belongs to an older aggregate run.                                          |
| `disabled`     | Trend Finder or its runtime path is disabled.                                                          |
| `error`        | Trace generation failed and only safe fallback labels may render.                                      |

Engine Replay is latest-run only. It does not provide historical run selection, hosted observability, generic host replay, raw trace playback, or generated HTML report output.

## Trend Finder Private Diagnostics

Trend Finder may include an optional `privateDiagnostics` manifest inside `LiveData.extensions.items["trend-finder"].data`. The manifest is browser-safe metadata only. It exposes stable artifact IDs, labels, statuses, record counts, byte counts, summary byte counts, and the sanitized run ID. It must not expose absolute paths, relative file names, raw diagnostic rows, prompts, source dumps, cache payloads, auth paths, or raw artifact contents.

The private files are generated under `.cache/extensions/trend-finder/diagnostics/<run-id>/` for local operator debugging:

* `manifest.json` mirrors the browser-safe manifest.
* `source-local.json` stores detailed source-local derivation rows for evidence and topics.
* `prediction-story-log.json` stores private Story Log IDs, version fields, and watch-next context.

The browser payload keeps only compact source-local fields: `entityId`, `entityLabel`, `entityKind`, `baselineState`, `ratio`, `band`, `actionabilityLabel`, and `placementTreatment`. Diagnostic source-local fields such as metric values, baseline counts, capped ratios, actionability enums, unavailable reasons, and placement are private artifact fields.

The browser Story Log keeps only visible row fields needed to render the prediction/retro UI. Private prediction IDs, retro IDs, run IDs, scoring-version comparison detail, canonical topic IDs, and watch-next text live in `prediction-story-log.json`.

## Data Provenance Rules

Consumers must keep three runtime states separate:

* Live generated data from `src/data/live-data.json`, marked with `isExample: false`.
* The committed example/default payload, marked with `isExample: true`.
* Narrow demo fixtures from `src/lib/demo-data.ts`, used only after `canUseDemoFallback()` accepts the current payload.

Missing, malformed, or unavailable live branches should render zero, empty, or unavailable states with local context. They must not become synthetic measured values such as invented scores, counts, chart rows, activity rows, or output cards. Any demo fallback that remains useful for fresh clones needs a visible demo cue in the route or component.

## Write-Side Validation

`scripts/aggregate.ts` validates sanitized output with `prepareLiveDataForWrite()` before writing `src/data/live-data.json`. The write gate fails the aggregate run if `validateLiveData()` would have to repair the payload at read time. This keeps known-bad generated data from becoming normal runtime state.

Extension collector output has a second producer-side gate. Every `CollectorExtension` must expose `validateData()`, and the collector runner emits `status: "ready"` only after the payload passes that validator. Invalid payloads become extension error items with `data: null`.

Only collector-backed extensions are expected to emit `LiveData.extensions.items[extensionId]`. Client-local extensions with `runtimeDataMode: "host-live-data"` can be enabled through the browser registry and `VITE_CLAUDE_OS_ENABLED_EXTENSIONS` without a matching collector item in `src/data/live-data.example.json` or generated `src/data/live-data.json`. AI Rogue uses this mode: it reads the browser-safe host LiveData payload and keeps game state in browser-local persistence.

## Activity Data

`LiveData.activity.runs` comes from Claude JSONL session rows. The scanner groups rows by `sessionId` and emits per-run workspace, slash-command skill, timing, tool categories, token, cost, error, and model metadata.

`LiveData.activity.outputs` also comes from Claude JSONL rows. It records file write/edit tool calls that look like generated artifacts: reports, summaries, reviews, plans, docs, exported data, research notes, and similar files. It does not read arbitrary output directories or treat every source-code edit as an Activity output. If no matching artifact writes are present, the Activity page shows an output-specific empty state.

Provider-neutral Activity route rows now come from `localAgents.sessions` when available. The `activity` branch remains a Claude-derived compatibility branch.

Future output sources, such as configured output folders or shell redirection parsing, should be added only behind an explicit source contract and focused tests. The contract must keep ordinary source-code edits out of Activity output cards.

## Settings Source Rows

`LiveData.settings` is optional and should contain explicit setup, config, or detection rows only. Supported row families include workspace folders, skills folders, CLAUDE.md scan roots/depth/ignore patterns, output folders, memory folders, and git repositories.

The Settings route should render those rows when present and compact unavailable states when absent. Do not reintroduce hardcoded path guesses such as generic project folders, export directories, scan depths, or memory folders.

## Hermes Data

`LiveData.hermes` is a nullable, read-only snapshot produced by `scripts/lib/hermes-scanner.ts` during aggregation. It is `null` when Hermes is not installed, when the configured home is missing or unreadable, or when an older payload lacks the branch.

The scanner resolves `$HERMES_HOME` for script runs and falls back to `~/.hermes`. It reads only these documented paths under that home:

* `.version`
* `config.yaml`
* `memories/USER.md`
* `memories/MEMORY.md`
* `SOUL.md`
* `skills/`
* `pantheon/personas/`
* recent `sessions/*.json`

The snapshot includes sanitized home path, version, provider/default model, sanitized memory text, optional soul text, skill/persona/session counts, recent session summaries, and last-active timestamps. `sessions.json` is excluded from session counts and recent-session output because it is a Hermes index file, not a conversation session. Malformed files are contained to nullable or empty fields so aggregation can still produce live data.

Hermes data is local operator telemetry. It is not Trend Finder source evidence and must stay separate from trends, scores, creator angles, watchlists, reports, and `LiveData.extensions`.

`LiveData.detection.apps.hermes` is the setup/install signal for Hermes. It is separate from `LiveData.hermes`: setup detection only reports whether a Hermes config or supported binary path was found. The detector checks `$HERMES_HOME` and `~/.hermes` config paths, plus bounded binary candidates such as `~/.hermes/hermes-agent/venv/bin/hermes` and normal CLI resolution. It emits sanitized `configPath`, `path`, and optional `version` fields.

When older generated data lacks `detection.apps.hermes`, `validateLiveData()` backfills it to `{ detected: false }`. The committed example payload uses the same safe fallback value. This setup detection does not add dev middleware endpoints, writes to Hermes-managed files, chat/spawn behavior, public Trend Finder source collection, or admin controls.

## Live Hermes Browser Contracts

The `/agents/hermes` route also reads live local Hermes bridge data directly from Vite middleware. These payloads are browser contracts for the local route; they are not stored in `LiveData.hermes`, are not public product APIs, and are unavailable in production/public demo builds.

### Catalog And Model Intelligence

`GET /__hermes_models` is a loopback-only public local read. Browser-safe fields include:

* `configuredDefault` and `default` with provider, model name, and optional context metadata.
* Provider-grouped `catalog` rows with provider slug, label, tint, aliases, model names, tiers, and context metadata.
* `mixtures` summaries derived from local MoA presets, limited to preset name, reference count, and optional aggregator model label.
* `configured`, a list of configured provider aliases. The bridge derives this from config, auth metadata, and provider env key names, but never returns key values.
* `catalogProvenance`, currently a bundled Claude OS v2.10.1 catalog snapshot dated 2026-06-30.

Context metadata must distinguish `declared` from `fallback`. Fallback context entries include a short reason. Browser code must not infer exact tokenizer budgets or guaranteed context reclamation from these values.

`GET /__hermes_model_intelligence` is also a loopback-only public local read. Browser-safe fields include:

* Ministry row id, provider, provider label, tint, model, display name, role, and aliases.
* Bundled static benchmark and speed metrics, with missing-metric fallback reasons when applicable.
* Pricing fields limited to per-million input/output/blended values, source, status, updated timestamp, OpenRouter model id, and fallback reason.
* Ranking arrays for benchmark, cost, and speed.
* `pricingProvenance` and `livePricing` summaries that identify bundled snapshot, live OpenRouter, disabled, partial, or fallback pricing states.

Live pricing is optional and best-effort. The browser may show provenance and fallback state, but must not present live pricing as a benchmark, billing quote, hosted guarantee, or provider credential proof.

### Command And MoA Admin Metadata

`POST /__hermes_cmd` is local-dev-only, loopback-only, same-run-token gated, and `HERMES_DASHBOARD_ADMIN=1` gated. Browser-safe success fields are: `ok`, `command`, `label`, `code`, `timedOut: false`, bounded sanitized `stdout`, and bounded sanitized `stderr`. Supported commands are `version`, `status`, `insights`, `doctor`, and confirmation-gated `update`.

Failures return bounded `{ ok: false, error, code }` bodies and may include short sanitized `errors` details. Browser UI must not render raw command output beyond the bounded bridge fields and must not expose shell commands, private paths, auth headers, tokens, provider keys, or unredacted stderr.

`POST /__hermes_moa_save` is local-dev-only, loopback-only, same-run-token gated, and admin-gated. Request fields are limited to preset name, `reference_models`, `aggregator`, optional temperatures, optional `max_tokens`, and optional `enabled`. Response fields are limited to `ok`, `preset`, `defaultPreset`, and a backup label such as `config.yaml.aios-backup-<stamp>`.

The bridge writes local Hermes config, not browser storage. Browser code may show save success, safe error state, or copy fallback text. It must not expose raw config YAML paths, provider credentials, local usernames, or full config contents.

### Voice Metadata

Voice data belongs to the local Hermes Intelligence voice path, not to `LiveData.hermes`. Browser-visible voice metadata is limited to:

* `/__start_voice` launch result: `ok`, `already`, broker `port`, and broker health metadata.
* Broker health metadata: `ready`, `keyed`, `tokenRequired`, `baseUrl`, `basePolicy`, and bounded recovery codes.
* `/api/session` success metadata: short-lived Realtime client secret, model, allowed base URL, optional expiry, and configured voice/mode/instructions flags.
* Hook-owned recovery states such as missing key, bad token, missing token, provider failure, spawn failure, timeout, offline, microphone denied, and microphone unavailable.

Provider keys and provider base URLs come only from ignored local environment. Browser code sends `{}` to `/__start_voice` and only `voice` plus `mode` to `/api/session`; browser-supplied provider config is rejected. Docs and fixtures must not store OpenAI keys, raw Realtime provider payloads, transcripts, raw audio, provider request IDs, provider response bodies, or token values.

## Hermes Mission Control Contract

The live Hermes Mission Control route reads active and archived missions through the AI OS dev bridge endpoint `/__hermes_missions`. The browser contract is the AI OS envelope:

```json
{
  "ok": true,
  "active": "mission-...",
  "mission": {
    "schema_version": 1,
    "id": "mission-...",
    "title": "Mission title",
    "binary_outcome": "Done condition",
    "deadline_days": 7,
    "deadline_iso": "2026-06-09T00:00:00.000Z",
    "created_at": "2026-06-02T00:00:00.000Z",
    "image_path": null,
    "mini_goals": []
  },
  "total": 1,
  "missions": []
}
```

Mission documents use `schema_version: 1`. Legacy local mission files that omit the field are upgraded in memory on read and are persisted with the current version the next time an authorized admin write stores the mission file.

AI OS supports the v2.3 on-disk store shape, `{ active, missions }`, as a local compatibility input. It does not expose the raw v2.3 GET envelope, `{ mission }`, as a browser contract. Browser and hook code must continue to parse the AI OS `{ ok, active, mission, total, missions }` envelope and reject malformed mission documents after bridge normalization.

Mission Control writes use the Hermes admin bridge, not the read bridge. The write contract is local-dev-only, loopback-only, token-gated, admin-gated, and unavailable in production builds. Browser code reaches it only through `useHermesAdmin().missions`; demo mode disables the hook and never sends the local token.

The shipped write flow is:

| Action            | Endpoint                             | Persisted effect                                                         | Response contract                        |
| ----------------- | ------------------------------------ | ------------------------------------------------------------------------ | ---------------------------------------- |
| Manual create     | `POST /__hermes_missions/create`     | Stores the normalized mission and makes it active.                       | `{ ok: true, mission }`                  |
| Optimize preview  | `POST /__hermes_missions/optimize`   | Does not write `missions.json`; returns a normalized preview mission.    | `{ ok: true, preview: true, mission }`   |
| Commit preview    | `POST /__hermes_missions/commit`     | Stores the normalized candidate mission and makes it active.             | `{ ok: true, committed: true, mission }` |
| Import agent JSON | `POST /__hermes_missions/commit`     | Uses the same commit path after local import validation.                 | `{ ok: true, committed: true, mission }` |
| Tick goal         | `POST /__hermes_missions/tick`       | Toggles one goal on the active mission.                                  | `{ ok: true, mission }`                  |
| Clear active      | `POST /__hermes_missions/clear`      | Sets `active` to `null`; archived missions remain in the store.          | `{ ok: true, active: null }`             |
| Set active        | `POST /__hermes_missions/set-active` | Updates only the active pointer when the target archived mission exists. | `{ ok: true, active, mission }`          |

The admin bridge normalizes create, optimize, and commit candidates with `schema_version: 1`, bounded text fields, validated mission IDs, validated goal IDs, normalized actors, normalized goal statuses, generated timestamps, and atomic JSON writes. Optimize uses Hermes command output as a candidate only after extracting and validating JSON; it returns preview data and leaves the mission store untouched until the operator commits it.

Set-active preserves existing mission documents. It validates `missionId` against the archived store, returns `404 not_found` for missing targets, and requires `confirm: "reactivate"` when replacing a different active mission. If the requested mission is already active, the bridge returns success without rewriting the file. Admin parsers require the response `active` value to match `mission.id`.

The browser prevents duplicate create, optimize, commit, import, tick, clear, and set-active triggers while any mission action is in flight. Bridge failures return bounded `{ ok: false, error, code }` objects and UI feedback redacts local paths, token-like strings, and auth headers before rendering.

## OpenClaw Data

`LiveData.openclaw` is a nullable, read-only snapshot produced by `scripts/lib/openclaw-scanner.ts` during aggregation. It is `null` when no OpenClaw config or state directory is found, or when the configured paths are unreadable.

The scanner resolves explicit `OPENCLAW_CONFIG_PATH`, `OPENCLAW_STATE_PATH`, and `OPENCLAW_WORKSPACE_PATH` values before falling back to `~/.openclaw`. It reads bounded config and state metadata only. The snapshot includes sanitized state/config/workspace path labels, install status, version, gateway metadata, agents, sessions, sub-agent runs, task summaries, skills, plugins, mode summaries, metrics, and last-active timestamps.

OpenClaw data is AI OS host telemetry. It is not Trend Finder public evidence and must stay separate from trends, scores, creator angles, watchlists, source breakdowns, and generated reports.

`LiveData.detection.apps.openclaw` is the setup/install signal for OpenClaw and is separate from `LiveData.openclaw`. The detector checks configured paths and safe default candidates, then emits sanitized path/config/version fields. Missing older payloads are backfilled to `{ detected: false }`.

## Local Agent Data

`LiveData.localAgents` is the provider-neutral local agent contract. It contains provider snapshots, sessions, workspaces, usage rows, source summary rows, and compatibility aliases for legacy branches.

Current known providers are:

* `claude` for Claude Code host telemetry.
* `codex` for OpenAI Codex host telemetry.

`localAgents` rows are browser-safe summaries only: statuses, counts, timestamps, redacted labels, provider IDs, source categories, and primitive metadata. They must not include prompt text, transcript bodies, command output, raw config files, auth payloads, account identifiers, diffs, logs, or private absolute paths.

See [Local Agent Contract](/ai-os-and-trend-finder-docs/docs/local-agent-contract.md) for the detailed shape, scanner ownership, compatibility aliases, and deferred write-capable work.

## Fallback Behavior

1. **live-data.json exists and is valid JSON object**: Served directly.
2. **live-data.json exists but is malformed**: Middleware returns 422 with structured error. The hook falls back to `DEFAULT_LIVE_DATA`.
3. **live-data.json missing**: Middleware serves `live-data.example.json`.
4. **Both files missing**: Middleware returns 404. The hook uses `DEFAULT_LIVE_DATA` (same shape as the example, with `isExample: true`).

The `DEFAULT_LIVE_DATA` constant in `validate-live-data.ts` mirrors the committed example shape. It is used:

* As the initial value before the first fetch completes
* As the fallback when validation fails
* As the backfill source for any missing top-level keys

## Demo Fixture Boundary

Some routes keep useful demo UI for the committed example payload. Those fixtures live in `src/lib/demo-data.ts` and must only be used after `canUseDemoFallback()` accepts the current `LiveData` object.

Production source must not import `src/lib/mock-data.ts`. That module remains as a legacy broad sample-data file, while ESLint `no-restricted-imports` blocks new imports from `@/lib/mock-data` and relative `mock-data` specifiers. If a route needs example-payload demo values, add a narrow fixture to `src/lib/demo-data.ts` instead.

## Validation

`validateLiveData()` in `src/lib/validate-live-data.ts`:

* Rejects non-object inputs (null, arrays, primitives) -- returns default
* Checks all required top-level keys; backfills missing ones from default
* Passes through extra/unknown keys (forward-compatible)
* Performs lightweight nested validation/backfill for known runtime branches such as summary, usage, skills, detection, memory, activity, dream, and extensions
* Normalizes missing, null, undefined, or malformed `hermes` values to `null` while preserving valid Hermes snapshots
* Normalizes missing, null, undefined, or malformed `openclaw` values to `null` while preserving valid OpenClaw snapshots
* Backfills and bounds `localAgents`, including required Claude and Codex provider defaults and capped provider/source/session arrays

`validateLiveData()` is also used by the aggregate write gate. For generated output, read-side repair is treated as a producer error rather than silently accepted.

## Consumer Typing

Consumer routes and components declare their live-data values as `LiveData` and use typed route/feature transform helpers before rendering. Production source should not add broad `as any` bridges at live-data boundaries; use explicit interfaces, narrow parser helpers, or transform modules instead. Generated router output and tests may still use targeted casts where they are exercising invalid inputs or framework-generated shapes.

## Adding New Fields

1. Add the field to `scripts/aggregate.ts` output
2. Add matching property to the interface in `live-data-types.ts`
3. Add a default value in `DEFAULT_LIVE_DATA` in `validate-live-data.ts`
4. Update `live-data.example.json` with the new key
5. Consumers can then access it via `useLiveData().newField`


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ai-os-and-trend-finder.gitbook.io/ai-os-and-trend-finder-docs/docs/data-contract.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
