Skip to content
AI systems & agentsInternal2026

Evolve Studio OS

A 23-tool internal creative-intelligence suite for a content studio, wrapping brief writing, YouTube analytics, and a client portal behind a single chokepoint that is the only…

20 of 23
tool routes live (3 stubbed pending an unbuilt clip pipeline and unavailable footage)
232 passing, 1 skipped
backend test count
9
Alembic migrations applied
ArchitectureGated system — no screenshot
Interface
  • FastAPI (api/) + Next.js (web/)
  • Google Workspace SSO (domain-res…
Edge
  • launchd services (api, web, work…
Application
  • Redis (arq) for the async worker
Data
  • Postgres 16 + pgvector 0.8.2, Al…
Intelligence
  • Claude Code headless (`claude -p…

Evolve Studio OS holds live data, so this shows the verified technology stack by layer rather than a screenshot. Hosts, ports and topology are deliberately absent.

Problem

A content studio running multiple brands needed a working set for brief writing, script drafting, thumbnail and title testing, YouTube performance analysis, competitor tracking, and shoot scheduling, without any of it becoming a second CRM, a second billing surface, or a place where an unbounded model call could rack up an unpredictable bill or generate off-brand copy unsupervised. Prior internal tooling had no single point where AI spend or brand-safety rules were enforced, which meant either risk was left to habit. The brief also had a specific trap built into it: an earlier plan assumed a clip-processing pipeline called Kaleidoscope already existed and could be built against. It didn't - no repo locally, none on GitHub, no running service - and a studio tool built to assume it would either silently fail or need to fake its output. The problem statement had to include "notice when the brief is wrong," not just "build the twenty-plus tools," because building against an assumption that turns out false is worse than building fewer tools honestly.

What was built

One app, three surfaces: an internal dashboard for the studio team, a YouTube analytics wing, and a separate client-facing portal. The internal dashboard groups into five lanes: Command (what's in flight, stuck, or awaiting a person), Create (Brief Builder, Script Forge with pgvector near-duplicate detection, Hook Lab, Content Score, Title Intelligence, Thumbnail Lab - each surfacing a "Bottom line" takeaway rather than a raw score), Operations (Projects with an assignments UI, Shoot Planner running NOAA sun-position math, Approvals, Proof Vault with a public-ties export gate), Analytics (Pulse, Channel Doctor, Video Autopsy - all reading real YouTube Data/Analytics API data), and Intelligence (Comment Intelligence for lead mining, Competitor Watch, Trend Radar), plus an Admin lane (Brand Brain, Team, Integrations). The client portal is a separately-authed surface for reviewing and approving deliverables. Every generative tool returns a plain-language verdict and next step rather than a raw score. Tools that need a credential or data source that doesn't exist yet say so explicitly in the UI rather than failing silently or being hidden - the three Media tools (Clip Miner, B-Roll Matchmaker, Repurpose Engine) are the visible example: they ship as real routes with a frozen contract, marked pending, never silently faked.

Technical approach

The core architectural decision is the spend chokepoint: api/app/spend.py is the only module permitted to reach a model, enforced by a test that walks the source tree looking for a second import of the Anthropic SDK or an Ollama call, plus a second test proving that guard itself has teeth (i.e. it actually fails when violated, not just when nothing violates it). Paid tiers route through claude -p (headless Claude Code) authenticating against a Max subscription rather than a metered API key, a directive change mid-build; this required stripping ANTHROPIC_API_KEY from the subprocess environment, since its mere presence causes Claude Code to prefer metered billing over subscription auth, and adding /opt/homebrew/bin to the launchd service's PATH since launchd's minimal PATH otherwise can't find the claude binary, silently degrading every paid call to the free local tier. The second load-bearing rule is that any complete(generative=True) call without a bound brand_id raises rather than returning generic output, with creative rules checked post-generation and one auto-regeneration attempt before a human sees a named rule violation. The client portal is architecturally separated from the internal app: brand.portal_users carries no foreign key to workflow.team_members, portal sessions carry portal_user_id and internal sessions carry team_member_id, and every portal query is hard-scoped to the session's client_id with cross-client access proven to 404 by test, not by convention. Six build-spec assumptions were corrected against the actual machine mid-project (a claimed prior clip pipeline didn't exist, a claimed 8TB drive didn't exist, three years of claimed footage was 12KB on disk, a chosen pgvector dimension was wrong for the installed embedder and was fixed from 1024 to 768 mid-build via a dedicated migration), which shaped the final scope: three Media tools (Clip Miner, B-Roll Matchmaker, Repurpose Engine) are visibly stubbed rather than built against a corpus that doesn't exist, following the project's own rule that a gap in source data must be labeled, never imputed.

Creative approach

Craft

The web shell's five-hue state taxonomy (live, not built, dormant, not connected, gated) is a deliberate information-design choice: graying every unavailable tool into one tone would collapse two very different problems ('no backend exists' vs 'a credential is missing') into a single unreadable signal, and each state carries a plain-language reason inline rather than a bare 'coming soon'. The same discipline shows up inside individual tools, not just the shell: every generative tool converges on the same "Bottom line" takeaway pattern instead of a raw model-score number, so a studio team member reads a verdict and a next step in the same place every time regardless of which of the six Create-lane tools they're in. Content Score goes further - when it can only run half its checks (the rule and compliance half, no model needed) it names which scoring dimensions it couldn't run rather than either blocking the whole tool on a missing credential or quietly presenting a partial score as a complete one. Seeded brand records carry names, tiers, scoring profiles, and locked palettes, but messaging pillars, audience avatars, offers, and CTAs are left deliberately empty for a human to fill in - the system declined to fabricate plausible-sounding positioning that every downstream generative tool would then read back as ground truth.

Reframe

The non-obvious insight is that honesty about partial capability is itself a feature, not a caveat to hide. Content Score ships live for the half that needs no model (rule and compliance checks) and explicitly names which scoring dimensions it could not run rather than either gating the whole tool on a missing credential or silently returning an incomplete score as if it were complete. The same logic drove treating a real-but-unbuilt dependency (an assumed clip pipeline) as 'real but unbuilt' rather than quietly rebuilding a worse version of it or hiding the tools that need it. That same posture extends to the platform's own data: the system's operating rule is that a missing metric stays null and is never imputed to zero or backfilled with a plausible guess, the same "gap gets labeled" instinct that produced the three visibly-stubbed Media tools instead of three tools quietly faking their own output.

Process and what failed

The build spec's assumptions about the machine were wrong in six separate ways discovered only by checking (a nonexistent drive, a taken port, a wrong vector dimension, a nonexistent footage corpus), each requiring a real correction rather than working around a fiction. A Cloudflare Access layer was added in front of the app's own Google SSO, then removed once it was recognized as a redundant second login stacked on the first. The git history shows a branch-naming accident: feat/media-vault started as a narrow side project and the entire 23-tool suite was built on top of it before merging to main, leaving a stale branch pointer that a later handoff had to explicitly debunk after an earlier handoff had wrongly described the branch as holding 29 commits of stranded work.

Outcome

Running internally on the Mac Mini under four launchd services (api, web, worker, tunnel), gated by the app's own Google Workspace SSO, single-tenant by explicit decision (never a multi-tenant product, never sold). Twenty of twenty-three tool routes are live and usable by the studio team today, backed by 232 passing tests and 1 intentional skip (a bootstrap-owner test that steps aside once the owner row already exists); the three Media tools remain intentionally stubbed pending a clip-processing dependency and a footage corpus that don't yet exist on the machine. What's live is not yet exercised against real data on every path: as of the last recorded handoff no YouTube channel had been connected, so the six analytics/intelligence tools that read from the YouTube store had not yet run against a live sync - the connect-and-sync flow on the Pulse tool is the explicitly named next real-world test, not a hypothetical one. The remaining activation steps are all last-mile configuration rather than unbuilt work: connecting a channel to unlock the YouTube tools, and setting an optional API token to light up Trend Radar's secondary data feed.