Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/apps/build.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { build, context } from "esbuild";
const watch = process.argv.includes("--watch");
const options = {
entryPoints: { home: "src/home.js", bank: "src/bank.js", chat: "src/chat.js", adgen: "src/adgen.js", imagegen: "src/imagegen.js", persona: "src/persona.js", cartridge: "src/cartridge.js", adpulse: "src/adpulse.js", adforge: "src/adforge.js", shelf: "src/shelf.js", studio: "src/studio.js", aplus: "src/aplus.js", natal: "src/natal.js", arcana: "src/arcana.js", redline: "src/redline.js", batch: "src/batch.js", take: "src/take.js", identity: "src/identity.js", reel: "src/reel.js", marquee: "src/marquee.js", huddle: "src/huddle.js", deck: "src/deck.js", dub: "src/dub.js", crest: "src/crest.js", arcade: "src/arcade.js", yearbook: "src/yearbook.js", toon: "src/toon.js", storybook: "src/storybook.js", anthem: "src/anthem.js", roast: "src/roast.js", emote: "src/emote.js", gist: "src/gist.js", rephrase: "src/rephrase.js", explainthis: "src/explainthis.js", translate: "src/translate.js", polish: "src/polish.js", extract: "src/extract.js", reply: "src/reply.js", unjargon: "src/unjargon.js", nameit: "src/nameit.js", actions: "src/actions.js", snap: "src/snap.js", recap: "src/recap.js", meetnotes: "src/meetnotes.js", inkling: "src/inkling.js", petrait: "src/petrait.js", rizz: "src/rizz.js", dreamlog: "src/dreamlog.js", roomify: "src/roomify.js", thumbs: "src/thumbs.js", meme: "src/meme.js", echo: "src/echo.js", regex: "src/regex.js", errslate: "src/errslate.js", commit: "src/commit.js", docstring: "src/docstring.js", shell: "src/shell.js", cron: "src/cron.js", steps: "src/steps.js", compare: "src/compare.js", formula: "src/formula.js", spellout: "src/spellout.js", clipfix: "src/clipfix.js", convert: "src/convert.js", pdftools: "src/pdftools.js", emboss: "src/emboss.js", qr: "src/qr.js", palette: "src/palette.js", canvas: "src/canvas.js", cut: "src/cut.js", hooks: "src/hooks.js", repurpose: "src/repurpose.js", caption: "src/caption.js", titles: "src/titles.js", outline: "src/outline.js", standup: "src/standup.js", objection: "src/objection.js", coldemail: "src/coldemail.js", resize: "src/resize.js", ideabrain: "src/ideabrain.js", ideafetch: "src/ideafetch.js", reachout: "src/reachout.js", os: "src/os/os.js" },
entryPoints: { home: "src/home.js", bank: "src/bank.js", chat: "src/chat.js", adgen: "src/adgen.js", imagegen: "src/imagegen.js", persona: "src/persona.js", cartridge: "src/cartridge.js", adpulse: "src/adpulse.js", adforge: "src/adforge.js", shelf: "src/shelf.js", studio: "src/studio.js", aplus: "src/aplus.js", natal: "src/natal.js", arcana: "src/arcana.js", redline: "src/redline.js", batch: "src/batch.js", take: "src/take.js", identity: "src/identity.js", reel: "src/reel.js", marquee: "src/marquee.js", huddle: "src/huddle.js", deck: "src/deck.js", dub: "src/dub.js", crest: "src/crest.js", arcade: "src/arcade.js", yearbook: "src/yearbook.js", toon: "src/toon.js", storybook: "src/storybook.js", anthem: "src/anthem.js", roast: "src/roast.js", emote: "src/emote.js", gist: "src/gist.js", rephrase: "src/rephrase.js", explainthis: "src/explainthis.js", translate: "src/translate.js", polish: "src/polish.js", extract: "src/extract.js", reply: "src/reply.js", unjargon: "src/unjargon.js", nameit: "src/nameit.js", actions: "src/actions.js", snap: "src/snap.js", recap: "src/recap.js", meetnotes: "src/meetnotes.js", inkling: "src/inkling.js", petrait: "src/petrait.js", rizz: "src/rizz.js", dreamlog: "src/dreamlog.js", roomify: "src/roomify.js", thumbs: "src/thumbs.js", meme: "src/meme.js", echo: "src/echo.js", regex: "src/regex.js", errslate: "src/errslate.js", commit: "src/commit.js", docstring: "src/docstring.js", shell: "src/shell.js", cron: "src/cron.js", steps: "src/steps.js", compare: "src/compare.js", formula: "src/formula.js", spellout: "src/spellout.js", clipfix: "src/clipfix.js", convert: "src/convert.js", pdftools: "src/pdftools.js", emboss: "src/emboss.js", qr: "src/qr.js", palette: "src/palette.js", canvas: "src/canvas.js", cut: "src/cut.js", hooks: "src/hooks.js", repurpose: "src/repurpose.js", caption: "src/caption.js", titles: "src/titles.js", outline: "src/outline.js", standup: "src/standup.js", objection: "src/objection.js", coldemail: "src/coldemail.js", resize: "src/resize.js", ideabrain: "src/ideabrain.js", ideafetch: "src/ideafetch.js", reachout: "src/reachout.js", draft: "src/draft.js", os: "src/os/os.js" },
bundle: true, format: "esm", target: "chrome111", outdir: "dist", sourcemap: true, logLevel: "info",
};
if (watch) { const ctx = await context(options); await ctx.watch(); console.error("[apps] watching…"); }
Expand Down
126 changes: 126 additions & 0 deletions examples/apps/draft.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Draft — social posts on your Claude, steered piece by piece</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,600;12..96,700&family=Hanken+Grotesk:wght@400;500;600&family=Spline+Sans+Mono:wght@400;500&display=swap" rel="stylesheet" />
<style>
/* HOUSE "Atlas cockpit" system (brandbrain tokens): near-black surfaces, panel cards on
hairline edges, ONE lime accent, Bricolage display / Hanken body / Spline mono for numbers
and kickers. Sentence case. App-specific CSS at the END of this block only. */
:root {
--page: #0A0C10; --inset: #070809; --panel: #12151C; --raised: #1A1F29;
--edge: #262C38; --edge-soft: #1C212B;
--ink: #E8EDF4; --ink-sec: #B4BECE; --ink-dim: #99A3B7; --ink-faint: #6E7C90;
--accent: #C8F250; --accent-soft: #232B0D;
--ok: #3DD68C; --warn: #F59E0B; --danger: #FF2D6E; --blue: #7DE0FF;
--display: "Bricolage Grotesque", ui-sans-serif, system-ui, sans-serif;
--sans: "Hanken Grotesk", ui-sans-serif, system-ui, sans-serif;
--mono: "Spline Sans Mono", ui-monospace, monospace;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { margin: 0; min-height: 100%; }
body { background: var(--page); color: var(--ink); font: 14px/1.6 var(--sans); -webkit-font-smoothing: antialiased; }
::selection { background: rgba(200, 242, 80, 0.3); }
button { font-family: inherit; }
.kicker { font: 500 10px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-dim); }

