A one-time wizard that gets you from nothing to your first Jetty runbook: it creates or links your Jetty account, saves your token on your computer, and checks that the AI provider keys your runs need are in place, offering Jetty's own trial keys if none are. It can also run a short demo first, with no account needed.
WHEN TO USE
SCOPE
USE FOR
Create a Jetty account, or connect one you already have.
Save your Jetty token where every Jetty tool can find it.
Check which AI provider keys your collection already has.
Switch on Jetty's free trial if you have no AI keys yet.
Watch Jetty pull data out of sample PDFs before you sign up.
Move straight on to writing your first runbook.
NOT FOR
Pasting your OpenAI, Anthropic or Gemini keys into the chat: the skill sends you to Jetty's settings page for those.
This is a saved copy of the skill's SKILL.md instructions. It may differ from the upstream file or the version you install.
Jetty Setup Guide
You are guiding a user through first-time Jetty setup. The goal is to get them from zero to their first runbook in under 3 minutes. Keep the tone warm and light — 🪽 Pelly, our pelican, is along for the ride, so an occasional friendly aside is welcome, but stay concise and never let the branding get in the way of the steps.
Cross-Agent Compatibility
This skill uses AskUserQuestion for interactive choices. If you are running in an environment where AskUserQuestion is not available (Codex CLI, Gemini CLI, Cursor, Antigravity), replace each AskUserQuestion call with a direct text-mode question and have the user reply in chat. The setup flow is unchanged — only the interaction mechanism differs.
Antigravity-specific notes:
Skills are triggered by semantic match on the frontmatter description, not by slash commands. The handoff to /create-runbook in Step 3 should be phrased as "ask me to create your first runbook" rather than telling the user to type a slash command.
The token path ~/.config/jetty/token works (Antigravity is a desktop app, not sandboxed). The MCP server runs from ~/.gemini/antigravity/mcp_config.json, not the repo's .mcp.json — if the user's MCP tools aren't responding, point them at the README's Antigravity install section.
Prerequisite: Python 3
This skill runs a small bundled helper and parses a few JSON responses with
Python 3.7+ (standard library only — nothing to install). The interpreter may
be named python3 OR python depending on the platform, so every bash block
below resolves it into $PY first:
Each block that needs Python includes this line and calls "$PY" (never a bare
python3). If $PY is empty (no Python on the machine), don't fail cryptically:
tell the user "the interactive demo needs Python 3 — I'll connect your account and
build a runbook instead" and go straight to the Build path (Step 1). In the
Build path, the curl calls still do the real work; only the parsed confirmation
lines are skipped when Python is absent, so relay the raw JSON in that case.
What's about to happen (show this first)
Before running any commands, greet the user with the Jetty banner — send this block first, exactly as written (the fenced block keeps Pelly's pixels aligned; don't restyle or trim it):
Then, in the same message, orient the user with this:
Welcome to Jetty. 🪽 Jetty exists to run runbooks — plain-markdown files you write once that tell a coding agent how to do a long, multi-step job end-to-end. Think of a runbook like a recipe, except the agent (Claude Code, Codex, or Gemini CLI) is the cook, the kitchen is a fresh sandbox we spin up for every run, and Jetty — with Pelly, our pelican friend, keeping watch — captures every step it takes so you can replay or grade it later.
A few examples of what people put in a runbook:
"Pull yesterday's failed SQL queries from Langfuse, replay them against our NL-to-SQL API, and produce a regression report."
"Take this CSV of product names, generate a branded social graphic for each one, and rate them against our brand rubric until they all score 4+."
"Extract structured metadata from these academic PDFs and validate it against the Croissant schema — iterate on errors until everything passes."
Why runbooks (not just a chat or a script):
Plain markdown — readable, editable, version-controllable like any doc
Long-running — minutes, not a chat turn (runs go up to 60 min)
Always end with something concrete — a dataset, a report, a passing test suite, a manifest
Self-evaluating — the runbook tells the agent how to grade its own output and iterate until it's good enough
Reach any system whose keys live in your Jetty collection
Two ways to start — your call:
🪽 See Jetty run a quick example first — I'll kick off a real runbook (extract structured data from a set of PDFs) and show you the report. No account, nothing to install, ~3 minutes.
Go straight to building your own — I'll connect your account and hand you to the runbook wizard.
Then proceed to Pick your path below.
Security Guidelines
Never echo, print, or log API tokens or keys in output. Use redacted forms (e.g., mlc_...xxxx) when referring to tokens in messages to the user.
Never store tokens in project files like CLAUDE.md that may be committed to version control. Use the user-scoped config directory ~/.config/jetty/.
Read secrets interactively with read -rs so the raw value never appears in generated commands, tool-call logs, or shell history.
Never ask the user to paste provider API keys (OpenAI, Anthropic, Gemini, Replicate) into this skill. Those keys belong in the Jetty web app under Settings → Environment Variables. This skill only handles the Jetty API token itself.
Pick your path
First, check whether they're already set up. Look for a token at ~/.config/jetty/token (and, for backward compatibility, a mlc_ line in the project's CLAUDE.md). If one exists, validate it:
API base: all Jetty API calls go to https://flows-api.jetty.io by default. To point at a non-default Jetty backend, put its URL in ~/.config/jetty/api_base — every $API below reads it. A token minted against one backend is only valid against that same backend, so this must match where the token came from.
If it returns collection data (a returning user), skip the demo and go straight to the Build path (Step 1 handles the already-connected case). Otherwise, offer the choice.
Use AskUserQuestion:
Header: "Start"
Question: "🪽 Want to see Jetty run a quick example first, or go straight to building your own runbook?"
Options:
"Run the demo" / "Watch Jetty extract structured data from a set of PDFs — no account needed"
"Build my own" / "Connect my account and build a runbook now"
"Run the demo" → go to the Simulate path immediately below.
"Build my own" → go to the Build path (Step 1).
Simulate path: watch Jetty run an example
This runs a real, pre-built runbook — conference-abstracts — on Jetty's hosted demo, with no account and no token. It's the emulated jetty simulate conference-abstracts procedure (documented in MACHINE_CONTEXT.md at the repo root, if present). The whole thing talks to a public, rate-limited endpoint; you never handle a secret here.
If anything in this path fails — the request errors, the run doesn't finish in time, or the report can't be fetched — don't retry silently or block. Say something light ("🪽 Pelly's demo pond is busy right now — let's build your own instead") and fall through to the Build path (Step 1). The demo is a bonus, never a gate.
The whole demo is driven by one bundled helper, scripts/jetty_simulate.py, so
the user sees clean Pelly-voiced progress — not curl, polling loops, or JSON.
Do not run your own curl, background poll, or python3 -c rendering.
Claude Code collapses long command output. That's fine for the transient
progress ticks — but the report is the payoff, so present it in your OWN
message (see S1) as a clean summary, where it always renders in full rather
than being hidden behind a "+N lines" fold.
S1: Explain the example — then run it
Do these in order. S1.1 is a plain chat message you MUST send FIRST — before you
call AskUserQuestion, before any Bash. Do not call any tool until it's sent.
S1.1 — Send the message below now (required, verbatim). It teaches what the
demo does and, critically, gives the six source-PDF links the user opens to
follow along — that is the whole point of the demo. The helper does not print
these links anywhere, so if you skip this message the user never sees the PDFs.
This is the single most common mistake — don't make it:
🪽 Here's what you're about to watch — structured extraction.
Six conference-abstract PDFs, each laid out completely differently — two-column
vs. single-column, metadata in the header vs. the footer, authors listed vs.
buried in prose — go into a runbook that pulls them all into one clean JSON
schema: title, authors, affiliations, conference, keywords. Every value carries
a provenance pointer — the page and the exact quote it came from — so nothing
is a black box. You get one JSON file per PDF plus a roll-up CSV to check
everything at a glance. That's the core Jetty pattern: messy documents in,
structured and verifiable data out — the same reliable job, every time.
Open the source PDFs and follow along — compare them to what Jetty pulls out:
S1.2 — Only after you have sent the S1.1 message, offer to name the workspace
(optional, low-friction). Use AskUserQuestion:
Header: "Workspace"
Question: "🪽 Before I run it — what should your workspace be called? Pick a name or let me generate one. It becomes your workspace's URL and API identifier, so only letters, numbers, hyphens, and underscores are allowed."
Options:
"Generate one for me" / "Auto-name my workspace"
"Let me choose" / "I'll type a name"
If they choose a name, pass it via --name "<their-name>". The name is the
workspace's permanent identifier, so it must be 3–48 characters of letters,
numbers, hyphens, and underscores — no spaces, and no leading, trailing, or
repeated separators. The helper validates this and exits with DEMO_STATUS=invalid_name
if it doesn't fit; when that happens, relay its message and ask for a different
name rather than retrying the same one. If they pick "Generate one for me", run
with no --name.
S1.3 — Run the demo. Locate and run the helper in one shell (this resolves the
script whether it's a plugin install or a project skill):
PY="$(command -v python3 || command -v python || true)" # empty → no Python; use Build path
# Locate the bundled helper across runtimes: env-var fast path (whichever runtime
# sets one), else search the known skill-install dirs for Claude Code, OpenCode,
# Codex, and Antigravity, plus project-local .{claude,opencode,codex}.
SIM="$(for r in "$CLAUDE_PLUGIN_ROOT" "$CODEX_PLUGIN_ROOT" "$OPENCODE_PLUGIN_ROOT"; do
f="$r/skills/jetty-setup/scripts/jetty_simulate.py"; [ -f "$f" ] && { echo "$f"; break; }
done)"
[ -n "$SIM" ] || SIM="$(find ~/.claude/plugins ~/.config/opencode ~/.codex ~/.gemini/antigravity .claude .opencode .codex -path '*jetty-setup/scripts/jetty_simulate.py' 2>/dev/null | head -1)"
"$PY" "$SIM" run # or: "$PY" "$SIM" run --name "my-workspace"
It streams 🪽 Step 1/6 … 6/6 progress (this may collapse in the terminal —
that's fine), then prints the report (a summary + per-document results + a CSV
preview), and ends with an internal DEMO_STATUS=completed / DEMO_STATUS=failed
marker line.
DEMO_STATUS=completed → present the report to the user as a clean
rendered summary in your OWN message so it's fully visible (the command output
may be collapsed). Lead with the headline — e.g. "✅ Pelly Approved — extracted
6 conference abstracts, every value traced to its source, 6/6 provenance-verified"
— then show the per-document results and mention the roll-up CSV. The report text
is in the helper's output (also saved to the file the helper wrote, if you need
to re-read it). Do NOT show the DEMO_STATUS= marker line to the user — it's
only for you. Go to S2.
DEMO_STATUS=failed (or the command errors) → the helper already printed a
friendly line; don't retry. Say "Let's build your own instead" and fall
through to the Build path (Step 1). The demo is a bonus, never a gate.
S2: One email — report + workspace
"The only thing I'll ask in return is an email. I'll send the report there and
set up your Jetty workspace from it — no sign-up form, no key to paste."
Ask for the email (a normal question — the one [HUMAN] step). When they give
it, run the helper's claim (same resolution one-liner). Put the address on the
<their-email> line of the quoted heredoc below — and nowhere else. The quoted
'JETTY_EMAIL' delimiter makes the heredoc body literal, so the shell never
expands anything inside the address; command substitution captures that literal
text and passes it as the --email value. An email containing $(…), backticks,
or a '/" can't run a command or break out. Do not instead interpolate the
email into a quoted argument (--email '…' or --email "…") — a ' or $(…) in
the address would break the quoting and could execute.
PY="$(command -v python3 || command -v python || true)"
# Locate the bundled helper across runtimes: env-var fast path (whichever runtime
# sets one), else search the known skill-install dirs for Claude Code, OpenCode,
# Codex, and Antigravity, plus project-local .{claude,opencode,codex}.
SIM="$(for r in "$CLAUDE_PLUGIN_ROOT" "$CODEX_PLUGIN_ROOT" "$OPENCODE_PLUGIN_ROOT"; do
f="$r/skills/jetty-setup/scripts/jetty_simulate.py"; [ -f "$f" ] && { echo "$f"; break; }
done)"
[ -n "$SIM" ] || SIM="$(find ~/.claude/plugins ~/.config/opencode ~/.codex ~/.gemini/antigravity .claude .opencode .codex -path '*jetty-setup/scripts/jetty_simulate.py' 2>/dev/null | head -1)"
"$PY" "$SIM" claim --email "$(cat <<'JETTY_EMAIL'
<their-email>
JETTY_EMAIL
)"
This mints the workspace, activates the trial, sends one email (the report +
a link to claim the workspace in a browser), and stores the token at
~/.config/jetty/token — printing only a redacted form. Relay its output.
SIGNUP_STATUS=completed → the token is saved and the trial is active.
Go to S3.
SIGNUP_STATUS=failed → don't block; fall through to the Build path.
If they'd rather not share an email, that's fine — skip claim and offer the
Build path.
S3: Stop here — this is the finish line
Do NOT automatically invoke /create-runbook or the Build path. The demo is
done and the user is set up. Offer the next step as an explicit choice via
AskUserQuestion:
Header: "Next"
Question: "🪽 You're all set. Want to build a runbook for your own data now, or stop here?"
Options:
"Build my own runbook" / "Start the runbook wizard"
"I'm good for now" / "Stop here — I'll come back later"
Only if they pick Build my own runbook, hand off to /create-runbook (skip
Step 2 — keys/trial are already set up). Otherwise, end warmly and point them at
https://jetty.io where their workspace and this run are waiting.
Security: the helper writes the token to ~/.config/jetty/token and only
ever prints a redacted form. Never echo a raw response or a full key yourself.
Build path: connect and build your own
Step 1: Connect Your Jetty Account
1a: Check for an Existing Token
Check ~/.config/jetty/token and, for backward compatibility, the project's CLAUDE.md for a line containing a token starting with mlc_. If found in CLAUDE.md but not in ~/.config/jetty/token, migrate it and remove that line from CLAUDE.md.
If validation fails (401 or error), let them retry up to 3 times. If still failing, point to https://jetty.io/settings.
On success, parse the response for the collection name (save it as COLLECTION for Step 2). Tell the user:
"Connected. Token saved to ~/.config/jetty/token (user-scoped, won't be committed to git). Your collection {name} is live at https://jetty.io — you can open it in your browser anytime."
If CLAUDE.md still has an old mlc_... line, remove it.
Step 2: Add AI Provider Keys in the Web App
Runbooks need API keys to reach AI providers (OpenAI, Anthropic, Gemini) and any other services your workflows call. Those keys live server-side in your Jetty collection's environment variables — you add them once in the web app and every workflow/runbook in that collection can use them.
OPENAI_API_KEY — for OpenAI models (GPT, DALL-E) — get one
ANTHROPIC_API_KEY — for Claude models, and for running Claude Code as the agent runtime — get one
GEMINI_API_KEY / GOOGLE_API_KEY — for Gemini models, and for the Gemini CLI agent runtime — get one
Plus any other service keys your runbooks need (Snowflake, Langfuse, etc.)
Come back here when you're done and I'll verify them
open "https://jetty.io/settings" 2>/dev/null || xdg-open "https://jetty.io/settings" 2>/dev/null
Wait for the user to confirm they're done. Use AskUserQuestion:
Header: "Keys"
Question: "Have you added your keys at jetty.io → Settings → Environment Variables?"
Options:
"Yes, keys added" / "Verify the keys are configured"
"Skip for now" / "I'll add keys later — continue to the runbook wizard"
If "Yes, keys added": re-run the check from 2a and list the configured key names (never values). Confirm which runtime keys are present. If the user added keys but the check shows nothing, they may not have saved them — ask them to verify in the web app and re-check.
If "Skip for now": warn that runbooks won't execute without keys, and continue.
Step 3: Build Your First Runbook
This is the part that matters — your account exists to run runbooks. Hand off to the /create-runbook skill now.
Tell the user:
"You're connected. Now the main event: building your first runbook. I'm handing you to the runbook wizard, which will:
Ask what task you want to automate (or show example tasks if you want inspiration)
Pick the right evaluation pattern (rubric scoring or programmatic checks) and sandbox for you
Scaffold a RUNBOOK.md with your task, parameters, evaluation criteria, and output manifest
Pre-register the task on Jetty with file-upload support so you can drop in CSVs/PDFs/images at run time
Hand you a single command to deploy it to Jetty (Claude Code on Sonnet 4.6 via OpenRouter) and run it for real
When you eventually trigger the runbook, you'll watch the trajectory appear live at https://jetty.io — every step, input, and output captured for replay and grading."
Then invoke /create-runbook. If the agent platform doesn't support skill invocation, tell the user:
"Run /create-runbook to start building your runbook."
What's Next (show after the handoff completes, or if the user returns later)
Useful commands:
/jetty run-runbook <path> — run a runbook on Jetty
/create-runbook — build another runbook
/optimize-runbook — analyze past runs and suggest improvements
/jetty list tasks — see everything in your collection
Live trajectories for every run (step-by-step replay)
Settings → Environment Variables for managing provider keys
Settings → API Tokens for managing Jetty tokens
Important Notes
Read the token from file: Use TOKEN="$(cat ~/.config/jetty/token)" at the start of each bash block. Environment variables don't persist across bash invocations.
Never log credentials: Don't echo, print, or include tokens/keys in output. Use redacted forms like mlc_...xxxx.
Read secrets interactively via read -rs: Never embed secrets in generated commands, heredocs, or temp files. Always unset after use.
Provider keys go in the web app, not this skill. The only secret this skill handles is the Jetty API token itself.
URL disambiguation: API calls go to flows-api.jetty.io (overridable via ~/.config/jetty/api_base — resolved into $API in each block); jetty.io is the web frontend. A token is only valid against the backend that minted it, so $API must match where the token came from.
Trajectories response shape: The list endpoint returns {"trajectories": [...]}.
Steps are objects, not arrays: Trajectory steps are keyed by step name (e.g., .steps.expand_prompt), not by index.
Account or credentials required
You'll need access credentials, such as an API key or token.
🔌 This skill ships inside the Jetty plugin. Listed package contents include an MCP server. Installed components and skill versions may vary by AI tool.
Install just this skill
Run this outside your AI tool, using Node.js 22.20.0 or newer. Skills CLI 1.7.2 skips skill selection; prompts cancel installation without an interactive terminal. If choosing Project when asked about installation scope, open your project's folder before running this.
Install checklist
Check selected tools if a picker appears; Claude Code may be unchecked under Additional agents. ↑/↓ moves, Space toggles selections, Enter confirms.
Without a tool picker, check Installing to: for your intended tool. Stop if it names a different tool.
If asked, choose Symlink (Recommended) for shared files or Copy to all agents for separate copies; review the summary before confirming installation.
Install the find-skills skill? defaults to Yes, adding another skill for all projects. Choose No if you don't want that extra installation.
Skills CLI 1.7.2 sends install data to skills.sh by default, including the source, skill names, target tools and file details; GitHub sources are reported only when GitHub confirms the repository is public, while other remote sources can also be reported. Confirmed-public GitHub sources also trigger a security-audit request. Before installing, set the environment variable DO_NOT_TRACK=1 or DISABLE_TELEMETRY=1 to disable both.
After installing for Claude Code, open it in the installation project if you chose Project; Global makes the skill available across projects on this computer. Once Claude Code loads the skill, its description helps Claude decide when to use it.
If installation created a top-level skills folder that did not exist when your Claude Code session started, run /reload-skills in that session. Run it again after later changes in that folder.
Install the whole plugin
This route installs the Jetty plugin package selected for your AI tool.
CLAUDE CODE
Add the plugin's marketplace, then install it
Install Claude Code first to get the claude command, then run the commands below in your terminal, outside a Claude Code session.
claude plugin marketplace add jettyio/jettyio-skills
claude plugin install jetty@jetty
Create a new runbook with guided assistance. A runbook is a structured markdown document that tells a coding agent how to accomplish a complex, multi-step task with evaluation loops and quality gates. Use this skill whenever the user wants to create, build, scaffold, or write a runbook — including 'create runbook', 'new runbook', 'build a runbook', 'make a runbook', 'runbook wizard', 'help me write a runbook', 'I need a runbook for...', 'automate this task with a runbook', or 'turn this into a runbook'. Also trigger when the user describes a multi-step agent task that would benefit from structured evaluation and iteration loops, even if they don't use the word 'runbook' — for example, 'I want to build an automated pipeline that evaluates its own output' or 'create a repeatable process with quality gates'.Read full description
Manage Jetty workflows and assets. Use when the user wants to create, edit, run, deploy, debug, or monitor AI/ML workflows on Jetty. Also use when they mention collections, tasks, trajectories, datasets, models, labels, step templates, or workflow runs. Triggers include 'run workflow', 'create task', 'list collections', 'check trajectory', 'label trajectory', 'add label', 'deploy workflow', 'show results', 'download output', 'debug run', 'workflow failed', or any Jetty/mise/dock operations. Even if the user doesn't say 'Jetty' explicitly, use this skill whenever they're working with Jetty API endpoints, workflow JSON, or init_params.Read full description
Analyze previous Jetty workflow runs and propose targeted improvements to your runbook. Use when the user wants to optimize, improve, or debug a runbook based on past execution results — including 'optimize runbook', 'improve runbook', 'why is my runbook failing', 'analyze my runs', 'runbook not working well', 'make my runbook better', 'debug runbook performance', or 'learn from past runs'. Also trigger when the user mentions trajectory analysis, run patterns, or evaluation score improvements.Read full description