EQTY LabDocs

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.

gethttps://<host>/api/v1/agents/{agentId}/profile/draft
bash
curl --request GET \
  --url 'https://<host>/api/v1/agents/{agentId}/profile/draft' \
  --header 'Authorization: Bearer <token>'
javascript
const response = await fetch("https://<host>/api/v1/agents/{agentId}/profile/draft", {
  method: "GET",
  headers: {
    "Authorization": "Bearer <token>"
  }
});

const data = await response.json();
typescript
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();
python
import requests

response = requests.get(
    "https://<host>/api/v1/agents/{agentId}/profile/draft",
    headers={
        "Authorization": "Bearer <token>",
    },
)
response.raise_for_status()
print(response.json())
go
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))
}
java
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());
    }
}
csharp
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
<?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;
ruby
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}"
rust
// 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

NameTypeDescription
agentId
required
string

Agent ID

Query parameters

NameTypeDescription
startstring

RFC3339 start time (default: 30 days before end)

endstring

RFC3339 end time (default: now)

state_cidstring

State CID whose configuration to draft from (default: the agent's newest usable observation)

Responses

200OK

application/json
  • agent_idstring
  • candidatesgithub_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.Candidate

    • matchstring

      Match is the rule an operation for the tool would carry.

    • suggested_impactagentprofile.Impact[]
    • systemstring

      System 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_idstring
  • coveragegithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Coverage
    Show github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Coverage
    • configurationobject

      Configuration is the one permissions were read from, or null.

      Show properties
      • app_typestring
      • cidstring
      • observed_atstring
      • state_cidstring
    • configuration_unavailablestring

      ConfigurationUnavailable says why no configuration was read.

    • hoststring

      Host 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.Coverage
      Show github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.Coverage
      • calls_not_visibleinteger
      • declaredgithub_com_eqtylab_gateway_control-plane_service_internal_toolinventory.DeclaredCoverage
        Show github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.DeclaredCoverage
        • claude_code_configstring
        • definitionstring
      • limitsstring[]
      • llm_exchangesinteger
      • tools_not_visibleinteger
      • tools_readinteger
      • tools_unreadableinteger
      • unread_endpointsgithub_com_eqtylab_gateway_control-plane_service_internal_toolinventory.UnreadEndpoint[]
        Show properties

        Array of github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.UnreadEndpoint

        • exchangesinteger
        • operationstring
        • providerstring
    • limitsstring[]
    • mcpstring

      MCP is configured when the configuration names servers; else via_tool_names.

    • permissionstring

      Permission is checked, not_captured (the app's integration derives none) or no_configuration.

    • toolstring

      Tool is checked when the window read at least one tool list, and not_visible otherwise.

  • documentgithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Document
    Show github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Document
    • accountableTeamstring
    • contextagentprofile.Context
      Show agentprofile.Context
      • actsForagentprofile.ActsFor

        One ofinvoking_userown_identity

      • modeagentprofile.Mode

        One ofinteractiveunattended

      • usersagentprofile.Users

        One ofinternalexternalboth

    • purposestring
    • schemaVersionstring
    • systemsagentprofile.System[]
      Show properties

      Array of agentprofile.System

      • accessagentprofile.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.

      • namestring

        Name 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.Operation

        • excludedboolean

          Excluded means the agent must never perform the operation.

        • impactagentprofile.Impact[]

          Impact says what a call can cause, sorted. Empty on an excluded operation.

        • matchstring
        • oversightagentprofile.Oversight
          Show agentprofile.Oversight
          • kindagentprofile.OversightKind

            One ofapprovalreview

          • notestring

            Note 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.SystemEvidence

    • itemsgithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Item[]
      Show properties

      Array of github_com_eqtylab_gateway_control-plane_service_internal_profilecheck.Item

      • callsinteger
      • descriptionstring
      • hoststring
      • kindstring
      • last_seen_atstring
      • match_keystring
      • namestring
      • namespacestring
      • permissionstring
      • run_bystring
      • serverstring
      • sourcesstring[]
      • 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
    • namestring
    • sourcestring
    • suggested_datagithub_com_eqtylab_gateway_control-plane_service_internal_profilecheck.DataHint[]

      SuggestedData are data classes the tools' input fields suggest. The document's data stays 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.DataHint

      • classagentprofile.DataClass

        One ofpublicinternalconfidentialpersonalspecial_categoryfinancialcredentials

      • fieldsstring[]
  • 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.Item

    • callsinteger
    • descriptionstring
    • hoststring
    • kindstring
    • last_seen_atstring
    • match_keystring
    • namestring
    • namespacestring
    • permissionstring
    • run_bystring
    • serverstring
    • sourcesstring[]
    • 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.Window
    Show github_com_eqtylab_gateway_control-plane_service_internal_toolinventory.Window
    • endstring
    • startstring
Examplejson
{
  "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

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}

401Unauthorized

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}

403Forbidden

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}

404Not Found

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}

409The state named by state_cid can't be used

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}

422The state named by state_cid can't be read

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}

500Internal Server Error

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}

503Service Unavailable

application/json
  • codestring
  • correlation_idstring
  • messagestring
Examplejson
{
  "code": "string",
  "correlation_id": "string",
  "message": "string"
}