diff --git a/.env.example b/.env.example
index 9096878481..0dea00257c 100644
--- a/.env.example
+++ b/.env.example
@@ -26,12 +26,9 @@ CLICKHOUSE_PASSWORD=maple
# MAPLE_IGNORE_ORG_CLICKHOUSE=1
# Database
-# Local non-worker entrypoints + tests use embedded PGlite. MAPLE_DB_URL is the
-# PGlite data dir: blank = apps/api/.data/pglite (persistent), or `memory://`
-# for ephemeral. The Workers under `alchemy dev` ignore this and dial the
-# docker-compose Postgres through the dev Hyperdrive origin in
-# apps/api/alchemy.run.ts (`bun run db:up && bun run db:migrate:local` to set it up).
-MAPLE_DB_URL=
+# The Workers under `alchemy dev` dial the docker-compose Postgres through the dev
+# Hyperdrive origin (`bun run db:up && bun run db:migrate:local` to set it up).
+# Tests use embedded PGlite and need nothing here.
# Deployed stages (set in Infisical, not here): the PlanetScale Postgres connection
# string for the `main` branch (direct port 5432), used by the import scripts. prd binds its Hyperdrive by dashboard
@@ -237,7 +234,7 @@ ELECTRIC_URL=http://localhost:3473
# # apps/electric/alchemy.run.ts into Secrets Manager as the
# # ECS service's DATABASE_URL.
-# LLM provider for AI chat + triage. Both paths stay wired in apps/api/src/platform/Llm.ts, so
+# LLM provider for AI chat + triage. Both paths stay wired in apps/ai/src/platform/Llm.ts, so
# switching is this one var: "openrouter" (default) or "workers-ai". Model overrides are
# provider-scoped so both can stay set across a flip.
# MAPLE_LLM_PROVIDER=openrouter
diff --git a/.oxfmtrc.jsonc b/.oxfmtrc.jsonc
index 06b50bdbde..85cc6a3914 100644
--- a/.oxfmtrc.jsonc
+++ b/.oxfmtrc.jsonc
@@ -6,8 +6,6 @@
"tabWidth": 4,
// packages/db/drizzle is generated (drizzle-kit, then effect-orm) — formatting
// it is churn that only obscures the migration-snapshot diff.
- // TanStack Router owns routeTree.gen.ts and regenerates it in its configured
- // style during web builds; formatting it only creates transient churn.
// The iOS OpenAPI spec is generated by scripts/generate-ios-openapi.ts, and
// `ios:openapi:check` re-runs that generator and compares byte for byte — so
// formatting it does not merely churn, it fails CI for anyone who has run
diff --git a/AGENTS.md b/AGENTS.md
index 99cebee88d..f4436e254f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -38,7 +38,7 @@ with `packageManager`.
`apps/api` forwards `/mcp`, `/api/chat/*`, `/internal/chat/*` to it over a service binding;
OAuth stays in `apps/api`.
- An investigation is **one agent turn** ending in `submit_diagnosis`. Do not split it across
- planner/lanes/validator. Sub-agents are fine elsewhere (e.g. review fan-out) via `SubagentHost`.
+ planner/lanes/validator. Sub-agents are fine elsewhere (e.g. review fan-out) via `Subagent` from `@yielded/agent/subagent`.
- LLM code (Effect AI + `@yielded/agent`) is only in `apps/ai`; Maple-specific wiring lives in
`apps/ai/src/platform/Llm.ts`.
- Shared services live in `packages/backend`, imported via `@maple/backend/*` subpaths.
diff --git a/CLAUDE.md b/CLAUDE.md
index 348a141fdf..6727dda93f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -38,7 +38,7 @@ with `packageManager`.
`apps/api` forwards `/mcp`, `/api/chat/*`, `/internal/chat/*` to it over a service binding;
OAuth stays in `apps/api`.
- An investigation is **one agent turn** ending in `submit_diagnosis`. Do not split it across
- planner/lanes/validator. Sub-agents are fine elsewhere (e.g. review fan-out) via `SubagentHost`.
+ planner/lanes/validator. Sub-agents are fine elsewhere (e.g. review fan-out) via `Subagent` from `@yielded/agent/subagent`.
- LLM code (Effect AI + `@yielded/agent`) is only in `apps/ai`; Maple-specific wiring lives in
`apps/ai/src/platform/Llm.ts`.
- Shared services live in `packages/backend`, imported via `@maple/backend/*` subpaths.
diff --git a/apps/scraper/Dockerfile b/apps/scraper/Dockerfile
index a522d94145..e3b88dfac6 100644
--- a/apps/scraper/Dockerfile
+++ b/apps/scraper/Dockerfile
@@ -1,4 +1,4 @@
-# Local docker-compose build. Build context: repo root (workspace deps @maple/domain +
+# Source build for a local image. Build context: repo root (workspace deps @maple/domain +
# @maple-dev/effect-sdk). Deploys use Dockerfile.prebuilt (apps/scraper/alchemy.run.ts).
FROM oven/bun:1.4.4 AS runner
WORKDIR /app
diff --git a/apps/web/src/document-headers.ts b/apps/web/src/document-headers.ts
index 75e1933fec..d2bd295850 100644
--- a/apps/web/src/document-headers.ts
+++ b/apps/web/src/document-headers.ts
@@ -25,7 +25,7 @@ const SHARE_PATH = "/share"
export const isShareDocument = (pathname: string): boolean =>
pathname === SHARE_PATH || Str.startsWith(`${SHARE_PATH}/`)(pathname)
-/** Every document: no plugins, no `` retargeting relative URLs. Keep in step with nginx.conf. */
+/** Every document: no plugins, no `` retargeting relative URLs. */
const BASE_CSP = "object-src 'none'; base-uri 'self'"
export const APP_DOCUMENT_HEADERS: HeaderEntries = [
diff --git a/docs/persistence.md b/docs/persistence.md
index e9704f13aa..d995804c08 100644
--- a/docs/persistence.md
+++ b/docs/persistence.md
@@ -10,8 +10,7 @@ Maple stores relational application state in PostgreSQL with a schema defined by
administrative connection.
- **Wrangler development:** Docker Postgres on port 5499 through Hyperdrive's
`localConnectionString`.
-- **Non-Worker local entrypoints and tests:** embedded PGlite. `MAPLE_DB_URL` is a PGlite data
- directory, or `memory://` for an ephemeral database. It is not a remote database URL.
+- **Tests and evals:** embedded PGlite, in memory.
- **PR previews:** a Neon branch `pr-` per preview, migrated by the deploy like prd's
`main` and deleted on teardown, behind one Hyperdrive config (`docs/pr-previews.md`).
@@ -59,9 +58,6 @@ bun db:up
bun db:migrate:local
```
-Persistent PGlite is created automatically for non-Worker local entrypoints under
-`apps/api/.data/pglite`. Set `MAPLE_DB_URL=memory://` when persistence is not wanted.
-
## Authoring migrations
Change a table in `packages/db/src/tables/`, then generate the migration:
diff --git a/docs/product-events-dashboard-parity.md b/docs/product-events-dashboard-parity.md
index aa8be36642..db3cf1b7a4 100644
--- a/docs/product-events-dashboard-parity.md
+++ b/docs/product-events-dashboard-parity.md
@@ -181,8 +181,8 @@ hangs off the `QuerySpec` arms from phase 1.
widened. `alert-signal-display.ts`: label "Event count" / "Sessions with events", unit `count`.
- Web: `apps/web/src/lib/alerts/form-utils.ts` and `signal-and-threshold-section.tsx` accept the
source; the where-clause editor gets the same scope as the dashboard panel.
-- Alert templates: one "Signups dropped" example under `alert-templates/` is enough to prove the
- path; don't build a catalogue.
+- Alert templates: one "Signups dropped" example is enough to prove the path; don't build a
+ catalogue.
### Phase 5: agents and public surfaces
diff --git a/packages/backend/src/platform/Env.ts b/packages/backend/src/platform/Env.ts
index fb4c3ba431..75c6019220 100644
--- a/packages/backend/src/platform/Env.ts
+++ b/packages/backend/src/platform/Env.ts
@@ -27,7 +27,6 @@ export interface EnvConfig {
readonly CLICKHOUSE_USER: string
readonly CLICKHOUSE_PASSWORD: Option.Option
readonly CLICKHOUSE_DATABASE: string
- readonly MAPLE_DB_URL: string
readonly MAPLE_AUTH_MODE: string
readonly MAPLE_ROOT_PASSWORD: Option.Option
readonly MAPLE_DEFAULT_ORG_ID: string
@@ -233,7 +232,6 @@ const envConfig = Config.all({
CLICKHOUSE_USER: stringWithDefault("CLICKHOUSE_USER", "default"),
CLICKHOUSE_PASSWORD: optionalRedacted("CLICKHOUSE_PASSWORD"),
CLICKHOUSE_DATABASE: stringWithDefault("CLICKHOUSE_DATABASE", "default"),
- MAPLE_DB_URL: stringWithDefault("MAPLE_DB_URL", ""),
MAPLE_AUTH_MODE: stringWithDefault("MAPLE_AUTH_MODE", "self_hosted"),
MAPLE_ROOT_PASSWORD: optionalRedacted("MAPLE_ROOT_PASSWORD"),
MAPLE_DEFAULT_ORG_ID: stringWithDefault("MAPLE_DEFAULT_ORG_ID", "default"),