> 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/api/readme_api.md).

# Local API Notes

The current app does not expose a public product API. Vite middleware defines local development endpoints used by the Trend Finder dashboard, extension runtime, and inherited local-operator surfaces.

## Endpoints

### Production (Cloudflare Worker)

| Method | Path      | Purpose                                               | Access |
| ------ | --------- | ----------------------------------------------------- | ------ |
| `GET`  | `/health` | Returns JSON `{"status":"healthy","timestamp":"..."}` | Public |

The `/health` endpoint runs before SSR and is handled directly by `src/server.ts`.

### Local Dev Only (Vite Middleware)

| Method   | Path                                | Purpose                                      | Access                                      |
| -------- | ----------------------------------- | -------------------------------------------- | ------------------------------------------- |
| `GET`    | `/__live-data`                      | Return runtime JSON data                     | Local dev server                            |
| `GET`    | `/__time-saved-config`              | Return optional saved-time file config       | Loopback only                               |
| `GET`    | `/__trend-finder-visibility-config` | Return optional Trend Finder visibility file | Loopback only                               |
| `GET`    | `/__just-installed`                 | Return and clear the setup marker            | Local dev server                            |
| `GET`    | `/__token`                          | Return per-run refresh token                 | Loopback only                               |
| `POST`   | `/__refresh_data`                   | Rerun `scripts/aggregate.ts`                 | Loopback only, token required               |
| `POST`   | `/__run_trend_finder`               | Run scoped Trend Finder scheduler job        | Loopback only, token required               |
| `GET`    | `/__refresh_status`                 | Return async refresh status                  | Loopback only, token required               |
| `POST`   | `/__run_dream`                      | Run Dream Review and refresh data            | Loopback only, token required               |
| `GET`    | `/__operator-photo`                 | Proxy configured operator avatar             | Loopback only                               |
| `GET`    | `/__graphify_list`                  | Return Knowledge Graph registry entries      | Loopback only                               |
| `GET`    | `/__graphify_graph`                 | Stream one Knowledge Graph payload           | Loopback only                               |
| `GET`    | `/__graphify_admin_status`          | Return Knowledge Graph write readiness       | Loopback only                               |
| `POST`   | `/__graphify_ingest`                | Ingest a local path or Git URL graph         | Loopback only, token required, current gate |
| `DELETE` | `/__graphify_remove`                | Remove one graph registry entry and artifact | Loopback only, token required, current gate |

### Skill Saved-Time Config

`GET /__time-saved-config` exists only inside Vite `configureServer`. It lets the browser hydrate the saved-time ROI calculator from optional private repo-local files:

```
data/ai-os.time-saved.json
data/ai-os.hourly-rate.json
```

The endpoint accepts only `GET`, requires loopback access, returns `Cache-Control: no-store`, and never reads arbitrary paths. It returns JSON even when both files are missing:

```ts
type TimeSavedFileConfigResponse = {
  source: "file" | "missing";
  minutes?: Record<string, number>;
  hourlyRateUsd?: number;
  files: {
    timeSaved: "loaded" | "missing" | "invalid";
    hourlyRate: "loaded" | "missing" | "invalid";
  };
  warnings: string[];
};
```

Valid file values win over browser `localStorage` during `useTimeSaved()` hydration. UI edits still write only to `localStorage`; no browser endpoint writes these files. The override files do not affect `skills.active` or `src/data/live-data.json`.

### Trend Finder Visibility Config

`GET /__trend-finder-visibility-config` exists only inside Vite `configureServer`. It lets the browser hydrate Trend Finder visible/hidden UI state from an optional private repo-local file:

```
data/trend-finder.visibility.json
```

The endpoint accepts only `GET`, requires loopback access, returns `Cache-Control: no-store`, and never reads arbitrary paths. It returns JSON even when the file is missing:

```ts
type TrendFinderVisibilityConfigResponse = {
  source: "file" | "missing";
  config?: {
    version: 1;
    views: Partial<
      Record<"trends" | "hidden-gems" | "sources" | "watchlist" | "brief", { hidden: string[] }>
    >;
  };
  file: "loaded" | "missing" | "invalid";
  warnings: string[];
};
```

