Case study
Content System
A native macOS ops console: SSH JSON-line jobs, no stored AWS secrets, and thirteen guided workspaces instead of Terminal tabs.

- Client
- Streaming content ops
- Services
- Automation · macOS app · Internal tools
01 / Challenge
Content operators lived in Terminal, SSH sessions, and memorized AWS CLI flags. Uploads, metadata checks, subtitle pulls, live episode review, promo staging, artwork resize, and weekly reporting were separate rituals with no shared history — fine for one engineer, fragile for a team that had to move a slate without dropping a file. Secrets sat in shells. Progress was scrollback. Failures were “did it finish?” in Slack.

02 / Insight
The bottleneck was not upload speed — it was cognitive load across uploads, validation, subtitles, live review, promos, artwork, and reporting with no shared state, plus secrets living in shells.

03 / System
We shipped a SwiftUI glass console that wraps remote bash behind SSH with JSON-line progress, plus local Python for validators and subtitle cleanup. Authenticate once per session: host, key, and AWS profile name — never a long-lived AWS secret in the app. Every workflow is preview-then-apply, with Activity as the shared log. Marketing copy, sanitize, live review, promos, artwork, and weekly Mail drafts all sit in the same sidebar instead of a wiki of scripts.
Process reconstruction
Content System architecture
How the pieces hand off without another dashboard nobody opens.
- Auth
- SSH / JSON
- Workflows
- Activity
04 / Execution
We shipped a SwiftUI glass console that wraps remote bash behind SSH with JSON-line progress, plus local Python for validators and subtitle cleanup. Authenticate once per session: host, key, and AWS profile name — never a long-lived AWS secret in the app. Every workflow is preview-then-apply, with Activity as the shared log. Marketing copy, sanitize, live review, promos, artwork, and weekly Mail drafts all sit in the same sidebar instead of a wiki of scripts.

05 / Outcome
Ops got a cockpit they could hand to someone who should not be trusted with raw IAM. Multi-file S3 uploads show live speed; CSV leaves a cleaned file; captions can be pulled and normalized; live IDs get checked against mapping paths; marketing leaves a folder instead of a scavenger hunt. The Mac is a console. The host still does the privileged work.

Toolkit
Every surface, featured fully.
Each piece below is almost its own product — designed, shipped, and used as a first-class workflow rather than a buried submenu.
01
Upload to S3
The upload workspace is a packaging console, not a file picker glued to AWS CLI. Operators drop or browse local masters, pick a destination prefix, and run a dry-run that checks names, extensions, and size before anything leaves the machine. When they commit, each file streams independently with live MB/s, remaining time, and a per-file status so a 40 GB episode does not hide a failed sidecar. Under the hood the Mac never talks to S3 with an embedded IAM key. A JSON-line SSH session to the ops host drives the existing remote scripts, and progress events hydrate the UI as they arrive. Sessions are resumable: if the laptop sleeps mid-batch, the operator reopens the same job instead of guessing which objects already landed. Sanitize-before-publish is the default so a space, emoji, or uppercase extension never becomes a 403 at the CDN. The problem this solves is cognitive, not bandwidth. The old ritual was Terminal tabs, remembered flags, and a Slack “did it finish?” The new one is preview, confirm, watch, and a row in Activity.

02
Marketing Request
Marketing did not need access to the master upload bucket — they needed a ready folder on their SFTP share. This workspace takes campaign paths, copies the matching objects, and writes a destination the editor can open without a scavenger hunt. The copy still happens on the ops host (same SSH JSON-line channel as upload). On success, a follow-on Asana call completes the content-ops sub-task, comments the video editor with the destination, and unassigns the operator from the parent so they stop getting edit/review spam. Failure stays in Activity with the remote stderr, not a silent AWS console error. This is the native face of the Marketing Requests pipeline: Slack form and Asana still start the work; this screen is where the files actually move.

03
Activity
Every workflow used to leave its own log — Terminal scrollback, a CSV on a desktop, a Slack screenshot. Activity is the shared history: uploads, marketing copies, subtitle pulls, CSV validation, artwork resize, and promo jobs in one reverse-chronological feed with success, warning, and failure. Rows expand to the same structured events the SSH stream emitted, so an operator can answer “what happened at 14:12?” without SSHing in. Filters keep the feed usable on a busy week. Nothing here is a second source of truth; it is a readable index over jobs the app already ran.

