Audit logs
Polyant keeps three audit trails: what an agent’s tools did, who changed who could do what, and who changed a configuration or an account. The panel reads all of them in the Monitor. The tool trail is the Monitor’s Tools type; with managed services the other two are its Changes. The earlier Audit Logs screen and the organization’s Audit page redirect there.
The three audit tiers
Polyant keeps them separate on purpose, and the three line up with the three tenancy levels. Knowing which one to open saves a lot of searching:
| Trail | Tier | Answers | Where |
|---|---|---|---|
| Tool audit | workspace | What did an agent’s tools do? | the workspace Monitor, Tools type, or one agent’s Monitor section |
| Authorization audit | organization | Who changed who could do what? | the organization’s Monitor, Changes (managed services, advanced audit); see Authorization audit |
| Management audit | installation, and each organization | Who changed a configuration, and who touched an account? | the Changes of the Monitor: the workspace’s for changes recorded against it, the organization’s for its whole trail, the Admin Console’s (/platform/monitor) for the whole deployment (managed services) |
A tool call that failed and a role that was widened are different questions, and they sit under different types of the same timeline.
Managed services. Reading the management and authorization trails in the panel is available with Polyant managed services. The open-source build records management changes and serves the tool trail.
The organization’s Monitor combines management and authorization events in one newest-first list under Changes. Management events appear without advanced audit; authorization events appear only with that licence. The organization’s Audit (/organizations/{org}/settings/organization/audit), its earlier Management audit and Authorization audit addresses, and the Admin Console’s /platform/settings/audit redirect to those Changes. The API routes behind the old pages remain: GET /api/organizations/{orgSlug}/audit-logs (both trails), /management-audit-logs and /authz-audit-logs, each under org.audit:read, and GET /api/platform/audit-logs for platform admins.
The management trail is always paginated, and an organization can read its own, under org.audit:read - the same key that gates the authorization trail beside it, because it is the same disclosure and two switches for one idea would leave nobody able to say why one was granted and not the other. Owner and Admin hold it; Member and Viewer do not. Unlike the authorization trail, it is not gated on the advanced-audit feature: who changed what is the base compliance record of a managed-services deployment, not an upsell. In a workspace’s Monitor the changes recorded against that workspace are read under audit_log:read. Every row carries the organization and workspace it belongs to, which is what makes that possible: the table used to record who did what to which target and never where, so filtering by tenant was impossible and platform-admin-only was a consequence of the schema rather than a decision. A platform-level action - the bootstrap, a cross-tenant operation - genuinely belongs to no tenant, and the columns are left empty rather than given an invented owner.
On upgrade, rows that name an agent are attributed through its slug, which is unique across the deployment. What cannot be resolved stays unattributed, because the alternative is an organization admin opening the page on day one, seeing nothing, and concluding it is broken.
What gets a row is no longer a short list. The rule is that a mutation somebody would have to explain afterwards must leave something to explain it from, and the product now applies it to every mutating route: an agent’s own settings, its prompts, tools, skills and skill versions, its hooks, its scheduled tasks (recorded before a manual run fires, since the run is fire-and-forget), its channels and MCP servers, organizations and workspaces through their lifecycle, management API keys, invitations, the skill catalogue, governance policies, provider admissions, connections and role bindings, the grant of the deployment’s AWS identity, dev-mode grants and tokens, shared knowledge libraries, a conversation destroyed by hand, memories written or purged, and a person changing their own password.
The exemptions are written down rather than assumed - a read-only probe, an agent’s icon, starting a two-factor enrolment that changes no standing. A guardrail enforces this per handler, not per file: a controller that audits some of its mutations used to vouch for the ones it did not, which is exactly how one route lost its row in a rebase and nothing went red.
What a row never carries is the thing that would make the trail itself a disclosure: a secret’s value, an API key or its hash, a dev token, a provider connection’s credentials, a knowledge document’s content, a channel’s token or phone number. Names, types, sizes and target ids only.
The tool audit
Every tool call an agent makes writes one row: the agent, the tool, the action, the input (redacted for sensitive tools), the output or the error, the duration, and the conversation and assistant message that issued it. Reading it needs audit_log:read (Admin and above), and the rows are scoped to the caller’s organization and narrowed to the active workspace, so “all agents” means all agents you can see, never the whole deployment.
In the panel a tool call is a Tools row of the Monitor: the drawer shows its Arguments, its Result and any error, and links to the conversation. Rows older than the Analytics retention installation policy (90 days by default) are deleted by the daily housekeeping, and deleting a conversation deletes its tool calls.
Reading it through the API
GET /api/audit-logs returns the rows, filtered by instanceId, toolName, action, search (over the details), conversationId, from and to, and paged with limit (default 50, at most 200) and offset. GET /api/audit-logs/stats returns the total, the error count, the error rate and the counts by tool and by action for instanceId, from and to. Both require audit_log:read and apply the same organization and workspace scoping as the panel.
Each row carries messageId, the assistant message that issued the call. Opening the conversation with ?around=<messageId> and the #msg-<messageId> fragment loads the window containing that turn and scrolls to it. The id is missing in four cases: a pre-LLM hook, the opt-out gate, spawnTask, and every row written before the migration that added tool_audit_logs.message_id. That column is nullable and deliberately not backfilled - the assistant message a historical tool call belonged to is not recoverable after the fact - so an old row points to its conversation and not to its turn.
See also
- Monitor - the timeline that reads these trails, with live updates.
- Authorization audit - role and membership changes.
- Roles and permissions - who holds
audit_log:readandorg.audit:read.