File view entries replace matching browser `localStorage` view entries during hydration; omitted file views keep browser settings. UI edits still write only to `localStorage` key `ai-os.trend-finder.visibility.v1`; no browser endpoint writes `data/trend-finder.visibility.json`.

### Trend Finder Creator Lens Bridge

The Creator Lens bridge exists only inside Vite `configureServer`. It lets the Trend Finder dashboard read and persist the local creator lens used by the next aggregate run. It is not a public product API and it is unavailable in production builds.

| Method | Path                           | Purpose                           | Access                        |
| ------ | ------------------------------ | --------------------------------- | ----------------------------- |
| `GET`  | `/__trend_finder_creator_lens` | Return local Creator Lens config  | Loopback only, token required |
| `POST` | `/__trend_finder_creator_lens` | Validate and persist Creator Lens | Loopback only, token required |

The persisted file lives under the gitignored Trend Finder cache directory. Requests use bounded JSON bodies and do not expose runtime tokens, prompt payloads, source data, or aggregate logs.

### Knowledge Graph Bridge

The Knowledge Graph bridge exists only inside Vite `configureServer`. It lets the `/knowledge-graph` route read the local graph registry and, when admin mode is enabled, ingest or remove graph projects through the dashboard. It is not a public product API and is unavailable in production builds.

Read endpoints are loopback-only and token-free:

| Method | Path                        | Purpose                                                                                           | Access        |
| ------ | --------------------------- | ------------------------------------------------------------------------------------------------- | ------------- |
| `GET`  | `/__graphify_list`          | Return sorted registry entries after pruning stale graph artifacts and missing local source paths | Loopback only |
| `GET`  | `/__graphify_graph?id=<id>` | Stream one graph JSON payload, or stream the bundled seed graph with fallback headers             | Loopback only |

Admin endpoints are local-dev-only. Mutation endpoints currently require the same-run token from `/__token` and the Phase 40 `HERMES_DASHBOARD_ADMIN=1` implementation gate; production mode reports admin unavailable even if the env key is present. The env gate is a migration constraint, not the future local access default.

| Method   | Path                         | Purpose                                                                 | Access                                      |
| -------- | ---------------------------- | ----------------------------------------------------------------------- | ------------------------------------------- |
| `GET`    | `/__graphify_admin_status`   | Return local admin readiness and optional graphify availability         | Loopback only                               |
| `POST`   | `/__graphify_ingest`         | Run graphify for a local path or Git/GitHub URL and upsert the registry | Loopback only, token required, current gate |
| `DELETE` | `/__graphify_remove?id=<id>` | Remove one registry entry and its confined graph artifact               | Loopback only, token required, current gate |

All JSON responses use `Cache-Control: no-store` and `X-Content-Type-Options: nosniff`. Graph streams use `application/json; charset=utf-8` and include `Content-Length`.

#### `GET /__graphify_list`

Returns the browser-visible Knowledge Graph registry:

```json
[
  {
    "id": "ai-os",
    "name": "AI OS",
    "description": "Bundled AI OS self-graph seed for offline Knowledge Graph fallback.",
    "lang": "TypeScript",
    "color": "#14b8a6",
    "nodeCount": 17,
    "edgeCount": 25,
    "communities": 5,
    "extractedPct": 80,
    "godNodes": [{ "name": "Operator Cockpit", "degree": 6, "id": "operator-cockpit" }],
    "graphPath": "src/data/graphs/ai-os.json",
    "provenance": {
      "kind": "bundled-seed",
      "label": "Bundled seed",
      "description": "Checked-in AI OS self-graph seed for demo-safe offline fallback.",
      "generatedAt": "2026-06-09T00:00:00.000Z"
    }
  }
]
```

The bridge normalizes absolute local `graphPath` values back to `src/data/graphs/*.json` before returning data to the browser.

#### `GET /__graphify_graph?id=<id>`

`id` must be lowercase kebab-case and at most 128 characters. A valid live graph request streams the graph JSON. If the requested graph is missing but the bundled seed graph exists, the response is still `200` and includes:

```
X-Knowledge-Graph-Fallback: ai-os
X-Knowledge-Graph-Requested-Id: <requested-id>
```

