Skip to content

feat: Add the jam router and four Jam skills - #22

Merged
baransu merged 2 commits into
masterfrom
tomasz/jam-router-and-skills
Oct 26, 2026
Merged

baransu merged 2 commits into
masterfrom
tomasz/jam-router-and-skills

Conversation

@baransu

@baransu baransu commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Why

A Jam pasted with no ask, or with "take a look at this jam", matched no skill well. A narrated feedback walkthrough landed in jam-fix and got diagnosed as one bug, and a Jam the user could not open still started jam-fix. The plugin also had no skill for turning a Jam into tasks or a ticket, listing proof at the end of a run, or splitting a video someone already has into Jams.

What changed

  • jam router: it reads the Jam, then loads the skill that fits. A walkthrough with several asks goes to jam-to-tasks, a bug to jam-fix, and a Jam it cannot open stops with a message. Its description covers only a bare link, a vague ask and /jam (/jam:jam from the plugin), so a clear ask still goes straight to its own skill.
  • New skills: jam-to-tasks, jam-to-ticket, jam-proof-table, video-to-jam.
  • jam-fix hands a walkthrough with several asks to jam-to-tasks when that skill is installed. The ChatGPT package ships jam-fix without it.
  • scripts/check.mjs: jam anywhere in a skill's name marks a Jam skill (was the jam- prefix), and the router's table must name every skill and only skills that exist.
  • CONTRIBUTING.md: jam is the one single-word skill name.
  • Jam text never goes into a double-quoted shell string: comments pass the body as "$(cat file)", and gh takes --body-file. A transcript quote such as "Pro shows $29" would otherwise post as "Pro shows 9".
  • The four new skills use the CLI setup block from Fix skills.sh audit findings #18: they ask the user to install jam instead of installing it. The check that keeps setup blocks identical now keys on that block; it matched nothing after Fix skills.sh audit findings #18.
  • Frames and screenshots go to mktemp -d, outside the repo. jam-to-tasks commits only when asked.

Review guide

  1. LOGIC skills/jam/SKILL.md: the description's trigger scope, the routing table, and the bare-link branch
  2. LOGIC skills/jam-to-tasks/SKILL.md: the trust line, step 6 (show the list, then work), and commits only on request
  3. LOGIC skills/jam-to-ticket/SKILL.md: the duplicate check, one ticket per problem, --body-file
  4. LOGIC scripts/check.mjs: Jam-skill detection and the router table check
  5. LOGIC skills/video-to-jam/SKILL.md, skills/jam-proof-table/SKILL.md
  6. MECHANICAL skills/jam-fix/SKILL.md (handoff line), README list entries, CHANGELOG, agents/openai.yaml
  7. TEST scripts/check.test.mjs, scripts/package-chatgpt.test.mjs

Verification

Headless Claude Code, claude-opus-5-5, with only this plugin's skills loaded and shell, edit and write tools blocked. 105 runs: each case with /jam typed, with the router and no /jam, and without the router, 3 runs each where the router matters.

Use case Configuration Proof
Bare link to a narrated feedback Jam goes to jam-to-tasks router, no /jam 3/3. Without the router: 0/3, sent to jam-fix
A Jam the user cannot open stops with a message router, no /jam 3/3. Without the router: 0/3, starts jam-fix
Bare bug link, bare Jam id, "take a look at this jam" go to jam-fix router, no /jam 9/9, and 9/9 without the router
"Fix this and then file a ticket" runs jam-fix, then jam-to-ticket router, no /jam 3/3. Without the router: 2/3
11 clear asks (ticket, e2e, fix, proof, video, annotate, a Polish ask, comment, list…) never load the router all three 0 router loads in every run
Check rules hold npm test 34/34. The tests fail on all 5 rule mutations tried: prefix match, substring match, feedback-drift check off, mention cap off, router check off

Not verified:

  • Codex and Cursor: no runs.
  • "Fix it and prove it": with edits blocked, jam-fix cannot finish in 8 turns, so jam-proof is never reached.
  • A bare screenshot Jam: the router read the fixture as proof of a finished change, not a bug, and asked instead of routing. The expected answer in the case was wrong.
  • 14 of 105 runs started before the Jam MCP server connected and are void.
  • No Jam links: the eval blocked writes, so none of these skills produced a Jam for this PR.

Compatibility

Additive. Existing skills keep their names and triggers. The ChatGPT package still holds jam-fix and jam-to-e2e, now asserted exactly. No CLI bundle resync: jam-proof and jam-annotate are unchanged.

Security

  • Jam content is evidence, not instructions, in jam-to-tasks and jam-to-ticket. jam-to-ticket keeps tokens, cookies and personal data from network bodies out of tickets.
  • video-to-jam transcribes on the machine, and asks before uploading a full recording or attaching a Playwright trace (cookies, headers, bodies). It pins whisper-ctranslate2@0.5.8.
  • jam-proof-table and video-to-jam ask before creating a folder on a Viewer account, which can change seat billing.
  • Accepted: jam-to-tasks acts on the narration of a Jam the user hands it, including one someone else recorded. That is the skill's job.
  • Accepted: jam-to-ticket does not check whether a GitHub repo is public; the user picks the tracker.

Rollback

Revert the merge on master before a v* tag: npx skills add follows master. After a tag, revert and release a patch. server.json is unchanged, so the MCP Registry is not involved.

