Engineering Review Dossier · Confidential · Pre-Launch
A complete, verified map of the OS stack — generated frontend, DINA backend, data spine, security posture, AI brain, and QA harness — plus the prioritized set of tasks that must close before launch. Every fact below was read out of the live codebase, not assumed.
build.pyindex.html, one fileTwo non-obvious rules cause silent lost work if ignored. Read §1 before touching anything.
A build + backend pass landed after v1 of this dossier. The OS was rebuilt (06:31, deployed, live 200). Net-new work, all verified in-tree:
app/_home/ControlRoom.tsx (mounted in page.tsx when AL_OS_ROOT is unset — i.e. the laptop; cloud still renders Landing). Surfaces live metrics + a browsable/runnable catalog of 254 agents + a map of what DINA does. Voice becomes one dockable panel. Owner-only, laptop-only — never on the cloud/tenant instance. Plan: dina/CONTROL_ROOM_PLAN.md.
auth/local)/api/chat now requires a logged-in session token (multi-tenant lockdown); the laptop DINA page sent none → 401 → chat error. New app/api/auth/local/route.ts mints an owner token only when AL_OS_ROOT is unset (returns 404 on cloud), so voice works on the laptop while every tenant instance stays locked.
lib/guard.ts — claudeGuard()Per-tenant rolling-window rate limit (default 40 req/min) + a monthly Claude-request budget (default 2,000/mo, persisted to ~/.awesome-link-work/usage). Owner is exempt; fail-open so a guard bug can never take a paying studio offline. Wired into 7 Claude-backed routes (chat, bid-extract, loc-extract, inv-tag, knowledge, outreach-draft, pulse-widget).
railway.json (NIXPACKS, start:cloud, restart-on-failure ×3) · Dockerfile (node:24-slim multi-stage, pnpm 10.13.1, port 8080) · fly.toml (app awesome-link-os-cloud, region fra, volume /data → AL_OS_ROOT=/data, min_machines_running=1 so no cold start) · .railwayignore correctly excludes credentials.json, .env*, operator-settings.json. Owner instance stays on the laptop; tenants served off-laptop with persistent per-tenant data.
agents-catalog + agent-run (read/run the 254 personas via headless Claude Code), metrics (owner-only real-source cockpit aggregator), auth/local. New libs: agentsCatalog.ts, agentRunner.ts, activity.ts, guard.ts. Deps bumped: Next.js 15.1.6 → 15.1.11, added @noble/hashes. Pricing/Stripe tiers wired in plans.ts + billing/checkout (owner still runs setup-stripe.mjs).
The partner email and company Tax ID/CR are gone from the shipped file (verified 0 hits in both index.html and the deployed copy). Rather than deleting them — which would have silently dropped the tax line from owner bids — they now resolve from the existing tenant config (pulseCfg.studioTax / pulseCfg.partnerAskTo), which already syncs server-side via /api/al-os/userdata and hydrates post-login. Owner values were seeded into that store, so behaviour is unchanged. verify-os → exit 0, 0 errors, all views OK.
P3 — models unchanged (claude-sonnet-4-6 ×4, claude-opus-4-8 ×4). B1/B2/B3 — proof gate, Path B decision, and tunnel boot-persistence all still open. The new guard.ts partially covers S2 at the app layer, but the Anthropic Console cap is still the account-wide backstop. New: see D1 and D2 below.
next start was failing with “Could not find a production build in the '.next' directory” (missing prerender-manifest.json), and @noble/hashes — added to package.json and imported by api/al-os/bid-deploy — was never installed. The Next.js 15.1.6 → 15.1.11 bump landed without a completed pnpm install && pnpm build, so the server had nothing to serve (launchd job showed exit -9). Resolved: installed, rebuilt, restarted — OS + health both 200. This is Rule 2 in CLAUDE.md failing in practice; a dep bump must always be followed by install + build + restart, or DINA silently dies.railway.json (Railway/NIXPACKS) and fly.toml + Dockerfile (Fly.io, region fra, /data volume) now exist, and the Dockerfile header says “Built by Fly.io” while .railwayignore was touched most recently. The recorded decision was Railway; the newer config is Fly. Ambiguity here means the off-laptop launch could be built twice or against the wrong target. Confirm the canonical host and delete the loser's config.This repo has an unusual architecture. Two facts break naïve edits, and both fail silently — the app looks fine, your change just vanishes or never activates.
index.html.The entire OS UI (HTML, CSS, and ~all JS) is emitted by awesome-link-os/build.py — a single Python file that holds the markup/CSS/JS as strings. Running it writes index.html and deploys a copy to dina/public/os/index.html.
build.py, never the generated index.html or the deployed copy — the next build overwrites them.python3 build.py · local-only: AL_OS_NO_DEPLOY=1 python3 build.pynode --check on the largest inline <script>.DINA (Next.js, port 3737) runs via next start over a compiled .next. Editing a .ts/route does nothing to the running server until you rebuild and restart. tsc --noEmit does not activate code.
pnpm build then bash scripts/dina-restart.sh (never launchctl kickstart directly).OPERATOR_RUN_ID) to avoid killing an in-flight run.curl -s -o /dev/null -w "%{http_code}" .../os/index.html → 200.Every OS change must pass the headless self-check verify/verify-os.mjs (exit 0) before it is considered done. It loads the live OS in real Chrome and fails on any JS error, thrown view, or stale deploy. node --check alone will not catch a runtime/render break. See §7.
One machine, two codebases. A vanilla-JS single-page frontend served as a static file, talking to a Next.js backend that holds all auth, data, and AI. There is no separate database or web framework on the frontend.
/os/index.html — a bare /os/ 404s (the redirect handles /os). Phone reaches it via the Cloudflare tunnel (backup: Tailscale bridge, port 3838).
build.py · 12,801 lines Python (~963 KB)index.html · ~860 KB, single self-contained fileD{}, hydrated after loginmanifest.webmanifest + service worker + iconsThe ~860 KB is dominated by inline JS. Boot cost on the 2017 dev laptop is the known frontend perf bottleneck (see §8 risks).
Tab views registered in build.py via data-view:
Phase-2 SKU plan mothballs several of these into a curated 6-tab sellable edition (Bids · Network · Locations · Rebate Calc · Pipeline · Studio Brain).
⟦OS⟧[…]⟦/OS⟧ action protocol; requires DINA online.next start over prebuilt .next127.0.0.1:3737 (loopback only)start:cloud → 0.0.0.0:$PORT (Railway-ready)alOsData.ts (30 KB) — data spine, tenant-scoped readsauth.ts (16 KB) — multi-tenant scrypt + HMAC sessionsstudioAgent.ts (47 KB) — sandboxed Studio / Edit-OS agentguard.ts new — per-tenant rate limit + monthly cost capagentsCatalog.ts · agentRunner.ts · activity.ts new — Control Room agents + metricsoperator.ts — phone agent runner + deferred restartalOsIngest / Enrich / Match / Tags / Knowledge / ThoughtScananthropicClient.ts · dinaPrompt.ts · plans.ts| Group | Representative routes | Purpose |
|---|---|---|
| /api/auth/* | login · me · refresh · signup · admin · team · change-pass · local | Passphrase login → HMAC token; 1h TTL with background refresh; multi-tenant. local new mints an owner token on the laptop only (404 on cloud). |
| /api/al-os/* (Control Room) | metrics · agents-catalog · agent-run | new Owner-only cockpit: real-source metrics aggregator + browse/run the 254 agent personas via headless Claude Code. |
| /api/al-os/* | bootstrap · roster · contacts · crm · locations · match · bid-extract · bid-template · bid-pptx · bid-deploy · enrich · tags · knowledge · outreach-draft · operator · camera · thoughts · export · health | The OS data + feature spine. bootstrap hydrates sensitive data post-login; the rest power each module. |
| /api/billing/* | checkout · status · webhook | Stripe subscription plumbing (harvested for the productized SKU). |
| /api/voice/* | route · list · stt | TTS voice list + speech-to-text (ElevenLabs). |
| /api/chat | route | Studio Core conversational brain. auth-gated (401) |
| /api/body/* | ingest · live · summary | Health/telemetry ingest (Whoop bridge experiment). |
All runtime data is flat files under ~/.awesome-link-work/, plus build-time JSON committed alongside build.py.
messages.json, tags.json, knowledge/, bid-templates/, loc-uploads/, operator/, studio/data.json (122 KB), mena.json (327 KB, 1,746 contacts), brain.jsondina/credentials.json (scrypt hashes, chmod 600)Implication: state is single-node and local by design. Off-laptop / multi-tenant scale means moving this to a persistent-disk host (Railway pivot) — see §8.
Anthropic API, tiered by task weight:
The Sonnet calls pin claude-sonnet-4-6; the current family is Sonnet 5 — worth a deliberate model-refresh pass at review (see checklist P3).
The threat model is "a static file can't be secured by a login — so stop shipping the data in the file." That principle is largely executed. Findings below are from a live probe of the shipped index.html, not the plan docs (which disagree with each other on this point — trust the probe).
| Control | State | Evidence / note |
|---|---|---|
| Backend auth | Done | scrypt passphrase + HMAC-signed stateless tokens, 1h TTL + background refresh loop. |
| Multi-tenant isolation | Done | Token carries {tenantId, role}; owner→global data, others→empty-by-default; verifySession() is fail-closed. |
| Token storage | Done | Held in memory in the OS, not localStorage. |
| CORS + network bind | Done | Origin-locked; all servers loopback-bound (LAN closed). |
/api/chat gated | Done | Returns 401 without a valid session (verified in source). |
| Per-tenant cost / rate guard | New | guard.ts — 40 req/min rolling window + 2,000 Claude req/mo per tenant (persisted); owner-exempt; fail-open. On 7 Claude routes. |
| De-embed MENA contacts | Done | 1,746 contacts removed from index.html (MENA = []); hydrated post-login via bootstrap. |
| Public exposure | Gated | Cloudflare named tunnel + Access (Mostafa's email only, 1-mo sessions). |
| Residual literals in built file | Done | Partner email + company Tax ID/CR removed 2026-07-16 — now resolve from tenant config (pulseCfg, synced via userdata, hydrated post-login). Verified 0 hits in the built + deployed file; verify-os exit 0. |
| Tunnel boot-persistence | Open | Quick-tunnel replaced by named tunnel, but not yet service install'd — a Mac reboot drops public access. |
The Studio agent (studioAgent.ts) spawns headless Claude Code with tools allow-listed to Read/Write/Edit only — no Bash, network, MCP, or secrets (env-stripped), under a single-run lock + timeout. Edit-OS mode edits OS source inside an isolated git worktree, runs a no-deploy verify build, shows a diff for human approval, and auto-rolls-back if the live build fails. Nothing reaches the live OS without an approved diff.
Loads the live OS in installed Chrome (playwright-core), blocks the service worker + backend-sync endpoint for a deterministic test, and runs 19 feature checks: cards render/edit/delete, leads, venues, preview, thumbnails, search narrows/empties/resets, filter options, lightbox, library/vision/outreach content, and deploy freshness.
errors/failedChecks, fix build.py, rebuild, re-runverify-tenant-gate.mjs — multi-tenant isolation checks (does tenant B ever see owner data).~/.awesome-link-work/operator/verify-latest.png.{outcome, errors, failedChecks, checks, views}.This harness is the Operator's only "eyes" — a "done" without a green verify is the #1 historical cause of "said done but it's broken."
Synthesized from TODO.md, BUILD_PLAN.md, and the live probe above. Ordered by severity. "Owner" = only Mostafa can do it; "Eng" = the engineer.
sudo cloudflared service install <token> so a Mac reboot doesn't silently drop os.awesomelinkfilms.com. Until this lands, public access is one reboot from down.build.pybuild.py (bid-generator studioProfile(), the read-only Settings row, and the outreach partner-ask prefill). They now read from pulseCfg.studioTax / pulseCfg.partnerAskTo — the existing tenant config that already syncs server-side through /api/al-os/userdata; owner values were seeded there so nothing changed for Mostafa. Rebuilt + deployed; 0 hits for all three literals in the built and deployed file; verify-os exit 0 (19 checks, all views OK). Backups: build.py.bak-scrub-*, userdata.json.bak-scrub-*.guard.ts (per-tenant app-layer cap), but the Console cap is the account-wide backstop the app can't provide.TODO.md and still open — harvesting contact/thread data into the OS. Scope + decide in/out of the launch cut.claude-sonnet-4-6 calls against the current Sonnet 5 family; upgrade where quality/latency/cost warrant, re-run the affected flows.railway.json) and Fly.io (fly.toml + Dockerfile, region fra, /data volume, one warm machine) — see D2: pick one before deploying. Blocked on the owner creating the account for whichever target wins.build.py (not index.html); after backend edits, pnpm build + dina-restart.sh.curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3737/os/index.html → 200.node verify/verify-os.mjs and read the JSON — this is your ground truth for "healthy."lib/auth.ts, lib/alOsData.ts, and one API route end-to-end to see the auth → data pattern.Durable business facts, decisions, and standing rules live in the Obsidian vault at ~/claude/brain (start at Home.md). The build rules also live in ~/claude/CLAUDE.md.