If no graph or seed graph can be streamed, the endpoint returns a bounded JSON error.

#### `GET /__graphify_admin_status`

Returns:

```json
{
  "ok": true,
  "adminEnabled": false,
  "gate": "HERMES_DASHBOARD_ADMIN",
  "expectedValue": "1",
  "devOnly": true,
  "productionAvailable": false,
  "tokenRequired": true,
  "graphify": {
    "available": false,
    "optional": true,
    "source": "missing"
  }
}
```

`graphify.source` is `configured`, `path`, or `missing`. The endpoint does not return the resolved graphify binary path.

#### `POST /__graphify_ingest`

Accepts JSON:

```json
{ "path": "~/code/my-repo", "name": "Optional display name" }
```

`path` may be a local directory path or a Git/GitHub URL. Local paths are resolved on the dev-server machine. Git URLs are shallow-cloned into a temp directory, graphed, registered, and removed.

A successful response is:

```json
{
  "ok": true,
  "id": "my-repo",
  "entry": {
    "id": "my-repo",
    "name": "Optional display name",
    "description": "Ingested from a local source path.",
    "lang": "TypeScript",
    "color": "#14b8a6",
    "nodeCount": 120,
    "edgeCount": 240,
    "communities": 8,
    "extractedPct": 91,
    "godNodes": [],
    "graphPath": "src/data/graphs/my-repo.json",
    "provenance": {
      "kind": "live-graphify",
      "label": "Live graphify",
      "description": "Generated from my-repo.",
      "generatedAt": "2026-06-09T00:00:00.000Z"
    }
  },
  "warnings": []
}
```

Safety behavior:

* Request body limit is 64 KiB.
* `Content-Type` must include `application/json` when present.
* Path and name strings reject control characters and excessive length.
* HTTP(S) Git URLs with embedded usernames are rejected.
* Git URL shell metacharacters are rejected.
* Git clone uses `git clone --depth 1`.
* Git and graphify calls use argv arrays, not shell command strings.
* Command output buffers and timeouts are bounded.
* Missing or malformed `graphify-out/graph.json` fails the request.
* Parsed graphs above 12,000 nodes are rejected.
* Graphs that appear to include vendored dependencies are rejected.
* Large accepted graphs may return warnings.
* Temp clones and local `graphify-out` directories are cleaned after the attempt.
* Graph writes are rolled back if registry writes fail.

#### `DELETE /__graphify_remove?id=<id>`

Returns:

```json
{
  "ok": true,
  "id": "my-repo",
  "removed": true,
  "registry": []
}
```

If the id is valid but not present, the response is still successful with `removed: false`. Removal deletes only the graph artifact resolved under `src/data/graphs/` and rewrites the registry. It never deletes the source repository.

#### Error Codes

Knowledge Graph bridge errors use:

| Code                        | Typical status | Meaning                                             |
| --------------------------- | -------------- | --------------------------------------------------- |
| `method_not_allowed`        | 405            | Wrong HTTP method.                                  |
| `loopback_required`         | 403            | Request did not originate from loopback.            |
| `invalid_token`             | 403            | Mutation token is missing or wrong.                 |
| `admin_disabled`            | 403            | Admin env is missing or production mode is active.  |
| `invalid_id`                | 400            | Graph id is missing or outside the allowed pattern. |
| `invalid_json`              | 400            | Request body is not valid JSON.                     |
| `invalid_payload`           | 400            | JSON body has the wrong shape.                      |
| `invalid_source`            | 400            | Path, name, or Git URL is invalid.                  |
| `source_not_found`          | 400            | Local path does not exist.                          |
| `unsupported_media_type`    | 415            | Content type is not JSON.                           |
| `body_too_large`            | 413            | JSON body exceeded the size limit.                  |
| `graphify_missing`          | 503            | Optional graphify binary is unavailable.            |
| `git_missing`               | 503            | Git command is unavailable for Git URL ingest.      |
| `clone_failed`              | 502            | Git clone failed.                                   |
| `graphify_failed`           | 500            | Graphify command failed.                            |
| `timeout`                   | 504            | Git or graphify timed out.                          |
| `missing_output`            | 500            | Graphify did not produce `graph.json`.              |
| `invalid_graph`             | 422            | Graphify graph payload failed validation.           |
| `graph_too_large`           | 422            | Graph exceeded the 12,000 node cap.                 |
| `vendored_dependency_graph` | 422            | Graph appears to include vendored dependencies.     |
| `invalid_registry`          | 422            | Registry JSON failed validation.                    |
| `path_escape`               | 400            | Registry graph path escapes the graph directory.    |
| `stream_failed`             | 500            | Graph stream failed.                                |
| `internal_error`            | 500            | Unexpected server error with bounded details.       |