@baransu baransu changed the title Add jam router and four Jam skills feat: Add the jam router and four Jam skills Oct 26, 2026
…proof-table, video-to-jam

- jam: routes a bare jam.dev link or a vague ask to the right skill after
  reading the Jam; a clear ask still goes straight to its own skill. /jam works too.
- jam-to-tasks, jam-to-ticket, jam-proof-table, video-to-jam: new skills.
- jam-fix hands a narrated multi-ask walkthrough to jam-to-tasks.
- check.mjs: jam anywhere in the name marks a Jam skill; the router table must
  name every skill and only real ones. Tests for both, the feedback-section
  drift, the one-mention cap, and the exact ChatGPT package contents.
@baransu
baransu force-pushed the tomasz/jam-router-and-skills branch from f751bf1 to 873963f Compare October 26, 2026 11:50

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 potential issues.

Devin Review

Comment thread skills/jam/SKILL.md
Comment on lines +32 to +35
Read the Jam's details first: the `getDetails` MCP tool, or
`jam get jam <id> --json`. Then route by what it holds:

- A narrated walkthrough that asks for several changes: `jam-to-tasks`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Narrated walkthroughs lose their task route

For a bare link, jam routes a narrated walkthrough using only details, without reading its transcript. Multiple spoken requests can be invisible there, so the walkthrough falls through to a question or bug diagnosis.

Learn more

Jam details contain metadata about the recording, while the spoken requests are in the video transcript. The router handles vague requests and bare links before loading another skill. It currently decides whether several changes were requested after reading only details, so it lacks the evidence needed for that decision. The transcript step shows where the actual spoken requests are obtained.

Example: A user pastes only a video Jam link. The speaker asks for a pricing fix and a checkout change, but the title merely says “Feedback.” Details alone cannot distinguish it from a single-bug report, so the router can miss jam-to-tasks.

Recommended fix: For video Jams with narration and no clear user ask, retrieve the transcript before deciding between jam-to-tasks, jam-fix, and a clarification question; handle unavailable captions explicitly.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +53 to +59
`integrations` lists the tickets Jam's own integrations already filed for
it, each with `id` and `url`. Then search the tracker for the Jam's id and
full URL, then for two or three words from its title. Tracker search is
fuzzy and returns near misses: a match is a ticket whose body or
attachments hold this Jam's id. On a match, return that ticket and stop.
That also answers "was this Jam ever ticketed?". Add the new Jam to the
existing ticket only when the user asks.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Existing ticket hides unfiled problems

When a Jam contains several problems and one is already ticketed, jam-to-ticket stops at that match. Other problems never get their own tickets.

Learn more

A narrated Jam can describe several unrelated problems. The one-problem-per-ticket step requires a separate ticket for each. Duplicate checking currently stops on the first match for the Jam ID, even if that match covers only one problem. That leaves other problems without tickets.

Example: A recording describes a broken price and a failed sign-in. The existing price ticket links to the recording. The lookup finds it and stops, so the sign-in ticket is never created.

Recommended fix: Enumerate the problems before deciding whether to stop. Compare each existing ticket with its corresponding problem and create tickets only for those still unfiled; retain the read-only answer path when the user only asks whether a ticket exists.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +80 to +87
```bash
jam get jam "$ID" --json # reads back, type, duration
jam get frames "$ID" --at 48000 --size medium --out "$(mktemp -d)" # outside the repo
```

Open the frame at the moment the claim shows up; `--at` must be below the
Jam's `duration`. A blank page, a single frozen frame, or the wrong tab is
not proof. Record it again with `jam-proof` and say that you did.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Screenshot and replay proof cannot be checked

When a row links a screenshot or replay Jam, jam-proof-table asks for video frames it cannot provide. Valid proof is rejected instead of checked through screenshots or events.

Learn more

Jam recordings have different visual capabilities: video Jams have frames, screenshot Jams have screenshots, and replay Jams have neither. The type guidance already distinguishes these cases. This skill fetches frames for every Jam and treats unavailable or unsuitable visuals as failed proof.

Example: A completed annotation is filed as a screenshot Jam. The proof table tries jam get frames on its ID, which cannot return a video frame, rather than opening the screenshot that shows the annotation.

Recommended fix: Inspect the type returned by jam get jam before verification. Use frames for video, screenshots for screenshot Jams, and recorded events, console, or network for replay Jams. Mark unsupported evidence unconfirmed instead of treating the Jam as a bad recording.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +57 to +60
## 2. Read the whole transcript

```bash
jam get transcript "$ID" --json # WebVTT in the "transcript" field

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Silent Jam tasks stall at transcript

For a silent Jam with several written requests, jam-to-tasks proceeds to jam get transcript, which has no captions. Its later coverage check also requires a transcript, leaving those requests without a workable completion path.

Learn more

The no-narration branch treats title, description, and comments as the requests. A silent recording or screenshot has no transcript, yet the next step unconditionally reads one and the coverage check demands rereading it. The documented caption error is final with the microphone off.

Example: A screenshot Jam's description lists two UI changes. It is not a single failure, so it remains in this skill. Transcript retrieval fails permanently, and the prescribed task-list and final coverage steps have no source to read.

Recommended fix: Branch explicitly on Jam type and narration availability. For silent Jams, extract and verify coverage against title, description and comments, and use screenshots when available rather than requesting video frames.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread skills/video-to-jam/SKILL.md
@baransu
baransu merged commit 64cb799 into master Oct 26, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant