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
2 changes: 1 addition & 1 deletion .github/workflows/kits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: python3 kits/video/skills/video-storyboard/validate_scene.py
- run: python3 kits/video/plugin/skills/video-storyboard/validate_scene.py
--templates kits/video/templates/templates.json
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ Four working products, each launched from **Starter Kits** in the HarnessRouter
one provisions the Harness it needs and serves the app from the HarnessRouter image — there is no
separate service to deploy, no database to configure, and no API key to paste into the app.

Each kit's Skills ship as a plugin, a package in the
[Agent Plugins](https://agent-plugins.org) format at `kits/<kit>/plugin/`: `plugin.json` names and
versions it, `skills/` holds the Skills. Launching a kit installs that package on the Harness it
provisions, so the Harness shows the kit as a named plugin it can export, and the same package installs
into any other server that speaks the
[Unified Harness Protocol](https://unifiedharnessprotocol.org/spec/2026-09-12/plugins) or any client that
reads the format.

Every one of them is the same idea in a different shape: **a session is a document**. The list of
decks, sheets, dashboards or films *is* the Harness's session list, and the document is a file in
that session's workspace. Delete the session and the work goes with it.
Expand Down
6 changes: 3 additions & 3 deletions kits/dashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ numbers are tomorrow's.
| Path | What |
|---|---|
| `kit.json` | The Harness this kit needs, and where its app is served |
| `skills/dashboard-design/` | The `dashboard.json` contract, how to explore a schema, which chart answers which question, and the validator — read before anything is written |
| `plugin/skills/dashboard-design/` | The `dashboard.json` contract, how to explore a schema, which chart answers which question, and the validator — read before anything is written |
| `templates/templates.json` | Five worked dashboards (revenue, pipeline, traffic, support, executive) as reference material |
| `app/` | The UI |

Expand All @@ -90,12 +90,12 @@ numbers are tomorrow's.
`dashboard.json` is the whole dashboard: `meta`, one `datasource`, a list of `queries` (id, name,
SQL), and a list of `panels` (a title, the query it draws, its place on a 12-column grid, and
either a single-number readout or an ECharts option). The contract is stated once, in
`skills/dashboard-design/SKILL.md`, and enforced twice — by the app's reader and by
`plugin/skills/dashboard-design/SKILL.md`, and enforced twice — by the app's reader and by
`validate_dashboard.py`, which the agent runs before it finishes. If the two ever disagree, the
app is right and the validator is the bug.

```
python3 skills/dashboard-design/validate_dashboard.py path/to/dashboard.json
python3 plugin/skills/dashboard-design/validate_dashboard.py path/to/dashboard.json
```

It catches what cannot be seen from inside a turn: a statement the read-only check would refuse,
Expand Down
9 changes: 5 additions & 4 deletions kits/dashboard/kit.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
"launch": {
"database": {
"$comment": "This kit reads a database, so launch asks for one before it provisions anything. Without a connection every panel it builds has nothing to read. Declaring this is what makes launch collect a connection string; the entry it provisions is an ordinary tool from then on.",
"engines": ["postgres", "mysql"],
"engines": [
"postgres",
"mysql"
],
"name": "database",
"id": "mcp.database"
}
Expand All @@ -31,9 +34,7 @@
}
],
"system_prompt": "You build dashboards that read a database.\n\nTHE FILE: ./dashboard.json, in your current working directory. That exact path, always. Do not search for it, do not look elsewhere in the tree, and do not treat its absence as a puzzle — on a new dashboard it simply does not exist yet and you create it there. It is the single source of truth and the only file the app reads.\n\nRead it before every change and write it back WHOLE — the person may have moved panels between turns. Its schema, and the mistakes that leave a panel blank, are in the dashboard-design skill: read that skill first, on every request, and validate with its validate_dashboard.py before you finish.\n\nThe database is reachable only through the database tools in your tool list, and only for reading: one statement, SELECT, row-capped and timed out. Explore the schema with the schema tool instead of guessing table names, and RUN every query before you put it in a panel — a panel whose query you never ran is a panel you have not seen. You are never given a connection string; never write one into any file.\n\nNever put a number in the file. Every value on a dashboard comes from a query at the moment someone opens it. There is nowhere in this document to type a figure you already know, and a chart with its data written in is a lie that never refreshes.\n\nWork directly. Every command you spend orienting is a command the person waits through.",
"skills": [
"dashboard-design"
]
"plugin": "plugin"
},
"app": {
"dir": "app",
Expand Down
20 changes: 20 additions & 0 deletions kits/dashboard/plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "harnessrouter-dashboard",
"version": "1.0.0",
"description": "Say what you want to understand; your database answers it.",
"author": {
"name": "HarnessRouter",
"url": "https://harnessrouter.ai"
},
"homepage": "https://github.com/HarnessRouter/starter-kit/tree/main/kits/dashboard",
"repository": "https://github.com/HarnessRouter/starter-kit",
"license": "LicenseRef-HarnessRouter-Starter-Kit-1.0.0",
"keywords": [
"harnessrouter",
"starter-kit",
"dashboards",
"sql",
"charts"
]
}
4 changes: 2 additions & 2 deletions kits/sheets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ agent doing real work, one row at a time, and you can watch each cell arrive.
| 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 |
| `plugin/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 |

Expand All @@ -70,7 +70,7 @@ npm run build
| `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
`model.test.mjs` and `run.test.mjs` cover both. `plugin/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.

## License
Expand Down
4 changes: 1 addition & 3 deletions kits/sheets/kit.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@
}
],
"system_prompt": "You build and edit spreadsheets.\n\nTHE FILE: ./sheet.json, in your current working directory. That exact path, always. Do not search for it, do not look elsewhere in the tree, and do not treat its absence as a puzzle — on a new sheet it simply does not exist yet and you create it there. It is the single source of truth and the only file the app reads.\n\nRead it before every change and write it back WHOLE — the person may have edited the grid between turns. Its schema, and the mistakes that make a sheet fail to load, are in the sheet-design skill: read that skill first, on every request, and validate with its validate_sheet.py before you finish.\n\nA column may be an AGENT column (type \"harness\"): it runs an agent once per row. You create and configure such a column, but you NEVER execute one — the app does, and it will not let a sheet run itself.\n\nALWAYS give an agent column a working default so the person can press Run the moment the sheet exists. Set harness_id to a BASE agent id, choosing the one that suits the work: \"codex\", \"claude-code\", \"hermes\", \"pi\", \"dsh\", \"opencode\", \"qwen\". Those ids are stable and you may write them. Never invent a chrn_ id — you cannot see the person’s own agents, and an invented id silently runs the wrong one. If the base you pick is not installed here the app substitutes one that is, so a reasonable choice is always better than leaving it blank. The person can change it in the column menu.\n\nCells in an agent column carry results the app produced — status, session_id, response_id, artifacts. Never write them and never delete them unless you are asked to clear that column; you cannot recompute them.\n\nWork directly. Every command you spend orienting is a command the person waits through.",
"skills": [
"sheet-design"
]
"plugin": "plugin"
},
"app": {
"dir": "app",
Expand Down
20 changes: 20 additions & 0 deletions kits/sheets/plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "harnessrouter-sheets",
"version": "1.0.0",
"description": "A spreadsheet where a column can be an agent.",
"author": {
"name": "HarnessRouter",
"url": "https://harnessrouter.ai"
},
"homepage": "https://github.com/HarnessRouter/starter-kit/tree/main/kits/sheets",
"repository": "https://github.com/HarnessRouter/starter-kit",
"license": "LicenseRef-HarnessRouter-Starter-Kit-1.0.0",
"keywords": [
"harnessrouter",
"starter-kit",
"spreadsheets",
"sheets",
"data"
]
}
2 changes: 1 addition & 1 deletion kits/slides/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ service: nothing it makes is a flat picture you have to ask it to change.
| Path | What |
|---|---|
| `kit.json` | The Harness this kit needs, and where its app is served |
| `skills/slide-design/` | How to design a deck — read before any slide is written |
| `plugin/skills/slide-design/` | How to design a deck — read before any slide is written |
| `templates/templates.json` | 46 starting points |
| `app/` | The UI |

Expand Down
8 changes: 3 additions & 5 deletions kits/slides/kit.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "slides",
"title": "Slides",
"tagline": "Design presentations by conversation, then edit them by hand.",
"description": "A deck is one conversation. Ask for a presentation and the agent designs it \u2014 structure first, then a style system, then slide by slide. Everything it makes is editable on the canvas: drag, resize, retype, add. Ships with 46 templates.",
"description": "A deck is one conversation. Ask for a presentation and the agent designs it structure first, then a style system, then slide by slide. Everything it makes is editable on the canvas: drag, resize, retype, add. Ships with 46 templates.",
"icon": "tabler:presentation",
"accent": "#6E55FF",
"harness": {
Expand All @@ -21,10 +21,8 @@
"model": "claude-opus-5"
}
],
"system_prompt": "You design and edit presentation decks.\n\nTHE FILE: ./deck.json, in your current working directory. That exact path, always. Do not search for it, do not look elsewhere in the tree, and do not treat its absence as a puzzle \u2014 on a new deck it simply does not exist yet and you create it there. It is the single source of truth and the only file the app reads.\n\nRead it before every change and write it back whole. Its schema, and the four mistakes that render as an empty rectangle, are in the slide-design skill \u2014 read that skill first, on every deck request, and validate with its validate_deck.py before you finish.\n\nWork directly. Every command you spend orienting is a command the person waits through.",
"skills": [
"slide-design"
]
"system_prompt": "You design and edit presentation decks.\n\nTHE FILE: ./deck.json, in your current working directory. That exact path, always. Do not search for it, do not look elsewhere in the tree, and do not treat its absence as a puzzle — on a new deck it simply does not exist yet and you create it there. It is the single source of truth and the only file the app reads.\n\nRead it before every change and write it back whole. Its schema, and the four mistakes that render as an empty rectangle, are in the slide-design skill — read that skill first, on every deck request, and validate with its validate_deck.py before you finish.\n\nWork directly. Every command you spend orienting is a command the person waits through.",
"plugin": "plugin"
},
"app": {
"dir": "app",
Expand Down
20 changes: 20 additions & 0 deletions kits/slides/plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "harnessrouter-slides",
"version": "1.0.0",
"description": "Design presentations by conversation, then edit them by hand.",
"author": {
"name": "HarnessRouter",
"url": "https://harnessrouter.ai"
},
"homepage": "https://github.com/HarnessRouter/starter-kit/tree/main/kits/slides",
"repository": "https://github.com/HarnessRouter/starter-kit",
"license": "LicenseRef-HarnessRouter-Starter-Kit-1.0.0",
"keywords": [
"harnessrouter",
"starter-kit",
"presentations",
"slides",
"design"
]
}
4 changes: 2 additions & 2 deletions kits/video/CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The five worked storyboards in `templates/templates.json` — their shot lists, their prompts and
their arrangement — are original to this kit, and so is the guidance in
`skills/video-storyboard/`. What is not original is the craft underneath: which shots a short film
`plugin/skills/video-storyboard/`. What is not original is the craft underneath: which shots a short film
needs, in what order, and why a face has to be established once rather than described repeatedly.
These are the sources that settled those questions.

Expand All @@ -30,7 +30,7 @@ These are the sources that settled those questions.

- Pat P. Miller, *Script Supervising and Film Continuity* (Focal Press) — continuity is somebody's
explicit responsibility on a real set, tracked shot by shot, precisely because it cannot be held
in anyone's head. `skills/video-storyboard/references/continuity.md` is that idea applied to a
in anyone's head. `plugin/skills/video-storyboard/references/continuity.md` is that idea applied to a
generative pipeline, where the failure mode is sharper: a described character is a distribution
of faces, and re-describing draws a new one each time.

Expand Down
8 changes: 4 additions & 4 deletions kits/video/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ ended on, which is how a move carries across a join without a jump.
| Path | What |
|---|---|
| `kit.json` | The Harness this kit needs, and where its app is served |
| `skills/video-storyboard/` | The loop, the storyboard format, the continuity rules, and the validator — read before anything is generated |
| `plugin/skills/video-storyboard/` | The loop, the storyboard format, the continuity rules, and the validator — read before anything is generated |
| `templates/templates.json` | Five worked storyboards (product launch, explainer, teaser, story, how-to) as reference material |
| `app/` | The UI |

Expand All @@ -120,13 +120,13 @@ Two rules about that file are worth stating outright because both fail silently:
- **The order of `timeline.shots` is the cut order.** It is never inferred from where cards sit on
the canvas, or dragging one to tidy the board would silently re-cut the film.

The contract is stated once, in `skills/video-storyboard/SKILL.md`, and enforced twice — by the app
The contract is stated once, in `plugin/skills/video-storyboard/SKILL.md`, and enforced twice — by the app
and the export pipeline, and by `validate_scene.py`, which the agent runs before it finishes. If
the two ever disagree, the running system is right and the validator is the bug.

```
python3 skills/video-storyboard/validate_scene.py path/to/scene.excalidraw --expect-seconds 36
python3 skills/video-storyboard/validate_scene.py --templates templates/templates.json
python3 plugin/skills/video-storyboard/validate_scene.py path/to/scene.excalidraw --expect-seconds 36
python3 plugin/skills/video-storyboard/validate_scene.py --templates templates/templates.json
```

It catches what cannot be seen from inside a turn: a timeline shot that is still rendering, a shot
Expand Down
4 changes: 1 addition & 3 deletions kits/video/kit.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@
}
],
"system_prompt": "You make short videos with someone, on a canvas you both edit.\n\nTHE CANVAS IS NOT A FILE YOU WRITE. Never create, read or edit scene.excalidraw or any file in this workspace to change what is on the canvas — it is a projection and your edits to it are discarded. Look at the canvas with the describe tool and change it with the place, move, arrange and remove tools. There is no other way and you do not need one.\n\nGENERATION IS SUBMIT AND POLL. Every generate tool returns a job id immediately; a clip takes about four minutes. Submit every shot you have planned, place all of them straight away so the person watches them appear, arrange the board, and only then check the jobs. Never submit one clip and wait for it.\n\nEVERY GENERATION COSTS MONEY. A duration is required on every clip because one model bills 15 seconds by default. Never re-render something that already exists — place it again instead. Never loop a generation.\n\nLIST THE CAPABILITIES FIRST. Models come and go and some are broken today. That tool is free, and it tells you what can actually be made and roughly what it costs. A capability with no model returns a plain refusal — believe it, tell the person, and do not look for a substitute. Speech is not music.\n\nGET THE STORYBOARD AGREED BEFORE YOU SPEND ANYTHING. Write the shot list in the conversation, with a length for each shot, and wait for a yes.\n\nRead your tool list for the exact names — it is the authority, not this paragraph. Read the video-storyboard skill on every request and follow it.",
"skills": [
"video-storyboard"
]
"plugin": "plugin"
},
"app": {
"dir": "app",
Expand Down
20 changes: 20 additions & 0 deletions kits/video/plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "harnessrouter-video",
"version": "1.0.0",
"description": "Describe the film; watch the shots arrive on the canvas.",
"author": {
"name": "HarnessRouter",
"url": "https://harnessrouter.ai"
},
"homepage": "https://github.com/HarnessRouter/starter-kit/tree/main/kits/video",
"repository": "https://github.com/HarnessRouter/starter-kit",
"license": "LicenseRef-HarnessRouter-Starter-Kit-1.0.0",
"keywords": [
"harnessrouter",
"starter-kit",
"video",
"storyboard",
"media"
]
}
Loading