Bridge error responses avoid echoing local temp paths, source directories, token values, auth headers, OAuth material, or command output.

### Hermes Dev Bridge

The Hermes bridge exists only inside Vite `configureServer`. It performs fresh local Hermes reads for the Hermes UI and is not a public product API. All responses use `Cache-Control: no-store`, all routes require loopback access, and sensitive local reads require `X-Claude-OS-Token` from `/__token`. Public Hermes reads cover connections, Pantheon templates, missions, and documents. Token-gated Hermes reads cover profiles, skills, sessions, session detail, memory, and Pantheon.

| Method | Path                                | Purpose                                              | Access                        |
| ------ | ----------------------------------- | ---------------------------------------------------- | ----------------------------- |
| `GET`  | `/__hermes_status`                  | Return Hermes install/config/model status            | Loopback only                 |
| `GET`  | `/__hermes_models`                  | Return configured default and fallback model catalog | Loopback only                 |
| `GET`  | `/__hermes_model_intelligence`      | Return Ministry model metrics and pricing provenance | Loopback only                 |
| `GET`  | `/__hermes_connections`             | Return public connection summaries                   | Loopback only                 |
| `GET`  | `/__hermes_pantheon_templates`      | Return public Pantheon template summaries            | Loopback only                 |
| `GET`  | `/__hermes_missions`                | Return the AI OS mission envelope                    | Loopback only                 |
| `GET`  | `/__hermes_documents`               | Return public document summaries                     | Loopback only                 |
| `GET`  | `/__hermes_documents/file?name=...` | Return a safe document file stream                   | Loopback only                 |
| `GET`  | `/__hermes_documents/trash`         | Return public document trash summaries               | Loopback only                 |
| `GET`  | `/__hermes_profiles`                | Return token-gated profile summaries                 | Loopback only, token required |
| `GET`  | `/__hermes_skills`                  | Return installed skill summaries                     | Loopback only, token required |
| `GET`  | `/__hermes_sessions`                | Return bounded recent session summaries              | Loopback only, token required |
| `GET`  | `/__hermes_session`                 | Return one sanitized session by strict `id`          | Loopback only, token required |
| `GET`  | `/__hermes_memory`                  | Return sanitized memory and soul file state          | Loopback only, token required |
| `GET`  | `/__hermes_pantheon`                | Return installed persona summaries                   | Loopback only, token required |

`/__hermes_models` returns:

* `configuredDefault` and `default`, including declared context when present.
* A provider-grouped catalog with provider labels, tints, aliases, tiers, and context metadata.
* `mixtures` derived from local MoA preset config.
* `configured`, a browser-safe list of configured provider aliases. The bridge derives it from local config, auth metadata, and provider env key names, but never returns key values.
* `catalogProvenance`, currently the bundled Claude OS v2.10.1 catalog snapshot from 2026-06-30.

Catalog context values are marked as either `declared` or `fallback`. Fallback entries include a short reason, such as bundled local-model context or provider fallback context. The catalog is filtered to configured provider aliases when possible and falls back to the bundled catalog when no configured provider can be identified.

`/__hermes_model_intelligence` returns the shipped Ministry model intelligence body:

