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
Evolve Studio OS interface
ArchitectureGated system — interior not shown
  1. 01
    Interface
    • FastAPI (api/) + Next.js (web/)
    • Google Workspace SSO (domain-res…
  2. 02
    Edge
    • launchd services (api, web, work…
  3. 03
    Application
    • Redis (arq) for the async worker
  4. 04
    Data
    • Postgres 16 + pgvector 0.8.2, Al…
  5. 05
    Intelligence
    • Claude Code headless (`claude -p…

Evolve Studio OS holds live data, so this shows the verified technology stack by layer rather than the interior of the app. Layers, not connections — which service calls which is not something a dependency list can prove. 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. None of it could become 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, so 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." 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 shows what's in flight, stuck, or awaiting a person. Create holds Brief Builder, Script Forge with pgvector near-duplicate detection, Hook Lab, Content Score, Title Intelligence, and Thumbnail Lab, each surfacing a "Bottom line" takeaway instead of a raw score. Operations covers Projects with an assignments UI, Shoot Planner running NOAA sun-position math, Approvals, and Proof Vault with a public-ties export gate. Analytics holds Pulse, Channel Doctor, and Video Autopsy, all reading real YouTube Data/Analytics API data. Intelligence covers Comment Intelligence for lead mining, Competitor Watch, and Trend Radar. An Admin lane rounds it out with Brand Brain, Team, and 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 instead of a raw score. Tools that need a credential or data source that doesn't exist yet say so explicitly in the UI instead of 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. A test walks the source tree looking for a second import of the Anthropic SDK or an Ollama call. A second test proves that guard itself has teeth — 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 instead of 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. It also required 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 instead of returning generic output. Creative rules are checked post-generation, with 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. 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, and three years of claimed footage was 12KB on disk. A chosen pgvector dimension was also wrong for the installed embedder, and was fixed from 1024 to 768 mid-build via a dedicated migration. These corrections shaped the final scope: three Media tools (Clip Miner, B-Roll Matchmaker, Repurpose Engine) are visibly stubbed instead of 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" versus "a credential is missing" — into a single unreadable signal. Each state carries a plain-language reason inline instead of 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. 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, instead of 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. It explicitly names which scoring dimensions it could not run, instead of 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," instead of 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 required a real correction instead of 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. That left 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 instead of 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.