← Changelog

Workspaces become a tenant primitive — top-right switcher in the shell, per-workspace `.env` loaded scoped (not into `process.env`), `client_id` flows through every chat turn, hardcoded reach-edu retires

augment-it was filing all its work under one tenant (reach-edu) and the slab that told the chat what `client_id` to use literally hardcoded the string. Tonight that ends. The shell grows a workspace switcher in the top-right of the header that lists every directory found under `clients/` (today: humain-vc, reach-edu), and clicking one persists the choice to localStorage, broadcasts it via `augment-it:workspace-changed`, and tells the workspace-service which `client_id` is process-wide active. The chat slab now reads the operator's pick from `ctx.client_id` (forwarded on every chat turn) and falls back to the server's process-wide active value — the hardcoded reach-edu string is gone. The load-bearing piece is the env-var seam: `clients/<slug>/.env` gets loaded into a frozen, in-memory map keyed by slug at workspace-service boot. We deliberately do NOT merge into `process.env` because the workspace-service runs in one process and serves all tenants — `process.env` would bleed Decile keys from humain-vc into a reach-edu chat turn. The connector-config seam (LLM / search / CRM / MCP / storage) the spec calls for lands in step 2; tonight surfaces the raw env, hides nothing, and gives Decile a clean home to slot into next.