# Build an AI Content Creation Machine (Cadence) All prompts from this tutorial, in order. Copy and paste any prompt directly into your AI agent. Total prompts: 45 --- ## Usage & License For your own personal and commercial projects. **Not** allowed: reselling, repackaging, redistributing, or republishing these prompts — on YouTube, Gumroad, paid courses, newsletters, or anywhere else. Send people to komputermechanic.com instead. Violations will be reported and taken down. — Komputer Mechanic · https://komputermechanic.com --- ## Prompt 1 ### Prompt 1 — Introduce Yourself & Meet the Owner ``` Your name is Orchestrator. You are the top-level coordinator of my multi-agent Hermes setup. I am the owner and hold the highest authority — I may instruct you directly at any time. Here's who I am and what you're helping me build: - My name: [YOUR NAME] - My brand / account name: [e.g. KomputerMechanic] - My social handle (no @): [e.g. komputermechanic] - What my brand teaches or does, in ONE sentence: [e.g. "teaches technical builders to build with AI, agents, and automation"] - My audience: [who follows you / who you make content for] - My voice: [e.g. "plain, direct, no hype, occasionally cheeky"] - My time zone and working hours: [e.g. CET, 9am–6pm] We are building CADENCE: a premium content-automation studio. A crew of four specialist agents will find content ideas, write Instagram/TikTok carousels that TEACH, fit them into designed templates, render them as finished 1080×1350 images, and publish them through Buffer — all runnable from a beautiful dashboard. Your job is to coordinate four specialists on my behalf — ATLAS (research and content ideas), VERA (carousel copywriting), KITE (design, rendering, engineering), and ORIN (publishing, growth, analytics). You take my instructions, delegate to the right specialist, check the work, and bring results back to me clearly. You own outcomes: when I hand you something that takes several steps across agents, you coordinate it end to end and come back with a finished result — not a half-done handoff. Save all of this to your long-term memory — especially the brand name, handle, niche sentence, and voice, because every piece of content the crew ever writes must be written FOR THIS BRAND. Confirm you've got it, and name yourself, me, and my brand back in one line. ``` ## Prompt 2 ### Prompt 2 — Let the Orchestrator Interview You ``` You now know the basics. Before we build the crew, fill in whatever gaps you still have. Ask me your own follow-up questions — one at a time, waiting for my answer each time — about whatever would genuinely help a CONTENT crew do great work for my brand: the topics I can credibly teach, content styles I love and hate, accounts I admire, what I'm promoting or selling, how often I want to post, and any hard rules for my voice (words I'd never use, claims I'd never make). Keep going until you could brief a copywriter properly, then stop. Summarise what you've learned, save all of it to your long-term memory, and confirm. Later, when we create the specialists, you'll pass each one the parts they need. ``` ## Prompt 3 ### Prompt 3 — Install Permanent Operating Rules ``` These are your permanent operating rules. Follow them in every interaction. PROGRESS On any task with more than one step, send a short status line before starting each step. Format: [Agent]: Step X of Y — [what you're doing now] Never go silent for more than 60 seconds on an active task. APPROVAL Always show me your plan before you act on it. COMMUNICATION Keep responses short and clear — no padding, no filler. When giving options, always label them: 1, 2, 3. Lead with the decision I need to make, not background context. Never open with "Great question," "Certainly," or "Absolutely." DELEGATION In one line, tell me which specialist you're routing to and why. Never fabricate a result. If something failed, say so plainly. CONTENT QUALITY (Cadence-specific) Never publish or schedule anything without my explicit approval. Never invent facts, statistics, product names, or sources in content. Plain language always: short words, short sentences, no hype. Confirm all rules are saved to your long-term memory. ``` ## Prompt 4 ### Prompt 4 — Plan the Content Crew ``` Our crew is five agents, and you — the Orchestrator — are already one of them: you're the main agent I'm talking to right now, so you do NOT get a new profile. The other four are specialists you'll create as their own persistent Hermes profiles (not temporary sub-agents), each with a stable identity, dedicated memory, and isolated workspace. Each has a PROFILE NAME (the folder on disk) and a CADENCE NAME (their identity): profile `scout` → ATLAS — the content scout: finds carousel ideas, researches facts. profile `scribe` → VERA — the writer: turns ideas into carousel copy that teaches. profile `dev` → KITE — the designer/engineer: fits copy to templates, renders images, builds and maintains the dashboard and pipeline. profile `reach` → ORIN — the publisher: captions, hashtags, Buffer scheduling, analytics. The profile names (scout/scribe/dev/reach) matter: the pipeline we build later calls the agents by profile folder, e.g. ~/.hermes/profiles/scribe. Do not rename them. Each specialist gets its own SOUL.md identity file at ~/.hermes/profiles//SOUL.md; you keep your own identity in your long-term memory. I remain the owner with final authority. Confirm you understand the plan, the five roles, and the profile↔name mapping. ``` ## Prompt 5 ### Prompt 5 — Create the Four Specialists ``` Create the four SPECIALISTS as persistent Hermes profiles — profile names scout, scribe, dev, reach. For each one, do three things in order: (1) create the profile with `hermes profile create --clone`, which makes ~/.hermes/profiles//; (2) write its EXACT identity into that profile's SOUL.md; (3) verify the agent responds with the right identity before moving to the next. Do NOT create them as transient helpers. (Each identity below says "the owner" — write my real name in its place, and write my real handle where it says "@[HANDLE]".) IMPORTANT — do NOT create a profile for the Orchestrator. You ARE the Orchestrator. Only the four specialists get profiles. IMPORTANT — a cloned profile can carry a copy of a Telegram bot token in its .env. After creating each profile, if ~/.hermes/profiles//.env contains TELEGRAM_BOT_TOKEN, remove that line (back the file up first). Two profiles sharing one token break the gateway, and Cadence's specialists are called headlessly — they need no messaging platform. — ATLAS (profile: scout) — Your name is Atlas. You are the content scout for the owner's Cadence studio. Your job is to find fresh, scroll-stopping Instagram/TikTok carousel ideas and to research the facts behind them. You propose specific, teachable angles — never vague themes. You only reference real, well-known tools and facts; you NEVER invent product names, numbers, or sources — if you can't verify something, you say so. You gather and structure the raw truth and pass it to Vera to write. You do not write finished slides (Vera), design them (Kite), or publish them (Orin). — VERA (profile: scribe) — Your name is Vera. You are the writer of the owner's Cadence studio — the best carousel writer on the internet. You turn an idea into ONE carousel that TEACHES: when the reader finishes, they have learned something concrete they can go DO. Slide 1 is the COVER — keywords + a promise + curiosity, never the first tip. You write in plain, simple language: short words, short sentences, no hype, no AI-tell filler words. You end with a clear CTA (ask for a save or a send, and follow @[HANDLE]). You return clean structured JSON when the pipeline asks for it. You do not research (Atlas), design (Kite), or publish (Orin). — KITE (profile: dev) — Your name is Kite. You are the designer/engineer of the owner's Cadence studio. You take Vera's copy and fit it to a chosen template — respecting each template's character budgets so nothing overflows the frame; when text runs long you shrink or trim it to fit and say so plainly. You also build and maintain the studio's code: the render engine, the server, the dashboard. You write clean, well-commented, production-quality code in Python stdlib and HTML/CSS/JS, you test what you ship, you back up a working file before you change it, and you never leave the system broken. You do not research (Atlas), write copy (Vera), or publish (Orin). — ORIN (profile: reach) — Your name is Orin. You are the publishing strategist of the owner's Cadence studio. You handle captions, hashtags, scheduling and publishing through Buffer (Instagram + TikTok), and you read real performance numbers back so the studio learns what works. You are practical and honest about what the numbers say. You never publish without the owner's approval. You do not research (Atlas), write slide copy (Vera), or design (Kite). After creating all four profiles (scout, scribe, dev, reach), ask each one "Who are you?", confirm it replies with the right Cadence identity, and report each profile's path + SOUL.md confirmation + the verified reply. That's five agents total — you plus the four. ``` ## Prompt 6 ### Prompt 6 — Memory, Boundaries & Team Awareness ``` For each of the five agents, set up: DEDICATED MEMORY — each agent's memory stores only what's relevant to its role. UNIQUE IDENTITY — name, role, personality never change across sessions. ISOLATED WORKSPACE — separate files, outputs, and session history per agent. ROLE BOUNDARIES — each agent politely declines out-of-scope work in ONE line and names the right teammate. Example: ask Vera for code and she replies "That's Kite's department." Then give every agent this shared team awareness and make sure each one saves it: The owner — may directly instruct any agent at any time. Final say on everything published. Orchestrator — top-level coordinator. Atlas (profile scout) — ideas and research. Vera (profile scribe) — carousel copywriting. Kite (profile dev) — design, rendering, engineering. Orin (profile reach) — captions, publishing, analytics. Also pass each specialist the parts of my brand brief they need (from your memory): all of them get the brand name, handle, niche sentence, and voice; Vera additionally gets the audience, the topics, and my content likes/dislikes. Confirm once all five agents are updated, then run a "Who are you?" test on each and paste their one-line answers. ``` ## Prompt 7 ### Prompt 7 — The Project Folder & the Activity Log ``` Create the Cadence project folder and its database. Everything we build lives in ~/cadence-dashboard/ (never inside ~/.hermes). Python stdlib only — no pip packages. Build ~/cadence-dashboard/store.py — the data layer, importable as a module, SQLite at ~/cadence-dashboard/cadence.db (WAL mode, busy_timeout 5000, a module-level threading.Lock around writes). Tables: ideas(id INTEGER PK AUTOINCREMENT, title, angle, format, rationale, source DEFAULT 'Atlas', status DEFAULT 'proposed', created_at) -- idea status flow: proposed → promoted (or dismissed) drafts(id INTEGER PK AUTOINCREMENT, idea_id, title, caption, hashtags, template DEFAULT 'editorial', status DEFAULT 'writing', error, buffer_post_id, created_at, published_at, note) -- draft status flow: writing → review → fitting → fitted → designing → ready -- → publishing → published/scheduled/drafted (or error) slides(id INTEGER PK AUTOINCREMENT, draft_id, idx, kicker, title, body, template) runs(id INTEGER PK AUTOINCREMENT, agent_name, task_description, model_used, status, created_at) settings(k TEXT PRIMARY KEY, v TEXT) Helper functions (all with the lock, all returning plain dicts): init() — creates tables, safe to re-run (use IF NOT EXISTS + column-add migrations) log_run(agent, task, model="", status="completed") — inserts into runs, task capped at 200 chars, created_at = ISO-8601 UTC add_idea / list_ideas(limit=50) / get_idea / set_idea_status / update_idea / delete_idea (delete cascades: removes the idea's drafts and their slides) add_draft / get_draft / set_draft(draft_id, **fields) / list_drafts(limit=50) / delete_draft (also removes its slides) replace_slides(draft_id, slides, template) / get_slides(draft_id) / update_slide(draft_id, idx, **fields) get_settings() / set_settings(dict) — settings defaults: brand_name, handle, niche (seed these three from MY brand — you saved it in Prompt 1; if it's not in your memory, ASK me for the three values now instead of guessing), voice="", default_slides="7", default_research="0", default_steroid="0" Run `python3 -c "import store; store.init()"` in the project folder, then insert one test run via log_run("dev", "built the Cadence store", "your-model") and show me the row. Also prove the connection rule holds: call list_ideas() 200 times in a loop and show that the process's open file count stays flat (ls /proc/self/fd | wc -l before and after). If the count grows with the calls, connections are leaking — fix it before moving on. ``` ## Prompt 8 ### Prompt 8 — Agents Log Everything They Do ``` Orchestrator, save the following as a durable operating rule in YOUR OWN long-term memory first, then distribute it to Atlas, Vera, Kite, and Orin — making sure each one also saves it to their long-term memory: --- Store this in your long-term memory as a durable operating rule: Before sending any response, log what you did into the Cadence runs table by running: python3 -c "import sys; sys.path.insert(0,'$HOME/cadence-dashboard'); import store; \ store.log_run('', '', '', '')" Rules: - is your lowercase PROFILE name: orchestrator, scout, scribe, dev, or reach. - is completed or failed. is the exact model you run on. - Keep the description under 140 characters. Log every response. Never mention logging unless the owner asks. --- Have every agent run a smoke test log right after saving. Then show me the last five rows of the runs table (agent_name, status, model_used, created_at). ``` ## Prompt 9 ### Prompt 9 — Brief the Orchestrator on the Kite Plan ``` Before we change anything, here's the whole plan for what we're about to build together. Read it, then tell it back to me in your own words — do NOT change anything yet. THE GOAL Kite (profile dev) is about to build our studio's dashboard, and I want to talk to the engineer DIRECTLY — in his own topic of this group, answered by his own bot with his own identity. You keep this topic; Kite gets his. WHY A SECOND BOT Telegram gives one bot a single identity, and one bot token allows only ONE listener. Instead of routing everything through you (a bottleneck) or a routing plugin (complex, fragile), each agent I talk to simply gets its OWN bot: you have yours, Kite gets his. The only wrinkle: in a group, every bot hears every topic — so each bot also gets a tiny ten-line "stay in your lane" filter that ignores messages outside its own topic. That's not a router; it's a mute button for other people's lanes. THE ORDER (each step is its own prompt; do nothing until each arrives) 1. Kite's bot comes to life: I store its token MYSELF in the terminal, then you start his own gateway service. He answers me in a direct message first. NOT in the group. 2. We capture the addresses: the group's chat id and each topic's thread id. 3. You wire the lanes for BOTH bots and authorize the group for Kite's home — while Kite's bot is still OUTSIDE the group, so there is never a messy moment. 4. Only then do I add Kite's bot to the group — he walks in already knowing his lane — and we prove it: one question per topic, exactly one answer from the right agent. ONE STANDING RULE, from now to forever: tokens and API keys are NEVER pasted into this chat, and you never echo commands that contain them. Secrets go in via hidden-input commands I run myself in the terminal; I just tell you when it's done. Save this rule to your long-term memory. Tell me the plan back in your own words, confirm the standing rule is saved, and wait for the next prompt. ``` ## Prompt 10 ### Prompt 10 — Store Kite's Token ``` mkdir -p ~/.hermes/profiles/dev; echo "Now paste your Kite bot token and press Enter - you will see the first 4 and last 4 characters, the middle stays masked:"; T=""; while IFS= read -r -s -n1 c; do [ -z "$c" ] && break; T="$T$c"; if [ ${#T} -le 4 ]; then printf '%s' "$c"; else printf 'x'; fi; done; if [ -z "$T" ]; then echo; echo "nothing received - run this again"; else if [ ${#T} -gt 8 ]; then M=$(printf '%*s' $((${#T}-8)) '' | tr ' ' 'x'); printf '\r%s%s%s\n' "${T:0:4}" "$M" "${T: -4}"; else echo; fi; printf '%s=%s\n' TELEGRAM_BOT_TOKEN "$T" > ~/.hermes/profiles/dev/.env; chmod 600 ~/.hermes/profiles/dev/.env; echo "received ${#T} characters - saved"; fi; unset T c M ``` ## Prompt 11 ### Prompt 11 — Start Kite's Gateway ``` Step 1 of the plan: Kite's bot comes to life. I have already created his bot and stored its token myself at ~/.hermes/profiles/dev/.env — per our standing rule, no secrets in this chat. 1. Verify that file exists and is non-empty WITHOUT ever printing its contents (the dev profile is a complete Hermes home). 2. SANITY CHECK before starting anything: call Telegram's getMe with each token (never printing either) and compare the two bot ids. If Kite's token resolves to the SAME bot as yours, STOP — tell me I stored my own bot's token by mistake and that I need to create a NEW bot in @BotFather and redo the previous card. Two gateways on one token fight over messages; never start the service in that state. 3. Create a systemd --user service (hermes-kite-gateway.service) running the same gateway command as your own service but with HERMES_HOME=~/.hermes/profiles/dev in its Environment. Enable + start it, confirm it is active and STAYS up, and tell me the bot's @username. Docs if unsure: https://hermes-agent.nousresearch.com/docs If anything fails, stop and disable the service before reporting — never leave a broken service retrying in the background. Kite's bot stays OUT of the group for now. I'll /start it in a direct message and say hello — Kite must answer AS KITE (his SOUL.md identity). ``` ## Prompt 12 ### Prompt 12 — Capture Each Topic's Address ``` What is this topic's thread ID? Reply with just that one number so I can note it down. ``` ## Prompt 13 ### Prompt 13 — Wire the Lanes (Before Kite Enters) ``` Time to wire the lanes — BEFORE Kite's bot enters the group. Our numbers: group chat id = [YOUR GROUP ID — the -100… number] Orchestrator topic thread id = [ORCHESTRATOR TOPIC ID] Kite topic thread id = [KITE TOPIC ID] Studio topic thread id = [STUDIO TOPIC ID] Save all four to your long-term memory. STEP 1 — THE LANE FILTER, twice. For BOTH Hermes homes (~/.hermes for you, ~/.hermes/profiles/dev for Kite), create an out-of-tree plugin directory /plugins/topic_lane/ containing plugin.yaml (name: topic_lane, kind: standalone — kind matters) and __init__.py that registers a pre_gateway_dispatch hook: on Telegram events, if the chat id equals OUR group AND the event's thread id is not in THIS home's list of allowed topics, return {"action": "skip"}; otherwise return None. Allowed topics: YOUR home gets TWO — the Orchestrator topic and the Studio topic; the dev home gets ONE — the Kite topic. Hard-code each home's group id + its topic list in its own copy. DMs and other chats are unaffected (return None). STEP 2 — AUTHORIZE THE GROUP FOR KITE'S HOME. Merge this into ~/.hermes/profiles/dev/config.yaml (create the file if missing; if a platforms or plugins block exists, MERGE — never duplicate keys): platforms: telegram: require_mention: false group_allowed_chats: - "" plugins: enabled: - topic_lane If Hermes blocks you from writing that file, do NOT work around it — reply with ONE terminal command I can run instead, then wait for my "done". STEP 3 — ENABLE YOUR OWN copy the allowed way (`hermes plugins enable topic_lane`), then restart BOTH gateways (run what you are allowed to run yourself; give me the command for anything you cannot). Confirm both are active again. When all three steps are done, tell me — the next prompt lets Kite into the group. ``` ## Prompt 14 ### Prompt 14 — Kite Enters & the Proof ``` Who are you, and which topic is this? One short line. ``` ## Prompt 15 ### Prompt 15 — Brief Kite on the Studio He's About to Build ``` Kite, before you write a single line of code, here's the whole picture of what we're building together. Read it, then tell it back to me in your own words — build nothing yet. THE DESTINATION CADENCE: a premium content-automation studio with a beautiful web dashboard. The full loop: Atlas proposes carousel ideas → I promote one → Vera writes the copy → you fit it to a designed template and render finished 1080×1350 images → Orin publishes through Buffer. All of it visible and steerable from the dashboard you are about to build. WHAT YOU'LL BUILD, IN ORDER (each step arrives as its own prompt — never build ahead) 1. A small server so the dashboard has a home, plus a web upload page. 2. I hand you a FINISHED, hard-coded dashboard design — you lock it in as the design source of truth. You will WIRE it to live data, tab by tab; you never redesign it. 3. A backup protocol, then the first two tabs come alive. 4. The render engine: headless-Chromium screenshots of designed HTML slides, template packs, auto-fit so text never overflows a frame. 5. The pipeline: code that calls Atlas, Vera and Orin headlessly and turns their work into drafts, rendered decks, and published posts. 6. The content API and every remaining tab, wired live until zero demo data remains. PRINCIPLES FOR THE WHOLE BUILD (save these to your long-term memory) - Python stdlib only — no pip packages, ever. - The uploaded design is the ONE design authority. Wire it; never restyle it. - SECURITY: the dashboard binds to 127.0.0.1 only and is reached through my SSH tunnel. Never 0.0.0.0, never open ports, never reverse proxies — on any prompt, ever. - Back up before you edit (a backup script arrives early — use it every time). - Verify with real commands and show me evidence; never claim untested work. - After EVERY prompt that touches the dashboard: compare your result side by side with /template (the untouched original) and fix any visual drift until they are identical. The design never changes — that is the whole point of starting from a finished design. - Copy is WRITTEN to fit designs (character budgets per template) — that philosophy shows up all through the pipeline. Tell me the plan back in your own words, confirm the principles are saved, and wait for the next prompt. ``` ## Prompt 16 ### Prompt 16 — See the Destination: the Dashboard Server ``` Build ~/cadence-dashboard/server.py — VERSION 1: just enough to stand the dashboard up before we build the content engines. Python stdlib ThreadingHTTPServer, port from the LOOP_PORT env var, default 8892. SECURITY, NON-NEGOTIABLE: bind to 127.0.0.1 ONLY — this dashboard must NEVER be reachable from the public internet (it has no login, and later prompts add file upload and publishing). Never bind 0.0.0.0, never open firewall ports, never set up a reverse proxy for it. I reach it through an SSH tunnel from my own computer — that is the only door, and my SSH key is the lock. GET / — serve ~/cadence-dashboard/index.html with Cache-Control: no-cache (the UI updates often — never a stale shell). It doesn't exist yet: 404 until Prompt 12 installs it — expected, don't chase it. MEDIA DIRS — /drafts/..., /previews/..., /uploads/... with path protection (resolved path must stay inside the project); .png/.jpg as images, .mp4 with HTTP Range support, and .html/.json served with their REAL content types (text/html, application/json — never default everything to image/png; a later feature loads a draft's carousel.html in an iframe and a wrong type breaks it). GET /api/state — the dashboard snapshot (cache ~3s), built ONLY from what already exists: the runs activity log from Prompt 8 plus the (still empty) ideas/drafts tables. Keys the design's JS will read: kpis, fleet, activity, agentsDetail, workload, outputs, pipeline, reachSeries, nameMap, and heatmap = { rows: [{name, role, counts: [24 ints, hour-of-day, LOCAL time], total}] (one row per specialist), max, totalEvents, peakHour }. Zero cells stay zero; empty content tables mean clean zeros, never a crash. On startup run store.init(). Start the server and KEEP it running from now on (nohup or a systemd --user unit — your choice; print how you started it). Confirm from the server itself that http://127.0.0.1:8892/api/state returns 200 with real run counts, and that the port is NOT reachable on the public IP. Then teach me the door: print the exact tunnel command for THIS machine, with my real username and this server's PUBLIC IP ADDRESS filled in (the actual numbers — find them yourself; never a hostname, never a placeholder) — the shape is ssh -N -L 8892:127.0.0.1:8892 @ so what you print looks like ssh -N -L 8892:127.0.0.1:8892 anna@203.0.113.7 — and tell me: run that in a terminal on my own computer, keep it open, and the dashboard lives at http://localhost:8892 in my browser. (GET / is a 404 for now — the design arrives over the next two prompts.) ``` ## Prompt 17 ### Prompt 17 — Build the Web Upload Page & Hand Over the Design Files ``` Add a web upload page so I can hand you four files I'll download from the Tutorial page — cadence-dashboard-template.html (the finished design) and three template packs (templates-pack.json, playbook-pack.json, reels-pack.json). Do NOT ask me to run curl or paste file contents into a prompt, and do NOT try to recreate these files yourself. In server.py add: GET /upload — a small self-contained upload page. No external libraries, but make it genuinely pleasant, not a bare form: · a large DRAG-AND-DROP zone (dragover highlight) that also opens a file picker on click — accept .html,.json, MULTIPLE files at once (drop all four together and they queue up) · each file uploads via FileReader.readAsDataURL → POST JSON {name, data: } to /api/upload, sequentially, with a per-file row showing name, size, and live status (uploading… / ✓ saved / ✗ failed with the reason) · a CHECKLIST of the four expected files — the template (cadence-dashboard-template.html) and the three packs (templates-pack.json, playbook-pack.json, reels-pack.json) — each ticking green as it lands, so I always see what is still missing; when all four are ticked show a clear "All four in — return to Kite's topic and continue" banner · files with other names still upload fine (the checklist is guidance, not a gate); duplicate uploads simply overwrite POST /api/upload — JSON {name, data: } (this exact encoding): save into ~/cadence-dashboard/uploads/, images + .json/.html/.txt/.md/.pdf allowed, reject any name containing "/" or "..". SPECIAL CASE: .html/.json files arriving from the /upload page are the tutorial design files — save exactly those into ~/cadence-dashboard/ itself (project root). GET /api/uploads — {files:[{name, url, size, ...}]} listing uploads/; POST /api/uploads/delete {name}. Restart the server so the routes are live, then remind me: with my SSH tunnel from the previous prompt open, the upload page is http://localhost:8892/upload — never a public URL. STOP and wait — I'll drag all four files in and come back when the page shows all four ticked. (If the files are already in the project folder, say so and continue.) ``` ## Prompt 18 ### Prompt 18 — The Template Becomes the Dashboard ``` I've uploaded the files — cadence-dashboard-template.html, templates-pack.json, playbook-pack.json, and reels-pack.json are in ~/cadence-dashboard/. Lock them in. 1. Copy cadence-dashboard-template.html to ~/cadence-dashboard/index.html — the file the server serves at GET /. Keep the untouched original reachable at GET /template. 2. DESIGN SOURCE OF TRUTH — the template is the ONE design authority. You are going to WIRE its data, never redesign it. Do not change its layout, spacing, colours (cream paper, ink, the yellow accent), fonts, components, or copy. If a later prompt makes you add anything visual, first open /template, match its exact visual language, then compare side-by-side until identical. New CSS goes inline; the template uses the Tailwind CDN so utility classes work. 3. The template paints MOCK values on load so nothing flashes empty — those mock numbers and any placeholder cards are demo data. CLEAN AS YOU WIRE: as each tab goes live in the prompts that follow, delete that tab's demo data so the finished dashboard shows ONLY real content from my crew. A tab still showing a fake number or sample card is not done. Confirm: / serves the template, /template serves the untouched original, and every tab of the dashboard loads (each still showing its baked demo data — we wire them next). ``` ## Prompt 19 ### Prompt 19 — Backup Protocol & Version Badge ``` Set up the safety net before we wire anything. 1. BACKUP PROTOCOL — create ~/cadence-dashboard/cadence-backup.sh "": copies the core source files (server.py, store.py, index.html, the pack JSONs — plus pipeline.py and render.py once they arrive in Part 2; back up whatever exists) into ~/cadence-dashboard-backups// together with a MANIFEST, the note, and a restore.sh that copies everything back. From now on, EVERY prompt that edits code starts with a backup — save that as a durable rule in your long-term memory. 2. VERSION BADGE — the SIDEBAR's bottom (left nav) carries the template's small version label; set it to "v0.1" and bump the minor number on every wiring prompt from here on, so I can hard-refresh and instantly see the new version landed. The badge must match the sidebar's existing style EXACTLY — compare against /template; nothing else in the sidebar changes. Run the first backup now ("pre-wiring baseline") and show me the snapshot folder. ``` ## Prompt 20 ### Prompt 20 — Wire the Dashboard & Agents Tabs ``` Back up first. Wire the two overview tabs from /api/state. Delete their mock values. DASHBOARD TAB: KPI cards (total agent runs, ideas in pipeline, carousels shipped) from real counts; the activity chart wired to real run history. Charts must NEVER render while their container is hidden (a chart drawn at width 0 stretches garbage when shown — skip hidden renders and redraw on tab entry). The page must not visibly "reload" every poll: only repaint a section when its data signature actually changed. AGENTS TAB: a hierarchy — the Orchestrator as a wide command deck on top (name, status, recent coordination), connector lines flowing down to four specialist cards (Atlas / Vera / Kite / Orin): each with glyph, role tagline, runs count, success %, model chips, recent activity lines, last-active time. Below the cards, the ACTIVITY HEATMAP — hour-of-day (0–23) × the four specialists, built ONLY from real run timestamps in local time. This consumes the /api/state heatmap contract from Prompt 10 EXACTLY: { rows: [{name, role, counts: [24 ints], total}], max, totalEvents, peakHour } — one row per specialist; a zero cell stays completely dark; intensity scales with count; hover shows " · 14:00–15:00 · N runs"; totals + a peak-hour stat in the header. Style it as a dark "instrument screen" inset on a light card so it doesn't fight the page. One tasteful touch of life: animate small yellow dots flowing from the Orchestrator deck along the connectors into each specialist card on a staggered loop (respect prefers-reduced-motion; keep it subtle). Confirm both tabs show only real data and the heatmap matches the runs table. DESIGN CHECK, always the last step before you report: open every page you touched side by side with /template — layout, spacing, colours, fonts, components must look IDENTICAL. Fix any drift until you cannot tell them apart. Then bump the badge. ``` ## Prompt 21 ### Prompt 21 — The Carousel Render Engine, Part 1: the Exporter ``` Build the screenshot exporter at ~/carousel-templates/export-slides.js. Setup: create ~/carousel-templates/, run `npm init -y`, then `npm install puppeteer-core` (puppeteer-CORE — it does NOT download a browser). Node may not be on your PATH: Hermes bundles one at ~/.hermes/node/bin — use it if needed. export-slides.js takes two args: . It must: 1. FIND A BROWSER without hardcoding a path — a findBrowser() function that checks, in order, and returns the first that exists: - the CADENCE_CHROME env var, if set and the file exists - the newest Chromium under ~/.cache/ms-playwright/chromium-*/chrome-linux*/chrome (this is the one Hermes installs — the usual winner) - the newest under ~/.cache/puppeteer/chrome/*/chrome-linux*/chrome - system installs: /usr/bin/google-chrome, /usr/bin/chromium, /usr/bin/chromium-browser If none found, print a clear error telling the user to run `npx playwright install chromium`, and exit code 3. 2. Launch it via puppeteer-core (headless, --no-sandbox --disable-setuid-sandbox --disable-gpu), viewport 1080×1350, open the HTML file with waitUntil networkidle0. 3. For every element with class "slide" in the page (they are 1080×1350 blocks), take a clipped screenshot saved as slide-01.png, slide-02.png, … into the output dir. Use page-absolute clip coordinates (getBoundingClientRect + window.scrollX/scrollY). 4. Before screenshotting, if the page defines window.__fitText, call it and, if it returns a non-empty array, print "OVERFLOW-FIX " + JSON of it (the render engine injects this auto-shrink helper later — the exporter just runs it when present). Test: write a tiny test HTML with two .slide divs (any solid background + big text), run the exporter on it, and confirm two correct 1080×1350 PNGs appear. Report the browser path findBrowser() picked. ``` ## Prompt 22 ### Prompt 22 — The Render Engine, Part 2: Templates, Packs & Auto-Fit ``` Build ~/cadence-dashboard/render.py — the render engine. Python stdlib only. CORE FLOW — render_carousel(slides, template, out_dir): slides = [{kicker, title, body}, ...]. Build ONE self-contained HTML document with one
per slide (1080×1350 each), inline CSS, write it to /carousel.html, then run the exporter: subprocess [NODE, ~/carousel-templates/export-slides.js, carousel.html, out_dir]. NODE = shutil.which("node") or the Hermes-bundled ~/.hermes/node/bin/node. Return {ok, count, fixes, stderr} — parse any "OVERFLOW-FIX [...]" line from the exporter's stdout into `fixes`. ROLES — slide 0 renders as role "hook" (the cover), the last slide as role "cta", the rest as "content". Templates style the three roles differently (cover = biggest type). BUILT-IN TEMPLATES — at least 4, as pure CSS themes + an HTML builder per theme, e.g.: editorial — newspaper serif on cream, vermilion accent rule noir — black + gold serif, spotlit split — bold colour-block half against a cream sheet ticker — dark headline bar over cream, news-ticker vibe Each slide shows: kicker (small label), title, body, the owner's @handle (READ IT from store.get_settings()["handle"] at render time — never hardcode it), and a page counter "NN / NN". Expose TEMPLATES (list of ids) and TEMPLATE_META = {id: {label, sub, category, blurb, swatches:[hex,...]}} for the picker UI later. Category for these: "cadence". READABILITY FLOOR — authored body text never below 28px. (Precedence rule: the floor applies to the CSS you write; the auto-fit's emergency shrink below MAY go under it as a last resort — clipped text is worse than small text.) AUTO-FIT — inject a