Skip to content
Merged
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
5 changes: 5 additions & 0 deletions demo/deck/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
dist/
out/
.wrangler/
.dev.vars
56 changes: 56 additions & 0 deletions demo/deck/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Demo deck

The demo as a slide deck that a Code Mode agent builds and edits. Each slide is a small program in a Cloudflare Artifacts git repo. The presenter renders slides from that repo, and you change them by chatting with the deck agent, which writes code against the repo.

- **`deck-slides` repo:** `slides/<id>.js` holds the program that draws a slide and `slides/<id>.json` holds what it returned, which is what the presenter renders. `deck.json` holds the slide order, and defaults to [outline.md](outline.md).
- **`deck-agent` repo:** the agent's own Code Mode history. `GitHistoryConnector` commits every program the agent runs, the same as for any codemode-git agent.
- **The agent:** a Workers AI tool-calling loop ([src/worker/agent.ts](src/worker/agent.ts)) around the Code Mode runtime, with a `slides` connector ([src/worker/slides.ts](src/worker/slides.ts)): `outline`, `list`, `read`, `write`, `remove`, `order`, `data`. `slides.write` runs the slide's program in a fresh Dynamic Worker, checks the layout ([src/spec.ts](src/spec.ts)), and commits only when it passes.
- **Slides:** a spec of text, boxes, arrows, agents, charts and code panels on a 1920×1080 canvas, drawn in the demo video's style ([src/client/SlideView.tsx](src/client/SlideView.tsx)). Charts read the real numbers from [../video/src/data.ts](../video/src/data.ts), and speaker notes come from [../video/transcript.md](../video/transcript.md).

A slide that has a program renders straight from the repo. Only a slide without one shows its outline prompt and waits for you to press **G**.

## Run it

It uses the same Artifacts namespace as the example agent. Create the namespace first if you haven't:

```bash
npx cf artifacts namespaces create --namespace codemode-git
```

```bash
npm install # from the repo root: the deck is an npm workspace
npm run dev -w demo/deck
```

Open http://localhost:5173. Locally anyone can edit; no sign-in.

```bash
npm run deploy -w demo/deck
```

The deployed deck is public to view at https://deck.clay.gripe. Editing goes through **Cloudflare Access**: an Access app covers `deck.clay.gripe/edit` and `deck.clay.gripe/api/agent` with the "only-me" policy. Press **E** (or click "sign in to edit"), sign in, and you're back on the same slide in edit mode. The Worker also checks the Access JWT itself ([src/worker/access.ts](src/worker/access.ts)): its signature, the app's audience (`ACCESS_AUD` in [wrangler.jsonc](wrangler.jsonc)) and expiry. Without those vars, only localhost can edit. Access can't scope itself to paths on `workers.dev`, which is why the deck needs a hostname on a zone. The `workers.dev` URL stays up as a view-only mirror.

`npm run build-slides -w demo/deck` asks the agent to build every slide that has no program yet, one message per slide, at high reasoning effort (a few minutes each). It talks to local dev, since the deployed agent is behind Access. Chat edits use low effort, so they take under a minute.

The local and deployed decks share the `deck-slides` repo, but each keeps its own copy. After committing slides from one, `POST /api/agent/reset` on the other reloads them. Avoid having both write at once: the repo is meant to have one writer.

## Presenting

| Key | |
|---|---|
| → / space / click, ← | next, back |
| N | speaker notes and the slide's prompt |
| F | fullscreen |
| E | sign in to edit (Cloudflare Access) |
| C | chat with the deck agent: "make the numbers bigger", "add a slide after this one about pricing", "delete this slide", "move the credits before close" |
| G | have the agent build or rewrite the current slide from its outline prompt |

The agent adds a slide by writing a program under a new id, removes one with `slides.remove` (the files leave the repo, and git history keeps them), and reorders with `slides.order`.

## Offline

`npm run pdf -w demo/deck` saves every built slide to `demo/deck/out/deck.pdf`, one slide per page, from the `?print` view (it needs `npm run dev` running, or set `DECK_URL`). Keep a copy in case the network goes down.

## Editing the outline

