---
title: "CreateAgentHookEvent"
method: POST
path: "/v1/namespaces/{tenant_meta.namespace}/agent-hook-events"
tags: ["AgentHookEventService"]
---

# CreateAgentHookEvent

`POST /v1/namespaces/{tenant_meta.namespace}/agent-hook-events`

## Request

- Base URL: `https://api.endorlabs.com`
- URL: `https://api.endorlabs.com/v1/namespaces/{tenant_meta.namespace}/agent-hook-events`
- Auth: none declared

Creates an AgentHookEvent.

## Path parameters

- `tenant_meta.namespace` string, required

## Request body

- AgentHookEventServiceCreateAgentHookEventBody: AgentHookEvent represents a single event emitted by the agent runtime. Each event has a type, context, and optional type-specific payload.
  - `consumers_failed` string[]: Consumer keys that failed to process this event. Used for retry.
  - `meta` V1Meta, required: Common fields for all Endor Labs resources.
    - `annotations` object: Annotations can be used to attach metadata to a resource message. Annotation values can be small or large, structured or unstructured, and may include characters not permitted by labels. The keys may contain alphanumerics, underscores (_), dots (.) and dashes (-). The values of an annotation must be 16384 bytes or smaller.
    - `create_time` string, date-time: Time the resource was created. Format: 2017-01-15T01:30:15.01Z RFC 3339: https://www.ietf.org/rfc/rfc3339.txt.
    - `created_by` string: Name and authentication source of the user who created the object, for example, ewok@endor.ai@google@api-key.
    - `description` string: Resource description. Must be less than 1024 bytes.
    - `index_data` V1IndexData: IndexData is used to index the resource for search. It's an internal object.
      - `data` string[]
      - `search_score` number, float: search_score is the score of the resource for search. Internal use only.
      - `tenant` string
      - `will_be_deleted_at` string, date-time: Time that the resource will be deleted.
    - `kind` string: Resource kind, for example, HelloResponse. Auto-generated using the protobuf message proto.MessageName().Name().
    - `name` string, required: Resource name. Must be 63 characters or less.
    - `parent_kind` string: Parent object resource kind, for example, Project.
    - `parent_uuid` string: Parent object UUID.
    - `references` object: Map of objects referenced in a query API.
    - `tags` string[]: List of tags attached to the resource. Tags can be used to select objects and to find collections of objects that satisfy certain conditions. A tag must be 255 characters or less.
    - `update_time` string, date-time: Time the resource was last updated. Note: Updated on all create/patch/delete operations. Format: 2017-01-15T01:30:15.01Z RFC 3339: https://www.ietf.org/rfc/rfc3339.txt.
    - `updated_by` string: Name and authentication source of the last user who updated the object, for example, vulnerabilityingestor@endor.ai@x509.
    - `upsert_time` string, date-time: Time the resource was last upserted. Note: create_time is only set the first time the resource is created. upsert_time is set every time the resource is upseted. Format: 2017-01-15T01:30:15.01Z RFC 3339: https://www.ietf.org/rfc/rfc3339.txt.
    - `version` string: Message version.
  - `processing_result` 'PROCESSING_RESULT_UNSPECIFIED' | 'PROCESSING_RESULT_COMPLETED' | 'PROCESSING_RESULT_FAILED': ProcessingResult indicates the downstream processing result of an event.
  - `spec` V1AgentHookEventSpec
    - `agent` 'AGENT_UNSPECIFIED' | 'AGENT_CURSOR' | 'AGENT_CLAUDE' | 'AGENT_CODEX' | 'AGENT_COPILOT'
    - `agent_version` string: Agent version if available.
    - `cmd_line` V1CmdHook: CmdHook contains payload for command-line related hooks.
      - `cmd_line` string: Command line that was executed.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `command_risk_categories` V1CommandRiskCategory[]: Risk categories the command matched, independent of policy enablement.
    - `command_risk_findings` V1CommandRiskFinding[]: Command fragments that evidenced each risk category.
      - `category` 'COMMAND_RISK_CATEGORY_UNSPECIFIED' | 'COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM' | 'COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION' | 'COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION' | 'COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE' | 'COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION' | 'COMMAND_RISK_CATEGORY_FORCE_PUSH' | 'COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH' | 'COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION' | 'COMMAND_RISK_CATEGORY_SECRET_FILE_READ' | 'COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE' | 'COMMAND_RISK_CATEGORY_NETWORK_ACCESS' | 'COMMAND_RISK_CATEGORY_RECURSIVE_GREP' | 'COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT' | 'COMMAND_RISK_CATEGORY_PUSH_TO_MAIN' | 'COMMAND_RISK_CATEGORY_PACKAGE_INSTALL' | 'COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS' | 'COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING' | 'COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY': CommandRiskCategory identifies the system command-policy family that matched. Values are permanent classifier keys and do not depend on policy names. - COMMAND_RISK_CATEGORY_UNSPECIFIED: No risk classification was performed. - COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM: Destructive filesystem operations, such as recursive root deletion. - COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION: Privilege escalation or broad permission and ownership changes. - COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION: Interpreter one-liners that expose dangerous execution capabilities. - COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE: Remote content that runs directly in a shell. - COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION: Git operations that discard work or skip local safeguards. - COMMAND_RISK_CATEGORY_FORCE_PUSH: Force pushes that rewrite remote history. - COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH: Package or artifact publication to a registry. - COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION: Raw network transfer tools used against remote endpoints. - COMMAND_RISK_CATEGORY_SECRET_FILE_READ: Shell reads of credential, key, or secret files. - COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE: Shell writes to startup files that can establish persistence. - COMMAND_RISK_CATEGORY_NETWORK_ACCESS: Network download or remote access commands. - COMMAND_RISK_CATEGORY_RECURSIVE_GREP: Recursive searches that can expose secrets in transcripts. - COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT: Export of credential-shaped environment variables. - COMMAND_RISK_CATEGORY_PUSH_TO_MAIN: Direct pushes to main or master branches. - COMMAND_RISK_CATEGORY_PACKAGE_INSTALL: Package installation or container run and pull commands. - COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS: Commands that bypass the package firewall. - COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING: Content publication to a public GitHub repository, gist, or release. - COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY: Discovery or staging of credentials and related secret material.
      - `matched_text` string: Text from the command after heredoc removal. The value is capped at 256 Unicode code points. Truncated values end with the literal `...` marker, which is included in the cap.
    - `cwd` string: Working directory when the event was captured.
    - `deny_source` 'DENY_SOURCE_UNSPECIFIED' | 'DENY_SOURCE_OS_SANDBOX' | 'DENY_SOURCE_PROXY' | 'DENY_SOURCE_APP_HOOK': DenySource identifies the layer that blocked a sandboxed execution. - DENY_SOURCE_UNSPECIFIED: No denying layer was reported. - DENY_SOURCE_OS_SANDBOX: The operating-system sandbox blocked the execution. - DENY_SOURCE_PROXY: A network proxy blocked the execution. - DENY_SOURCE_APP_HOOK: An agent hook or application policy blocked the execution.
    - `device_id` string: Device ID if available.
    - `duration_msec` number, float: Duration in milliseconds.
    - `error_message` string: Error message if the hook event failed.
    - `file` V1FileHook: FileHook contains payload for file-related hooks.
      - `file_name` string: File name or path.
      - `operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `has_policy_violation` boolean: Set to true when policy_matches is non-empty.
    - `hook_event_category` 'HOOK_EVENT_CATEGORY_UNSPECIFIED' | 'HOOK_EVENT_CATEGORY_TOOL' | 'HOOK_EVENT_CATEGORY_SESSION' | 'HOOK_EVENT_CATEGORY_CMD' | 'HOOK_EVENT_CATEGORY_FILE' | 'HOOK_EVENT_CATEGORY_USER_PROMPT' | 'HOOK_EVENT_CATEGORY_CONFIG': - HOOK_EVENT_CATEGORY_CONFIG: Changes to the agent's own configuration, which are governance events rather than work the agent performed. Counted under AgenticInventory.config_hook_events, not file_hook_events, even though the event still carries a FileHook payload.
    - `hook_event_name` 'HOOK_EVENT_NAME_UNSPECIFIED' | 'HOOK_EVENT_NAME_SESSION_START' | 'HOOK_EVENT_NAME_SESSION_STOP' | 'HOOK_EVENT_NAME_USER_PROMPT_SUBMIT' | 'HOOK_EVENT_NAME_PRE_TOOL_USE' | 'HOOK_EVENT_NAME_POST_TOOL_USE' | 'HOOK_EVENT_NAME_PRE_CMD' | 'HOOK_EVENT_NAME_POST_CMD' | 'HOOK_EVENT_NAME_PRE_FILE_OPERATION' | 'HOOK_EVENT_NAME_POST_FILE_OPERATION' | 'HOOK_EVENT_NAME_CONFIG_CHANGE': HookEventName identifies the kind of agent lifecycle or tool event. Different agents use different names, so here we will have a normalized list. - HOOK_EVENT_NAME_CONFIG_CHANGE: Agent configuration changed mid-session (e.g. a settings file edit or a /sandbox toggle). Distinct from a file operation so that queries can name it and so file-activity counters exclude settings churn: AgenticAggregate keys file_access_events and edit_operations on this name, and AgenticInventory counts these under config_hook_events rather than file_hook_events.
    - `identity` V1AgentIdentity: AgentIdentity is the org identity resolved for the account behind an event, sourced from the agent provider's org directory. Only the caller's own identity is ever resolved on a client (self-scoped).
      - `display_name` string: Display name of the resolved user.
      - `email` string: Corporate email of the resolved user.
      - `groups` string[]: Org groups / teams the user belongs to.
      - `roles` string[]: Org roles the user holds.
    - `internal_tool` V1InternalToolHook: InternalToolHook contains payload for internal tool-related hooks.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_name` string: Name of the tool (e.g. "Bash", "Glob", "AskUserQuestion", "Skill").
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `is_interrupted` boolean: Whether the hook event was interrupted.
    - `llm_judgments` V1LlmJudgment[]: Judgments the LLM judge made while this event was evaluated. Repeated because the judge will be asked more than one kind of question (prompt injection is Phase 1), not because one command produces several judgments: one command is one judge call, and a command that matches two policies still carries exactly one. A judgment here does NOT by itself mean the event violated a policy. Under JUDGE_SCOPE_ALL_COMMANDS most commands come back benign and match nothing, and those events carry a judgment with has_policy_violation unset. So does a command whose every match the judge released. The released matches are in LlmJudgment.judged_matches.
      - `ai_request_uuid` string: Join key to the AIRequest row for this call, which carries CompletionUsage and the credit accounting. Cost is derived from that row and the price table of the day, never stored here: a stored currency figure goes stale on a price change and cannot be recomputed. Note the derived figure is a FLOOR — the hook client retries a failed POST and each retry bills another inference, while only the attempt that returned leaves its uuid here.
      - `cached_tokens` integer: Tokens served from the provider's prompt cache. The rubric is a standing prefix, so this reports whether it is actually being cached — something the RFC's cost table assumes rather than measures.
      - `completion_tokens` integer: Tokens the label itself cost. Small by design: a large value means the model is explaining itself rather than answering.
      - `confidence` number, float: The model's own 0.0-1.0 self-report, advisory only: recorded so a threshold can be calibrated against real data rather than guessed.
      - `error` string: Set when the judge could not be reached, timed out, or returned something unusable. Without it a fail-open allow reads in the data as a real allow and the fail-open rate cannot be measured at all.
      - `judged_matches` V1AgentHookPolicyMatch[]: The policy matches handed to the judge, as the patterns produced them and before the label acted on them. This is the only record of what the judge decided against. A benign label removes these matches from policy_matches, and a review or suspicious label rewrites their action, so without this copy an event cannot say which policy fired or what it would have done. Empty when the judge ruled on a command no pattern matched, which JUDGE_SCOPE_ALL_COMMANDS does for most commands.
        - `cmd_line` V1CmdLineMatch: CmdLineMatch describes a command-line invocation that matched a policy.
          - `command_source` 'COMMAND_SOURCE_UNSPECIFIED' | 'COMMAND_SOURCE_CMD_HOOK' | 'COMMAND_SOURCE_MCP_TOOL_INPUT': CommandSource names the hook payload the evaluated command text was read from. A shell exposed as an MCP tool (e.g. Claude Desktop's "workspace" server, tool "bash") carries its command in mcp_tool.tool_input rather than in cmd_line, so CmdLine policies read from either payload and record which one they read. - COMMAND_SOURCE_UNSPECIFIED: Records written before the command source was tracked. - COMMAND_SOURCE_CMD_HOOK: spec.cmd_line: the agent's own shell tool. - COMMAND_SOURCE_MCP_TOOL_INPUT: spec.mcp_tool.tool_input: a shell exposed as an MCP tool.
          - `matched_cmd_pattern` string
          - `matched_text` string: Text the pattern matched, cut from the heredoc-stripped command, capped at 256 characters.
          - `mcp_server_name` string: MCP server that carried the command (e.g. "workspace"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
          - `tool_name` string: MCP tool that carried the command (e.g. "bash"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
        - `dependency_risk` V1DependencyRiskMatch: DependencyRiskMatch describes a known-vulnerable dependency found by the dependency-risk check.
          - `direct` boolean: Whether the package is a direct dependency of the introduced package.
          - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
          - `fixed_version` string: Version the advisory names as fixed, when one is published.
          - `introduced_by` string: Package the agent named, set on transitive matches (e.g. "express@4.18.2").
          - `message` string: Human-readable explanation of what fired.
          - `package_name` string: Package name (e.g. "path-to-regexp").
          - `severity` string: Worst matched CVSS severity, as the Severity enum name (e.g. "SEVERITY_HIGH").
          - `version` string: Version judged. For an unpinned install or a range spec, the highest satisfying version known to Endor; the message says so.
          - `vulnerability_id` string: CVE or GHSA id.
        - `file_access` V1FileAccessMatch: FileAccessMatch describes a file access that matched a policy.
          - `matched_file_name_pattern` string: File name pattern that matched.
          - `matched_file_operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
          - `matched_text` string: Text the pattern matched, cut from the separator-normalized name, capped at 256 characters.
        - `malware` V1MalwareMatch: MalwareMatch describes a package flagged by the malware check. The verdict comes from a MALWARE-status, non-contested record in Endor's malware feed.
          - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
          - `message` string: Human-readable explanation of what fired.
          - `package_name` string: Package name (e.g. "reftest-helper-for-ae1x").
          - `reasons` string[]: Why the package is flagged — indicators reported by the malware feed.
          - `source` string: Feed that flagged it, as the MalwareSource enum name (e.g. "MALWARE_SOURCE_AMF").
          - `summary` string: Short title from the malware feed (e.g. "Malicious code in <pkg> (npm)").
          - `version` string: Version from the install command, when it was pinned; empty for an unpinned install.
        - `match_type` 'AGENT_HOOK_POLICY_MATCH_TYPE_UNSPECIFIED' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_TOOL_CALL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_CMD_LINE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_FILE_ACCESS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SKILL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_SERVER' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SESSION' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK' | 'AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX': The type of policy match. - AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE: A package flagged as malware by the malware check. - AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS: A secret detected in file content by the secrets check. - AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK: A known-vulnerable dependency detected by the dependency-risk check. - AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX: Runtime sandbox state of a tool call.
        - `mcp_server` V1McpServerMatch: McpServerMatch describes an MCP server that matched a policy. Carries only the matched server's name; consumers can fetch the full McpMeta from AgenticInventory if more detail is needed. Server-level match; for individual tool calls, see McpToolMatch.
          - `mcp_server_name` string: Name of the MCP server that matched.
          - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "supply_chain_provenance at or below 4").
        - `mcp_tool_call` V1McpToolMatch: McpToolMatch describes a tool call that matched a policy.
          - `matched_server_name_pattern` string: Matched server name pattern.
          - `matched_tool_input_pattern` string: Tool input pattern that matched.
          - `matched_tool_name_pattern` string: Matched tool name pattern.
          - `mcp_server_name` string: MCP server name (e.g. "jira").
          - `message` string: Describes what exactly matched.
          - `tool_name` string: Tool name (e.g. "open bug").
        - `policy_matched` V1AgentHookPolicy: AgentHookPolicy describes a policy to apply when agent hook events match a given activity. When the activity matches, the action (e.g. feedback, block, alert) is applied.
          - `action` V1AgentHookAction: Action describes how to match the activity with the policy and what to do when it matches.
            - `alert` V1AlertAction: AlertAction records an alert with a message (e.g. for audit).
              - …
            - `ask` V1AskAction: AskAction allows asking the user with a message.
              - …
            - `auto` V1AutoAction: AutoAction hands the decision on a matched command to the LLM judge: the command is judged on its own security intent and effect, and the label that comes back is the decision — benign allows, review asks, suspicious blocks. It carries no message on purpose. The agent sees the model's own reason, naming the concrete thing it saw, and a policy-authored string would either be ignored or contradict it. The evaluator converts a matched AUTO policy into a plain ask or block carrying that reason before the verdict is computed, so the verdict is still read off ordinary action kinds. Valid only on cmd_line activities, with either match type, and never on a POLICY_INTENT_GOVERNANCE policy. On an ALLOWLIST the permitted set acts as a prefilter: a listed command never reaches the judge, and one outside it is judged rather than refused outright. Requires an endorctl new enough to know the field. An older client drops it (maniprest unmarshals with DiscardUnknown), is left with an empty action kind, and allows — so switching a policy to AUTO silently loses enforcement of that policy on clients below the minimum version.
            - `block` V1BlockAction: BlockAction blocks the activity and shows a message.
              - …
            - `feedback` V1FeedbackAction: FeedbackAction prompts the user with a message without blocking.
              - …
            - `match_type` 'MATCH_TYPE_UNSPECIFIED' | 'MATCH_TYPE_BLOCKLIST' | 'MATCH_TYPE_ALLOWLIST': We may want to trigger when the activity matches the patterns in the policy (blocklist) or alternatively when the activity does not match the patterns in the policy (allowlist).
          - `activity` V1AgentHookActivity: Activity describes what kind of hook activity the policy applies to.
            - `auto_mode` V1AutoModeActivity: AutoModeActivity turns LLM command judging on for a namespace and says which commands reach the judge. It is an activity kind rather than a resource of its own so that it inherits the AgentHookPolicyDefinition machinery: namespace propagation, name-based deduplication, the JSONL policy-file cache, enabled, and scope. It never produces a match of its own. It is read before the per-policy loop to decide which commands are judged, and a match the judge raises is a CMD_LINE match attributed to this policy. The model stays server-owned: the policy carries no model name and no prompt, only deployment_context. EXACTLY ONE applies to an event — the most specifically scoped candidate, with the policy name breaking an equal rank — and it supplies the whole configuration. They are not unioned, unlike secrets_check or malware_check, because a mode is not a finding: OR is monotone, so nothing at a narrower scope could ever turn a setting back off. A policy that loses is named in a warning, stays enabled and listed, and does nothing.
              - …
            - `cmd_line` V1CmdLineActivity: CmdLineActivity matches command-line execution by regex patterns.
              - …
            - `dependency_risk` V1DependencyRiskActivity: DependencyRiskActivity checks the dependencies an event introduces (from an install command or a manifest/lockfile edit) against Endor's vulnerability data. Matching the activity means running the check; the verdict comes from the lookup, not from the policy config.
              - …
            - `file_access` V1FileAccessActivity: FileAccessActivity matches file access by operation and path patterns.
              - …
            - `malware_check` V1MalwareCheckActivity: MalwareCheckActivity runs Endor's malware lookup against the packages in a package-install command (a cmd_line event). It carries no regex matchers: matching the activity means running the check, and the block/allow verdict comes from the malware feed (MALWARE-status, non-contested records), not from the policy config.
              - …
            - `mcp_server` V1McpServerActivity: McpServerActivity matches MCP servers by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both server_name_matchers and score predicates are set, both must hold; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. This is server-level matching; for per-tool-call matching, use McpToolCallActivity.
              - …
            - `mcp_tool_call` V1McpToolCallActivity: McpToolCallActivity matches tool calls to a specific MCP server and tool.
              - …
            - `secrets_check` V1SecretsCheckActivity: SecretsCheckActivity runs Endor's secret detection over file content (the proposed content of a write/edit, or a file read scanned from disk). Matching the activity means running the scan; the verdict comes from the findings, not from the policy config.
              - …
            - `session` V1SessionActivity: SessionActivity matches sessions by posture predicates over SessionHook fields and the captured AgentConfigSnapshot. Sessions have no stable name, so matching uses field predicates instead of name regexes. Each sub-message is optional; if set, all its predicates are AND'd. Sub-messages are also AND'd with each other. Predicates that target AgentConfigSnapshot evaluate across repository / user / enterprise levels (any-level satisfies). MCP-server-related criteria intentionally live on McpServerActivity, not here.
              - …
            - `skill` V1SkillActivity: SkillActivity matches skills by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both name_matchers and score predicates are set, both must hold for the match to fire; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. When score predicates are set but no SkillMeta is available for the skill, the score branch is configured-but-cannot-fire, failing the AND with the name branch (fail-safe).
              - …
            - `tool_sandbox` V1ToolSandboxActivity: ToolSandboxActivity matches runtime sandbox state on a tool-call event. Values in each repeated field are OR'd. Configured fields are AND'd, and an excluded reason vetoes a match. Exclusions alone and empty activities never match. Unspecified and not-applicable postures do not satisfy posture matches.
              - …
          - `enabled` boolean: Whether this policy is active.
          - `intent` 'POLICY_INTENT_UNSPECIFIED' | 'POLICY_INTENT_RISK' | 'POLICY_INTENT_GOVERNANCE': PolicyIntent says what kind of rule a policy encodes, and so whether the LLM command judge may rule on its matches. Only cmd_line policies are judged, so today the intent changes behavior only on a cmd_line policy. - POLICY_INTENT_UNSPECIFIED: Read as POLICY_INTENT_RISK, so a policy that never sets the field keeps the behavior it had before the field existed. - POLICY_INTENT_RISK: The policy is a risk assessment. A judge scope may hand its matches to the judge, and the label can release, ask about, or block the command. - POLICY_INTENT_GOVERNANCE: The policy is an organisational rule, for example "installs go through the package firewall". A verdict on how risky the command is answers a question the rule does not ask, so no judge scope hands its matches to the judge. Its own action is final: no label releases it, and no label escalates it. Not valid with the AUTO action, which hands the decision to the judge.
          - `inventory_classification` 'INVENTORY_CLASSIFICATION_UNSPECIFIED' | 'INVENTORY_CLASSIFICATION_ALLOW' | 'INVENTORY_CLASSIFICATION_BLOCK' | 'INVENTORY_CLASSIFICATION_SUSPICIOUS' | 'INVENTORY_CLASSIFICATION_MALICIOUS': InventoryClassification declares the classification a policy assigns to a matched MCP server or skill when it fires. UNSPECIFIED means the policy plays no role in inventory classification (e.g. a session, file-access, or cmd-line policy, or an MCP/skill policy whose author only wants the per-event action).
          - `name` string: Name of the policy.
          - `scope` V1AgentHookPolicyScope: AgentHookPolicyScope restricts a policy to a subset of events by matching against per-event identity carried on AgentHookEvent.Spec (repository, user). Scope is evaluated once, before activity-kind matching, so it applies uniformly to all activity kinds. Match logic: an unset scope (or a scope with no matchers set) applies to every event. When set, configured matcher branches are AND'd — every set branch must produce a hit; within a branch the regexes are OR'd (any one matching satisfies the branch); an empty branch is ignored. A scope miss makes the policy a no-op for the event for both blocklist and allowlist match types (the policy simply does not apply).
            - `repository_matchers` string[]: Regex matchers for the repository from AgentHookEvent.Spec.repository (e.g. "github\\.com/acme/.*", ".*-infra$"). OR'd among themselves.
            - `user_matchers` string[]: Regex matchers for the user/account from AgentHookEvent.Spec.user (e.g. "alice", "svc-.*", ".*@example\\.com"). "Account" in the ticket maps to this per-session user identity; there is no separate account entity. OR'd among themselves.
          - `system` boolean: Whether this is a system-defined policy (vs user-defined).
        - `secrets` V1SecretsMatch: SecretsMatch describes a secret detected by the secrets check. It carries only the rule and location, never the secret value, so a finding can be surfaced without leaking the credential.
          - `column` integer: Column in the scanned content where the secret starts.
          - `fingerprint` string: Unique finding fingerprint, for dedup and cross-round false-positive suppression.
          - `line` integer: Line number in the scanned content where the secret was found.
          - `message` string: Human-readable explanation of what fired.
          - `rule_description` string: Friendly rule name (e.g. "AWS Access Key").
          - `rule_id` string: Detection rule that fired (e.g. "aws-access-token", "github-pat").
        - `session` V1SessionMatch: SessionMatch describes a session that matched a policy. Unlike SkillMatch or McpServerMatch, the source data (SessionHook + AgentConfigSnapshot) is already carried by the surrounding AgentHookEvent, so this match only describes what fired.
          - `matched_criteria` string: The criteria category that fired (mirrors a SessionActivity sub-message name, e.g. "top_level", "sandbox", "permissions", "hook", "model").
          - `matched_value` string: The specific predicate value or pattern that matched (e.g. "default_mode=bypassPermissions", "any-level sandbox.enabled=false").
          - `message` string: Free-form human-readable explanation of what fired.
        - `skill` V1SkillMatch: SkillMatch describes a skill that matched a policy. Carries only the matched skill's name; consumers can fetch the full SkillMeta from AgenticInventory if more detail is needed.
          - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "instruction_integrity at or below 4").
          - `skill_name` string: Name of the skill that matched.
        - `tool_sandbox` V1ToolSandboxMatch: ToolSandboxMatch describes the sandbox state that matched a policy.
          - `matched_criteria` string: Policy branch that produced the match.
          - `matched_value` string: Value that satisfied, or failed to satisfy, the policy branch.
          - `override_requested` boolean: Whether the call requested a sandbox override.
          - `posture` 'CALL_SANDBOX_POSTURE_UNSPECIFIED' | 'CALL_SANDBOX_POSTURE_UNKNOWN' | 'CALL_SANDBOX_POSTURE_IN_SANDBOX' | 'CALL_SANDBOX_POSTURE_NO_SANDBOX' | 'CALL_SANDBOX_POSTURE_BLOCKED' | 'CALL_SANDBOX_POSTURE_NOT_APPLICABLE' | 'CALL_SANDBOX_POSTURE_IN_HARNESS': CallSandboxPosture mirrors ToolSandbox by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_POSTURE_UNSPECIFIED: No runtime sandbox state was evaluated. - CALL_SANDBOX_POSTURE_UNKNOWN: The execution is sandbox-governed, but its runtime state is indeterminate. - CALL_SANDBOX_POSTURE_IN_SANDBOX: The execution ran inside the agent's sandbox. - CALL_SANDBOX_POSTURE_NO_SANDBOX: The execution was sandbox-governed but ran without a sandbox. - CALL_SANDBOX_POSTURE_BLOCKED: A sandbox denied the execution. - CALL_SANDBOX_POSTURE_NOT_APPLICABLE: The tool does not execute through a sandbox. - CALL_SANDBOX_POSTURE_IN_HARNESS: A sandbox around the agent harness supplied the isolation.
          - `reason` 'CALL_SANDBOX_REASON_UNSPECIFIED' | 'CALL_SANDBOX_REASON_DISABLED' | 'CALL_SANDBOX_REASON_UNAVAILABLE' | 'CALL_SANDBOX_REASON_MANUAL_APPROVAL' | 'CALL_SANDBOX_REASON_EXCLUDED_COMMAND' | 'CALL_SANDBOX_REASON_ESCALATED' | 'CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE' | 'CALL_SANDBOX_REASON_ESCALATION_PENDING': CallSandboxReason mirrors NoSandboxReason by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_REASON_UNSPECIFIED: No reason was reported. - CALL_SANDBOX_REASON_DISABLED: Sandboxing was disabled by configuration. - CALL_SANDBOX_REASON_UNAVAILABLE: The sandbox was unavailable on this host. - CALL_SANDBOX_REASON_MANUAL_APPROVAL: Manual approval allowed the execution outside the sandbox. - CALL_SANDBOX_REASON_EXCLUDED_COMMAND: The command matched an agent exclusion rule. - CALL_SANDBOX_REASON_ESCALATED: The execution was escalated out of the sandbox. - CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE: A dangerous override disabled sandbox enforcement. - CALL_SANDBOX_REASON_ESCALATION_PENDING: An escalation request was made, but its outcome is not yet known.
      - `kind` 'KIND_UNSPECIFIED' | 'KIND_COMMAND_RISK': What the judge was asked to rule on. - KIND_COMMAND_RISK: Risk of a shell command the agent proposed to run.
      - `label` 'LABEL_UNSPECIFIED' | 'LABEL_BENIGN' | 'LABEL_SUSPICIOUS' | 'LABEL_REVIEW': Label is the judgment on one command. Each value maps to an action the agent hook already has. - LABEL_UNSPECIFIED: No label was produced. Never treat this as a benign result. - LABEL_BENIGN: The command shows nothing concerning on its own. - LABEL_SUSPICIOUS: The command shows something concerning. - LABEL_REVIEW: The decision turns on context the model does not have, so the command belongs in front of the user rather than being cleared or blocked.
      - `latency_ms` string, int64: Round trip as the client measured it, covering assembling the request and mapping the answer back. The one number here that the server-side AIRequest row cannot produce.
      - `model` string: The model that produced the label, as served — the backend rewrites the requested model when aliasing or fallback applies.
      - `prompt_tokens` integer: Tokens the prompt cost.
      - `reason` string: One clause naming the concrete thing the model saw. This is also the text the agent is shown when a judgment raises an ask or a block, which is why an AUTO policy carries no message of its own.
      - `rubric_version` string: Version of the rubric the label was produced under. A label recorded today is not comparable to one recorded after the rubric changed, which is the whole reason the rubric is embedded verbatim rather than assembled per call.
    - `mcp_tool` V1McpToolHook: McpToolHook contains payload for MCP tool-related hooks.
      - `cmd_line` string: Shell command this call runs, when the tool is a shell (Claude Desktop's local agent mode exposes server "workspace", tool "bash"). Such a call is indistinguishable in what it can do from the agent's own Bash tool, but the command arrives inside tool_input, where nothing that reads CmdHook.cmd_line can find it. Lifting it here gives the two paths one field to read, so a consumer does not have to re-derive the shell-tool vocabulary to see the highest-signal action an agent takes. Empty for every non-shell tool.
      - `server_host` string: Host or URL of the server (e.g. "localhost", "https://api.example.com").
      - `server_name` string: Name of the server (e.g. "filesystem", "postgres-mcp", "github-mcp", "enfor-cli-tools").
      - `server_type` 'SERVER_TYPE_UNSPECIFIED' | 'SERVER_TYPE_LOCAL' | 'SERVER_TYPE_REMOTE': ServerType indicates whether a tool server runs locally or remotely.
      - `source` 'MCP_SERVER_SOURCE_UNSPECIFIED' | 'MCP_SERVER_SOURCE_PROJECT_CONFIG' | 'MCP_SERVER_SOURCE_USER_CONFIG' | 'MCP_SERVER_SOURCE_ENTERPRISE_CONFIG' | 'MCP_SERVER_SOURCE_PLUGIN' | 'MCP_SERVER_SOURCE_VENDOR_CONNECTOR' | 'MCP_SERVER_SOURCE_CLIENT_RESERVED' | 'MCP_SERVER_SOURCE_CLIENT_INJECTED': McpServerSource is where an MCP server came from. Orthogonal to ServerType, which answers "where does it run": a vendor connector is a connector by source and REMOTE by type at the same time. Declared here rather than in agentic_inventory.proto because that file imports this one, not the reverse. - MCP_SERVER_SOURCE_UNSPECIFIED: Not classified: no config snapshot was available to check the server against. Distinct from "checked and absent", which is CLIENT_INJECTED. - MCP_SERVER_SOURCE_PROJECT_CONFIG: Registered in the workspace's own checked-in agent config. - MCP_SERVER_SOURCE_USER_CONFIG: Registered in the user's home-directory agent config. - MCP_SERVER_SOURCE_ENTERPRISE_CONFIG: Registered in the OS-managed enterprise agent config. - MCP_SERVER_SOURCE_PLUGIN: Supplied by an agent plugin's manifest rather than by an mcp_servers entry. - MCP_SERVER_SOURCE_VENDOR_CONNECTOR: Vendor hosted connector enabled on the user's agent account, for example a claude.ai connector. Never present in local config. - MCP_SERVER_SOURCE_CLIENT_RESERVED: A name the client reserves for one of its own built in servers, so user config cannot register under it. Highest confidence verdict. - MCP_SERVER_SOURCE_CLIENT_INJECTED: Injected by the client at runtime but not on the reserved list: other product surfaces, IDE bridges, host applications. Absent from a config snapshot that was loaded.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_name` string: Name of the tool (e.g. "Bash", "Glob", "AskUserQuestion", "Skill").
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `model` string: Model involved.
    - `no_sandbox_reason` 'NO_SANDBOX_REASON_UNSPECIFIED' | 'NO_SANDBOX_REASON_DISABLED' | 'NO_SANDBOX_REASON_UNAVAILABLE' | 'NO_SANDBOX_REASON_MANUAL_APPROVAL' | 'NO_SANDBOX_REASON_EXCLUDED_COMMAND' | 'NO_SANDBOX_REASON_ESCALATED' | 'NO_SANDBOX_REASON_DANGEROUS_OVERRIDE' | 'NO_SANDBOX_REASON_ESCALATION_PENDING': NoSandboxReason explains an unsandboxed or unresolved sandbox outcome. - NO_SANDBOX_REASON_UNSPECIFIED: No reason was reported. - NO_SANDBOX_REASON_DISABLED: Sandboxing was disabled by configuration. - NO_SANDBOX_REASON_UNAVAILABLE: The sandbox was unavailable on this host. - NO_SANDBOX_REASON_MANUAL_APPROVAL: Manual approval allowed the execution outside the sandbox. - NO_SANDBOX_REASON_EXCLUDED_COMMAND: The command matched an agent exclusion rule. - NO_SANDBOX_REASON_ESCALATED: The execution was escalated out of the sandbox. - NO_SANDBOX_REASON_DANGEROUS_OVERRIDE: A dangerous override disabled sandbox enforcement. - NO_SANDBOX_REASON_ESCALATION_PENDING: An escalation request is pending. Pair with TOOL_SANDBOX_UNKNOWN, not TOOL_SANDBOX_UNSPECIFIED.
    - `os_user` string: Operating-system login of the account running the agent, carried alongside user rather than instead of it, and populated even when it repeats user. This is the key that links one person's agent accounts, because the same developer is an email to one agent and a GitHub handle to another while staying one OS login underneath. Pair it with device_id: on a shared machine or a CI runner the login is a generic name such as "runner" or "root", and joining on it alone merges unrelated people.
    - `permission_mode` string: Permission mode at capture time (e.g. "default", "acceptEdits").
    - `policy_matches` V1AgentHookPolicyMatch[]: List of policy matches (if any).
      - `cmd_line` V1CmdLineMatch: CmdLineMatch describes a command-line invocation that matched a policy.
        - `command_source` 'COMMAND_SOURCE_UNSPECIFIED' | 'COMMAND_SOURCE_CMD_HOOK' | 'COMMAND_SOURCE_MCP_TOOL_INPUT': CommandSource names the hook payload the evaluated command text was read from. A shell exposed as an MCP tool (e.g. Claude Desktop's "workspace" server, tool "bash") carries its command in mcp_tool.tool_input rather than in cmd_line, so CmdLine policies read from either payload and record which one they read. - COMMAND_SOURCE_UNSPECIFIED: Records written before the command source was tracked. - COMMAND_SOURCE_CMD_HOOK: spec.cmd_line: the agent's own shell tool. - COMMAND_SOURCE_MCP_TOOL_INPUT: spec.mcp_tool.tool_input: a shell exposed as an MCP tool.
        - `matched_cmd_pattern` string
        - `matched_text` string: Text the pattern matched, cut from the heredoc-stripped command, capped at 256 characters.
        - `mcp_server_name` string: MCP server that carried the command (e.g. "workspace"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
        - `tool_name` string: MCP tool that carried the command (e.g. "bash"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
      - `dependency_risk` V1DependencyRiskMatch: DependencyRiskMatch describes a known-vulnerable dependency found by the dependency-risk check.
        - `direct` boolean: Whether the package is a direct dependency of the introduced package.
        - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
        - `fixed_version` string: Version the advisory names as fixed, when one is published.
        - `introduced_by` string: Package the agent named, set on transitive matches (e.g. "express@4.18.2").
        - `message` string: Human-readable explanation of what fired.
        - `package_name` string: Package name (e.g. "path-to-regexp").
        - `severity` string: Worst matched CVSS severity, as the Severity enum name (e.g. "SEVERITY_HIGH").
        - `version` string: Version judged. For an unpinned install or a range spec, the highest satisfying version known to Endor; the message says so.
        - `vulnerability_id` string: CVE or GHSA id.
      - `file_access` V1FileAccessMatch: FileAccessMatch describes a file access that matched a policy.
        - `matched_file_name_pattern` string: File name pattern that matched.
        - `matched_file_operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
        - `matched_text` string: Text the pattern matched, cut from the separator-normalized name, capped at 256 characters.
      - `malware` V1MalwareMatch: MalwareMatch describes a package flagged by the malware check. The verdict comes from a MALWARE-status, non-contested record in Endor's malware feed.
        - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
        - `message` string: Human-readable explanation of what fired.
        - `package_name` string: Package name (e.g. "reftest-helper-for-ae1x").
        - `reasons` string[]: Why the package is flagged — indicators reported by the malware feed.
        - `source` string: Feed that flagged it, as the MalwareSource enum name (e.g. "MALWARE_SOURCE_AMF").
        - `summary` string: Short title from the malware feed (e.g. "Malicious code in <pkg> (npm)").
        - `version` string: Version from the install command, when it was pinned; empty for an unpinned install.
      - `match_type` 'AGENT_HOOK_POLICY_MATCH_TYPE_UNSPECIFIED' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_TOOL_CALL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_CMD_LINE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_FILE_ACCESS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SKILL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_SERVER' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SESSION' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK' | 'AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX': The type of policy match. - AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE: A package flagged as malware by the malware check. - AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS: A secret detected in file content by the secrets check. - AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK: A known-vulnerable dependency detected by the dependency-risk check. - AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX: Runtime sandbox state of a tool call.
      - `mcp_server` V1McpServerMatch: McpServerMatch describes an MCP server that matched a policy. Carries only the matched server's name; consumers can fetch the full McpMeta from AgenticInventory if more detail is needed. Server-level match; for individual tool calls, see McpToolMatch.
        - `mcp_server_name` string: Name of the MCP server that matched.
        - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "supply_chain_provenance at or below 4").
      - `mcp_tool_call` V1McpToolMatch: McpToolMatch describes a tool call that matched a policy.
        - `matched_server_name_pattern` string: Matched server name pattern.
        - `matched_tool_input_pattern` string: Tool input pattern that matched.
        - `matched_tool_name_pattern` string: Matched tool name pattern.
        - `mcp_server_name` string: MCP server name (e.g. "jira").
        - `message` string: Describes what exactly matched.
        - `tool_name` string: Tool name (e.g. "open bug").
      - `policy_matched` V1AgentHookPolicy: AgentHookPolicy describes a policy to apply when agent hook events match a given activity. When the activity matches, the action (e.g. feedback, block, alert) is applied.
        - `action` V1AgentHookAction: Action describes how to match the activity with the policy and what to do when it matches.
          - `alert` V1AlertAction: AlertAction records an alert with a message (e.g. for audit).
            - `feedback_message` string: Feedback message shown to the user when the alert is raised.
            - `message` string
          - `ask` V1AskAction: AskAction allows asking the user with a message.
            - `feedback_message` string: Feedback message shown to the user when asking for confirmation.
            - `message` string
          - `auto` V1AutoAction: AutoAction hands the decision on a matched command to the LLM judge: the command is judged on its own security intent and effect, and the label that comes back is the decision — benign allows, review asks, suspicious blocks. It carries no message on purpose. The agent sees the model's own reason, naming the concrete thing it saw, and a policy-authored string would either be ignored or contradict it. The evaluator converts a matched AUTO policy into a plain ask or block carrying that reason before the verdict is computed, so the verdict is still read off ordinary action kinds. Valid only on cmd_line activities, with either match type, and never on a POLICY_INTENT_GOVERNANCE policy. On an ALLOWLIST the permitted set acts as a prefilter: a listed command never reaches the judge, and one outside it is judged rather than refused outright. Requires an endorctl new enough to know the field. An older client drops it (maniprest unmarshals with DiscardUnknown), is left with an empty action kind, and allows — so switching a policy to AUTO silently loses enforcement of that policy on clients below the minimum version.
          - `block` V1BlockAction: BlockAction blocks the activity and shows a message.
            - `feedback_message` string: Feedback message shown to the user when the action is blocked.
            - `message` string
          - `feedback` V1FeedbackAction: FeedbackAction prompts the user with a message without blocking.
            - `feedback_message` string
            - `message` string
          - `match_type` 'MATCH_TYPE_UNSPECIFIED' | 'MATCH_TYPE_BLOCKLIST' | 'MATCH_TYPE_ALLOWLIST': We may want to trigger when the activity matches the patterns in the policy (blocklist) or alternatively when the activity does not match the patterns in the policy (allowlist).
        - `activity` V1AgentHookActivity: Activity describes what kind of hook activity the policy applies to.
          - `auto_mode` V1AutoModeActivity: AutoModeActivity turns LLM command judging on for a namespace and says which commands reach the judge. It is an activity kind rather than a resource of its own so that it inherits the AgentHookPolicyDefinition machinery: namespace propagation, name-based deduplication, the JSONL policy-file cache, enabled, and scope. It never produces a match of its own. It is read before the per-policy loop to decide which commands are judged, and a match the judge raises is a CMD_LINE match attributed to this policy. The model stays server-owned: the policy carries no model name and no prompt, only deployment_context. EXACTLY ONE applies to an event — the most specifically scoped candidate, with the policy name breaking an equal rank — and it supplies the whole configuration. They are not unioned, unlike secrets_check or malware_check, because a mode is not a finding: OR is monotone, so nothing at a narrower scope could ever turn a setting back off. A policy that loses is named in a warning, stays enabled and listed, and does nothing.
            - `deployment_context` string[]: Free-text lines describing the local deployment: which hosts are the organisation's own, which registries are sanctioned, that ENDOR_TOKEN is expected on this machine. These fill the trust anchors the rubric names as deployment-supplied and ships empty; until they are set the rubric over-escalates on ordinary internal traffic. They are appended AFTER the rubric, so the rubric stays a byte-identical prefix the provider can serve from its cache. The bounds below are per entry. ValidatePolicy bounds the SUM at 8 KiB, the point past which the judge stops reading, so a tenant cannot store context that would be dropped unread on every call — nor a policy line long enough to break the JSONL reader that distributes the set to hooks.
            - `judge_scope` 'JUDGE_SCOPE_UNSPECIFIED' | 'JUDGE_SCOPE_MATCHED_COMMANDS' | 'JUDGE_SCOPE_ALL_COMMANDS': JudgeScope says which commands reach the judge. It is one selector rather than a set of booleans so that no two modes can be in force at once. - JUDGE_SCOPE_UNSPECIFIED: Judge nothing. The policy still supplies deployment_context to the cmd_line policies that carry the AUTO action and judge on their own. This is also what an endorctl too old to know a value added later reads, so every future value fails safe. - JUDGE_SCOPE_MATCHED_COMMANDS: Judge the commands a RISK command policy already matched, treating the action of each matched policy as AUTO. This overrides an explicit customer decision in BOTH directions: a policy that says block stops blocking and asks the judge, and one that says alert or feedback can escalate to a block on a suspicious label. The override lasts only as long as the judge answers — with no label each policy keeps its own action, so an outage degrades to the enforcement the tenant had. A GOVERNANCE policy is never overridden, and a command that only a governance policy matched is not judged at all. - JUDGE_SCOPE_ALL_COMMANDS: Judge every command and stand the RISK command policies down. The malware and secrets checks are untouched: they carry real detections rather than regular expressions. The patterns are still evaluated. They are stood down by a label coming back rather than by this scope alone, which is what lets a judge that cannot be reached fall back to the verdict they produced. An allowlist stands down on the same terms as a blocklist, so a command absent from the set a tenant permitted runs anyway if the judge finds nothing wrong with it. Mark a command policy GOVERNANCE to keep its action final: a governance match keeps its own action under every label. The judge still rules on the command itself, so a review or suspicious label also raises an ask or a block against the auto-mode policy, next to the governance match.
          - `cmd_line` V1CmdLineActivity: CmdLineActivity matches command-line execution by regex patterns.
            - `command_risk_category` 'COMMAND_RISK_CATEGORY_UNSPECIFIED' | 'COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM' | 'COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION' | 'COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION' | 'COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE' | 'COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION' | 'COMMAND_RISK_CATEGORY_FORCE_PUSH' | 'COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH' | 'COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION' | 'COMMAND_RISK_CATEGORY_SECRET_FILE_READ' | 'COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE' | 'COMMAND_RISK_CATEGORY_NETWORK_ACCESS' | 'COMMAND_RISK_CATEGORY_RECURSIVE_GREP' | 'COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT' | 'COMMAND_RISK_CATEGORY_PUSH_TO_MAIN' | 'COMMAND_RISK_CATEGORY_PACKAGE_INSTALL' | 'COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS' | 'COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING' | 'COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY': CommandRiskCategory identifies the system command-policy family that matched. Values are permanent classifier keys and do not depend on policy names. - COMMAND_RISK_CATEGORY_UNSPECIFIED: No risk classification was performed. - COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM: Destructive filesystem operations, such as recursive root deletion. - COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION: Privilege escalation or broad permission and ownership changes. - COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION: Interpreter one-liners that expose dangerous execution capabilities. - COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE: Remote content that runs directly in a shell. - COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION: Git operations that discard work or skip local safeguards. - COMMAND_RISK_CATEGORY_FORCE_PUSH: Force pushes that rewrite remote history. - COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH: Package or artifact publication to a registry. - COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION: Raw network transfer tools used against remote endpoints. - COMMAND_RISK_CATEGORY_SECRET_FILE_READ: Shell reads of credential, key, or secret files. - COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE: Shell writes to startup files that can establish persistence. - COMMAND_RISK_CATEGORY_NETWORK_ACCESS: Network download or remote access commands. - COMMAND_RISK_CATEGORY_RECURSIVE_GREP: Recursive searches that can expose secrets in transcripts. - COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT: Export of credential-shaped environment variables. - COMMAND_RISK_CATEGORY_PUSH_TO_MAIN: Direct pushes to main or master branches. - COMMAND_RISK_CATEGORY_PACKAGE_INSTALL: Package installation or container run and pull commands. - COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS: Commands that bypass the package firewall. - COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING: Content publication to a public GitHub repository, gist, or release. - COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY: Discovery or staging of credentials and related secret material.
            - `patterns` string[]: Patterns to match against the command (e.g. "rm -rf /.*", "curl .* \\| bash").
          - `dependency_risk` V1DependencyRiskActivity: DependencyRiskActivity checks the dependencies an event introduces (from an install command or a manifest/lockfile edit) against Endor's vulnerability data. Matching the activity means running the check; the verdict comes from the lookup, not from the policy config.
            - `ecosystems` string[]: Ecosystems to check (e.g. "npm", "pypi"). Empty means all ecosystems.
            - `exclude_file_patterns` string[]: Skip files whose path matches one of these regexes. Applied after include_file_patterns.
            - `include_file_patterns` string[]: Only check files whose path matches one of these regexes. Empty means every manifest/lockfile name the check recognizes.
            - `include_transitives` boolean: Also check the packages the new dependency pulls in.
            - `min_cvss_severity` 'SEVERITY_UNSPECIFIED' | 'SEVERITY_LOW' | 'SEVERITY_MEDIUM' | 'SEVERITY_HIGH' | 'SEVERITY_CRITICAL': Severity levels, mirroring Vuln.Spec.CVSSV3Severity.Level. - SEVERITY_UNSPECIFIED: Unset. min_cvss_severity treats this as HIGH. - SEVERITY_LOW: CVSS low (0.1 - 3.9). - SEVERITY_MEDIUM: CVSS medium (4.0 - 6.9). - SEVERITY_HIGH: CVSS high (7.0 - 8.9). - SEVERITY_CRITICAL: CVSS critical (9.0 - 10.0).
          - `file_access` V1FileAccessActivity: FileAccessActivity matches file access by operation and path patterns.
            - `file_name_patterns` string[]: Regex file patterns (e.g. "\\.env$", "secrets/.*", ".*\\.key$").
            - `file_operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
          - `malware_check` V1MalwareCheckActivity: MalwareCheckActivity runs Endor's malware lookup against the packages in a package-install command (a cmd_line event). It carries no regex matchers: matching the activity means running the check, and the block/allow verdict comes from the malware feed (MALWARE-status, non-contested records), not from the policy config.
            - `ecosystems` string[]: Ecosystems to check (e.g. "npm", "pypi", "cargo"). Empty means all ecosystems.
          - `mcp_server` V1McpServerActivity: McpServerActivity matches MCP servers by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both server_name_matchers and score predicates are set, both must hold; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. This is server-level matching; for per-tool-call matching, use McpToolCallActivity.
            - `dimension_at_or_below` V1McpDimensionThresholds: McpDimensionThresholds holds per-dimension score thresholds for McpServerActivity. Each field is optional; an unset dimension is ignored. Set dimensions are OR'd among themselves and with score_at_or_below: any single dimension at or below its threshold fires the predicate. Dimension names mirror AgenticInventory.McpScoreDimensions.
              - …
            - `score_at_or_below` number, float: Match when the overall score is at or below this threshold (scores are 1-10, higher = safer). OR'd with dimension_at_or_below.
            - `server_name_matchers` string[]: Regex matchers for MCP server name (e.g. "untrusted-.*", "remote-.*"). AND'd with the score-predicate branch when both are configured.
          - `mcp_tool_call` V1McpToolCallActivity: McpToolCallActivity matches tool calls to a specific MCP server and tool.
            - `mcp_server_name` string: MCP server name (e.g. "jira").
            - `server_name_matchers` string[]: Optional regex matchers for MCP server name.
            - `tool_input_matchers` string[]: Optional regex matchers for tool input (e.g. ".*AI.*").
            - `tool_name` string: Tool name (e.g. "open bug").
            - `tool_name_matchers` string[]: Optional regex matchers for tool name.
          - `secrets_check` V1SecretsCheckActivity: SecretsCheckActivity runs Endor's secret detection over file content (the proposed content of a write/edit, or a file read scanned from disk). Matching the activity means running the scan; the verdict comes from the findings, not from the policy config.
            - `exclude_file_patterns` string[]: Skip files whose path matches one of these regexes (e.g. test fixtures, "*.example" files, vendored dirs). Applied after include_file_patterns.
            - `exclude_rule_ids` string[]: Rule IDs whose findings this policy ignores. Matched as for include_rule_ids, and applied after it, so an id in both is ignored.
            - `file_operations` V1FileAccessActivityFileOperation[]: File operations to scan. Empty means write and edit; scanning a read means reading the file from disk, so reads are opt-in.
            - `include_file_patterns` string[]: Only scan files whose path matches one of these regexes. Empty means all files the event covers.
            - `include_rule_ids` string[]: Rule IDs whose findings this policy acts on, compared exactly and case-sensitively against the rule id on each finding (SecretRule.spec.rule_id, e.g. "aws-access-token"). Empty means every rule in the tenant's effective ruleset.
          - `session` V1SessionActivity: SessionActivity matches sessions by posture predicates over SessionHook fields and the captured AgentConfigSnapshot. Sessions have no stable name, so matching uses field predicates instead of name regexes. Each sub-message is optional; if set, all its predicates are AND'd. Sub-messages are also AND'd with each other. Predicates that target AgentConfigSnapshot evaluate across repository / user / enterprise levels (any-level satisfies). MCP-server-related criteria intentionally live on McpServerActivity, not here.
            - `hook` V1SessionHookCriteria: SessionHookCriteria matches against AgentHookConfig entries at any AgentConfigLevel. Each field is optional.
              - …
            - `model` V1SessionModelCriteria: SessionModelCriteria matches against default_model and available_models at any AgentConfigLevel. Each field is optional.
              - …
            - `permissions` V1SessionPermissionsCriteria: SessionPermissionsCriteria matches against AgentPermissionsConfig at any AgentConfigLevel. Each field is optional.
              - …
            - `sandbox` V1SessionSandboxCriteria: SessionSandboxCriteria matches against AgentSandboxConfig at any AgentConfigLevel, and against the session's resolved sandbox posture. Each field is optional.
              - …
            - `top_level` V1SessionTopLevelCriteria: SessionTopLevelCriteria matches against SessionHook top-level fields (composer_mode, source, is_background_agent) and the per-session user identity carried on AgentHookEvent.Spec.user.
              - …
          - `skill` V1SkillActivity: SkillActivity matches skills by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both name_matchers and score predicates are set, both must hold for the match to fire; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. When score predicates are set but no SkillMeta is available for the skill, the score branch is configured-but-cannot-fire, failing the AND with the name branch (fail-safe).
            - `dimension_at_or_below` V1SkillDimensionThresholds: SkillDimensionThresholds holds per-dimension score thresholds for SkillActivity. Each field is optional; an unset dimension is ignored. Set dimensions are OR'd among themselves and with score_at_or_below: any single dimension at or below its threshold fires the predicate. Dimension names mirror AgenticInventory.SkillScoreDimensions.
              - …
            - `name_matchers` string[]: Regex matchers for skill name (e.g. "untrusted-.*", "experimental-.*"). AND'd with the score-predicate branch when both are configured.
            - `score_at_or_below` number, float: Match when the overall score is at or below this threshold (scores are 1-10, higher = safer). OR'd with dimension_at_or_below.
          - `tool_sandbox` V1ToolSandboxActivity: ToolSandboxActivity matches runtime sandbox state on a tool-call event. Values in each repeated field are OR'd. Configured fields are AND'd, and an excluded reason vetoes a match. Exclusions alone and empty activities never match. Unspecified and not-applicable postures do not satisfy posture matches.
            - `excluded_reasons` V1CallSandboxReason[]: Reasons that veto an otherwise successful match.
            - `override_requested` boolean: If set, the event's override request must equal this value.
            - `postures` V1CallSandboxPosture[]: Runtime postures to match. An empty list accepts any posture.
            - `reasons` V1CallSandboxReason[]: Unsandboxed or unresolved outcome reasons to match. An empty list accepts any reason.
        - `enabled` boolean: Whether this policy is active.
        - `intent` 'POLICY_INTENT_UNSPECIFIED' | 'POLICY_INTENT_RISK' | 'POLICY_INTENT_GOVERNANCE': PolicyIntent says what kind of rule a policy encodes, and so whether the LLM command judge may rule on its matches. Only cmd_line policies are judged, so today the intent changes behavior only on a cmd_line policy. - POLICY_INTENT_UNSPECIFIED: Read as POLICY_INTENT_RISK, so a policy that never sets the field keeps the behavior it had before the field existed. - POLICY_INTENT_RISK: The policy is a risk assessment. A judge scope may hand its matches to the judge, and the label can release, ask about, or block the command. - POLICY_INTENT_GOVERNANCE: The policy is an organisational rule, for example "installs go through the package firewall". A verdict on how risky the command is answers a question the rule does not ask, so no judge scope hands its matches to the judge. Its own action is final: no label releases it, and no label escalates it. Not valid with the AUTO action, which hands the decision to the judge.
        - `inventory_classification` 'INVENTORY_CLASSIFICATION_UNSPECIFIED' | 'INVENTORY_CLASSIFICATION_ALLOW' | 'INVENTORY_CLASSIFICATION_BLOCK' | 'INVENTORY_CLASSIFICATION_SUSPICIOUS' | 'INVENTORY_CLASSIFICATION_MALICIOUS': InventoryClassification declares the classification a policy assigns to a matched MCP server or skill when it fires. UNSPECIFIED means the policy plays no role in inventory classification (e.g. a session, file-access, or cmd-line policy, or an MCP/skill policy whose author only wants the per-event action).
        - `name` string: Name of the policy.
        - `scope` V1AgentHookPolicyScope: AgentHookPolicyScope restricts a policy to a subset of events by matching against per-event identity carried on AgentHookEvent.Spec (repository, user). Scope is evaluated once, before activity-kind matching, so it applies uniformly to all activity kinds. Match logic: an unset scope (or a scope with no matchers set) applies to every event. When set, configured matcher branches are AND'd — every set branch must produce a hit; within a branch the regexes are OR'd (any one matching satisfies the branch); an empty branch is ignored. A scope miss makes the policy a no-op for the event for both blocklist and allowlist match types (the policy simply does not apply).
          - `repository_matchers` string[]: Regex matchers for the repository from AgentHookEvent.Spec.repository (e.g. "github\\.com/acme/.*", ".*-infra$"). OR'd among themselves.
          - `user_matchers` string[]: Regex matchers for the user/account from AgentHookEvent.Spec.user (e.g. "alice", "svc-.*", ".*@example\\.com"). "Account" in the ticket maps to this per-session user identity; there is no separate account entity. OR'd among themselves.
        - `system` boolean: Whether this is a system-defined policy (vs user-defined).
      - `secrets` V1SecretsMatch: SecretsMatch describes a secret detected by the secrets check. It carries only the rule and location, never the secret value, so a finding can be surfaced without leaking the credential.
        - `column` integer: Column in the scanned content where the secret starts.
        - `fingerprint` string: Unique finding fingerprint, for dedup and cross-round false-positive suppression.
        - `line` integer: Line number in the scanned content where the secret was found.
        - `message` string: Human-readable explanation of what fired.
        - `rule_description` string: Friendly rule name (e.g. "AWS Access Key").
        - `rule_id` string: Detection rule that fired (e.g. "aws-access-token", "github-pat").
      - `session` V1SessionMatch: SessionMatch describes a session that matched a policy. Unlike SkillMatch or McpServerMatch, the source data (SessionHook + AgentConfigSnapshot) is already carried by the surrounding AgentHookEvent, so this match only describes what fired.
        - `matched_criteria` string: The criteria category that fired (mirrors a SessionActivity sub-message name, e.g. "top_level", "sandbox", "permissions", "hook", "model").
        - `matched_value` string: The specific predicate value or pattern that matched (e.g. "default_mode=bypassPermissions", "any-level sandbox.enabled=false").
        - `message` string: Free-form human-readable explanation of what fired.
      - `skill` V1SkillMatch: SkillMatch describes a skill that matched a policy. Carries only the matched skill's name; consumers can fetch the full SkillMeta from AgenticInventory if more detail is needed.
        - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "instruction_integrity at or below 4").
        - `skill_name` string: Name of the skill that matched.
      - `tool_sandbox` V1ToolSandboxMatch: ToolSandboxMatch describes the sandbox state that matched a policy.
        - `matched_criteria` string: Policy branch that produced the match.
        - `matched_value` string: Value that satisfied, or failed to satisfy, the policy branch.
        - `override_requested` boolean: Whether the call requested a sandbox override.
        - `posture` 'CALL_SANDBOX_POSTURE_UNSPECIFIED' | 'CALL_SANDBOX_POSTURE_UNKNOWN' | 'CALL_SANDBOX_POSTURE_IN_SANDBOX' | 'CALL_SANDBOX_POSTURE_NO_SANDBOX' | 'CALL_SANDBOX_POSTURE_BLOCKED' | 'CALL_SANDBOX_POSTURE_NOT_APPLICABLE' | 'CALL_SANDBOX_POSTURE_IN_HARNESS': CallSandboxPosture mirrors ToolSandbox by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_POSTURE_UNSPECIFIED: No runtime sandbox state was evaluated. - CALL_SANDBOX_POSTURE_UNKNOWN: The execution is sandbox-governed, but its runtime state is indeterminate. - CALL_SANDBOX_POSTURE_IN_SANDBOX: The execution ran inside the agent's sandbox. - CALL_SANDBOX_POSTURE_NO_SANDBOX: The execution was sandbox-governed but ran without a sandbox. - CALL_SANDBOX_POSTURE_BLOCKED: A sandbox denied the execution. - CALL_SANDBOX_POSTURE_NOT_APPLICABLE: The tool does not execute through a sandbox. - CALL_SANDBOX_POSTURE_IN_HARNESS: A sandbox around the agent harness supplied the isolation.
        - `reason` 'CALL_SANDBOX_REASON_UNSPECIFIED' | 'CALL_SANDBOX_REASON_DISABLED' | 'CALL_SANDBOX_REASON_UNAVAILABLE' | 'CALL_SANDBOX_REASON_MANUAL_APPROVAL' | 'CALL_SANDBOX_REASON_EXCLUDED_COMMAND' | 'CALL_SANDBOX_REASON_ESCALATED' | 'CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE' | 'CALL_SANDBOX_REASON_ESCALATION_PENDING': CallSandboxReason mirrors NoSandboxReason by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_REASON_UNSPECIFIED: No reason was reported. - CALL_SANDBOX_REASON_DISABLED: Sandboxing was disabled by configuration. - CALL_SANDBOX_REASON_UNAVAILABLE: The sandbox was unavailable on this host. - CALL_SANDBOX_REASON_MANUAL_APPROVAL: Manual approval allowed the execution outside the sandbox. - CALL_SANDBOX_REASON_EXCLUDED_COMMAND: The command matched an agent exclusion rule. - CALL_SANDBOX_REASON_ESCALATED: The execution was escalated out of the sandbox. - CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE: A dangerous override disabled sandbox enforcement. - CALL_SANDBOX_REASON_ESCALATION_PENDING: An escalation request was made, but its outcome is not yet known.
    - `raw_hook_event_name` string: Raw hook event name from the agent.
    - `reported_sandbox_config` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
      - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
      - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
      - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
      - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
      - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
      - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
      - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
      - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
    - `repository` string: Repository where the action happened.
    - `sandbox_confidence` 'SANDBOX_DETECTION_CONFIDENCE_UNSPECIFIED' | 'SANDBOX_DETECTION_CONFIDENCE_REPORTED' | 'SANDBOX_DETECTION_CONFIDENCE_DERIVED' | 'SANDBOX_DETECTION_CONFIDENCE_INFERRED': SandboxDetectionConfidence describes how directly a sandbox state was observed. - SANDBOX_DETECTION_CONFIDENCE_UNSPECIFIED: No confidence was reported. - SANDBOX_DETECTION_CONFIDENCE_REPORTED: The agent explicitly reported the sandbox state. - SANDBOX_DETECTION_CONFIDENCE_DERIVED: The state was derived from configuration or structured events. - SANDBOX_DETECTION_CONFIDENCE_INFERRED: The state was inferred from indirect evidence.
    - `sandbox_config_posture` 'SANDBOX_CONFIG_POSTURE_UNSPECIFIED' | 'SANDBOX_CONFIG_POSTURE_UNKNOWN' | 'SANDBOX_CONFIG_POSTURE_ENABLED' | 'SANDBOX_CONFIG_POSTURE_DISABLED': SandboxConfigPosture is the session-level sandbox posture derived from agent configuration. - SANDBOX_CONFIG_POSTURE_UNSPECIFIED: No posture was evaluated by this client. - SANDBOX_CONFIG_POSTURE_UNKNOWN: The client evaluated configuration but could not determine posture. - SANDBOX_CONFIG_POSTURE_ENABLED: Configuration indicates sandboxing is enabled for the session. - SANDBOX_CONFIG_POSTURE_DISABLED: Configuration indicates sandboxing is disabled for the session.
    - `sandbox_override_requested` boolean: Whether this call requested a sandbox override.
    - `session` V1SessionHook
      - `ai_tool_inventory` V1AiToolInventory: AiToolInventory contains all AI development tools detected on the host machine.
        - `detections` V1AiToolDetection[]: Detected AI tools.
          - `category` 'AI_TOOL_CATEGORY_UNSPECIFIED' | 'AI_TOOL_CATEGORY_IDE' | 'AI_TOOL_CATEGORY_CLI_TOOL' | 'AI_TOOL_CATEGORY_AGENT' | 'AI_TOOL_CATEGORY_FRAMEWORK' | 'AI_TOOL_CATEGORY_MCP_CONFIG' | 'AI_TOOL_CATEGORY_IDE_EXTENSION' | 'AI_TOOL_CATEGORY_SANDBOX_TOOL': AiToolCategory classifies a detected AI development tool. - AI_TOOL_CATEGORY_SANDBOX_TOOL: Dedicated sandbox tools that wrap an agent, as opposed to an agent's own built-in sandbox.
          - `evidence` V1AiToolEvidence[]: Evidence supporting the detection.
            - `key` string: Evidence key (e.g. "install_path", "binary_path", "version", "config_path").
            - `value` string: Evidence value.
          - `tool` string: Tool identifier (e.g. "cursor", "claude-code", "ollama").
          - `vendor` string: Vendor name (e.g. "Anthropic", "OpenSource", "Google").
      - `composer_mode` string: Composer mode of the session. "agent", "ask", "edit"
      - `config` V1AgentConfigSnapshot: AgentConfigSnapshot captures the three-level configuration hierarchy (repository, user, enterprise) at session start time.
        - `enterprise` V1AgentConfigLevel: AgentConfigLevel captures the agent configuration at one scope level (repository, user, or enterprise).
          - `available_models` string[]: AvailableModels restricts which model IDs are selectable. Populated from Claude Code settings only.
          - `default_model` string: DefaultModel is the default model ID configured at this level. Populated from Claude Code settings only.
          - `env` object: Env holds environment variables configured at this level.
          - `environment_type` string: EnvironmentType is the remote environment type (e.g. "docker"). Populated from Cursor environment.json only.
          - `hooks` V1AgentHookConfig[]: Hooks lists the hook event bindings configured at this level.
            - `commands` string[]: Commands lists the shell commands registered for this event.
            - `event_name` string: EventName is the lifecycle hook event name (e.g. "PostToolUse").
          - `instruction_files` V1AgentInstructionFile[]: InstructionFiles lists rule/instruction files discovered at this level. Cursor: .mdc files from rules/ directories. Claude Code: reserved for future use.
            - `content_hash` string: ContentHash is the SHA-256 hex digest of the file content.
            - `name` string: Name is the base filename without extension (e.g. "security" from "security.mdc").
            - `path` string: Path is the absolute filesystem path to the instruction file.
          - `mcp_servers` V1AgentMCPServer[]: McpServers lists the MCP servers configured at this level.
            - `args` string[]: Args are the command-line arguments passed to the server process.
            - `command` string: Command is the executable used for stdio-transport servers.
            - `config_server_name` string: ConfigServerName is the user-authored mcp.json map key that named this server entry in the agent's configuration (e.g. "claude-endor-cli-tools", "postgres"). It is the stable identifier per-tool hooks can use to look the entry up in the cached SESSION_START snapshot — Claude's tool name shape "mcp__<server>__<tool>" carries this value, while Name carries the runtime program identity. Wrapped to distinguish "unset" from "".
            - `env` object: Env holds environment variables injected into the server process.
            - `from_plugin` boolean: FromPlugin marks a server contributed by an enabled agent plugin's manifest rather than by an mcp_servers entry a user wrote. Only the collector that walked the plugin registry can tell the two apart, and both inventory writers need the answer to agree, so it is stated here rather than inferred downstream from the "<plugin>/<server>" shape of config_server_name — a user-authored key may legitimately contain a slash ("@vendor/server"). Wrapped to distinguish "unset" (a collector predating this field) from "false".
            - `headers` object: Headers are additional HTTP headers sent with requests. Populated by collectors when available; Cursor's mcp.json has no headers field so this is empty for Cursor.
            - `name` string: Name is the canonical runtime identifier of the MCP server program — the value extracted from the command line (e.g. "endorctl" from "npx -y endorctl ai-tools mcp-server") or, for HTTP/SSE servers, the host slice of the URL. The backend uses this as the inventory document name so SESSION_START rows and per-tool rows (whose McpToolHook.server_name is derived the same way from the runtime URL/command) land on a single inventory document per logical server.
            - `transport` string: Transport is the MCP transport type: "stdio", "http", or "sse". Collectors must populate this; an empty value means the collector could not classify the server. Claude Code reads this from .mcp.json; Cursor derives it structurally from command/url since mcp.json has no transport field.
            - `url` string: URL is the endpoint for HTTP or SSE transport servers.
          - `permissions` V1AgentPermissionsConfig: AgentPermissionsConfig normalizes permission rules across agents.
            - `additional_directories` string[]: AdditionalDirectories lists extra working directories the agent may access. Claude Code: from permissions.additionalDirectories. Cursor: from CLI allowedPaths.
            - `allowed_commands` string[]: AllowedCommands lists shell command patterns that are auto-approved. For Claude Code these are permission rule strings (e.g. "Bash(git:*)").
            - `allowed_mcp_servers` string[]: AllowedMcpServers lists MCP server names permitted by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `allowed_tools` string[]: AllowedTools lists MCP tool names that are auto-approved. Populated primarily from Cursor configs; Claude Code uses rule strings instead.
            - `bypass_disabled` boolean: BypassDisabled indicates whether bypass-permissions mode is disabled. Populated from Claude Code only.
            - `default_mode` string: DefaultMode is the permission mode used when no explicit rule matches. Populated from Claude Code only (e.g. "default", "bypassPermissions").
            - `denied_commands` string[]: DeniedCommands lists shell command patterns that are blocked.
            - `denied_mcp_servers` string[]: DeniedMcpServers lists MCP server names blocked by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `denied_tools` string[]: DeniedTools lists MCP tool names that are blocked.
          - `sandbox` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
            - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
            - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
            - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
            - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
            - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
            - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
            - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
            - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
        - `repository` V1AgentConfigLevel: AgentConfigLevel captures the agent configuration at one scope level (repository, user, or enterprise).
          - `available_models` string[]: AvailableModels restricts which model IDs are selectable. Populated from Claude Code settings only.
          - `default_model` string: DefaultModel is the default model ID configured at this level. Populated from Claude Code settings only.
          - `env` object: Env holds environment variables configured at this level.
          - `environment_type` string: EnvironmentType is the remote environment type (e.g. "docker"). Populated from Cursor environment.json only.
          - `hooks` V1AgentHookConfig[]: Hooks lists the hook event bindings configured at this level.
            - `commands` string[]: Commands lists the shell commands registered for this event.
            - `event_name` string: EventName is the lifecycle hook event name (e.g. "PostToolUse").
          - `instruction_files` V1AgentInstructionFile[]: InstructionFiles lists rule/instruction files discovered at this level. Cursor: .mdc files from rules/ directories. Claude Code: reserved for future use.
            - `content_hash` string: ContentHash is the SHA-256 hex digest of the file content.
            - `name` string: Name is the base filename without extension (e.g. "security" from "security.mdc").
            - `path` string: Path is the absolute filesystem path to the instruction file.
          - `mcp_servers` V1AgentMCPServer[]: McpServers lists the MCP servers configured at this level.
            - `args` string[]: Args are the command-line arguments passed to the server process.
            - `command` string: Command is the executable used for stdio-transport servers.
            - `config_server_name` string: ConfigServerName is the user-authored mcp.json map key that named this server entry in the agent's configuration (e.g. "claude-endor-cli-tools", "postgres"). It is the stable identifier per-tool hooks can use to look the entry up in the cached SESSION_START snapshot — Claude's tool name shape "mcp__<server>__<tool>" carries this value, while Name carries the runtime program identity. Wrapped to distinguish "unset" from "".
            - `env` object: Env holds environment variables injected into the server process.
            - `from_plugin` boolean: FromPlugin marks a server contributed by an enabled agent plugin's manifest rather than by an mcp_servers entry a user wrote. Only the collector that walked the plugin registry can tell the two apart, and both inventory writers need the answer to agree, so it is stated here rather than inferred downstream from the "<plugin>/<server>" shape of config_server_name — a user-authored key may legitimately contain a slash ("@vendor/server"). Wrapped to distinguish "unset" (a collector predating this field) from "false".
            - `headers` object: Headers are additional HTTP headers sent with requests. Populated by collectors when available; Cursor's mcp.json has no headers field so this is empty for Cursor.
            - `name` string: Name is the canonical runtime identifier of the MCP server program — the value extracted from the command line (e.g. "endorctl" from "npx -y endorctl ai-tools mcp-server") or, for HTTP/SSE servers, the host slice of the URL. The backend uses this as the inventory document name so SESSION_START rows and per-tool rows (whose McpToolHook.server_name is derived the same way from the runtime URL/command) land on a single inventory document per logical server.
            - `transport` string: Transport is the MCP transport type: "stdio", "http", or "sse". Collectors must populate this; an empty value means the collector could not classify the server. Claude Code reads this from .mcp.json; Cursor derives it structurally from command/url since mcp.json has no transport field.
            - `url` string: URL is the endpoint for HTTP or SSE transport servers.
          - `permissions` V1AgentPermissionsConfig: AgentPermissionsConfig normalizes permission rules across agents.
            - `additional_directories` string[]: AdditionalDirectories lists extra working directories the agent may access. Claude Code: from permissions.additionalDirectories. Cursor: from CLI allowedPaths.
            - `allowed_commands` string[]: AllowedCommands lists shell command patterns that are auto-approved. For Claude Code these are permission rule strings (e.g. "Bash(git:*)").
            - `allowed_mcp_servers` string[]: AllowedMcpServers lists MCP server names permitted by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `allowed_tools` string[]: AllowedTools lists MCP tool names that are auto-approved. Populated primarily from Cursor configs; Claude Code uses rule strings instead.
            - `bypass_disabled` boolean: BypassDisabled indicates whether bypass-permissions mode is disabled. Populated from Claude Code only.
            - `default_mode` string: DefaultMode is the permission mode used when no explicit rule matches. Populated from Claude Code only (e.g. "default", "bypassPermissions").
            - `denied_commands` string[]: DeniedCommands lists shell command patterns that are blocked.
            - `denied_mcp_servers` string[]: DeniedMcpServers lists MCP server names blocked by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `denied_tools` string[]: DeniedTools lists MCP tool names that are blocked.
          - `sandbox` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
            - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
            - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
            - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
            - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
            - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
            - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
            - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
            - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
        - `resolved_sandbox_posture` 'SANDBOX_CONFIG_POSTURE_UNSPECIFIED' | 'SANDBOX_CONFIG_POSTURE_UNKNOWN' | 'SANDBOX_CONFIG_POSTURE_ENABLED' | 'SANDBOX_CONFIG_POSTURE_DISABLED': SandboxConfigPosture is the session-level sandbox posture derived from agent configuration. - SANDBOX_CONFIG_POSTURE_UNSPECIFIED: No posture was evaluated by this client. - SANDBOX_CONFIG_POSTURE_UNKNOWN: The client evaluated configuration but could not determine posture. - SANDBOX_CONFIG_POSTURE_ENABLED: Configuration indicates sandboxing is enabled for the session. - SANDBOX_CONFIG_POSTURE_DISABLED: Configuration indicates sandboxing is disabled for the session.
        - `user` V1AgentConfigLevel: AgentConfigLevel captures the agent configuration at one scope level (repository, user, or enterprise).
          - `available_models` string[]: AvailableModels restricts which model IDs are selectable. Populated from Claude Code settings only.
          - `default_model` string: DefaultModel is the default model ID configured at this level. Populated from Claude Code settings only.
          - `env` object: Env holds environment variables configured at this level.
          - `environment_type` string: EnvironmentType is the remote environment type (e.g. "docker"). Populated from Cursor environment.json only.
          - `hooks` V1AgentHookConfig[]: Hooks lists the hook event bindings configured at this level.
            - `commands` string[]: Commands lists the shell commands registered for this event.
            - `event_name` string: EventName is the lifecycle hook event name (e.g. "PostToolUse").
          - `instruction_files` V1AgentInstructionFile[]: InstructionFiles lists rule/instruction files discovered at this level. Cursor: .mdc files from rules/ directories. Claude Code: reserved for future use.
            - `content_hash` string: ContentHash is the SHA-256 hex digest of the file content.
            - `name` string: Name is the base filename without extension (e.g. "security" from "security.mdc").
            - `path` string: Path is the absolute filesystem path to the instruction file.
          - `mcp_servers` V1AgentMCPServer[]: McpServers lists the MCP servers configured at this level.
            - `args` string[]: Args are the command-line arguments passed to the server process.
            - `command` string: Command is the executable used for stdio-transport servers.
            - `config_server_name` string: ConfigServerName is the user-authored mcp.json map key that named this server entry in the agent's configuration (e.g. "claude-endor-cli-tools", "postgres"). It is the stable identifier per-tool hooks can use to look the entry up in the cached SESSION_START snapshot — Claude's tool name shape "mcp__<server>__<tool>" carries this value, while Name carries the runtime program identity. Wrapped to distinguish "unset" from "".
            - `env` object: Env holds environment variables injected into the server process.
            - `from_plugin` boolean: FromPlugin marks a server contributed by an enabled agent plugin's manifest rather than by an mcp_servers entry a user wrote. Only the collector that walked the plugin registry can tell the two apart, and both inventory writers need the answer to agree, so it is stated here rather than inferred downstream from the "<plugin>/<server>" shape of config_server_name — a user-authored key may legitimately contain a slash ("@vendor/server"). Wrapped to distinguish "unset" (a collector predating this field) from "false".
            - `headers` object: Headers are additional HTTP headers sent with requests. Populated by collectors when available; Cursor's mcp.json has no headers field so this is empty for Cursor.
            - `name` string: Name is the canonical runtime identifier of the MCP server program — the value extracted from the command line (e.g. "endorctl" from "npx -y endorctl ai-tools mcp-server") or, for HTTP/SSE servers, the host slice of the URL. The backend uses this as the inventory document name so SESSION_START rows and per-tool rows (whose McpToolHook.server_name is derived the same way from the runtime URL/command) land on a single inventory document per logical server.
            - `transport` string: Transport is the MCP transport type: "stdio", "http", or "sse". Collectors must populate this; an empty value means the collector could not classify the server. Claude Code reads this from .mcp.json; Cursor derives it structurally from command/url since mcp.json has no transport field.
            - `url` string: URL is the endpoint for HTTP or SSE transport servers.
          - `permissions` V1AgentPermissionsConfig: AgentPermissionsConfig normalizes permission rules across agents.
            - `additional_directories` string[]: AdditionalDirectories lists extra working directories the agent may access. Claude Code: from permissions.additionalDirectories. Cursor: from CLI allowedPaths.
            - `allowed_commands` string[]: AllowedCommands lists shell command patterns that are auto-approved. For Claude Code these are permission rule strings (e.g. "Bash(git:*)").
            - `allowed_mcp_servers` string[]: AllowedMcpServers lists MCP server names permitted by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `allowed_tools` string[]: AllowedTools lists MCP tool names that are auto-approved. Populated primarily from Cursor configs; Claude Code uses rule strings instead.
            - `bypass_disabled` boolean: BypassDisabled indicates whether bypass-permissions mode is disabled. Populated from Claude Code only.
            - `default_mode` string: DefaultMode is the permission mode used when no explicit rule matches. Populated from Claude Code only (e.g. "default", "bypassPermissions").
            - `denied_commands` string[]: DeniedCommands lists shell command patterns that are blocked.
            - `denied_mcp_servers` string[]: DeniedMcpServers lists MCP server names blocked by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `denied_tools` string[]: DeniedTools lists MCP tool names that are blocked.
          - `sandbox` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
            - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
            - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
            - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
            - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
            - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
            - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
            - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
            - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
      - `harness_sandbox` 'HARNESS_SANDBOX_UNSPECIFIED' | 'HARNESS_SANDBOX_NONE_DETECTED' | 'HARNESS_SANDBOX_CONTAINER_DIY' | 'HARNESS_SANDBOX_DEDICATED_TOOL' | 'HARNESS_SANDBOX_SANDBOX_RUNTIME' | 'HARNESS_SANDBOX_UNKNOWN': HarnessSandbox identifies sandboxing around the agent harness itself. - HARNESS_SANDBOX_UNSPECIFIED: Harness sandboxing was not evaluated. - HARNESS_SANDBOX_NONE_DETECTED: No harness sandbox was detected. - HARNESS_SANDBOX_CONTAINER_DIY: The harness appears to run inside a generic container. - HARNESS_SANDBOX_DEDICATED_TOOL: The harness is managed by a dedicated sandbox tool. - HARNESS_SANDBOX_SANDBOX_RUNTIME: The harness is managed by a sandbox runtime. - HARNESS_SANDBOX_UNKNOWN: Checked but could not be classified.
      - `harness_sandbox_detail` string: Additional harness sandbox classification detail.
      - `is_background_agent` boolean: Whether the session is a background agent.
      - `reason` string: Reason for the session. For SESSION_END: "completed", "aborted", "error"
      - `sandbox_config_posture` 'SANDBOX_CONFIG_POSTURE_UNSPECIFIED' | 'SANDBOX_CONFIG_POSTURE_UNKNOWN' | 'SANDBOX_CONFIG_POSTURE_ENABLED' | 'SANDBOX_CONFIG_POSTURE_DISABLED': SandboxConfigPosture is the session-level sandbox posture derived from agent configuration. - SANDBOX_CONFIG_POSTURE_UNSPECIFIED: No posture was evaluated by this client. - SANDBOX_CONFIG_POSTURE_UNKNOWN: The client evaluated configuration but could not determine posture. - SANDBOX_CONFIG_POSTURE_ENABLED: Configuration indicates sandboxing is enabled for the session. - SANDBOX_CONFIG_POSTURE_DISABLED: Configuration indicates sandboxing is disabled for the session.
      - `skills` V1DiscoveredSkill[]: Skills discovered in the workspace during session start.
        - `allowed_tools` string[]: Tools declared in SKILL.md frontmatter (allowed-tools).
        - `compatibility` string: Environment requirements from SKILL.md frontmatter (agentskills.io standard field).
        - `content` string: Base64-encoded SKILL.md content for backend scoring. Capped at 128 KB.
        - `content_hash` string: SHA-256 hash of the SKILL.md content.
        - `description` string: Human-readable description from SKILL.md frontmatter.
        - `file_count` integer: Number of files in the skill directory (including SKILL.md).
        - `license` string: License from SKILL.md frontmatter (agentskills.io standard field).
        - `name` string: Skill name from SKILL.md frontmatter or directory name fallback.
        - `path` string: Path to the SKILL.md file within the workspace or user home directory.
      - `source` string: Source of the session. "startup", "resume", "clear"
    - `session_id` string: Session identifier for the agent run.
    - `sub_session_id` string: Sub-session identifier for the agent run.
    - `tool_sandbox` 'TOOL_SANDBOX_UNSPECIFIED' | 'TOOL_SANDBOX_UNKNOWN' | 'TOOL_SANDBOX_IN_SANDBOX' | 'TOOL_SANDBOX_NO_SANDBOX' | 'TOOL_SANDBOX_BLOCKED' | 'TOOL_SANDBOX_NOT_APPLICABLE' | 'TOOL_SANDBOX_IN_HARNESS': ToolSandbox is the runtime sandbox state of a single tool-call execution. - TOOL_SANDBOX_UNSPECIFIED: No runtime sandbox state was evaluated. - TOOL_SANDBOX_UNKNOWN: The execution is sandbox-governed, but its runtime state is indeterminate. - TOOL_SANDBOX_IN_SANDBOX: The execution ran inside the agent's sandbox. - TOOL_SANDBOX_NO_SANDBOX: The execution was sandbox-governed but ran without a sandbox. - TOOL_SANDBOX_BLOCKED: A sandbox denied the execution. - TOOL_SANDBOX_NOT_APPLICABLE: The tool does not execute through a sandbox. - TOOL_SANDBOX_IN_HARNESS: A sandbox around the agent harness supplied the isolation.
    - `tool_sandbox_basis` 'TOOL_SANDBOX_BASIS_UNSPECIFIED' | 'TOOL_SANDBOX_BASIS_REPORTED_BEFORE_RUN' | 'TOOL_SANDBOX_BASIS_OBSERVED_AFTER_RUN' | 'TOOL_SANDBOX_BASIS_DENIED_BEFORE_RUN': ToolSandboxBasis identifies the sole record, if any, used to aggregate one shell call's sandbox result. Producers must set a nonzero basis on at most one record per call. DENIED_BEFORE_RUN takes precedence when multiple bases apply. - TOOL_SANDBOX_BASIS_UNSPECIFIED: This record is not selected as the call's sandbox result for aggregation. - TOOL_SANDBOX_BASIS_REPORTED_BEFORE_RUN: The agent reported intended sandbox state before execution, not an observed outcome. Use only if no later OBSERVED_AFTER_RUN or DENIED_BEFORE_RUN record will be emitted for the call. - TOOL_SANDBOX_BASIS_OBSERVED_AFTER_RUN: The client observed the sandbox outcome after execution. - TOOL_SANDBOX_BASIS_DENIED_BEFORE_RUN: An enforced policy denied the call before execution.
    - `user` string: User name if available.
    - `user_kind` 'USER_KIND_UNSPECIFIED' | 'USER_KIND_EMAIL' | 'USER_KIND_GITHUB_LOGIN' | 'USER_KIND_OS_LOGIN' | 'USER_KIND_ASSERTED': UserKind says which kind of identifier the user field carries. Agents name their users differently, so the value alone cannot be classified: a bare login is indistinguishable from an OS login of the same spelling. A consumer that joins identities must read this before treating a user as an account. - USER_KIND_UNSPECIFIED: No kind was reported, which is what events from builds older than this field look like. Treat the user field as unclassified rather than as any particular kind. - USER_KIND_EMAIL: Account email the agent itself reports. - USER_KIND_GITHUB_LOGIN: GitHub account handle, which is all GitHub Copilot records locally. - USER_KIND_OS_LOGIN: No agent account was resolved, so the user field repeats os_user. Never join on this as an account: one shared machine would merge every developer who used it into a single identity. - USER_KIND_ASSERTED: Identifier supplied by the operator through the environment rather than read from the agent, so its shape is whatever the fleet configured.
  - `tenant_meta` object: AgentHookEvent are associated with a tenant or are global.
  - `uuid` string: The UUID of an AgentHookEvent.

## Response `200`

A successful response.

- V1AgentHookEvent: AgentHookEvent represents a single event emitted by the agent runtime. Each event has a type, context, and optional type-specific payload.
  - `consumers_failed` string[]: Consumer keys that failed to process this event. Used for retry.
  - `meta` V1Meta, required: Common fields for all Endor Labs resources.
    - `annotations` object: Annotations can be used to attach metadata to a resource message. Annotation values can be small or large, structured or unstructured, and may include characters not permitted by labels. The keys may contain alphanumerics, underscores (_), dots (.) and dashes (-). The values of an annotation must be 16384 bytes or smaller.
    - `create_time` string, date-time: Time the resource was created. Format: 2017-01-15T01:30:15.01Z RFC 3339: https://www.ietf.org/rfc/rfc3339.txt.
    - `created_by` string: Name and authentication source of the user who created the object, for example, ewok@endor.ai@google@api-key.
    - `description` string: Resource description. Must be less than 1024 bytes.
    - `index_data` V1IndexData: IndexData is used to index the resource for search. It's an internal object.
      - `data` string[]
      - `search_score` number, float: search_score is the score of the resource for search. Internal use only.
      - `tenant` string
      - `will_be_deleted_at` string, date-time: Time that the resource will be deleted.
    - `kind` string: Resource kind, for example, HelloResponse. Auto-generated using the protobuf message proto.MessageName().Name().
    - `name` string, required: Resource name. Must be 63 characters or less.
    - `parent_kind` string: Parent object resource kind, for example, Project.
    - `parent_uuid` string: Parent object UUID.
    - `references` object: Map of objects referenced in a query API.
    - `tags` string[]: List of tags attached to the resource. Tags can be used to select objects and to find collections of objects that satisfy certain conditions. A tag must be 255 characters or less.
    - `update_time` string, date-time: Time the resource was last updated. Note: Updated on all create/patch/delete operations. Format: 2017-01-15T01:30:15.01Z RFC 3339: https://www.ietf.org/rfc/rfc3339.txt.
    - `updated_by` string: Name and authentication source of the last user who updated the object, for example, vulnerabilityingestor@endor.ai@x509.
    - `upsert_time` string, date-time: Time the resource was last upserted. Note: create_time is only set the first time the resource is created. upsert_time is set every time the resource is upseted. Format: 2017-01-15T01:30:15.01Z RFC 3339: https://www.ietf.org/rfc/rfc3339.txt.
    - `version` string: Message version.
  - `processing_result` 'PROCESSING_RESULT_UNSPECIFIED' | 'PROCESSING_RESULT_COMPLETED' | 'PROCESSING_RESULT_FAILED': ProcessingResult indicates the downstream processing result of an event.
  - `spec` V1AgentHookEventSpec
    - `agent` 'AGENT_UNSPECIFIED' | 'AGENT_CURSOR' | 'AGENT_CLAUDE' | 'AGENT_CODEX' | 'AGENT_COPILOT'
    - `agent_version` string: Agent version if available.
    - `cmd_line` V1CmdHook: CmdHook contains payload for command-line related hooks.
      - `cmd_line` string: Command line that was executed.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `command_risk_categories` V1CommandRiskCategory[]: Risk categories the command matched, independent of policy enablement.
    - `command_risk_findings` V1CommandRiskFinding[]: Command fragments that evidenced each risk category.
      - `category` 'COMMAND_RISK_CATEGORY_UNSPECIFIED' | 'COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM' | 'COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION' | 'COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION' | 'COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE' | 'COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION' | 'COMMAND_RISK_CATEGORY_FORCE_PUSH' | 'COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH' | 'COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION' | 'COMMAND_RISK_CATEGORY_SECRET_FILE_READ' | 'COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE' | 'COMMAND_RISK_CATEGORY_NETWORK_ACCESS' | 'COMMAND_RISK_CATEGORY_RECURSIVE_GREP' | 'COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT' | 'COMMAND_RISK_CATEGORY_PUSH_TO_MAIN' | 'COMMAND_RISK_CATEGORY_PACKAGE_INSTALL' | 'COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS' | 'COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING' | 'COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY': CommandRiskCategory identifies the system command-policy family that matched. Values are permanent classifier keys and do not depend on policy names. - COMMAND_RISK_CATEGORY_UNSPECIFIED: No risk classification was performed. - COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM: Destructive filesystem operations, such as recursive root deletion. - COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION: Privilege escalation or broad permission and ownership changes. - COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION: Interpreter one-liners that expose dangerous execution capabilities. - COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE: Remote content that runs directly in a shell. - COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION: Git operations that discard work or skip local safeguards. - COMMAND_RISK_CATEGORY_FORCE_PUSH: Force pushes that rewrite remote history. - COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH: Package or artifact publication to a registry. - COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION: Raw network transfer tools used against remote endpoints. - COMMAND_RISK_CATEGORY_SECRET_FILE_READ: Shell reads of credential, key, or secret files. - COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE: Shell writes to startup files that can establish persistence. - COMMAND_RISK_CATEGORY_NETWORK_ACCESS: Network download or remote access commands. - COMMAND_RISK_CATEGORY_RECURSIVE_GREP: Recursive searches that can expose secrets in transcripts. - COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT: Export of credential-shaped environment variables. - COMMAND_RISK_CATEGORY_PUSH_TO_MAIN: Direct pushes to main or master branches. - COMMAND_RISK_CATEGORY_PACKAGE_INSTALL: Package installation or container run and pull commands. - COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS: Commands that bypass the package firewall. - COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING: Content publication to a public GitHub repository, gist, or release. - COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY: Discovery or staging of credentials and related secret material.
      - `matched_text` string: Text from the command after heredoc removal. The value is capped at 256 Unicode code points. Truncated values end with the literal `...` marker, which is included in the cap.
    - `cwd` string: Working directory when the event was captured.
    - `deny_source` 'DENY_SOURCE_UNSPECIFIED' | 'DENY_SOURCE_OS_SANDBOX' | 'DENY_SOURCE_PROXY' | 'DENY_SOURCE_APP_HOOK': DenySource identifies the layer that blocked a sandboxed execution. - DENY_SOURCE_UNSPECIFIED: No denying layer was reported. - DENY_SOURCE_OS_SANDBOX: The operating-system sandbox blocked the execution. - DENY_SOURCE_PROXY: A network proxy blocked the execution. - DENY_SOURCE_APP_HOOK: An agent hook or application policy blocked the execution.
    - `device_id` string: Device ID if available.
    - `duration_msec` number, float: Duration in milliseconds.
    - `error_message` string: Error message if the hook event failed.
    - `file` V1FileHook: FileHook contains payload for file-related hooks.
      - `file_name` string: File name or path.
      - `operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `has_policy_violation` boolean: Set to true when policy_matches is non-empty.
    - `hook_event_category` 'HOOK_EVENT_CATEGORY_UNSPECIFIED' | 'HOOK_EVENT_CATEGORY_TOOL' | 'HOOK_EVENT_CATEGORY_SESSION' | 'HOOK_EVENT_CATEGORY_CMD' | 'HOOK_EVENT_CATEGORY_FILE' | 'HOOK_EVENT_CATEGORY_USER_PROMPT' | 'HOOK_EVENT_CATEGORY_CONFIG': - HOOK_EVENT_CATEGORY_CONFIG: Changes to the agent's own configuration, which are governance events rather than work the agent performed. Counted under AgenticInventory.config_hook_events, not file_hook_events, even though the event still carries a FileHook payload.
    - `hook_event_name` 'HOOK_EVENT_NAME_UNSPECIFIED' | 'HOOK_EVENT_NAME_SESSION_START' | 'HOOK_EVENT_NAME_SESSION_STOP' | 'HOOK_EVENT_NAME_USER_PROMPT_SUBMIT' | 'HOOK_EVENT_NAME_PRE_TOOL_USE' | 'HOOK_EVENT_NAME_POST_TOOL_USE' | 'HOOK_EVENT_NAME_PRE_CMD' | 'HOOK_EVENT_NAME_POST_CMD' | 'HOOK_EVENT_NAME_PRE_FILE_OPERATION' | 'HOOK_EVENT_NAME_POST_FILE_OPERATION' | 'HOOK_EVENT_NAME_CONFIG_CHANGE': HookEventName identifies the kind of agent lifecycle or tool event. Different agents use different names, so here we will have a normalized list. - HOOK_EVENT_NAME_CONFIG_CHANGE: Agent configuration changed mid-session (e.g. a settings file edit or a /sandbox toggle). Distinct from a file operation so that queries can name it and so file-activity counters exclude settings churn: AgenticAggregate keys file_access_events and edit_operations on this name, and AgenticInventory counts these under config_hook_events rather than file_hook_events.
    - `identity` V1AgentIdentity: AgentIdentity is the org identity resolved for the account behind an event, sourced from the agent provider's org directory. Only the caller's own identity is ever resolved on a client (self-scoped).
      - `display_name` string: Display name of the resolved user.
      - `email` string: Corporate email of the resolved user.
      - `groups` string[]: Org groups / teams the user belongs to.
      - `roles` string[]: Org roles the user holds.
    - `internal_tool` V1InternalToolHook: InternalToolHook contains payload for internal tool-related hooks.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_name` string: Name of the tool (e.g. "Bash", "Glob", "AskUserQuestion", "Skill").
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `is_interrupted` boolean: Whether the hook event was interrupted.
    - `llm_judgments` V1LlmJudgment[]: Judgments the LLM judge made while this event was evaluated. Repeated because the judge will be asked more than one kind of question (prompt injection is Phase 1), not because one command produces several judgments: one command is one judge call, and a command that matches two policies still carries exactly one. A judgment here does NOT by itself mean the event violated a policy. Under JUDGE_SCOPE_ALL_COMMANDS most commands come back benign and match nothing, and those events carry a judgment with has_policy_violation unset. So does a command whose every match the judge released. The released matches are in LlmJudgment.judged_matches.
      - `ai_request_uuid` string: Join key to the AIRequest row for this call, which carries CompletionUsage and the credit accounting. Cost is derived from that row and the price table of the day, never stored here: a stored currency figure goes stale on a price change and cannot be recomputed. Note the derived figure is a FLOOR — the hook client retries a failed POST and each retry bills another inference, while only the attempt that returned leaves its uuid here.
      - `cached_tokens` integer: Tokens served from the provider's prompt cache. The rubric is a standing prefix, so this reports whether it is actually being cached — something the RFC's cost table assumes rather than measures.
      - `completion_tokens` integer: Tokens the label itself cost. Small by design: a large value means the model is explaining itself rather than answering.
      - `confidence` number, float: The model's own 0.0-1.0 self-report, advisory only: recorded so a threshold can be calibrated against real data rather than guessed.
      - `error` string: Set when the judge could not be reached, timed out, or returned something unusable. Without it a fail-open allow reads in the data as a real allow and the fail-open rate cannot be measured at all.
      - `judged_matches` V1AgentHookPolicyMatch[]: The policy matches handed to the judge, as the patterns produced them and before the label acted on them. This is the only record of what the judge decided against. A benign label removes these matches from policy_matches, and a review or suspicious label rewrites their action, so without this copy an event cannot say which policy fired or what it would have done. Empty when the judge ruled on a command no pattern matched, which JUDGE_SCOPE_ALL_COMMANDS does for most commands.
        - `cmd_line` V1CmdLineMatch: CmdLineMatch describes a command-line invocation that matched a policy.
          - `command_source` 'COMMAND_SOURCE_UNSPECIFIED' | 'COMMAND_SOURCE_CMD_HOOK' | 'COMMAND_SOURCE_MCP_TOOL_INPUT': CommandSource names the hook payload the evaluated command text was read from. A shell exposed as an MCP tool (e.g. Claude Desktop's "workspace" server, tool "bash") carries its command in mcp_tool.tool_input rather than in cmd_line, so CmdLine policies read from either payload and record which one they read. - COMMAND_SOURCE_UNSPECIFIED: Records written before the command source was tracked. - COMMAND_SOURCE_CMD_HOOK: spec.cmd_line: the agent's own shell tool. - COMMAND_SOURCE_MCP_TOOL_INPUT: spec.mcp_tool.tool_input: a shell exposed as an MCP tool.
          - `matched_cmd_pattern` string
          - `matched_text` string: Text the pattern matched, cut from the heredoc-stripped command, capped at 256 characters.
          - `mcp_server_name` string: MCP server that carried the command (e.g. "workspace"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
          - `tool_name` string: MCP tool that carried the command (e.g. "bash"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
        - `dependency_risk` V1DependencyRiskMatch: DependencyRiskMatch describes a known-vulnerable dependency found by the dependency-risk check.
          - `direct` boolean: Whether the package is a direct dependency of the introduced package.
          - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
          - `fixed_version` string: Version the advisory names as fixed, when one is published.
          - `introduced_by` string: Package the agent named, set on transitive matches (e.g. "express@4.18.2").
          - `message` string: Human-readable explanation of what fired.
          - `package_name` string: Package name (e.g. "path-to-regexp").
          - `severity` string: Worst matched CVSS severity, as the Severity enum name (e.g. "SEVERITY_HIGH").
          - `version` string: Version judged. For an unpinned install or a range spec, the highest satisfying version known to Endor; the message says so.
          - `vulnerability_id` string: CVE or GHSA id.
        - `file_access` V1FileAccessMatch: FileAccessMatch describes a file access that matched a policy.
          - `matched_file_name_pattern` string: File name pattern that matched.
          - `matched_file_operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
          - `matched_text` string: Text the pattern matched, cut from the separator-normalized name, capped at 256 characters.
        - `malware` V1MalwareMatch: MalwareMatch describes a package flagged by the malware check. The verdict comes from a MALWARE-status, non-contested record in Endor's malware feed.
          - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
          - `message` string: Human-readable explanation of what fired.
          - `package_name` string: Package name (e.g. "reftest-helper-for-ae1x").
          - `reasons` string[]: Why the package is flagged — indicators reported by the malware feed.
          - `source` string: Feed that flagged it, as the MalwareSource enum name (e.g. "MALWARE_SOURCE_AMF").
          - `summary` string: Short title from the malware feed (e.g. "Malicious code in <pkg> (npm)").
          - `version` string: Version from the install command, when it was pinned; empty for an unpinned install.
        - `match_type` 'AGENT_HOOK_POLICY_MATCH_TYPE_UNSPECIFIED' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_TOOL_CALL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_CMD_LINE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_FILE_ACCESS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SKILL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_SERVER' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SESSION' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK' | 'AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX': The type of policy match. - AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE: A package flagged as malware by the malware check. - AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS: A secret detected in file content by the secrets check. - AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK: A known-vulnerable dependency detected by the dependency-risk check. - AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX: Runtime sandbox state of a tool call.
        - `mcp_server` V1McpServerMatch: McpServerMatch describes an MCP server that matched a policy. Carries only the matched server's name; consumers can fetch the full McpMeta from AgenticInventory if more detail is needed. Server-level match; for individual tool calls, see McpToolMatch.
          - `mcp_server_name` string: Name of the MCP server that matched.
          - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "supply_chain_provenance at or below 4").
        - `mcp_tool_call` V1McpToolMatch: McpToolMatch describes a tool call that matched a policy.
          - `matched_server_name_pattern` string: Matched server name pattern.
          - `matched_tool_input_pattern` string: Tool input pattern that matched.
          - `matched_tool_name_pattern` string: Matched tool name pattern.
          - `mcp_server_name` string: MCP server name (e.g. "jira").
          - `message` string: Describes what exactly matched.
          - `tool_name` string: Tool name (e.g. "open bug").
        - `policy_matched` V1AgentHookPolicy: AgentHookPolicy describes a policy to apply when agent hook events match a given activity. When the activity matches, the action (e.g. feedback, block, alert) is applied.
          - `action` V1AgentHookAction: Action describes how to match the activity with the policy and what to do when it matches.
            - `alert` V1AlertAction: AlertAction records an alert with a message (e.g. for audit).
              - …
            - `ask` V1AskAction: AskAction allows asking the user with a message.
              - …
            - `auto` V1AutoAction: AutoAction hands the decision on a matched command to the LLM judge: the command is judged on its own security intent and effect, and the label that comes back is the decision — benign allows, review asks, suspicious blocks. It carries no message on purpose. The agent sees the model's own reason, naming the concrete thing it saw, and a policy-authored string would either be ignored or contradict it. The evaluator converts a matched AUTO policy into a plain ask or block carrying that reason before the verdict is computed, so the verdict is still read off ordinary action kinds. Valid only on cmd_line activities, with either match type, and never on a POLICY_INTENT_GOVERNANCE policy. On an ALLOWLIST the permitted set acts as a prefilter: a listed command never reaches the judge, and one outside it is judged rather than refused outright. Requires an endorctl new enough to know the field. An older client drops it (maniprest unmarshals with DiscardUnknown), is left with an empty action kind, and allows — so switching a policy to AUTO silently loses enforcement of that policy on clients below the minimum version.
            - `block` V1BlockAction: BlockAction blocks the activity and shows a message.
              - …
            - `feedback` V1FeedbackAction: FeedbackAction prompts the user with a message without blocking.
              - …
            - `match_type` 'MATCH_TYPE_UNSPECIFIED' | 'MATCH_TYPE_BLOCKLIST' | 'MATCH_TYPE_ALLOWLIST': We may want to trigger when the activity matches the patterns in the policy (blocklist) or alternatively when the activity does not match the patterns in the policy (allowlist).
          - `activity` V1AgentHookActivity: Activity describes what kind of hook activity the policy applies to.
            - `auto_mode` V1AutoModeActivity: AutoModeActivity turns LLM command judging on for a namespace and says which commands reach the judge. It is an activity kind rather than a resource of its own so that it inherits the AgentHookPolicyDefinition machinery: namespace propagation, name-based deduplication, the JSONL policy-file cache, enabled, and scope. It never produces a match of its own. It is read before the per-policy loop to decide which commands are judged, and a match the judge raises is a CMD_LINE match attributed to this policy. The model stays server-owned: the policy carries no model name and no prompt, only deployment_context. EXACTLY ONE applies to an event — the most specifically scoped candidate, with the policy name breaking an equal rank — and it supplies the whole configuration. They are not unioned, unlike secrets_check or malware_check, because a mode is not a finding: OR is monotone, so nothing at a narrower scope could ever turn a setting back off. A policy that loses is named in a warning, stays enabled and listed, and does nothing.
              - …
            - `cmd_line` V1CmdLineActivity: CmdLineActivity matches command-line execution by regex patterns.
              - …
            - `dependency_risk` V1DependencyRiskActivity: DependencyRiskActivity checks the dependencies an event introduces (from an install command or a manifest/lockfile edit) against Endor's vulnerability data. Matching the activity means running the check; the verdict comes from the lookup, not from the policy config.
              - …
            - `file_access` V1FileAccessActivity: FileAccessActivity matches file access by operation and path patterns.
              - …
            - `malware_check` V1MalwareCheckActivity: MalwareCheckActivity runs Endor's malware lookup against the packages in a package-install command (a cmd_line event). It carries no regex matchers: matching the activity means running the check, and the block/allow verdict comes from the malware feed (MALWARE-status, non-contested records), not from the policy config.
              - …
            - `mcp_server` V1McpServerActivity: McpServerActivity matches MCP servers by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both server_name_matchers and score predicates are set, both must hold; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. This is server-level matching; for per-tool-call matching, use McpToolCallActivity.
              - …
            - `mcp_tool_call` V1McpToolCallActivity: McpToolCallActivity matches tool calls to a specific MCP server and tool.
              - …
            - `secrets_check` V1SecretsCheckActivity: SecretsCheckActivity runs Endor's secret detection over file content (the proposed content of a write/edit, or a file read scanned from disk). Matching the activity means running the scan; the verdict comes from the findings, not from the policy config.
              - …
            - `session` V1SessionActivity: SessionActivity matches sessions by posture predicates over SessionHook fields and the captured AgentConfigSnapshot. Sessions have no stable name, so matching uses field predicates instead of name regexes. Each sub-message is optional; if set, all its predicates are AND'd. Sub-messages are also AND'd with each other. Predicates that target AgentConfigSnapshot evaluate across repository / user / enterprise levels (any-level satisfies). MCP-server-related criteria intentionally live on McpServerActivity, not here.
              - …
            - `skill` V1SkillActivity: SkillActivity matches skills by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both name_matchers and score predicates are set, both must hold for the match to fire; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. When score predicates are set but no SkillMeta is available for the skill, the score branch is configured-but-cannot-fire, failing the AND with the name branch (fail-safe).
              - …
            - `tool_sandbox` V1ToolSandboxActivity: ToolSandboxActivity matches runtime sandbox state on a tool-call event. Values in each repeated field are OR'd. Configured fields are AND'd, and an excluded reason vetoes a match. Exclusions alone and empty activities never match. Unspecified and not-applicable postures do not satisfy posture matches.
              - …
          - `enabled` boolean: Whether this policy is active.
          - `intent` 'POLICY_INTENT_UNSPECIFIED' | 'POLICY_INTENT_RISK' | 'POLICY_INTENT_GOVERNANCE': PolicyIntent says what kind of rule a policy encodes, and so whether the LLM command judge may rule on its matches. Only cmd_line policies are judged, so today the intent changes behavior only on a cmd_line policy. - POLICY_INTENT_UNSPECIFIED: Read as POLICY_INTENT_RISK, so a policy that never sets the field keeps the behavior it had before the field existed. - POLICY_INTENT_RISK: The policy is a risk assessment. A judge scope may hand its matches to the judge, and the label can release, ask about, or block the command. - POLICY_INTENT_GOVERNANCE: The policy is an organisational rule, for example "installs go through the package firewall". A verdict on how risky the command is answers a question the rule does not ask, so no judge scope hands its matches to the judge. Its own action is final: no label releases it, and no label escalates it. Not valid with the AUTO action, which hands the decision to the judge.
          - `inventory_classification` 'INVENTORY_CLASSIFICATION_UNSPECIFIED' | 'INVENTORY_CLASSIFICATION_ALLOW' | 'INVENTORY_CLASSIFICATION_BLOCK' | 'INVENTORY_CLASSIFICATION_SUSPICIOUS' | 'INVENTORY_CLASSIFICATION_MALICIOUS': InventoryClassification declares the classification a policy assigns to a matched MCP server or skill when it fires. UNSPECIFIED means the policy plays no role in inventory classification (e.g. a session, file-access, or cmd-line policy, or an MCP/skill policy whose author only wants the per-event action).
          - `name` string: Name of the policy.
          - `scope` V1AgentHookPolicyScope: AgentHookPolicyScope restricts a policy to a subset of events by matching against per-event identity carried on AgentHookEvent.Spec (repository, user). Scope is evaluated once, before activity-kind matching, so it applies uniformly to all activity kinds. Match logic: an unset scope (or a scope with no matchers set) applies to every event. When set, configured matcher branches are AND'd — every set branch must produce a hit; within a branch the regexes are OR'd (any one matching satisfies the branch); an empty branch is ignored. A scope miss makes the policy a no-op for the event for both blocklist and allowlist match types (the policy simply does not apply).
            - `repository_matchers` string[]: Regex matchers for the repository from AgentHookEvent.Spec.repository (e.g. "github\\.com/acme/.*", ".*-infra$"). OR'd among themselves.
            - `user_matchers` string[]: Regex matchers for the user/account from AgentHookEvent.Spec.user (e.g. "alice", "svc-.*", ".*@example\\.com"). "Account" in the ticket maps to this per-session user identity; there is no separate account entity. OR'd among themselves.
          - `system` boolean: Whether this is a system-defined policy (vs user-defined).
        - `secrets` V1SecretsMatch: SecretsMatch describes a secret detected by the secrets check. It carries only the rule and location, never the secret value, so a finding can be surfaced without leaking the credential.
          - `column` integer: Column in the scanned content where the secret starts.
          - `fingerprint` string: Unique finding fingerprint, for dedup and cross-round false-positive suppression.
          - `line` integer: Line number in the scanned content where the secret was found.
          - `message` string: Human-readable explanation of what fired.
          - `rule_description` string: Friendly rule name (e.g. "AWS Access Key").
          - `rule_id` string: Detection rule that fired (e.g. "aws-access-token", "github-pat").
        - `session` V1SessionMatch: SessionMatch describes a session that matched a policy. Unlike SkillMatch or McpServerMatch, the source data (SessionHook + AgentConfigSnapshot) is already carried by the surrounding AgentHookEvent, so this match only describes what fired.
          - `matched_criteria` string: The criteria category that fired (mirrors a SessionActivity sub-message name, e.g. "top_level", "sandbox", "permissions", "hook", "model").
          - `matched_value` string: The specific predicate value or pattern that matched (e.g. "default_mode=bypassPermissions", "any-level sandbox.enabled=false").
          - `message` string: Free-form human-readable explanation of what fired.
        - `skill` V1SkillMatch: SkillMatch describes a skill that matched a policy. Carries only the matched skill's name; consumers can fetch the full SkillMeta from AgenticInventory if more detail is needed.
          - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "instruction_integrity at or below 4").
          - `skill_name` string: Name of the skill that matched.
        - `tool_sandbox` V1ToolSandboxMatch: ToolSandboxMatch describes the sandbox state that matched a policy.
          - `matched_criteria` string: Policy branch that produced the match.
          - `matched_value` string: Value that satisfied, or failed to satisfy, the policy branch.
          - `override_requested` boolean: Whether the call requested a sandbox override.
          - `posture` 'CALL_SANDBOX_POSTURE_UNSPECIFIED' | 'CALL_SANDBOX_POSTURE_UNKNOWN' | 'CALL_SANDBOX_POSTURE_IN_SANDBOX' | 'CALL_SANDBOX_POSTURE_NO_SANDBOX' | 'CALL_SANDBOX_POSTURE_BLOCKED' | 'CALL_SANDBOX_POSTURE_NOT_APPLICABLE' | 'CALL_SANDBOX_POSTURE_IN_HARNESS': CallSandboxPosture mirrors ToolSandbox by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_POSTURE_UNSPECIFIED: No runtime sandbox state was evaluated. - CALL_SANDBOX_POSTURE_UNKNOWN: The execution is sandbox-governed, but its runtime state is indeterminate. - CALL_SANDBOX_POSTURE_IN_SANDBOX: The execution ran inside the agent's sandbox. - CALL_SANDBOX_POSTURE_NO_SANDBOX: The execution was sandbox-governed but ran without a sandbox. - CALL_SANDBOX_POSTURE_BLOCKED: A sandbox denied the execution. - CALL_SANDBOX_POSTURE_NOT_APPLICABLE: The tool does not execute through a sandbox. - CALL_SANDBOX_POSTURE_IN_HARNESS: A sandbox around the agent harness supplied the isolation.
          - `reason` 'CALL_SANDBOX_REASON_UNSPECIFIED' | 'CALL_SANDBOX_REASON_DISABLED' | 'CALL_SANDBOX_REASON_UNAVAILABLE' | 'CALL_SANDBOX_REASON_MANUAL_APPROVAL' | 'CALL_SANDBOX_REASON_EXCLUDED_COMMAND' | 'CALL_SANDBOX_REASON_ESCALATED' | 'CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE' | 'CALL_SANDBOX_REASON_ESCALATION_PENDING': CallSandboxReason mirrors NoSandboxReason by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_REASON_UNSPECIFIED: No reason was reported. - CALL_SANDBOX_REASON_DISABLED: Sandboxing was disabled by configuration. - CALL_SANDBOX_REASON_UNAVAILABLE: The sandbox was unavailable on this host. - CALL_SANDBOX_REASON_MANUAL_APPROVAL: Manual approval allowed the execution outside the sandbox. - CALL_SANDBOX_REASON_EXCLUDED_COMMAND: The command matched an agent exclusion rule. - CALL_SANDBOX_REASON_ESCALATED: The execution was escalated out of the sandbox. - CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE: A dangerous override disabled sandbox enforcement. - CALL_SANDBOX_REASON_ESCALATION_PENDING: An escalation request was made, but its outcome is not yet known.
      - `kind` 'KIND_UNSPECIFIED' | 'KIND_COMMAND_RISK': What the judge was asked to rule on. - KIND_COMMAND_RISK: Risk of a shell command the agent proposed to run.
      - `label` 'LABEL_UNSPECIFIED' | 'LABEL_BENIGN' | 'LABEL_SUSPICIOUS' | 'LABEL_REVIEW': Label is the judgment on one command. Each value maps to an action the agent hook already has. - LABEL_UNSPECIFIED: No label was produced. Never treat this as a benign result. - LABEL_BENIGN: The command shows nothing concerning on its own. - LABEL_SUSPICIOUS: The command shows something concerning. - LABEL_REVIEW: The decision turns on context the model does not have, so the command belongs in front of the user rather than being cleared or blocked.
      - `latency_ms` string, int64: Round trip as the client measured it, covering assembling the request and mapping the answer back. The one number here that the server-side AIRequest row cannot produce.
      - `model` string: The model that produced the label, as served — the backend rewrites the requested model when aliasing or fallback applies.
      - `prompt_tokens` integer: Tokens the prompt cost.
      - `reason` string: One clause naming the concrete thing the model saw. This is also the text the agent is shown when a judgment raises an ask or a block, which is why an AUTO policy carries no message of its own.
      - `rubric_version` string: Version of the rubric the label was produced under. A label recorded today is not comparable to one recorded after the rubric changed, which is the whole reason the rubric is embedded verbatim rather than assembled per call.
    - `mcp_tool` V1McpToolHook: McpToolHook contains payload for MCP tool-related hooks.
      - `cmd_line` string: Shell command this call runs, when the tool is a shell (Claude Desktop's local agent mode exposes server "workspace", tool "bash"). Such a call is indistinguishable in what it can do from the agent's own Bash tool, but the command arrives inside tool_input, where nothing that reads CmdHook.cmd_line can find it. Lifting it here gives the two paths one field to read, so a consumer does not have to re-derive the shell-tool vocabulary to see the highest-signal action an agent takes. Empty for every non-shell tool.
      - `server_host` string: Host or URL of the server (e.g. "localhost", "https://api.example.com").
      - `server_name` string: Name of the server (e.g. "filesystem", "postgres-mcp", "github-mcp", "enfor-cli-tools").
      - `server_type` 'SERVER_TYPE_UNSPECIFIED' | 'SERVER_TYPE_LOCAL' | 'SERVER_TYPE_REMOTE': ServerType indicates whether a tool server runs locally or remotely.
      - `source` 'MCP_SERVER_SOURCE_UNSPECIFIED' | 'MCP_SERVER_SOURCE_PROJECT_CONFIG' | 'MCP_SERVER_SOURCE_USER_CONFIG' | 'MCP_SERVER_SOURCE_ENTERPRISE_CONFIG' | 'MCP_SERVER_SOURCE_PLUGIN' | 'MCP_SERVER_SOURCE_VENDOR_CONNECTOR' | 'MCP_SERVER_SOURCE_CLIENT_RESERVED' | 'MCP_SERVER_SOURCE_CLIENT_INJECTED': McpServerSource is where an MCP server came from. Orthogonal to ServerType, which answers "where does it run": a vendor connector is a connector by source and REMOTE by type at the same time. Declared here rather than in agentic_inventory.proto because that file imports this one, not the reverse. - MCP_SERVER_SOURCE_UNSPECIFIED: Not classified: no config snapshot was available to check the server against. Distinct from "checked and absent", which is CLIENT_INJECTED. - MCP_SERVER_SOURCE_PROJECT_CONFIG: Registered in the workspace's own checked-in agent config. - MCP_SERVER_SOURCE_USER_CONFIG: Registered in the user's home-directory agent config. - MCP_SERVER_SOURCE_ENTERPRISE_CONFIG: Registered in the OS-managed enterprise agent config. - MCP_SERVER_SOURCE_PLUGIN: Supplied by an agent plugin's manifest rather than by an mcp_servers entry. - MCP_SERVER_SOURCE_VENDOR_CONNECTOR: Vendor hosted connector enabled on the user's agent account, for example a claude.ai connector. Never present in local config. - MCP_SERVER_SOURCE_CLIENT_RESERVED: A name the client reserves for one of its own built in servers, so user config cannot register under it. Highest confidence verdict. - MCP_SERVER_SOURCE_CLIENT_INJECTED: Injected by the client at runtime but not on the reserved list: other product surfaces, IDE bridges, host applications. Absent from a config snapshot that was loaded.
      - `tool_input` object: Tool invocation input; structure is tool-specific (use Struct for JSON).
      - `tool_name` string: Name of the tool (e.g. "Bash", "Glob", "AskUserQuestion", "Skill").
      - `tool_response` object: Tool result; structure is tool-specific (e.g. stdout/stderr or filenames).
    - `model` string: Model involved.
    - `no_sandbox_reason` 'NO_SANDBOX_REASON_UNSPECIFIED' | 'NO_SANDBOX_REASON_DISABLED' | 'NO_SANDBOX_REASON_UNAVAILABLE' | 'NO_SANDBOX_REASON_MANUAL_APPROVAL' | 'NO_SANDBOX_REASON_EXCLUDED_COMMAND' | 'NO_SANDBOX_REASON_ESCALATED' | 'NO_SANDBOX_REASON_DANGEROUS_OVERRIDE' | 'NO_SANDBOX_REASON_ESCALATION_PENDING': NoSandboxReason explains an unsandboxed or unresolved sandbox outcome. - NO_SANDBOX_REASON_UNSPECIFIED: No reason was reported. - NO_SANDBOX_REASON_DISABLED: Sandboxing was disabled by configuration. - NO_SANDBOX_REASON_UNAVAILABLE: The sandbox was unavailable on this host. - NO_SANDBOX_REASON_MANUAL_APPROVAL: Manual approval allowed the execution outside the sandbox. - NO_SANDBOX_REASON_EXCLUDED_COMMAND: The command matched an agent exclusion rule. - NO_SANDBOX_REASON_ESCALATED: The execution was escalated out of the sandbox. - NO_SANDBOX_REASON_DANGEROUS_OVERRIDE: A dangerous override disabled sandbox enforcement. - NO_SANDBOX_REASON_ESCALATION_PENDING: An escalation request is pending. Pair with TOOL_SANDBOX_UNKNOWN, not TOOL_SANDBOX_UNSPECIFIED.
    - `os_user` string: Operating-system login of the account running the agent, carried alongside user rather than instead of it, and populated even when it repeats user. This is the key that links one person's agent accounts, because the same developer is an email to one agent and a GitHub handle to another while staying one OS login underneath. Pair it with device_id: on a shared machine or a CI runner the login is a generic name such as "runner" or "root", and joining on it alone merges unrelated people.
    - `permission_mode` string: Permission mode at capture time (e.g. "default", "acceptEdits").
    - `policy_matches` V1AgentHookPolicyMatch[]: List of policy matches (if any).
      - `cmd_line` V1CmdLineMatch: CmdLineMatch describes a command-line invocation that matched a policy.
        - `command_source` 'COMMAND_SOURCE_UNSPECIFIED' | 'COMMAND_SOURCE_CMD_HOOK' | 'COMMAND_SOURCE_MCP_TOOL_INPUT': CommandSource names the hook payload the evaluated command text was read from. A shell exposed as an MCP tool (e.g. Claude Desktop's "workspace" server, tool "bash") carries its command in mcp_tool.tool_input rather than in cmd_line, so CmdLine policies read from either payload and record which one they read. - COMMAND_SOURCE_UNSPECIFIED: Records written before the command source was tracked. - COMMAND_SOURCE_CMD_HOOK: spec.cmd_line: the agent's own shell tool. - COMMAND_SOURCE_MCP_TOOL_INPUT: spec.mcp_tool.tool_input: a shell exposed as an MCP tool.
        - `matched_cmd_pattern` string
        - `matched_text` string: Text the pattern matched, cut from the heredoc-stripped command, capped at 256 characters.
        - `mcp_server_name` string: MCP server that carried the command (e.g. "workspace"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
        - `tool_name` string: MCP tool that carried the command (e.g. "bash"). Set only when command_source is COMMAND_SOURCE_MCP_TOOL_INPUT.
      - `dependency_risk` V1DependencyRiskMatch: DependencyRiskMatch describes a known-vulnerable dependency found by the dependency-risk check.
        - `direct` boolean: Whether the package is a direct dependency of the introduced package.
        - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
        - `fixed_version` string: Version the advisory names as fixed, when one is published.
        - `introduced_by` string: Package the agent named, set on transitive matches (e.g. "express@4.18.2").
        - `message` string: Human-readable explanation of what fired.
        - `package_name` string: Package name (e.g. "path-to-regexp").
        - `severity` string: Worst matched CVSS severity, as the Severity enum name (e.g. "SEVERITY_HIGH").
        - `version` string: Version judged. For an unpinned install or a range spec, the highest satisfying version known to Endor; the message says so.
        - `vulnerability_id` string: CVE or GHSA id.
      - `file_access` V1FileAccessMatch: FileAccessMatch describes a file access that matched a policy.
        - `matched_file_name_pattern` string: File name pattern that matched.
        - `matched_file_operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
        - `matched_text` string: Text the pattern matched, cut from the separator-normalized name, capped at 256 characters.
      - `malware` V1MalwareMatch: MalwareMatch describes a package flagged by the malware check. The verdict comes from a MALWARE-status, non-contested record in Endor's malware feed.
        - `ecosystem` string: Ecosystem the package belongs to (e.g. "npm", "pypi").
        - `message` string: Human-readable explanation of what fired.
        - `package_name` string: Package name (e.g. "reftest-helper-for-ae1x").
        - `reasons` string[]: Why the package is flagged — indicators reported by the malware feed.
        - `source` string: Feed that flagged it, as the MalwareSource enum name (e.g. "MALWARE_SOURCE_AMF").
        - `summary` string: Short title from the malware feed (e.g. "Malicious code in <pkg> (npm)").
        - `version` string: Version from the install command, when it was pinned; empty for an unpinned install.
      - `match_type` 'AGENT_HOOK_POLICY_MATCH_TYPE_UNSPECIFIED' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_TOOL_CALL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_CMD_LINE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_FILE_ACCESS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SKILL' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MCP_SERVER' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SESSION' | 'AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE' | 'AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS' | 'AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK' | 'AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX': The type of policy match. - AGENT_HOOK_POLICY_MATCH_TYPE_MALWARE: A package flagged as malware by the malware check. - AGENT_HOOK_POLICY_MATCH_TYPE_SECRETS: A secret detected in file content by the secrets check. - AGENT_HOOK_POLICY_MATCH_TYPE_DEPENDENCY_RISK: A known-vulnerable dependency detected by the dependency-risk check. - AGENT_HOOK_POLICY_MATCH_TYPE_TOOL_SANDBOX: Runtime sandbox state of a tool call.
      - `mcp_server` V1McpServerMatch: McpServerMatch describes an MCP server that matched a policy. Carries only the matched server's name; consumers can fetch the full McpMeta from AgenticInventory if more detail is needed. Server-level match; for individual tool calls, see McpToolMatch.
        - `mcp_server_name` string: Name of the MCP server that matched.
        - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "supply_chain_provenance at or below 4").
      - `mcp_tool_call` V1McpToolMatch: McpToolMatch describes a tool call that matched a policy.
        - `matched_server_name_pattern` string: Matched server name pattern.
        - `matched_tool_input_pattern` string: Tool input pattern that matched.
        - `matched_tool_name_pattern` string: Matched tool name pattern.
        - `mcp_server_name` string: MCP server name (e.g. "jira").
        - `message` string: Describes what exactly matched.
        - `tool_name` string: Tool name (e.g. "open bug").
      - `policy_matched` V1AgentHookPolicy: AgentHookPolicy describes a policy to apply when agent hook events match a given activity. When the activity matches, the action (e.g. feedback, block, alert) is applied.
        - `action` V1AgentHookAction: Action describes how to match the activity with the policy and what to do when it matches.
          - `alert` V1AlertAction: AlertAction records an alert with a message (e.g. for audit).
            - `feedback_message` string: Feedback message shown to the user when the alert is raised.
            - `message` string
          - `ask` V1AskAction: AskAction allows asking the user with a message.
            - `feedback_message` string: Feedback message shown to the user when asking for confirmation.
            - `message` string
          - `auto` V1AutoAction: AutoAction hands the decision on a matched command to the LLM judge: the command is judged on its own security intent and effect, and the label that comes back is the decision — benign allows, review asks, suspicious blocks. It carries no message on purpose. The agent sees the model's own reason, naming the concrete thing it saw, and a policy-authored string would either be ignored or contradict it. The evaluator converts a matched AUTO policy into a plain ask or block carrying that reason before the verdict is computed, so the verdict is still read off ordinary action kinds. Valid only on cmd_line activities, with either match type, and never on a POLICY_INTENT_GOVERNANCE policy. On an ALLOWLIST the permitted set acts as a prefilter: a listed command never reaches the judge, and one outside it is judged rather than refused outright. Requires an endorctl new enough to know the field. An older client drops it (maniprest unmarshals with DiscardUnknown), is left with an empty action kind, and allows — so switching a policy to AUTO silently loses enforcement of that policy on clients below the minimum version.
          - `block` V1BlockAction: BlockAction blocks the activity and shows a message.
            - `feedback_message` string: Feedback message shown to the user when the action is blocked.
            - `message` string
          - `feedback` V1FeedbackAction: FeedbackAction prompts the user with a message without blocking.
            - `feedback_message` string
            - `message` string
          - `match_type` 'MATCH_TYPE_UNSPECIFIED' | 'MATCH_TYPE_BLOCKLIST' | 'MATCH_TYPE_ALLOWLIST': We may want to trigger when the activity matches the patterns in the policy (blocklist) or alternatively when the activity does not match the patterns in the policy (allowlist).
        - `activity` V1AgentHookActivity: Activity describes what kind of hook activity the policy applies to.
          - `auto_mode` V1AutoModeActivity: AutoModeActivity turns LLM command judging on for a namespace and says which commands reach the judge. It is an activity kind rather than a resource of its own so that it inherits the AgentHookPolicyDefinition machinery: namespace propagation, name-based deduplication, the JSONL policy-file cache, enabled, and scope. It never produces a match of its own. It is read before the per-policy loop to decide which commands are judged, and a match the judge raises is a CMD_LINE match attributed to this policy. The model stays server-owned: the policy carries no model name and no prompt, only deployment_context. EXACTLY ONE applies to an event — the most specifically scoped candidate, with the policy name breaking an equal rank — and it supplies the whole configuration. They are not unioned, unlike secrets_check or malware_check, because a mode is not a finding: OR is monotone, so nothing at a narrower scope could ever turn a setting back off. A policy that loses is named in a warning, stays enabled and listed, and does nothing.
            - `deployment_context` string[]: Free-text lines describing the local deployment: which hosts are the organisation's own, which registries are sanctioned, that ENDOR_TOKEN is expected on this machine. These fill the trust anchors the rubric names as deployment-supplied and ships empty; until they are set the rubric over-escalates on ordinary internal traffic. They are appended AFTER the rubric, so the rubric stays a byte-identical prefix the provider can serve from its cache. The bounds below are per entry. ValidatePolicy bounds the SUM at 8 KiB, the point past which the judge stops reading, so a tenant cannot store context that would be dropped unread on every call — nor a policy line long enough to break the JSONL reader that distributes the set to hooks.
            - `judge_scope` 'JUDGE_SCOPE_UNSPECIFIED' | 'JUDGE_SCOPE_MATCHED_COMMANDS' | 'JUDGE_SCOPE_ALL_COMMANDS': JudgeScope says which commands reach the judge. It is one selector rather than a set of booleans so that no two modes can be in force at once. - JUDGE_SCOPE_UNSPECIFIED: Judge nothing. The policy still supplies deployment_context to the cmd_line policies that carry the AUTO action and judge on their own. This is also what an endorctl too old to know a value added later reads, so every future value fails safe. - JUDGE_SCOPE_MATCHED_COMMANDS: Judge the commands a RISK command policy already matched, treating the action of each matched policy as AUTO. This overrides an explicit customer decision in BOTH directions: a policy that says block stops blocking and asks the judge, and one that says alert or feedback can escalate to a block on a suspicious label. The override lasts only as long as the judge answers — with no label each policy keeps its own action, so an outage degrades to the enforcement the tenant had. A GOVERNANCE policy is never overridden, and a command that only a governance policy matched is not judged at all. - JUDGE_SCOPE_ALL_COMMANDS: Judge every command and stand the RISK command policies down. The malware and secrets checks are untouched: they carry real detections rather than regular expressions. The patterns are still evaluated. They are stood down by a label coming back rather than by this scope alone, which is what lets a judge that cannot be reached fall back to the verdict they produced. An allowlist stands down on the same terms as a blocklist, so a command absent from the set a tenant permitted runs anyway if the judge finds nothing wrong with it. Mark a command policy GOVERNANCE to keep its action final: a governance match keeps its own action under every label. The judge still rules on the command itself, so a review or suspicious label also raises an ask or a block against the auto-mode policy, next to the governance match.
          - `cmd_line` V1CmdLineActivity: CmdLineActivity matches command-line execution by regex patterns.
            - `command_risk_category` 'COMMAND_RISK_CATEGORY_UNSPECIFIED' | 'COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM' | 'COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION' | 'COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION' | 'COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE' | 'COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION' | 'COMMAND_RISK_CATEGORY_FORCE_PUSH' | 'COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH' | 'COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION' | 'COMMAND_RISK_CATEGORY_SECRET_FILE_READ' | 'COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE' | 'COMMAND_RISK_CATEGORY_NETWORK_ACCESS' | 'COMMAND_RISK_CATEGORY_RECURSIVE_GREP' | 'COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT' | 'COMMAND_RISK_CATEGORY_PUSH_TO_MAIN' | 'COMMAND_RISK_CATEGORY_PACKAGE_INSTALL' | 'COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS' | 'COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING' | 'COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY': CommandRiskCategory identifies the system command-policy family that matched. Values are permanent classifier keys and do not depend on policy names. - COMMAND_RISK_CATEGORY_UNSPECIFIED: No risk classification was performed. - COMMAND_RISK_CATEGORY_DESTRUCTIVE_FILESYSTEM: Destructive filesystem operations, such as recursive root deletion. - COMMAND_RISK_CATEGORY_PRIVILEGE_ESCALATION: Privilege escalation or broad permission and ownership changes. - COMMAND_RISK_CATEGORY_INLINE_CODE_EXECUTION: Interpreter one-liners that expose dangerous execution capabilities. - COMMAND_RISK_CATEGORY_DOWNLOAD_AND_EXECUTE: Remote content that runs directly in a shell. - COMMAND_RISK_CATEGORY_DANGEROUS_GIT_OPERATION: Git operations that discard work or skip local safeguards. - COMMAND_RISK_CATEGORY_FORCE_PUSH: Force pushes that rewrite remote history. - COMMAND_RISK_CATEGORY_PACKAGE_PUBLISH: Package or artifact publication to a registry. - COMMAND_RISK_CATEGORY_NETWORK_EXFILTRATION: Raw network transfer tools used against remote endpoints. - COMMAND_RISK_CATEGORY_SECRET_FILE_READ: Shell reads of credential, key, or secret files. - COMMAND_RISK_CATEGORY_SHELL_PROFILE_WRITE: Shell writes to startup files that can establish persistence. - COMMAND_RISK_CATEGORY_NETWORK_ACCESS: Network download or remote access commands. - COMMAND_RISK_CATEGORY_RECURSIVE_GREP: Recursive searches that can expose secrets in transcripts. - COMMAND_RISK_CATEGORY_ENV_VAR_EXPORT: Export of credential-shaped environment variables. - COMMAND_RISK_CATEGORY_PUSH_TO_MAIN: Direct pushes to main or master branches. - COMMAND_RISK_CATEGORY_PACKAGE_INSTALL: Package installation or container run and pull commands. - COMMAND_RISK_CATEGORY_PACKAGE_MANAGER_BYPASS: Commands that bypass the package firewall. - COMMAND_RISK_CATEGORY_PUBLIC_GITHUB_PUBLISHING: Content publication to a public GitHub repository, gist, or release. - COMMAND_RISK_CATEGORY_CREDENTIAL_DISCOVERY: Discovery or staging of credentials and related secret material.
            - `patterns` string[]: Patterns to match against the command (e.g. "rm -rf /.*", "curl .* \\| bash").
          - `dependency_risk` V1DependencyRiskActivity: DependencyRiskActivity checks the dependencies an event introduces (from an install command or a manifest/lockfile edit) against Endor's vulnerability data. Matching the activity means running the check; the verdict comes from the lookup, not from the policy config.
            - `ecosystems` string[]: Ecosystems to check (e.g. "npm", "pypi"). Empty means all ecosystems.
            - `exclude_file_patterns` string[]: Skip files whose path matches one of these regexes. Applied after include_file_patterns.
            - `include_file_patterns` string[]: Only check files whose path matches one of these regexes. Empty means every manifest/lockfile name the check recognizes.
            - `include_transitives` boolean: Also check the packages the new dependency pulls in.
            - `min_cvss_severity` 'SEVERITY_UNSPECIFIED' | 'SEVERITY_LOW' | 'SEVERITY_MEDIUM' | 'SEVERITY_HIGH' | 'SEVERITY_CRITICAL': Severity levels, mirroring Vuln.Spec.CVSSV3Severity.Level. - SEVERITY_UNSPECIFIED: Unset. min_cvss_severity treats this as HIGH. - SEVERITY_LOW: CVSS low (0.1 - 3.9). - SEVERITY_MEDIUM: CVSS medium (4.0 - 6.9). - SEVERITY_HIGH: CVSS high (7.0 - 8.9). - SEVERITY_CRITICAL: CVSS critical (9.0 - 10.0).
          - `file_access` V1FileAccessActivity: FileAccessActivity matches file access by operation and path patterns.
            - `file_name_patterns` string[]: Regex file patterns (e.g. "\\.env$", "secrets/.*", ".*\\.key$").
            - `file_operation` 'FILE_OPERATION_UNSPECIFIED' | 'FILE_OPERATION_READ' | 'FILE_OPERATION_WRITE' | 'FILE_OPERATION_DELETE' | 'FILE_OPERATION_EDIT': FileOperation identifies the type of file access.
          - `malware_check` V1MalwareCheckActivity: MalwareCheckActivity runs Endor's malware lookup against the packages in a package-install command (a cmd_line event). It carries no regex matchers: matching the activity means running the check, and the block/allow verdict comes from the malware feed (MALWARE-status, non-contested records), not from the policy config.
            - `ecosystems` string[]: Ecosystems to check (e.g. "npm", "pypi", "cargo"). Empty means all ecosystems.
          - `mcp_server` V1McpServerActivity: McpServerActivity matches MCP servers by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both server_name_matchers and score predicates are set, both must hold; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. This is server-level matching; for per-tool-call matching, use McpToolCallActivity.
            - `dimension_at_or_below` V1McpDimensionThresholds: McpDimensionThresholds holds per-dimension score thresholds for McpServerActivity. Each field is optional; an unset dimension is ignored. Set dimensions are OR'd among themselves and with score_at_or_below: any single dimension at or below its threshold fires the predicate. Dimension names mirror AgenticInventory.McpScoreDimensions.
              - …
            - `score_at_or_below` number, float: Match when the overall score is at or below this threshold (scores are 1-10, higher = safer). OR'd with dimension_at_or_below.
            - `server_name_matchers` string[]: Regex matchers for MCP server name (e.g. "untrusted-.*", "remote-.*"). AND'd with the score-predicate branch when both are configured.
          - `mcp_tool_call` V1McpToolCallActivity: McpToolCallActivity matches tool calls to a specific MCP server and tool.
            - `mcp_server_name` string: MCP server name (e.g. "jira").
            - `server_name_matchers` string[]: Optional regex matchers for MCP server name.
            - `tool_input_matchers` string[]: Optional regex matchers for tool input (e.g. ".*AI.*").
            - `tool_name` string: Tool name (e.g. "open bug").
            - `tool_name_matchers` string[]: Optional regex matchers for tool name.
          - `secrets_check` V1SecretsCheckActivity: SecretsCheckActivity runs Endor's secret detection over file content (the proposed content of a write/edit, or a file read scanned from disk). Matching the activity means running the scan; the verdict comes from the findings, not from the policy config.
            - `exclude_file_patterns` string[]: Skip files whose path matches one of these regexes (e.g. test fixtures, "*.example" files, vendored dirs). Applied after include_file_patterns.
            - `exclude_rule_ids` string[]: Rule IDs whose findings this policy ignores. Matched as for include_rule_ids, and applied after it, so an id in both is ignored.
            - `file_operations` V1FileAccessActivityFileOperation[]: File operations to scan. Empty means write and edit; scanning a read means reading the file from disk, so reads are opt-in.
            - `include_file_patterns` string[]: Only scan files whose path matches one of these regexes. Empty means all files the event covers.
            - `include_rule_ids` string[]: Rule IDs whose findings this policy acts on, compared exactly and case-sensitively against the rule id on each finding (SecretRule.spec.rule_id, e.g. "aws-access-token"). Empty means every rule in the tenant's effective ruleset.
          - `session` V1SessionActivity: SessionActivity matches sessions by posture predicates over SessionHook fields and the captured AgentConfigSnapshot. Sessions have no stable name, so matching uses field predicates instead of name regexes. Each sub-message is optional; if set, all its predicates are AND'd. Sub-messages are also AND'd with each other. Predicates that target AgentConfigSnapshot evaluate across repository / user / enterprise levels (any-level satisfies). MCP-server-related criteria intentionally live on McpServerActivity, not here.
            - `hook` V1SessionHookCriteria: SessionHookCriteria matches against AgentHookConfig entries at any AgentConfigLevel. Each field is optional.
              - …
            - `model` V1SessionModelCriteria: SessionModelCriteria matches against default_model and available_models at any AgentConfigLevel. Each field is optional.
              - …
            - `permissions` V1SessionPermissionsCriteria: SessionPermissionsCriteria matches against AgentPermissionsConfig at any AgentConfigLevel. Each field is optional.
              - …
            - `sandbox` V1SessionSandboxCriteria: SessionSandboxCriteria matches against AgentSandboxConfig at any AgentConfigLevel, and against the session's resolved sandbox posture. Each field is optional.
              - …
            - `top_level` V1SessionTopLevelCriteria: SessionTopLevelCriteria matches against SessionHook top-level fields (composer_mode, source, is_background_agent) and the per-session user identity carried on AgentHookEvent.Spec.user.
              - …
          - `skill` V1SkillActivity: SkillActivity matches skills by name patterns and/or score thresholds. Match logic: configured branches are AND'd — when both name_matchers and score predicates are set, both must hold for the match to fire; when only one is set, only that one must hold; if neither is set, the activity never matches. Within the score branch, score_at_or_below and every set field of dimension_at_or_below are OR'd: any single satisfied threshold fires the branch. When score predicates are set but no SkillMeta is available for the skill, the score branch is configured-but-cannot-fire, failing the AND with the name branch (fail-safe).
            - `dimension_at_or_below` V1SkillDimensionThresholds: SkillDimensionThresholds holds per-dimension score thresholds for SkillActivity. Each field is optional; an unset dimension is ignored. Set dimensions are OR'd among themselves and with score_at_or_below: any single dimension at or below its threshold fires the predicate. Dimension names mirror AgenticInventory.SkillScoreDimensions.
              - …
            - `name_matchers` string[]: Regex matchers for skill name (e.g. "untrusted-.*", "experimental-.*"). AND'd with the score-predicate branch when both are configured.
            - `score_at_or_below` number, float: Match when the overall score is at or below this threshold (scores are 1-10, higher = safer). OR'd with dimension_at_or_below.
          - `tool_sandbox` V1ToolSandboxActivity: ToolSandboxActivity matches runtime sandbox state on a tool-call event. Values in each repeated field are OR'd. Configured fields are AND'd, and an excluded reason vetoes a match. Exclusions alone and empty activities never match. Unspecified and not-applicable postures do not satisfy posture matches.
            - `excluded_reasons` V1CallSandboxReason[]: Reasons that veto an otherwise successful match.
            - `override_requested` boolean: If set, the event's override request must equal this value.
            - `postures` V1CallSandboxPosture[]: Runtime postures to match. An empty list accepts any posture.
            - `reasons` V1CallSandboxReason[]: Unsandboxed or unresolved outcome reasons to match. An empty list accepts any reason.
        - `enabled` boolean: Whether this policy is active.
        - `intent` 'POLICY_INTENT_UNSPECIFIED' | 'POLICY_INTENT_RISK' | 'POLICY_INTENT_GOVERNANCE': PolicyIntent says what kind of rule a policy encodes, and so whether the LLM command judge may rule on its matches. Only cmd_line policies are judged, so today the intent changes behavior only on a cmd_line policy. - POLICY_INTENT_UNSPECIFIED: Read as POLICY_INTENT_RISK, so a policy that never sets the field keeps the behavior it had before the field existed. - POLICY_INTENT_RISK: The policy is a risk assessment. A judge scope may hand its matches to the judge, and the label can release, ask about, or block the command. - POLICY_INTENT_GOVERNANCE: The policy is an organisational rule, for example "installs go through the package firewall". A verdict on how risky the command is answers a question the rule does not ask, so no judge scope hands its matches to the judge. Its own action is final: no label releases it, and no label escalates it. Not valid with the AUTO action, which hands the decision to the judge.
        - `inventory_classification` 'INVENTORY_CLASSIFICATION_UNSPECIFIED' | 'INVENTORY_CLASSIFICATION_ALLOW' | 'INVENTORY_CLASSIFICATION_BLOCK' | 'INVENTORY_CLASSIFICATION_SUSPICIOUS' | 'INVENTORY_CLASSIFICATION_MALICIOUS': InventoryClassification declares the classification a policy assigns to a matched MCP server or skill when it fires. UNSPECIFIED means the policy plays no role in inventory classification (e.g. a session, file-access, or cmd-line policy, or an MCP/skill policy whose author only wants the per-event action).
        - `name` string: Name of the policy.
        - `scope` V1AgentHookPolicyScope: AgentHookPolicyScope restricts a policy to a subset of events by matching against per-event identity carried on AgentHookEvent.Spec (repository, user). Scope is evaluated once, before activity-kind matching, so it applies uniformly to all activity kinds. Match logic: an unset scope (or a scope with no matchers set) applies to every event. When set, configured matcher branches are AND'd — every set branch must produce a hit; within a branch the regexes are OR'd (any one matching satisfies the branch); an empty branch is ignored. A scope miss makes the policy a no-op for the event for both blocklist and allowlist match types (the policy simply does not apply).
          - `repository_matchers` string[]: Regex matchers for the repository from AgentHookEvent.Spec.repository (e.g. "github\\.com/acme/.*", ".*-infra$"). OR'd among themselves.
          - `user_matchers` string[]: Regex matchers for the user/account from AgentHookEvent.Spec.user (e.g. "alice", "svc-.*", ".*@example\\.com"). "Account" in the ticket maps to this per-session user identity; there is no separate account entity. OR'd among themselves.
        - `system` boolean: Whether this is a system-defined policy (vs user-defined).
      - `secrets` V1SecretsMatch: SecretsMatch describes a secret detected by the secrets check. It carries only the rule and location, never the secret value, so a finding can be surfaced without leaking the credential.
        - `column` integer: Column in the scanned content where the secret starts.
        - `fingerprint` string: Unique finding fingerprint, for dedup and cross-round false-positive suppression.
        - `line` integer: Line number in the scanned content where the secret was found.
        - `message` string: Human-readable explanation of what fired.
        - `rule_description` string: Friendly rule name (e.g. "AWS Access Key").
        - `rule_id` string: Detection rule that fired (e.g. "aws-access-token", "github-pat").
      - `session` V1SessionMatch: SessionMatch describes a session that matched a policy. Unlike SkillMatch or McpServerMatch, the source data (SessionHook + AgentConfigSnapshot) is already carried by the surrounding AgentHookEvent, so this match only describes what fired.
        - `matched_criteria` string: The criteria category that fired (mirrors a SessionActivity sub-message name, e.g. "top_level", "sandbox", "permissions", "hook", "model").
        - `matched_value` string: The specific predicate value or pattern that matched (e.g. "default_mode=bypassPermissions", "any-level sandbox.enabled=false").
        - `message` string: Free-form human-readable explanation of what fired.
      - `skill` V1SkillMatch: SkillMatch describes a skill that matched a policy. Carries only the matched skill's name; consumers can fetch the full SkillMeta from AgenticInventory if more detail is needed.
        - `message` string: Describes what exactly matched (e.g. "score at or below threshold 5", "instruction_integrity at or below 4").
        - `skill_name` string: Name of the skill that matched.
      - `tool_sandbox` V1ToolSandboxMatch: ToolSandboxMatch describes the sandbox state that matched a policy.
        - `matched_criteria` string: Policy branch that produced the match.
        - `matched_value` string: Value that satisfied, or failed to satisfy, the policy branch.
        - `override_requested` boolean: Whether the call requested a sandbox override.
        - `posture` 'CALL_SANDBOX_POSTURE_UNSPECIFIED' | 'CALL_SANDBOX_POSTURE_UNKNOWN' | 'CALL_SANDBOX_POSTURE_IN_SANDBOX' | 'CALL_SANDBOX_POSTURE_NO_SANDBOX' | 'CALL_SANDBOX_POSTURE_BLOCKED' | 'CALL_SANDBOX_POSTURE_NOT_APPLICABLE' | 'CALL_SANDBOX_POSTURE_IN_HARNESS': CallSandboxPosture mirrors ToolSandbox by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_POSTURE_UNSPECIFIED: No runtime sandbox state was evaluated. - CALL_SANDBOX_POSTURE_UNKNOWN: The execution is sandbox-governed, but its runtime state is indeterminate. - CALL_SANDBOX_POSTURE_IN_SANDBOX: The execution ran inside the agent's sandbox. - CALL_SANDBOX_POSTURE_NO_SANDBOX: The execution was sandbox-governed but ran without a sandbox. - CALL_SANDBOX_POSTURE_BLOCKED: A sandbox denied the execution. - CALL_SANDBOX_POSTURE_NOT_APPLICABLE: The tool does not execute through a sandbox. - CALL_SANDBOX_POSTURE_IN_HARNESS: A sandbox around the agent harness supplied the isolation.
        - `reason` 'CALL_SANDBOX_REASON_UNSPECIFIED' | 'CALL_SANDBOX_REASON_DISABLED' | 'CALL_SANDBOX_REASON_UNAVAILABLE' | 'CALL_SANDBOX_REASON_MANUAL_APPROVAL' | 'CALL_SANDBOX_REASON_EXCLUDED_COMMAND' | 'CALL_SANDBOX_REASON_ESCALATED' | 'CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE' | 'CALL_SANDBOX_REASON_ESCALATION_PENDING': CallSandboxReason mirrors NoSandboxReason by ordinal because this file cannot import agent_hook_event.proto. Keep the values and suffixes aligned. - CALL_SANDBOX_REASON_UNSPECIFIED: No reason was reported. - CALL_SANDBOX_REASON_DISABLED: Sandboxing was disabled by configuration. - CALL_SANDBOX_REASON_UNAVAILABLE: The sandbox was unavailable on this host. - CALL_SANDBOX_REASON_MANUAL_APPROVAL: Manual approval allowed the execution outside the sandbox. - CALL_SANDBOX_REASON_EXCLUDED_COMMAND: The command matched an agent exclusion rule. - CALL_SANDBOX_REASON_ESCALATED: The execution was escalated out of the sandbox. - CALL_SANDBOX_REASON_DANGEROUS_OVERRIDE: A dangerous override disabled sandbox enforcement. - CALL_SANDBOX_REASON_ESCALATION_PENDING: An escalation request was made, but its outcome is not yet known.
    - `raw_hook_event_name` string: Raw hook event name from the agent.
    - `reported_sandbox_config` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
      - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
      - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
      - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
      - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
      - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
      - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
      - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
      - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
    - `repository` string: Repository where the action happened.
    - `sandbox_confidence` 'SANDBOX_DETECTION_CONFIDENCE_UNSPECIFIED' | 'SANDBOX_DETECTION_CONFIDENCE_REPORTED' | 'SANDBOX_DETECTION_CONFIDENCE_DERIVED' | 'SANDBOX_DETECTION_CONFIDENCE_INFERRED': SandboxDetectionConfidence describes how directly a sandbox state was observed. - SANDBOX_DETECTION_CONFIDENCE_UNSPECIFIED: No confidence was reported. - SANDBOX_DETECTION_CONFIDENCE_REPORTED: The agent explicitly reported the sandbox state. - SANDBOX_DETECTION_CONFIDENCE_DERIVED: The state was derived from configuration or structured events. - SANDBOX_DETECTION_CONFIDENCE_INFERRED: The state was inferred from indirect evidence.
    - `sandbox_config_posture` 'SANDBOX_CONFIG_POSTURE_UNSPECIFIED' | 'SANDBOX_CONFIG_POSTURE_UNKNOWN' | 'SANDBOX_CONFIG_POSTURE_ENABLED' | 'SANDBOX_CONFIG_POSTURE_DISABLED': SandboxConfigPosture is the session-level sandbox posture derived from agent configuration. - SANDBOX_CONFIG_POSTURE_UNSPECIFIED: No posture was evaluated by this client. - SANDBOX_CONFIG_POSTURE_UNKNOWN: The client evaluated configuration but could not determine posture. - SANDBOX_CONFIG_POSTURE_ENABLED: Configuration indicates sandboxing is enabled for the session. - SANDBOX_CONFIG_POSTURE_DISABLED: Configuration indicates sandboxing is disabled for the session.
    - `sandbox_override_requested` boolean: Whether this call requested a sandbox override.
    - `session` V1SessionHook
      - `ai_tool_inventory` V1AiToolInventory: AiToolInventory contains all AI development tools detected on the host machine.
        - `detections` V1AiToolDetection[]: Detected AI tools.
          - `category` 'AI_TOOL_CATEGORY_UNSPECIFIED' | 'AI_TOOL_CATEGORY_IDE' | 'AI_TOOL_CATEGORY_CLI_TOOL' | 'AI_TOOL_CATEGORY_AGENT' | 'AI_TOOL_CATEGORY_FRAMEWORK' | 'AI_TOOL_CATEGORY_MCP_CONFIG' | 'AI_TOOL_CATEGORY_IDE_EXTENSION' | 'AI_TOOL_CATEGORY_SANDBOX_TOOL': AiToolCategory classifies a detected AI development tool. - AI_TOOL_CATEGORY_SANDBOX_TOOL: Dedicated sandbox tools that wrap an agent, as opposed to an agent's own built-in sandbox.
          - `evidence` V1AiToolEvidence[]: Evidence supporting the detection.
            - `key` string: Evidence key (e.g. "install_path", "binary_path", "version", "config_path").
            - `value` string: Evidence value.
          - `tool` string: Tool identifier (e.g. "cursor", "claude-code", "ollama").
          - `vendor` string: Vendor name (e.g. "Anthropic", "OpenSource", "Google").
      - `composer_mode` string: Composer mode of the session. "agent", "ask", "edit"
      - `config` V1AgentConfigSnapshot: AgentConfigSnapshot captures the three-level configuration hierarchy (repository, user, enterprise) at session start time.
        - `enterprise` V1AgentConfigLevel: AgentConfigLevel captures the agent configuration at one scope level (repository, user, or enterprise).
          - `available_models` string[]: AvailableModels restricts which model IDs are selectable. Populated from Claude Code settings only.
          - `default_model` string: DefaultModel is the default model ID configured at this level. Populated from Claude Code settings only.
          - `env` object: Env holds environment variables configured at this level.
          - `environment_type` string: EnvironmentType is the remote environment type (e.g. "docker"). Populated from Cursor environment.json only.
          - `hooks` V1AgentHookConfig[]: Hooks lists the hook event bindings configured at this level.
            - `commands` string[]: Commands lists the shell commands registered for this event.
            - `event_name` string: EventName is the lifecycle hook event name (e.g. "PostToolUse").
          - `instruction_files` V1AgentInstructionFile[]: InstructionFiles lists rule/instruction files discovered at this level. Cursor: .mdc files from rules/ directories. Claude Code: reserved for future use.
            - `content_hash` string: ContentHash is the SHA-256 hex digest of the file content.
            - `name` string: Name is the base filename without extension (e.g. "security" from "security.mdc").
            - `path` string: Path is the absolute filesystem path to the instruction file.
          - `mcp_servers` V1AgentMCPServer[]: McpServers lists the MCP servers configured at this level.
            - `args` string[]: Args are the command-line arguments passed to the server process.
            - `command` string: Command is the executable used for stdio-transport servers.
            - `config_server_name` string: ConfigServerName is the user-authored mcp.json map key that named this server entry in the agent's configuration (e.g. "claude-endor-cli-tools", "postgres"). It is the stable identifier per-tool hooks can use to look the entry up in the cached SESSION_START snapshot — Claude's tool name shape "mcp__<server>__<tool>" carries this value, while Name carries the runtime program identity. Wrapped to distinguish "unset" from "".
            - `env` object: Env holds environment variables injected into the server process.
            - `from_plugin` boolean: FromPlugin marks a server contributed by an enabled agent plugin's manifest rather than by an mcp_servers entry a user wrote. Only the collector that walked the plugin registry can tell the two apart, and both inventory writers need the answer to agree, so it is stated here rather than inferred downstream from the "<plugin>/<server>" shape of config_server_name — a user-authored key may legitimately contain a slash ("@vendor/server"). Wrapped to distinguish "unset" (a collector predating this field) from "false".
            - `headers` object: Headers are additional HTTP headers sent with requests. Populated by collectors when available; Cursor's mcp.json has no headers field so this is empty for Cursor.
            - `name` string: Name is the canonical runtime identifier of the MCP server program — the value extracted from the command line (e.g. "endorctl" from "npx -y endorctl ai-tools mcp-server") or, for HTTP/SSE servers, the host slice of the URL. The backend uses this as the inventory document name so SESSION_START rows and per-tool rows (whose McpToolHook.server_name is derived the same way from the runtime URL/command) land on a single inventory document per logical server.
            - `transport` string: Transport is the MCP transport type: "stdio", "http", or "sse". Collectors must populate this; an empty value means the collector could not classify the server. Claude Code reads this from .mcp.json; Cursor derives it structurally from command/url since mcp.json has no transport field.
            - `url` string: URL is the endpoint for HTTP or SSE transport servers.
          - `permissions` V1AgentPermissionsConfig: AgentPermissionsConfig normalizes permission rules across agents.
            - `additional_directories` string[]: AdditionalDirectories lists extra working directories the agent may access. Claude Code: from permissions.additionalDirectories. Cursor: from CLI allowedPaths.
            - `allowed_commands` string[]: AllowedCommands lists shell command patterns that are auto-approved. For Claude Code these are permission rule strings (e.g. "Bash(git:*)").
            - `allowed_mcp_servers` string[]: AllowedMcpServers lists MCP server names permitted by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `allowed_tools` string[]: AllowedTools lists MCP tool names that are auto-approved. Populated primarily from Cursor configs; Claude Code uses rule strings instead.
            - `bypass_disabled` boolean: BypassDisabled indicates whether bypass-permissions mode is disabled. Populated from Claude Code only.
            - `default_mode` string: DefaultMode is the permission mode used when no explicit rule matches. Populated from Claude Code only (e.g. "default", "bypassPermissions").
            - `denied_commands` string[]: DeniedCommands lists shell command patterns that are blocked.
            - `denied_mcp_servers` string[]: DeniedMcpServers lists MCP server names blocked by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `denied_tools` string[]: DeniedTools lists MCP tool names that are blocked.
          - `sandbox` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
            - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
            - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
            - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
            - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
            - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
            - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
            - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
            - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
        - `repository` V1AgentConfigLevel: AgentConfigLevel captures the agent configuration at one scope level (repository, user, or enterprise).
          - `available_models` string[]: AvailableModels restricts which model IDs are selectable. Populated from Claude Code settings only.
          - `default_model` string: DefaultModel is the default model ID configured at this level. Populated from Claude Code settings only.
          - `env` object: Env holds environment variables configured at this level.
          - `environment_type` string: EnvironmentType is the remote environment type (e.g. "docker"). Populated from Cursor environment.json only.
          - `hooks` V1AgentHookConfig[]: Hooks lists the hook event bindings configured at this level.
            - `commands` string[]: Commands lists the shell commands registered for this event.
            - `event_name` string: EventName is the lifecycle hook event name (e.g. "PostToolUse").
          - `instruction_files` V1AgentInstructionFile[]: InstructionFiles lists rule/instruction files discovered at this level. Cursor: .mdc files from rules/ directories. Claude Code: reserved for future use.
            - `content_hash` string: ContentHash is the SHA-256 hex digest of the file content.
            - `name` string: Name is the base filename without extension (e.g. "security" from "security.mdc").
            - `path` string: Path is the absolute filesystem path to the instruction file.
          - `mcp_servers` V1AgentMCPServer[]: McpServers lists the MCP servers configured at this level.
            - `args` string[]: Args are the command-line arguments passed to the server process.
            - `command` string: Command is the executable used for stdio-transport servers.
            - `config_server_name` string: ConfigServerName is the user-authored mcp.json map key that named this server entry in the agent's configuration (e.g. "claude-endor-cli-tools", "postgres"). It is the stable identifier per-tool hooks can use to look the entry up in the cached SESSION_START snapshot — Claude's tool name shape "mcp__<server>__<tool>" carries this value, while Name carries the runtime program identity. Wrapped to distinguish "unset" from "".
            - `env` object: Env holds environment variables injected into the server process.
            - `from_plugin` boolean: FromPlugin marks a server contributed by an enabled agent plugin's manifest rather than by an mcp_servers entry a user wrote. Only the collector that walked the plugin registry can tell the two apart, and both inventory writers need the answer to agree, so it is stated here rather than inferred downstream from the "<plugin>/<server>" shape of config_server_name — a user-authored key may legitimately contain a slash ("@vendor/server"). Wrapped to distinguish "unset" (a collector predating this field) from "false".
            - `headers` object: Headers are additional HTTP headers sent with requests. Populated by collectors when available; Cursor's mcp.json has no headers field so this is empty for Cursor.
            - `name` string: Name is the canonical runtime identifier of the MCP server program — the value extracted from the command line (e.g. "endorctl" from "npx -y endorctl ai-tools mcp-server") or, for HTTP/SSE servers, the host slice of the URL. The backend uses this as the inventory document name so SESSION_START rows and per-tool rows (whose McpToolHook.server_name is derived the same way from the runtime URL/command) land on a single inventory document per logical server.
            - `transport` string: Transport is the MCP transport type: "stdio", "http", or "sse". Collectors must populate this; an empty value means the collector could not classify the server. Claude Code reads this from .mcp.json; Cursor derives it structurally from command/url since mcp.json has no transport field.
            - `url` string: URL is the endpoint for HTTP or SSE transport servers.
          - `permissions` V1AgentPermissionsConfig: AgentPermissionsConfig normalizes permission rules across agents.
            - `additional_directories` string[]: AdditionalDirectories lists extra working directories the agent may access. Claude Code: from permissions.additionalDirectories. Cursor: from CLI allowedPaths.
            - `allowed_commands` string[]: AllowedCommands lists shell command patterns that are auto-approved. For Claude Code these are permission rule strings (e.g. "Bash(git:*)").
            - `allowed_mcp_servers` string[]: AllowedMcpServers lists MCP server names permitted by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `allowed_tools` string[]: AllowedTools lists MCP tool names that are auto-approved. Populated primarily from Cursor configs; Claude Code uses rule strings instead.
            - `bypass_disabled` boolean: BypassDisabled indicates whether bypass-permissions mode is disabled. Populated from Claude Code only.
            - `default_mode` string: DefaultMode is the permission mode used when no explicit rule matches. Populated from Claude Code only (e.g. "default", "bypassPermissions").
            - `denied_commands` string[]: DeniedCommands lists shell command patterns that are blocked.
            - `denied_mcp_servers` string[]: DeniedMcpServers lists MCP server names blocked by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `denied_tools` string[]: DeniedTools lists MCP tool names that are blocked.
          - `sandbox` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
            - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
            - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
            - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
            - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
            - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
            - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
            - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
            - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
        - `resolved_sandbox_posture` 'SANDBOX_CONFIG_POSTURE_UNSPECIFIED' | 'SANDBOX_CONFIG_POSTURE_UNKNOWN' | 'SANDBOX_CONFIG_POSTURE_ENABLED' | 'SANDBOX_CONFIG_POSTURE_DISABLED': SandboxConfigPosture is the session-level sandbox posture derived from agent configuration. - SANDBOX_CONFIG_POSTURE_UNSPECIFIED: No posture was evaluated by this client. - SANDBOX_CONFIG_POSTURE_UNKNOWN: The client evaluated configuration but could not determine posture. - SANDBOX_CONFIG_POSTURE_ENABLED: Configuration indicates sandboxing is enabled for the session. - SANDBOX_CONFIG_POSTURE_DISABLED: Configuration indicates sandboxing is disabled for the session.
        - `user` V1AgentConfigLevel: AgentConfigLevel captures the agent configuration at one scope level (repository, user, or enterprise).
          - `available_models` string[]: AvailableModels restricts which model IDs are selectable. Populated from Claude Code settings only.
          - `default_model` string: DefaultModel is the default model ID configured at this level. Populated from Claude Code settings only.
          - `env` object: Env holds environment variables configured at this level.
          - `environment_type` string: EnvironmentType is the remote environment type (e.g. "docker"). Populated from Cursor environment.json only.
          - `hooks` V1AgentHookConfig[]: Hooks lists the hook event bindings configured at this level.
            - `commands` string[]: Commands lists the shell commands registered for this event.
            - `event_name` string: EventName is the lifecycle hook event name (e.g. "PostToolUse").
          - `instruction_files` V1AgentInstructionFile[]: InstructionFiles lists rule/instruction files discovered at this level. Cursor: .mdc files from rules/ directories. Claude Code: reserved for future use.
            - `content_hash` string: ContentHash is the SHA-256 hex digest of the file content.
            - `name` string: Name is the base filename without extension (e.g. "security" from "security.mdc").
            - `path` string: Path is the absolute filesystem path to the instruction file.
          - `mcp_servers` V1AgentMCPServer[]: McpServers lists the MCP servers configured at this level.
            - `args` string[]: Args are the command-line arguments passed to the server process.
            - `command` string: Command is the executable used for stdio-transport servers.
            - `config_server_name` string: ConfigServerName is the user-authored mcp.json map key that named this server entry in the agent's configuration (e.g. "claude-endor-cli-tools", "postgres"). It is the stable identifier per-tool hooks can use to look the entry up in the cached SESSION_START snapshot — Claude's tool name shape "mcp__<server>__<tool>" carries this value, while Name carries the runtime program identity. Wrapped to distinguish "unset" from "".
            - `env` object: Env holds environment variables injected into the server process.
            - `from_plugin` boolean: FromPlugin marks a server contributed by an enabled agent plugin's manifest rather than by an mcp_servers entry a user wrote. Only the collector that walked the plugin registry can tell the two apart, and both inventory writers need the answer to agree, so it is stated here rather than inferred downstream from the "<plugin>/<server>" shape of config_server_name — a user-authored key may legitimately contain a slash ("@vendor/server"). Wrapped to distinguish "unset" (a collector predating this field) from "false".
            - `headers` object: Headers are additional HTTP headers sent with requests. Populated by collectors when available; Cursor's mcp.json has no headers field so this is empty for Cursor.
            - `name` string: Name is the canonical runtime identifier of the MCP server program — the value extracted from the command line (e.g. "endorctl" from "npx -y endorctl ai-tools mcp-server") or, for HTTP/SSE servers, the host slice of the URL. The backend uses this as the inventory document name so SESSION_START rows and per-tool rows (whose McpToolHook.server_name is derived the same way from the runtime URL/command) land on a single inventory document per logical server.
            - `transport` string: Transport is the MCP transport type: "stdio", "http", or "sse". Collectors must populate this; an empty value means the collector could not classify the server. Claude Code reads this from .mcp.json; Cursor derives it structurally from command/url since mcp.json has no transport field.
            - `url` string: URL is the endpoint for HTTP or SSE transport servers.
          - `permissions` V1AgentPermissionsConfig: AgentPermissionsConfig normalizes permission rules across agents.
            - `additional_directories` string[]: AdditionalDirectories lists extra working directories the agent may access. Claude Code: from permissions.additionalDirectories. Cursor: from CLI allowedPaths.
            - `allowed_commands` string[]: AllowedCommands lists shell command patterns that are auto-approved. For Claude Code these are permission rule strings (e.g. "Bash(git:*)").
            - `allowed_mcp_servers` string[]: AllowedMcpServers lists MCP server names permitted by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `allowed_tools` string[]: AllowedTools lists MCP tool names that are auto-approved. Populated primarily from Cursor configs; Claude Code uses rule strings instead.
            - `bypass_disabled` boolean: BypassDisabled indicates whether bypass-permissions mode is disabled. Populated from Claude Code only.
            - `default_mode` string: DefaultMode is the permission mode used when no explicit rule matches. Populated from Claude Code only (e.g. "default", "bypassPermissions").
            - `denied_commands` string[]: DeniedCommands lists shell command patterns that are blocked.
            - `denied_mcp_servers` string[]: DeniedMcpServers lists MCP server names blocked by managed policy. Populated from Claude Code managed settings; empty for Cursor.
            - `denied_tools` string[]: DeniedTools lists MCP tool names that are blocked.
          - `sandbox` V1AgentSandboxConfig: AgentSandboxConfig normalizes sandbox network and filesystem rules across agents.
            - `allow_unsandboxed_commands` boolean: AllowUnsandboxedCommands allows the agent to escape the sandbox on demand. Wrapped to distinguish "unset" from "false".
            - `allowed_network_hosts` string[]: AllowedNetworkHosts lists hostnames/domains the agent may reach.
            - `blocked_network_hosts` string[]: BlockedNetworkHosts lists hostnames/domains the agent may not reach. Populated from Cursor configs only; Claude Code uses allowlist-only.
            - `enabled` boolean: Enabled indicates whether sandboxing is turned on. Wrapped to distinguish "unset" from "false".
            - `excluded_commands` string[]: ExcludedCommands lists commands that always run outside the sandbox.
            - `fail_if_unavailable` boolean: FailIfUnavailable causes the agent to exit when sandboxing is unavailable. Wrapped to distinguish "unset" from "false".
            - `readable_paths` string[]: ReadablePaths lists filesystem paths the agent may read from.
            - `writable_paths` string[]: WritablePaths lists filesystem paths the agent may write to.
      - `harness_sandbox` 'HARNESS_SANDBOX_UNSPECIFIED' | 'HARNESS_SANDBOX_NONE_DETECTED' | 'HARNESS_SANDBOX_CONTAINER_DIY' | 'HARNESS_SANDBOX_DEDICATED_TOOL' | 'HARNESS_SANDBOX_SANDBOX_RUNTIME' | 'HARNESS_SANDBOX_UNKNOWN': HarnessSandbox identifies sandboxing around the agent harness itself. - HARNESS_SANDBOX_UNSPECIFIED: Harness sandboxing was not evaluated. - HARNESS_SANDBOX_NONE_DETECTED: No harness sandbox was detected. - HARNESS_SANDBOX_CONTAINER_DIY: The harness appears to run inside a generic container. - HARNESS_SANDBOX_DEDICATED_TOOL: The harness is managed by a dedicated sandbox tool. - HARNESS_SANDBOX_SANDBOX_RUNTIME: The harness is managed by a sandbox runtime. - HARNESS_SANDBOX_UNKNOWN: Checked but could not be classified.
      - `harness_sandbox_detail` string: Additional harness sandbox classification detail.
      - `is_background_agent` boolean: Whether the session is a background agent.
      - `reason` string: Reason for the session. For SESSION_END: "completed", "aborted", "error"
      - `sandbox_config_posture` 'SANDBOX_CONFIG_POSTURE_UNSPECIFIED' | 'SANDBOX_CONFIG_POSTURE_UNKNOWN' | 'SANDBOX_CONFIG_POSTURE_ENABLED' | 'SANDBOX_CONFIG_POSTURE_DISABLED': SandboxConfigPosture is the session-level sandbox posture derived from agent configuration. - SANDBOX_CONFIG_POSTURE_UNSPECIFIED: No posture was evaluated by this client. - SANDBOX_CONFIG_POSTURE_UNKNOWN: The client evaluated configuration but could not determine posture. - SANDBOX_CONFIG_POSTURE_ENABLED: Configuration indicates sandboxing is enabled for the session. - SANDBOX_CONFIG_POSTURE_DISABLED: Configuration indicates sandboxing is disabled for the session.
      - `skills` V1DiscoveredSkill[]: Skills discovered in the workspace during session start.
        - `allowed_tools` string[]: Tools declared in SKILL.md frontmatter (allowed-tools).
        - `compatibility` string: Environment requirements from SKILL.md frontmatter (agentskills.io standard field).
        - `content` string: Base64-encoded SKILL.md content for backend scoring. Capped at 128 KB.
        - `content_hash` string: SHA-256 hash of the SKILL.md content.
        - `description` string: Human-readable description from SKILL.md frontmatter.
        - `file_count` integer: Number of files in the skill directory (including SKILL.md).
        - `license` string: License from SKILL.md frontmatter (agentskills.io standard field).
        - `name` string: Skill name from SKILL.md frontmatter or directory name fallback.
        - `path` string: Path to the SKILL.md file within the workspace or user home directory.
      - `source` string: Source of the session. "startup", "resume", "clear"
    - `session_id` string: Session identifier for the agent run.
    - `sub_session_id` string: Sub-session identifier for the agent run.
    - `tool_sandbox` 'TOOL_SANDBOX_UNSPECIFIED' | 'TOOL_SANDBOX_UNKNOWN' | 'TOOL_SANDBOX_IN_SANDBOX' | 'TOOL_SANDBOX_NO_SANDBOX' | 'TOOL_SANDBOX_BLOCKED' | 'TOOL_SANDBOX_NOT_APPLICABLE' | 'TOOL_SANDBOX_IN_HARNESS': ToolSandbox is the runtime sandbox state of a single tool-call execution. - TOOL_SANDBOX_UNSPECIFIED: No runtime sandbox state was evaluated. - TOOL_SANDBOX_UNKNOWN: The execution is sandbox-governed, but its runtime state is indeterminate. - TOOL_SANDBOX_IN_SANDBOX: The execution ran inside the agent's sandbox. - TOOL_SANDBOX_NO_SANDBOX: The execution was sandbox-governed but ran without a sandbox. - TOOL_SANDBOX_BLOCKED: A sandbox denied the execution. - TOOL_SANDBOX_NOT_APPLICABLE: The tool does not execute through a sandbox. - TOOL_SANDBOX_IN_HARNESS: A sandbox around the agent harness supplied the isolation.
    - `tool_sandbox_basis` 'TOOL_SANDBOX_BASIS_UNSPECIFIED' | 'TOOL_SANDBOX_BASIS_REPORTED_BEFORE_RUN' | 'TOOL_SANDBOX_BASIS_OBSERVED_AFTER_RUN' | 'TOOL_SANDBOX_BASIS_DENIED_BEFORE_RUN': ToolSandboxBasis identifies the sole record, if any, used to aggregate one shell call's sandbox result. Producers must set a nonzero basis on at most one record per call. DENIED_BEFORE_RUN takes precedence when multiple bases apply. - TOOL_SANDBOX_BASIS_UNSPECIFIED: This record is not selected as the call's sandbox result for aggregation. - TOOL_SANDBOX_BASIS_REPORTED_BEFORE_RUN: The agent reported intended sandbox state before execution, not an observed outcome. Use only if no later OBSERVED_AFTER_RUN or DENIED_BEFORE_RUN record will be emitted for the call. - TOOL_SANDBOX_BASIS_OBSERVED_AFTER_RUN: The client observed the sandbox outcome after execution. - TOOL_SANDBOX_BASIS_DENIED_BEFORE_RUN: An enforced policy denied the call before execution.
    - `user` string: User name if available.
    - `user_kind` 'USER_KIND_UNSPECIFIED' | 'USER_KIND_EMAIL' | 'USER_KIND_GITHUB_LOGIN' | 'USER_KIND_OS_LOGIN' | 'USER_KIND_ASSERTED': UserKind says which kind of identifier the user field carries. Agents name their users differently, so the value alone cannot be classified: a bare login is indistinguishable from an OS login of the same spelling. A consumer that joins identities must read this before treating a user as an account. - USER_KIND_UNSPECIFIED: No kind was reported, which is what events from builds older than this field look like. Treat the user field as unclassified rather than as any particular kind. - USER_KIND_EMAIL: Account email the agent itself reports. - USER_KIND_GITHUB_LOGIN: GitHub account handle, which is all GitHub Copilot records locally. - USER_KIND_OS_LOGIN: No agent account was resolved, so the user field repeats os_user. Never join on this as an account: one shared machine would merge every developer who used it into a single identity. - USER_KIND_ASSERTED: Identifier supplied by the operator through the environment rather than read from the agent, so its shape is whatever the fleet configured.
  - `tenant_meta` V1TenantMeta: Tenant related data for the tenant containing the resource.
    - `namespace` string, required: Namespaces are a way to organize organizational units into virtual groupings of resources. Namespaces must be a fully qualified name, for example, the child namespace of namespace "endor.prod" called "app" is called "endor.prod.app".
  - `uuid` string: The UUID of an AgentHookEvent.

## Other responses

- `default`: An unexpected error response.

## Changes

- **2026-11-03** `4acd9fe15140`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/endorlabs/apis/endor-labs-rest-api-reference/changes/v1/namespaces/:tenant_meta.namespace/agent-hook-events/post.md)

---

[API](https://skmtc.dev/endorlabs/apis/endor-labs-rest-api-reference.md) - [All operations](https://skmtc.dev/endorlabs/apis/endor-labs-rest-api-reference/llms.txt) - [OpenAPI document](https://skmtc.dev/endorlabs/apis/endor-labs-rest-api-reference/revisions/4acd9fe15140?raw)
