Asking people
A Hug is a request a run makes of people while it is running: approve this plan, send it back, upload the guest list, tell me which customer this is about. Every way a team asks a person goes through the same Hug framework, so a review gate, an agent’s question and an LLM’s ask_human call all look the same to the people answering and behave the same while the run waits.
How it works
- CliqHub stores the Hug, sends it to its channels, checks who may answer, validates answers against the requested inputs, stores uploaded files, sends reminders and expires the Hug. It never interprets an answer.
- cliqd carries Hugs between the phase and CliqHub. It keeps every event, so a phase that stops or a cliqd that restarts picks up where it left off.
- The phase (through cliq-sdk) decides what the answers mean — the policy: the first answer is enough, every reviewer group must approve, and so on.
cliq run asks the question in the terminal.
Three ways to open a Hug
A run never asks for its own missing inputs: inputs are checked when the run starts, and a phase that still lacks one fails with
Phase 'x' is missing inputs: a, b — supply them when starting the run.
Example 1 — an approval gate
The most common Hug: a person reviews the work and approves it, sends it back to an earlier phase, or rejects it.note field and an optional comment. What each answer does:
The first answer that isn’t an approval decides. A round is one review: sending the work back and reviewing it again is round 2.
Gate review fields
Example 2 — collect a file in the review
A review can ask for files. The files stay in storage (CliqHub, or cliqd’s own store for a terminal answer); a later phase saves the ones it needs withcliq hug files.
cliq hug files human-review guest_list guests/ saves each file as guests/<responder>-<file name> (a second file of the same name gets -2) and writes guests/files.json saying who sent what:
- Inside a phase,
cliq hug filesuses the run it is running in, and the folder must be inside the workspace. Outside a phase, name the run with--run(and-wfor another workspace). - No matching file is not an error: the folder gets an empty
files.json. A phase or input that has no files at all is (HUG_FILES_NOT_FOUND), and the error lists what the run does have — so a typo is caught. - Every file is checked against its size and SHA-256 before it is written, and written atomically.
$CLIQ_RUN_DIR/hug-files.json (<workspace>/.cliq/runs/<run_id>/hug-files.json), which cliqd keeps up to date as answers arrive.
Example 3 — run @cliq/hug-example
@cliq/hug-example is a built-in team that shows a review collecting a file. A planner writes a party plan, a reviewer approves it and uploads the guest list, and the next phase writes one invitation per guest plus a shopping list.
1. Save this as guests.csv — you will upload it in the review:
The team keeps its parsing simple: the first line is a header (always skipped), names are in the first column, and names must not contain commas (quoted fields aren’t handled —
"Smith, Jo" would be cut at the comma). Blank lines and duplicates are dropped. The file must be a .csv of at most 1 MB.- Signed in to CliqHub: you get a notification; open the Hug from it or from HUGs in the sidebar. Read
plan.md(Preview), pick Approve, uploadguests.csv, and Submit response. - Local cliqd (not signed in):
cliq runasks in the terminal. Chooseapproveand give the path toguests.csv.
invitations phase saves the file with cliq hug files human-review guest_list guests/ and writes:
invitations. Because the guest list is required, the form asks for a file whatever you decide.
@cliq/hello-world is the smallest Hug: an exec phase writes review.txt, a gate (agent: hug, 60-minute timeout, policy: any) asks you to approve it, and a final phase runs on approval. It is the team Get started runs.
Example 4 — an agent asks a person
An agent written with cliq-sdk asks withctx.ask. The phase’s hug: block in team.yml says where its questions go, how long they stay open and how often people are reminded (from examples/hello-ask in the cliq repo):
ctx.ask returns { values, responses, … }. With the default policy, values are the first answer’s values keyed by input name. It throws when the Hug ends without a result:
All extend
HugError. Uncaught, they fail the phase.
ctx.ask options
Example 5 — several reviewers, and letting the agent stop while waiting
wait: 'yield' the agent’s process ends, the phase and run show awaiting_input, and cliqd starts the phase again when the Hug has news (an answer, its expiry or its cancellation). The SDK finds the same Hug again — it is never asked twice — and ctx.ask returns or throws as if it had waited. With wait: 'block' (the default, and what the review gate does) the run stays running.
Either way the phase never times out while it waits for people: its timeout stops counting while any of its Hugs is open and resumes, with the time that was left, when they end. The Hug’s own expiry bounds the wait instead.
For full control, open Hugs yourself with ctx.hug.open(spec, { state }) and wait on several with ctx.wait({ sessions, state }).
Example 6 — read uploaded files in agent code
The same catalogcliq hug files reads is available to agents:
ctx.hug_files({ phase, input, round?, responder?, include_replaced? }) takes the same choices as the CLI (round: 'latest' (default), 'all' or a number). ctx.download(ref) returns a readable stream; ctx.download(ref, dest) saves to a path inside the workspace and returns { path, size, sha256 }. Both read through cliqd, wherever the file is stored, and retry for up to two minutes if cliqd is restarting.
Example 7 — an LLM agent asks
Agents that drive a model (LLM and CLI agents) can ask people without any code:- the
ask_humantool, when the model supports tools; - a fenced
cliq_hugblock with the same JSON asctx.ask(title,prompt,requested_inputs); - a final line
QUESTION: <text>, which becomes a one-field text question.
wait: 'yield'), and use the phase’s hug: block for channels, expiry and reminders. The answer comes back to the model as the next turn.
Requested inputs
Each requested input is one field in the form. Every input hasname (lowercase letters, digits and _, starting with a letter), and optionally label, help, default and required — required defaults to true. At most 50 per Hug.
The review gate’s
review.inputs use friendlier names that map onto these:
The gate adds its own
decision and comment fields; those two names are reserved.
Files are checked against accept by declared type, extension and their first bytes, and against max_bytes and the server limit (CLIQ_ARTIFACT_MAX_MB, default 50 MB) — an input can lower the limit, never raise it.
Who is asked, and who may answer
- Channels say who is asked: a person (by username, or
me), or a shared channel your org set up (email, Slack, in-app…).{{inputs.x}}uses a run input — usually atype: channelinput. Unknown names raise anotification.unknown_channelevent; a Hug with no channel at all is refused. - Seeing a Hug needs
runs.viewin its realm. Answering also needs it to be addressed to you — through your own channel or a shared channel it was sent to. Being asked grants nothing: a person reached by a channel who can’t view the realm’s runs is skipped, shown as “Not sent to …” on the Hug page, and raisesnotification.no_access. If nobody left can answer, the Hug is refused (no_one_can_answer). - Changing an answer: a person can submit again while the Hug is open; their latest answer counts. Files from the earlier answer stay in the catalog with
current: false(--include-replaced/include_replacedto see them). - Several people: each answer goes to the phase as it arrives; the policy decides when it’s complete —
any()on the first answer,groupswhen every group is satisfied, or your owncustom(fn).
Answering
On CliqHub
Each Hug has a page at/hugs/<hug id>, linked from its notifications and from HUGs in the sidebar (its badge counts open Hugs addressed to you that you haven’t answered yet; the HUGs page has Waiting and Done tabs). The page shows:
- who it was sent to, when it opened and when it expires;
- the title and prompt;
- the run’s workflow — click a phase to see its output;
- the context: attached files as a list (Preview opens a dialog, with ‹ › to move between files; open in a new tab or download), notes and check results;
- Your response: required fields first, then optional ones, and Submit response. Files upload as you pick them.
In the terminal
With a local cliqd that isn’t signed in to CliqHub,cliq run asks each requested input in the terminal and checks it as you type. For a file input, give a path: the file is checked against accept and max_bytes, and cliqd keeps it in its own file store (~/.cliqrc/artifacts/<run_id>/, or CLIQ_ARTIFACTS_DIR) — the answer holds a reference, nothing is left in the workspace. Not at a terminal, cliq run prints the question instead.
Lifecycle
- Reminders go to people who haven’t answered, every
remind_every/reminders.every_min. - When a run ends, its open Hugs are cancelled.
- If cliqd restarts while a run waits on a Hug, the run is picked up again and its phase finds the same Hug — nobody is asked twice (root runs; a sub-team’s run can’t be re-attached and is marked crashed). cliqd catches up on anything that happened while it was down.
Defaults and limits
Notifications and events
A new Hug is sent straight to its channels (“Input requested”). The rest are events you can route with notification rules —hug.* matches them all:
For example, tell the release channel whenever a review expires:
hug.opened, hug.responded, hug.closed, hug.expired, hug.cancelled, and phase.waiting / phase.resumed when a phase stops and starts again around a Hug.
APIs
- CliqHub (Hub API › Hugs):
hugs/get(your Hugs, by realm or org),hugs/get_by_id,hugs/respond(answer one).hugs/create,hugs/closeandhugs/get_eventsare for daemons. Errors:HUG_EXPIRED(410),HUG_CLOSED(409),invalid_values(422 — an answer that doesn’t fit the requested inputs). - cliqd (Daemon API › Hugs):
hugs/open,hugs/next,hugs/save_state,hugs/closefor agents (cliq-sdk calls these for you),hugs/deliverfor CliqHub, andhugs/respondfor terminal answers. Errors:HUG_NOT_FOUND(404),HUG_CLOSED(409),HUG_EXPIRED(410),HUG_REFUSED(422).
Related
- Phase types and gates → Workflows & phases
- Writing agents that ask → Building agents
cliq hug filesandcliq run→ CLI- Who can see runs → Auth