Agent skills & updates
Install jurniti's agent skills into Claude Code or Codex with jurniti skills install — open SKILL.md format. Keep both current with jurniti upgrade.
Agent skills
Skip this page if you only use the web dashboard. Skills are for when your coding agent (Claude Code, Codex, …) should operate jurniti the way a human would in the terminal.
jurniti ships its workflows as Agent Skills — the open SKILL.md format
those agents already understand: provision agents, capture templates, fork
them, run swarms.
The skills are embedded in the jurniti binary itself — no separate registry,
always matching the CLI version you're running:
jurniti skills install # Claude Code (~/.claude/skills)
jurniti skills install --target codex
jurniti skills install --dir <path> # any agent that reads SKILL.md dirs--dir points the install at any other harness's skills directory — the
format is the ecosystem-standard one, so any agent that loads SKILL.md
folders can use them.
Staying current
The CLI checks for new releases at most once a day and prints a one-line
notice on stderr when one exists. The notice never appears in --json output,
in CI, in non-interactive shells, or when you opt out:
export JURNITI_NO_UPDATE_CHECK=1Nothing is ever installed without your say-so. When you're ready:
jurniti upgradeupgrade downloads the release, verifies its checksum and its minisign
signature against a key built into the binary (it refuses anything unsigned or
tampered), swaps the binary atomically, and then re-syncs any skills it
previously installed so their content matches the new version. Skills you've
modified yourself are never overwritten.
For agents and scripts:
jurniti upgrade --check --jsonexits 0 whether you're up to date, an update exists, or the check couldn't
complete — the answer lives in the JSON (update_available: true | false | null), so a skill or pipeline can run it unconditionally. The bundled skills
do exactly that at the start of a session and will ask you before ever
upgrading; an agent should never run jurniti upgrade --yes on its own.
Telling yourself a scheduled run finished
An agent that runs on a schedule and finishes quietly is indistinguishable from one that never ran. Both leave you with nothing in your inbox, and "no news is good news" is exactly backwards — the failures that bite are the silent ones: a run that never fired, one that died in step two, one that skipped its last step.
Your agent can email you its own run receipt using jurniti's sender, so you do not have to run a mailer inside the box or give it email credentials.
One-time setup
The box needs a read-write API key and its own VM id. Nothing is injected for you — set both from your machine, once per agent:
jurniti keys issue --read-write --label run-notify # prints the key once
jurniti env set <vm> JURNITI_API_KEY=<the key>
jurniti env set <vm> JURNITI_VM_ID=<vm>jurniti env set writes into the harness's dotenv inside the guest, so the
agent picks both up on its next run.
A read-write key is not scoped to notifications
A read-write key can do everything the API allows on your account, not just
send notifications. Treat putting one inside a VM as a deliberate decision, and
revoke it with jurniti keys revoke if the box is ever shared or captured into
a public template.
Sending the receipt
curl -sS -X POST https://api.jurniti.com/v1/api/vms/$JURNITI_VM_ID/notify \
-H "Authorization: Bearer $JURNITI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"subject": "Content run 2026-08-02",
"status": "ok",
"body": "# Content run\n\n## STATUS: ok\n\n1. Three drafts queued.\n\n## NEEDS APPROVAL\n\n1. `hub-2026-08-02.md`"
}'| Field | |
|---|---|
body | Required. The receipt, as markdown. Rendered to formatted HTML for you — headings, tables, lists and code all survive into the email. Up to 64 KB; larger returns 413 body_too_large. |
status | ok (default) or failed. A failed run gets a FAILED: subject prefix so it is legible in an inbox list without opening it. |
subject | Optional; defaults to Scheduled run on <agent name>. |
It always goes to your own account email — there is no recipient field, and one cannot be added. That is deliberate: jurniti's sending domain is shared by every customer's magic links and receipts, so an endpoint that let a box name an arbitrary recipient would put everyone's deliverability at the mercy of one compromised agent. Forward from your own inbox if you want it elsewhere.
Notifications are limited to one per five minutes per agent — per VM, not per account, so a fleet of scheduled agents all report normally.
The call needs the read-write key. It returns 200 only when the mail was actually accepted. A 502 means
it was not sent, and a 503 means this deployment has no mailer configured;
treat either as a failed step rather than logging success.
Send it even when the run failed
The receipt is only useful if it is unconditional. Write it from a trap so a run that dies partway still reports:
notify() {
jq -n --arg s "$1" --arg sub "$2" --rawfile b "$3" \
'{status:$s, subject:$sub, body:$b}' |
curl -sS -X POST "https://api.jurniti.com/v1/api/vms/$JURNITI_VM_ID/notify" \
-H "Authorization: Bearer $JURNITI_API_KEY" \
-H 'Content-Type: application/json' --data-binary @-
}
trap 'notify failed "Run died early" /tmp/receipt.md' ERRAnd treat a missing receipt as a failure, not just a failed one. A run
that never fired sends nothing at all, so waiting for a failure message catches
none of the three silent cases.
Communication
Connect a self-hosted Buzz relay to agents from the CLI or MCP, buy the relay in the dashboard, Open Buzz in the browser, and join as a human via Buzz desktop.
CLI Reference
Every verb the jurniti CLI ships — rendered from the binary's own command registry, so it can never drift from what you actually run.