```ts
type HermesModelIntelligenceResponse = {
  ok: true;
  generatedAt: string;
  lineup: Array<{
    id: string;
    provider: string;
    providerLabel: string;
    providerTint: string;
    model: string;
    displayName: string;
    role: "aggregator" | "reasoning" | "cost-specialist" | "speed-specialist";
    aliases: string[];
    benchmark: {
      value: number | null;
      fallbackValue: number;
      rankValue: number;
      unit: "score" | "tokens_per_second";
      source: "bundled-static" | "missing-fallback";
      label: string;
      fallbackReason: string | null;
    };
    speed: {
      value: number | null;
      fallbackValue: number;
      rankValue: number;
      unit: "score" | "tokens_per_second";
      source: "bundled-static" | "missing-fallback";
      label: string;
      fallbackReason: string | null;
    };
    pricing: {
      inputPerMillionUsd: number | null;
      outputPerMillionUsd: number | null;
      blendedPerMillionUsd: number | null;
      rankValue: number;
      source: "bundled" | "openrouter-live";
      status: "snapshot" | "live" | "fallback";
      label: string;
      updatedAt: string;
      openRouterModelId: string | null;
      fallbackReason: string | null;
    };
  }>;
  ranking: Record<"benchmark" | "cost" | "speed", string[]>;
  pricingProvenance: {
    source: "bundled" | "openrouter-live";
    status: "snapshot" | "live" | "fallback";
    label: string;
    snapshotDate: string;
    liveUpdatedAt: string | null;
    staleTimeMs: number;
    reason: string | null;
  };
  livePricing: {
    enabled: boolean;
    attempted: boolean;
    status: "disabled" | "success" | "partial" | "fallback";
    staleTimeMs: number;
    updatedAt: string | null;
    reason: string | null;
  };
};
```

Benchmarks and speed rankings are bundled static Ministry data. Pricing uses a bundled snapshot by default and can overlay live public OpenRouter model-list pricing when enabled and reachable. Failed, unavailable, or partial live pricing falls back to the bundled snapshot with provenance fields explaining the reason.

### OpenClaw Dev Bridge

The OpenClaw bridge exists only inside Vite `configureServer`. It performs fresh bounded local reads for the AI OS host cockpit and is not a public product API. All responses use `Cache-Control: no-store`, all routes require loopback access, and sensitive local reads require `X-Claude-OS-Token` from `/__token`.

| Method | Path                    | Purpose                                                     | Access                        |
| ------ | ----------------------- | ----------------------------------------------------------- | ----------------------------- |
| `GET`  | `/__openclaw_status`    | Return coarse OpenClaw install/config/status counts         | Loopback only                 |
| `GET`  | `/__openclaw_dashboard` | Return a compact scanner-backed OpenClaw dashboard snapshot | Loopback only, token required |
| `GET`  | `/__openclaw_sessions`  | Return bounded recent session metadata, no transcript text  | Loopback only, token required |
| `GET`  | `/__openclaw_subagents` | Return bounded sub-agent run summaries                      | Loopback only, token required |
| `GET`  | `/__openclaw_tasks`     | Return bounded SQLite task run summaries and status counts  | Loopback only, token required |
| `GET`  | `/__openclaw_skills`    | Return configured skill and plugin summaries                | Loopback only, token required |

The optional `limit` query parameter is clamped per endpoint. The bridge does not expose write, upload, spawn, shell, git, OpenClaw CLI, or Gateway RPC behavior. It does not read transcript bodies, raw prompts, command output, logs, repo diffs, credentials, or workspace files.

`/__openclaw_status` is intentionally coarse and token-free so the route can show setup-required, loading, endpoint-error, and offline states before asking for a per-run token. Dashboard, sessions, sub-agent, task, and skill/plugin summaries remain token-gated because they expose bounded local state metadata.

### OpenClaw Admin Bridge

The OpenClaw admin bridge exists only inside Vite `configureServer`. It is currently gated by `OPENCLAW_DASHBOARD_ADMIN=1` and reports whether that implementation gate is set for the current local dev-server run. Production builds report admin unavailable even when the env key is present. The project-wide access contract treats this as a current implementation constraint, not the future local default.

No supported local OpenClaw deploy or spawn execution path is implemented. The action endpoint is a current-gated preflight that validates the request and returns an explicit unsupported response; it does not start OpenClaw, spawn sub-agents, write files, run shell/git commands, upload data, delete data, or call Gateway RPCs. Do not document deploy/spawn as delivered until the product executes it end to end with visible results, recovery paths, and tests.

