SparkUAPIExperimentalllms.txtРусский

Sections · 8/11

Questions to User

POST …/dialogs and sparku ask — options, confirmation, timeout, attachment; how an agent asks for permission.

Markdown ↗

How it works#

POST /v1/integrations/{slug}/dialogs shows a question on the island and keeps the connection open until the user answers (or the question is withdrawn). The answer comes in the body of the same HTTP response — curl or an HTTP client that doesn't close the connection early needs to wait for timeout from the request body.

An integration can have at most one unanswered question at a time: a second dialogs before an answer to the first gets 409 dialog_pending. Dialogs must be explicitly enabled in the integration settings.

Request body#

A question with options — has options or custom:

{
  "message": "Deploy to prod?",
  "title": "Deploy",
  "options": ["yes", {"id": "no", "label": "Cancel", "detail": "do nothing"}],
  "multiple": false,
  "custom": false,
  "timeout": "10m"
}

Confirmation — no options or custom:

{"message": "Delete branch feature/x?", "accept": "Delete", "decline": "Keep", "comment": true}
Field Type Default Rule
message string — required, up to 600 characters
title string integration address up to 60 characters
options array of strings or {id, label, detail?} — up to 9 options; string is both id and label
multiple bool false select multiple — requires ≥ 2 options
custom bool false add free-text answer field
accept / decline string "Yes" / "No" confirmation button labels, up to 30 characters
comment bool false allow comment on decline
timeout number of seconds or "90s" / "10m" / "2h" 600 (10 min) 5 seconds to 1 day
attachment absolute path — file the user can open from the question; must exist

With options or custom — a question with options; otherwise — a confirmation with two buttons. You can't specify both options/custom and accept/decline — accept/decline apply only to confirmation.

Answer#

Always 200 OK; the response body depends on the outcome:

Situation Body
selected option(s) {"answer": "chose", "options": ["yes"]}
custom answer {"answer": "custom", "text": "…"}
accepted {"answer": "accepted"}
declined {"answer": "declined"} or {"answer": "declined", "comment": "…"}
timeout expired {"answer": "expired"}
question withdrawn {"answer": "withdrawn"}

withdrawn is returned if: the client disconnects before answering (though then there's no one to answer — the question is just removed from the island), SparkU closes, the API is disabled, or the integration is disabled/deleted while a question is waiting for an answer.

To hide a question with the "Hide" button only works for an integration with a card — you can bring it back with the "Reply" button in the card; until then it remains unanswered on the server.

Example: curl#

curl --unix-socket ~/.sparku/run/api.sock \
  -H "Authorization: Bearer $SPARKU_TOKEN_DEPLOY" \
  -d '{"message": "Deploy to prod?", "accept": "Yes", "decline": "No"}' \
  http://sparku/v1/integrations/deploy/dialogs
{"answer": "accepted"}

sparku ask#

sparku ask <slug> "question" [-o id:label …] [--multi] [--custom]
           [--accept Yes --decline No --comment] [--title …] [--timeout 10m] [--attach file]
sparku ask deploy "Deploy to prod?" -o yes:Yes -o no:No
sparku ask deploy "Where to deploy?" -o prod:Prod -o staging:Staging --custom
sparku ask deploy "Delete branch?" --accept Delete --decline Keep --comment

Selected options are printed to stdout one per line (id, not label), custom answer as text, and the decline comment also to stdout.

Exit codes for ask#

Separate from <sysexits.h> used by push/end/doctor — so if sparku ask deploy "Deploy?"; then … works:

Code Meaning
0 answer received (choice or custom text — in stdout)
1 declined
2 timeout expired, question withdrawn, or "Hide", or SparkU closed

Transport errors (no socket, invalid token, 409 dialog_pending) return regular sparku codes — 69, 77, 69 respectively, see sparku CLI.

if sparku ask deploy "Deploy to prod?"; then
  ./deploy.sh
else
  echo "deploy cancelled"
fi

For AI agents#

An agent like Claude Code or Codex that runs commands in a shell can ask for permission the same way a CI script does: through sparku ask to an integration the user set up beforehand (for example, "Agent" with the slug agent; if it has a card, the question can be hidden and answered later). This is not a separate protocol — an agent is just another API client, like any other process.

if sparku ask agent "Delete branch feature/old and close its PR on GitHub?" \
     --accept Delete --decline "Don't touch" --timeout 90s; then
  git push origin --delete feature/old
  gh pr close 42
else
  echo "cancelled by user" >&2
  exit 1
fi

While a question is on the island, the agent blocks on the sparku ask call — this is expected: the user makes the decision, and the dangerous step can't run until they answer. If the user doesn't answer before --timeout, default 10 minutes, ask returns 2, and the agent should treat it as a refusal, not as permission to proceed.

TIP

The tool an agent runs commands with usually has its own timeout (2 minutes by default in Claude Code). Keep --timeout below it, otherwise the agent stops waiting before the user can answer, and the question is withdrawn from the island.

An instruction for the agent (in CLAUDE.md, AGENTS.md, etc.) can read:

Before irreversible actions (deleting, force-pushing, deploying, migrations), ask
the user: sparku ask agent "<what and why>" --accept Yes --decline No --timeout 90s
Exit 0 — go ahead, 1 — declined, 2 — no answer: treat it as declined.