> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryhoard.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent permissions and safety

> How Hoard keeps a connected AI assistant from doing something dangerous to your store. Three layers: per-namespace permission grants, server-side risk scoring, and unconditional hard floors.

When an AI assistant has bearer-token access to your Hoard account, the question isn't "is the assistant authenticated" — it's "what's this specific call about to do, and is that worth a human glance?" Asking Claude to "increase my sales" is fine; Claude responding by setting every multiplier to 0.001x is not. Hoard's job is to make sure the second one can never happen, no matter how the conversation is framed.

We do that with three layers, applied to every write action.

## Layer 1: Permission grants

Permission grants are the **policy** for the assistant. Each kind of action has a mode:

| Mode                   | What it means                                                          |
| ---------------------- | ---------------------------------------------------------------------- |
| `deny`                 | Assistant cannot do this at all. Hard stop.                            |
| `always_ask`           | Every call needs an explicit click-through, no matter how low-risk.    |
| `ask_for_mutations`    | Reads run automatically; any change asks first. (This is the default.) |
| `auto_low_risk`        | Low and medium risk run automatically; high and critical ask first.    |
| `auto_unless_critical` | Only critical-risk calls ask first. Power-user mode.                   |

Defaults err on the side of asking. Edit a pricing rule? Default is `ask_for_mutations`. Run a sale? Default is `always_ask`. Change account settings? Default is `always_ask`.