| Method | Path                       | Purpose                                                | Access                                             |
| ------ | -------------------------- | ------------------------------------------------------ | -------------------------------------------------- |
| `GET`  | `/__openclaw_admin_status` | Return local admin readiness and support status        | Loopback only                                      |
| `POST` | `/__openclaw_admin_action` | Validate deploy/spawn preflight and report unsupported | Loopback only, token required, current action gate |

Both endpoints use `Cache-Control: no-store`.

`POST /__openclaw_admin_action` accepts bounded JSON for either:

```json
{ "action": "deploy", "modeId": "configured-agents" }
```

or:

```json
{ "action": "spawn", "swarmId": "agent:builder:main", "taskId": "task-preflight" }
```

IDs must contain only letters, numbers, `:`, `_`, and `-`, and path fields are rejected. A valid request returns `supported: false` and a warning that no OpenClaw action was started.

The route treats this response as an unsupported support check. It does not simulate success, start a process, write OpenClaw state, or mutate a workspace.

### Hermes Admin Bridge

The Hermes admin bridge also exists only inside Vite `configureServer`. It is currently gated by all of the following before chat, write, or delete behavior runs:

* Local loopback request.
* Per-run `X-Claude-OS-Token` from `/__token`.
* Current `HERMES_DASHBOARD_ADMIN=1` implementation gate in the shell or `.env.local`.

The project-wide access contract treats the env gate as a migration constraint, not the future local default. The admin bridge is unavailable in production builds. The implemented surface covers chat, image upload, mission orchestration, Pantheon sync, document mutation, and Obsidian actions. Memory editing, session deletion, arbitrary git behavior outside the Pantheon mirror sync, and arbitrary file paths are not implemented.

Pantheon sync is intentionally narrow. It resolves an allowed local git mirror root from `HERMES_MIRROR`, `~/.hermes/.mirror_path`, or `~/code/hermes-mirror`; the resolved directory must already contain `.git`. The endpoint copies persona YAML into `pantheon/personas/`, then runs `git add`, `git commit -m "Sync Hermes Pantheon personas"`, and `git push`. An otherwise empty private repo checkout is valid as long as it has an initial branch and can push.

Hermes document reads and mutations use `HERMES_DOCUMENTS_DIR` when set and fall back to `~/Documents/Hermes`. Obsidian writes require the requested vault root to be present in `HERMES_OBSIDIAN_VAULTS` or `HERMES_OBSIDIAN_VAULT`.

| Method   | Path                            | Purpose                                      | Access                                            |
| -------- | ------------------------------- | -------------------------------------------- | ------------------------------------------------- |
| `GET`    | `/__hermes_admin_status`        | Return local admin readiness status          | Loopback only                                     |
| `POST`   | `/__hermes_chat`                | Stream one Hermes chat response as SSE       | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_cmd`                 | Run one allowlisted Hermes command           | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_moa_save`            | Save one local MoA preset into Hermes config | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_image_upload`        | Upload one Hermes image asset                | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_missions/create`     | Create and activate one Hermes mission       | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_missions/optimize`   | Return a non-persisted optimized preview     | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_missions/commit`     | Commit a mission candidate and activate it   | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_missions/tick`       | Tick one active mission goal                 | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_missions/clear`      | Clear the active mission pointer             | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_missions/set-active` | Reactivate one archived mission              | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_pantheon_sync`       | Sync Pantheon files into the mirror root     | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_pantheon/validate`   | Validate persona YAML and return warnings    | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_pantheon/install`    | Install default personas without clobbering  | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_pantheon/create`     | Create one validated persona YAML            | Loopback only, token required, current write gate |
| `PUT`    | `/__hermes_pantheon/<id>`       | Replace one validated persona YAML           | Loopback only, token required, current write gate |
| `DELETE` | `/__hermes_pantheon/<id>`       | Delete one persona YAML by strict persona ID | Loopback only, token required, current write gate |
| `DELETE` | `/__hermes_documents?name=...`  | Move one document to trash                   | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_documents/restore`   | Restore one trashed document                 | Loopback only, token required, current write gate |
| `DELETE` | `/__hermes_documents/trash`     | Purge one trashed document                   | Loopback only, token required, current write gate |
| `POST`   | `/__hermes_obsidian`            | Sync Hermes notes into Obsidian              | Loopback only, token required, current write gate |

