Web app
Access control and sources
Two pages about what an agent answers from: Access control says which person may see which source; Verified sources says which sources can be trusted at all.
When to use this
- One agent serves many people, and a person must not see another's data through it (a shared support or HR assistant).
- Answers are grounded in documents and databases, and you need to know whether those are the master copy or somebody's notes, and whether they are still current.
These are about end users and data. What an agent may do (call a tool) is a capability grant; see Contain tool calls.
Access control
In the web app Access control
/app/entitlement loads GET /api/entitlement/over-permission, /principals and /grants. Entitlement is checked when your retrieval asks the gateway to filter candidates for a caller (/api/entitlement/filter); until something does, the page says "Nobody is being checked yet".
Over-permission
Once checks run, four cards: the share of content held back because the caller was not cleared for it (this is not an error rate: it is what the agent could reach and correctly did not show), checks run in the window, distinct callers, and pieces of content evaluated. Why content was withheld breaks that down by reason.
Callers (principals)
+ Add a person or group: email or team name, display name, teams they belong to, and the sensitive categories they are cleared to see. Saved with PUT /api/entitlement/principals. The table shows subject, groups, clearances and data residency.
Grants
+ Add a grant: which source (the same key as on Verified sources), which person or team (must match a principal), and which sensitive categories the grant covers: sensitive personal data (pii_sensitive), insider financial information (mnpi), under legal hold, blackout-period restricted, insider-only. Saved with POST /api/entitlement/grants.
- Default deny: a resource with no grant is invisible to every caller.
- A grant does not open a restricted category on its own; the caller also needs the matching clearance.
- The web form always records the grantee as a
group. To grant to one person by subject, useagentfox permit user … --kind subject.
agentfox declare principal bob@example.com --groups support-team
agentfox permit user "kb/*" support-team
agentfox report entitlement✓ principal bob@example.com
groups: support-team
✓ support-team → kb/*
╭─ No entitlement decisions ─────────────────────────────────────────────────────╮
│ No access checks recorded yet — until the agent is told who's asking, it can't │
│ know whether they're cleared to see the answer. │
╰────────────────────────────────────────────────────────────────────────────────╯
Register a principal with `agentfox declare principal <subject>`, then filter retrieval through
/api/entitlement/filter.Verified sources
In the web app Verified sources
/app/sources loads GET /api/sources and /api/sources/health. A tier is a person's claim about a source; validation is AgentFox fetching it and checking the content is still what it was.
- A bar shows how many sources sit in each tier:
system_of_record,approved,unverified,external. A card appears when sources are past their freshness SLA; a note when deprecated or unowned sources remain. - Registered sources: tier, key (with
deprecatedandsample datatags), connection (Database, Enterprise API / KB, plain URL, or none), owner, domain, freshness (fresh or stale against its SLA), content check, and an actions menu (⋯).
Add a source
+ Add a source asks what you are adding:
- Just a name: register it now with a tier, connect it later.
- Database: PostgreSQL, MySQL, SQL Server or SQLite; host, port, database, username, password, and optionally a table to fingerprint (otherwise every table name is used) so schema drift is detected.
- API or knowledge base: Confluence, SharePoint, Notion or any authenticated REST endpoint; the URL to check, the auth header name (default
Authorization), a prefix (defaultBearer) and the token.
Every type asks for the name your team uses, the tier ("Official company data, kept up to date" through "Someone's personal notes, or an outside source"), the owner's email and how often it is updated (daily, weekly, monthly, rarely). Submit registers it with PUT /api/sources and, for a database or API, attaches the connection with POST /api/sources/connections. If the connection fails, the source stays registered and the error says so.
The actions menu
- Edit details: tier, owner, domain, freshness SLA (only for sources something can re-read), and un-deprecate.
- Connect a database or API / Reconnect: for a source that is a bare name, or to re-point one. Not offered for an
http(s)key, which is fetched directly. - Validate now (
POST /api/sources/{key}/validate): fetch and compare. The content check column then reads content verified, content changed since last check, or could not fetch. A bare name with no connection cannot be validated and the menu says so. - Deprecate (
DELETE /api/sources/{key}): keep the record as "do not trust"; every answer grounded in it raises a finding. - Delete permanently, offered only once deprecated (
?hard=true): removes the record and with it the do-not-trust signal, so an answer grounded in it afterwards looks unverified rather than flagged.
agentfox declare source ticket-history --tier system_of_record --owner support-ops@example.com --sla-hours 24
agentfox declare list sources✓ ticket-history → system_of_record
! a 24h SLA is set but no update time is recorded, so this reads as stale. Pass --updated when the
source changes.
tier source owner domain state
approved crm-notes priya@example.com support ok
system_of_record help-center-articles priya@example.com support ok
system_of_record ticket-history support-ops@example.com — age unknownFor a whole corpus, agentfox declare import-sources sources.json registers a JSON list in one go. (The empty-state text in the app shows the older command name.)
Check ingestion quality
At the foot of the page, not tied to a registered source. Check one document takes extracted text and looks for encoding damage, mojibake, unbalanced code fences and words glued together by a lost space. Check chunk boundaries takes chunks separated by blank lines and looks for orphan fragments, mid-sentence splits and headings with no body. Both call POST /api/sources/context-check.
{"document":{"score":0.9,"usable":true,"findings":[{"code":"control-characters","detail":"3.5% of the document is control or private-use characters, which usually means a binary was read as text","severity":"warn","evidence":{"printable_ratio":0.9649},"verdict":"allow"}]}}Common tasks
| You want to | Run |
|---|---|
| Register the person an agent acts for | agentfox declare principal alice@example.com --groups support-team --clearances pii_sensitive |
| Grant a group a resource pattern | agentfox permit user "kb/*" support-team |
| Grant one person | agentfox permit user ticket-history alice@example.com --kind subject |
| How much more the agent reaches than callers may see | agentfox report entitlement |
| Tier a source | agentfox declare source ticket-history --tier system_of_record |
| List sources and their state | agentfox declare list sources |
What can go wrong
- Access control stays on "Nobody is being checked yet". Principals and grants alone do nothing; your retrieval must pass candidates through the entitlement filter with the caller's identity. See Retrieval and answers.
- A grant has no effect. The principal name in the grant must match a registered principal or one of its groups exactly, and the resource must match the source key.
- A source reads stale right after registering. An SLA with no recorded update time is stale by definition. Pass
--updated, or validate it. - "registered, but the connection failed". The gateway could not reach the database or API with those credentials, from where it runs.
Limits
- No edit or delete for principals and grants in the web app.
- A tier is a claim. Only validation checks content, and only for URLs and connected sources.