/agent/actions). Each is a file, actions/<name>.yaml. See Agent files for every key.
This page is about actions your server calls. Actions that run in the customer’s browser, registered by your website’s code, are page actions. The desk lists the ones it has seen under On your website, at the bottom of the Actions page.
How an action works
- The AI sees each action’s name and What it does and decides whether the customer’s message needs it.
- It asks the customer for any required detail it doesn’t have yet (like an order number), then calls the action with those details.
- The desk builds the request: your address with the details filled in, your headers and keys, and for a change, a JSON body.
- The customer sees only the action’s status line, like “Checking your order”, never the action’s name, inputs or result.
- The AI gets the response (only the fields you pick, at most 4,000 characters) and answers from it. If the action has a widget, the customer sees the result as a card.
- Agents see every call in the conversation’s audit log.
Create an action
1
Press New action
On Agent → Actions.
2
Say what the AI should be able to do
For example “Look up an order by its number and tell the customer where it is”.
3
Paste a curl command (optional)
Under How does your system do it?, paste a curl command from your API docs, or describe the request in a few words. No API yet? Leave it empty.
4
Check the name and press Set it up
The name is made from your description, like
look_up_order: lowercase letters, digits and underscores. handoff, flag_problem, jun_done, activate_skill and show_widget are taken by the AI’s own tools.What the desk reads from a curl command
A curl command is read on the desk, without the AI, and the dialog shows what it found:- Method, address, query, headers and a JSON body go into the action.
- Keys never go in the file. An
Authorizationheader, anx-api-key(or any header ending inkey,tokenorsecret) and-u user:passwordbecome{secrets.NAME}, named after the host (api.acme.com→ACME_API_KEY). The key itself is saved on the desk. A stand-in like$API_KEYor<your-token>gets a key name for you to add on the action’s page. - Keys in the address are left out, with a note: the desk sends keys only in headers. Ask your developer whether the API takes it as a header.
- Only GET and POST.
PUT,PATCHandDELETEbecome POST, and so does a GET with a body. Form fields are sent as JSON.-ubecomes anAuthorizationheader. Anhttp://address becomeshttps://. File uploads (-F) aren’t supported.
The action’s page
The page has AI and Code tabs on the left and the form on the right. At the top of the form, Connected links the action to the tasks and widgets that use it.Form fields
text
required
The
description. The AI reads it to decide when to use the action, so say what it returns or changes. For example “Finds an order by its number and returns its status and delivery date.”string
default:"Looking that up"
The
status line, like “Checking your order”. One line of plain text, up to 60 characters, no placeholders.GET | POST, URL
Look up (GET) or Make a change (POST), and the address. Put details the AI fills in inside braces:
https://api.acme.com/orders/{order_id}. Your developer can give you this address.An action that only shows a widget can leave the address empty: it calls nothing and draws the widget from its example data and the AI’s inputs.list
The action’s inputs: what the AI needs from the customer (or the chat) before it can run it. Each has a name, a type (Text, Number, Whole number or Yes or no), a description the AI reads, and Required (on by default). Renaming a detail renames its
{placeholder} in the address and query too.map
Sent with every request, like
Authorization: Bearer {secrets.API_KEY}.map
Added to the address after the
?, like email: {email}. Empty values are left out.list
The
pages list. See Offer an action only on some pages.string
The
widget that shows a successful result as a card. Without one, the AI describes the answer in words.string
The
widget_done line, for when a widget’s button runs this action. See Done and failed lines.string
The
widget_failed line.body (a POST’s JSON body template), pick (the top-level fields of a JSON response the AI gets) and mock (a canned response for jun eval --mock-tools and the task test chat’s safe mode).
A complete action
Thelookup_order example from jun init:
actions/lookup_order.yaml
This example still points at
api.example.com, so the desk flags it as not set up until you change the address. See Setup problems.Placeholders
Every{placeholder} in the address, query, headers or body must be one of these:
Key names are
UPPER_SNAKE_CASE. Secrets in the address or query are refused, because addresses end up in logs.
For a POST without body, the details the AI filled in are sent as a JSON object. With body, its values are filled in; a value that is exactly "{param}" keeps the input’s type, so numbers stay numbers. The apply-offer example:
actions/apply_save_offer.yaml
Acting for the signed-in customer
{user.*} values come only from a verified identity token, never from the chat or the page’s JavaScript, so the AI can’t be talked into looking up someone else’s account. If the visitor isn’t signed in, the call fails and the AI is told to ask them to sign in or hand off.
{user.secrets.NAME} is for APIs that only accept the customer’s own key. The key is kept only until their token expires (or JunDesk.logout()), and never shown to agents, the AI or the prompt.
Keys
The Keys field lists each{secrets.NAME} the headers use and where its value comes from:
-
Set by your developer: the Worker secret
JUN_SECRET_<NAME>. It always wins. - Pasted on the desk: an owner or admin pastes the key and presses Save. It’s saved right away, kept in the workspace’s Durable Object storage (never in the agent’s files or the database), and only its last 4 characters are shown. Replace and Remove change it. A workspace can keep up to 50 keys this way.
-
The customer’s own (
{user.secrets.NAME}): from their sign-in, nothing to add here.
•••• if the API echoes it back, in what the AI reads and in the audit log. See Secrets.
Setup problems
An action that can’t work yet is never offered to the AI. Its card says Not set up, and its form starts with “The AI won’t use this action yet.” and the reasons:- The key NAME isn’t added yet. Paste it under Keys, or set the Worker secret.
- Its address is still an example (
example.com,example.orgorexample.net). - Its description is still the starter text, so the AI can’t tell when to use it.
--mock-tools still use such actions, with their mock responses.
Try it
Try it on the action’s page calls your draft of the action once, for real, with details you type. Use it before you save.- Type a value for each detail. An action made from a curl command starts with the command’s own values.
- If the action uses
{user.*}, type a test customer’s id, email, attributes or key. - Press Try it, or Run it for real for an action that makes a change (“This makes a real change in your system.”).
- Use as the widget’s example data, when the action already has a widget.
- Show it as this widget, which makes a first widget from the answer and links it to the action. Restyle it afterwards with the widget’s AI.
Offer an action only on some pages
Only on these pages (pages) offers the action only while the customer is on matching pages of your site:
/billingmatches exactly that path./orders/*matches anything starting with/orders/.
pages are offered.
Audit log
Every call the AI makes is recorded next to the conversation. In the inbox, the conversation’s side panel shows AI actions: each call’s action, inputs, output, status, HTTP status and duration, and which saved version of the agent made it (config v4). Request headers are never stored, so keys can’t show there. Calls made by a widget’s button are recorded the same way.
Only your team sees the log. Customers see only the status line while an action runs.
On your website
The bottom of Agent → Actions lists the page actions your website’s code registers (with WebMCP orJunDesk.registerAction). The AI runs these in the customer’s browser, with their own login. The desk never has their code: it lists what the loader reported when a customer chatted, with names, descriptions and the shape of the last result, never its values.
“None seen yet” means no customer has chatted on a page that registers them.
For each website action you can set:
auto | confirm | human
- Your site’s setting (default): what your code asked for.
- Runs without asking (
auto). - Asks the customer first (
confirm): the chat shows a summary and a Confirm button. - A person does it (
human): the chat is handed to your team instead.
string
The line shown while it runs, up to 60 characters, like “Setting your pickup”. Without one, a line is made from the action’s name.
string
Text (no widget), or one of your widgets. Every time it runs, its result shows as that widget. A widget picked here wins over one your site’s code names.
website-actions.yaml:
website-actions.yaml
Limits
Widgets
Show an action’s result as a card.
Tasks
Use actions in step-by-step jobs.
Page actions
Actions that run in the customer’s browser.
Identify users
Verified customers for
{user.*}.