header { display: flex; align-items: center; gap: 14px; padding: 13px 20px; border-bottom: 1px solid var(--edge-soft); }
.word { font: 700 20px/1 var(--display); letter-spacing: -0.02em; display: flex; align-items: center; gap: 9px; }
.word em { font-style: normal; color: var(--accent); }
.word .mk { width: 22px; height: 22px; border-radius: 6px; background: var(--accent); box-shadow: 0 0 14px rgba(200,242,80,.4); }
#chip-dock { margin-left: auto; }

main { max-width: 760px; margin: 0 auto; padding: 40px 20px 90px; }
.hero h1 { font: 700 clamp(1.7rem, 4vw, 2.5rem)/1.05 var(--display); letter-spacing: -0.02em; margin: 0 0 10px; }
.hero h1 em { font-style: normal; color: var(--accent); }
.hero p { color: var(--ink-sec); margin: 0 0 26px; font-size: 14.5px; max-width: 560px; }

.steps-card { margin-top: 8px; }
.steps { font: 400 12.5px/1.9 var(--mono); color: var(--ink-faint); }
.steps b { color: var(--accent); font-weight: 500; }

.start .ctx { font: 500 11.5px/1 var(--mono); color: var(--accent); margin-bottom: 10px; }
.bindrow { display: flex; gap: 8px; }
.bindrow textarea { flex: 1; min-width: 0; background: var(--inset); border: 1px solid var(--edge); border-radius: 10px; color: var(--ink); font: 400 13px/1.5 var(--mono); padding: 12px 13px; outline: none; resize: vertical; }
.bindrow textarea:focus { border-color: color-mix(in srgb, var(--accent) 55%, var(--edge)); }
.primary { font: 600 13.5px/1 var(--sans); border-radius: 10px; padding: 12px 18px; cursor: pointer; border: 1px solid var(--accent); background: var(--accent); color: var(--page); transition: filter .15s, opacity .15s; }
.primary:hover { filter: brightness(1.08); }
.primary:disabled { opacity: .5; cursor: default; }

