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

# Development Guide

## Required Tools

* Bun 1.3.14. The repository `.bun-version` and CI workflows pin this exact release for certification parity.
* Git.

## Port Mappings

| Service                  | Port | URL                     |
| ------------------------ | ---- | ----------------------- |
| Vite/TanStack dev server | 5189 | `http://127.0.0.1:5189` |
| Vite preview             | 4176 | `http://127.0.0.1:4176` |
| Wrangler local dev       | 8788 | `http://127.0.0.1:8788` |
| Wrangler inspector       | 9231 | `127.0.0.1:9231`        |

The dev server uses `strictPort: true`, so a port collision fails instead of silently switching ports.

## Local Setup Modes

Use the smallest setup mode that matches the work:

* Quick UI work: `bun install` then `bun run dev`.
* Full local telemetry: `bun install`, `bun run setup`, then `bun run dev`.
* Public static demo: `bun install` then `bun run demo:preview:pages`.
* Credential-free Trend Finder demo: use a disposable clone and follow [Credential-Free Demo Path](/ai-os-and-trend-finder-docs/docs/hackathon/hackathon-submission.md#credential-free-demo-path).

`bun install` may load `.env.local` before install-time scripts run. Keep secrets in ignored files and avoid pasting secret values into commands or logs.

`bun run dev` runs `seed:data` before starting Vite with `--open`. The `seed:data` command copies `src/data/live-data.example.json` to `src/data/live-data.json` only when the generated file is missing. It preserves existing generated local data.

## Local Access Default

Local operator features default to full local access, write access, and edit access. Keep loopback, Host-header, same-run token, validation, confirmation, timeout, safe-error, and redaction controls, but do not design local product goals around observe-only or manually disabled controls. If a feature cannot execute yet, document it as an implementation gap and do not present it as shipped.

Public demo mode, third-party source-compliance limits, missing credentials, offline dependencies, and privacy boundaries are explicit exceptions. They do not change the local product default.

For clean certification or demo recording, avoid reusing browser state from the fixed `http://127.0.0.1:5189` origin. Clear site data for that origin, use a fresh browser profile, or start the server without auto-open:

```bash
bun run seed:data
bunx vite dev --host 127.0.0.1 --port 5189
```

## Dev Scripts

| Command                                   | Purpose                                                                  |
| ----------------------------------------- | ------------------------------------------------------------------------ |
| `bun run setup`                           | Run inherited starter setup and local aggregator                         |
| `bun run dev`                             | Seed fallback data and start Vite                                        |
| `bun run build`                           | Seed fallback data and build production output                           |
| `bun run build:dev`                       | Build in development mode                                                |
| `bun run preview`                         | Preview built output                                                     |
| `bun run worker:preview`                  | Build and run the Worker locally with pinned Wrangler                    |
| `bun run worker:deploy`                   | Build and deploy the Worker with pinned Wrangler                         |
| `bun run demo:snapshot`                   | Regenerate browser-safe public demo fixtures locally                     |
| `bun run demo:build:pages`                | Build static Cloudflare Pages public demo output                         |
| `bun run demo:scan:pages`                 | Scan public demo fixtures and generated Pages output                     |
| `bun run demo:budget:pages`               | Check the Pages static client bundle budget                              |
| `bun run demo:preview:pages`              | Build and serve the static Pages demo with Wrangler                      |
| `bun run demo:deploy:pages`               | Print or execute a validated Pages direct-upload command                 |
| `bun run typecheck`                       | Run TypeScript compiler in check-only mode (`--noEmit`)                  |
| `bun run test`                            | Run all Vitest tests once                                                |
| `bun run test:watch`                      | Run Vitest in watch mode (re-run on save)                                |
| `bun run test:coverage`                   | Run Vitest with coverage report                                          |
| `bun run lint`                            | Run ESLint in check mode                                                 |
| `bun run lint:fix`                        | Run ESLint with auto-fix                                                 |
| `bun run format`                          | Format files with Prettier (`--write`)                                   |
| `bun run format:check`                    | Check formatting without modifying files (`--check`)                     |
| `bun run typecheck:scripts`               | Run TypeScript compiler on scripts (`tsconfig.scripts.json`)             |
| `bun run test:e2e`                        | Run Playwright end-to-end browser tests                                  |
| `bun run clean`                           | Remove `dist/`, `.output/`, `.vinxi/` build artifacts                    |
| `bun run budget:check`                    | Verify bundle chunk sizes are within budget                              |
| `bun run seed:data`                       | Create `src/data/live-data.json` from the example if missing             |
| `bun run aggregate`                       | Refresh local telemetry and extension collector data                     |
| `bun run trend-finder:backtest`           | Run the script-only Trend Finder historical backtest CLI                 |
| `bun run trend-finder:export-brief`       | Export a browser-safe local Trend Finder static Brief report             |
| `bun run trend-finder:replay-backhistory` | Replay reviewed Trend Finder backhistory windows                         |
| `bun run auth:openai`                     | Run the local OpenAI account-auth helper                                 |
| `bun run codex:smoke`                     | Smoke-test the OpenAI Codex account-auth transport                       |
| `bun run agents:codex:smoke`              | Smoke-test the deferred Agents Codex runtime path                        |
| `bun run apify:smoke`                     | Smoke-test configured Trend Finder Apify source access                   |
| `bun run scheduler:run`                   | Run aggregate through the AI OS scheduler runner                         |
| `bun run scheduler:status`                | Print safe aggregate scheduler status                                    |
| `bun run scheduler:agents:run`            | Refresh host/local AI OS data through the scoped scheduler               |
| `bun run scheduler:agents:status`         | Print safe host/local agent aggregate scheduler status                   |
| `bun run scheduler:trend-finder:run`      | Refresh only Trend Finder data through the scoped scheduler              |
| `bun run scheduler:trend-finder:status`   | Print safe Trend Finder scheduler status                                 |
| `bun run scheduler:dream:run`             | Run material-first AI OS Dream through the scheduler                     |
| `bun run scheduler:dream:status`          | Print safe AI OS Dream scheduler status                                  |
| `bun run runtime:check-private`           | Verify generated private artifacts are ignored and untracked             |
| `bun run install-dream`                   | Install AI OS Dream schedule on macOS/Windows; print Linux cron guidance |
| `bun run uninstall-dream`                 | Remove AI OS Dream schedule on macOS/Windows                             |
| `bun run postinstall`                     | Re-activate `.githooks/` for this clone                                  |

## Local Restart Helpers

Use these shell helpers when you want tmux-managed local dev instead of a foreground `bun run dev` process:

```bash
scripts/dev.sh
scripts/dev.sh --stop
scripts/cleandev.sh
scripts/cleandev.sh --configured
scripts/cleandev.sh --stop
scripts/cleandev.sh --stopclean
```

`scripts/dev.sh` starts the app in the `aios-dev` tmux session only when the app is down. It installs dependencies if `node_modules/.bin/vite` is missing, waits for `http://127.0.0.1:5189`, and leaves the workspace alone when the app is already healthy. `scripts/dev.sh --stop` stops the tmux-managed or project-owned local dev process without cleaning, reinstalling, validating, or restarting.

`scripts/cleandev.sh` is the repeatable full clean launch path. It stops the existing project dev server, runs `bun run clean`, removes ignored generated state and dependencies, reinstalls from `bun.lock`, runs focused validation, hydrates host/local launch data, and restarts the app in the `aios-dev` tmux session. The additional clean scope is `.tanstack`, `coverage`, `playwright-report`, `test-results`, `logs`, `.wrangler`, and `node_modules`.

The default `all` launch profile makes feature surfaces available without rerunning paid or cadence-sensitive jobs:

* `bun run scheduler:agents:run` refreshes home, skills, memory, activity, local agent, and other host/local branches.
* The tmux app process starts with `VITE_CLAUDE_OS_ENABLED_EXTENSIONS=all` unless overridden, so extension UI routes are available.
* Trend Finder collection is not run by default because configured sources and AI runtime analysis can spend provider budget.
* Dream is not run by default because its output is designed around an intentional daily cadence.

Use `scripts/cleandev.sh --configured` or set `CLEANDEV_LAUNCH_PROFILE=configured` when you want clean dev to launch only features enabled by the shell or `.env.local`. For finer control, set `CLEANDEV_RUN_HOST_AGGREGATE=0`, `CLEANDEV_RUN_TREND_FINDER=1`, or `CLEANDEV_RUN_DREAM=1`; set `CLEANDEV_ENABLED_EXTENSIONS=<ids|all|none>` to override the extension env used for hydration and the tmux Vite process. Only set the Trend Finder and Dream opt-ins for deliberate refreshes.

Clean restart intentionally preserves private and tracked state such as `.env.local`, `src/data/live-data.json`, scheduler and Dream private output, `bun.lock`, source files, and documentation. It does not run `bun run setup` or the full compatibility `bun run aggregate`; the default launch uses the scoped scheduler jobs so host/local data refreshes preserve existing Trend Finder and Dream generated-data branches.

The current Phase 40 Hermes write bridge still uses `HERMES_DASHBOARD_ADMIN=1` as an implementation gate. That gate is not the future local access default. When `.env.local` or `.env` sets it, `scripts/cleandev.sh` performs an additional post-start Hermes check against the tmux-started Vite server. The check calls `/__hermes_status`, `/__hermes_admin_status`, and `/__token`; it fails the clean restart if Hermes is not `ready`, the current admin bridge is not enabled, or the per-run token is not available. A passing run prints a line such as:

```
[cleandev] Hermes runtime: status=ready admin=enabled token=ready home=...
```

For test isolation, `scripts/cleandev.sh` runs:

```bash
VITE_CLAUDE_OS_ENABLED_EXTENSIONS= bun run test
```

If an extension is listed in `.env.local` but the sidebar, route, or Settings still shows the wrong state, check the active process env first: `VITE_CLAUDE_OS_ENABLED_EXTENSIONS` controls browser navigation and enabled state, Vite must be restarted after `VITE_` changes, and editing `.env.local.example` does not change local runtime config. Then check the extension runtime-data mode. Collector-backed `extension-item` extensions such as Trend Finder need `src/data/live-data.json` extension items, so run `bun run aggregate` when collected topics are stale. Client-local `host-live-data` extensions such as AI Rogue do not need a matching collector item; inspect host LiveData availability instead.

Trend Finder routes are still statically registered when the env switch is unset, so direct URLs can render fixture/demo data from the committed fallback payload. That does not mean the collector, scoped scheduler job, Apify Actors, or AI runtime ran. Collector execution needs `VITE_CLAUDE_OS_ENABLED_EXTENSIONS=trend-finder` or `all`; Apify execution also needs `APIFY_TOKEN` and reviewed source config.

## Main Source Areas

| Path                  | Purpose                                                     |
| --------------------- | ----------------------------------------------------------- |
| `src/routes/`         | TanStack Router route files                                 |
| `src/components/`     | Shared components and dashboard UI                          |
| `src/components/ui/`  | Local wrappers around UI primitives                         |
| `src/lib/`            | Utilities and runtime data helpers                          |
| `src/hooks/`          | React hooks                                                 |
| `src/data/`           | Runtime data shape and generated local JSON                 |
| `src/extensions/`     | Client extension contracts, registry, and extension modules |
| `scripts/`            | Bun scripts                                                 |
| `scripts/extensions/` | Extension collector registries and source adapters          |
| `skills/`             | Inherited starter skill assets                              |

## Runtime Data During Development

The app reads live data through `useLiveData()`:

```
src/lib/use-live-data.ts -> GET /__live-data -> src/data/live-data.json
```

If `src/data/live-data.json` is missing, the dev server falls back to `src/data/live-data.example.json`.

Local browser actions use the current Vite middleware control plane:

| Endpoint               | Development boundary                                                                                                                          |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /__live-data`     | Reads generated or fallback data from disk.                                                                                                   |
| `GET /__token`         | Returns the same-run token to the local browser after loopback and Host checks.                                                               |
| `POST /__refresh_data` | Runs aggregate refresh after loopback, Host, and token checks.                                                                                |
| `POST /__run_dream`    | Runs the Dream scheduler job after loopback, Host, and token checks.                                                                          |
| `/__hermes_*`          | Uses route-specific current read/write rules; local writes are expected to move toward default write readiness under the all-access contract. |

These are local development surfaces, not public demo APIs. Keep raw local paths, prompts, transcripts, auth JSON, and tokens out of browser-visible responses.

`bun run aggregate` also writes private structured traces under `logs/`. Use `logs/aggregate.latest.jsonl` for the most recent collector run, including runtime readiness, source counts, sanitized AI-analysis request/response metadata, validation issues, and fallback reasons. These logs are gitignored and should stay local.

Terminal logs are allowed to include local diagnostic paths for operator debugging. Anything emitted to browser data, Vite middleware responses, or scheduler status must keep raw private paths out of the payload by using safe labels, counts, or redacted path text.

Codex app-server readiness is optional aggregate-time metadata. Leave `CODEX_APP_SERVER_URL` unset for normal CLI-only setups. If you already run a local Codex app-server, set a loopback-only `http://` or `ws://` endpoint and rerun `bun run aggregate`; AI OS records health/status/count metadata only.

Scheduled aggregate is the scheduler-wrapped full compatibility form of the same aggregate implementation. Use `bun run scheduler:run` when validating the full aggregate scheduler lock, timeout, private run state, and private log path. Use `bun run scheduler:agents:run` for host/local-only data and `bun run scheduler:trend-finder:run` for Trend Finder-only extension data. Dream uses `bun run scheduler:dream:run` and `bun run scheduler:dream:status` for the material-first host runtime path. These commands are command-only and do not add browser-visible scheduler fields.

The scoped agent aggregate and Trend Finder scheduler jobs are enabled by default in starter metadata. Full aggregate remains a manual compatibility writer and is not enabled by default. Timer installation remains local machine setup; keep user systemd unit files and private scheduler state out of git. Local timer intent is recorded in `data/ai-os.scheduler.json`, seeded from `data/ai-os.scheduler.example.json`, and limited to reviewed jobs, reviewed cadence IDs, booleans, and strict Dream `HH:MM` times.

`bun run scheduler:run` remains the full compatibility writer. The scoped agent aggregate and Trend Finder commands preserve each other's owned generated-data branches through the shared merge writer, while the full public command still writes the complete generated data artifact.

The Trend Finder historical backtest CLI is script-only. It replays reviewed historical windows, writes full output under `.cache/extensions/trend-finder/backtests/`, and publishes only bounded browser-safe summaries when explicitly requested.

## Environment Variables

The inherited starter can use optional keys in `.env.local` or the shell environment. These are not required for basic development.

| Variable                                    | Purpose                                                                                             |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `PINECONE_API_KEY`                          | Optional Pinecone index stats in imported memory graph                                              |
| `OPENROUTER_API_KEY`                        | Optional OpenRouter balance and usage data                                                          |
| `ANTHROPIC_API_KEY`                         | Optional raw API mode for imported scripts                                                          |
| `OPENAI_API_KEY`                            | Optional OpenAI-backed local scripts and Dream images                                               |
| `APIFY_TOKEN`                               | Optional Trend Finder Apify Actor and Dataset collection                                            |
| `KIE_API_KEY`                               | Optional image generation scripts                                                                   |
| `NOTION_TOKEN` / `NOTION_API_KEY`           | Optional Notion memory graph ingestion                                                              |
| `REDDIT_CLIENT_ID` / `REDDIT_CLIENT_SECRET` | Optional Trend Finder Reddit source credentials                                                     |
| `GITHUB_TOKEN`                              | Optional Trend Finder GitHub source credential                                                      |
| `YOUTUBE_API_KEY`                           | Optional Trend Finder YouTube source credential                                                     |
| `AI_OS_AI_RUNTIME_*`                        | Optional script-only AI OS host AI runtime configuration                                            |
| `AI_OS_OPENAI_ACCOUNT_AUTH_PATH`            | Optional host account-auth JSON path override                                                       |
| `AI_OS_DREAM_ENABLED`                       | Optional script-only Dream scheduler activation gate                                                |
| `FINDTREND_APIFY_*`                         | Optional reviewed Actor source declarations and source caps                                         |
| `FINDTREND_AI_RUNTIME_*`                    | Optional script-only Trend Finder AI runtime configuration                                          |
| `FINDTREND_OPENAI_*`                        | Optional local OpenAI account-auth path and OAuth callback                                          |
| `HERMES_HOME`                               | Optional Hermes home override for local scanner and bridge                                          |
| `HERMES_DASHBOARD_ADMIN`                    | Current Phase 40 implementation gate for Hermes write bridge controls; not the future local default |
| `HERMES_BIN`                                | Optional trusted local Hermes executable for admin chat                                             |
| `HERMES_DOCUMENTS_DIR`                      | Optional Hermes document read/write directory override                                              |
| `HERMES_MIRROR`                             | Optional allowed git mirror root for Pantheon persona sync                                          |
| `HERMES_OBSIDIAN_VAULTS`                    | Optional Obsidian vault allow-list for Hermes memory linking                                        |
| `HERMES_OBSIDIAN_VAULT`                     | Optional single-vault Obsidian allow-list compatibility value                                       |
| `GIT_BIN`                                   | Optional git executable override for Pantheon mirror sync                                           |
| `OPENCLAW_CONFIG_PATH`                      | Optional direct OpenClaw config file override                                                       |
| `OPENCLAW_STATE_PATH`                       | Optional OpenClaw state directory or config file override                                           |
| `OPENCLAW_WORKSPACE_PATH`                   | Optional OpenClaw workspace label source                                                            |
| `OPENCLAW_DASHBOARD_ADMIN`                  | Current implementation gate for OpenClaw admin support checks; not the future local default         |
| `CODEX_HOME`                                | Optional Codex home path for AI OS host telemetry                                                   |
| `CODEX_APP_SERVER_URL`                      | Optional loopback-only Codex app-server readiness endpoint                                          |
| `CLAUDE_OS_OPERATOR_PHOTO_SOURCE_URL`       | Optional server-side source URL for the dev photo proxy                                             |
| `CLAUDE_OS_PHOTO_ALLOWED_HOSTS`             | Optional operator photo proxy host allowlist extension                                              |
| `CLAUDE_OS_ANONYMIZE`                       | Set to `0` to disable aggregator anonymization                                                      |
| `CLAUDE_OS_REDACT_PREVIEWS`                 | Set to `0` to keep preview strings in emitted data                                                  |
| `CLAUDE_OS_OBSIDIAN_PATH`                   | Optional custom Obsidian path for imported scanner                                                  |
| `LOG_LEVEL`                                 | pino log level (default: `info`)                                                                    |
| `VITE_CLAUDE_OS_ENABLED_EXTENSIONS`         | Public extension enablement list (e.g. `trend-finder`, `ai-rogue`, or `all`)                        |
| `TREND_FINDER_HN_ITEMS`                     | HN story fetch count per collection run (default: 30, max 200)                                      |

See [Environments](/ai-os-and-trend-finder-docs/docs/environments.md) for the full public `VITE_` setup override list and private script-only secret handling. The `FINDTREND_*` names are retained compatibility names for Trend Finder runtime configuration; they are not the host app identity.

When changing Codex app-server readiness behavior, run focused scanner and UI tests plus script typechecking before broader validation:

```bash
bun test scripts/lib/__tests__/codex-app-server-readiness.test.ts
bun test scripts/lib/__tests__/local-agent-assembly.test.ts src/lib/__tests__/local-agent-ui.test.ts
bun run typecheck:scripts
```

When changing scheduler, scheduled aggregate, or Dream behavior, run focused scheduler tests before broader validation:

```bash
bun run test -- scripts/lib/__tests__/scheduler-registry.test.ts scripts/lib/__tests__/scheduler-aggregate-handler.test.ts scripts/lib/__tests__/scheduler-agent-aggregate-handler.test.ts scripts/lib/__tests__/scheduler-trend-finder-handler.test.ts scripts/lib/__tests__/scheduler-dream-handler.test.ts scripts/lib/__tests__/scheduler-runner.test.ts scripts/lib/__tests__/scheduler-run-state.test.ts scripts/lib/__tests__/scheduler-run-log.test.ts scripts/lib/__tests__/scheduler-locks.test.ts scripts/lib/__tests__/scheduler-operator-status.test.ts scripts/lib/__tests__/scheduler-status-cli.test.ts scripts/lib/__tests__/aggregate-live-data-write.test.ts scripts/lib/__tests__/aggregate-orchestration.test.ts scripts/lib/__tests__/dream-execution.test.ts scripts/lib/__tests__/extensions-runner.test.ts
bun run typecheck:scripts
bun run scheduler:status
bun run scheduler:dream:status
bun run runtime:check-private
```

When changing AI Rogue behavior, run the focused extension checks before broader validation:

```bash
bun run test -- src/extensions/ai-rogue src/routes/__tests__/extensions-routes.test.tsx
bun run test:e2e -- tests/e2e/ai-rogue-runtime.spec.ts tests/e2e/ai-rogue-ledger.spec.ts tests/e2e/ai-rogue-persistence.spec.ts tests/e2e/ai-rogue-mobile.spec.ts
bun run runtime:check-private
bash scripts/check-asset-sizes.sh
```

For AI Rogue input-mode or public-demo gameplay changes, also keep the fresh-state mobile, desktop Auto, explicit override, and Pages no-bridge coverage green:

```bash
bun run test:e2e -- tests/e2e/ai-rogue-mobile.spec.ts tests/e2e/ai-rogue-runtime.spec.ts tests/e2e/pages-demo-mobile.spec.ts --project=chromium --project=pages-demo-chromium
```

When changing the Cloudflare Pages public demo, keep the static demo path separate from the Worker deployment path and run the focused checks first. The snapshot exporter may read local generated data, but the committed fixture must stay an allowlisted public-safe projection and `bun run demo:scan:pages` must remain clean:

```bash
bun run demo:build:pages
bun run demo:scan:pages
bun run demo:budget:pages
bun run typecheck:scripts
```

For route-level confidence, serve the built output and run the Pages route matrix against that static preview:

```bash
bun run demo:build:pages
bunx wrangler pages dev demo-website/dist --ip 127.0.0.1 --port 8789
PLAYWRIGHT_BASE_URL=http://127.0.0.1:8789 PLAYWRIGHT_REUSE_EXISTING_SERVER=true bunx playwright test tests/e2e/pages-demo-routes.spec.ts tests/e2e/pages-demo-mobile.spec.ts
```

Run the Playwright command from a second shell after the Wrangler preview is ready, then stop the preview process.

If Wrangler Pages dev follows repository Worker configuration instead of the static Pages root, copy `demo-website/dist` to a temporary directory and serve that isolated copy before running the same route matrix.

## Testing

The project uses [Vitest](https://vitest.dev/) as the test runner. Tests live colocated with source modules in `__tests__/` directories under `src/`, `scripts/lib/`, and `scripts/extensions/`. Browser regressions live in `tests/e2e/`.

| Command                 | Purpose                        |
| ----------------------- | ------------------------------ |
| `bun run test`          | Run all tests once             |
| `bun run test:watch`    | Run tests in watch mode        |
| `bun run test:coverage` | Run tests with coverage report |

See [docs/testing.md](/ai-os-and-trend-finder-docs/docs/testing.md) for configuration details, test locations, and coverage strategy.


---

# 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/development.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.
