Documentation
Privacy, budget & audit
PII redaction guarantees, monthly message budgets per plan, and how every assistant turn lands in the tamper-evident audit log.
Last updated May 10, 2026
The compliance copilot is held to the same evidence bar as the rest of Attestly: nothing leaves the workspace without a redaction pass, nothing happens that isn't recorded, and you can't accidentally rack up an unbounded LLM bill.
PII redaction
Every user prompt and every assistant response is run through
src/lib/assistant/redact.ts before any LLM call and again before
storage. The redactor catches:
| Pattern | Replaced with |
|---|---|
| Email addresses | [redacted-email] |
| Phone numbers (E.164 + common US formats) | [redacted-phone] |
US SSN-shaped strings (###-##-####) | [redacted-ssn] |
| Luhn-validated credit-card numbers | [redacted-cc] |
API tokens (atst_live_…, att_live_…, sk_live_…, pk_live_…, generic high-entropy 32+ char) | [redacted-token] |
| PEM private keys | [redacted-key] |
| IPv4 / IPv6 addresses | [redacted-ip] |
Tool arguments and tool results pass through the same recursive
redactor (redactJson) before they're persisted, so a
get_document result that happens to quote a customer email in your
Privacy Policy is redacted at-rest in the assistant's message history.
The redactor is failsafe: if you spot a pattern we miss, please email
security@attestly.dev with a sample (we accept synthetic samples).
What is not redacted
We deliberately leave repository-style identifiers alone — file paths, package names, GitHub org/repo slugs, version tags. Redacting those would make answers useless. If you need to ask about a vendor without naming it, the assistant will follow your lead.
Audit-log coverage
| Event | Action key | Target |
|---|---|---|
| User sends a message | assistant.message | assistant_thread:<id> |
| Assistant proposes a mutating tool | assistant.tool.proposed | assistant_thread:<id> |
| Mutating tool confirmed and executed | assistant.tool.<name> | the affected entity (e.g. drift_alert:<id>) |
| Public Trust Q&A question received | trust_qna.question | tenant:<id> |
| Settings changed (expert default, budget override, Q&A toggle) | settings.assistant.update / settings.trust_qna.update | tenant:<id> |
Every entry chains into the same SHA-256 hash chain as the rest of
your audit log and is signed Ed25519 — see operations/audit-log.
Run the standalone @attestly/audit-cli against an export to verify
the chain offline.
We store the hash of the redacted prompt and response on each
assistant message row (redacted_input_hash, redacted_output_hash)
so the audit chain commits to the conversation content without
re-storing the (already-redacted) text in plaintext on the
audit-log row itself.
Monthly message budgets
The assistant has hard per-tenant budgets enforced in
src/lib/assistant/budget.ts:
| Plan | In-product copilot / month | Trust Q&A / month | Per-user rate limit |
|---|---|---|---|
| Free | 0 | 0 | — |
| Starter | 250 | 0 | 12 / minute |
| Growth | 1,500 | 500 | 12 / minute |
| Scale | 10,000 | 5,000 | 12 / minute |
| Enterprise | Unlimited (fair-use) | Unlimited (fair-use) | 12 / minute |
A workspace owner can override the in-product copilot budget upward
on Scale and Enterprise via Settings → Compliance copilot → Monthly message budget (set to 0 to fall back to the plan default). The
override is stored in tenants.assistant_message_budget_monthly.
When the budget is exhausted the assistant responds with a friendly "out of budget for this month" message and the LLM is not called. The budget rolls over on the first of each calendar month (UTC).
Cost telemetry
Every turn writes the prompt-token and completion-token counts plus
an estimated cost in micro-dollars (assistant_messages.prompt_tokens,
completion_tokens, cost_micros). assistant_usage rolls those
up monthly per tenant for billing and capacity planning. Owners can
see the current month's totals at Settings → Compliance copilot.
BYO-LLM end-to-end
If you've configured an OpenAI-compatible BYO-LLM endpoint at
Settings → AI provider, every component on this page honours it:
- Document generation uses your endpoint.
- The compliance copilot uses your endpoint, including tool calls.
- The public Trust Q&A widget uses your endpoint.
This means assistant traffic also counts against your provider's rate limits and your provider's billing — Attestly's monthly budget on top is purely an internal abuse / runaway guard. Set your provider-side limits accordingly.
If your endpoint goes down, assistant turns return a graceful "copilot temporarily unavailable" error rather than failing silently. Document generation has the same behavior.