Source: https://docs.specvista.com/assent.md # Assent documentation One inbox and one set of rules for every agent you run. Approve, decline or reply to Claude Code, Codex, scripts, CI and automations. Assent is one inbox and one set of rules for every agent you run. When an agent, script or scheduled job reaches a step it should not take alone, it sends you an ask. You answer from your phone or the web, and the agent picks up your answer and carries on. It works the same for every kind of agent: - **Claude Code.** A hook sends risky tool calls, such as `git push` or a deploy, to your inbox and blocks them until you allow them. See [Claude Code](https://docs.specvista.com/assent/claude-code.md). - **ChatGPT, Claude Desktop, Cursor, Codex and other MCP clients.** They connect to the Assent MCP server to ask you, wait for your answer and check your rules. See [Connect Claude, ChatGPT, Cursor or Codex](https://docs.specvista.com/assent/connect-an-assistant.md). - **Scripts and CI.** The [command line](https://docs.specvista.com/assent/cli.md) or one [HTTP request](https://docs.specvista.com/assent/api.md) sends an ask, and `assent ask --wait` holds a script or pipeline step until you answer. See [Scripts and CI](https://docs.specvista.com/assent/scripts-and-ci.md). - **Scheduled jobs and automations.** They report each run, ask when they need you, and pick up your answer on their next run, or straight away on a Mac or Windows computer you [pair with the helper](https://docs.specvista.com/assent/connect-a-computer.md). Your rules live in one place as well. Answer Always or Never on an approval, or add a rule on the web for one agent or for every agent, and it answers matching asks from then on. See [Rules](https://docs.specvista.com/assent/rules.md). ## What an agent can ask - **Approve or decline.** The agent says what it wants to do and why. Approve and it carries on, decline and it stops. - **Pick the items.** When an agent finds several things, it lists them. Keep the ones you want and it acts on just those. - **Reply with a draft.** You see the drafted reply first and change what you like. Send sends exactly that text. - **Enter a code.** When a sign-in sends you a one-time code, type it into the ask and the agent picks it up. - **Pay.** The agent stops at the payment and sends you the page. You pay yourself, then tell it you are done. - **Sign in.** The agent hands the sign-in to you. You sign in, then it carries on. See [Asks](https://docs.specvista.com/assent/asks.md) for every kind and option. ## Answer once, not every time - **Always and Never.** On an approval, tap Always or Never and choose how long it lasts. Until then, asks like it from that agent are answered for you. See [Rules](https://docs.specvista.com/assent/rules.md). - **Usual answers.** When you keep giving an agent the same answer, Assent says so above the buttons. See [Usual answers](https://docs.specvista.com/assent/usual-answers.md). ## How agents connect Anything that can send an HTTP request, run a command or call an MCP server can use Assent: Claude Code, Codex, scripts, CI jobs, scheduled jobs and automations. Each agent gets its own agent key. See [Connect an agent](https://docs.specvista.com/assent/connect-an-agent.md). ## Where you answer Everything works on the web. The [iPhone app](https://docs.specvista.com/assent/answer-from-your-phone.md) adds pushes the moment an agent needs you and answers from the lock screen. Answer buttons on the lock screen need Face ID or your passcode, and codes, payments and sign-ins open the app. See [Notifications](https://docs.specvista.com/assent/notifications.md). ## Access Assent is invite only for now, and sign-up is closed. To ask for access, email [hello@specvista.com](mailto:hello@specvista.com?subject=Access%20request) with the subject "Access request". If you have an invite, open the link in your email to create your account, then sign in on your phone or the web. ## For AI agents [Build with AI agents](https://docs.specvista.com/assent/agents.md) lists every entry point: `llms.txt`, Markdown pages, the MCP server, the command line, the helper and the HTTP API. --- Source: https://docs.specvista.com/assent/agents.md # Build with AI agents Every way an AI agent can use Assent, how a person gets access, safe ways to try it, and a rules snippet for your own repository. This page is for AI agents and the people who set them up. It lists every entry point, in the order most agents need them. ## Access comes first Assent is invite only, and sign-up is closed. An agent cannot create an account, and must never try to. - A person without an account emails [hello@specvista.com](mailto:hello@specvista.com?subject=Access%20request) with the subject "Access request". The **Request access** button at [assent.specvista.com/sign-up](https://assent.specvista.com/sign-up) opens the same email. - With an invite, they open the invite link from their email, create the account with the address the invite was sent to, and sign in on the web or in the iPhone app. - They then add an agent for you and give you its agent key. See [Connect an agent](https://docs.specvista.com/assent/connect-an-agent.md). ## Entry points | Entry point | Address | Use it for | |---|---|---| | `llms.txt` | [docs.specvista.com/assent/llms.txt](https://docs.specvista.com/assent/llms.txt) | The docs index, opening with instructions for agents | | `llms-full.txt` | [docs.specvista.com/assent/llms-full.txt](https://docs.specvista.com/assent/llms-full.txt) | Every docs page as one Markdown file | | Markdown pages | Add `.md` to any docs URL, for example [agents.md](https://docs.specvista.com/assent/agents.md) | Reading one page without HTML | | Product summary | [assent.specvista.com/llms.txt](https://assent.specvista.com/llms.txt) | What Assent is and where to start | | Remote MCP server | `https://ordia-api.specvista.com/api/v1/mcp` | Ask, wait for the answer, check rules, report runs. Streamable HTTP with the agent key as a bearer token, or OAuth for Claude, ChatGPT, Cursor and Claude Code. See [MCP server](https://docs.specvista.com/assent/mcp.md) | | Local MCP server | `assent mcp` | Clients that start MCP servers as a command, such as Codex and Claude Desktop | | Command line | `assent-cli` on npm, commands `assent` and `assent-cli` | Scripts, CI and scheduled jobs. See [Command line](https://docs.specvista.com/assent/cli.md) and [Scripts and CI](https://docs.specvista.com/assent/scripts-and-ci.md) | | Helper | `assent-helper` on npm | Pairing a Mac or Windows computer so Run now restarts an agent with the answer. See [Connect a computer](https://docs.specvista.com/assent/connect-a-computer.md) | | HTTP API | `https://ordia-api.specvista.com/api/v1` | Anything that can send HTTP. See [HTTP API](https://docs.specvista.com/assent/api.md) | | Claude Code hook | `assent hook claude-code install` | Sending risky Claude Code tool calls to the person first. See [Claude Code](https://docs.specvista.com/assent/claude-code.md) | Check what npm serves before you install or report a version: ```bash npm view assent-cli version npm view assent-helper version ``` Compare with `assent --version` and `assent-helper --version`. Both packages need Node.js 20 or later. There is no OpenAPI document and no agent skill to install yet. The rules snippet below plays the part of a skill. ## Which one to use - **An assistant that speaks MCP** (Claude Code, Claude Desktop, ChatGPT, Cursor, Codex): [Connect Claude, ChatGPT, Cursor or Codex](https://docs.specvista.com/assent/connect-an-assistant.md). - **A shell script, CI job or scheduled job**: [Scripts and CI](https://docs.specvista.com/assent/scripts-and-ci.md). - **An agent that should restart when the person answers**: pair its computer with [Connect a computer](https://docs.specvista.com/assent/connect-a-computer.md), then set the agent to **Run now**. - **The person answering**: [Answer asks from your phone](https://docs.specvista.com/assent/answer-from-your-phone.md). ## Safe ways to try There is no sandbox or test mode: every ask reaches a real person's phone. - `assent whoami` and `assent answers` only read. `assent rules check` tells you whether the person's rules allow an action, without notifying them. - A person who wants to see Assent before connecting a real agent can add the sample agent: **Try a sample** on the **Agents** page while it is empty, or **Try a sample agent** in **Connect**. It posts one approval, a few renewals and a small plan, never runs anything, and can be removed from the same place. - When you retry an ask, send the same `dedupeKey` (or `--dedupe`) or `Idempotency-Key` header, so the person sees one ask, not two. ## What agents never do - Answer an ask. Only the person can; there is no agent endpoint for it. - Put passwords, card numbers, bank details or one-time codes in an ask. `pay` and `login` asks carry only a link, and a `code` ask asks the person to type the code. - Print, log or commit an agent key (`oak_...`) or a computer key. - Pair a computer, or allow a resume command, without the person seeing it. `assent-helper allow --yes` skips the confirmation, so use it only when the person has approved that exact command. - Sign up, request an invite or accept terms on someone's behalf. ## Ordia Desk Ordia Desk is the Specvista notes and tasks app at [notes.specvista.com](https://notes.specvista.com). It uses the same account as Assent, and its own [llms.txt](https://notes.specvista.com/llms.txt) describes it for agents. - Agents can add to it: `assent_ordia_todo_add` and `assent_ordia_note_add` over MCP, `assent task add` and `assent note personal` on the command line. Note that the MCP tool `assent_task_add` adds a to-do in Assent, while the command `assent task add` adds one to Ordia Desk; `assent ask --kind todo` is the command line's Assent to-do. - Agents cannot browse or search Ordia Desk. They read only notes pinned as shared memory for them (`assent_memory`), projects the person linked them to (`assent project get` or `GET /agent/projects/{uuid}`), and items they created. ## A rules snippet for your repository Paste this into `AGENTS.md`, `CLAUDE.md` or your editor's rules file so every agent working in the repository uses Assent the same way. ```markdown ## Assent Ask the person through Assent before any step you should not take alone, and act only on their answer. - Docs: https://docs.specvista.com/assent/llms.txt (every page also as .md). - The agent key is in ASSENT_AGENT_KEY. Never print, log or commit it. - Before a risky action, run `assent rules check --action --target `. Exit 0: go ahead. Exit 10: do not do it. Exit 11: ask. - To ask: `assent ask --title "" --why "" --rule-action --target --dedupe --wait --timeout 900`. Act only when `answer.actionId` is `done`. Exit 6 means no answer yet: stop and say so. - Never put passwords, card details or one-time codes in an ask. - If Assent is unreachable (exit 69), do not take the risky step; stop and report. ``` ## Errors The HTTP API answers errors as JSON with `statusCode`, `error` and a `message` that says what to change. MCP tools return `{"error": message, "status": code}` as a tool error. The command line prints `{"error": message, "exitCode": code}` on stderr and exits with a stable code. See [HTTP API](https://docs.specvista.com/assent/api.md#errors), [MCP server](https://docs.specvista.com/assent/mcp.md#errors) and [Command line](https://docs.specvista.com/assent/cli.md#exit-codes). --- Source: https://docs.specvista.com/assent/connect-an-agent.md # Connect an agent Add an agent, copy its key and send your first ask from Claude Code, Codex, a script, CI or any MCP client. Assent gives you one inbox and one set of rules for every agent you run. Each agent connects in the way that suits it: | Agent | How it connects | |---|---| | Claude Code | The [Claude Code hook](https://docs.specvista.com/assent/claude-code.md) for risky tool calls, and the [MCP server](https://docs.specvista.com/assent/mcp.md) for asks it decides to send | | ChatGPT, Claude Desktop, Cursor, Codex and other MCP clients | The [MCP server](https://docs.specvista.com/assent/mcp.md). See [Connect Claude, ChatGPT, Cursor or Codex](https://docs.specvista.com/assent/connect-an-assistant.md) | | Shell scripts and CI jobs | The [command line](https://docs.specvista.com/assent/cli.md), or the [HTTP API](https://docs.specvista.com/assent/api.md). See [Scripts and CI](https://docs.specvista.com/assent/scripts-and-ci.md) | | Scheduled jobs and automations | The command line or the HTTP API, with the [helper](https://docs.specvista.com/assent/connect-a-computer.md) on a paired Mac or Windows computer to restart them when you answer | Whichever way it connects, each agent needs its own agent key, except Claude, ChatGPT, Cursor and Claude Code, which can sign in with OAuth. You need an Assent account first; it is invite only (see [Build with AI agents](https://docs.specvista.com/assent/agents.md#access-comes-first)). ## 1. Add the agent Verify your email address first: Assent asks for it before you can add an agent. In Assent, open **Agents** and choose **Add agent** (on the web) or **Add an agent** (in the app). Give it: - **Name**, the name you see on its asks. - **What it does**, an optional line about the agent. - **Runs on**: Mac, Windows PC, Server or Cloud. - **Schedule**, optional, for example `daily 6:00`. - **When you answer one of its asks**: **Next run** waits for its next scheduled run. **Run now** restarts it on its computer straight away and needs the [helper](https://docs.specvista.com/assent/connect-a-computer.md) on a paired computer. Assent then shows the agent key, which starts with `oak_`. Copy it now: Assent shows it once. Give it to the agent as `ASSENT_AGENT_KEY`, and rotate it from the agent's settings if it leaks. If you only want to see how it feels first, **Connect** has a **Try a sample agent** button. The sample agent posts one approval, a few renewals and a small plan. It never runs anything, and you can remove it from the same place. ## 2. Send your first ask Every request carries the agent key as a bearer token in the `Authorization` header. The API base is `https://ordia-api.specvista.com/api/v1`, and **Connect**, under **Scripts and services**, shows the same command. ```bash curl -X POST https://ordia-api.specvista.com/api/v1/agent/ask \ -H "Authorization: Bearer $ASSENT_AGENT_KEY" \ -H "Content-Type: application/json" \ -d '{"kind":"approve","title":"Try Assent","why":"So you can see how an agent ask reaches you","items":[{"id":"a","title":"First option","selected":true}]}' ``` The ask arrives in Assent straight away, with a push if the app is installed. Approve or decline it, then read the answer back with `GET /api/v1/agent/answers`. An approve, to-do or pay ask needs a `why`: one sentence on why the person should act now. A title that reads like a status update is refused too, so phrase it as an action ("Approve sending 3 applications") or a question. ## 3. Or connect an MCP client Point any MCP client at the Assent MCP server: ```text https://ordia-api.specvista.com/api/v1/mcp ``` Send the agent key as a bearer token in the `Authorization` header. The client can then ask, wait for your answer, check your standing rules, read answers and mark them picked up, add to-dos, write notes, take shared locks, hand work to another agent and report each run. [Connect Claude, ChatGPT, Cursor or Codex](https://docs.specvista.com/assent/connect-an-assistant.md) has the setup for each assistant, and [MCP server](https://docs.specvista.com/assent/mcp.md) lists every tool. ## 4. The command line and the helper The [command line](https://docs.specvista.com/assent/cli.md) wraps the same API for shell scripts and CI (see [Scripts and CI](https://docs.specvista.com/assent/scripts-and-ci.md)), and the [helper](https://docs.specvista.com/assent/helper.md) pairs a Mac or Windows computer so **Run now** can restart an agent with your answer. ```bash npm install -g assent-cli ``` ```bash npm install -g assent-helper ``` Then run `assent-helper pair`, and scan the QR code it shows with your iPhone camera, or type its 8 character code at [assent.specvista.com/connect/pair](https://assent.specvista.com/connect/pair). The code lasts 10 minutes. Pairing is needed once on each computer. [Connect a computer](https://docs.specvista.com/assent/connect-a-computer.md) walks through every step on macOS and Windows. --- Source: https://docs.specvista.com/assent/connect-an-assistant.md # Connect Claude, ChatGPT, Cursor or Codex Add the Assent MCP server to Claude Code, Claude Desktop, ChatGPT, Cursor or Codex, on macOS, Windows or Linux, and check it works. Each assistant connects to the Assent MCP server as its own agent, so its asks carry its name and your rules can treat it on its own. The server is at: ```text https://ordia-api.specvista.com/api/v1/mcp ``` It speaks Streamable HTTP and keeps no session. Claude (on the web, the desktop app and mobile), ChatGPT, Cursor and Claude Code can sign in with OAuth, so you never paste a key. Every other assistant authenticates with an agent key sent as `Authorization: Bearer `. ## Before you start 1. In Assent, open **Agents**, choose **Add agent**, and name it after the assistant, for example `Claude Code` or `Cursor`. 2. Copy the agent key. It starts with `oak_` and Assent shows it once. Rotate it from the agent's settings if it leaks. 3. Keep the key out of files you commit. The examples below read it from the `ASSENT_AGENT_KEY` environment variable or from a private config file. Set the variable in the shell you start the assistant from: ```bash export ASSENT_AGENT_KEY=oak_... ``` In PowerShell, `$env:ASSENT_AGENT_KEY = "oak_..."` sets it for that window, and `setx ASSENT_AGENT_KEY oak_...` keeps it for new windows. ## Claude Code ```bash claude mcp add --transport http assent https://ordia-api.specvista.com/api/v1/mcp --header "Authorization: Bearer $ASSENT_AGENT_KEY" ``` In PowerShell, write `$env:ASSENT_AGENT_KEY` in place of `$ASSENT_AGENT_KEY`. The shell fills in the key, so Claude Code stores it in its own MCP settings; keep those private. Run `claude mcp list` and check that `assent` is connected. To have risky tool calls wait for your answer too, add the [Claude Code hook](https://docs.specvista.com/assent/claude-code.md). To sign in with OAuth instead of a key, run `claude mcp add --transport http assent https://ordia-api.specvista.com/api/v1/mcp`, then run `/mcp` in Claude Code, pick assent and choose Authenticate. Assent opens in your browser; the page warns that it returns to a program on this computer, so choose Allow only if you just started this yourself. ## Claude Desktop Claude Desktop starts local MCP servers from its config file: `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows. Add: ```json { "mcpServers": { "assent": { "command": "npx", "args": ["-y", "assent-cli@latest", "mcp"], "env": { "ASSENT_AGENT_KEY": "oak_..." } } } } ``` Restart Claude Desktop. `assent mcp` reads MCP messages on stdin and forwards each one to the server above with the key. To skip the key, add Assent as a custom connector instead: in Claude, open Settings, then Connectors, choose Add custom connector, paste `https://ordia-api.specvista.com/api/v1/mcp`, leave the advanced OAuth settings empty, choose Connect and then Allow. This works in Claude on the web, the desktop app and mobile. ## ChatGPT ChatGPT adds Assent as a custom connector and signs in with OAuth, so you never paste a key. Everything it does shows up under one agent named **ChatGPT** (or **ChatGPT connector** if you already have an agent called ChatGPT). 1. In a workspace, an admin first allows developer mode or custom connectors under **Workspace settings**, **Permissions & roles**. OpenAI renames these menus between rollouts, so look for the closest match. 2. In ChatGPT, open **Settings**, **Apps** (or **Connectors**), **Advanced settings**, and turn on **Developer mode**. 3. Choose **Create app** (or **Create**) and fill in: - Name: `Assent` - MCP server URL: `https://ordia-api.specvista.com/api/v1/mcp` - Authentication: **OAuth**, leaving the client ID and secret empty. ChatGPT registers itself. 4. Tick that you trust the app and choose **Create**. 5. ChatGPT opens Assent. Sign in if asked. The page reads **Allow ChatGPT?** and names the agent it will act as. Choose **Allow** within 10 minutes, in the same browser ChatGPT opened. You return to ChatGPT and it lists the Assent tools. Never choose **Allow** on a link someone sent you: if you did not just start connecting, choose **Deny**. To disconnect, open the ChatGPT agent in Assent and rotate its key, which ends ChatGPT's sign-in so it has to connect again, or pause the agent to stop it for a while. A scheduled task that cannot wait for you should call `assent_answers` at the start of each run, act on what it finds and mark each answer with `assent_picked_up`, then ask with `assent_ask` and leave the answer for the next run. ## Cursor Add the server to `~/.cursor/mcp.json`, or `.cursor/mcp.json` in one project (on Windows, `%USERPROFILE%\.cursor\mcp.json`): ```json { "mcpServers": { "assent": { "url": "https://ordia-api.specvista.com/api/v1/mcp", "headers": { "Authorization": "Bearer ${env:ASSENT_AGENT_KEY}" } } } } ``` Start Cursor from a shell where `ASSENT_AGENT_KEY` is set, or put the key in place of `${env:ASSENT_AGENT_KEY}` in a file you never commit. Open **Cursor Settings**, **MCP** and check that `assent` shows its tools. ## Codex Codex starts MCP servers as local commands. Save the agent key in a private config file first: ```bash mkdir -p ~/.assent echo '{ "agentKey": "oak_..." }' > ~/.assent/codex.json chmod 600 ~/.assent/codex.json ``` On Windows, in PowerShell: ```powershell New-Item -ItemType Directory -Force "$HOME\.assent" | Out-Null Set-Content -Encoding ascii -Path "$HOME\.assent\codex.json" -Value '{ "agentKey": "oak_..." }' ``` Use `-Encoding ascii`. In Windows PowerShell 5, `-Encoding utf8` adds a byte order mark and `>` writes UTF-16, and the command line rejects both. Then add to `~/.codex/config.toml` (`%USERPROFILE%\.codex\config.toml` on Windows): ```toml [mcp_servers.assent] command = "npx" args = ["-y", "assent-cli@latest", "mcp"] env = { ASSENT_CONFIG = "/Users/you/.assent/codex.json" } ``` On Windows, use the full path with doubled backslashes, such as `"C:\\Users\\you\\.assent\\codex.json"`, and if Codex cannot start the server, set `command = "npx.cmd"`. Start a new Codex session and ask it to list its Assent tools. ## Check it works Ask the assistant to call `assent_ask` with a small approval, for example a title of `Try Assent?` and a why of `Checking the connection`, then `assent_wait_for_answer`. The ask appears in your inbox; approve it and the assistant sees `answer.actionId` `done`. Then ask it to call `assent_picked_up` with the ask's uuid, so the answer is never delivered again. ## Common problems | What you see | What to do | |---|---| | `401` or "Agent key required" | The key is missing or not sent as a bearer token. Check the variable is set in the shell that started the assistant. | | `401` after it worked before | The key was rotated or the agent removed. Copy the new key from the agent's settings. | | `assent mcp` exits with code 5 | It found no agent key, or the config file is not plain JSON. Set `ASSENT_AGENT_KEY`, or point `ASSENT_CONFIG` at a file holding `{ "agentKey": "oak_..." }` saved without a byte order mark. | | `invalid_redirect_uri` when connecting ChatGPT | ChatGPT's return address changed. Email [hello@specvista.com](mailto:hello@specvista.com). | | The consent page says the request expired | Start connecting again from ChatGPT, and finish in the same browser within 10 minutes. | | `Too many waits at once for this agent or account` (status 429) | Each agent can wait on 4 asks at a time and each account on 10. Wait for one to finish, then try again. | [MCP server](https://docs.specvista.com/assent/mcp.md) lists every tool and its arguments. --- Source: https://docs.specvista.com/assent/scripts-and-ci.md # Scripts and CI Use assent-cli with an agent key from shell scripts, scheduled jobs and CI, to ask before a risky step, wait for the answer and report runs. The `assent` command lets a script or CI job ask you before a risky step and wait for your answer, check your standing rules, and report each run. It reads its agent key from the environment, so it never needs an interactive login. ## Set it up 1. In Assent, open **Agents**, choose **Add agent**, name it after the job (for example `Release pipeline`) and copy its agent key. It starts with `oak_` and is shown once. 2. Store the key as a secret in your CI, named `ASSENT_AGENT_KEY`. On your own computer, export it or save it in `~/.assent/config.json` (see [Command line](https://docs.specvista.com/assent/cli.md#configure)). 3. Install the command line. It needs Node.js 20 or later. ```bash npm install -g assent-cli ``` 4. Check the key: ```bash assent whoami ``` It prints one line of JSON describing the agent. Exit code 5 means the key is missing or wrong. ## Ask before a risky step ```bash assent ask \ --title "Deploy build 512 to production?" \ --why "All checks passed on the release branch" \ --rule-action deploy:web --target production \ --dedupe deploy:web:512 \ --wait --timeout 1800 ``` - `--wait` checks every 15 seconds until you answer, for at most `--timeout` seconds (default 3600). When you answer, it marks the answer as picked up and prints the ask with its `answer`. - An approval comes back with `answer.actionId` `done`; a decline with `decline`. Act only on `done`. - `--rule-action` and `--target` let you answer **Always** or **Never**, so the next matching ask is answered for you. - `--dedupe` makes a retried job reuse the same ask instead of sending a second one. Exit codes for `ask --wait`: | Code | Meaning | |---|---| | 0 | Answered (read `answer.actionId` to see what you chose) | | 3 | The ask expired or was closed without an answer, or a paired computer already picked the answer up | | 5 | No agent key, or the key is not valid | | 6 | No answer within `--timeout` | | 69 | Assent unreachable: network failure, timeout, rate limit or a server error | Treat anything other than an answer of `done` as "do not go ahead". ## GitHub Actions ```yaml jobs: deploy: runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Ask before deploying env: ASSENT_AGENT_KEY: ${{ secrets.ASSENT_AGENT_KEY }} run: | ACTION=$(npx --yes assent-cli@latest ask \ --title "Deploy ${GITHUB_SHA::7} to production?" \ --why "The release workflow passed on ${GITHUB_REF_NAME}" \ --rule-action deploy:web --target production \ --dedupe "deploy:web:${GITHUB_SHA}" \ --wait --timeout 1800 --get answer | jq -r '.actionId // empty') test "$ACTION" = "done" - run: ./deploy.sh ``` `npx` runs the latest `assent-cli` without a global install. `--get answer` prints just the answer object. If you decline, or the ask times out (exit 6) or expires (exit 3), `ACTION` is not `done`, so `test` fails the step and the deploy never runs. ## Windows and PowerShell The commands are the same on Windows. Set the key with `$env:ASSENT_AGENT_KEY = "oak_..."`, and check the exit code with `$LASTEXITCODE`: ```powershell $answer = assent ask --title "Run the clean-up job?" --why "It deletes builds older than 30 days" --wait --timeout 900 --get answer | ConvertFrom-Json if ($LASTEXITCODE -ne 0 -or $answer.actionId -ne "done") { exit 1 } ``` If PowerShell refuses to run `assent.ps1` because running scripts is disabled, call `assent.cmd` instead. ## Check your rules first When the action might already be covered by one of your standing rules, check before asking: ```bash assent rules check --action deploy:web --target production ``` Exit 0 means a rule allows it, 10 means a rule forbids it, and 11 means no rule covers it, so ask. See [Rules](https://docs.specvista.com/assent/rules.md). ## Report each run Scheduled jobs can show up in **Runs** with how they ended: ```bash RUN=$(assent run start --summary "Nightly clean-up" --get uuid) ./clean-up.sh > clean-up.log 2>&1 assent run finish "$RUN" --exit-code $? --summary "Nightly clean-up" --log-file clean-up.log ``` `run finish` redacts emails, keys, tokens, phone numbers and home paths from the summary and log tail before sending. ## Keep two jobs apart ```bash assent lock acquire deploy:web --ttl 45 --wait 90 && ./deploy.sh; assent lock release deploy:web ``` If another agent holds the lock after 90 seconds, `lock acquire` exits with 3 and the deploy does not start. ## When Assent is unreachable Decide what a job should do if Assent cannot be reached (exit 69). For a risky step, stop: never treat "no answer" as approval. For reporting commands such as `run start` and `run finish`, carry on with the job. [Command line](https://docs.specvista.com/assent/cli.md) lists every command, option, setting and exit code. --- Source: https://docs.specvista.com/assent/connect-a-computer.md # Connect a computer Pair a Mac or Windows computer with Assent using assent-helper, so Run now restarts an agent there as soon as you answer it. Pairing a computer lets **Run now** work: when you answer one of an agent's asks, the Assent helper on that computer restarts the agent with your answer straight away, instead of waiting for its next scheduled run. Agents do not need a paired computer to ask you; they only need an agent key. See [Connect an agent](https://docs.specvista.com/assent/connect-an-agent.md). The commands are the same on macOS and Windows. Use Terminal on a Mac, and PowerShell or Command Prompt on Windows. ## What you need - An Assent account, signed in on the web or in the iPhone app. Assent is invite only: see [Build with AI agents](https://docs.specvista.com/assent/agents.md#access-comes-first). - macOS, or Windows 10 version 1809 or later. Linux can pair and run the helper, but `install` does not add a background service there. - Node.js 20 or later. Check with `node --version`. - Your phone or a browser within reach: you confirm the pairing yourself. If Node.js is missing or older than 20, install the current LTS release from [nodejs.org](https://nodejs.org). On a Mac with Homebrew, `brew install node` works too, and on Windows, `winget install OpenJS.NodeJS.LTS`. Open a new terminal afterwards so it finds `node` and `npm`. ## 1. Install the helper ```bash npm install -g assent-helper ``` Check it worked: ```bash assent-helper --version ``` It prints the version number. `npm view assent-helper version` shows the latest release; if yours is older, run the install again. ## 2. Start pairing ```bash assent-helper pair ``` Add `--name "Work laptop"` to choose the name you see in Assent; it defaults to the computer's host name. The helper shows a QR code and a line like this, then waits: ```text Open Assent on your phone, go to Connect, Pair a computer, and scan this, or type the code K7QM2XWA. Waiting... ``` The code has 8 letters and numbers and lasts 10 minutes. Leave the command running. The message names Connect, Pair a computer: on the web that is the page below, in the Assent app it is **Connect a computer** under Connect, and on an iPhone the camera opens the same step. If an AI agent runs this step for you, it should tell you the code and wait for the command to finish. It cannot confirm the pairing itself. ## 3. Confirm it in Assent Do one of these: - **iPhone**: point the Camera at the QR code and tap the banner to open it in Assent. Assent opens its pairing screen and asks "Pair with code K7QM 2XWA?". Choose **Pair this computer**. - **Web**: sign in and open [assent.specvista.com/connect/pair](https://assent.specvista.com/connect/pair). Type the code under **Enter the code** and choose **Pair this computer**. Only pair a computer you own: it can run your agents with your answers. Assent shows that the computer is paired, and the helper finishes with one line of JSON: ```json {"paired":true,"computerUuid":"...","name":"Work laptop"} ``` ## 4. Check the pairing ```bash assent-helper status ``` You should see `"paired":true` and the computer's name. Pairing is needed once on each computer. ## 5. Let an agent run here 1. In Assent on the web, open **Agents**, open the agent and go to its settings. 2. Under **When you answer one of its asks**, choose **Run now**. 3. Choose this computer as its **Linked computer**, and enter its **Resume command**: the command that restarts the agent, for example `/Users/you/jobs/scan.sh --resume` or `C:/jobs/scan.cmd`. The command reads your answer from `ASSENT_ANSWER_JSON` and carries on. On Windows it runs in Git Bash when Git for Windows is installed, otherwise in `cmd.exe`. Write Windows paths with forward slashes, because Git Bash drops unquoted backslashes; to run a PowerShell script, use `powershell -NoProfile -File C:/jobs/scan.ps1`. 4. On the computer, list the agents linked to it and allow the one you set up: ```bash assent-helper agents assent-helper allow ``` `allow` shows the exact command and asks "Allow it?". Nothing runs until you say yes. If the command later changes in Assent, it stops running until you allow it again. 5. Start the background service: ```bash assent-helper install ``` On macOS it adds the launchd agent `com.ordia.helper`. On Windows it adds the scheduled task `AssentHelper` for your user, without needing an administrator; it starts when you sign in and is checked every minute. The output names the log file. On Linux, `install` exits with code 2: keep `assent-helper run` going with your own service manager, such as a systemd user service; its log is `~/Library/Logs/ordia/helper.log`, the same path as on macOS, even on Linux. ## 6. Confirm it works Answer one of the agent's asks. Within about 30 seconds the helper claims the answer and runs the resume command with your answer in `ASSENT_ANSWER_JSON` (see [Helper](https://docs.specvista.com/assent/helper.md#what-the-resumed-agent-receives)). `assent-helper queue` lists answers waiting to run, and the log shows each run: - macOS: `~/Library/Logs/ordia/helper.log` - Windows: `%LOCALAPPDATA%\Assent\Logs\helper.log` ## Common problems | What you see | What to do | |---|---| | `The pairing code expired. Run assent-helper pair again.` (exit code 3) | Codes last 10 minutes. Run `assent-helper pair` again and confirm the new code. | | On the web: "This code did not work." In the app: "This code has expired or was already used." | The code expired or was used. Run `assent-helper pair` again. | | PowerShell: `assent-helper.ps1 cannot be loaded because running scripts is disabled on this system` | Run `assent-helper.cmd pair` instead, use Command Prompt, or allow local scripts for your user with `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned`. | | `assent-helper` is not recognised, or `command not found` | Open a new terminal. If it still fails, check that the folder `npm prefix -g` prints (on macOS and Linux, its `bin` folder) is on your `PATH`. | | `npm` warns `EBADENGINE`, or the helper fails to start | Node.js is older than 20. Install the LTS release and reinstall the helper. | | The QR code looks broken in the Windows console | Type the 8 character code on the web instead. | | `This computer is not paired yet. Run: assent-helper pair` (exit code 5) | Pair it first, or pair again after `unpair`. | | `That agent is not linked to this computer. Link it in Assent first.` (exit code 4) | Set the agent's **Linked computer** to this computer in Assent, then run `assent-helper agents` again. | | ` has no resume command yet` (exit code 2) | Add a **Resume command** in the agent's settings. | | `install and uninstall work on macOS and Windows` (exit code 2) | On Linux, keep `assent-helper run` going with your own service manager, such as a systemd user service. | | `Cannot tell which Windows user to install the helper for: USERNAME is not set` | Run `install` from your own signed-in session, not a service account. | | `The api url must use https` | Leave out `--api-url` to use the hosted service. | | Exit code 69 | Assent could not be reached within 15 seconds. Check the network or proxy and try again. | ## Remove a computer ```bash assent-helper uninstall assent-helper unpair ``` `uninstall` stops the background service (on Linux, stop your own service instead) and `unpair` removes the computer from Assent and forgets its key. You can also unpair it from **Connect** in Assent. [Helper](https://docs.specvista.com/assent/helper.md) lists every command, setting and exit code, and how Run now stays safe. --- Source: https://docs.specvista.com/assent/answer-from-your-phone.md # Answer asks from your phone Install the Assent iPhone app, turn on pushes, and approve, pick, reply, enter codes, pay or sign in when an agent asks you. When an agent needs you, its ask arrives in your Assent inbox. You answer it on your phone or on the web, and the agent picks up your answer and carries on. ## What you need - An Assent account. Assent is invite only: see [Build with AI agents](https://docs.specvista.com/assent/agents.md#access-comes-first). - An iPhone for pushes and lock screen answers: install [Assent from the App Store](https://apps.apple.com/gb/app/assent-ai-agent-inbox/id6758003844). - On any other phone, or a computer, use [assent.specvista.com](https://assent.specvista.com) in the browser. Everything works there except pushes. ## 1. Sign in and allow pushes 1. Open Assent and sign in with the same email and password you use on the web. 2. When Assent asks to send notifications, choose **Allow**. If you said no earlier, turn them on in the iPhone **Settings**, **Notifications**, **Assent**. 3. In **Settings** in Assent, check your time zone and quiet hours (22:00 to 07:30 unless you change them). ## 2. Answer an ask Open **Inbox**. Each ask names the agent, what it wants and why. Open it and answer: | Kind | What you do | |---|---| | Approve | Choose **Approve** or **Decline**, or the agent's own buttons. Untick any item you do not want before you approve. | | To-do | Do the step yourself, then choose **Done**. | | Reply | Edit the draft, then **Send**, or **Skip**. The agent sends exactly the text you leave. | | Code | Type the one-time code you were sent. | | Pay | Open the link, pay on that page yourself, then choose **Paid**. | | Sign in | Open the link, sign in yourself, then choose **Done**. | Assent never asks you for a password or card number. An ask that does is not from Assent. You can also answer from the push itself. Approvals and to-dos show their buttons (up to 4), and on the lock screen they need Face ID or your passcode. A code ask's button opens the app, where you type the code. Payments and sign-ins always open the app. ## 3. Answer once, not every time On an approval, choose **Always** or **Never** and how long it lasts. Until then, asks like it from that agent are answered for you and never push. See [Rules](https://docs.specvista.com/assent/rules.md) and [Usual answers](https://docs.specvista.com/assent/usual-answers.md). ## How you know it worked The ask leaves **Inbox** and its push clears from your phone. The agent sees your answer the next time it checks: straight away if it is waiting, at its next run otherwise, or within about 30 seconds on a [paired computer](https://docs.specvista.com/assent/connect-a-computer.md) with Run now. **Runs** shows what each agent did afterwards. ## Common problems | What you see | What to do | |---|---| | No pushes arrive | Check that notifications for Assent are on in the iPhone Settings and that you are signed in to the app. Pushes wait during quiet hours, are silent while you are using Assent on the web, and stop for one agent after 25 asks in 10 minutes. See [Notifications](https://docs.specvista.com/assent/notifications.md). | | An ask disappeared | It was answered on another device, answered by one of your rules, withdrawn by the agent, or it expired. Asks other than to-dos expire if nobody answers in time, and Assent nudges you a day and an hour before. | | Answer buttons on the lock screen do nothing | Unlock with Face ID or your passcode first. | | A code ask expired before you typed the code | Ask the agent to start the sign-in again. Code asks push straight away, even in quiet hours. | --- Source: https://docs.specvista.com/assent/claude-code.md # Claude Code Set up Assent for Claude Code in about a minute. Risky tool calls such as git push wait for your answer from your phone or the web. Claude Code already asks before it runs a tool, but only in the terminal you started it from. The Assent hook sends the risky calls to your Assent inbox instead, so you can answer from your phone, and the call waits until you do. For a call on the ask list, no answer means no call. The hook is a best-effort tripwire, not a sandbox. It matches the commands Claude Code is about to run against a list of patterns, and a command written to dodge the list (a script file, a renamed binary, an encoded string) can get past it. Keep using Claude Code's own permissions, and a separate account or sandbox for anything you cannot afford to lose. ## Set it up You need the [command line](https://docs.specvista.com/assent/cli.md) and Node.js 20 or later. The steps below are for macOS and Linux. The hook command it installs is written for a POSIX shell and has not been tested with Claude Code on Windows yet; there, use the [MCP server](https://docs.specvista.com/assent/connect-an-assistant.md#claude-code) for asks. ```bash npm install -g assent-cli ``` 1. In Assent, open **Agents**, add an agent called `Claude Code` and copy its agent key. 2. Save the key in its own config file, readable only by you: ```bash mkdir -p ~/.assent echo '{ "agentKey": "oak_..." }' > ~/.assent/claude-code.json chmod 600 ~/.assent/claude-code.json ``` 3. Add the hook to Claude Code: ```bash assent hook claude-code install --config ~/.assent/claude-code.json ``` It shows exactly what it will change in `~/.claude/settings.json` and writes nothing until you confirm. Pass `--yes` to skip the question, or `--settings .claude/settings.json` to set it up for one project only. 4. Start a new Claude Code session and ask it to push a branch. The ask arrives in Assent; tap **Allow** or **Block**. ## What it does The hook runs before every Bash, Edit, Write, MultiEdit, NotebookEdit, WebFetch and MCP tool call. - **Your standing rules come first.** A Never rule blocks the call, and an Always rule lets it run when the call is one simple command the rule covers. See [Rules](https://docs.specvista.com/assent/rules.md). - **Risky calls go to your inbox.** A call on the ask list becomes an approve ask, and Claude Code waits for your answer. The ask shows the part that matched, then the whole command with hidden characters made visible, and where it runs. **Allow** runs it and **Block** stops it. Each call gets its own ask, so one answer never covers a different command. A call too long to show in full is blocked. - **No answer blocks it.** If you have not answered within two minutes, the call is blocked and the ask is withdrawn. If Assent cannot be reached, or the hook has no agent key, risky calls are blocked too. - **Everything else is unchanged.** Calls that are not on the ask list and have no rule go to Claude Code's own prompt, as before. On an ask for one simple command, you can also tap Always or Never, so the next identical call is answered for you. Chained commands, such as `cd app && git push`, and very long ones always need a fresh answer. ## The ask list By default the hook asks you about these Bash commands, wherever they appear in a command line: after `sudo`, `&&`, `bash -c` or `eval`, inside quotes or braces, with a path such as `/usr/bin/git`, or with git options such as `git -C app push`: | Pattern | Covers | |---|---| | `git push*` | Pushing | | `git reset --hard*` | Throwing away local work | | `rm -r*`, `rm -fr*` | Deleting folders, including `rm -R`, `rm -f -r` and `rm --recursive` | | `*deploy*` | Anything with deploy in it, such as `npm run deploy` | | `npm publish*` | Publishing a package | | `terraform apply*`, `terraform destroy*` | Changing infrastructure | | `kubectl delete*`, `docker push*` | Removing cluster resources, pushing images | To use your own list, add `hook.ask` to the config file. It replaces the default list. `tool` is the tool name and `target` is the command, file path or URL, both with `*` as a wildcard and ignoring case. Leave out `target` to ask about every call of that tool. ```json { "agentKey": "oak_...", "hook": { "ask": [ { "tool": "Bash", "target": "git push*" }, { "tool": "Bash", "target": "*deploy*" }, { "tool": "Write", "target": "*.env" }, { "tool": "mcp__github__*" } ], "waitSeconds": 300 } } ``` `waitSeconds` sets how long a call waits for your answer, from 1 to 3600 seconds (default 120). `ASSENT_HOOK_WAIT_SECONDS` overrides it. The install records the wait in the hook command (`--max-wait`) and gives the hook a Claude Code timeout 30 seconds longer, so the hook always answers before Claude Code gives up on it. A longer `waitSeconds` only takes effect after you run `assent hook claude-code install` again. A hook added by hand without `--max-wait` waits at most 45 seconds, inside Claude Code's default timeout. ## Remove it ```bash assent hook claude-code uninstall ``` It shows the change first and removes only the Assent hook, leaving the rest of your settings as they were. --- Source: https://docs.specvista.com/assent/mcp.md # MCP server The Assent MCP server address, how clients authenticate, every tool and its arguments, limits and errors. Assent runs a remote MCP server, so any assistant that speaks MCP can send asks and act on the answers. Every agent connects as itself, so its asks carry its name and the person's rules can treat it on its own. For step-by-step setup in Claude Code, Claude Desktop, ChatGPT, Cursor and Codex, see [Connect Claude, ChatGPT, Cursor or Codex](https://docs.specvista.com/assent/connect-an-assistant.md). ## Connect ```text https://ordia-api.specvista.com/api/v1/mcp ``` - **Transport**: Streamable HTTP with `POST`. The server keeps no session, so every call stands on its own. `GET` and `DELETE` answer `405`. - **Agent key**: send `Authorization: Bearer `. Keys start with `oak_`; the person creates one under **Agents** in Assent. - **OAuth**: Claude, ChatGPT, Cursor and Claude Code connect with OAuth 2.1 (authorisation code with PKCE `S256`, dynamic client registration, refresh tokens, scope `agent`). The metadata is at `https://ordia-api.specvista.com/.well-known/oauth-protected-resource` and `https://ordia-api.specvista.com/.well-known/oauth-authorization-server`. Local apps such as Claude Code and the Cursor desktop app return to `http://localhost:/callback` or `http://127.0.0.1:/callback` on your computer, and the sign-in page warns about that. Each connected app gets its own agent, so disconnecting one leaves the others. Other clients use an agent key. - **Local stdio**: `assent mcp`, from the [command line](https://docs.specvista.com/assent/cli.md), reads MCP messages on stdin and forwards each one to this server with the agent key, for clients that start servers as a command. ## Ask and wait for the answer | Tool | Arguments | What it does | |---|---|---| | `assent_ask` | `kind`, `title`, and optionally `why`, `detail`, `draft`, `url`, `actions`, `items`, `fields`, `group`, `rules`, `quote`, `dueAt`, `remindAt`, `dedupeKey`, `runUuid`, `action`, `target`, `question`, `answerType`, `effortMinutes`, `seriesKey`, `idempotencyKey`, `allowDuplicate` | Ask the person. `kind` is `approve`, `todo`, `pay`, `login`, `code` or `reply`. Give a `why` and a title phrased as an action or question, or it is refused. | | `assent_wait_for_answer` | `taskUuid`, optional `timeoutSeconds` (1 to 50, default 45) | Wait for the answer. Returns as soon as the ask is no longer open, or with `timedOut: true`; call it again to keep waiting. | | `assent_get_task` | `taskUuid` | Read an ask you created or were handed, with its status and answer. | | `assent_answers` | none | Your answered asks that are not picked up yet. | | `assent_picked_up` | `taskUuid` | Mark an answer as acted on, so it is never delivered again. | | `assent_resolve` | `taskUuid`, `outcome` (`resolved` or `withdrawn`), optional `note` | Close your own ask or to-do once the work is done or no longer needed. An answered ask cannot be closed; pick it up instead. | | `assent_check` | `action`, optional `target` and `summary` | Check the person's standing rules before acting: `allow`, `deny` or `ask`, with the rule that decided. | The answer says what the person chose: `answer.actionId` is the button (`done` for Approve, `decline` for Decline), `answer.selectedItemIds` the items they kept, and `answer.value` the text they sent or typed. A typical approval: 1. `assent_ask` with `kind: "approve"`, a title such as `Deploy the web app?`, a `why`, and `action` and `target` (for example `deploy:web` and `production`) so the person can answer Always or Never. 2. `assent_wait_for_answer` with the returned `uuid`, until it is no longer open. 3. Act on `answer.actionId`, then `assent_picked_up`. An ask that matches one of the person's Always or Never rules comes back already answered, so the wait returns at once. [Asks](https://docs.specvista.com/assent/asks.md) describes every kind and field, and [Rules](https://docs.specvista.com/assent/rules.md) explains how rules match. ## To-dos and notes | Tool | Arguments | What it does | |---|---|---| | `assent_task_add` | `title`, and optionally `why`, `detail`, `url`, `dueAt`, `remindAt`, `dedupeKey`, `runUuid`, `question`, `answerType`, `effortMinutes`, `seriesKey`, `idempotencyKey`, `allowDuplicate` | Add a to-do in Assent for a step the person must take for your work. A date without a time is due at 09:00 in their time zone. | | `assent_ordia_todo_add` | `title`, and optionally `why`, `detail`, `url`, `dueAt`, `remindAt`, `dedupeKey`, `runUuid`, `effortMinutes`, `seriesKey`, `idempotencyKey`, `allowDuplicate` | Add a durable personal to-do to the person's Ordia Desk (the Specvista notes and tasks app that uses the same account), only for a concrete action they must take. | | `assent_note` | `title`, `content`, optional `tags`, `runUuid` | Write a note under the agent's name in Assent, for example a run report. | | `assent_ordia_note_add` | `title`, `content`, optional `tags`, `runUuid` | Add a long-lived personal reference note to the person's Ordia Desk. | | `assent_note_update` | `noteUuid`, optional `title`, `content`, `tags`, `pinnedAsMemory`, `memoryScope` (`all` or `listed`) | Update a note you wrote, or pin it as memory for the person's other agents. | | `assent_memory` | none | Read the pinned memory notes the person shared with you. | | `assent_link` | `from` and `to` (each `{type, uuid}` with type `note`, `task`, `run` or `agent`), `relation` (`produced`, `about`, `blocks` or `related`) | Link two items. | ## Runs, locks, hand-offs and plans | Tool | Arguments | What it does | |---|---|---| | `assent_run_start` | optional `summary`, `maxMinutes` (1 to 1440) | Record that a run started. Keep the returned uuid and pass it as `runUuid`. | | `assent_run_finish` | `runUuid`, `status` (`ok` or `fail`), optional `exitCode`, `summary`, `logTail` | Finish a run. Emails, keys, phone numbers and home paths are redacted. | | `assent_lock_acquire` | `resource` (lower case, for example `deploy:web`), `ttlMinutes` (1 to 720) | Take a shared lock. Returns `acquired: false` with the holder when another agent has it; do not go ahead then. | | `assent_lock_release` | `resource`, `token` | Release a lock with the token `assent_lock_acquire` returned. | | `assent_handoff` | `toAgentName` or `toAgentUuid`, `title`, optional `detail`, `runUuid` | Hand work to another of the person's agents. | | `assent_handoffs` | none | Open work other agents handed to you. | | `assent_task_complete` | `taskUuid` | Mark a hand-off you received as done. | | `assent_plan_create` | `title`, `tracks`, `sessions`, optional `summary`, `nudge` (`off`, `morning` or `each`), `idempotencyKey` | Create a plan of dated sessions grouped into tracks, up to 1000 sessions. | | `assent_plan_get` | `planUuid` | Read back a plan you created. | | `assent_plan_update_sessions` | `planUuid`, `sessions` (each with `key` and optional `dueAt`, `title`, `detail`, `status`) | Move, retitle or mark sessions `open`, `done` or `cancelled`, up to 500 a call. | Dates (`dueAt`, `remindAt`) take a date and time with an offset, such as `2026-10-15T17:00:00+01:00` or `2026-10-15T16:00:00Z`, or a bare date such as `2026-10-15`, which means 09:00 that day in the person's time zone. ## Limits - `assent_wait_for_answer` waits at most 50 seconds per call. Each agent can wait on 4 asks at once and each account on 10; more returns status `429` with "Too many waits at once for this agent or account. Try again shortly." - Requests count towards the agent key's per-minute rate limit, the same as the [HTTP API](https://docs.specvista.com/assent/api.md). ## Errors A failed call comes back as a tool error whose text is `{"error": message, "status": code}`: | Status | Meaning | |---|---| | `400` | Invalid arguments. The message names the argument, for example `Invalid arguments: kind: ...`. | | `401` | No agent key or OAuth token, or it was rotated. This comes back as an HTTP `401` before any tool runs. | | `403` | The agent is paused, or attachments are off for it. | | `404` | The ask, run or note does not exist or belongs to another agent, or the tool name is unknown. | | `409` | Already answered, closed or expired. Read the ask again. | | `422` | The ask has no `why` or no clear question. The message says what to add. | | `429` | Too many waits or requests at once. Try again shortly. | --- Source: https://docs.specvista.com/assent/cli.md # Command line Every assent command, option, setting and exit code, for agents and shell scripts that talk to Assent. The `assent` command is how agents and scripts talk to Assent from a shell: ask and wait for the answer, record runs, write notes and to-dos, take shared locks, check standing rules and hand work to other agents. It needs Node.js 20 or later. ```bash npm install -g assent-cli ``` ## Configure Create an agent in Assent and copy its agent key (see [Connect an agent](https://docs.specvista.com/assent/connect-an-agent.md)). Then either set it in the environment: ```bash export ASSENT_AGENT_KEY=oak_... ``` or write it to `~/.assent/config.json` (on Windows, `%USERPROFILE%\.assent\config.json`), readable only by you: ```json { "agentKey": "oak_..." } ``` In PowerShell, set it with `$env:ASSENT_AGENT_KEY = "oak_..."`. Requests go to the hosted Assent service at `https://ordia-api.specvista.com/api/v1` unless you set `ASSENT_API_URL`. Another server must use https (plain http only for localhost), and redirects are refused, so the agent key is never sent in the clear or to another host. | Setting | What it does | |---|---| | `ASSENT_AGENT_KEY` | The agent key. Wins over `agentKey` in the config file. | | `ASSENT_API_URL` | Optional. Set it only to point at another Assent server. Wins over `apiUrl` in the config file. | | `ASSENT_CONFIG` | Path of the config file to read instead of `~/.assent/config.json`, for example one file per agent. | | `ASSENT_TIMEOUT_MS` | Request timeout in milliseconds. Default 10000. | | `ASSENT_RUN_UUID` | The run that `ask`, `task add`, `note`, `note personal` and `handoff` link their new item to when `--run` is not given. | | `ASSENT_HOOK_TIMEOUT_MS` | Timeout for each request `assent hook pre-tool-use` makes. Default 3000. | | `ASSENT_HOOK_WAIT_SECONDS` | How long `assent hook pre-tool-use --ask` waits for your answer. Wins over `hook.waitSeconds` in the config file. Default 120. | ## Output Every command prints one line of JSON. `--get ` prints just that field, which suits shell scripts: ```bash RUN=$(assent run start --summary "job scan" --get uuid) ``` `assent help` (or `assent --help`) prints every command and option, and `assent --version` prints the version. Check the latest release with `npm view assent-cli version`. ## Dates and times `--due`, `--remind` and `--retry-at` take a date and time: - `2026-10-15T17:00` or `2026-10-15 17:00`, in this computer's time zone. - `2026-10-15T17:00:00+01:00`, with an offset. - `2026-10-15`, a bare date, which means 09:00 that day in your Assent time zone and prints a warning on stderr. ## Commands ### Who am I ```text assent whoami ``` Shows the agent this key belongs to. ### Runs ```text assent run start [--summary s] [--max-minutes n] assent run progress --done n --total m [--label l] assent run finish (--exit-code n | --status ok|fail|deferred) [--summary s] [--log-file path] [--log-tail-bytes n] [--task task-uuid] [--result-json path|-] [--done n] [--skipped n] [--needs-you n] [--failed n] [--retry-at when] [--issue-reason needs_action|recovery_exhausted|deadline_at_risk --impact text --action-needed text] assent run defer --retry-at when ``` - `run progress` shows progress on the phone as a Live Activity. - `run finish` records how the run ended. With `--task`, the counts come from that task's item results. `--retry-at` is only allowed with `--status deferred`. - `--issue-reason`, `--impact` and `--action-needed` go together and raise an action for you. They are not allowed with `ok`, and each text is at most 500 characters. - `run defer` shows the run as deferred until that time, for example after a usage limit. ### Asks ```text assent ask --title t [--kind approve|todo|pay|login|code|reply] [--detail d] [--url u] [--draft text | --draft-file path|-] [--action id:label[:primary|secondary|danger]]... [--item id:title[:unselected]]... [--item-json path|-] [--recommend item-id]... [--reason item-id:text]... [--badge item-id:label[:tone]]... [--link item-id:label:url]... [--why text] [--field key:label[:type]:value]... [--attach item-id:path]... [--quote-json json|path|- [--quote-image path]] [--group key:title] [--conflict-on field-key]... [--total-of field-key] [--decline-action action-id] [--rule-action name] [--target t] [--due when] [--remind when] [--dedupe key] [--wait [--timeout seconds] [--interval seconds] [--no-pickup]] [--question text] [--answer-type yes_no|choice|text|number|done] [--effort minutes] [--series key] [--idempotency-key uuid] [--allow-duplicate] assent attach [--name n] assent answers assent picked-up ``` - `ask` asks you. The kind defaults to `approve`. [Asks](https://docs.specvista.com/assent/asks.md) covers every kind and option. `--quote-json` shows the post or message the ask responds to, exactly as written and without redaction: inline JSON, a path, or `-` for stdin, with `author`, `text` and optional `handle`, `postedAt` and `url`. `--quote-image` uploads a screenshot (png, jpeg or webp) to show with it. - `attach` uploads a file (pdf, png, jpeg, gif, webp, txt or md, at most 10 MB) and prints its uuid, once you turn attachments on for this agent. - `answers` lists your answered asks that are not picked up yet. - `picked-up` marks an answer as acted on, so it is never delivered again. ### To-dos ```text assent task add --title t --why text [--detail d] [--url u] [--due when] [--remind when] [--dedupe key] [--project project-uuid [--track name]] [--effort minutes] [--series key] [--idempotency-key uuid] [--allow-duplicate] [--parent ask-uuid --parent-item item-id] assent task resolve [--withdraw] [--note text] assent task update [--due when|none] [--remind when|none] assent task get assent task item-result done|skipped|needs_you|failed [--reason r] [--url u] assent task item-status ``` - `task add` adds a personal to-do to your Ordia Desk (the Specvista notes and tasks app at [notes.specvista.com](https://notes.specvista.com), which uses your Assent account). `--parent` and `--parent-item` link it to one item of the agent's own ask: marking the to-do done marks that item done, and resolving the item in the ask closes the to-do. For a to-do in your Assent inbox instead, use `assent ask --kind todo`. - `task resolve` closes your own ask once the work is done, or withdraws it with `--withdraw`. Its reminders stop. - `task update` changes the due or reminder time of a task this agent created. `none` clears it. - `task item-result` reports each item as it finishes. The `--url` must start with `http://` or `https://`. - `task item-status` prints `go`, `held`, `withdrawn`, `not_selected` or the recorded outcome for an item. ### Notes, links and memory ```text assent note --title t (--content text | --content-file path | --content-file -) [--tag t]... [--run run-uuid] assent note personal --title t (--content text | --content-file path | --content-file -) [--tag t]... [--run run-uuid] assent note update [--title t] [--content text | --content-file path | --content-file -] [--tag t]... assent link --from type:uuid --to type:uuid [--relation produced|about|blocks|related] assent memory get ``` - `note` writes a note you see under the agent's name in Assent. `--content-file -` reads stdin. - `note personal` adds a long-lived personal note to your Ordia Desk. - `link` links two items. The types are `note`, `task`, `run` and `agent`, and the relation defaults to `related`. - `memory get` reads the pinned memory notes you shared with this agent. ### Locks ```text assent lock acquire [--ttl minutes] [--wait seconds] [--interval seconds] assent lock release [--token t] ``` A shared lock, for example `deploy:web`, keeps two agents off the same resource. The lock lasts `--ttl` minutes (default 30). `--wait` keeps trying for that many seconds, every `--interval` seconds (default 15). If the lock is still held, the command exits with 3. `lock release` uses the token saved when the lock was taken, or `--token`. ```bash assent lock acquire deploy:web --ttl 45 --wait 90 && deploy; assent lock release deploy:web ``` ### Hand-offs ```text assent handoff (--to | --to-uuid ) --title t [--detail d] [--run run-uuid] assent handoffs assent handoffs done ``` Hand work to another of your agents, list the open hand-offs other agents gave this one, and mark one as done. ### Projects and plans ```text assent project get assent project overview assent plan create --file path|- [--idempotency-key uuid] assent plan get assent plan sessions --file path|- ``` - `project get` and `project overview` read a project you linked this agent to: progress, tracks, milestones, this week and overdue. - `plan create` takes JSON `{ title, summary?, tracks: [{key,title}], sessions: [{key,trackKey,title,dueAt,detail?,sessionMinutes?,habitKey?,url?}] }`, with at most 1000 sessions. - `plan sessions` takes JSON `{ sessions: [{key, dueAt?, title?, detail?, status?: open|done|cancelled}] }`, with at most 500 sessions. ### Rules and the Claude Code hook ```text assent rules check --action name [--target t] [--summary s] assent rules list assent rules add --deny --action pattern [--target pattern] [--reason r] [--expires 1d|7d|30d|none] assent rules remove assent hook pre-tool-use [--ask [--max-wait seconds]] assent hook claude-code install [--config path] [--settings path] [--yes] assent hook claude-code uninstall [--settings path] [--yes] ``` `rules check` exits 0 for allow, 10 for deny and 11 for ask. `rules list` shows the standing rules that apply to this agent. Agents can only add deny rules for themselves, and `rules remove` removes only a deny rule this agent added. [Rules](https://docs.specvista.com/assent/rules.md) explains how rules match. `hook pre-tool-use` reads a Claude Code PreToolUse event on stdin, prints allow, deny or ask, and always exits 0. With `--ask`, it sends calls on its ask list to you and blocks them unless you allow them, waiting at most `--max-wait` seconds (default 45). `hook claude-code install` adds that hook to `~/.claude/settings.json` (or the `--settings` file) after showing the change, and `uninstall` removes it. See [Claude Code](https://docs.specvista.com/assent/claude-code.md). ### MCP ```text assent mcp ``` Runs a local MCP server on stdin and stdout for clients that start one as a command, sending each message to the Assent MCP server with this agent's key. See [MCP server](https://docs.specvista.com/assent/mcp.md). ## Exit codes | Code | Meaning | |---|---| | 0 | OK | | 1 | Error | | 2 | Usage error | | 3 | Conflict: lock held, already answered or expired | | 4 | Not found | | 5 | Not configured or unauthorised | | 6 | `--wait` timed out | | 10 | `rules check` found a deny rule | | 11 | `rules check` found no rule: ask the person | | 69 | Assent unreachable: network failure, timeout, rate limit or a 5xx | Before a risky step, go ahead only when `ask --wait` exits 0 with `answer.actionId` `done`, or `rules check` exits 0. Any other exit code, including 5, 6 and 69, means stop. Reporting commands such as `run start`, `run finish` and `note` can treat a failure as "Assent unavailable, carry on as before". ## Privacy `run finish` redacts emails, tokens, keys, phone numbers and home paths from the summary and log tail before sending. `note`, `note personal` and `note update` redact the title and content the same way, and `ask` and `task add` redact the title and detail. A `--url` link, a reply draft and a `--quote-json` quote are sent as given. Never pass passwords, card or bank details to any command: `pay` and `login` asks carry only a link. --- Source: https://docs.specvista.com/assent/api.md # HTTP API The Assent HTTP API for agents. Base URL, agent key auth, sending an ask, reading the answer, every agent endpoint and errors. Anything that can send an HTTP request can use Assent. The [command line](https://docs.specvista.com/assent/cli.md) and the [MCP server](https://docs.specvista.com/assent/mcp.md) use the same API. ## Base URL and auth ```text https://ordia-api.specvista.com/api/v1 ``` Send JSON bodies, and the agent key as a bearer token: ```text Authorization: Bearer ``` Agent keys start with `oak_`. A person creates one in Assent: **Agents**, **Add agent**, then copy the key, which is shown once. Their email address must be verified first. If a key leaks, they open the agent's settings and choose **Rotate key**; the old key stops working. See [Connect an agent](https://docs.specvista.com/assent/connect-an-agent.md). There is no OpenAPI document yet. This page and [Asks](https://docs.specvista.com/assent/asks.md) describe every field. ## Ask the person `POST /agent/ask` sends an ask to the person's inbox. Every ask needs `kind` and `title`; phrase the title as an action or a question. | `kind` | Required | What the person sees | |---|---|---| | `approve` | `title`, `why` | Approve (`actionId` `done`) or Decline (`decline`), or your own actions. Items show as ticked checkboxes the person can untick. | | `todo` | `title`, `why` | A step only the person can take. Done is `done`. | | `pay` | `title`, `why`, `url` | A link where the person pays, answered with Paid (`done`). Send the link only, never card details. | | `login` | `title`, `url` | A link where the person signs in, answered with Done (`done`). Never send passwords. | | `code` | `title` | The person types a value, such as a one-time code. It comes back as `answer.value`. | | `reply` | `title`, `draft` | A draft of up to 4000 characters the person can edit. Default actions `send` and `skip`; `send` returns the final text as `answer.value`. | Optional fields include `detail`, `items` (each with `id`, `title` and `selected`), `actions` (up to 6, each with `id`, `label` and an optional `style` of `primary`, `secondary` or `danger`), `dueAt`, `remindAt`, `dedupeKey`, `runUuid`, and `action` with `target` so the person can answer Always or Never. [Asks](https://docs.specvista.com/assent/asks.md) covers every field. ```bash curl -X POST https://ordia-api.specvista.com/api/v1/agent/ask \ -H "Authorization: Bearer $ASSENT_AGENT_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 6f1c2b8e-3f43-4c3a-9d55-0f3a4c1b2e7d" \ -d '{"kind":"approve","title":"Deploy build 512 to production?","why":"All checks passed on the release branch","action":"deploy:web","target":"production"}' ``` A new ask returns `201` with the task and its `uuid`. Sending the same `dedupeKey` or the same `Idempotency-Key` header (a UUID) returns the existing ask with `200` and `created` set to `false`. Reusing an `Idempotency-Key` for a different request is refused with `422`. An ask that a standing rule answers comes back already answered. ## Get the answer An ask starts as `open` and becomes `answered` when the person answers. Its `answer` holds `actionId`, `selectedItemIds` and, for `code` and `reply` asks, `value`. Asks other than `todo` expire if nobody answers in time; `answerExpiresAt` says when. There is no long-poll endpoint. Poll `GET /agent/tasks/{uuid}` every few seconds, or use the MCP tool `assent_wait_for_answer` or `assent ask --wait`. When you have acted on the answer, call `POST /agent/tasks/{uuid}/picked-up` so it is never delivered again. ## Endpoints | Method and path | What it does | |---|---| | `GET /agent/me` | The agent this key belongs to. | | `POST /agent/ask` | Ask the person. | | `GET /agent/tasks/{uuid}` | Read an ask you created or were handed, with its status and answer. | | `GET /agent/answers` | Your answered asks that are not picked up yet. | | `POST /agent/tasks/{uuid}/picked-up` | Mark an answer as acted on. | | `POST /agent/tasks/{uuid}/resolve` | Close your own ask with `{"outcome":"resolved"}` or `{"outcome":"withdrawn"}`, and an optional `note`. | | `PATCH /agent/tasks/{uuid}` | Change `dueAt` or `remindAt` of a task you created. | | `POST /agent/tasks/{uuid}/items/{id}/result` | Report one item's outcome: `done`, `skipped`, `needs_you` or `failed`. | | `POST /agent/personal-tasks` | Add a personal to-do to the person's Ordia Desk, the Specvista notes and tasks app that uses the same account. | | `POST /agent/handoff` | Hand work to another of the person's agents. | | `GET /agent/handoffs` | Open hand-offs other agents gave you. | | `POST /agent/tasks/{uuid}/complete` | Mark a hand-off you received as done. | | `POST /agent/runs` | Start a run. Then `POST /agent/runs/{uuid}/progress`, `/finish` or `/defer`. | | `POST /agent/notes` | Write a note under the agent's name. `PATCH /agent/notes/{uuid}` updates it. | | `POST /agent/personal-notes` | Add a personal note to the person's Ordia Desk. | | `GET /agent/memory` | Pinned memory notes the person shared with this agent. | | `POST /agent/links` | Link two items. | | `POST /agent/locks/acquire`, `POST /agent/locks/release` | Take and release a shared lock. | | `POST /agent/rules/check` | Check the person's standing rules: `allow`, `deny` or `ask`. | | `GET /agent/rules`, `POST /agent/rules`, `DELETE /agent/rules/{uuid}` | List rules that apply to this agent, add a deny rule for itself, remove one it added. | | `POST /agent/attachments` | Upload a file once the person turns attachments on for this agent. | | `POST /agent/plans`, `GET /agent/plans/{uuid}`, `PATCH /agent/plans/{uuid}/sessions` | Create, read and update plans of dated sessions. | | `GET /agent/projects/{uuid}`, `GET /agent/projects/{uuid}/overview` | Read a project the person linked this agent to. | ## Errors Errors are JSON with the HTTP status in `statusCode`, a short `error`, and a `message` that says what to change. Some also carry a stable `code`, such as `IDEMPOTENCY_KEY_REUSED`: ```json {"message":"Agent key required","error":"Unauthorized","statusCode":401} ``` | Status | Meaning and what to do | |---|---| | `400` | A field is missing or invalid; the message names it. | | `401` | No agent key, or the key was rotated or removed. Ask the person for the current key. | | `403` | The agent is paused (the person resumes it in Assent), attachments are off for this agent, or the account reached one of its limits. The message says which. | | `404` | The ask, run, note or plan does not exist or belongs to another agent. | | `409`, `410` | Already answered, already closed, expired, or a lock is held. Read the ask again. | | `422` | The ask is unclear (it needs a `why`, or a title phrased as an action or question), or an `Idempotency-Key` was reused for a different request. The message says what to change. | | `429` | Too many requests for this agent key in the last minute. Wait and retry with the same `Idempotency-Key`. | | `5xx` | Assent had a problem. Retry later with the same `Idempotency-Key`. | --- Source: https://docs.specvista.com/assent/helper.md # Helper Every assent-helper command, setting and exit code for macOS and Windows, what a resumed agent receives, and how Run now stays safe. The Assent helper pairs a computer with Assent by QR code or an 8 character code, sends a heartbeat every 30 seconds and runs **Run now**: when you answer an agent's ask on your phone, the helper restarts that agent on this computer with your answer. It needs macOS, or Windows 10 version 1809 or later, and Node.js 20 or later. On Linux it can pair and run, but `install` adds no background service. The commands are the same everywhere, in Terminal on a Mac or in PowerShell or Command Prompt on Windows. For a step-by-step guide with the expected result of each step and fixes for common problems, see [Connect a computer](https://docs.specvista.com/assent/connect-a-computer.md). ```bash npm install -g assent-helper ``` ## Set it up 1. Run `assent-helper pair`. It shows a QR code and an 8 character code, which lasts 10 minutes. 2. Scan the QR code with your iPhone camera to open it in Assent, or sign in at [assent.specvista.com/connect/pair](https://assent.specvista.com/connect/pair) and type the code. Choose **Pair this computer**. 3. Link an agent to this computer in Assent: set **When you answer one of its asks** to **Run now**, pick this computer as its **Linked computer** and give it a **Resume command**. 4. Review and allow that agent's command on this computer, then start the background service: ```bash assent-helper agents assent-helper allow assent-helper install ``` The helper talks to the hosted Assent service. Set `ASSENT_API_URL` or pass `--api-url` to `pair` only to point at another Assent server. Pairing refuses a plain `http://` address unless the host is `localhost` or `127.0.0.1`. ## Commands ```text assent-helper pair [--api-url url] [--name name] show a QR code and wait for your phone to scan it assent-helper status pairing, allowed agents and the local queue size assent-helper agents agents linked to this computer and whether each is allowed assent-helper allow [--yes] review and allow an agent's resume command assent-helper revoke stop allowing it assent-helper unpair remove this computer from Assent and forget its key assent-helper queue answers claimed and waiting to run on this computer assent-helper once heartbeat, claim and run what is due, then exit assent-helper run keep doing that every 30 seconds assent-helper install | uninstall add or remove the background service ``` `--name` sets the computer's name in Assent and defaults to the host name. Every command prints one line of JSON, and an error prints `{"error": message, "exitCode": code}` on stderr. `assent-helper help` prints the commands, and `assent-helper --version` the version. ## Settings | Setting | What it does | |---|---| | `ASSENT_API_URL` | Optional. The Assent server `pair` uses when `--api-url` is not given. Default `https://ordia-api.specvista.com/api/v1`. | | `ASSENT_HELPER_INTERVAL_SECONDS` | Loop interval. A whole number of at least 5, otherwise 30. | | `ASSENT_HELPER_RUN_TIMEOUT_MINUTES` | How long one resume command may run before it is stopped. A positive whole number, otherwise 360. | Requests to Assent give up after 15 seconds and count as Assent being unreachable. Pairing again while `run` is active takes effect on the next tick, without a restart. ## What the resumed agent receives The helper runs the agent's resume command with your answer in these environment variables: | Variable | Value | |---|---| | `ASSENT_RESUME` | `1` | | `ASSENT_TASK_UUID` | The ask you answered. | | `ASSENT_AGENT_UUID` | The agent. | | `ASSENT_ANSWER_JSON` | Your answer, for example `{"actionId":"submit","selectedItemIds":["02"]}`. | | `ASSENT_TASK_JSON` | The whole ask, when it fits in 64 KB. | | `ASSENT_TASK_FILE` | Set instead of `ASSENT_TASK_JSON` when the ask is larger than 64 KB: a private file holding it, removed after the run. | Exit code 75 from the command means "busy, try later". The helper tries again every 10 minutes, for up to 6 hours. If the agent is still busy after that, the answer is reported as failed and goes back to the agent's next scheduled run. ## Exit codes | Code | Meaning | |---|---| | 0 | OK | | 1 | Error | | 2 | Usage error | | 3 | Pairing expired, or another helper holds the queue | | 4 | Unknown agent | | 5 | Not paired | | 69 | Assent unreachable | ## How Run now stays safe - Only agents linked to this computer in Assent, with Run now on and a resume command, are considered. - Nothing runs until you allow that agent's exact resume command on this computer with `assent-helper allow `, which shows you the command first. If the command changes in Assent, it stops running until you allow the new one. The helper always runs the command stored on this computer. - The command gets your environment with every other `ASSENT_` variable removed, and without any value holding an agent or computer key. - Each answer is claimed once. A run that was interrupted (helper stopped, computer restarted) is never re-run automatically: the helper tells Assent it was interrupted, the answer goes back to waiting for the agent's next scheduled run, and the log tells you which one to check. - Only one helper works the queue at a time. A second `once` or `run` exits with code 3 and names the process holding it. - The helper's log is redacted: emails, keys, tokens, phone numbers, home paths and this computer's own key. Pairing never prints the computer key. - While Assent is unreachable, answers wait on the server. The helper keeps running anything it already claimed and catches up when Assent is back. ## Background service `install` records the path of the helper and of Node.js it was run from, so run it again after reinstalling the helper somewhere else. - **macOS**: `install` adds the launchd agent `com.ordia.helper`, which restarts the helper if it stops (at most once a minute). The log is `~/Library/Logs/ordia/helper.log`. - **Windows**: `install` adds the scheduled task `AssentHelper` for your user, without needing an administrator. It starts when you sign in, runs in a hidden console and is checked every minute, so a helper that stopped is started again. The log is `%LOCALAPPDATA%\Assent\Logs\helper.log`, and the task's own output goes to `%LOCALAPPDATA%\Assent\Logs\helper.task.log`. Resume commands run in Git Bash when Git for Windows is installed, otherwise in `cmd.exe`. Write paths with forward slashes, such as `C:/jobs/scan.cmd`, because Git Bash drops unquoted backslashes. A command that runs too long is stopped with its child processes. - **Linux**: `install` is not available. Keep `assent-helper run` going with your own service manager. The service restarts itself if it stops, so to pause the helper run `assent-helper uninstall`, and `assent-helper install` to start it again. --- Source: https://docs.specvista.com/assent/asks.md # Asks The six kinds of ask, with actions, items, fields, groups, waiting for the answer and marking it picked up. An ask is a question from an agent to you. The examples use the [command line](https://docs.specvista.com/assent/cli.md); the HTTP API (`POST /api/v1/agent/ask`) and the MCP connector take the same fields. ## Kinds | Kind | What you do | Buttons unless the agent sets its own | |---|---|---| | `approve` | Approve or decline. This is the default kind. | Approve, Decline | | `todo` | A step only you can do. Mark it done. | Done | | `pay` | Open the payment page, pay yourself, then say so. | Paid | | `login` | Open the sign-in page, sign in, then say so. | Done | | `code` | Type a one-time code. The code comes back as `answer.value`. | One button that takes the code | | `reply` | Edit the agent's draft, then Send or Skip. | Send, Skip | `pay` and `login` asks carry only a link (`--url`). Never put passwords, card or bank details in an ask. ### Reply A reply ask carries a draft: `--draft text`, or `--draft-file path`, or `--draft-file -` for stdin, at most 4000 characters. One final line break is dropped. You can edit the draft in Assent; the send action's `answer.value` is the final text to send. The draft is sent as written, without redaction. If the agent sets its own actions, exactly one must be primary, the send action. ```bash assent ask --kind reply --title "Reply to Ada" --draft-file ./reply.txt --dedupe reply:ada:42 ``` ## What every ask needs - A **title** phrased as an action ("Approve sending 3 applications") or a question. A title that reads like a status update is refused unless you add `--question`. - A **why** for `approve`, `todo` and `pay` asks: one sentence on why you should act now. ```bash assent ask --title "Deploy now?" --why "All checks passed on the release branch" --wait --timeout 600 ``` ## Actions `--action id:label[:primary|secondary|danger]` adds a button, up to 6. The id comes back in `answer.actionId`. ```bash assent ask --title "Submit 2 applications" --why "Both close on Friday" \ --item "01:Acme, Staff Engineer" --item "02:Globex, Lead Engineer" \ --action "submit:Submit selected:primary" --action "skip:Skip all" --dedupe jobs:2026-09-29 ``` ## Items Items turn an ask into a list you pick from, up to 200. Each item starts ticked unless you add `:unselected`. The ticked ids come back in `answer.selectedItemIds`. - `--item id:title[:unselected]` adds an item. - `--item-json path|-` reads a JSON array of items instead, for per-item fields, subtitles and field tones. - `--recommend item-id` marks recommended items. When any item is recommended, only the recommended ones start ticked. - `--reason item-id:text` adds a line on why. - `--badge item-id:label[:tone]` adds a badge, at most 4 per item. Tones are `neutral`, `ok`, `warn`, `danger` and `note`. - `--link item-id:label:url` adds an `http` or `https` link, at most 4 per item. - `--attach item-id:path` uploads a file and attaches it to the item, at most 4 per item. Attachments work once you turn them on for the agent. ## Fields `--field key:label[:type]:value` shows a labelled value, up to 12. Types are `text`, `money` (`GBP 42.00`), `date`, `datetime`, `number` and `score` (`8/10`). ## Groups `--group key:title` puts separate asks from the same agent with the same key into one decision card. The key cannot contain a colon. - `--conflict-on field-key` (up to 4) flags members that share that field's day or value, for example two bookings on one evening. - `--total-of field-key` totals the open members of a `money` field, per currency. - `--decline-action action-id` is what **Keep one** answers the other members with. ## Times, reminders and repeats - `--due when` sets a due time and `--remind when` a reminder. See [Notifications](https://docs.specvista.com/assent/notifications.md) for when pushes arrive. - `--dedupe key` returns the live ask with that key instead of creating another one. - An `approve` or `todo` ask whose title closely matches an open one from the same agent is merged into it, unless you pass `--dedupe`, `--group` or `--allow-duplicate`. - `--idempotency-key uuid` makes a retry return the ask the first request created. - `--question`, `--answer-type yes_no|choice|text|number|done`, `--effort minutes` (1 to 1440) and `--series key` add context. `choice` needs at least two actions or items. - `--project project-uuid [--track name]` files the ask into a project you linked the agent to. - `--rule-action name` and `--target t` name what an approval is about, so you can answer Always or Never. See [Rules](https://docs.specvista.com/assent/rules.md). ## Getting the answer An answer looks like this: ```json { "actionId": "submit", "selectedItemIds": ["02"], "value": "only for code and reply asks" } ``` There are three ways to get it. - **Wait.** `--wait` blocks until you answer, checking every `--interval` seconds (default 15) for up to `--timeout` seconds (default 3600). It exits 0 with the answered ask, or when the ask is resolved as done while it waits. It exits 6 if the wait timed out, and 3 if the ask expired, was withdrawn or was otherwise closed without an answer. An ask that a standing rule answers comes back at once. - **Poll later.** `assent answers` lists answered asks that are not picked up yet, oldest first. `assent task get ` reads one ask. - **Run now.** With the [helper](https://docs.specvista.com/assent/connect-a-computer.md) on a paired computer, answering restarts the agent with the answer in its environment. ## Picked up Once the agent has acted on an answer, it marks it picked up so it is never delivered again: ```bash assent picked-up "$TASK" ``` `--wait` does this for you unless you pass `--no-pickup`. If the helper already claimed the answer to resume the agent, `--wait` exits 3 and the output says `"resumedBy": "helper"`. ## Closing an ask yourself `assent task resolve ` closes an ask the agent created once the work is done, and `--withdraw` withdraws it when it is no longer needed. Its reminders stop and its notification clears. Asks other than to-dos expire if nobody answers them in time; the ask's `answerExpiresAt` says when. ## Reporting each item For an ask with items, the agent can report each item as it finishes, and check whether an item is still wanted before it starts: ```bash assent task item-result "$TASK" 02 done --url https://example.com/application/02 assent task item-status "$TASK" 02 ``` --- Source: https://docs.specvista.com/assent/rules.md # Rules Answer an approval with Always or Never once, check standing rules before acting, and guard Claude Code tool calls with a hook. A standing rule answers asks for you. It is an allow or a deny for an action, optionally narrowed to a target, for one agent or for every agent. ## Always and Never When an agent asks for approval, you can answer with **Always** or **Never** instead of a single answer, and choose how long the rule lasts: 1 day, 7 days (the default), 30 days or no expiry. That answers this ask and creates a rule for the agent that asked. Until the rule expires, a later ask from that agent that matches it comes back already answered, without a push, and `--wait` returns at once. Always and Never are offered on `approve` asks from an agent when Assent can tell the approving button from the declining one. The declining button is the agent's `--decline-action`, otherwise a `danger` button, otherwise one with an id such as `decline`, `skip` or `cancel`. The approving button is then the `primary` one, otherwise one with an id such as `approve`, `go` or `submit`, otherwise the only other button. To make the rule reusable, name what the ask is about with `--rule-action` and `--target`: ```bash assent ask --title "Deploy the web app" --why "Tests passed" --rule-action deploy:web --target production \ --action "go:Deploy:primary" --action "hold:Not now" --wait ``` Without them, the rule matches asks from that agent with the same title. ## Managing rules **Rules** in Assent lists every rule with who it applies to, when it expires and how often it was used, and you can remove any rule there at any time. On the web, **Rules** also lets you add a rule yourself, for one agent or for every agent. ## How a rule is chosen - Deny always beats allow. - Otherwise the most specific rule wins: a rule for this agent over one for every agent, a rule with a target over one without, then the longer pattern. - Patterns use `*` as a wildcard and ignore case. - An allow is only honoured when nothing in the target had to be redacted and, for a shell command, when the target is one simple command, with none of `;`, `&`, `|`, `$`, a backtick, `<`, `>`, `(`, `)` or a line break. Otherwise the answer is ask. ## Check before acting `assent rules check` asks the rules before the agent does anything at all: ```bash assent rules check --action post --target linkedin --summary "Post the weekly update" case $? in 0) post_it ;; 10) echo "not allowed" ;; 11) assent ask --title "Post the weekly update?" --why "It is ready" --rule-action post --target linkedin ;; *) echo "Assent unavailable" ;; esac ``` | Exit code | Decision | |---|---| | 0 | A rule allows it | | 10 | A rule denies it | | 11 | No rule covers it: ask the person | `assent rules list` shows the rules that apply to this agent. ## Agents add only deny rules An agent can add deny rules for itself, and remove the ones it added. Allow rules come only from you. ```bash assent rules add --deny --action Bash --target "git push*" --reason "Pushing deploys" --expires 30d assent rules remove ``` `--expires` takes `1d`, `7d`, `30d` or `none` (the default). ## Claude Code hook `assent hook pre-tool-use` reads a Claude Code PreToolUse event on stdin, checks the tool call against your standing rules and prints the hook decision: allow, deny or ask. The action is the tool name (`Bash`, `Edit`, `Write`, `WebFetch`, an MCP tool name and so on) and the target is the command, file path, URL or query. Secrets are redacted from the target before it is sent. - An allow is only honoured when the target is exactly what will run. If a secret had to be redacted, the target is longer than 4000 characters, or a shell command is anything but one simple command, the hook answers ask instead. - A deny is always honoured. - For file tools, a relative path is resolved against the working directory before rules are checked, and an allow is never honoured for a path that cannot be resolved to an absolute path, or one containing `..`. A path with `..` is also checked against deny rules in its resolved form. - Without `--ask`, the hook fails open to ask, so Claude Code shows its own prompt: a network error, a timeout, a rate limit, a 5xx, missing config or an unreadable event all answer ask, and it always exits 0. `ASSENT_HOOK_TIMEOUT_MS` sets its timeout (default 3000). With `--ask`, which `assent hook claude-code install` sets up, calls on the ask list are blocked instead when Assent cannot be reached, and every call is blocked when the hook settings in the config file are invalid; see [Claude Code](https://docs.specvista.com/assent/claude-code.md). The hook needs the [command line](https://docs.specvista.com/assent/cli.md): ```bash npm install -g assent-cli ``` Add it to `~/.claude/settings.json` (every project) or `.claude/settings.json` (one project), with the key of an agent you created for this assistant: ```json { "hooks": { "PreToolUse": [ { "matcher": "Bash|Edit|Write|MultiEdit|NotebookEdit|WebFetch|mcp__.*", "hooks": [{ "type": "command", "command": "ASSENT_CONFIG=$HOME/.assent/claude-code.json assent hook pre-tool-use", "timeout": 10 }] } ] } } ``` To have risky calls wait for your answer in Assent instead, and to add the hook with one command, see [Claude Code](https://docs.specvista.com/assent/claude-code.md). Try it by hand: ```bash echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | assent hook pre-tool-use ``` --- Source: https://docs.specvista.com/assent/usual-answers.md # Usual answers When you keep giving an agent the same answer, Assent shows it above the buttons so you can decide faster. When you keep answering an agent the same way, Assent tells you so on its next ask, in a note above the answer buttons: > **You usually approve this** > > You chose "Approve" on 4 of the last 5 asks like this from Release agent. A usual answer is a suggestion only. Nothing is answered for you: you still tap the answer yourself. To have asks answered for you, use [Always or Never](https://docs.specvista.com/assent/rules.md). ## When it shows Assent looks at your last 20 answers to asks of the same kind from the same agent, and shows a usual answer when: - there are at least 3 such answers, and - one answer makes up at least 4 in 5 of them (80% or more), and - that answer is one of the buttons on the new ask. The note reads "You usually approve this" or "You usually decline this" when the answer is the approve or decline button of an approval, and "You usually choose" with the button's label otherwise. ## When it does not - Code and reply asks, because each answer is different. - Asks in a [group](https://docs.specvista.com/assent/asks.md#groups). - Asks with fewer than two buttons. - Asks you have already answered. - Answers a standing rule gave for you do not count towards it. --- Source: https://docs.specvista.com/assent/notifications.md # Notifications When Assent pushes, how quiet hours, reminders, --remind and due times work, and what you can answer from the lock screen. Pushes go to the Assent iPhone app. Everything else works on the web as well. ## A new ask When an agent asks, you get a push straight away. A plain to-do from an agent, with no question, buttons or items, does not push when it arrives; it reminds you at its due or reminder time instead. - **Answer from the push.** Approvals and to-dos show their buttons (up to 4). On iPhone, answer buttons on the lock screen need Face ID or your passcode. A code ask's button opens the app, where you type the code, and payments and sign-ins open the app too. - **Bursts become one push.** Asks from the same agent within 3 minutes of each other arrive as one push, and the asks of one [group](https://docs.specvista.com/assent/asks.md#groups) share a push. - **Fewer sounds.** An agent's pushes make a sound at most once every 10 minutes, and pushes are silent while you are using Assent on the web. - **A flood stays quiet.** When one agent sends more than 25 asks in 10 minutes, the extra asks arrive without a push. - **Asks a rule answers** never push. ## Quiet hours Quiet hours run from 22:00 to 07:30 in your time zone unless you change them. Set your time zone and quiet hours in **Settings**. During quiet hours, pushes wait and arrive when quiet hours end. Sign-in and code asks are the exception: they push straight away, because the agent is waiting on you. ## Due times and reminders An ask or to-do can have a due time (`--due`) and a reminder time (`--remind`). Both take a date and time, `2026-10-15T17:00` or `2026-10-15 17:00` (the agent computer's time zone), or with an offset such as `2026-10-15T17:00:00+01:00`. A bare date such as `2026-10-15` means 09:00 that day in your Assent time zone. Assent reminds you at the reminder time, or at the due time when there is no reminder time. While the ask stays open: - the first reminder goes at that time, and is skipped if it is more than 12 hours late, - one more follows 3 hours later, - after that, while it is overdue, one a day after 09:00, - and never more than 3 a day for one task. A reminder push has **Done**, **Snooze until tomorrow** and **Open**. ### Exact reminders A reminder time on a to-do (`assent task add --remind`, or a time you set yourself) pushes at that exact moment, even in quiet hours. Every other reminder waits for quiet hours to end. ### The daily reminder budget Reminders that are not exact share a daily budget, **Reminder pushes a day** in **Settings** on the web: 5 by default, from 0 to 50. At most 2 go out in any 30 minutes, the most important first: approvals from agents, overdue and due today, payments and high priority. Reminders for related to-dos, such as a series of payments or one project track, arrive together as one push. ## Before an ask expires Asks other than to-dos expire if nobody answers them in time (the ask's `answerExpiresAt` says when). Assent nudges you a day before and again an hour before it expires. ## Tidying up When an ask is answered, resolved or withdrawn, its push is cleared from your phone.