Draft an agent's operating profile
Drafts a profile from the agent's tool inventory and captured configuration: a system for each MCP server, Responses namespace and registrable domain its traffic reached, one for the tools the agent's app defines itself (named for the app, such as Claude Code tools) and one for the tools its model provider runs, grouped by where each tool comes from rather than by name, with access suggested from tool names and descriptions. An app's or provider's tool the agent was only offered stays out, among the unassigned. The document is a starting point, not a valid profile: purpose, accountable team and context are left for the owner. Tools whose names suggest consequence come back as candidates beside it, and items it couldn't place as unassigned. Systems lists, in the document's order, the items each system covers and the data classes its tools' inputs suggest.
https://<host>/api/v1/agents/{agentId}/profile/draftcurl --request GET \
--url 'https://<host>/api/v1/agents/{agentId}/profile/draft' \
--header 'Authorization: Bearer <token>'const response = await fetch("https://<host>/api/v1/agents/{agentId}/profile/draft", {
method: "GET",
headers: {
"Authorization": "Bearer <token>"
}
});
const data = await response.json();interface AgentProfileDraftResponse {
agent_id?: string;
candidates?: Record<string, unknown>[];
correlation_id?: string;
coverage?: Record<string, unknown>;
document?: Record<string, unknown>;
systems?: Record<string, unknown>[];
unassigned?: Record<string, unknown>[];
window?: Record<string, unknown>;
}
const response = await fetch("https://<host>/api/v1/agents/{agentId}/profile/draft", {
method: "GET",
headers: {
"Authorization": "Bearer <token>"
}
});
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
const data: AgentProfileDraftResponse = await response.json();import requests
response = requests.get(
"https://<host>/api/v1/agents/{agentId}/profile/draft",
headers={
"Authorization": "Bearer <token>",
},
)
response.raise_for_status()
print(response.json())package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, err := http.NewRequest(http.MethodGet, "https://<host>/api/v1/agents/{agentId}/profile/draft", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer <token>")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
data, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(res.Status, string(data))
}import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://<host>/api/v1/agents/{agentId}/profile/draft"))
.header("Authorization", "Bearer <token>")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, "https://<host>/api/v1/agents/{agentId}/profile/draft");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "<token>");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");<?php
$ch = curl_init('https://<host>/api/v1/agents/{agentId}/profile/draft');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer <token>',
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
echo $status . " " . $response . PHP_EOL;require "net/http"
uri = URI("https://<host>/api/v1/agents/{agentId}/profile/draft")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer <token>"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts "#{response.code} #{response.body}"// Cargo.toml dependencies: reqwest, tokio (features "full")
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = reqwest::Client::new()
.get("https://<host>/api/v1/agents/{agentId}/profile/draft")
.header("Authorization", "Bearer <token>")
.send()
.await?;
println!("{} {}", response.status(), response.text().await?);
Ok(())
}Authorizations
BearerAuth· API key in header "Authorization" — Type "Bearer" followed by a space and a sign-in token: a Guardian Platform JWT, or an OIDC ID token in a standalone deployment.ApiKeyAuth· API key in header "Authorization" — Type "Bearer" followed by a space and a Guardian Platform API key. Project-scoped routes and registration tokens check the key's scopes and project binding. Per-agent routes accept a key bound to no project that has empty scopes or full access, which acts as its holder, or a scope for what the route does: submit_agent_assessments reads an agent (its detail, configurations, state history and the files a state references, definitions, tools and operating profile, as its assessments rest on), view_agent_certifications reads its certifications, and manage_programs or review_agent_assessments attach a certification. A state's raw snapshot and findings, its audit exchanges and plugin events, and saving its operating profile take full access. A scope counts only while the key's holder still holds that permission in the key's organization, which auth-service reports as keyHeldScopes. A key never acts as an admin, so its holder's binding to the agent still decides.
Parameters
Path parameters
| Name | Type | Description |
|---|---|---|
agentIdrequired | string | Agent ID |
Query parameters
| Name | Type | Description |
|---|---|---|
start | string | RFC3339 start time (default: 30 days before end) |
end | string | RFC3339 end time (default: now) |
state_cid | string | State CID whose configuration to draft from (default: the agent's newest usable observation) |
Responses
200OK
agent_idstringcandidatesgithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Candidate[]Candidates are tools whose names suggest consequence, among those the draft covers or the agent called. Each needs the owner's answer: fine as is, an operation with oversight, or excluded.
Show properties
Array of
github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.CandidatematchstringMatch is the rule an operation for the tool would carry.
suggested_impactagentprofile.Impact[]systemstringSystem is the drafted system the tool is in; empty when unassigned.
verbsstring[]Verbs are the words in the tool's name the impacts come from.
correlation_idstringcoveragegithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.CoverageShow github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Coverage
configurationobjectConfiguration is the one permissions were read from, or null.
Show properties
app_typestringcidstringobserved_atstringstate_cidstring
configuration_unavailablestringConfigurationUnavailable says why no configuration was read.
hoststringHost is gateway_traffic_only: hosts the agent reached directly, or over stdio, are never seen. no_traffic when the window holds no exchanges.
inventorygithub_com_eqtylab_gateway_control-plane_service_internal_toolinventory.CoverageShow github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.Coverage
calls_not_visibleintegerdeclaredgithub_com_eqtylab_gateway_control-plane_service_internal_toolinventory.DeclaredCoverageShow github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.DeclaredCoverage
claude_code_configstringdefinitionstring
limitsstring[]llm_exchangesintegertools_not_visibleintegertools_readintegertools_unreadableintegerunread_endpointsgithub_com_eqtylab_gateway_control-plane_service_internal_toolinventory.UnreadEndpoint[]Show properties
Array of
github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.UnreadEndpointexchangesintegeroperationstringproviderstring
limitsstring[]mcpstringMCP is configured when the configuration names servers; else via_tool_names.
permissionstringPermission is checked, not_captured (the app's integration derives none) or no_configuration.
toolstringTool is checked when the window read at least one tool list, and not_visible otherwise.
documentgithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.DocumentShow github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Document
accountableTeamstringcontextagentprofile.ContextShow agentprofile.Context
actsForagentprofile.ActsForOne of
invoking_userown_identitymodeagentprofile.ModeOne of
interactiveunattendedusersagentprofile.UsersOne of
internalexternalboth
purposestringschemaVersionstringsystemsagentprofile.System[]Show properties
Array of
agentprofile.Systemaccessagentprofile.Access[]Access is sorted.
dataagentprofile.DataClass[]Data lists the classes of data the agent can read or write there, sorted.
matchstring[]Match lists the tools, MCP servers, hosts and permissions that make up the system, sorted.
namestringName is the owner's name for the system, such as
GitHub.operationsagentprofile.Operation[]Operations lists the operations that need saying more about, sorted by Match.
Show properties
Array of
agentprofile.OperationexcludedbooleanExcluded means the agent must never perform the operation.
impactagentprofile.Impact[]Impact says what a call can cause, sorted. Empty on an excluded operation.
matchstringoversightagentprofile.OversightShow agentprofile.Oversight
kindagentprofile.OversightKindOne of
approvalreviewnotestringNote says where the oversight happens, such as a permission prompt or a required code review.
typestring
systemsgithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.SystemEvidence[]Systems is the evidence for each system in Document, in the same order: the items it covers and the data its tools' inputs suggest.
Show properties
Array of
github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.SystemEvidenceitemsgithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Item[]Show properties
Array of
github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Itemcallsintegerdescriptionstringhoststringkindstringlast_seen_atstringmatch_keystringnamestringnamespacestringpermissionstringrun_bystringserverstringsourcesstring[]suggested_accessagentprofile.Access[]SuggestedAccess is what the draft guesses the item needs, from every verb in a tool's name, or its description's first word when the name has none; empty when it has no guess. The check leaves it out.
traffic_kindstring
namestringsourcestringsuggested_datagithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.DataHint[]SuggestedData are data classes the tools' input fields suggest. The document's
datastays empty: what a system holds is the owner's to say, and a wrong "none" would under-declare it.Show properties
Array of
github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.DataHintclassagentprofile.DataClassOne of
publicinternalconfidentialpersonalspecial_categoryfinancialcredentialsfieldsstring[]
unassignedgithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Item[]Unassigned are items the draft could not place in a system, could not fit in the profile, or left out because the agent was only ever offered them: an app's or provider's tool it never called.
Show properties
Array of
github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Itemcallsintegerdescriptionstringhoststringkindstringlast_seen_atstringmatch_keystringnamestringnamespacestringpermissionstringrun_bystringserverstringsourcesstring[]suggested_accessagentprofile.Access[]SuggestedAccess is what the draft guesses the item needs, from every verb in a tool's name, or its description's first word when the name has none; empty when it has no guess. The check leaves it out.
traffic_kindstring
windowgithub_com_eqtylab_gateway_control-plane_service_internal_toolinventory.WindowShow github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.Window
endstringstartstring
{
"agent_id": "string",
"candidates": [
{
"match": "string",
"suggested_impact": [
"financial"
],
"system": "string",
"verbs": [
"string"
]
}
],
"correlation_id": "string",
"coverage": {
"configuration": {
"app_type": "string",
"cid": "string",
"observed_at": "string",
"state_cid": "string"
},
"configuration_unavailable": "string",
"host": "string",
"inventory": {
"calls_not_visible": 0,
"declared": {
"claude_code_config": "string",
"definition": "string"
},
"limits": [
"string"
],
"llm_exchanges": 0,
"tools_not_visible": 0,
"tools_read": 0,
"tools_unreadable": 0,
"unread_endpoints": [
{
"exchanges": 0,
"operation": "string",
"provider": "string"
}
]
},
"limits": [
"string"
],
"mcp": "string",
"permission": "string",
"tool": "string"
},
"document": {
"accountableTeam": "string",
"context": {
"actsFor": "invoking_user",
"mode": "interactive",
"users": "internal"
},
"purpose": "string",
"schemaVersion": "string",
"systems": [
{
"access": [
"read"
],
"data": [
"public"
],
"match": [
"string"
],
"name": "string",
"operations": [
{
"excluded": true,
"impact": [
"financial"
],
"match": "string",
"oversight": {
"kind": "approval",
"note": "string"
}
}
]
}
],
"type": "string"
},
"systems": [
{
"items": [
{
"calls": 0,
"description": "string",
"host": "string",
"kind": "string",
"last_seen_at": "string",
"match_key": "string",
"name": "string",
"namespace": "string",
"permission": "string",
"run_by": "string",
"server": "string",
"sources": [
"string"
],
"suggested_access": [
"read"
],
"traffic_kind": "string"
}
],
"name": "string",
"source": "string",
"suggested_data": [
{
"class": "public",
"fields": [
"string"
]
}
]
}
],
"unassigned": [
{
"calls": 0,
"description": "string",
"host": "string",
"kind": "string",
"last_seen_at": "string",
"match_key": "string",
"name": "string",
"namespace": "string",
"permission": "string",
"run_by": "string",
"server": "string",
"sources": [
"string"
],
"suggested_access": [
"read"
],
"traffic_kind": "string"
}
],
"window": {
"end": "string",
"start": "string"
}
}400Bad Request
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}401Unauthorized
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}403Forbidden
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}404Not Found
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}409The state named by state_cid can't be used
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}422The state named by state_cid can't be read
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}500Internal Server Error
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}503Service Unavailable
codestringcorrelation_idstringmessagestring
{
"code": "string",
"correlation_id": "string",
"message": "string"
}