`POST /__hermes_chat` accepts JSON:

```json
{
  "prompt": "Summarize the local Hermes status.",
  "sessionId": "optional-session-id",
  "model": "gpt-5.5",
  "provider": "openai",
  "toolsets": "web,graph",
  "yolo": true,
  "graph": true
}
```

Only `prompt` is required. `sessionId` must match the local session-id pattern when present. `model`, `provider`, and `toolsets` are strict short strings; `provider: "moa"` requires a `model` override. `yolo` and `graph` are accepted only as booleans and are sent only when `true`.

The response is `text/event-stream` with:

* `chunk` events: sanitized assistant output.
* `info` events: sanitized stderr or bridge diagnostics, including safe provider auth failure wording.
* `done` events: final exit code.
* `error` events: controlled bridge or Hermes failure code and message.

Heartbeat comments keep the stream alive. The server passes prompt text as argv, never through a shell, and kills the child process on timeout, post-output idle, or browser disconnect.

`POST /__hermes_cmd` accepts JSON for one allowlisted command:

```json
{ "command": "status" }
```

Supported commands are `version`, `status`, `insights`, `doctor`, and `update`. `update` requires confirmation:

```json
{ "command": "update", "confirmation": "update" }
```

Command output is sanitized, byte-bounded, and returned as JSON:

```json
{
  "ok": true,
  "command": "status",
  "label": "Hermes status",
  "code": 0,
  "timedOut": false,
  "stdout": "...",
  "stderr": ""
}
```

Timeouts and command failures return bounded error bodies and may include short sanitized `errors` details.

`POST /__hermes_moa_save` accepts a strict MoA preset payload:

```json
{
  "name": "local-panel",
  "reference_models": [
    { "provider": "openai", "model": "gpt-5" },
    { "provider": "anthropic", "model": "claude-sonnet-5" }
  ],
  "aggregator": { "provider": "openrouter", "model": "anthropic/claude-sonnet-5" },
  "reference_temperature": 0.2,
  "aggregator_temperature": 0.1,
  "max_tokens": 2000,
  "enabled": true
}
```

The bridge reads the local Hermes config, creates a timestamped backup label, merges the preset under `moa.presets`, sets it as the default preset, and atomically replaces the config file. The response returns only safe metadata:

```json
{
  "ok": true,
  "preset": "local-panel",
  "defaultPreset": "local-panel",
  "backup": "config.yaml.aios-backup-20260703120000"
}
```

Mission endpoints accept bounded JSON and return JSON. All mission documents returned by create, optimize, commit, tick, and set-active include `schema_version: 1`, `id`, `title`, `binary_outcome`, `deadline_days`, `deadline_iso`, `created_at`, `image_path`, and `mini_goals`.

`POST /__hermes_missions/create` accepts a mission candidate:

```json
{
  "title": "Ship the mission",
  "binary_outcome": "Mission is complete",
  "deadline_days": 14,
  "mini_goals": [
    {
      "title": "Draft the plan",
      "actor": "human",
      "done_when": "Plan is approved",
      "full_prompt": "Human briefing text",
      "estimate": "30m"
    }
  ]
}
```

It validates IDs and goal fields, normalizes the mission to schema version 1, writes `missions.json` atomically, makes the mission active, and returns:

```json
{ "ok": true, "mission": { "schema_version": 1, "id": "mission-..." } }
```

`POST /__hermes_missions/optimize` accepts:

```json
{ "input": "Turn this operator goal into a Mission Control mission." }
```

The server sends bounded input to Hermes as argv, not through a shell. A successful response is preview-only and does not write `missions.json`:

```json
{ "ok": true, "preview": true, "mission": { "schema_version": 1 } }
```

`POST /__hermes_missions/commit` accepts:

```json
{ "mission": { "title": "Reviewed mission", "mini_goals": [] } }
```

The endpoint is used both for committing optimized previews and for importing locally validated agent-authored mission JSON. It normalizes the candidate, writes it atomically, makes it active, and returns:

```json
{ "ok": true, "committed": true, "mission": { "schema_version": 1 } }
```