[outline.md](outline.md) has one `## <id>` section per slide, and the prompt goes under it. The agent reads it through `slides.outline()`. A changed prompt doesn't rewrite a slide by itself: press **G** on that slide, or ask the agent.
13 changes: 13 additions & 0 deletions demo/deck/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>codemode-git deck</title>
<meta name="description" content="Self-Improving Code Mode Workers, with Artifacts Memory: slides written live by a Code Mode agent." />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/client/main.tsx"></script>
</body>
</html>
84 changes: 84 additions & 0 deletions demo/deck/outline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Deck outline

<!--
One section per slide, in order. The heading is the slide id; the paragraph
under it is the prompt the Code Mode agent writes the slide from. Speaker notes
come from the section with the same id in ../video/transcript.md, if any.

Edit a prompt, redeploy, and press G on that slide to regenerate it. Run
`npm run backup` afterwards to refresh the backup deck.

HTML comments like this one are not part of any prompt.
-->

## thesis

Title slide. Ask the question "What if Cloudflare Artifacts could make Code Mode in Workers self-improving?" over three big lines, with "self-improving?" in amber. Under it, the title "Self-Improving Code Mode Workers, with Artifacts Memory" and the package name codemode-git in mono.

## hook

The headline result: DABstep accuracy went from 32.2% to 46.2% with the same model, prompt and 450 tasks. Two huge numbers with an arrow between them, the new one in orange, and the hard-task numbers smaller underneath. The only change was "+ memory".

## vanish

Today every Code Mode agent writes code, runs it and throws it away. Show a grid of agents, each with a little code snippet, and the caption "every agent starts from zero".

## code-mode

Before and after Code Mode. Left: model and tools with many round-trip arrows, one tool call at a time. Right: the model writes one program (show a few lines of code in a dashed "isolate" box) that calls the tools.

## gap

The isolate is thrown away after every run, and the code goes with it. Show the code box fading out and "the code is gone" in red.

## code-memory

Phase 1, code memory: four agents (michelle, matthew, lena, omar), each with an arrow to its own Artifacts git repo shown as a row of commit dots. Caption: one repo per agent, one writer per repo, zero merges; 1,000 agents made 1,000 commits in 27s with 0 errors.

## under-the-hood

Under the hood, as a left-to-right pipeline of four boxes: execution ends (disposeExecution()), Durable Object (SQLite outbox), isomorphic-git (push, in order), Artifacts repo (one commit per run). Below it, a mono `git clone` line.

## repo

Every attempt, in git: a terminal panel with `git log --oneline` showing three commits for "Count flowing lava lamps", the oldest one an error, the newest two completed.

## recall

Phase 2, learning: michelle's repo feeds Workers AI (embed question + code), which feeds Vectorize (nearest runs), which hands "unverified examples" to the next agent, matthew.

## walkthrough

One real DABstep task (use deck.data("walkthrough")): without memory, 10 programs, 279k tokens, wrong; with memory, 2 programs, 8k tokens, right. Two lanes, one per run, comparing them.

## provenance

Provenance: matthew's commit names the exact runs it learned from. A terminal panel with `git show` output that has a `Codemode-Examples:` trailer pointing at agent-michelle@3f90b41.

## curve

The learning curve (use deck.data("learningCurve")): median tokens per task by position in the run, baseline vs with memory. A line chart; call out that memory costs about a third of the tokens once it has a few dozen runs.

## accuracy

Accuracy by DABstep's official scorer (use deck.data("accuracy")): a bar chart of baseline vs with memory, for Overall and Hard tasks.

## contagion

Which memory works: a shared library of verified skills spread one wrong skill to every agent (show a hub with red spokes), while raw runs labeled unverified worked better (separate agents, mostly green).

## next-steps

Next steps, as three cards: record outcomes (a git note on each commit), index on push (Artifacts events), and learn between tasks (agents review their own history).

## new-worker

Getting started in about a minute: a terminal panel with `npx cf init lava-agent`, `npm install @cloudflare/codemode @smithclay/codemode-git`, the connector plus ARTIFACTS, LOADER and AGENT bindings, then `npx cf deploy --dry-run`.

## close

