Specvista Docs

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:

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:

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 codeDecision
0A rule allows it
10A rule denies it
11No 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.

assent rules add --deny --action Bash --target "git push*" --reason "Pushing deploys" --expires 30d
assent rules remove <rule-uuid>

--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.
  • The hook fails open to ask: 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).

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:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Edit|Write|MultiEdit|WebFetch|mcp__.*",
        "hooks": [{ "type": "command", "command": "ASSENT_CONFIG=$HOME/.assent/claude-code.json assent hook pre-tool-use", "timeout": 10 }]
      }
    ]
  }
}

Try it by hand:

echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | assent hook pre-tool-use

On its way to npm

The Assent command line tools are on their way to npm, so there is no install command yet. Asks already work from the HTTP API and MCP, and you answer them in the app and on the web.

On this page