These modes are seeded for you when you first enable agent permissions, and for most sellers they're the right call — let the assistant read freely, ask before changes. Editing individual modes per action from the UI isn't available yet (it's on the roadmap). For now, Settings → Assistants is a single Enable/Disable toggle plus a read-only view of the current grants.

New Hoard accounts start with permission gating on. Connected assistants get read access first, and mutations go through the seeded permission modes. Existing accounts keep their prior setting until you change it.

## Layer 2: Risk scoring (per call)

Even with a permission grant, every write call runs through a server-side risk scorer that classifies it as **low**, **medium**, **high**, or **critical** based on the actual parameters of the call.

The scorer is **user-relative**: a 25% multiplier change is "high risk" for a Stay Competitive seller (whose pricing wizard set the per-card change cap at 20%) but "medium risk" for a Win the Buy Box seller (cap 30%). The system uses what *you* told the pricing wizard you were comfortable with as the calibration point.

What pushes risk up:

* Larger multiplier changes
* Turning off "never go down" on rules that cover many cards
* Changing the price source
* Repricing across more cards
* Aggregate projected drop in your listed inventory value
* Lots of recent activity in the same session (cumulative escalation)

Even `pricing.suggest_rule` (which always lands as a *disabled* draft) can score `medium` for broad sweeps — 1000+ matched inventory cards with a multiplier more than 20% away from 1.0x. The rule still lands disabled, but `auto_low_risk` will pause and ask you to confirm before creating the draft so you read the scope before approving.

When a call's risk exceeds what your grant allows, the assistant returns the preview to you with a "confirm to proceed" link instead of committing. You click through (signed in, on hoard.tryhoard.com), Hoard issues a short-lived confirmation token, and the commit goes through.

## Layer 3: Hard floors (unconditional)

These are server-side invariants every write must clear, no matter who's calling — assistant, dashboard, API key, OAuth, anything. The assistant literally cannot construct a request that violates them. If it tries, the server returns a `floor_violation` error explaining which floor tripped and what to do about it.

Active hard floors today:

**Absolute minimum: \$0.01.** No listed price can ever go below one cent. Server-side invariant, not user-tunable.

**Your per-card price floor.** Defaults to \$1.00 but customizable in your pricing preferences. No card lists below this regardless of what the rule says.

**Per-rule aggregate drop cap.** Default 30%. A single rule application cannot drop your total listed inventory value by more than this percentage. Tunable per-user. The point: if you accidentally tell the assistant "discount everything by 40%," the server stops it.

**Per-session aggregate drop cap.** Default 20%, rolling 1-hour window. Cumulative across multiple calls in the same session — a series of "small" edits that together drop the store significantly will trip this even if no single edit was big enough on its own. Tunable per-user.

**Per-card clamps (inherited from your pricing rules).** Your `never_go_down` setting, your `change_cap_pct` (max % move per sync), your `hard_floor` — these already gate every reprice your dashboard runs, and they continue to gate everything an assistant initiates. The agent doesn't get to bypass anything you've configured for yourself.

## The flow in practice

What it looks like end-to-end when you ask Claude to "raise my Rare/Mythic pricing rule from 1.05x to 1.15x":

1. Claude calls the **preview** endpoint with the proposed change.
2. The server checks your grant for `pricing.edit_rule` (default: `ask_for_mutations`).
3. The risk scorer runs against the actual numbers. A 1.05 → 1.15 change is a +9.5% multiplier move. On a "Stay Competitive" cap-20 seller, that's `low` risk. On a more conservative cap-15 seller, it might be `medium`.
4. Hard floors run. They project what your aggregate listed value becomes after the change. If the rule covers 200 cards and the projected aggregate change is +\$80 (an increase, not a decrease), no floor trips.
5. Because your grant is `ask_for_mutations` and the action IS a mutation, the server returns a plan with `requires_confirmation: true`.
6. Claude shows you the preview: "200 cards affected, projected change +\$80, low risk, requires confirmation. Click here to confirm."
7. You click the link. It opens `/agent/plans/<plan_id>` in your already signed-in browser session, showing the same diff (cards affected, before/after listed total, risk pill). You tap **Approve**.
8. The server issues a 60-second confirmation token. Claude commits with the token within that window. The change applies.
9. Your audit log gets a new row: "edited rule X, multiplier 1.05 → 1.15, committed by Claude assistant at 2026-05-11 03:42 UTC."

If `pricing.edit_rule` were seeded to `auto_low_risk` and this call scored `low`, steps 5–7 are skipped — Claude commits in one round trip and tells you what just happened.

If the same edit had been "set the multiplier to 5.0x," the scorer would have flagged it `critical`, the floors might have tripped (a massive markup on an active rule can push some cards above sale-likely thresholds), and even with `auto_unless_critical` the call would have required confirmation.

## Audit log

Every committed change, every rejected-by-floor attempt, every expired plan that timed out without confirmation — they all go in your audit log. There's no dashboard page for it yet; the log is available through the activity API, and the easiest way to read it is to just ask a connected assistant ("show me everything you changed in the last week").

The audit row includes: what action, what risk score, who committed it, what the before/after state was, and which floor tripped if any. Rejections at commit time — wrong confirmation token, the plan's params changed between preview and commit, a floor that tightened mid-flight — are logged with their reason too, so a probing pattern shows up instead of vanishing silently.

## Best practices

* **Get comfortable with the seeded defaults.** Watch what gets asked. The defaults err toward asking before changes, which is the right starting point for most sellers. Per-action tuning (loosening one namespace to `auto_low_risk`, say) isn't in the UI yet — it's on the roadmap.
* **Set a per-card floor that reflects your actual minimum.** The default is $1.00. If you'd never list a card below $0.25, leave it at $1.00 — the cushion is your safety net. If you genuinely sell bulk commons at $0.10, lower it.
* **If you run flash sales, expect more confirmations.** Sales by their nature push risk up. The system will ask. That's working as intended; click through.
* **Check the audit log when something feels off.** It captures exactly what happened. If the assistant says it edited a rule and you can't see the change, ask a connected assistant to read the log back — it's the source of truth.

## What's NOT controlled by this

These are all **outside** the agent permissions system and have their own (older, stricter) controls:

* Sync mode (autonomous vs confirm) — set via the pricing wizard or Settings
* Pricing engine clamps (change\_cap\_pct, change\_cap\_mode) — set via the pricing wizard
* Revoking a connected assistant — done from [Settings → Assistants](https://www.tryhoard.com/settings/connected-apps)

These controls remain dashboard-only. An assistant cannot loosen them on its own.

## Tutorials

Walk-throughs for the flows sellers actually run into:

* [Your first agent-driven price change](/tutorials/first-agent-price-change)
* [Picking the right permission mode](/tutorials/picking-a-permission-mode)
* [Reading your agent activity log](/tutorials/reading-the-audit-log)
* [When the agent says 'I can't do that'](/tutorials/when-the-agent-says-no)
* [Rotating your agent bearer key](/tutorials/rotating-your-bearer-key)
* [Going from cautious to confident](/tutorials/trust-progression)

## Related reading

* [What your AI assistant can do](/agent-capabilities)
* [Connect Hoard to Claude](/connect-to-claude)
* [Pricing rules](/features/pricing)
* [Security](/security)
