A
?
← Handbook

Handover

Where things stand for whoever picks this up next, agent or person. Updated 9 September 2026 by the previous agent (Claude) at Alex's request, so that a different agent can continue from GitHub alone. Update this file at the end of any session that changes what is live, blocked or next. Keep it short. Detail belongs in docs/register.md and docs/knowledge/.

What Atlas is after

A performance marketing agency whose internal tooling is better than what it could buy. Each backend function should stand alone as a best-in-class app: creative strategy that a client would pay a senior strategist for, media buying intelligence that a human buyer acts on, finance that matches the bank to the cent. The frontend is for team adoption. See docs/vision.md and docs/knowledge/atlas-portal-real-goal.md.

The agency's own positioning, decided 8 Sep 2026: a bespoke performance marketing agency, two levers post-Andromeda (creative and funnel), AI for speed with experienced direction, unlimited creative within a standard, fixed fee. Never a vendor. Never cite Atlas Homes or Reno Retreat as agency proof; that is a separate business.

Areas, and their state

Sales pipeline (GHL + Google Sheet; portal is a view only)

  • Sales pipeline (21 Sep): loaded into GHL sub-account Atlas Media Creative by API: 11 fields, 15 tags, 1,022 contacts, 451 history notes, 40 past appointments, all verified by read-back. 24 leads whose company later became a client were set Closed (became-client). Portal is now the working layer (Alex, same day): /leads grid from the ghl_contacts mirror with date-first filters, /leads/c/[ghlId] editor that writes to GHL with an audit log, /api/webhooks/ghl for live GHL-to-portal, sync-ghl.ts in refresh.sh as backstop. Deals board retired (/pipeline redirects to /leads, rail and Today no longer read deals). Right-hand column removed portal-wide. /leads redesigned 22 Sep (one KPI row, view tabs, one filter line, seven columns, details behind disclosures; every count scoped to the active filters). Built on the sales SOP (docs/sop/sales-pipeline.md): Qualification / Stage / Cohort fields (GHL custom fields + q-*/stage-*/cohort-* tags, no GHL pipeline), rates on Current + Renewed only, legacy counted not measured; all 1,022 mapped to Cohort = Legacy on 21 Sep. Row toggles, inline notes, stars, links, Web column (website/IG/TikTok/Ads Library) with dialog; enrichment from email domains; economics tiles (spend, cost per lead/booked/show/closed, revenue paid, return) and source/ad breakdown from ad_account_daily, leads.imported_from and paid invoices. Attribution (Campaign / Ad Set / Ad) is on every ad lead as GHL fields; spend definition = agency lead campaigns by name (the shared Atlas Consulting account also ran summit, client and recruitment campaigns, never counted). Projected month tile from live ad set budgets. Ads Library link is exact only with a stored page id (paste in the row dialog); automatic resolution is not possible with our Meta permissions (tested 21 Sep). Next: ad-level spend sync for per-ad cost; per-client version. Inbound/referral phones imported (12 created), 12 junk contacts removed from GHL with audit; full re-verification against the old sheet done 21 Sep evening (six colour changes and six late leads found and fixed); old sheet must be retired. JoJo skin v6 (Astra's colour manga spread) merged into dev and live on prod behind ?skin=jojo; branch skin-jojo-v6 is its origin. Take the skin's stylesheet and assets wholesale when merging a new version, and re-apply its class hooks by hand: those branches predate the leads redesign. Alex is building the GHL workflows himself; rules in docs/knowledge/atlas-ghl-workflow-rules.md. Live on dev. Next: Alex creates the GHL workflow that calls the webhook and adds Cel/JK as users; re-point or retire the old leads table; pipeline stages, then Sheet to GHL write-back for Jun Kai's columns (pause, canary, live), then AI meeting notes worker. Brief for the next thread at ~/Documents/atlas/sales-pipeline-brief.md. See docs/knowledge/atlas-sales-pipeline-setup.md and atlas-ghl-import-field-spec.md.

Portal core (creative pipeline, brand intelligence, media buying)

  • Live on dev and prod. Prod is many commits behind dev and is promoted deliberately.
  • Appearance (22 Sep): JoJo skin v6 is on branch skin-jojo-v6, unmerged. Leads is composed as a colour manga spread: an interlocked cyan/pink/gold ATLAS MEDIA / BIZARRE SALES / LEAD PIPELINE crest, issue stamp, diagonal search panel, staggered score panels, tilted filter panel and pastel dossier stack. Pointer movement drives a local speed-line field and opposing title/glyph parallax; panels, rows, clicks and route changes react. Fine pointers gain a target-star cursor with cyan afterimage, lock-on hover and click impact; reduced-motion and coarse pointers keep the native cursor. The dense table stays aligned and its fixed dialogs still escape correctly. Skins are a data-skin axis separate from light/dark; default unchanged. docs/knowledge/atlas-portal-skins.md.
  • 23 workers, 27 skills. Copy and script workers load copy-commandments, copy-structures, anti-slop, copy-voice, and since 8 Sep humanizer. Proposals load copy-structures, anti-slop, humanizer.
  • What is generatable per client is limited by evidence: see docs/knowledge/atlas-portal-delivery-blockers.md.
  • Meta sync does not yet pull hook rate and hold rate. Columns exist; the API request lacks the fields. About 30 lines. docs/knowledge/atlas-video-metrics-gap.md.
  • Next: campaign intelligence (log buying decisions, map ads to angles, changelogs). docs/knowledge/atlas-campaign-intelligence-vision.md.

Video editing pipeline (video-pipeline/)

  • Manifest-first pipeline; a third SBRC cut was delivered 7 Sep. Frame.io is the working store, Drive is cold storage. Never compose from FFmpeg alone; Remotion is the chosen renderer. docs/knowledge/video-pipeline-sep7-state.md, video-pipeline-research-sep7.md.
  • House edit style measured from 38 client finals: docs/knowledge/atlas-edit-style-metrics.md.
  • TED Recruitment October scripts (4 Oct): script 1 v1 delivered, made with the platform-v2 video stack (HyperFrames composition, S-Log3 LUT, Google review proof cards); scripts 2-5 wait on Alex's notes. The read says "only five-star reviews", which is false (4.8 from 27), so "only" is cut. Footage, verified facts and the HLG gotcha: docs/knowledge/ted-recruitment-video-facts.md.
  • Frame.io is never deleted from. New rule doc docs/rules/frameio-never-deletes.md, enforced by src/lib/video/frameio-never-deletes.test.ts, which fails if a delete path appears in the client. Alex asked for this explicitly, twice: Frame.io holds the agency's live working files.
  • Back-catalogue pass is mid-flight (8 Sep). 785 delivered videos → measurements, style sheets on 9 named axes, and reconstructed scripts. Read video-pipeline/NEXT-SESSION-BRIEF.md first; it has the exact resume commands. Transcription runs both on the worker droplet (bash /opt/atlas/phaseb.sh, resumable — the same command is the resume command) and across 18 GitHub Actions runners (.github/workflows/transcribe-corpus.yml), because the droplet is CPU-bound at 1.1 videos/min and that is 11 hours for the corpus.
  • Transcript accuracy is the binding constraint, above speed and cost, because the scripts become the library that trains the script writer. TwelveLabs Pegasus was measured and rejected: 94% word agreement but every disagreement was a brand or domain word. docs/knowledge/asr-whisper-beats-pegasus-on-brand-words.md.
  • Two guards were added after the same fault twice: the classifier refuses any video with no transcript, and refuses to write a script with no spoken words when the transcript has words. Frame.io now backs off on 429 (a bulk resolve had lost 425 of 785 files to rate limiting).
  • The back-catalogue pass is finished (9 Sep). 785 measured, 783 transcribed, 783 style sheets, 782 reconstructed scripts, $44.67 of the $160 ceiling across 471 calls. The two missing are 0-byte files in Frame.io. 781 English, 2 genuinely Mandarin, zero Malay: Alex confirmed all his videos are English, so whisper hearing Singlish as Malay was a detection fault, not content. docs/knowledge/whisper-hears-singlish-as-malay.md.
  • Indexed into the portal. 785 delivered_videos rows on Supabase dev, 783 with style and transcript, 671 reconstructed scripts in video_scripts as drafts with no angle. 19 scripts refused and named: 18 paraphrased, 1 wordless. Register 258.
  • The convergence test passed. 0 new traits after the first video across nearly every client, on within-client depth series, 59 traits over 9 axes. This was the number that decided whether trait selection works. Register 259.
  • The corpus is backed up off the droplet. It was machine-hours and API spend in one place. video-pipeline/scripts/backup-corpus.sh to branch corpus-backup, 26 MB of JSON, counted on both sides. Run it from a git worktree: another session switched branches in the shared tree mid-backup and its commit consumed the staged index, so the backup silently appeared to revert. docs/knowledge/atlas-corpus-artefacts-are-the-expensive-part.md.
  • The wordless-script fault recurred a third time and now has two independent guards. The R7 refusal used an 8-word threshold and a 4-word transcript walked through it into video_scripts. Threshold is one word, and the ingest refuses the same thing again so the library does not trust the producer. docs/knowledge/wordless-scripts-need-two-guards.md.
  • Cuts now land on the music beat, answering the standing note on v20 that only cards and even splits snapped. 0.22 s early / 0.06 s late so picture never arrives after the line that motivates it; 4 of 10 cuts moved on sbrc-nov, and 40% is the ceiling under that rule at 89 BPM rather than a target missed. A missing beat grid now fails the build instead of quietly producing an unsnapped edit. docs/knowledge/cuts-go-on-the-beat-but-never-late.md.
  • v21 is rendered and not delivered. Full res 1080x1920, look pass, -14 LUFS / -1 dBTP, no compositor kills, on the droplet at work/out/sbrc-nov-v21.mp4. Alex chose delivery as a new version of the existing Frame.io asset; the asset in decisions.deliverable has not been confirmed out loud yet, so nothing was uploaded.
  • The video tools now have SOPs, which they did not before: docs/sop/video-editor.md and docs/sop/back-catalogue-corpus.md. Between them they hold the droplet-only rule, the no-half-res rule, the two delivery modes, and a table of what is in git versus what is regenerable media. Register 264.
  • GitHub Actions is blocked on billing after the fan-out used the account's minutes, which also blocks CI and Deploy. The refusal appears as a plan-job failure with no logs; the reason is only in the check-run annotations. Only Alex can lift it. Transcription finished before it bit, so the corpus did not suffer.
  • Still open, and Alex's call because they cost money: cutsOnBeat is null for all 785 in the corpus (a re-decode, about 3.7 hours), and the first 340 style sheets were classified while tempo was null so their music axis is weaker.

Finance (/finance, atlas-finance repo)

  • Dashboard live: cashflow, expenses, personnel, receipts, transactions, analytics, scaling. Numbers verified against bank statements to the cent as of 5 Sep. Two entities, one business; portal shows both combined, bookkeeper sheet is Creative only.
  • Client acquisition cost is not computable until startedOn is filled for clients. docs/knowledge/atlas-own-ad-spend-brands.md.
  • Access is Alex and Junkai by user id. docs/knowledge/atlas-finance-access.md.
  • Finance is being rebuilt in layers (10 Sep). Layer one, the bank ledger, replaced the P&L at /finance/overview: both accounts, every row, month/year/total, reconciled to printed balances, zero breaks, and independently verified against the 46 statement PDFs in Alex's Downloads (40 of 40 printed totals match to the cent; months are statement periods, not calendar months). Attested by Alex on 10 Sep and locked by database trigger (migration 0117); see docs/rules/ledger-attested.md. Do not touch attested rows. Open: no PDF for 2026-09 Creative, and an unexplained third account 072-144500-0 in Downloads. The P&L and cashflow queries were removed because they excluded Atlas Homes rows and misclassified transfers as expenses. Layer two, /finance/deposits, is built read-only: every incoming row in four buckets that add back to the ledger (871k matched, 103k client money with no invoice, 81k Stripe payouts covering 51 card-paid invoices, 24k not client money). Layer three, /finance/monthly, is built: invoices and costs by statement month, cost groups from cost-groups.ts, both sides adding back to the ledger. The deposit-to-invoice links were re-synced to Alex's sheets on 11 Sep (see knowledge file for which sheets and the precedence). /finance/cash-in shows one company and one statement month at a time for his review; he approved the matching rules on 11 Sep and the whole period was reconciled in one pass (see knowledge file): 389 of 424 client deposits now carry an invoice, 36 client records were created for payers that had none, and cheques from AC Vision and RC Design are matched as a pool because the bank text does not name the payer. Left for Alex: 20 deposits with no invoice (AC Vision and Todzterior extras, RC Design 2025 cheques with no invoices raised, Hoft 2,400, Inspire 19,000, two unknown payers) and 13 Stripe payouts with no unique invoice. Cash-out side started 15 Sep: CPF, Wise contractors and two videographers recategorised from Alex's answers; period/period_source added to bank rows (0119) with salary and CPF periods filled from bank-text tags and the days-1-to-10 rule. Waiting on Alex: Aspire statements, the 11,776 FAST payment, 'BEN', the Meta ad spend split, the Stripe receipt files. Then: read receipt PDF amounts from Drive and match to outflows. Next: Alex names the unclassified outflows (PayNow and FAST transfers, SGD 60k), confirms the salary period rule, and works the 36 unmatched deposits; then a period column and accrual view, then margins. A match action and an attest action on the pages would help and do not exist yet. Do not bring back category-based profit until both layers reconcile. docs/knowledge/finance-bank-ledger-is-the-ssot.md.
  • Deposit means paid (10 Sep). Migration 0114 derives invoice status from matched bank deposits by trigger and ignores Stripe's status; 312 rows flipped to paid with a note. 125 Stripe rows with no deposit found (SGD 335k) are shown apart on /finance and excluded from owed, aging and chase. Data fix is applied to dev; the page change waits on the blocked deploy. Prod lacks the Stripe columns from the 4 Sep audit session; they need a migration before promotion. docs/knowledge/finance-deposit-means-paid.md.
  • Invoice revenue and ad spend made exact (15 Sep). Alex: costings can be loose, invoice revenue and ad spend cannot, because they decide which clients get scaled. Stripe is the only record of what was billed and the portal's copy had drifted: seven invoices never imported, three voided ones still billed (9,640), and INS-0029/INS-0030 with their amounts swapped. scripts/sync-stripe-invoices.ts mirrors Stripe and is re-runnable; it fixes issued_on and never an existing period. Ad spend is now recognised only as far as it was paid, shortfall coming off the ad line first, verified against DAM-0007 (5,167.20 through, 8,400 unpaid) which Alex recalled independently; the rule is src/lib/finance/ad-spend.ts with tests. /finance/clients ranks on money kept, not money received: Damien paid the most in 2026 and kept 4,580 of 23,923. 2026 is 474,302 received, 62,689 to Meta, 411,613 kept. These were data writes to the dev database, not migrations. Promoting the code to prod does not carry them; re-run sync-stripe-invoices.ts against prod after any promotion. Still open: AC Vision 7,500 and InnerSpac 2,000 received for months never invoiced, FSL and Granvision 1,500 each with no Stripe invoice under any name, three Damien-era invoices bundling fee and spend in one line. Alex suggested the WhatsApp archive can date when each retainer started and stopped, which would settle the uninvoiced months. docs/knowledge/finance-invoice-and-ad-spend-truth.md.

Google Sheets write route

  • POST /api/drive/sheet writes a formatted tab into a Google Sheet using the domain-wide-delegated service account (the write scope was already granted). Committed as 1b9db10, not yet deployed because of the build failure above. A 73-row analytics payload for the Ctrl Alt Career migration sheet is ready to send once dev deploys.

Ctrl Alt Career migration (client project, files outside this repo)

  • Salesable to FunnelWeb contact import for Jennifer Ong. Import files built 7 Sep. 113 contacts were still being worked in Salesable after the March move; for 79 of them Salesable is the newer record, so the "FunnelWeb wins" rule is wrong for that set and they are flagged for hand review. Open decisions in docs/knowledge/ctrl-alt-career-migration-build.md.

Agency website (atlas-media-site repo, being rebuilt in Lovable)

  • Three sequential Lovable prompts live in atlas-media-site/docs/: website-v2-copy-and-lovable-brief.md (site map, services, six case studies, facts register), lovable-home-fix.md (type system and plain copy), lovable-v3-peel.md (objection-ladder home page, media frames, one depth effect, budget filters). Twenty items are marked CONFIRM for Alex: fee floor, unlimited creative definition, Atlas & Bone figure, team roles, PAP client.

Production (since 22 Sep 2026)

  • The request gate is src/proxy.ts (Next 16 proxy convention). Do not recreate src/middleware.ts: it is deprecated and runs on the edge runtime, where PORTAL_MODULES and any other runtime env is invisible.
  • https://app.atlasconsulting.tech runs the same commit as dev, on its own database (a clone of dev as of 22 Sep 03:09 SGT). PORTAL_MODULES in /srv/atlas-portal/.env lists the visible sections; add a section there and redeploy to release a module. GHL webhook for prod: https://app.atlasconsulting.tech/api/webhooks/ghl?key=<GHL_WEBHOOK_SECRET> (same secret as dev).
  • From now on promote by git push origin dev:main, ./scripts/migrate.sh prod, ./scripts/deploy.sh prod, one build at a time. Dev and prod databases are separate again from this point; data written on dev after 03:09 SGT on 22 Sep is not on prod (leads state re-mirrors from GHL; run scripts/one-off/copy-lead-state-dev-to-prod.ts for portal-only columns if the team used dev after that).

Blocked on Alex

  • Xero: create the app at developer.xero.com, put XERO_CLIENT_ID and XERO_CLIENT_SECRET in both droplet envs, then open /api/xero/connect. docs/knowledge/atlas-xero-integration.md.
  • ~~Production promotion~~ Done 22 Sep 2026 03:00 SGT. Prod's database was a stale 2 Sep copy (27 invoices, no bank rows), so it was replaced by a verified restore of dev's dump (138 tables, counts identical), main was pointed at dev (old main preserved as branch main-finance-sep4), and dev's code deployed to the prod stack with PORTAL_MODULES=/pipeline,/finance so only the sales pipeline and finance are visible while Alex checks modules one at a time. Prod backup before the restore: /srv/backups/prod-20260922T030255Z.dump. Prod refresh (every 3h) and backup crons added. Historic note on the divergence that made a plain migrate fail: main and dev have diverged: 20 commits only on main (Sep finance/analytics work) including migrations 0112_client_prefix_unique and 0113_invoice_ad_spend, while dev's 0112/0113 are different files. Prod's schema_migrations recorded main's checksums, so a blind migrate.sh prod from dev would flag both as edited and never run dev's versions. Needs a dedicated session: merge main into dev, renumber the two main migrations to new numbers, baseline, back up prod, apply 36+ migrations, copy GHL secrets to prod .env, run sync-ghl.ts and sync-ad-budgets.ts on prod, copy the portal-only columns of ghl_contacts (deck_url, quote_url, invoice_url, portal_notes, portal_next_action_at, enrichment_source, enriched_at, fb_page_source) and the whole ghl_writes table from dev to prod so nothing the team did on dev is lost, switch the webhook URL, deploy, verify. Everything else on the leads page re-derives from GHL, Meta and the sheet. Until then Jun Kai works on dev.
  • Committing the video pipeline dependencies (or deciding to exclude that folder from the build).
  • Website facts marked CONFIRM.
  • startedOn dates for clients, to unblock acquisition cost.
  • Which Reno Retreat and finance figures may ever be published.

Rules learned the hard way, in one line each

Full text in docs/knowledge/.

  • Numbers must match Ads Manager; use Meta's date presets, not manual date math.
  • Recruitment leads never average into client cost per lead. Ecommerce is judged on purchases.
  • Build the reconciliation before the feature. A wrong number looks exactly like a right one.
  • Never write a guessed value. Blank beats wrong; there is often no UI to undo it.
  • No clever wording anywhere, including the website. Salesperson test, line by line.
  • The laptop disk is not storage. It filled twice. Compute in CI, store in Drive or Frame.io.
  • One area per session. Commit only your own files by path; other sessions have uncommitted work in the same tree.
  • Read-only everywhere an integration could spend or send: Meta, WhatsApp, Frame.io.

How to continue in a different agent

  1. Clone the repo. Read AGENTS.md, then this file, then docs/start-here.md.
  2. Secrets are on the droplet in .env; nothing is in the repo. Ask Alex for SSH access to 209.97.171.176 and the Supabase dev project.
  3. Before any task a skill covers, read skills/<name>/SKILL.md. Workers load them at runtime; you read them by hand.
  4. When you learn something, write it to docs/knowledge/, add it to the index, and update this file if the picture changed. Then commit and push your own files.

Sep 8 2026 (evening) — the back catalogue is being indexed

Running unattended on the droplet right now. bash /opt/atlas/overnight.sh over 785 delivered videos, in three phases: measure (8 shards, free), then transcribe (whisper, free) and classify (one Claude call per video) together, then harvest any style traits the classifier had to propose. Every stage checks for its own artefact first, so the same command is the resume command — run it again after any death and it costs nothing for work already done. Progress: node stages/R6-corpus-status.mjs.

What each video ends up with, in work/corpus/<frameio-asset-id>/:

File What it is Cost
evidence.jsonmeasured from the file: cut rhythm, shot lengths, saturation, luma, motion, the dominant vivid accent hue, loudness, speech ratio, tempo, cut-on-beatfree
sheet.jpgone timecoded contact sheet, 12 framesfree
transcript.jsonwhisper large-v3-turbo, words with times — for most of these videos the script was lost, so this is the only record of what was saidfree
style.jsonone trait per axis against references/style-vocabulary.json, with evidence and confidence~$0.107 on Opus 5
script-beats.jsonthe reconstructed script: per beat the spoken line (verbatim, checked against the transcript), the on-screen text, the B-roll subject and the effectsame call

Budget ceiling is $100, checked before every call from measured usage; the run stops cleanly at it. 785 videos is about $84 on Opus 5. Ledger: work/corpus/classify-ledger.json.

Indexing into the portal is a separate, re-runnable step and is NOT part of the overnight run, on purpose: the files are the durable artefact and the rows are derived from them, so a dead session costs nothing. When the pass is done:

rsync -az --include='*/' --include='*.json' --exclude='*' \
  root@188.166.225.209:/opt/atlas/video-pipeline/work/corpus/ video-pipeline/work/corpus/
npx tsx scripts/one-off/index-back-catalogue.ts video-pipeline/work/corpus
npx tsx scripts/one-off/back-catalogue-report.ts

Live on dev: migrations 0111 and 0112, delivered_videos. 134 rows indexed so far as a proof of the path. Not applied to prod yet.

Client mapping is done and evidenced. Frame.io projects were matched to clients through the finance data — client name, slug, prefix, registry refs, 579 invoice bill_to values and 4,438 bank counterparties. 34 of 41 matched on evidence; Alex confirmed MG Group, Occra Education and Viv's Schoolhouse, told us CAG is Climate Action Group (a free client, hence no invoice trail) and Ryan & Jaelyn is JAE, and that Reno Retreat belongs to Atlas Homes as videos only, never revenue. Two client rows were created for CAG and JAE — rename or merge them if the legal names differ. Atlas Media's own 93 videos are marked own_brand, not a client. Map: work/corpus/client-map-resolved.json.

Known limitations, not yet fixed.

  • Whisper mis-hears brand names: SBRC comes back as "Sehabo's", "hard-won" as "hard-worn". A per-client correction lexicon would fix the displayed wording while keeping the timings. Not built.
  • sound_design and music are classified from measurements only — nobody has listened. The style files say "measured, not heard" where that is the case.
  • Convergence of the trait vocabulary is untested: the 40-video breadth sample is one video per client, which maximises novelty by construction. The number that decides selection is whether a client's own finals reuse traits, and that needs the depth series (sample-depth.json, 10 Inspire ID finals). node stages/R4-style-classify.mjs converge refuses to draw a conclusion until then.

Next, in order: let the pass finish, harvest the proposed traits, run the convergence test on a within-client series, then index and report. After that the open question is selection — resolving a brief to one trait per axis — which is what skills/video-style-vocabulary/SKILL.md specifies.

18 Sep 2026 — editor output, sales pipeline, client list

  • Client list locked: 96 → 23 active, 1 onboarding, 5 paused. Every active client has an AM. paused now means is_active = true but excluded from daily views (migration 0128).
  • editor_output (migration 0130) unifies Asana (Nov 2025–Feb 2026) and Frame.io (Jun 2026+) editing work. See docs/knowledge/atlas-editor-output.md. March 2026 has no data anywhere.
  • Droplet is 4 GB / 2 vCPU: one build at a time. 20 Sep two concurrent builds took it down (load 43, OOM). deploy.sh now takes a lock; never run two deploys or a deploy during the nightly's npm ci.
  • Product catalog seeded (20 Sep): 31 units + 9 bundles in products/bundles, every invoice line tagged (product_id, bundle_code, catalog_qty), visible on /finance/catalogue; spec docs/specs/product-catalog.md; defaults that disagree await Alex. Client board artifact and client journey / list standard specs in docs/specs/.
  • New ClickUp Space "Atlas Delivery" exists (created 19 Sep from the droplet, creation only, 30 folders x 4 lists, ids in clickup_created). Old Clients Space untouched. Alex sets statuses, fields, Teams and access in the GUI; cutover plan in docs/proposals/clickup-cutover-plan.md. Droplet host now has node_modules; nightly tsx steps had failed 16–19 Sep.
  • Operating system from 1 Oct: proposal in docs/proposals/atlas-operating-system-oct-2026.md; build order in docs/specs/video-assigner.md (form + deliverables table first, ClickUp creation behind a dry run, never edit/delete ClickUp). SOPs: docs/sop/day-as-usual.md, docs/sop/revisions.md.
  • BI tabs (years, months, clients, rate card) sit at the front of the client sheet; editing rate card and the setup-fee placeholder (3 videos) are constants in scripts/build-bi-sheet.ts. Next: fill 'Est. AM & other'.
  • Client-by-month sheet 1b8ku1FcQDSRb5Js5XUHwiWfxwAkJ2QUtk3ssJLuwgKA is the view Alex works from (invoiced, paid, sold, editors, cost, design tasks). Next column: cost design work from ClickUp windows.
  • Frame.io token was dead and is renewed (Mac only). The droplet holds no Frame.io credentials; the editor chain's Frame.io half runs on the Mac by launchd at 03:00, the droplet rebuilds from the DB. See docs/knowledge/atlas-editor-output.md.
  • Sales pipeline lives in GHL + Google Sheets, portal is a view. See docs/knowledge/atlas-sales-pipeline-setup.md. Brief for the separate thread at ~/Documents/atlas/sales-pipeline-brief.md.
  • Open on Alex: deliverable rate card (0 of 7), Target CPL on all active clients (0 of 24), retainer per client for MRR (0 of 24), the $21k unidentified supplier line, four editors paid under rate, Asana token so the board syncs instead of CSV.