An example
One rule: “Anything that sends data out needs approval if it touches both web content and internal data.”
If the FAQ page carried a prompt injection telling the model to post the roadmap, no single call looks wrong; the rule fires because of what the message is made of. An admin sees the held call in Approvals with the exact message, the rule and the labels, and approves or rejects it.
Five ideas
1. Side effects
Every tool declares one:read (fetches data), write (changes something in a connected system: a ticket, a card, a page) or egress (delivers content to people or places: a message, an email, an invitation, a comment). Rules and the read_only role constraint key off this, never off a tool’s name. The tool catalog lists each tool’s side effect.
2. Labels
Data carries labels such asinternal, confidential, untrusted and pii.
- Tools label what they return. Docs, Sheets, files, Jira, Trello and GitHub code are
internal; web search results areuntrusted; GitHub issues are bothinternalanduntrusted, because anyone who can open an issue writes that text. - Label rules add labels, e.g. “reading sheet
cust-2026isconfidential”. - Labels follow the workflow. A step’s inputs carry the labels of every step it depends on or references with
{{…}}. Parallel branches don’t share labels.
3. Rules
Action rules match on side effect, tools, labels and parameters, and return a verdict:allow, require_approval or deny. When several match, the most restrictive wins.
4. Approvals
A held step pauses the run where it is. Approving resumes it on the worker from that point. Steps that already finished never run again, and the approval covers that exact call (tool plus parameters) and nothing else.5. Receipts and audit
Every tool call writes a decision with the rule that made it and the labels involved:GET /api/v1/runs/{id}/authorization. The audit log is append-only and hash-chained, and the database rejects edits to it. GET /api/v1/organizations/{id}/audit-events/verify recomputes the chain and reports the first entry that doesn’t match.
Before a run starts, Fibonacci analyses the whole plan. If a rule would definitely deny a step, the run is refused up front (403) and nothing executes. POST /api/v1/workflows/{id}/authorization-preview shows that analysis without running anything.
Rules
Rules belong to an organization. Fibonacci ships templates, and nothing is active until an org saves a rule.Rule fields
Parameter operators:
equals, in, not_in, contains, startswith, domain_in, domain_not_in.
Label rules
- Paste links. Google Docs, Sheets, Slides and Drive links match the bare file ID a workflow uses, and the other way round.
- No placeholders. A whole value like
<YOUR_SHEET_ID>is rejected when you save (422) with a message to replace it.
Approvals
Approvals are opt-in: setapprovals_enabled in the org’s governance settings. Risk is assessed and audited either way.
Who hears about it
If your org has connected Slack (Organization → Integrations → Add to Slack), the Fibonacci bot sends DMs:- When something waits, to every admin and owner who can decide it (owners only when it needs an owner). The message says what is waiting (the tool and step, the workflow, or the agent), the rule and data labels or the risk reasons, who asked and when it expires, and links straight to it in Approvals.
- When it’s decided, to the person who asked: who approved or rejected it, their reason, and what happens next.
slack_approval_notifications: false. The Approvals inbox and the dashboard badge also refresh on their own.
Besides rules, whole runs can need approval by risk level. Fibonacci scores a workflow from the tools it uses (sending messages and email is high; creating channels, pages, tickets and cards is medium; reading company data is medium), and runs at or above approval_required_from wait for approval before they start.
Organization settings
Tool policies
Block a tool, or narrow what it may do, for the whole org or for one role (owner, admin, member, viewer).
In the dashboard: go to Governance → Tool permissions. Pick who the policy applies to and the tool, then set its access and limits. The editor only shows the settings that can affect that tool: a GitHub tool offers allowed repositories, and Slack offers channels and a message length. You can paste a github.com link for a repository. Each role’s row shows the limits that apply once the org’s policy is combined with it, and warns when the two leave nothing allowed. Owners make changes; admins see the policies.
Through the API:
"allowed": null keeps the org’s access and only adds limits. false blocks the tool for that role.
GET /api/v1/governance/tool-constraints returns this table for every tool, which is what the dashboard uses. For external agents, a policy names the agent’s tool (Bash, Write, or mcp__<server>__<tool>), and only blocks and read_only apply.
Without any policy, a tool works as soon as the person running it has connected it. Policies only ever narrow that, including for someone who saved their own token: a personal token only decides which credential a call uses, never whether a role may make it. Role constraints narrow the org’s: lists intersect, limits take the minimum, and read_only holds if either side sets it. An org block always wins.
Quota
A run over quota is refused when it’s queued (
429), with the limit it hit.
Workflow versions and the registry
Every execution runs a frozen version of the workflow, so a run is reproducible even if the workflow is edited later.Reporting
External agents
The same rules for Claude Code and any MCP client
Security
Production hardening and secrets