`POST /__hermes_missions/tick` accepts `{ "goalId": "g-mission-1" }`, requires an active mission, toggles that active goal between `queued` and `done`, and returns `{ "ok": true, "mission": { "schema_version": 1 } }`.

`POST /__hermes_missions/clear` accepts `{ "confirm": "clear" }`, clears only the active pointer, leaves archived missions stored, and returns `{ "ok": true, "active": null }`.

`POST /__hermes_missions/set-active` accepts:

```json
{ "missionId": "mission-archived", "confirm": "reactivate" }
```

The `confirm` field is required only when replacing a different active mission. The endpoint validates that the target mission exists in the archived store, preserves existing mission documents, updates the active pointer, and returns:

```json
{ "ok": true, "active": "mission-archived", "mission": { "id": "mission-archived" } }
```

If the target mission is already active, the endpoint returns success without rewriting the file.

Mission Control's browser UI prevents duplicate create, optimize, commit, import, tick, clear, and set-active submits while a mission mutation is in flight. The bridge returns bounded error bodies such as `{ "ok": false, "error": "invalid token", "code": "invalid_token" }`; UI feedback redacts local paths, token-like strings, and auth headers before rendering failures.

Persona write endpoints accept JSON containing either a `yaml` string, a `persona` object, or direct persona fields. IDs must match `^[a-z][a-z0-9_-]{0,63}$` and are validated before filesystem paths are built. Create and install operations never overwrite existing persona files.

### Voice Launch Bridge

`POST /__start_voice` exists only inside Vite `configureServer`. It starts or reuses the local voice broker for the Hermes Intelligence portal. It is not a public product API and is unavailable outside local dev.

Access requirements:

* Method must be `POST`.
* Request must originate from loopback.
* `X-Claude-OS-Token` must match the same-run token from `/__token`.
* Request body is limited to 1024 bytes.
* Browser-supplied provider config is rejected. Provider credentials come only from ignored local environment.

Valid launch bodies are empty or `{}`:

```json
{}
```

`/__start_voice` reads `OPENAI_API_KEY` and optional `OPENAI_BASE_URL` from the local dev-server environment, validates that the base URL is the OpenAI default or loopback, starts `bun run voice`, passes `AI_OS_VOICE_TOKEN` to the child environment, and polls broker health. A successful response is:

```json
{
  "ok": true,
  "already": false,
  "port": 8099,
  "health": {
    "ok": true,
    "service": "voice-broker",
    "ready": true,
    "keyed": true,
    "tokenRequired": true,
    "baseUrl": "https://api.openai.com",
    "basePolicy": "openai",
    "recovery": []
  }
}
```

Safe error codes include `method_not_allowed`, `loopback_required`, `invalid_token`, `invalid_json`, `invalid_payload`, `body_too_large`, `missing_key`, `base_not_allowed`, `start_in_flight`, `spawn_failed`, and `health_timeout`.

The broker itself serves `GET /api/health` and `POST /api/session` on the local voice port. `/api/session` requires the same-run voice token and accepts only `voice` and `mode`; it mints a short-lived Realtime client secret server-side. Browser code sends no provider key or provider base URL to `/__start_voice` or `/api/session`.

## Data Shape

The fallback runtime data shape is committed at:

```
src/data/live-data.example.json
```

The generated local runtime data file is:

```
src/data/live-data.json
```

`src/data/live-data.json` is gitignored because it can contain private local machine data.

## Extension Data

Extension runtime data is delivered through the existing `/__live-data` endpoint as the `extensions` branch of the `LiveData` JSON object. Extension views read generated runtime data via `useExtensionData(extensionId)`, which selects from the shared React Query cache. The Trend Finder Creator Lens bridge is a separate dev-only config endpoint; it does not deliver generated extension runtime data.

## Trend Finder API Boundary

No public Trend Finder ingestion, scoring, or generated report API exists yet. Current Trend Finder runtime data is produced by local Bun scheduler and aggregation scripts and delivered through `/__live-data`; the Trend Finder-specific HTTP surfaces are the dev-only visibility config bridge, Creator Lens bridge, and scoped `/__run_trend_finder` run bridge above.


---

# 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/api/readme_api.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.
