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
34 changes: 34 additions & 0 deletions .github/workflows/kits.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Build every kit app on every PR.
#
# Nothing built these before, and a broken kit only showed up at image bake — where the failure is
# a docker layer, not a diff. An undefined JSX identifier does not even fail there: it is a
# runtime error, so it ships. This is the cheapest place to catch both.
name: kits

on:
push:
branches: [main]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
kit: [slides, sheets]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
# Not `npm ci` at the repo root: install-kits.sh cds into each app and resolves against that
# app's own lockfile, so hoisting here would test a tree the image never has.
- run: npm ci
working-directory: kits/${{ matrix.kit }}/app
- run: npm test --if-present
working-directory: kits/${{ matrix.kit }}/app
- run: npm run build
working-directory: kits/${{ matrix.kit }}/app
- name: dist exists
run: test -d kits/${{ matrix.kit }}/app/dist
3 changes: 2 additions & 1 deletion kits.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"so adding a kit does not mean editing this file beyond one line."
],
"kits": [
{ "name": "slides", "include": true }
{ "name": "slides", "include": true },
{ "name": "sheets", "include": true }
]
}
16 changes: 16 additions & 0 deletions kits/sheets/CREDITS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Credits

## Templates

The starting sheets in `templates/templates.json` are original to this kit.

## Components

The grid, the conversation surface, the dialogs and the HarnessRouter transport come from
**[reifyui](https://www.npmjs.com/package/reifyui)** (MIT), which is where they live so that a
second kit does not start a second copy of them.

## Spreadsheet export

`.xlsx` export uses **[SheetJS](https://sheetjs.com/)** (`xlsx`, Apache-2.0), loaded only when
someone actually exports one.
56 changes: 56 additions & 0 deletions kits/sheets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Sheets

A spreadsheet where a column can be an agent. Rows are your data; an **agent column** runs one of
your other agents once per row, builds its input from the columns to its left, and fills each cell
with what that agent said and made.

Launch it from **Starter Kits** in the HarnessRouter console. That provisions the Harness this app
talks to; nothing else is deployed and nothing is configured.

## How it works

- **One session is one sheet.** The sheet list is this Harness's session list, and a sheet's
content is `sheet.json` in that session's workspace. There is no database.
- **The app is served by the HarnessRouter image** at `/kits/sheets`, same-origin with the
console, which is why it needs no API key and no login of its own.
- **Column order is execution order.** An agent column may only read columns earlier in the sheet,
which makes the column list a valid running order by construction — there is no graph to sort
and no cycle to handle.
- **The run happens in your browser tab.** There is no workflow engine in this deployment, so the
page is the orchestrator: it walks the cells in dependency order with a concurrency limit you
choose. Cells already started finish if you leave; nothing new starts, and the page says so
before you press Run.
- **Each cell is its own conversation.** One session per cell, titled for its column and row, so
every result is a real conversation you can open in the console and read.
- **Only the last run is kept.** Starting a run clears the cells it owns. The conversations are
never deleted — you drop the reference, not the work.

## What's in the folder

| Path | What |
|---|---|
| `kit.json` | The Harness this kit needs, and where its app is served |
| `skills/sheet-design/` | The `sheet.json` contract and how to design columns — read before anything is written |
| `templates/templates.json` | Starting points, including one with agent columns |
| `app/` | The UI |

## Working on the app

```
cd app
npm install
npm test # the document rules and the run planner, no network needed
npm run build
```

`src/lib` is deliberately free of React and of the network:

| File | What |
|---|---|
| `model.js` | The document: ids, references, interpolation, and every way a sheet can be wrong |
| `run.js` | `plan()` and the `Runner` — what would run, and the walk, over an injected dispatcher |
| `cell.js` | The dispatcher: one cell, one turn |
| `sh.js` | What "sheet" adds on top of `reifyui/harness` |

`model.test.mjs` and `run.test.mjs` cover both. `skills/sheet-design/validate_sheet.py` is the
agent-side twin of `model.js`'s `validate()`; if the two ever disagree, the app is right.
1 change: 1 addition & 0 deletions kits/sheets/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
public/
9 changes: 9 additions & 0 deletions kits/sheets/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Sheets</title>
</head>
<body><div id="root"></div><script type="module" src="/src/main.jsx"></script></body>
</html>
Loading
Loading