Close: `npm install @smithclay/codemode-git` in green mono, then exactly these three lines as code (don't change them): `const history = new GitHistoryConnector(ctx, env, { sink });`, `const runtime = history.bind(createCodemodeRuntime({`, ` ctx, executor, connectors: [lamps, history] }));`. Then the tagline "Keep the code." in big amber with "Your Workers get smarter over time." under it.

## credits

Built by Clay Smith, on Cloudflare. A big name, then the tech stack in three short columns: Code (Workers, Code Mode, Artifacts, Durable Objects, Vectorize), Benchmark (DABstep by Adyen, GLM-5.3 Flash), and Presentation (this deck, written by Code Mode). End with github.com/smithclay/codemode-git.
30 changes: 30 additions & 0 deletions demo/deck/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "codemode-git-deck",
"private": true,
"type": "module",
"description": "The demo as a slide deck: a Code Mode deck agent keeps one program per slide in an Artifacts repo, the presenter renders from it, and you chat with the agent to change slides.",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"deploy": "vite build && wrangler deploy",
"typecheck": "tsc -p .",
"pdf": "node scripts/pdf.mjs",
"build-slides": "node scripts/build-slides.mjs"
},
"dependencies": {
"@cloudflare/codemode": "^0.5.3",
"@smithclay/codemode-git": "^0.1.0",
"react": "^19.3.0",
"react-dom": "^19.3.0"
},
"devDependencies": {
"@cloudflare/vite-plugin": "^1.60.0",
"@cloudflare/workers-types": "^5.20261011.1",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^5.2.0",
"typescript": "^5.9.0",
"vite": "^7.3.7",
"wrangler": "^4.149.0"
}
}
27 changes: 27 additions & 0 deletions demo/deck/scripts/build-slides.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Asks the deck agent to build every slide that has no program yet, one
// message per slide, the same as pressing G on each. Slides that already
// exist are left alone; pass ids to rebuild specific ones. Builds use high
// reasoning effort: slower, but low effort cuts corners on a blank slide.
//
// npm run build-slides (npm run dev in another terminal)
// npm run build-slides -- hook curve (rebuild these)
// It talks to local dev: a deployed deck's agent is behind Cloudflare Access.
// Both write to the same deck-slides repo; reload the deployed deck after.

const base = (process.env.DECK_URL ?? "http://localhost:5173").replace(/\/$/, "");
const headers = { "content-type": "application/json" };
const only = process.argv.slice(2);

const deck = await (await fetch(`${base}/api/deck`)).json();
const todo = deck.slides.filter((s) => (only.length ? only.includes(s.id) : !s.slide));
console.log(`${todo.length} slides to build: ${todo.map((s) => s.id).join(", ") || "none"}`);

for (const s of todo) {
const started = Date.now();
const verb = s.slide ? "Rewrite" : "Build";
const res = await fetch(`${base}/api/agent`, { method: "POST", headers, body: JSON.stringify({ message: `${verb} slide ${s.id} from its outline prompt.`, current: s.id, effort: "high" }) });
const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
const secs = Math.round((Date.now() - started) / 1000);
if (body.error) console.log(`✗ ${s.id} (${secs}s): ${body.error}`);
else console.log(`${body.changed.includes(s.id) ? "✓" : "·"} ${s.id} (${secs}s, ${body.steps} steps, ${body.tokens} tokens): ${body.reply}`);
}
27 changes: 27 additions & 0 deletions demo/deck/scripts/pdf.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Saves the deck as a PDF, one slide per 16:9 page, from the ?print view, for
// presenting offline. Uses a local Chrome in headless mode.
//
// npm run pdf (npm run dev in another terminal)
// DECK_URL=https://… npm run pdf (a deployed deck)
// CHROME=/path/to/chrome npm run pdf

import { execFileSync } from "node:child_process";
import { existsSync, mkdirSync } from "node:fs";

const base = (process.env.DECK_URL ?? "http://localhost:5173").replace(/\/$/, "");
const chrome =
process.env.CHROME ??
["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "/usr/bin/google-chrome", "/usr/bin/chromium"].find((p) => existsSync(p));
if (!chrome) throw new Error("no Chrome found; set CHROME=/path/to/chrome");

const out = new URL("../out/deck.pdf", import.meta.url).pathname;
mkdirSync(new URL("../out/", import.meta.url), { recursive: true });
execFileSync(chrome, [
"--headless",
"--disable-gpu",
"--no-pdf-header-footer",
"--virtual-time-budget=15000",
`--print-to-pdf=${out}`,
`${base}/?print`
], { stdio: "ignore" }); // Chrome logs harmless GPU noise on stderr; a failure still throws.
console.log(`wrote ${out}`);
Loading
Loading