JURNITI°docs

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=1

Nothing is ever installed without your say-so. When you're ready:

jurniti upgrade

upgrade 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 --json

exits 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
bodyRequired. 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.
statusok (default) or failed. A failed run gets a FAILED: subject prefix so it is legible in an inbox list without opening it.
subjectOptional; 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' ERR

And 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.

On this page