Air Check
Inspiration
I've hosted Rhythm Lab Radio on Radio Milwaukee for more than twenty years. Every show should also go up on Mixcloud: two hour-long files joined, a title in the house style, five tags, a description and a tracklist. That work kept slipping, and about 35 shows from 2026 sat unposted. Prepping a show takes time too: I research every track for my notes, and new music arrives as a flood of label emails.
I wanted help, not a bot posting under my name. A station runs on trust with labels and listeners. Can an agent do the busywork while the station keeps control of its data, and can I see that it does?
What it does
Air Check is a private console for one person: me.
- Episodes lists every 2026 show and what's in for it: audio, tracklist, notes. When a show is complete, the agent drafts a Mixcloud package: title, tags, a description in my voice, and the tracklist. I can watch the run live and take over.
- Approval happens only in the signed-in console. My phone gets a Telegram link, never an approve button. When I approve, a separate publisher uploads the show.
- Show notes research every track of a playlist and write private notes shaped like the ones I used to write by hand: album and label, the story, samples and connections, chart history, video. Every fact links its source, and anything single-sourced or unsourced is marked [verify].
- Deep dives turn an artist, label or release into a short Wikipedia-style article: a fact box, sections in prose, numbered references, and how often it's been on my show (counted in code).
- Pre-air verify checks my own notes before I go on air.
- Release radar turns Bandcamp and label emails I forward into records I can play, consider or pass on, including roundup emails that list a dozen releases. An embargoed release blocks Approve on any show containing it until its date.
- Trust shows every network call the agent's sandbox allowed or blocked.
The first real show, 10-2-26, went live on Mixcloud through Air Check on Oct 28.
How we built it
- Model: NVIDIA Nemotron 3 Super (
nvidia/nemotron-3-super-120b-a12b) on Nebius Token Factory. In our test Super returned valid structured output 10 of 10 times, Nano 9 of 10, so we use Super. - Agent: Hermes Agent in an OpenShell sandbox, installed with NVIDIA NemoClaw, restricted policy tier. Unlisted hosts are denied and logged.
- Compute: one Nebius AI Cloud VM runs the console, the agent and small host services: a relay that starts agent runs, an ffmpeg media service, a publisher that alone holds the Mixcloud login, an ingest worker for Box, Google Drive and Dropbox, and a bridge that holds the research keys.
- Research with Tavily: Tavily search runs in the bridge, never inside the agent's sandbox, so the agent holds no search key and code sees every result. When a show-notes job starts, the bridge runs two searches per track in parallel (one about the release, one for interviews, reviews and samples), five at a time with retries, following Tavily's batch guidance. A deep dive gets five searches on its subject. The agent reads the results through a tool and must read them before it may save, and code checks each cited fact against the page text Tavily returned. Advanced depth, page text for fact checks, and a daily cap shown in Settings.
- Also: my existing Crate service (MusicBrainz, Wikipedia, Bandcamp search, iTunes) over MCP, and the Apple Music catalog for release dates and labels. [CHECK: no live Apple Music lookup seen yet; drop this if none happens before you submit.]
- App: Next.js, Tailwind, Convex, Clerk, Docker Compose. 2,582 automated tests run on every pull request.
- Email: an AgentMail inbox with signed webhooks and a sender allowlist.
The safety model, in plain English:
- The agent drafts. Only a signed-in person can approve a publish. There is no path from the agent to the Mixcloud upload, and a test fails if one appears.
- The agent holds no Box, Drive, Dropbox, Mixcloud, Tavily or Apple credentials.
- Email is data, not instructions. Links and addresses are stripped before any model reads an email. Promos are read by one Nemotron call with no tools, and code checks every field against the email. The agent only sees finished records.
- Embargoes are checked in code wherever text can go public. An unreadable date counts as still embargoed.
- Show notes and deep dives are private. Public Mixcloud descriptions stay strict: no unverified claims.
- The sandbox reaches only approved hosts, and Trust shows what it tried.
Judges get their own sandbox with sample data, memory off, publishing off, and their own daily search cap.
Challenges we ran into
- Restarts. After a reboot the sandbox got stuck in an error state no command cleared. The supervisor only ran while someone was logged in, and Docker stopped the container first. We fixed both and added a watchdog that messages me on Telegram.
- Installed isn't used. The agent never opened my description skill (the logs proved it), and the first show went out flat. Now the guide travels with every draft.
- The model skipped the search. Nemotron ignored "search first" and went to narrower sources, and research took about 3 minutes a track. We moved the searches into code: every track's searches run in parallel the moment the job starts, and the agent can't save a track until it has read them. On a live 6-track test (one search per track), the searches took 10.5 seconds and the whole notes job 3½ minutes, down from about 3 minutes a track.
- A search tool the agent could point anywhere. Tavily inside the sandbox could fetch any URL. We rebuilt the sandbox without it and moved search to the bridge, where the agent asks for searches by track, not by URL.
- Bandcamp's bot check. Bandcamp began answering our server's page reads with a "Client Challenge". We decided not to work around it. Instead I attach players and covers with a "Send to Air Check" bookmarklet that reads the Bandcamp page I already have open.
Accomplishments that we're proud of
- A real show went from backlog to Mixcloud with one tap from me, and nothing else could have sent it.
- Show notes that read like my own, with a source on every fact, in minutes instead of an evening.
- The prompt-injection guard lives in code, not in a prompt.
- Judges test a live agent in its own sandbox, with run limits.
What we learned
Check what the agent did, not what it was given. If a step must happen, do it in code and make the agent's next step depend on it. Approve is the real gate.
What's next
- Covers and links from label emails, attached to each release.
- My Bandcamp collection through Bandcamp's official Subsonic service, as metadata only.
- Writing several tracks' notes in parallel.
- Clearing the backlog, at most three uploads a day.
- Create a RAG, knowledgebase from all my notes and playlist prior to 2026 to help plan future shows and theme shows as well.
Most Valuable Feedback
We kept a friction log from day one: 35 dated entries as of Oct 30 (docs/FRICTION_LOG.md in the public repo), each with the error, the workaround and a suggestion. A few: Nemotron 3 spending a small max_tokens budget on reasoning and returning empty content; NemoClaw's gateway stopping after logout on a headless VM; a sandbox Error state with no way back but destroy; leftover gateway records blocking a rebuild; MCP tools silently unwired after a restart.
What existed before the hackathon
The repo started Oct 26, 2026, from planning docs written Oct 19. It calls my existing Crate service over MCP and borrows patterns, not code, from Crate Web, TarikOS and CopilotKit's MIT-licensed OpenMuse. Everything else was written during the hackathon. The repo is public under the MIT license: https://github.com/tmoody1973/air-check
Built With
- agentmail
- apple-music
- box
- clerk
- convex
- docker
- dropbox
- ffmpeg
- google-drive
- hermes-agent
- mcp
- mixcloud
- nebius-ai-cloud
- nebius-token-factory
- nemotron
- next.js
- nvidia-nemoclaw
- openshell
- tailwind
- tavily
- telegram
- typescript
Log in or sign up for Devpost to join the conversation.