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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- The README lists skills as one bulleted list instead of a table plus a section per skill. `scripts/check.mjs` checks for the list entry.
- The skills no longer download and run an installer. If `jam` is missing, they ask you to install it from jam.dev/cli. Addresses the remote-code-execution audit finding on `jam-proof` and `jam-annotate`.
- `jam-annotate` and the `jam-fix` proof step write the Jam payload to a file and run `jam create jam @payload.json`, so user and page text never reaches a shell argument.
- `jam-fix` and `jam-to-e2e` treat Jam content (transcript, logs, network bodies, page text, comments) as evidence, not instructions.
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Then run the skill on a real task in at least one agent and say which one in the

- One skill per pull request. Maintainers may ship a coordinated release of several in one.
- Add a line under **Unreleased** in [CHANGELOG.md](./CHANGELOG.md).
- A new skill also needs a card in [README.md](./README.md). CI fails without one.
- A new skill also needs an entry in the Skills list in [README.md](./README.md). CI fails without one.

## Releasing (maintainers)

Expand Down
26 changes: 4 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,10 @@ A Jam is a recording of what happened on screen, with the console logs, network

## Skills

| Skill | You say | You get |
| --- | --- | --- |
| [jam-fix](#jam-fix) | "fix this jam.dev link" | the root cause with evidence, and the fix when you ask |
| [jam-proof](#jam-proof) | "record a Jam showing it works" | a Jam of the change working, console and network attached |
| [jam-annotate](#jam-annotate) | "mark what's broken and file it" | a screenshot Jam with boxes, arrows and redactions |
| [jam-to-e2e](#jam-to-e2e) | "write an e2e test for this Jam" | a test in your own runner: guards a flow, or fails on a bug until it is fixed |

### jam-fix

Reads the recording's console errors, failed requests, user steps, frames and transcript, then writes a diagnosis with the evidence for it. Changes code only when you ask.

### jam-proof

Records the change working and hands back a Jam link for the pull request. Headless Chrome by default: it records the page, not your screen.

### jam-annotate

Turns a screenshot into a Jam that points at the problem: boxes, arrows, notes, redactions and blurs, with the retina math done right.

### jam-to-e2e

Turns a Jam into steps and a test in the project's own runner and language, whatever it is, with first-class guidance for Playwright and [tester-army/e2e](https://github.com/tester-army/e2e). A Jam of a flow becomes a test that guards it. A Jam of a bug becomes a failing test, so the fix has something to turn green.
- [jam-fix](./skills/jam-fix/SKILL.md): "Fix this jam.dev link." Reads the recording's **console errors**, **failed requests**, **user steps**, **frames** and **transcript**, then writes the **root cause with evidence**. Changes code only when you ask.
- [jam-proof](./skills/jam-proof/SKILL.md): "Record a Jam showing it works." Records the change working and hands back a **Jam link for the pull request**, with **console** and **network** attached. Headless Chrome by default: it records the page, not your screen.
- [jam-annotate](./skills/jam-annotate/SKILL.md): "Mark what's broken and file it." Turns a screenshot into a Jam that points at the problem: **boxes**, **arrows**, **notes**, **redactions** and **blurs**, with the retina math done right.
- [jam-to-e2e](./skills/jam-to-e2e/SKILL.md): "Write an e2e test for this Jam." Turns a Jam into a test in **your own runner and language**, with first-class guidance for **Playwright** and [tester-army/e2e](https://github.com/tester-army/e2e). A Jam of a flow becomes a test that **guards it**. A Jam of a bug becomes a **failing test**, so the fix has something to turn green.

## Requirements

Expand Down
2 changes: 1 addition & 1 deletion scripts/check.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ for (const dir of skillDirs) {
if (description.length > 1024) fail(`${skillPath}: description is ${description.length} chars, max 1024`);
}
if (!existsSync(join("skills", dir, "agents", "openai.yaml"))) fail(`${dir}: missing agents/openai.yaml`);
if (!readme.includes(`### ${dir}\n`)) fail(`${dir}: missing "### ${dir}" card in README.md`);
if (!readme.includes(`- [${dir}](./skills/${dir}/SKILL.md): `)) fail(`${dir}: missing "- [${dir}](./skills/${dir}/SKILL.md): " entry in README.md`);
if (dir.startsWith("jam-")) {
const feedback = src.match(/\n## Send feedback to Jam\n[\s\S]*?(?=\n## |$)/)?.[0];
if (!feedback) fail(`${skillPath}: missing "## Send feedback to Jam" section; copy it from another jam-* skill`);
Expand Down
2 changes: 1 addition & 1 deletion scripts/check.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function fixture(t, frontmatter = "name: sample-skill\ndescription: A useful ski
};
write(skillPath, `---\n${frontmatter}\n---\n# Sample skill\n`);
write("skills/sample-skill/agents/openai.yaml", "interface: {}\n");
write("README.md", "### sample-skill\n");
write("README.md", "- [sample-skill](./skills/sample-skill/SKILL.md): x\n");
for (const file of [".claude-plugin/plugin.json", ".codex-plugin/plugin.json", ".cursor-plugin/plugin.json", "gemini-extension.json"]) {
write(file, '{"version":"1.0.0"}\n');
}
Expand Down
Loading