.runbar { display: flex; align-items: center; gap: 10px; padding-bottom: 12px; border-bottom: 1px solid var(--edge-soft); flex-wrap: wrap; }
.runbar .grow { flex: 1; }
.run-input { font: 400 12.5px/1.4 var(--sans); color: var(--ink-sec); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 340px; }
.act { font: 500 11.5px/1 var(--mono); background: var(--inset); border: 1px solid var(--edge); border-radius: 999px; color: var(--ink-sec); padding: 7px 11px; cursor: pointer; transition: border-color .15s, color .15s; }
.act:hover { border-color: var(--accent); color: var(--ink); }
.act:disabled { opacity: .45; cursor: default; }
.act.tiny { padding: 5px 9px; font-size: 10.5px; }

.researching { display: flex; align-items: center; gap: 8px; margin-top: 14px; font: 500 11.5px/1.4 var(--mono); color: var(--ink-dim); }
.scan { position: relative; width: 26px; height: 6px; border-radius: 3px; background: var(--inset); overflow: hidden; }
.scan::after { content: ""; position: absolute; inset: 0; width: 40%; background: linear-gradient(90deg, transparent, var(--accent), transparent); animation: scan 1.1s linear infinite; }
@keyframes scan { from { transform: translateX(-100%); } to { transform: translateX(260%); } }
.err { color: var(--danger); font: 400 12px/1.6 var(--mono); margin-top: 12px; }

/* option cards (the brandbrain atom — used here for the format picker) */
.opts { display: flex; flex-direction: column; gap: 8px; }
.opt { position: relative; border: 1px solid var(--edge); background: var(--inset); border-radius: 14px; padding: 13px 14px; cursor: pointer; transition: border-color .15s, background .15s; }
.opt:hover { border-color: var(--edge-soft); }
.opt.sel { border-color: var(--accent); background: color-mix(in srgb, var(--accent-soft) 55%, var(--inset)); }
.opt .check { position: absolute; right: 11px; top: 11px; width: 18px; height: 18px; border-radius: 50%; border: 1px solid var(--edge); display: grid; place-items: center; color: transparent; font: 700 11px/1 var(--sans); }
.opt.sel .check { border-color: var(--accent); background: var(--accent); color: var(--page); }
.opt .rec { display: inline-block; font: 500 9px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--accent); background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); border-radius: 999px; padding: 3px 7px; margin-bottom: 7px; }
.opt .o-label { font: 600 13.5px/1.3 var(--display); color: var(--ink); padding-right: 22px; }
.opt .o-text { font: 400 13px/1.5 var(--sans); color: var(--ink-sec); margin-top: 5px; }

/* steer input (the per-piece "say") */
.steer { margin-top: 16px; display: flex; flex-direction: column; gap: 7px; }
.steer .chips { display: flex; flex-wrap: wrap; gap: 6px; }
.steer .chip { font: 500 11px/1 var(--sans); border: 1px solid var(--edge); background: var(--panel); color: var(--ink-sec); border-radius: 999px; padding: 6px 10px; cursor: pointer; }
.steer .chip:hover { border-color: color-mix(in srgb, var(--accent) 50%, var(--edge)); color: var(--ink); }
.steer .row { display: flex; gap: 8px; align-items: center; }
.steer .box { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; border: 1px solid var(--edge); background: var(--panel); border-radius: 10px; padding: 8px 11px; }
.steer input { flex: 1; min-width: 0; background: none; border: 0; outline: none; color: var(--ink); font: 400 12.5px/1.4 var(--sans); }
.steer .send { flex: none; font: 600 12px/1 var(--sans); background: var(--accent); color: var(--page); border: 0; border-radius: 9px; padding: 9px 12px; cursor: pointer; }