04
Sanitize Files
CDN and player stacks are unforgiving about filenames. Sanitize scans a server directory, proposes a rename for every illegal character, collision, or extension mismatch, and waits. Apply is explicit. There is no “fix it as we upload and hope.” The preview table is the safety valve: operators can uncheck a row, keep a house exception, or abort. Remote apply uses the same SSH channel; the Mac never mounts the volume. This exists because a single bad name used to fail a whole batch after minutes of transfer.

05
Download Subtitles
Subtitle packages live next to the masters in S3, but pulling them used to mean composing a prefix, an AWS profile, and a local destination by hand. This workspace lists recent uploads or accepts an explicit path, then fetches VTT/SRT (and related sidecars) with a completion summary. Auth is the session AWS profile already chosen in Settings — still not a secret stored in the app. Operators get a folder they can hand to Clean Subtitles or to an editor, instead of a half-downloaded prefix they have to inspect in the console.

06
Clean Subtitles
Broadcast and web captions arrive as SCC, SRT, and VTT with overlapping cues, wild speaker tags, and timecodes that drift. Clean Subtitles runs local Python against the files on disk: normalize, de-overlap, strip junk, preview the diff, then apply with an on-disk backup. Preview-first is non-negotiable. Caption QC is legal and accessibility work; a silent rewrite would be worse than leaving the file alone. The Mac can do this without SSH because the files are already local — a deliberate split from the remote S3 tools.

07
Validate CSV
Episode and shorts metadata still travels in spreadsheets. Validate CSV checks required columns, ID formats, titles, and window fields, then writes a cleaned file instead of asking someone to hunt red cells in Excel. Excel format guidance is one click away because the failure mode is almost always “saved as the wrong sheet” or “wrapped the ID in a formula.” The cleaned output is what downstream tools (live review, weekly report) actually consume — so the validator is a gate, not a suggestion.

08
Review Live Episodes
Live slates fail in public. This workspace cross-checks episode IDs against the schedule CSV and the stream-mapping paths configured in Settings: missing files, window mismatches, and IDs that exist in the sheet but not on the server. It does not try to be a scheduler. It is a pre-air gate so the person who will get the Slack ping has already seen the miss. Mapping paths are session configuration, not hardcoded brands, so the same binary can point at whichever streams the desk is running today.

09
Vidaa Monthly Promos
Monthly promo packages are a checklist that used to live in someone’s head: path tokens, ownership, file presence, then a copy. This workspace validates the package first — pass/fail with the reason on the row — and only then stages the copy. The workaround it replaced was a shared doc plus a hope that last month’s folder naming still applied. Tokens and ownership checks are boring on purpose. Promo misses are public.

10
Resize Images
Artwork has a dozen required sizes (banners, keyart, boxart, CTV, hub icons) and a habit of being exported once, wrong. Resize Images runs named presets against the original in place, then shows an outcome strip so you can see which rendition was written. It is local Python, not Photoshop scripting and not a trip through a DAM. The point is repeatability: the same preset list every week, not a designer reconstructing export settings from Slack.

11
Weekly Report
Ops still owes a written week. Weekly Report is a structured composer: paste section updates, preview HTML, and hand a Mail draft to the operator instead of another spreadsheet that nobody formats the same way twice. It is not analytics. It is the human summary that used to take Friday afternoon and a fight with Outlook. Preview is HTML so what you send is what you saw.

12
Settings & auth
Settings is the only place host, user, SSH key path, AWS profile name, and stream-mapping directories are entered. Authenticate once per session. The app stores connection shape (which profile, which key file) — not the AWS secret, not a long-lived token, not a pasted password. Jobs then stream progress as JSON lines over that SSH session. If auth fails, every workspace fails in the same obvious way instead of each script prompting differently. Mapping paths are data: point them at the streams this desk is running; do not fork the app. Demo captures on this site use a placeholder host. Production operators bring their own bastion.

Thirteen first-class workspaces in one native shell.
Preview-first safety on sanitize, subtitles, CSV, and promos.
Auth once — JSON-line progress, no secrets stored in-app.

