Triage shadow agents
A shadow agent is an agent doing work with no matching registered agent. Bairav infers candidates from the events it already receives and gives you an evidence-based score to triage. Nothing here blocks, stops, isolates or removes anything: detection and human review only. Requesting registration creates a notification and a review record; escalating creates an incident.
You need the view_security permission to read, and investigate_security to act.
How a candidate is scored
The score is an evidence score, not a calibrated probability. It is built from seven categories, each with a maximum weight:
| Category | Max |
|---|---|
| Endpoint signature (talks to a model provider) | 20 |
| Tool behaviour | 20 |
| Framework signature | 15 |
| Registry mismatch | 15 |
| Session recurrence | 10 |
| Identity attribution | 10 |
| Multiple sources | 10 |
Bands: low below 35, medium 35 to 64, high 65 and above. GET /api/shadow-agents/method returns the live method, thresholds and caveats, and GET /api/shadow-agents/signatures the signature catalogue.
Classifications
managed, suspected_unmanaged, confirmed_unmanaged, authorized_exception, false_positive and insufficient_evidence.
Work the queue
| Task | Call |
|---|---|
List candidates (filter by classification, band, status, assignee, search) | GET /api/shadow-agents |
| Open one, with its score breakdown, timeline, endpoints, tools, registry matches and coverage gaps | GET /api/shadow-agents/{id} |
| Record a decision | POST /api/shadow-agents/{id}/review with decision |
| Assign an investigator | POST /api/shadow-agents/{id}/assign |
| Link it to a registered, approved agent | POST /api/shadow-agents/{id}/link |
| Ask the owner to register it | POST /api/shadow-agents/{id}/request-registration |
| Raise an incident | POST /api/shadow-agents/{id}/escalate |
| Run discovery now | POST /api/shadow-agents/scan (10 a minute per tenant) |
review accepts note, approve_known, false_positive, confirm_unmanaged, insufficient_evidence, reopen and exception_granted. Assign, link, request-registration and escalate have their own routes, because they need their own inputs. An exception_granted decision needs a note and an expires_at at most 365 days ahead; when it expires the candidate returns to the queue. Repeating a decision that would change nothing returns 409.
Every decision appends an immutable review row and an Audit ledger entry.
Honest coverage
Each candidate lists coverage gaps, for example "No network or DNS telemetry is connected: encrypted traffic cannot be attributed". Read them: a low score with large gaps means "we cannot see", not "it is safe".