.toast { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); background: var(--raised); border: 1px solid var(--edge); color: var(--ink); font: 500 12.5px/1.4 var(--sans); padding: 11px 16px; border-radius: 10px; box-shadow: 0 14px 40px -14px rgba(0,0,0,.7); z-index: 200; max-width: 80vw; }
.toast.err { border-color: var(--danger); color: #ffd6e2; }

/* ==== app-specific CSS below this line ==== */
.field { margin-top: 18px; }
.field > .kicker { display: block; margin-bottom: 8px; }
.start .hint { font: 400 11px/1.4 var(--mono); color: var(--ink-faint); margin-top: 12px; }
.countrow { display: flex; gap: 8px; }
.count { font: 600 13px/1 var(--sans); min-width: 46px; padding: 10px 0; border-radius: 10px; border: 1px solid var(--edge); background: var(--inset); color: var(--ink-sec); cursor: pointer; transition: border-color .15s, color .15s; }
.count:hover { border-color: var(--edge-soft); color: var(--ink); }
.count.on { border-color: var(--accent); color: var(--page); background: var(--accent); }

/* the drafted pieces — one card each, editable in place */
.q-card { border: 1px solid var(--edge); background: var(--panel); border-radius: 16px; padding: 16px 18px; margin-top: 14px; }
.phead { display: flex; align-items: center; gap: 10px; }
.phead .grow { flex: 1; }
.q-num { font: 500 10px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-faint); }
.redraft-chip { font: 500 9px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--accent); background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); border-radius: 999px; padding: 4px 8px; }
.phook { font: 500 11.5px/1.4 var(--mono); color: var(--ink-faint); margin-top: 10px; }
.pbody { font: 400 14px/1.65 var(--sans); color: var(--ink); white-space: pre-wrap; word-break: break-word; margin-top: 8px; }
</style>
</head>
<body>
<header>
<span class="word"><span class="mk"></span>Dra<em>ft</em></span>
<div id="chip-dock"></div>
</header>
<main>
<section class="hero" id="hero">
<h1>Say it once. <em>Steer it in place.</em></h1>
<p>Topic and a format in — your own Claude drafts a few genuinely different posts, grounded in your brief. Then select any one and say what to change: only that piece re-runs, swapped in place. Runs on your Claude via Switchboard — the operator holds no key and never sees your data.</p>
</section>
<div id="view"></div>
</main>
<script type="module" src="./dist/draft.js"></script>
</body>
</html>
5 changes: 5 additions & 0 deletions examples/apps/harness/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@
// readout never renders. The pull route is also tightened to the pull prompt's own language.
[function (lc, p) { return /you are adpulse|blunt, numbers-first|pre-computed aggregates|monthlyburn/i.test(p); }, function () { return adpulseDiagnosis(); }],
[function (lc, p) { return /reply with only a csv|campaign-level performance for the last 30 days/i.test(p); }, function () { return "text:Campaign name,Amount spent (INR),Impressions,Clicks,CTR,CPC,Purchases,Purchase value,ROAS\nProspecting — Broad,42000,900000,4200,0.47,10,30,33600,0.8\nRetargeting — 7d,18000,210000,3800,1.81,4.7,180,75600,4.2\nLookalike 1%,26000,540000,3100,0.57,8.4,90,54600,2.1"; }],
// draft — the general content drafter. batch → {pieces:[{hook,body}]}, revise → {hook,body}. The
// revise route MUST be matched (it also says "return only a json object"); both sit before the
// generic json fallback so the select-and-say swap gets a real re-drafted body, not the fallback.
[function (lc, p) { return /you are revising one|current piece:/i.test(p); }, function (lc, p) { return { hook: "revised", body: "Revised for " + bname + " — " + optionCard(0).body }; }],
[function (lc, p) { return /you are drafting \d+ |"pieces"\s*:\s*\[/i.test(p); }, function (lc, p) { var m = p.match(/drafting (\d+)/i); var n = m ? Math.max(1, Number(m[1])) : 3; var out = []; for (var i = 0; i < n; i++) out.push({ hook: "angle " + (i + 1), body: optionCard(i).body }); return { pieces: out }; }],
// batch (YC answers / video scripts)
[function (lc, p) { return /y combinator application|founder video|prepping the videos|complete answer options/i.test(p); }, function () { return labelTextArray(3); }],
// identity (5 sequential label/text stages)
Expand Down
1 change: 1 addition & 0 deletions examples/apps/harness/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const CFG = {
take: { name: "Take", cat: "founder-stack", count: (d) => /the script/i.test(txt(d)) ? d.querySelectorAll("#view .opt").length || 1 : 0 },
identity: { name: "Identity", cat: "founder-stack", count: (d) => d.querySelectorAll("#view .q-card .opt, #view .opt").length },
batch: { name: "Batch", cat: "founder-stack", count: (d) => d.querySelectorAll("#view .q-card").length },
draft: { name: "Draft", cat: "founder-stack", count: (d) => d.querySelectorAll("#view .q-card.piece").length },
bank: { name: "Bank", cat: "founder-stack", count: (d) => d.querySelectorAll("#brief-out .briefline").length || (d.getElementById("brief-sec") && !d.getElementById("brief-sec").hidden ? 1 : 0) },
redline: { name: "Redline", cat: "founder-stack", count: (d) => d.querySelectorAll("#side-body .dec").length },
// no crutch: AdPulse diagnoses its own representative month on connect (live pull first when a
Expand Down
2 changes: 2 additions & 0 deletions examples/apps/harness/serve.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ const WRAPPS = [
{ id: "coldemail", html: "coldemail.html", cat: "skill" },
// ideabrain "I have an idea" widget (2026-08) — idea-first, no cold-open; the runner types the idea line.
{ id: "ideabrain", html: "ideabrain.html", cat: "studio" },
// draft — the general content drafter + select-and-say revise (2026-08); cold-opens from the lent brief.
{ id: "draft", html: "draft.html", cat: "founder-stack" },
];

const HARNESS_JSON = JSON.stringify(PROJECTS);
Expand Down
Loading