types

package
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package types is the single source of truth for Harbor Protocol wire types (CLAUDE.md §8). Every Protocol message struct lives here; other packages import these types, and nothing else defines a Protocol message struct. The Phase 58 lint formalises this — Phase 54 lays the foundation so that lint is a no-op formalisation, not a cleanup.

What Phase 54 ships

Phase 54 ships the Protocol task control surface's wire types: the flat IdentityScope every request carries, the StartRequest / StartResponse pair, and the ControlRequest / ControlResponse pair the nine steering-control methods share. The wire shapes are deliberately flat (string identity fields + a payload map) — a Protocol type that re-exported an internal runtime Go struct would be the RFC §5.1 reject-on-sight smell ("a Protocol method that maps 1:1 to an internal Go function signature"). The runtime-facing translation lives in the protocol package's ControlSurface, not in these types.

Versioning

ProtocolVersion is pinned here. Bumping it is an RFC change (RFC §5.3, CLAUDE.md §8) — the Protocol surface is versioned independently of the Runtime implementation so third-party Consoles are not whipsawed by a Runtime refactor.

Versioning discipline (Phase 59)

Phase 59 turns the version *pin* into a versioning *discipline*:

  • Version + ParseVersion + Compatible — the pinned string parsed into a comparable Major/Minor/Patch value, so a client detects version skew mechanically (same-major ⇒ Compatible) instead of string-comparing. CurrentVersion is the parsed form of ProtocolVersion; the two cannot drift.
  • Deprecation + Deprecations() — the settled structured note format for a breaking Protocol change's removal window (RFC §5.3: "Breaking changes require a deprecation window"), plus the single-home registry of active deprecations. The registry is empty at 0.1.0 — a 0.1.0 Protocol that just shipped has nothing to deprecate — but the format and its home exist so the first real deprecation lands structured, not as a free-text comment.
  • Capability + Capabilities() + VersionHandshake — the capability-negotiation shape. A Protocol client asks the Runtime which surfaces are live and gets a structured VersionHandshake (the version + the advertised capability set) rather than discovering a missing surface by a 404. V1 advertises exactly the surfaces that have shipped — CapTaskControl, the Phase 54 surface; later Protocol-surface phases add their constant here.

None of this bumps the version: Phase 59 ships the *mechanism* for living with versions, not a new version. It is transport-agnostic — a Phase 60 SSE+REST adapter or a Phase 63 `harbor version` subcommand consumes these values; Phase 59 binds to no transport.

Index

Constants

View Source
const (
	// DefaultArtifactsLimit is the page size applied when a request omits
	// Limit.
	DefaultArtifactsLimit = 100
	// MaxArtifactsLimit is the hard ceiling on an artifacts.list page.
	MaxArtifactsLimit = 1000
)

Default + maximum page bounds for artifacts.list.

View Source
const (
	// PresignExpiryMin is the floor on a presigned-URL expiry window.
	PresignExpiryMin = time.Minute
	// PresignExpiryMax is the ceiling on a presigned-URL expiry window
	// (7 days — S3's documented limit).
	PresignExpiryMax = 7 * 24 * time.Hour
	// DefaultPresignExpiry is the expiry applied when a request omits it.
	DefaultPresignExpiry = 15 * time.Minute
)

Presigned-URL expiry bounds for artifacts.get_ref, matching the internal/artifacts.Presigner interface contract (S3's documented limit).

View Source
const (
	// DefaultFlowListPageSize is the page size applied when a
	// `flows.list` / `flows.runs.list` request omits PageSize.
	DefaultFlowListPageSize = 50
	// MaxFlowListPageSize is the upper bound on a Flows-page request's
	// PageSize. A request above this is rejected with CodeInvalidRequest.
	MaxFlowListPageSize = 200
)

Flows-page pagination bounds. They mirror the `pause.list` / `search.*` pagination contract so the Console-side pagination component is shared across pages, not re-implemented per-method. A client that omits Page / PageSize gets the documented defaults; a request above the max gets a 400 (CodeInvalidRequest) — never a silent clamp.

View Source
const (
	DefaultMemoryListPageSize = 50
	MaxMemoryListPageSize     = 200
)

Memory-page pagination bounds, shared by the `memory.list` method per the Phase 73j plan acceptance criteria. The values mirror the Phase 72c `search.*` / Phase 72e `pause.list` pagination contracts so a future Console-side pagination component is shared across pages, not re-implemented per-method. A client that omits Page / PageSize gets the documented defaults; a request above the max — or negative — gets a 400 (CodeInvalidRequest), never a silent clamp.

View Source
const (
	DefaultPauseListPageSize = 50
	MaxPauseListPageSize     = 200
)

Pause-snapshot pagination bounds, shared by the `pause.list` method per the Phase 72e plan acceptance criteria. The values mirror the Phase 72c `search.*` pagination contract (DefaultSearchPageSize / MaxSearchPageSize) so a future Console-side pagination component is shared across pages, not re-implemented per-method. A client that omits Page / PageSize gets the documented defaults; a request above the max gets a 400 (CodeInvalidRequest) — never a silent clamp, since a silent clamp would defeat the per-row identity boundary the integration test asserts.

View Source
const (
	// HealthStatusReady — the subsystem is registered and healthy.
	HealthStatusReady = "ready"
	// HealthStatusDegraded — the subsystem is registered and partially
	// functional.
	HealthStatusDegraded = "degraded"
	// HealthStatusUnavailable — the subsystem is not registered, or is
	// registered but non-functional.
	HealthStatusUnavailable = "unavailable"
)

The canonical SubsystemHealth.Status values. The set is closed: a posture seam reports one of exactly these three.

View Source
const (
	DefaultSearchPageSize = 20
	MaxSearchPageSize     = 200
)

Default + maximum pagination bounds, shared by every `search.*` method per the Phase 72c plan acceptance criteria. The defaults are the wire contract — a client that omits Page / PageSize gets the documented defaults; a client requesting more than the max gets a 400.

View Source
const (
	// DefaultSessionListLimit is the page size applied when a
	// SessionsListRequest omits Limit (or passes a non-positive value).
	DefaultSessionListLimit = 50
	// MaxSessionListLimit bounds the page size a client may request.
	MaxSessionListLimit = 200
	// MaxSessionInterventionSummaries caps the RecentInterventions slice
	// the right-rail Session Summary projection carries.
	MaxSessionInterventionSummaries = 5
	// MaxSessionArtifactSummaries caps the RecentArtifacts slice the
	// right-rail Session Summary projection carries.
	MaxSessionArtifactSummaries = 5
)

Sessions-page pagination bounds for `sessions.list`. Mirrors the tools.list / pause.list / search.* contract so the shared Console pagination component is reused, not re-implemented per page. A request above MaxSessionListLimit gets a 400 (CodeInvalidRequest) — never a silent clamp.

View Source
const (
	// DefaultTaskListPageSize is the page size applied when a
	// TaskListRequest omits PageSize (or passes a non-positive value).
	DefaultTaskListPageSize = 50
	// MaxTaskListPageSize bounds the page size a client may request.
	MaxTaskListPageSize = 200
)

Tasks-page pagination bounds for `tasks.list`. Mirrors the tools.list / pause.list / search.* contract so a future shared Console-side pagination component is reused, not re-implemented per page. A request above MaxTaskListPageSize gets a 400 (CodeInvalidRequest) — never a silent clamp.

View Source
const (
	// DefaultToolListPageSize is the page size applied when a
	// ToolListRequest omits PageSize (or passes a non-positive value).
	DefaultToolListPageSize = 50
	// MaxToolListPageSize bounds the page size a client may request.
	MaxToolListPageSize = 200
)

Tools-page pagination bounds for `tools.list`. Mirrors the pause.list / search.* contract so a future Console-side pagination component is shared, not re-implemented per page. A request above MaxToolListPageSize gets a 400 (CodeInvalidRequest) — never a silent clamp.

View Source
const DefaultAgentListPageSize = 50

DefaultAgentListPageSize is the page size `agents.list` applies when the request omits PageSize (or sends 0). Agents are slow-moving catalog data; a 50-row page is comfortable for the cards grid.

View Source
const MaxAgentListPageSize = 200

MaxAgentListPageSize bounds the `agents.list` page size. A request above this ceiling is rejected with CodeInvalidRequest rather than silently clamped (CLAUDE.md §13 — fail loudly).

View Source
const ProtocolVersion = "0.1.0"

ProtocolVersion is the pinned Harbor Protocol version. Bumping this constant is an RFC change (RFC §5.3): the Protocol surface is versioned independently of the Runtime, and a breaking change requires a deprecation window so third-party Consoles are not whipsawed.

V1 ships 0.1.0 — the task control surface (Phase 54) is the first Protocol surface to land; the streaming-events / state-snapshot / topology / artifacts / traces / metrics surfaces (RFC §5.2) extend it in later phases without bumping the major while V1 is in flight.

Variables

View Source
var CurrentVersion = mustParseVersion(ProtocolVersion)

CurrentVersion is the parsed form of the ProtocolVersion constant. It is derived from ProtocolVersion at package-init, so the two can never drift — TestCurrentVersion_MatchesProtocolVersion pins CurrentVersion.String() == ProtocolVersion. Callers that need to *reason* about the version (skew detection, ordering) use CurrentVersion; the ProtocolVersion string stays the RFC-change trip-wire.

View Source
var ErrInvalidDeprecation = stderrors.New("types: invalid Protocol deprecation")

ErrInvalidDeprecation is returned (wrapped) by Deprecation.Validate when a Deprecation is malformed.

View Source
var ErrInvalidVersion = stderrors.New("types: invalid Protocol version")

ErrInvalidVersion is returned (wrapped) by ParseVersion when the input is not a well-formed `MAJOR.MINOR.PATCH` triple of non-negative integers. Parsing fails loudly — there is no silent zero-Version degradation path (CLAUDE.md §5 "fail loudly").

View Source
var HighCardinalityLabelKeys = []string{"run_id", "trace_id", "span_id"}

HighCardinalityLabelKeys is the closed set of label keys that must NEVER appear on a metric crossing the Protocol boundary — they are unbounded per-run identifiers and would explode the metric series cardinality. The Phase 56 telemetry cardinality firewall gates these on the SDK side; this set lets the wire boundary re-check (D-132 / Wave 13 NIT cleanup, mirroring the Phase 56 label-lint pattern).

Functions

func IsValidAgentStatus

func IsValidAgentStatus(s AgentStatus) bool

IsValidAgentStatus reports whether s is one of the canonical AgentStatus values.

func IsValidArtifactSource

func IsValidArtifactSource(s ArtifactSource) bool

IsValidArtifactSource reports whether s is one of the four canonical artifact sources. The artifacts handler uses this to fail loud on an unknown source value rather than silently dropping the filter.

func IsValidCapability

func IsValidCapability(c Capability) bool

IsValidCapability reports whether c is one of the canonical Protocol capabilities. O(1).

func IsValidFlowNodeKind

func IsValidFlowNodeKind(k FlowNodeKind) bool

IsValidFlowNodeKind reports whether k is one of the four canonical flow-node kinds.

func IsValidFlowRunStatus

func IsValidFlowRunStatus(s FlowRunStatus) bool

IsValidFlowRunStatus reports whether s is one of the four canonical flow-run statuses.

func IsValidMemoryDriver

func IsValidMemoryDriver(d MemoryDriverName) bool

IsValidMemoryDriver reports whether d is one of the three V1 memory-driver names.

func IsValidMemoryScope

func IsValidMemoryScope(s MemoryScope) bool

IsValidMemoryScope reports whether s is one of the three canonical memory-record scopes.

func IsValidMemoryStrategy

func IsValidMemoryStrategy(s MemoryStrategyName) bool

IsValidMemoryStrategy reports whether s is one of the three V1 memory-strategy names.

func IsValidPauseSnapshotState

func IsValidPauseSnapshotState(s PauseSnapshotState) bool

IsValidPauseSnapshotState reports whether s is one of the two canonical pause-snapshot states.

func IsValidSearchIndex

func IsValidSearchIndex(i SearchIndex) bool

IsValidSearchIndex reports whether i is one of the four canonical runtime-side indexes.

func IsValidSessionSort

func IsValidSessionSort(s SessionSort) bool

IsValidSessionSort reports whether s is one of the four canonical sort orders. An empty value resolves to SessionSortStartedDesc.

func IsValidSessionStatus

func IsValidSessionStatus(s SessionStatus) bool

IsValidSessionStatus reports whether s is one of the four canonical session statuses.

func IsValidTaskKind

func IsValidTaskKind(k TaskKind) bool

IsValidTaskKind reports whether k is one of the two canonical task kinds.

func IsValidTaskStatus

func IsValidTaskStatus(s TaskStatus) bool

IsValidTaskStatus reports whether s is one of the six canonical task statuses. `tasks.list` rejects a filter naming any other value with CodeInvalidRequest.

func IsValidToolApprovalPolicy

func IsValidToolApprovalPolicy(p ToolApprovalPolicy) bool

IsValidToolApprovalPolicy reports whether p is one of the three canonical approval policies. `tools.set_approval_policy` rejects any other value with CodeInvalidRequest.

func IsValidToolMetricsWindow

func IsValidToolMetricsWindow(w ToolMetricsWindow) bool

IsValidToolMetricsWindow reports whether w is one of the three canonical windows.

func IsValidToolOAuthStatus

func IsValidToolOAuthStatus(s ToolOAuthStatus) bool

IsValidToolOAuthStatus reports whether s is one of the canonical OAuth statuses.

func IsValidToolStatus

func IsValidToolStatus(s ToolStatus) bool

IsValidToolStatus reports whether s is one of the canonical health statuses.

func IsValidToolTransport

func IsValidToolTransport(t ToolTransport) bool

IsValidToolTransport reports whether t is one of the canonical tool transports.

Types

type Agent

type Agent struct {
	// ID is the agent_id — the stable registration identity (D-059).
	ID string `json:"id"`
	// Name is the operator-facing display name.
	Name string `json:"name"`
	// Description is the operator-facing description.
	Description string `json:"description"`
	// Incarnation bumps on every process start (D-059).
	Incarnation int64 `json:"incarnation"`
	// VersionHash is the SHA-256 over canonical JSON of AgentConfig
	// (D-068). Empty for a HostingRemote agent.
	VersionHash string `json:"version_hash"`
	// Owner is the registration key of the agent — the operator-stable
	// logical-agent key the admin registered it under.
	Owner string `json:"owner"`
	// Status is the lifecycle status pill.
	Status AgentStatus `json:"status"`
	// Health is the operational-health badge.
	Health AgentHealth `json:"health"`
	// Hosting discriminates locally-hosted vs connect-to-remote.
	Hosting AgentHosting `json:"hosting"`
	// PlannerType is the configured planner ("react" / "deterministic"
	// / future). Empty when not declared in AgentConfig.
	PlannerType string `json:"planner_type"`
	// Model is the configured model id. Empty when not declared.
	Model string `json:"model"`
	// ToolsCount is the number of tool bindings on the agent.
	ToolsCount int `json:"tools_count"`
	// MCPCount is the number of MCP-transport tool bindings.
	MCPCount int `json:"mcp_count"`
	// RegisteredAt is the RFC3339 timestamp of the first registration.
	RegisteredAt string `json:"registered_at"`
	// UpdatedAt is the RFC3339 timestamp of the most recent mutation.
	UpdatedAt string `json:"updated_at"`
}

Agent is the catalog-row projection of one registered agent — the shape `agents.list` returns per row and `agents.get` nests in its response. ID is a registration identity (D-059), NOT an isolation principal.

type AgentAggregates

type AgentAggregates struct {
	// Total is the count of agents in the filtered view.
	Total int64 `json:"total"`
	// Active is the count of AgentStatusActive agents in the view.
	Active int64 `json:"active"`
	// Paused is the count of AgentStatusPaused agents in the view.
	Paused int64 `json:"paused"`
	// Drained is the count of AgentStatusDrained agents in the view.
	Drained int64 `json:"drained"`
}

AgentAggregates is the four catalog counters over the filtered view.

type AgentConfig

type AgentConfig struct {
	// PlannerType is the configured planner ("react" / "deterministic").
	PlannerType string `json:"planner_type"`
	// PlannerConfig is the planner's key/value configuration set
	// (MaxSteps, repair policy, etc.).
	PlannerConfig map[string]string `json:"planner_config,omitempty"`
	// Model is the configured model id.
	Model string `json:"model"`
	// ModelPolicy is the model-selection / model-policy key/value set.
	ModelPolicy map[string]string `json:"model_policy,omitempty"`
	// MaxSteps is the planner's max-steps ceiling (0 ⇒ not declared).
	MaxSteps int `json:"max_steps"`
}

AgentConfig is the Protocol projection of the agent's configuration — planner config + model + max-steps + cost ceilings. It mirrors the registry's AgentConfig but is the flat wire shape, not the internal type (RFC §5.1).

type AgentControlRequest added in v1.3.0

type AgentControlRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the agent_id to control.
	ID string `json:"id"`
	// Reason is the operator-supplied control reason (redacted, audited).
	Reason string `json:"reason,omitempty"`
}

AgentControlRequest is the shared request body for the five fleet- control verbs (`agents.pause` / `agents.drain` / `agents.restart` / `agents.force_stop` / `agents.deregister`) — Phase 108l / D-184. Every control verb mutates registry state and requires the elevated `auth.ScopeAdmin` control claim (D-066). `Reason` is operator-supplied free text the registry redacts through `audit.Redactor` before it reaches the `agent.*` event; `agents.deregister` ignores it.

type AgentControlResponse added in v1.3.0

type AgentControlResponse struct {
	// AgentID echoes the controlled agent_id.
	AgentID string `json:"agent_id"`
	// Command is the applied control verb: pause / drain / restart /
	// force_stop / deregister.
	Command string `json:"command"`
	// Status is the agent's post-control lifecycle status.
	Status AgentStatus `json:"status"`
}

AgentControlResponse is the shared reply for the five fleet-control verbs. Status is the ACTUAL post-control status the registry re-read after applying the command — NOT the verb's nominal intent (no fabrication; CLAUDE.md §13). The V1 registry's Health enum has no "paused" state, and `pause` / `restart` do not transition Health, so:

  • pause → the agent's prior status, unchanged (active for a healthy agent — there is no "paused" status);
  • restart → the agent's prior status, unchanged (restart bumps the incarnation but does NOT clear a prior drain/stop Health, so a restarted-after-drain agent reads `drained`, not `active`);
  • drain → drained;
  • force_stop → force_stopped;
  • deregister → deregistered (the record is gone; not re-read).

In every case the registry emitted the matching `agent.*` event, which is the authoritative observation surface the Console also subscribes to.

type AgentCostCeiling

type AgentCostCeiling struct {
	// Tier is the identity tier the ceiling applies to.
	Tier string `json:"tier"`
	// LimitUSD is the configured spend ceiling in USD.
	LimitUSD float64 `json:"limit_usd"`
	// SpendUSD is the current accumulated spend in USD.
	SpendUSD float64 `json:"spend_usd"`
}

AgentCostCeiling is one per-identity-tier cost ceiling (Phase 36a).

type AgentFilter

type AgentFilter struct {
	// Status narrows to agents whose Status is in the set; empty = all.
	Status []AgentStatus `json:"status,omitempty"`
	// PlannerType narrows to agents whose PlannerType is in the set;
	// empty = all.
	PlannerType []string `json:"planner_type,omitempty"`
	// Search is a free-text query over Name + Description (case-fold).
	Search string `json:"search,omitempty"`
}

AgentFilter is the server-enforced facet filter on `agents.list`.

type AgentGetRequest

type AgentGetRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the agent_id to fetch.
	ID string `json:"id"`
}

AgentGetRequest is the `agents.get` request body.

type AgentGetResponse

type AgentGetResponse struct {
	// Agent is the catalog-row projection.
	Agent Agent `json:"agent"`
	// Config is the agent's configuration projection.
	Config AgentConfig `json:"config"`
	// AgentCardRef references the canonical A2A AgentCard for a
	// HostingRemote agent. Empty for a HostingLocal agent.
	AgentCardRef string `json:"agent_card_ref,omitempty"`
}

AgentGetResponse is the `agents.get` reply — the full projection of one agent.

type AgentGovernance

type AgentGovernance struct {
	// Ceilings is the per-identity-tier cost ceilings + spend.
	Ceilings []AgentCostCeiling `json:"ceilings"`
	// RateLimits is the per-identity-tier rate-limit posture.
	RateLimits []AgentRateLimit `json:"rate_limits"`
}

AgentGovernance is the agent's governance posture — per-identity-tier ceilings + spend + rate-limit posture.

type AgentGovernanceRequest

type AgentGovernanceRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the agent_id whose governance posture to fetch.
	ID string `json:"id"`
}

AgentGovernanceRequest is the `agents.governance` request body.

type AgentGovernanceResponse

type AgentGovernanceResponse struct {
	// AgentID echoes the requested agent_id.
	AgentID string `json:"agent_id"`
	// Governance is the agent's governance posture.
	Governance AgentGovernance `json:"governance"`
}

AgentGovernanceResponse is the `agents.governance` reply.

type AgentHealth

type AgentHealth string

AgentHealth is the operational-health enum the Agents page renders as a health badge. It mirrors the registry's Health enum projected onto operator-facing labels.

const (
	// AgentHealthHealthy — the agent reported itself operational.
	AgentHealthHealthy AgentHealth = "Healthy"
	// AgentHealthDegraded — the agent reported impaired operation.
	AgentHealthDegraded AgentHealth = "Degraded"
	// AgentHealthPaused — a Pause control verb is in effect.
	AgentHealthPaused AgentHealth = "Paused"
	// AgentHealthDrained — a Drain control verb is in effect.
	AgentHealthDrained AgentHealth = "Drained"
	// AgentHealthForceStopped — a ForceStop control verb is in effect.
	AgentHealthForceStopped AgentHealth = "Force-Stopped"
	// AgentHealthUnknown — no health has been reported yet.
	AgentHealthUnknown AgentHealth = "Unknown"
)

type AgentHosting

type AgentHosting string

AgentHosting discriminates a locally-hosted agent from a connect-to-remote agent (D-060).

const (
	// AgentHostingLocal — the agent is hosted by this runtime instance.
	AgentHostingLocal AgentHosting = "local"
	// AgentHostingRemote — the agent runs elsewhere; the local agent_id
	// is a handle and the canonical identity is the remote A2A AgentCard.
	AgentHostingRemote AgentHosting = "remote"
)

type AgentListRequest

type AgentListRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// Filter is the optional facet filter.
	Filter AgentFilter `json:"filter,omitempty"`
	// Page is the 1-based page index. <= 0 is treated as page 1.
	Page int `json:"page,omitempty"`
	// PageSize is the rows-per-page. 0 ⇒ DefaultAgentListPageSize.
	PageSize int `json:"page_size,omitempty"`
}

AgentListRequest is the `agents.list` request body.

type AgentListResponse

type AgentListResponse struct {
	// Agents is the page of catalog rows.
	Agents []Agent `json:"agents"`
	// Page is the 1-based page index this response covers.
	Page int `json:"page"`
	// PageSize is the rows-per-page applied.
	PageSize int `json:"page_size"`
	// PageCount is the total number of pages in the filtered view.
	PageCount int `json:"page_count"`
	// TotalRows is the total row count in the filtered view.
	TotalRows int64 `json:"total_rows"`
	// Aggregates is the four counters over the filtered view.
	Aggregates AgentAggregates `json:"aggregates"`
}

AgentListResponse is the `agents.list` reply.

type AgentMemoryBinding

type AgentMemoryBinding struct {
	// StrategyID is the memory strategy id (Phase 24).
	StrategyID string `json:"strategy_id"`
	// TTLSeconds is the configured memory TTL in seconds (0 ⇒ no TTL).
	TTLSeconds int64 `json:"ttl_seconds"`
	// Scope is the memory scope: "session" / "user" / "tenant".
	Scope string `json:"scope"`
}

AgentMemoryBinding is the agent's configured memory strategy.

type AgentMemoryRequest

type AgentMemoryRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the agent_id whose memory binding to fetch.
	ID string `json:"id"`
}

AgentMemoryRequest is the `agents.memory` request body.

type AgentMemoryResponse

type AgentMemoryResponse struct {
	// AgentID echoes the requested agent_id.
	AgentID string `json:"agent_id"`
	// Binding is the agent's memory-strategy binding.
	Binding AgentMemoryBinding `json:"binding"`
}

AgentMemoryResponse is the `agents.memory` reply.

type AgentMetrics

type AgentMetrics struct {
	// ActiveAgents is the count of AgentStatusActive agents in scope.
	ActiveAgents int64 `json:"active_agents"`
	// RunningTasks is the count of in-flight tasks across those agents.
	RunningTasks int64 `json:"running_tasks"`
	// TotalCostUSD is the total accumulated spend across those agents.
	TotalCostUSD float64 `json:"total_cost_usd"`
	// TotalTokens is the total token consumption across those agents.
	TotalTokens int64 `json:"total_tokens"`
}

AgentMetrics is the registry-wide rollup the Agents page hero shows — the four "Active Agents / Running Tasks / Total Cost / Total Tokens" numbers, computed over the operator's identity scope.

type AgentMetricsRequest

type AgentMetricsRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
}

AgentMetricsRequest is the `agents.metrics` request body.

type AgentMetricsResponse

type AgentMetricsResponse struct {
	// Metrics is the registry-wide rollup.
	Metrics AgentMetrics `json:"metrics"`
}

AgentMetricsResponse is the `agents.metrics` reply.

type AgentPermissions

type AgentPermissions struct {
	// Model is the permission model: "implicit" (V1 default) or
	// "explicit" (post-V1).
	Model string `json:"model"`
	// Description is the operator-facing explanation of the model.
	Description string `json:"description"`
	// AllowedPrincipals is the explicit ACL when Model is "explicit";
	// empty for the implicit model.
	AllowedPrincipals []string `json:"allowed_principals,omitempty"`
}

AgentPermissions is the agent's permission model. V1 default is implicit ("every authenticated user in the tenant can invoke this agent"); an explicit ACL surface is post-V1 (page-agents.md §10).

type AgentPermissionsRequest

type AgentPermissionsRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the agent_id whose permission model to fetch.
	ID string `json:"id"`
}

AgentPermissionsRequest is the `agents.permissions` request body.

type AgentPermissionsResponse

type AgentPermissionsResponse struct {
	// AgentID echoes the requested agent_id.
	AgentID string `json:"agent_id"`
	// Permissions is the agent's permission model.
	Permissions AgentPermissions `json:"permissions"`
}

AgentPermissionsResponse is the `agents.permissions` reply.

type AgentRateLimit

type AgentRateLimit struct {
	// Tier is the identity tier the rate limit applies to.
	Tier string `json:"tier"`
	// RequestsPerMinute is the configured per-minute request ceiling.
	RequestsPerMinute int64 `json:"requests_per_minute"`
	// MaxTokens is the configured per-request MaxTokens ceiling.
	MaxTokens int64 `json:"max_tokens"`
}

AgentRateLimit is one per-identity-tier rate-limit posture (Phase 36b).

type AgentSkillBinding

type AgentSkillBinding struct {
	// SkillID is the catalog key of the attached skill.
	SkillID string `json:"skill_id"`
	// Name is the operator-facing skill name.
	Name string `json:"name"`
	// Generated reports whether the skill was generated in-runtime
	// (Phase 41) rather than imported (Phase 38).
	Generated bool `json:"generated"`
}

AgentSkillBinding is one skill attached to an agent (Phase 38 + Phase 41 generated skills).

type AgentSkillsRequest

type AgentSkillsRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the agent_id whose attached skills to list.
	ID string `json:"id"`
}

AgentSkillsRequest is the `agents.skills` request body.

type AgentSkillsResponse

type AgentSkillsResponse struct {
	// AgentID echoes the requested agent_id.
	AgentID string `json:"agent_id"`
	// Skills is the agent's attached skills.
	Skills []AgentSkillBinding `json:"skills"`
}

AgentSkillsResponse is the `agents.skills` reply.

type AgentStatus

type AgentStatus string

AgentStatus is the lifecycle-status enum the Agents page renders as a status pill. It mirrors the registry's control-verb outcomes.

const (
	// AgentStatusActive — the agent is registered and accepting work.
	AgentStatusActive AgentStatus = "active"
	// AgentStatusPaused — a registry.Pause control verb is in effect.
	AgentStatusPaused AgentStatus = "paused"
	// AgentStatusDrained — a registry.Drain control verb is in effect.
	AgentStatusDrained AgentStatus = "drained"
	// AgentStatusForceStopped — a registry.ForceStop verb is in effect.
	AgentStatusForceStopped AgentStatus = "force_stopped"
	// AgentStatusDeregistered — the agent was removed from the registry.
	AgentStatusDeregistered AgentStatus = "deregistered"
)

type AgentToolBinding

type AgentToolBinding struct {
	// ToolID is the catalog key of the bound tool.
	ToolID string `json:"tool_id"`
	// ToolName is the operator-facing tool name.
	ToolName string `json:"tool_name"`
	// Transport is the tool's transport ("in-proc" / "HTTP" / "MCP" /
	// "A2A" / "flow").
	Transport string `json:"transport"`
	// AuthStatus is the per-binding OAuth status: "no_auth" / "headers"
	// / "oauth_user_bound" / "oauth_agent_bound" / "oauth_expired".
	AuthStatus string `json:"auth_status"`
	// BindingScope is the OAuth binding scope (auth.BindingScope per
	// D-083): "user" / "agent". Empty for a non-OAuth binding.
	BindingScope string `json:"binding_scope,omitempty"`
}

AgentToolBinding is one tool binding on an agent — a tool + the per-binding OAuth status (D-083).

type AgentToolsRequest

type AgentToolsRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the agent_id whose tool bindings to list.
	ID string `json:"id"`
}

AgentToolsRequest is the `agents.tools` request body.

type AgentToolsResponse

type AgentToolsResponse struct {
	// AgentID echoes the requested agent_id.
	AgentID string `json:"agent_id"`
	// Bindings is the agent's tool bindings.
	Bindings []AgentToolBinding `json:"bindings"`
}

AgentToolsResponse is the `agents.tools` reply.

type ArtifactRef

type ArtifactRef struct {
	// ID is the content-addressed identifier
	// (`{namespace}_{sha256[:12]}`).
	ID string `json:"id"`
	// MimeType is the IANA media type, when known.
	MimeType string `json:"mime_type,omitempty"`
	// SizeBytes is the length of the referenced bytes.
	SizeBytes int64 `json:"size_bytes"`
	// Filename is metadata only — never used for path construction.
	Filename string `json:"filename,omitempty"`
	// SHA256 is the full hex digest of the referenced bytes.
	SHA256 string `json:"sha256,omitempty"`
	// Namespace is the logical bucket the artifact lives in.
	Namespace string `json:"namespace,omitempty"`
	// Scope is the artifact's owning identity scope.
	Scope ArtifactScope `json:"scope"`
}

ArtifactRef is the flat Protocol projection of the storage-side internal/artifacts.ArtifactRef. It carries the catalog-rendering metadata a Console row needs — never the artifact bytes (D-026).

type ArtifactRefSummary

type ArtifactRefSummary struct {
	// Filename is the artifact's display filename.
	Filename string `json:"filename"`
	// MIME is the artifact's content type.
	MIME string `json:"mime"`
	// SizeBytes is the artifact's byte size.
	SizeBytes int64 `json:"size_bytes"`
	// CreatedAt is when the artifact was produced.
	CreatedAt time.Time `json:"created_at"`
}

ArtifactRefSummary is one entry in the right-rail Session Summary's Recent Artifacts card. Capped at MaxSessionArtifactSummaries. It carries metadata only — never inline bytes (D-026).

type ArtifactRow

type ArtifactRow struct {
	// Ref is the canonical artifact reference.
	Ref ArtifactRef `json:"ref"`
	// Tags is the chip list assigned by the producing planner / tool.
	// Sourced from the storage-side `Source["tags"]` projection — never
	// promoted onto the storage ArtifactRef shape (D-120 open-question
	// resolution: project on the Protocol row, not the storage struct).
	Tags []string `json:"tags,omitempty"`
	// Source is the producer of the artifact — one of the four canonical
	// ArtifactSource values.
	Source ArtifactSource `json:"source,omitempty"`
	// Driver is the artifact store driver that holds this artifact —
	// "inmem" | "fs" | "sqlite" | "postgres" | "s3".
	Driver string `json:"driver,omitempty"`
	// CreatedAt is the artifact's put timestamp.
	CreatedAt time.Time `json:"created_at,omitempty"`
}

ArtifactRow is the artifacts.list row shape. It wraps the canonical ArtifactRef with the catalog-only fields the Console table renders — Tags, the storage Driver name, and the creation timestamp. ArtifactRow is deliberately distinct from ArtifactRef so the Protocol's wire surface stays independent of the storage shape.

type ArtifactScope

type ArtifactScope struct {
	// Tenant / User / Session are the mandatory isolation triple. An
	// empty component fails put / get_ref closed at the Protocol edge.
	Tenant  string `json:"tenant"`
	User    string `json:"user"`
	Session string `json:"session"`
	// Task is the per-task scope inside a session. Optional — empty for
	// session-scoped artifacts; a list filter treats an empty Task as a
	// wildcard.
	Task string `json:"task,omitempty"`
}

ArtifactScope is the flat wire identity an artifacts-method request carries. It mirrors the four-field internal/artifacts.ArtifactScope shape — `(tenant, user, session, task)` — because the artifact store keys artifacts on tasks (RFC §6.10), but it is a Protocol-owned wire type, never a re-export.

Identity is mandatory: Tenant / User / Session must be non-empty for artifacts.put and artifacts.get_ref. Task is optional for session- scoped artifacts. For artifacts.list, empty fields are wildcards (tenant-wide listing requires the admin scope per D-079).

type ArtifactSource

type ArtifactSource string

ArtifactSource is the closed enum of artifact producers. A free-text field would invite drift; the enum can be extended via a future RFC PR. Deserialisation of an unknown source returns CodeInvalidRequest loudly (the artifacts surface fails loud per CLAUDE.md §13) — there is no silent "unknown" bucket.

const (
	// ArtifactSourceTool — the artifact was produced by a tool call.
	ArtifactSourceTool ArtifactSource = "tool"
	// ArtifactSourcePlanner — the artifact was produced by a planner
	// decision.
	ArtifactSourcePlanner ArtifactSource = "planner"
	// ArtifactSourceUserUpload — the artifact was uploaded by an operator
	// through the Console (or Playground) file-upload pipeline. This is
	// the default Source for an artifacts.put with no explicit Source.
	ArtifactSourceUserUpload ArtifactSource = "user_upload"
	// ArtifactSourceSystem — the artifact was produced by the runtime
	// itself (a generated report, a system dump).
	ArtifactSourceSystem ArtifactSource = "system"
)

Canonical ArtifactSource values. The set is closed.

type ArtifactsDeleteRequest added in v1.3.0

type ArtifactsDeleteRequest struct {
	// Scope is the artifact's isolation scope. The triple is mandatory.
	Scope ArtifactScope `json:"scope"`
	// ID is the content-addressed artifact id to evict.
	ID string `json:"id"`
}

ArtifactsDeleteRequest is the wire request for the `artifacts.delete` method (Phase 108o / D-187) — the admin-gated "evict an artifact" mutation. Identity is mandatory (full triple); admin scope is required (D-079). Heavy bytes never cross the wire — only the scope + the content-addressed id.

type ArtifactsDeleteResponse added in v1.3.0

type ArtifactsDeleteResponse struct {
	// Deleted reports whether the artifact existed before the delete.
	// Idempotent: deleting an absent artifact returns deleted=false with
	// no error (CodeNotFound is NOT raised — delete is a no-op-safe verb).
	Deleted bool `json:"deleted"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

ArtifactsDeleteResponse is the wire response for the `artifacts.delete` method.

type ArtifactsGetRefRequest

type ArtifactsGetRefRequest struct {
	// Scope is the caller's identity scope. Tenant / User / Session are
	// mandatory.
	Scope ArtifactScope `json:"scope"`
	// ID is the content-addressed artifact identifier to resolve.
	ID string `json:"id"`
	// Expiry is the presigned-URL validity window. Defaults to
	// DefaultPresignExpiry (15m) when zero; values outside
	// [PresignExpiryMin, PresignExpiryMax] are rejected loudly.
	Expiry time.Duration `json:"expiry,omitempty"`
}

ArtifactsGetRefRequest is the wire request for the artifacts.get_ref Protocol method — the read-side presigned-URL resolver. Expiry is bounded [PresignExpiryMin, PresignExpiryMax]; an out-of-range expiry is rejected with CodeInvalidRequest.

func (ArtifactsGetRefRequest) NormalisedExpiry

func (r ArtifactsGetRefRequest) NormalisedExpiry() time.Duration

NormalisedExpiry returns the request's Expiry, applying DefaultPresignExpiry when the request omitted it. The handler separately bounds-checks against [PresignExpiryMin, PresignExpiryMax] so it can return CodeInvalidRequest rather than silently clamping.

type ArtifactsGetRefResponse

type ArtifactsGetRefResponse struct {
	// Ref is the artifact metadata reference.
	Ref ArtifactRef `json:"ref"`
	// PresignedURL is the time-bounded HTTPS URL the Console downloads
	// the bytes from directly, bypassing the runtime's bytes path.
	PresignedURL string `json:"presigned_url"`
	// ExpiresAt is the wall-clock instant the presigned URL stops being
	// valid.
	ExpiresAt time.Time `json:"expires_at"`
	// ProtocolVersion echoes the Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

ArtifactsGetRefResponse is the wire response for artifacts.get_ref. It carries the time-bounded presigned URL plus the artifact metadata — the Console's Preview / Download / Share all consume this single shape per D-022 / D-026.

type ArtifactsListRequest

type ArtifactsListRequest struct {
	// Scope is the caller's identity scope. A list filter treats empty
	// fields as wildcards; a Tenant differing from the caller's verified
	// tenant requires the admin scope per D-079.
	Scope ArtifactScope `json:"scope"`
	// MimeType is an OR-set of IANA media types. Empty == wildcard.
	MimeType []string `json:"mime_type,omitempty"`
	// Source is an OR-set of artifact producers. Empty == wildcard. An
	// unknown source value fails the request with CodeInvalidRequest.
	Source []ArtifactSource `json:"source,omitempty"`
	// SizeRange, when set, filters by stored byte size.
	SizeRange *SizeRange `json:"size_range,omitempty"`
	// CreatedRange, when set, filters by put timestamp.
	CreatedRange *TimeRange `json:"created_range,omitempty"`
	// Tags is an OR-set of tag strings. An artifact matches when it
	// carries at least one of the listed tags. Empty == wildcard.
	Tags []string `json:"tags,omitempty"`
	// Limit bounds the returned page. Defaults to DefaultArtifactsLimit
	// (100) when zero; values above MaxArtifactsLimit (1000) are clamped.
	Limit int `json:"limit,omitempty"`
}

ArtifactsListRequest is the wire request for the artifacts.list Protocol method. The Phase 73l filter extensions — MimeType, Source, SizeRange, CreatedRange, Tags — are all optional; an empty field is a wildcard. The handler applies them as a Go-side projection over the driver's returned slice (the V1 ArtifactStore.List signature is not extended — driver conformance stays untouched, D-120).

func (ArtifactsListRequest) NormalisedLimit

func (r ArtifactsListRequest) NormalisedLimit() int

NormalisedLimit returns the request's Limit clamped to [1, MaxArtifactsLimit], applying DefaultArtifactsLimit when the request omitted it. The handler calls this so a client that omits Limit gets the documented default and one that over-asks is bounded.

func (ArtifactsListRequest) Validate

func (r ArtifactsListRequest) Validate() error

Validate checks the artifacts.list filter for an unknown ArtifactSource value, failing loud (CLAUDE.md §13) rather than silently dropping it. Returns an error naming the offending value when one is found.

type ArtifactsListResponse

type ArtifactsListResponse struct {
	// Rows is the page slice, at most Limit rows. Empty when the filter
	// matched nothing.
	Rows []ArtifactRow `json:"rows"`
	// TotalMatched is the count of rows matching the filter before the
	// Limit truncation — the Console paginator renders "N of M".
	TotalMatched int `json:"total_matched"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

ArtifactsListResponse is the wire response for artifacts.list. Rows is the metadata-only page slice — never artifact bytes (D-026).

func (ArtifactsListResponse) MarshalJSON

func (r ArtifactsListResponse) MarshalJSON() ([]byte, error)

MarshalJSON is the standard json.Marshaler kept explicit so the ArtifactsListResponse shape stays stable across a field-reorder refactor. Round-trip is verified by artifacts_test.go.

type ArtifactsPutOpts

type ArtifactsPutOpts struct {
	// MimeType is the IANA media type of the upload. Empty defaults to
	// the store's own default (text/plain for PutText-shaped bytes).
	MimeType string `json:"mime_type,omitempty"`
	// Filename is metadata only — never used for path construction.
	Filename string `json:"filename,omitempty"`
	// Namespace is the logical bucket the artifact lands in. Empty
	// defaults to "default" at the store.
	Namespace string `json:"namespace,omitempty"`
	// Source is the artifact producer. Defaults to ArtifactSourceUserUpload
	// when empty (an artifacts.put IS, by construction, a user upload).
	// An explicit unknown value fails the request with
	// CodeInvalidRequest.
	Source ArtifactSource `json:"source,omitempty"`
	// Tags is the chip list to assign to the artifact.
	Tags []string `json:"tags,omitempty"`
}

ArtifactsPutOpts carries the optional upload metadata an artifacts.put request supplies. It mirrors the catalog-relevant subset of the storage-side internal/artifacts.PutOpts.

type ArtifactsPutRequest

type ArtifactsPutRequest struct {
	// Scope is the caller's identity scope. Tenant / User / Session are
	// mandatory; a body whose Tenant disagrees with the caller's
	// verified tenant is rejected with CodeScopeMismatch.
	Scope ArtifactScope `json:"scope"`
	// Bytes is the artifact payload. JSON-encoded as a base64 string by
	// the standard []byte marshaller.
	Bytes []byte `json:"bytes"`
	// Opts is the optional upload metadata.
	Opts ArtifactsPutOpts `json:"opts,omitempty"`
}

ArtifactsPutRequest is the wire request for the artifacts.put Protocol method (Brief 11 §PG-2). The upload bytes travel inline on the request leg only — the response is a reference, never an echo of the body. Body size is bounded by config.ProtocolConfig.MaxRequestBytes; an oversize body is rejected with CodeRequestTooLarge.

type ArtifactsPutResponse

type ArtifactsPutResponse struct {
	// Ref is the content-addressed reference to the stored artifact.
	Ref ArtifactRef `json:"ref"`
	// ProtocolVersion echoes the Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

ArtifactsPutResponse is the wire response for artifacts.put. It carries the canonical ArtifactRef the store minted — never the uploaded bytes (D-026).

type AuthRotateTokenRequest

type AuthRotateTokenRequest struct {
	// Identity is the caller's identity scope. The auth surface asserts
	// the triple against the verified JWT before re-minting.
	Identity IdentityScope `json:"identity"`
}

AuthRotateTokenRequest is the `auth.rotate_token` request body.

Token rotation requires no body fields beyond the identity scope — the caller's identity is carried by the verified JWT, and the Runtime re-mints for exactly that identity. The Identity field is the standard flat IdentityScope every Protocol request carries; the Runtime asserts it against the verified JWT (defence-in-depth — a caller cannot present a valid token for one identity and a body claiming another).

type AuthRotateTokenResponse

type AuthRotateTokenResponse struct {
	// NewToken is the re-minted Protocol-auth JWT, Bearer-shaped. The
	// operator copies this exactly once.
	NewToken string `json:"new_token"`
	// ExpiresAt is the new token's expiry, UTC.
	ExpiresAt time.Time `json:"expires_at"`
}

AuthRotateTokenResponse is the `auth.rotate_token` response body — the re-minted token. It is one-time-revealed: the Console copies `NewToken` once into its encrypted 72h `auth_profiles` blob and never displays the raw token again.

type Capability

type Capability string

Capability is a Protocol surface a Runtime can advertise. The Protocol exposes several surfaces (RFC §5.2 — task control, streaming events, state snapshots, topology, artifacts, traces/metrics); a Capability is how a Runtime tells a client *which* of them are live, so a client negotiates rather than discovering a missing surface by a 404.

Capability is a fixed string enum, not a registration seam: a new Protocol surface adds its Capability constant in the phase that ships the surface (and extends canonicalCapabilities), exactly as a new Protocol method extends methods.canonicalMethods.

const (
	// CapTaskControl — the task control surface (RFC §5.2 "Task
	// control" row): the `start` method plus the nine steering-control
	// methods. Shipped in Phase 54.
	CapTaskControl Capability = "task_control"
	// CapEventsSubscribe — the streaming-events surface (RFC §5.2
	// "Streaming events" row): the `events.subscribe` method and the
	// `events.aggregate` time-bucket method. Shipped in Wave 13
	// (Phase 72 / 72a).
	CapEventsSubscribe Capability = "events_subscribe"
	// CapRuntimePosture — the runtime-posture surface (RFC §5.3, §6.15,
	// §7): the five read-only `runtime.*` / `metrics.*` methods
	// (`runtime.info`, `runtime.health`, `runtime.counters`,
	// `runtime.drivers`, `metrics.snapshot`). Shipped in Wave 13
	// (Phase 72f / D-111). A Protocol client negotiates "does this
	// Runtime advertise the posture surface?" via
	// `VersionHandshake.Accepts(CapRuntimePosture)`. The addition is
	// backward-compatible (RFC §5.3 minor-class change) — no version
	// bump.
	CapRuntimePosture Capability = "runtime_posture"
	// CapTopologySnapshot — the engine-graph topology projection
	// (`topology.snapshot`, Phase 74 / D-114). Conditional: a runtime
	// only advertises this capability when it hosts an engine (the
	// ControlSurface's topology accessor is non-nil). Planner /
	// RunLoop-shaped runtimes — including `harbor dev` against an
	// agent yaml — do NOT advertise it; the Console reads
	// `runtime.info.capabilities` at attach and gates its
	// `topology.snapshot` calls behind `caps.has('topology_snapshot')`
	// so the browser console stays clean on runtimes without the
	// surface (round-8 F1 / phase 84a). Backward-compatible (RFC §5.3
	// minor-class addition) — no version bump.
	CapTopologySnapshot Capability = "topology_snapshot"
)

The V1 Protocol capability set. At Protocol 0.1.0 exactly one surface has shipped — the Phase 54 task control surface — so CapTaskControl is the only capability. RFC §5.2's other surfaces add their Capability constant here as their phase lands.

func Capabilities

func Capabilities() []Capability

Capabilities returns the deterministic, lexicographically-sorted set of Protocol capabilities the Runtime advertises. At Protocol 0.1.0 this is exactly {CapTaskControl}.

type ControlRequest

type ControlRequest struct {
	// Identity is the request's identity scope. The full quadruple
	// (triple + Run) is mandatory — a steering control targets a
	// specific run's inbox. Scope is the caller's steering scope claim.
	Identity IdentityScope `json:"identity"`
	// Payload is the method-specific control payload. May be nil — a
	// bare `cancel` / `pause` carries no payload. The Phase 52
	// ValidatePayload enforces the RFC §6.3 bounds (depth ≤ 6, ≤ 64
	// keys, ≤ 50 list items, ≤ 4096 chars/string, ≤ 16 KiB total) at the
	// edge; an oversize payload fails the request closed.
	Payload map[string]any `json:"payload,omitempty"`
	// EventID is the caller-supplied idempotency / correlation key
	// (ULID-shaped). Optional — Phase 53's control-history dedupe uses
	// it. Empty is permitted.
	EventID string `json:"event_id,omitempty"`
}

ControlRequest is the wire request shared by the nine steering-control Protocol methods (`cancel`, `pause`, `resume`, `redirect`, `inject_context`, `approve`, `reject`, `prioritize`, `user_message`). The method name selects which steering ControlType the surface constructs; the Payload carries the method-specific arguments (the `goal` for redirect, the `message` for user_message, the `priority` for prioritize, `hard` for a hard cancel, etc.).

The ControlSurface constructs a steering.ControlEvent from a ControlRequest and lets the Phase 52 Inbox.Enqueue do the validation, the RFC §6.3 payload-bounds enforcement, and the per-event scope check — Phase 54 does not re-implement any of that (CLAUDE.md §13 forbids a second validator).

type ControlResponse

type ControlResponse struct {
	// Accepted is true when the control event was validated, scope-checked,
	// and enqueued on the run's steering inbox. A false Accepted is never
	// returned — a rejected control surfaces as a *protocol.Error from
	// Dispatch, not an Accepted=false response.
	Accepted bool `json:"accepted"`
	// Method echoes the Protocol method name the control was submitted
	// under (`cancel`, `pause`, …) so a client correlating async
	// responses can match them up.
	Method string `json:"method"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

ControlResponse is the wire response shared by the nine steering-control Protocol methods. It is a minimal acknowledgement: the control was validated, scope-checked, and enqueued on the run's inbox. The control's *effect* on the run (the redirected goal taking hold, the pause blocking the loop, the approval advancing it) is observed via the canonical event stream (`control.received` / `control.applied`, Phase 53), NOT synchronously in this response — a richer synchronous response would couple the Protocol edge to the run loop's step timing.

type Deprecation

type Deprecation struct {
	// Subject names the Protocol element being deprecated — the method
	// name, error code, `Type.Field` wire-field path, or capability
	// string, depending on Kind.
	Subject string `json:"subject"`
	// Kind classifies what Subject is — one of the DeprecationKind
	// constants.
	Kind DeprecationKind `json:"kind"`
	// DeprecatedIn is the Protocol version (a MAJOR.MINOR.PATCH string)
	// in which Subject was first marked deprecated.
	DeprecatedIn string `json:"deprecated_in"`
	// RemovedIn is the Protocol version in which Subject is removed. It
	// MUST sort strictly after DeprecatedIn — the span between the two
	// is the deprecation window.
	RemovedIn string `json:"removed_in"`
	// Replacement names the Protocol element callers should migrate to.
	// Optional — a deprecation with no replacement is a pure removal.
	Replacement string `json:"replacement,omitempty"`
	// Note is an optional human-readable migration hint.
	Note string `json:"note,omitempty"`
}

Deprecation is the settled structured note format for a breaking Protocol change's removal window. RFC §5.3: "Breaking changes require a deprecation window so third-party Consoles aren't whipsawed." A deprecated Protocol element carries its window in this shape — a structured, machine-readable record — rather than a free-text code comment, so a Protocol client (or a `harbor version` subcommand, Phase 63) can surface "this method is going away in 0.3.0, use X instead" mechanically.

Deprecation is a wire type — it round-trips through JSON so the negotiation surface (Phase 60) can hand the active set to a client.

func Deprecations

func Deprecations() []Deprecation

Deprecations returns a copy of the active Protocol deprecation registry, sorted deterministically by RemovedIn version then Subject. The slice is a copy — a caller cannot mutate the registry through the return value. At Protocol 0.1.0 the registry is empty.

func (Deprecation) String

func (d Deprecation) String() string

String renders the settled human-readable deprecation note format:

<kind> "<subject>" is deprecated in <deprecated_in>, removed in <removed_in>[; use <replacement>][ — <note>]

This is the canonical phrasing a Protocol client / CLI surfaces to a human operator.

func (Deprecation) Validate

func (d Deprecation) Validate() error

Validate reports whether the Deprecation is well-formed: a non-empty Subject, a recognised Kind, parseable DeprecatedIn / RemovedIn versions, and a RemovedIn that sorts strictly after DeprecatedIn (an empty or inverted window is a malformed deprecation). It fails loudly — a malformed Deprecation in the registry is a bug, not a silently-tolerated entry.

type DeprecationKind

type DeprecationKind string

DeprecationKind classifies which Protocol element a Deprecation applies to. It is a fixed string enum — the four kinds of element the versioned Protocol surface exposes (RFC §5.2, §5.3) — not a registration seam.

const (
	// DeprecationMethod — a Protocol method name (internal/protocol/
	// methods) is being retired.
	DeprecationMethod DeprecationKind = "method"
	// DeprecationErrorCode — a Protocol error code (internal/protocol/
	// errors) is being retired.
	DeprecationErrorCode DeprecationKind = "error_code"
	// DeprecationWireField — a field on a Protocol wire type
	// (internal/protocol/types) is being retired.
	DeprecationWireField DeprecationKind = "wire_field"
	// DeprecationCapability — a Protocol Capability is being retired.
	DeprecationCapability DeprecationKind = "capability"
)

The four kinds of Protocol element a Deprecation can apply to.

type EventAggregateRequest

type EventAggregateRequest struct {
	// Identity is the (tenant, user, session) scope envelope every
	// Protocol client carries on the body. The aggregate handler pulls
	// the authoritative identity from the JWT / X-Harbor-* edge headers
	// (RFC §5.5) — this field is shape-only, declared so the body
	// decode's `DisallowUnknownFields` accepts the Console's standard
	// payload shape (`Transport.request` auto-injects `identity` on
	// every request body). Optional in the wire schema; ignored by the
	// handler. Round-5 walkthrough fix — pre-fix the request was the
	// only typed request shape on the Console-facing surface that
	// REFUSED the identity envelope, breaking every Events page
	// `events.aggregate` call cross-origin.
	Identity IdentityScope `json:"identity,omitempty"`
	// Filter narrows the events the aggregator counts. The empty filter
	// (zero EventFilter) is interpreted as "every event in the caller's
	// own identity tuple" (per the EventFilter godoc).
	Filter EventFilter `json:"filter"`
	// Window is the inclusive lookback span. Must be > 0. The response
	// covers [Now-Window, Now) where Now is the runtime's clock at
	// handler entry.
	Window time.Duration `json:"window"`
	// Bucket is the per-bucket width. Must be > 0 and must evenly
	// divide Window (Window % Bucket == 0) — a non-dividing pair is
	// rejected with `CodeInvalidRequest` so the response's bucket count
	// is deterministic and a rendering client never sees a fractional
	// trailing bucket.
	Bucket time.Duration `json:"bucket"`
}

EventAggregateRequest is the wire request for the `events.aggregate` Protocol method (Phase 72a). It returns a deterministic time series of event-type counts over `Window`, bucketed by `Bucket`. The window is anchored at the request's effective `Now` (the runtime's monotonic clock at handler entry) — the response slice runs [Now-Window, Now) bucketed at `Bucket` width.

The request body's `filter` is the EventFilter above; the same identity-scope rules apply (a cross-tenant aggregate is gated on the `auth.ScopeAdmin` OR `auth.ScopeConsoleFleet` claim per D-079).

type EventAggregateResponse

type EventAggregateResponse struct {
	// Buckets is the per-bucket count series, oldest first. Each
	// bucket's [Start, End) span is exactly `Request.Bucket` wide; the
	// last bucket's End equals the request's effective Now.
	Buckets []EventBucket `json:"buckets"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew (mirrors the
	// Phase 54 ControlResponse / StartResponse shape).
	ProtocolVersion string `json:"protocol_version"`
}

EventAggregateResponse is the wire response for the `events.aggregate` Protocol method. Buckets are in chronological order (oldest first); `len(Buckets) == Window/Bucket`.

type EventBucket

type EventBucket struct {
	// Start is the bucket's lower bound (inclusive). UTC. The JSON tag
	// is namespaced (bucket_start rather than start) so the wire
	// surface does not collide with the Phase 54 task-control method
	// name start — the Phase 58 single-source grep backstop is
	// substring-shaped (it does not parse struct tags) and a bare
	// start tag would false-positive against it.
	Start time.Time `json:"bucket_start"`
	// End is the bucket's upper bound (exclusive). UTC. End - Start ==
	// the request's `Bucket` width.
	End time.Time `json:"bucket_end"`
	// Counts maps event-type string → count of events in this bucket.
	// An empty map means "no matching events in this window slice" —
	// the bucket is still present so the rendering client sees the gap.
	Counts map[string]int64 `json:"counts"`
}

EventBucket is a single time-bucketed count series — one stripe of the per-event-type stacked-area sparkline the Events page renders (Phase 73g). Start (inclusive) and End (exclusive) are UTC; Counts is keyed by event-type string.

Bucket boundaries are computed deterministically by the aggregator: for a request whose window is W and bucket size is B (B divides W), the response carries exactly ceil(W/B) buckets, each spanning [Start, Start+B). Empty buckets are present (with an empty Counts map) so a rendering client can scan a contiguous time axis without gap arithmetic.

type EventFilter

type EventFilter struct {
	// EventTypes narrows to events whose `Type` is in the set. Empty
	// matches every type (today's `events.subscribe` default). The
	// strings are the registered `events.EventType` values
	// (`tool.failed`, `planner.repair_exhausted`, etc.).
	EventTypes []string `json:"event_types,omitempty"`
	// TenantIDs / UserIDs / SessionIDs / RunIDs narrow to events whose
	// identity tuple matches one of the supplied values. Empty on any
	// axis is interpreted as "the caller's own component"; >1 on the
	// tenant axis (or a single tenant other than the caller's) requires
	// `auth.ScopeAdmin` OR `auth.ScopeConsoleFleet` per D-079.
	TenantIDs  []string `json:"tenant_ids,omitempty"`
	UserIDs    []string `json:"user_ids,omitempty"`
	SessionIDs []string `json:"session_ids,omitempty"`
	RunIDs     []string `json:"run_ids,omitempty"`
	// Since is the optional lower bound (inclusive) on `OccurredAt`.
	// Zero means "unbounded on the lower side." UTC.
	Since time.Time `json:"since,omitempty"`
	// Until is the optional upper bound (exclusive) on `OccurredAt`.
	// Zero means "unbounded on the upper side." UTC.
	Until time.Time `json:"until,omitempty"`
}

EventFilter is the canonical wire predicate every events.* Protocol method consumes — `events.subscribe` (Phase 72) for live subscriptions and `events.aggregate` (Phase 72a) for time-bucketed count series. The shape is identity-scope-aware: cross-tenant filters (TenantIDs with more than one entry, or a tenant other than the caller's) require the `auth.ScopeAdmin` OR `auth.ScopeConsoleFleet` claim per D-079 — there is NO dedicated `events.crosstenant` scope (the closed two-scope set is the wire posture).

Identity is mandatory. An EventFilter with empty UserIDs / SessionIDs is interpreted as "the caller's own identity tuple" — the wire edge resolves the missing components from the caller's identity quadruple. A filter that elides the triple WITHOUT a scope claim is rejected loudly at the wire edge with `CodeIdentityRequired`; one that names multiple tenants WITHOUT a scope claim is rejected with `CodeIdentityScopeRequired` (Phase 72; HTTP 403).

Heavy payloads (D-026 / RFC §6.5): the filter operates on event HEADER fields only (type, identity, timestamp). Predicates over event payload bytes would force the runtime to materialise heavy payloads through the LLM-edge safety net — explicitly out of scope per Brief 11 §CC-4 (substring payload search is post-V1).

Since / Until are UTC; the empty zero-value means "unbounded on that side." A non-zero Until that precedes Since is a structurally-invalid filter (`CodeInvalidRequest`).

type Flow

type Flow struct {
	// ID is the flow's stable identifier — the registered flow name.
	ID string `json:"id"`
	// Name is the operator-facing display name. Equal to ID at V1; the
	// field exists so a future rename surface does not break the wire.
	Name string `json:"name"`
	// Owner is the flow's declared owner (the agent / team that
	// registered it). Empty when the registration carried no owner.
	Owner string `json:"owner,omitempty"`
	// Version is the flow's version string. Empty when unversioned.
	Version string `json:"version,omitempty"`
	// PlannerFamily is the graph-family planner the flow runs on —
	// "graph" / "workflow" / "deterministic". The catalog is filtered
	// to graph-family planners (D-063).
	PlannerFamily string `json:"planner_family,omitempty"`
	// NodeCount is the number of nodes in the flow's engine graph.
	NodeCount int `json:"node_count"`
	// EdgeCount is the number of directed edges in the flow's graph.
	EdgeCount int `json:"edge_count"`
	// Runs24h is the count of invocations in the trailing 24h window
	// scoped to the caller's identity (admin fans across tenants).
	Runs24h int64 `json:"runs_24h"`
	// P50LatencyMS is the median run latency over the window, in ms.
	P50LatencyMS int64 `json:"p50_latency_ms"`
	// P95LatencyMS is the 95th-percentile run latency over the window.
	P95LatencyMS int64 `json:"p95_latency_ms"`
	// SuccessRate is the fraction of runs in the window that succeeded,
	// in [0,1].
	SuccessRate float64 `json:"success_rate"`
	// LastRun is the wall-clock time of the most recent invocation. The
	// zero value (omitted) means the flow has never run.
	LastRun time.Time `json:"last_run,omitempty"`
	// Budget is the flow's per-flow Budget (D-023). Read-only at V1.
	Budget FlowBudget `json:"budget"`
}

Flow is one row of the `flows.list` catalog: a registered engine-graph flow with its aggregate run metrics over the active window. A "flow" in the Console is exactly an engine node graph a graph-family planner runs on (D-063); this row is the catalog lens over it.

type FlowArtifactRef

type FlowArtifactRef struct {
	// ID is the content-addressed identifier.
	ID string `json:"id"`
	// MimeType is the IANA media type, when known.
	MimeType string `json:"mime_type,omitempty"`
	// SizeBytes is the length of the referenced bytes.
	SizeBytes int64 `json:"size_bytes,omitempty"`
	// Filename is metadata only (never used for path construction).
	Filename string `json:"filename,omitempty"`
	// SHA256 is the full hex digest of the referenced bytes.
	SHA256 string `json:"sha256,omitempty"`
}

FlowArtifactRef is the by-reference shape a `FlowRunDescription` carries when a run's final output meets or exceeds the configured heavy-content threshold (D-026). It mirrors a subset of `internal/artifacts.ArtifactRef` but is a flat wire type, kept distinct from `PauseArtifactRef` / `SearchArtifactRef` so a future divergence in either surface does not whipsaw the other.

type FlowBudget

type FlowBudget struct {
	// DeadlineMS is the flow's wall-clock deadline in milliseconds. Zero
	// means "no deadline cap".
	DeadlineMS int64 `json:"deadline_ms,omitempty"`
	// RequestCap is the flow's hop budget — the maximum number of node
	// hops a single invocation may take. Zero means "no hop cap".
	RequestCap int `json:"request_cap,omitempty"`
	// CostCapUSD is the flow's aggregate cost cap in US dollars. Zero
	// means "no cost cap".
	CostCapUSD float64 `json:"cost_cap_usd,omitempty"`
	// TokenCap is the flow's aggregate token cap. Zero means "no token
	// cap". The token cap is a post-V1 axis on the runtime `Budget`;
	// the field exists on the wire so the Budget meter can render it
	// without a wire-shape break when the axis lands.
	TokenCap int64 `json:"token_cap,omitempty"`
}

FlowBudget is the wire projection of a flow's per-flow Budget (D-023 — Flow-as-Tool registration, Phase 26a). It mirrors the three caps a flow's aggregate `Budget` enforces at the flow boundary: a wall-clock deadline, a hop (request) cap, and a cost cap. It is a flat wire type — the Protocol owns its vocabulary; the runtime `flow.Budget` struct never leaks. Edit of the Budget is `flows.set_budget` — post-V1 per page-flows.md §10; at V1 the Budget is read-only.

type FlowBudgetConsumption

type FlowBudgetConsumption struct {
	// RequestsUsed is the hop count consumed in the active window.
	RequestsUsed int `json:"requests_used"`
	// CostUSDUsed is the cost consumed in the active window.
	CostUSDUsed float64 `json:"cost_usd_used"`
	// TokensUsed is the token count consumed in the active window.
	TokensUsed int64 `json:"tokens_used"`
}

FlowBudgetConsumption is the live consumption of a flow's Budget vs. its caps, derived from the flow's run history within the active window. It is the data the Budget meter (right rail) renders as progress bars. Consumption is observation-only — there is no edit surface at V1.

type FlowDescribeRequest

type FlowDescribeRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// ID is the flow to describe. An unknown id fails with CodeNotFound.
	ID string `json:"id"`
}

FlowDescribeRequest is the wire request for `flows.describe`.

type FlowDescription

type FlowDescription struct {
	// Flow is the catalog row for the described flow.
	Flow Flow `json:"flow"`
	// Nodes is the flow's node set, sorted lexicographically by ID.
	Nodes []FlowNode `json:"nodes"`
	// Edges is the flow's directed edge set, sorted by (From, To).
	Edges []FlowEdge `json:"edges"`
	// Source is the source-of-truth reference — a Go path or YAML
	// descriptor path. A string reference, never executable code.
	Source string `json:"source,omitempty"`
	// BudgetConsumption is the flow's live Budget consumption over the
	// active window — the data the Budget meter renders.
	BudgetConsumption FlowBudgetConsumption `json:"budget_consumption"`
}

FlowDescription is the wire projection of a flow's full engine-graph description — the `flows.describe` payload. It carries the catalog row plus the node / edge set plus a string source reference. The source reference is a Go path or a YAML descriptor path (D-023: Go- coded V1; declarative YAML in V1.1) — it is NEVER executable code in the Console.

type FlowEdge

type FlowEdge struct {
	// From is the upstream node's ID.
	From string `json:"from"`
	// To is the downstream node's ID.
	To string `json:"to"`
}

FlowEdge is one directed edge of a flow's projected engine graph.

type FlowFilter

type FlowFilter struct {
	// Tenants restricts the catalog to the named tenants. Empty means
	// "the caller's own tenant". A value reaching outside the caller's
	// tenant requires the admin scope claim.
	Tenants []string `json:"tenants,omitempty"`
	// PlannerFamilies restricts the catalog to the named planner
	// families. Empty means "all graph-family planners".
	PlannerFamilies []string `json:"planner_families,omitempty"`
	// Query is a free-text substring match over the flow name / owner.
	// Empty means "no text filter".
	Query string `json:"query,omitempty"`
}

FlowFilter narrows the `flows.list` catalog. An empty filter means "the caller's own identity scope". Supplying a `Tenants` value that reaches OUTSIDE the caller's own tenant (or naming more than one tenant) requires the `auth.ScopeAdmin` scope claim (D-079); a missing-claim cross-tenant request is rejected loudly with CodeIdentityScopeRequired (HTTP 403) — never silently downgraded.

type FlowListRequest

type FlowListRequest struct {
	// Identity is the mandatory caller identity scope. An incomplete
	// triple fails the request closed with CodeIdentityRequired.
	Identity IdentityScope `json:"identity"`
	// Filter narrows the catalog. The zero value lists the caller's
	// own-tenant flows.
	Filter FlowFilter `json:"filter"`
	// Page is the 1-based page index. Zero is treated as page 1.
	Page int `json:"page,omitempty"`
	// PageSize is the per-page row count. Zero applies
	// DefaultFlowListPageSize; a value above MaxFlowListPageSize is
	// rejected with CodeInvalidRequest.
	PageSize int `json:"page_size,omitempty"`
}

FlowListRequest is the wire request for `flows.list`.

type FlowListResponse

type FlowListResponse struct {
	// Flows is the catalog page, sorted lexicographically by ID for
	// byte-stability across requests.
	Flows []Flow `json:"flows"`
	// Page is the 1-based page index this response covers.
	Page int `json:"page"`
	// PageSize is the per-page row count applied.
	PageSize int `json:"page_size"`
	// PageCount is the total number of pages for the filtered set.
	PageCount int `json:"page_count"`
	// TotalRows is the total number of catalog rows the filter matched
	// before pagination.
	TotalRows int `json:"total_rows"`
}

FlowListResponse is the wire response for `flows.list`.

type FlowMetrics

type FlowMetrics struct {
	// FlowID is the flow these metrics describe.
	FlowID string `json:"flow_id"`
	// WindowStart is the wall-clock start of the aggregation window.
	WindowStart time.Time `json:"window_start"`
	// WindowEnd is the wall-clock end of the aggregation window.
	WindowEnd time.Time `json:"window_end"`
	// Buckets are the time-bucketed aggregates, oldest first.
	Buckets []FlowMetricsBucket `json:"buckets"`
	// BudgetConsumption is the flow's live Budget consumption over the
	// window — the data the budget sparkline renders.
	BudgetConsumption FlowBudgetConsumption `json:"budget_consumption"`
}

FlowMetrics is the wire projection of a flow's sparkline aggregates — the `flows.metrics` payload. The buckets feed the Flow Metrics card (runs-per-hour, p95 latency, success rate, budget consumption).

type FlowMetricsBucket

type FlowMetricsBucket struct {
	// BucketStart is the wall-clock start of the bucket.
	BucketStart time.Time `json:"bucket_start"`
	// Runs is the count of runs that started within the bucket.
	Runs int64 `json:"runs"`
	// P95LatencyMS is the 95th-percentile run latency within the bucket.
	P95LatencyMS int64 `json:"p95_latency_ms"`
	// SuccessRate is the fraction of bucketed runs that succeeded.
	SuccessRate float64 `json:"success_rate"`
	// CostUSD is the total cost recorded within the bucket.
	CostUSD float64 `json:"cost_usd"`
}

FlowMetricsBucket is one time bucket of a flow's sparkline metrics.

type FlowMetricsRequest

type FlowMetricsRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// FlowID is the flow whose metrics to aggregate. An empty FlowID
	// fails with CodeInvalidRequest.
	FlowID string `json:"flow_id"`
	// WindowMS is the aggregation window in milliseconds. Zero applies
	// the default 24h window.
	WindowMS int64 `json:"window_ms,omitempty"`
	// BucketMS is the bucket width in milliseconds. Zero applies the
	// default 1h bucket.
	BucketMS int64 `json:"bucket_ms,omitempty"`
}

FlowMetricsRequest is the wire request for `flows.metrics`.

type FlowNode

type FlowNode struct {
	// ID is the node's unique identifier within the flow.
	ID string `json:"id"`
	// Type is the node's role tag — subflow / tool / pause /
	// artifact_emitter.
	Type FlowNodeKind `json:"type"`
	// Descriptor is a schema reference for the node — the tool name for
	// a tool node, the nested flow id for a subflow node. It is a string
	// reference, never executable code.
	Descriptor string `json:"descriptor,omitempty"`
	// Policy is the node's per-node policy. Nil when the node carries
	// the engine default policy.
	Policy *FlowNodePolicy `json:"policy,omitempty"`
}

FlowNode is one vertex of a flow's projected engine graph.

type FlowNodeKind

type FlowNodeKind string

FlowNodeKind tags a node's role in the flow's engine graph. The V1 set is closed — a node is a subflow, a tool invocation, a pause point, or an artifact emitter.

const (
	// FlowNodeSubflow tags a node that runs a nested flow.
	FlowNodeSubflow FlowNodeKind = "subflow"
	// FlowNodeTool tags a node that invokes a registered Tool.
	FlowNodeTool FlowNodeKind = "tool"
	// FlowNodePause tags a node that parks the run at a pause point.
	// The wire value is the two-word form pause_point — deliberately
	// distinct from the Protocol method-name vocabulary so the Phase 58
	// single-source checker never flags this enum value.
	FlowNodePause FlowNodeKind = "pause_point"
	// FlowNodeArtifactEmitter tags a node that emits an artifact.
	FlowNodeArtifactEmitter FlowNodeKind = "artifact_emitter"
)

The V1 flow-node-kind constants.

type FlowNodePolicy

type FlowNodePolicy struct {
	// MaxRetries is the per-node retry ceiling.
	MaxRetries int `json:"max_retries,omitempty"`
	// TimeoutMS is the per-node wall-clock timeout in milliseconds.
	TimeoutMS int64 `json:"timeout_ms,omitempty"`
}

FlowNodePolicy is the wire projection of a node's per-node policy (the runtime `engine.NodePolicy` — retry / timeout). It is a flat wire type; the runtime struct never leaks.

type FlowNodeRunState

type FlowNodeRunState struct {
	// NodeID is the node's identifier within the flow.
	NodeID string `json:"node_id"`
	// Status is the node's outcome within the run.
	Status FlowRunStatus `json:"status"`
	// DurationMS is the node's wall-clock duration in milliseconds.
	DurationMS int64 `json:"duration_ms,omitempty"`
	// Retries is the number of times the node was retried.
	Retries int `json:"retries,omitempty"`
	// ErrorClass is a short classification of a node failure. Empty for
	// a non-failed node.
	ErrorClass string `json:"error_class,omitempty"`
}

FlowNodeRunState is one node's slice of a run's per-node timeline.

type FlowRun

type FlowRun struct {
	// RunID is the run's stable identifier.
	RunID string `json:"run_id"`
	// FlowID is the flow this run executed.
	FlowID string `json:"flow_id"`
	// Status is the run's outcome.
	Status FlowRunStatus `json:"status"`
	// Trigger is what initiated the run.
	Trigger FlowRunTrigger `json:"trigger"`
	// StartedAt is the wall-clock time the run started.
	StartedAt time.Time `json:"started_at"`
	// DurationMS is the run's wall-clock duration in milliseconds. Zero
	// for a run still in flight.
	DurationMS int64 `json:"duration_ms,omitempty"`
	// CostUSD is the run's recorded cost in US dollars.
	CostUSD float64 `json:"cost_usd,omitempty"`
	// Identity is the (tenant, user, session) the run executed under.
	Identity IdentityScope `json:"identity"`
	// ErrorClass is a short classification of the failure for a failed
	// run. Empty for a non-failed run.
	ErrorClass string `json:"error_class,omitempty"`
}

FlowRun is one row of the `flows.runs.list` history: a single invocation of a flow with timing + outcome.

type FlowRunDescribeRequest

type FlowRunDescribeRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// RunID is the run to describe. An unknown id fails with
	// CodeNotFound.
	RunID string `json:"run_id"`
}

FlowRunDescribeRequest is the wire request for `flows.runs.describe`.

type FlowRunDescription

type FlowRunDescription struct {
	// Run is the run-history row for the described run.
	Run FlowRun `json:"run"`
	// NodeStates is the per-node execution timeline, in node order.
	NodeStates []FlowNodeRunState `json:"node_states"`
	// OutputPreview is the run's final output INLINE when its serialised
	// size is below the heavy-content threshold. Empty when the run
	// produced no output or when the output was routed by-reference.
	OutputPreview string `json:"output_preview,omitempty"`
	// OutputRef is populated when the run's final output exceeded the
	// heavy-content threshold (D-026). The Console fetches the bytes via
	// `artifacts.get` when it wants them. When OutputRef is set,
	// OutputPreview is empty.
	OutputRef *FlowArtifactRef `json:"output_ref,omitempty"`
}

FlowRunDescription is the wire projection of a single flow run's per-node timeline + final-output reference — the `flows.runs.describe` payload. Heavy outputs are shipped by-reference via OutputRef (D-026); the description NEVER inlines heavy bytes.

type FlowRunRequest

type FlowRunRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// FlowID is the flow to invoke. An empty / unknown id fails with
	// CodeInvalidRequest / CodeNotFound.
	FlowID string `json:"flow_id"`
	// Inputs is the hand-crafted input form for the invocation. The
	// runtime validates it against the flow's input schema.
	Inputs map[string]any `json:"inputs,omitempty"`
}

FlowRunRequest is the wire request for `flows.run` — a one-shot invocation of a registered flow. `flows.run` is the ONLY mutating Flows-page method; it is gated on identity + the appropriate scope claim (D-079).

type FlowRunResponse

type FlowRunResponse struct {
	// RunID is the identifier of the accepted run.
	RunID string `json:"run_id"`
	// Status is the run's status at acceptance — "running" for an
	// accepted run.
	Status FlowRunStatus `json:"status"`
	// StartedAt is the wall-clock time the run started.
	StartedAt time.Time `json:"started_at"`
}

FlowRunResponse is the wire response for `flows.run` — the accepted run's identifier so the Console can drill into the run as it progresses.

type FlowRunStatus

type FlowRunStatus string

FlowRunStatus is the typed enum of flow-run outcomes. The V1 set is closed — a run is still running, succeeded, failed, or was cancelled.

const (
	// FlowRunRunning tags a run still in flight.
	FlowRunRunning FlowRunStatus = "running"
	// FlowRunSucceeded tags a run that completed without error.
	FlowRunSucceeded FlowRunStatus = "succeeded"
	// FlowRunFailed tags a run that terminated with an error.
	FlowRunFailed FlowRunStatus = "failed"
	// FlowRunCancelled tags a run that was cancelled before completion.
	FlowRunCancelled FlowRunStatus = "cancelled"
)

The V1 flow-run-status constants.

type FlowRunTrigger

type FlowRunTrigger string

FlowRunTrigger tags what initiated a flow run.

const (
	// FlowTriggerUser tags a run initiated by an operator via
	// `flows.run`.
	FlowTriggerUser FlowRunTrigger = "user"
	// FlowTriggerPlanner tags a run initiated by a planner step.
	FlowTriggerPlanner FlowRunTrigger = "planner"
	// FlowTriggerSystem tags a run initiated by the runtime itself.
	FlowTriggerSystem FlowRunTrigger = "system"
)

The V1 flow-run-trigger constants.

type FlowRunsListRequest

type FlowRunsListRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// FlowID is the flow whose run history to list. An empty FlowID
	// fails with CodeInvalidRequest.
	FlowID string `json:"flow_id"`
	// Tenants restricts the history to the named tenants. Empty means
	// "the caller's own tenant". A value reaching outside the caller's
	// tenant requires the admin scope claim (D-079).
	Tenants []string `json:"tenants,omitempty"`
	// Page is the 1-based page index. Zero is treated as page 1.
	Page int `json:"page,omitempty"`
	// PageSize is the per-page row count. Zero applies
	// DefaultFlowListPageSize.
	PageSize int `json:"page_size,omitempty"`
}

FlowRunsListRequest is the wire request for `flows.runs.list`.

type FlowRunsListResponse

type FlowRunsListResponse struct {
	// Runs is the run-history page, sorted by StartedAt descending
	// (newest first).
	Runs []FlowRun `json:"runs"`
	// Page is the 1-based page index this response covers.
	Page int `json:"page"`
	// PageSize is the per-page row count applied.
	PageSize int `json:"page_size"`
	// PageCount is the total number of pages.
	PageCount int `json:"page_count"`
	// TotalRows is the total number of run rows the filter matched.
	TotalRows int `json:"total_rows"`
}

FlowRunsListResponse is the wire response for `flows.runs.list`.

type GovernancePostureRequest

type GovernancePostureRequest struct {
	// TenantID — empty = the caller's own tenant; non-empty + different
	// from the caller's resolved tenant = requires auth.ScopeAdmin.
	TenantID string `json:"tenant_id,omitempty"`
}

GovernancePostureRequest is the `governance.posture` request body.

TenantID is forward-looking: an empty value (the default) reads the caller's own tenant — no scope claim required. A non-empty value that differs from the caller's identity-resolved tenant is a cross-tenant read and requires the `auth.ScopeAdmin` scope claim (D-079 closed two-scope set). V1 ships a single tenant per Harbor instance, so the cross-tenant path is reachable in code but the value space is a singleton; the field exists so a post-V1 multi-tenant deployment finds the surface ready.

type GovernancePostureResponse

type GovernancePostureResponse struct {
	// DefaultTier is the operator-configured default tier name applied
	// to an identity that does not match a custom resolver mapping.
	// Empty when no tiers are configured.
	DefaultTier string `json:"default_tier"`
	// ResolvedTier is the tier name the caller's identity resolves to
	// via the runtime's configured TierResolver. Empty when no tier
	// resolves (latent default).
	ResolvedTier string `json:"resolved_tier"`
	// IdentityTiers maps tier name → tier configuration (the D-081
	// shape). Always non-nil; an empty map signals no enforcement.
	IdentityTiers map[string]IdentityTierView `json:"identity_tiers"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// with — same field every Protocol response carries.
	ProtocolVersion string `json:"protocol_version"`
}

GovernancePostureResponse is the `governance.posture` response body — the read-only projection of the runtime's governance configuration.

IdentityTiers is keyed by tier name (e.g. `"free"`, `"team"`, `"enterprise"`). An empty map (the latent-default boot per D-044 / Phase 36a) means no enforcement is configured — the Console renders an explicit "No tiers configured" state, never a blank panel. The map is always non-nil in the wire JSON (`{}`, never `null`).

type HistogramBucket

type HistogramBucket struct {
	// UpperBound is the inclusive upper bound of the bucket.
	UpperBound float64 `json:"upper_bound"`
	// Count is the cumulative observation count at or below
	// UpperBound.
	Count uint64 `json:"count"`
}

HistogramBucket is one cumulative bucket in a NamedHistogram.

type IdentityScope

type IdentityScope struct {
	// Tenant / User / Session are the mandatory isolation triple. An
	// empty component fails the request closed at the Protocol edge.
	// When impersonation is in use, these fields carry the IMPERSONATED
	// identity — the identity the run executes under (matches the
	// Impersonating triple component-for-component).
	Tenant  string `json:"tenant"`
	User    string `json:"user"`
	Session string `json:"session"`
	// Run is the per-execution scope inside a session. Mandatory for the
	// nine steering-control methods (they target a specific run's inbox);
	// optional for `start` (a `start` request mints a new run / task, so
	// it carries no pre-existing run id).
	Run string `json:"run,omitempty"`
	// Scope is the caller's steering scope claim — one of the three
	// canonical steering scopes (`session_user` / `owner_user` /
	// `admin`). It is trust-based until Phase 61 Protocol auth, exactly
	// as `events.Filter.Admin` is; the ControlSurface enforces the
	// per-method scope via the Phase 52 steering CheckScope. Ignored for
	// `start` (task creation is not a steering control).
	Scope string `json:"scope,omitempty"`

	// Actor is the verified admin identity at the request edge — the
	// identity whose JWT claim was validated by the Phase 61 middleware.
	// V1 invariant: Actor MUST equal the JWT's verified `(tenant, user,
	// session)` triple; the transport rejects a body claiming a different
	// Actor with CodeScopeMismatch. The Actor's audit trail ("admin X
	// impersonated user Y at time T") is what makes impersonation
	// accountable. Brief 11 §PG-5, Phase 72b, D-107.
	Actor *IdentityScope `json:"actor,omitempty"`

	// Requester is the originating admin identity for delegated
	// impersonation chains (e.g. an admin acting on behalf of another
	// admin's audited request). At V1: Requester MUST equal Actor; the
	// field exists so post-V1 delegated impersonation does not require a
	// wire-shape break. The runtime rejects Requester != Actor with
	// CodeScopeMismatch. Brief 11 §PG-5, Phase 72b, D-107.
	Requester *IdentityScope `json:"requester,omitempty"`

	// Impersonating is the target identity the run executes under. When
	// non-empty, MUST carry a complete `(tenant, user, session)` triple —
	// identity is mandatory; the impersonated triple is identity too.
	// Setting Impersonating gates on auth.ScopeAdmin on the verified JWT;
	// a non-admin request with Impersonating set is rejected with
	// CodeScopeMismatch before Dispatch runs.
	//
	// V1 semantics: the top-level Tenant/User/Session fields MUST equal
	// the Impersonating triple when impersonation is in use — the run
	// executes as the impersonated identity. The Actor field carries the
	// audit-visible record of WHO impersonated. Brief 11 §PG-5, Phase
	// 72b, D-107.
	Impersonating *IdentityScope `json:"impersonating,omitempty"`
}

IdentityScope is the flat wire identity a Protocol task-control request carries. It is the wire projection of the runtime's identity quadruple `(tenant, user, session, run)` plus the caller's steering scope claim — flat strings, never a re-export of `identity.Quadruple` (a Protocol type that mapped 1:1 onto an internal Go struct would be the RFC §5.1 reject-on-sight smell). The protocol.ControlSurface translates an IdentityScope into the runtime's `identity.Quadruple` + `steering.Scope` at the edge.

Identity is mandatory (CLAUDE.md §6 rule 9, RFC §5.5: "the Protocol rejects any request without an identity scope"). The ControlSurface fails closed on an incomplete triple — there is no identity-downgrading knob.

Wave 13 (Phase 72b) admin-impersonation extension per Brief 11 §PG-5. The three optional fields Actor / Requester / Impersonating carry the admin-on-behalf-of-user triplet so an operator with the `auth.ScopeAdmin` claim can steer a run "on behalf of" another `(tenant, user, session)` while every request still carries BOTH the requesting admin's verified identity AND the impersonated identity for audit. An IdentityScope MAY carry zero impersonation fields (today's behaviour, the verified JWT identity IS the request identity) OR all three set (admin acting on behalf of a target user). The runtime rejects any other shape loudly at the Protocol edge — never silently degrades. See D-107.

func (IdentityScope) IsImpersonating

func (s IdentityScope) IsImpersonating() bool

IsImpersonating reports whether this scope carries a non-empty Impersonating field. The transport edge gates impersonation behaviour off this predicate; downstream code SHOULD use it rather than checking the field directly so a future shape change (e.g. flattening the triplet) lands in one place.

type IdentityTierView

type IdentityTierView struct {
	// BudgetCeilingUSD is the per-identity (per tier) cost ceiling in
	// USD. 0 = no ceiling.
	BudgetCeilingUSD float64 `json:"budget_ceiling_usd"`
	// RateLimit is the per-(identity, model) token-bucket configuration.
	RateLimit RateLimitView `json:"rate_limit"`
	// MaxTokens is the per-call MaxTokens cap. 0 = no enforcement.
	MaxTokens int `json:"max_tokens"`
}

IdentityTierView is the wire projection of one governance tier's policy bundle (the D-081 `governance.TierConfig` shape). Every field zero = latent for that policy.

type InterventionSummary

type InterventionSummary struct {
	// Type is the intervention kind — a HITL pause, a tool-approval
	// gate, or a tool-OAuth gate.
	Type string `json:"type"`
	// Reason is the operator-facing reason the intervention fired.
	Reason string `json:"reason"`
	// Outcome is the intervention's resolution — pending, resolved,
	// approved, or rejected.
	Outcome string `json:"outcome"`
	// OccurredAt is when the intervention fired.
	OccurredAt time.Time `json:"occurred_at"`
}

InterventionSummary is one entry in the right-rail Session Summary's Recent Interventions card. Capped at MaxSessionInterventionSummaries.

type LLMPostureRequest

type LLMPostureRequest struct {
	// TenantID — empty = the caller's own tenant; non-empty + different
	// from the caller's resolved tenant = requires auth.ScopeAdmin.
	TenantID string `json:"tenant_id,omitempty"`
}

LLMPostureRequest is the `llm.posture` request body. The TenantID field has the same forward-looking cross-tenant semantics as GovernancePostureRequest.TenantID — empty reads the caller's own tenant; a non-empty different value requires `auth.ScopeAdmin`.

type LLMPostureResponse

type LLMPostureResponse struct {
	// Provider is the LLM provider name (e.g. "bifrost", "mock").
	Provider string `json:"provider"`
	// Model is the bound model identifier (e.g. "openai/gpt-5.3-chat").
	Model string `json:"model"`
	// Region is the provider endpoint region; "" when not applicable
	// (the Console renders an em-dash placeholder for the empty case).
	Region string `json:"region"`
	// MockMode is true iff the runtime booted with HARBOR_DEV_ALLOW_MOCK=1
	// (D-089). The Console renders the canonical
	// `[DEV-ONLY MOCK LLM — DO NOT USE IN PRODUCTION]` banner when this
	// is true; hiding the banner is a §13 forbidden-practice violation.
	MockMode bool `json:"mock_mode"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// with — same field every Protocol response carries.
	ProtocolVersion string `json:"protocol_version"`
}

LLMPostureResponse is the `llm.posture` response body — the read-only projection of the runtime's bound LLM provider.

type MCPBindingScopeCount

type MCPBindingScopeCount struct {
	// BindingScope is the auth.BindingScope value ("user" / "agent").
	BindingScope string `json:"binding_scope"`
	// Count is the number of bindings at that scope.
	Count int32 `json:"count"`
}

MCPBindingScopeCount is one (binding-scope, count) pair in a per-server bindings summary.

type MCPBindingView

type MCPBindingView struct {
	// PrincipalID is the bound principal — a user id (ScopeUser) or an
	// agent id (ScopeAgent).
	PrincipalID string `json:"principal_id"`
	// BindingScope is the auth.BindingScope value ("user" / "agent").
	BindingScope string `json:"binding_scope"`
	// Scopes is the configured OAuth scope list. Always non-nil.
	Scopes []string `json:"scopes"`
	// ExpiresAt is the access-token expiry, or zero when no token is
	// bound yet.
	ExpiresAt time.Time `json:"expires_at"`
	// LastUsedAt is the last-use instant, or zero when never used.
	LastUsedAt time.Time `json:"last_used_at"`
}

MCPBindingView is one OAuth binding row. It NEVER carries token plaintext — only the binding metadata (D-083 invariant).

type MCPHealthBucket

type MCPHealthBucket struct {
	// StartMs is the bucket start (Unix milliseconds).
	StartMs int64 `json:"start_ms"`
	// LatencyMs is the observed handshake latency for the bucket.
	LatencyMs int64 `json:"latency_ms"`
}

MCPHealthBucket is one handshake-latency sparkline bucket.

type MCPPromptArg

type MCPPromptArg struct {
	// Name is the argument name.
	Name string `json:"name"`
	// Description is the argument description.
	Description string `json:"description,omitempty"`
	// Required reports whether the argument is mandatory.
	Required bool `json:"required"`
}

MCPPromptArg is one declared argument of an MCP prompt.

type MCPPromptView

type MCPPromptView struct {
	// Name is the prompt name.
	Name string `json:"name"`
	// Description is the prompt description.
	Description string `json:"description,omitempty"`
	// Arguments is the declared argument list. Always non-nil.
	Arguments []MCPPromptArg `json:"arguments"`
}

MCPPromptView is one advertised MCP prompt.

type MCPReconnect

type MCPReconnect struct {
	// OccurredAt is the reconnect instant.
	OccurredAt time.Time `json:"occurred_at"`
	// Reason carries the reconnect cause.
	Reason string `json:"reason,omitempty"`
}

MCPReconnect is one reconnect-history entry.

type MCPResourceView

type MCPResourceView struct {
	// URI is the resource URI.
	URI string `json:"uri"`
	// MimeType is the resource MIME type, or empty when the server
	// declared none.
	MimeType string `json:"mime_type,omitempty"`
	// SizeBytes is the declared resource size, or zero when unknown.
	SizeBytes int64 `json:"size_bytes,omitempty"`
	// Name is the resource short name.
	Name string `json:"name,omitempty"`
	// Title is the resource human-readable title.
	Title string `json:"title,omitempty"`
}

MCPResourceView is one advertised MCP resource.

type MCPServerBindingsListRequest

type MCPServerBindingsListRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
}

MCPServerBindingsListRequest is the wire shape for mcp.servers.bindings.list.

type MCPServerBindingsListResponse

type MCPServerBindingsListResponse struct {
	// Bindings is the OAuth binding list. Always non-nil (may be empty).
	Bindings []MCPBindingView `json:"bindings"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerBindingsListResponse is the mcp.servers.bindings.list reply.

type MCPServerGetRequest

type MCPServerGetRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name to inspect. Required.
	Name string `json:"name"`
}

MCPServerGetRequest is the wire shape for mcp.servers.get — a single-server detail read.

type MCPServerGetResponse

type MCPServerGetResponse struct {
	// Server is the per-server row shape.
	Server MCPServerView `json:"server"`
	// DisplayModesAdvertised lists the MCP-Apps DisplayMode values the
	// server declares (D-062). Always non-nil in the wire JSON.
	DisplayModesAdvertised []string `json:"display_modes_advertised"`
	// ContentShapes lists the canonical content shapes the server's
	// tools return ("string" / "ImageRef" / ...). Always non-nil.
	ContentShapes []string `json:"content_shapes"`
	// ToolPolicy is the read-only ToolPolicy projection.
	ToolPolicy MCPToolPolicyView `json:"tool_policy"`
	// BindingsSummary is the per-scope binding count rollup. Always
	// non-nil in the wire JSON.
	BindingsSummary []MCPBindingScopeCount `json:"bindings_summary"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerGetResponse is the mcp.servers.get reply — the list-row shape plus per-server detail fields.

type MCPServerHealthRequest

type MCPServerHealthRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
}

MCPServerHealthRequest is the wire shape for mcp.servers.health.

type MCPServerHealthResponse

type MCPServerHealthResponse struct {
	// HandshakeLatencyBuckets is the latency sparkline. Always non-nil.
	HandshakeLatencyBuckets []MCPHealthBucket `json:"handshake_latency_buckets"`
	// ReconnectHistory is the reconnect-history list. Always non-nil.
	ReconnectHistory []MCPReconnect `json:"reconnect_history"`
	// TransportErrorRate is the transport-error rate (errors / minute).
	TransportErrorRate float64 `json:"transport_error_rate"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerHealthResponse is the mcp.servers.health reply.

type MCPServerPolicyRequest

type MCPServerPolicyRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
}

MCPServerPolicyRequest is the wire shape for mcp.servers.policy.

type MCPServerPolicyResponse

type MCPServerPolicyResponse struct {
	// ToolPolicy is the read-only ToolPolicy projection.
	ToolPolicy MCPToolPolicyView `json:"tool_policy"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerPolicyResponse is the mcp.servers.policy reply — the read-only ToolPolicy projection.

type MCPServerProbeRequest

type MCPServerProbeRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
}

MCPServerProbeRequest is the wire shape for mcp.servers.probe — a control-plane verb that runs a transport ping / tools-list round-trip.

type MCPServerProbeResponse

type MCPServerProbeResponse struct {
	// OK reports whether the probe round-trip succeeded.
	OK bool `json:"ok"`
	// LatencyMs is the probe round-trip latency in milliseconds.
	LatencyMs int64 `json:"latency_ms"`
	// Error carries the probe failure message when OK is false.
	Error string `json:"error,omitempty"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerProbeResponse is the mcp.servers.probe reply.

type MCPServerPromptsRequest

type MCPServerPromptsRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
}

MCPServerPromptsRequest is the wire shape for mcp.servers.prompts.

type MCPServerPromptsResponse

type MCPServerPromptsResponse struct {
	// Prompts is the advertised prompt list. Always non-nil.
	Prompts []MCPPromptView `json:"prompts"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerPromptsResponse is the mcp.servers.prompts reply.

type MCPServerRefreshBindingRequest

type MCPServerRefreshBindingRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
	// PrincipalID is the binding principal to (re)connect. Optional —
	// empty drives the flow for the caller's own ScopeUser binding.
	PrincipalID string `json:"principal_id,omitempty"`
}

MCPServerRefreshBindingRequest is the wire shape for mcp.servers.refresh_binding — an admin verb (auth.ScopeAdmin).

type MCPServerRefreshBindingResponse

type MCPServerRefreshBindingResponse struct {
	// AuthorizeURL is the OAuth authorization endpoint URL the Console
	// navigates the popup to. NEVER a token.
	AuthorizeURL string `json:"authorize_url"`
	// State is the opaque flow-state the Console matches against the
	// subsequent tool.auth_completed event.
	State string `json:"state"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerRefreshBindingResponse is the mcp.servers.refresh_binding reply — the AuthorizeURL the Console opens in a popup, plus the flow state for matching the completion event.

type MCPServerRefreshDiscoveryRequest

type MCPServerRefreshDiscoveryRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
}

MCPServerRefreshDiscoveryRequest is the wire shape for mcp.servers.refresh_discovery — a control-plane verb.

type MCPServerRefreshDiscoveryResponse

type MCPServerRefreshDiscoveryResponse struct {
	// DiscoveryID is an opaque id correlating this refresh with the
	// runtime logs.
	DiscoveryID string `json:"discovery_id"`
	// ToolCount / ResourceCount / PromptCount are the post-refresh
	// advertised counts.
	ToolCount     int32 `json:"tool_count"`
	ResourceCount int32 `json:"resource_count"`
	PromptCount   int32 `json:"prompt_count"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerRefreshDiscoveryResponse is the mcp.servers.refresh_discovery reply — the new counts plus a discovery-id for log correlation.

type MCPServerResourcesRequest

type MCPServerResourcesRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
}

MCPServerResourcesRequest is the wire shape for mcp.servers.resources.

type MCPServerResourcesResponse

type MCPServerResourcesResponse struct {
	// Resources is the advertised resource list. Always non-nil.
	Resources []MCPResourceView `json:"resources"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerResourcesResponse is the mcp.servers.resources reply.

type MCPServerRevokeBindingRequest

type MCPServerRevokeBindingRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
	// PrincipalID is the binding principal to revoke. Optional — empty
	// revokes the caller's own ScopeUser binding.
	PrincipalID string `json:"principal_id,omitempty"`
}

MCPServerRevokeBindingRequest is the wire shape for mcp.servers.revoke_binding — an admin verb (auth.ScopeAdmin).

type MCPServerRevokeBindingResponse

type MCPServerRevokeBindingResponse struct {
	// Revoked reports whether a binding was revoked.
	Revoked bool `json:"revoked"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerRevokeBindingResponse is the mcp.servers.revoke_binding reply.

type MCPServerSetRawHTMLTrustRequest

type MCPServerSetRawHTMLTrustRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// Name is the MCP server name. Required.
	Name string `json:"name"`
	// Trusted is the new per-server raw-HTML trust flag value.
	Trusted bool `json:"trusted"`
}

MCPServerSetRawHTMLTrustRequest is the wire shape for mcp.servers.set_raw_html_trust — an admin verb (auth.ScopeAdmin).

type MCPServerSetRawHTMLTrustResponse

type MCPServerSetRawHTMLTrustResponse struct {
	// Name is the MCP server name the flag was set on.
	Name string `json:"name"`
	// Trusted is the persisted raw-HTML trust flag value.
	Trusted bool `json:"trusted"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServerSetRawHTMLTrustResponse is the mcp.servers.set_raw_html_trust reply.

type MCPServerStateView

type MCPServerStateView string

MCPServerStateView is the canonical state chip a Console renders for an MCP server row. The V1 set is closed.

const (
	// MCPStateOnline — the transport is connected and the last
	// discovery / probe succeeded.
	MCPStateOnline MCPServerStateView = "online"
	// MCPStateReconnecting — the transport dropped and the driver is
	// re-establishing the session.
	MCPStateReconnecting MCPServerStateView = "reconnecting"
	// MCPStateOffline — the transport is down (never connected, or
	// closed).
	MCPStateOffline MCPServerStateView = "offline"
	// MCPStateAuthPending — the server requires an OAuth binding that
	// has not been completed.
	MCPStateAuthPending MCPServerStateView = "auth_pending"
	// MCPStateError — the last discovery / probe failed with a
	// transport error.
	MCPStateError MCPServerStateView = "error"
)

The canonical MCP server state values.

type MCPServerView

type MCPServerView struct {
	// Name is the unique MCP server / source id.
	Name string `json:"name"`
	// Transport is the wire transport — "stdio", "http+sse",
	// "streamable-http", or "websocket".
	Transport string `json:"transport"`
	// URLOrCommand is the transport-prefixed endpoint URL (HTTP
	// transports) or the argv-form command string (stdio).
	URLOrCommand string `json:"url_or_command"`
	// State is the canonical state chip.
	State MCPServerStateView `json:"state"`
	// LastDiscoveryAt is the wall-clock instant of the last successful
	// discovery. Zero when discovery has never run.
	LastDiscoveryAt time.Time `json:"last_discovery_at"`
	// ToolCount is the number of tools the server advertises.
	ToolCount int32 `json:"tool_count"`
	// ResourceCount is the number of resources the server advertises.
	ResourceCount int32 `json:"resource_count"`
	// PromptCount is the number of prompts the server advertises.
	PromptCount int32 `json:"prompt_count"`
	// RecentLatencyMs is the most recent observed handshake / probe
	// latency in milliseconds.
	RecentLatencyMs int64 `json:"recent_latency_ms"`
	// ErrorRatePerMin is the transport-error rate over the recent
	// window (errors per minute).
	ErrorRatePerMin float64 `json:"error_rate_per_min"`
	// OAuthBindingCount is the number of OAuth bindings configured for
	// this server.
	OAuthBindingCount int32 `json:"oauth_binding_count"`
	// RawHTMLTrusted reports whether the per-server raw-HTML opt-in flag
	// is set. Default false (default-deny — brief 11 §8).
	RawHTMLTrusted bool `json:"raw_html_trusted"`
}

MCPServerView is the per-row payload returned by mcp.servers.list and (extended) by mcp.servers.get. It is a flat projection of the runtime MCP driver's per-server state — never a re-export of the driver type.

type MCPServersListRequest

type MCPServersListRequest struct {
	// Identity is the mandatory caller identity scope.
	Identity IdentityScope `json:"identity"`
	// State filters to servers in any of the given states. Empty = all.
	State []MCPServerStateView `json:"state,omitempty"`
	// Transport filters to servers on any of the given transports.
	Transport []string `json:"transport,omitempty"`
	// HasOAuth, when set, filters to servers with (true) / without
	// (false) at least one OAuth binding.
	HasOAuth *bool `json:"has_oauth,omitempty"`
	// HasRecentError, when set, filters to servers with (true) /
	// without (false) a recent transport error.
	HasRecentError *bool `json:"has_recent_error,omitempty"`
	// NamePrefix filters to servers whose name has the given prefix.
	NamePrefix string `json:"name_prefix,omitempty"`
	// PageToken is the opaque cursor from a prior response. Empty = the
	// first page.
	PageToken string `json:"page_token,omitempty"`
	// PageSize is the requested maximum row count. Zero = the surface
	// default; the surface clamps to a maximum.
	PageSize int32 `json:"page_size,omitempty"`
}

MCPServersListRequest is the wire shape for mcp.servers.list — a paged, filterable list of the configured MCP southbound servers.

type MCPServersListResponse

type MCPServersListResponse struct {
	// Servers is the page of server rows. Always non-nil in the wire
	// JSON (an empty list is `[]`, never `null`).
	Servers []MCPServerView `json:"servers"`
	// NextPageToken is the cursor for the next page, or empty when this
	// is the last page.
	NextPageToken string `json:"next_page_token,omitempty"`
	// ProtocolVersion is the pinned Harbor Protocol version.
	ProtocolVersion string `json:"protocol_version"`
}

MCPServersListResponse is the mcp.servers.list reply.

type MCPToolPolicyView

type MCPToolPolicyView struct {
	// TimeoutMs is the per-invocation timeout in milliseconds.
	TimeoutMs int64 `json:"timeout_ms"`
	// MaxRetries is the retry cap.
	MaxRetries int32 `json:"max_retries"`
	// ConcurrencyCap is the per-server concurrent-invocation cap. Zero
	// means unbounded.
	ConcurrencyCap int32 `json:"concurrency_cap"`
}

MCPToolPolicyView is the read-only projection of an MCP server's ToolPolicy (D-024). It is read-only at V1 (policy editing is post-V1).

type MemoryAggregates

type MemoryAggregates struct {
	// Total is the total record count across the filtered set.
	Total int64 `json:"total"`
	// ExpiringIn1h is the count of records whose ExpiresAt falls
	// within (now, now+1h].
	ExpiringIn1h int64 `json:"expiring_in_1h"`
	// IdentityRejected24h is the count of `memory.identity_rejected`
	// events (D-033) observed in the last 24 hours.
	IdentityRejected24h int64 `json:"identity_rejected_24h"`
	// RecoveryDropped24h is the count of `memory.recovery_dropped`
	// events (D-035) observed in the last 24 hours. The shipped wire
	// string is `memory.recovery_dropped` — page-memory.md §12 names a
	// mockup-refinement `memory.overflow_drop_oldest`; this phase uses
	// the shipped constant (see the phase plan "Findings I'm departing
	// from").
	RecoveryDropped24h int64 `json:"recovery_dropped_24h"`
}

MemoryAggregates carries the page-level counters the Memory page's sub-header strip renders. The 24-h-window counters derive from `events.aggregate` (Phase 72a) over the `memory.*` event types — runtime-side computation per brief 11 §CC-4.

type MemoryArtifactRef

type MemoryArtifactRef struct {
	// ID is the content-addressed identifier (`{namespace}_{sha256[:12]}`).
	ID string `json:"id"`
	// MimeType is the IANA media type, when known.
	MimeType string `json:"mime_type,omitempty"`
	// SizeBytes is the length of the referenced bytes.
	SizeBytes int64 `json:"size_bytes,omitempty"`
	// Filename is metadata only (never used for path construction).
	Filename string `json:"filename,omitempty"`
	// SHA256 is the full hex digest of the referenced bytes.
	SHA256 string `json:"sha256,omitempty"`
}

MemoryArtifactRef is the by-reference shape `memory.get` returns when the record's value serialised size meets or exceeds the configured heavy-content threshold (D-026). It mirrors a subset of `internal/artifacts.ArtifactRef` but is a flat wire type — the Protocol owns its vocabulary; runtime Go structs never leak (RFC §5.1 / CLAUDE.md §13 single-source rule). It is the same flat shape `PauseArtifactRef` / `SearchArtifactRef` use, kept as a distinct type so a future divergence in either surface does not whipsaw the other.

type MemoryDeleteRequest added in v1.3.0

type MemoryDeleteRequest struct {
	// Identity is the request's identity scope. The triple is mandatory.
	Identity IdentityScope `json:"identity"`
	// Key is the memory turn key to evict — a value carried on a
	// `MemoryItem.Key` returned by `memory.list`.
	Key string `json:"key"`
}

MemoryDeleteRequest is the wire request for the `memory.delete` method (Phase 108n / D-186) — the admin-gated, audited "evict a memory turn" mutation. Identity is mandatory; admin scope is required (D-079).

type MemoryDeleteResponse added in v1.3.0

type MemoryDeleteResponse struct {
	// Deleted is true when the keyed turn was found and evicted.
	Deleted bool `json:"deleted"`
	// RemainingTurns is the turn count remaining in the session record
	// after the eviction (the Console re-reads the list to refresh).
	RemainingTurns int `json:"remaining_turns"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

MemoryDeleteResponse is the wire response for the `memory.delete` method.

type MemoryDriverName

type MemoryDriverName string

MemoryDriverName is the typed enum of the three V1 persistence drivers a `memory.list` filter facet accepts. The set matches the persistence triad (in-memory / SQLite / Postgres) every persistence- shaped subsystem ships at V1 (CLAUDE.md §9).

const (
	MemoryDriverInmem    MemoryDriverName = "inmem"
	MemoryDriverSQLite   MemoryDriverName = "sqlite"
	MemoryDriverPostgres MemoryDriverName = "postgres"
)

Canonical V1 memory-driver names.

type MemoryFilter

type MemoryFilter struct {
	// TenantIDs narrows to a tenant set; empty = the caller's own
	// tenant. A foreign tenant OR len>1 requires auth.ScopeAdmin
	// (D-079 closed set).
	TenantIDs []string `json:"tenant_ids,omitempty"`
	// UserIDs narrows to a user set within the visible tenants.
	UserIDs []string `json:"user_ids,omitempty"`
	// SessionIDs narrows to a session set.
	SessionIDs []string `json:"session_ids,omitempty"`
	// AgentIDs narrows to records produced by a given agent set. NOT
	// an isolation filter (CLAUDE.md §6 clarifying note).
	AgentIDs []string `json:"agent_ids,omitempty"`
	// Scopes narrows to a subset of ["session", "user", "tenant"].
	// Each value must be a canonical MemoryScope.
	Scopes []string `json:"scopes,omitempty"`
	// Drivers narrows to a subset of ["inmem", "sqlite", "postgres"].
	// Each value must be a canonical MemoryDriverName.
	Drivers []string `json:"drivers,omitempty"`
	// Strategies narrows to a subset of the V1 MemoryStrategyName set.
	Strategies []string `json:"strategies,omitempty"`
	// HasTTLExpiring, when true, narrows to records whose ExpiresAt
	// falls within (now, now+1h].
	HasTTLExpiring bool `json:"has_ttl_expiring,omitempty"`
	// ContentSearch is an optional substring matched against the
	// post-redaction record value text. The match is runtime-side
	// (brief 11 §CC-4) — never a Console-side scan over an exported
	// snapshot.
	ContentSearch string `json:"content_search,omitempty"`
}

MemoryFilter narrows the `memory.list` response. An empty filter means "the caller's own identity scope, every record." Supplying a `TenantIDs` value that reaches OUTSIDE the caller's own tenant (or names more than one tenant) requires the `auth.ScopeAdmin` (or `auth.ScopeConsoleFleet`) scope claim from the D-079 closed two-scope set; a missing-claim cross-tenant request is rejected loudly with `CodeIdentityScopeRequired` (HTTP 403) — NEVER silently downgraded to an empty result set. There is NO dedicated memory scope: cross-tenant memory listing gates on the same closed set every other Stage-2 page uses (audit B1 resolution).

type MemoryGetRequest

type MemoryGetRequest struct {
	// Identity is the request's identity scope. The triple is
	// mandatory; an incomplete triple fails closed with
	// CodeIdentityRequired (401).
	Identity IdentityScope `json:"identity"`
	// Key is the memory record key — the value carried on a
	// `MemoryItem.Key` returned by `memory.list`.
	Key string `json:"key"`
}

MemoryGetRequest is the wire request for the `memory.get` method.

type MemoryGetResponse

type MemoryGetResponse struct {
	// Detail is the full record detail.
	Detail MemoryItemDetail `json:"detail"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

MemoryGetResponse is the wire response for the `memory.get` method.

type MemoryHealthAggregate

type MemoryHealthAggregate struct {
	// Total is the total memory-record count for the caller's scope.
	Total int64 `json:"total"`
	// ExpiringIn1h is the count of records whose TTL expires within
	// the next hour.
	ExpiringIn1h int64 `json:"expiring_in_1h"`
	// IdentityRejected24h is the count of `memory.identity_rejected`
	// events (D-033) observed in the last 24 hours.
	IdentityRejected24h int64 `json:"identity_rejected_24h"`
	// RecoveryDropped24h is the count of `memory.recovery_dropped`
	// events (D-035) observed in the last 24 hours.
	RecoveryDropped24h int64 `json:"recovery_dropped_24h"`
	// DriverByScope maps each memory scope to the persistence driver
	// backing it — e.g. {"session":"inmem", "tenant":"postgres"}. The
	// driver-comparison rollup the Memory page renders.
	DriverByScope map[string]string `json:"driver_by_scope"`
}

MemoryHealthAggregate carries the aggregate memory-health counters the Memory page's right-rail Memory-health card renders. The 24-h- window counters derive from `events.aggregate` (Phase 72a) over the `memory.*` event types — runtime-side computation per brief 11 §CC-4.

type MemoryHealthRequest

type MemoryHealthRequest struct {
	// Identity is the request's identity scope. The triple is
	// mandatory; an incomplete triple fails closed with
	// CodeIdentityRequired (401).
	Identity IdentityScope `json:"identity"`
}

MemoryHealthRequest is the wire request for the `memory.health` method. The identity is read from ctx; the body Identity is the Phase 60 carrier-header echo, defended against the verified identity.

type MemoryHealthResponse

type MemoryHealthResponse struct {
	// Aggregate carries the aggregate health counters.
	Aggregate MemoryHealthAggregate `json:"aggregate"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

MemoryHealthResponse is the wire response for the `memory.health` method.

type MemoryItem

type MemoryItem struct {
	// Key is the memory record key — a deterministic per-record
	// identifier the Console passes back to `memory.get`. A client
	// never constructs or parses it.
	Key string `json:"key"`
	// Strategy is the memory strategy this record was produced under —
	// one of the MemoryStrategyName values.
	Strategy string `json:"strategy"`
	// Scope is the record's scope — "session" | "user" | "tenant".
	Scope string `json:"scope"`
	// Identity is the (tenant, user, session [, run]) the record lives
	// under. Flat strings — never a re-export of the runtime identity
	// quadruple.
	Identity IdentityScope `json:"identity"`
	// AgentID is the registration identity of the agent that produced
	// the record, when known. NOT an isolation principal (CLAUDE.md §6
	// clarifying note) — surfaced for the Owner column only.
	AgentID string `json:"agent_id,omitempty"`
	// CreatedAt is the wall-clock time the record was first written.
	CreatedAt time.Time `json:"created_at"`
	// LastUpdatedAt is the wall-clock time the record was last touched.
	LastUpdatedAt time.Time `json:"last_updated_at"`
	// ExpiresAt is the record's TTL expiry; the zero value (omitted)
	// means the record has no TTL.
	ExpiresAt time.Time `json:"expires_at,omitempty"`
	// SizeBytes is the byte length of the record's post-redaction
	// value. A count only — the bytes themselves are never inlined on
	// this row shape.
	SizeBytes int64 `json:"size_bytes"`
	// HeavyContent is true when SizeBytes meets or exceeds the D-026
	// heavy-content threshold; the Console renders a heavy-content icon
	// and `memory.get` returns a `MemoryArtifactRef` for the value.
	HeavyContent bool `json:"heavy_content,omitempty"`
	// Driver is the persistence driver backing this record —
	// "inmem" | "sqlite" | "postgres".
	Driver string `json:"driver"`
}

MemoryItem is one row in the Memory page's main table — the wire projection of a single memory record. Heavy values are NEVER inlined on this row shape: a row carries the `SizeBytes` count and the `HeavyContent` flag, and the Console calls `memory.get` for the per-item detail (which produces an `MemoryArtifactRef` above the heavy-content threshold per D-026). Cross-package single source per CLAUDE.md §8 + D-002; the typed Protocol client (D-093) regenerates from this without hand-editing.

D-065 invariant: there is NO `Priority` field. The `Pinned` strategy overlay chip is a Phase 24 strategy, not a session-level priority dimension — no priority surfaces on a memory row, ever.

type MemoryItemDetail

type MemoryItemDetail struct {
	// Item is the row-shaped projection of the record (the same shape
	// `memory.list` returns).
	Item MemoryItem `json:"item"`
	// Value is the post-redaction record value, populated ONLY when
	// SizeBytes is below the heavy-content threshold (D-026).
	Value []byte `json:"value,omitempty"`
	// ValueArtifact is populated when SizeBytes meets or exceeds the
	// heavy-content threshold (D-026). The Console fetches the bytes
	// via `artifacts.get` against this stub. When ValueArtifact is set,
	// Value is nil — and vice-versa.
	ValueArtifact *MemoryArtifactRef `json:"value_artifact,omitempty"`
	// Metadata carries the per-record metadata.
	Metadata MemoryMetadata `json:"metadata"`
}

MemoryItemDetail is the `memory.get` result. EXACTLY ONE of `Value` / `ValueArtifact` is populated; never both. Above the heavy-content threshold (D-026), `Value` is empty and `ValueArtifact` carries the by-reference stub; below it, `Value` carries the post-redaction bytes and `ValueArtifact` is nil. A driver that returns raw heavy bytes is a leak — the runtime fails loudly rather than inlining them.

type MemoryListRequest

type MemoryListRequest struct {
	// Identity is the request's identity scope. The triple is
	// mandatory; an incomplete triple fails the request closed at the
	// Protocol edge with CodeIdentityRequired (401).
	Identity IdentityScope `json:"identity"`
	// Filter narrows the listed records. Empty filter = the caller's
	// own identity scope, every record.
	Filter MemoryFilter `json:"filter,omitempty"`
	// Page is the 1-based page number; defaults to 1 when zero. A
	// negative Page is rejected with CodeInvalidRequest (400).
	Page int `json:"page,omitempty"`
	// PageSize is the per-page row count. Defaults to
	// DefaultMemoryListPageSize (50) when zero; values above
	// MaxMemoryListPageSize (200) — or negative — are rejected with
	// CodeInvalidRequest (400). Never silently clamped.
	PageSize int `json:"page_size,omitempty"`
}

MemoryListRequest is the wire request for the `memory.list` method.

Identity is mandatory at the Protocol edge per RFC §5.5 — the request flows out of an auth-verified identity in ctx, never trusted from the body. The `Identity` field exists for the Phase 60 trust-based carrier-header posture and for body-side echo; the memory-list handler reads the verified identity from ctx (preferred) and defends the body identity against it.

type MemoryListResponse

type MemoryListResponse struct {
	// Items is the page of memory records, ordered LastUpdatedAt
	// descending (newest first) for a deterministic table.
	Items []MemoryItem `json:"items"`
	// Page is the 1-based page number this response covers.
	Page int `json:"page"`
	// PageSize is the per-page row count applied.
	PageSize int `json:"page_size"`
	// PageCount is the total number of pages over the filtered set.
	PageCount int `json:"page_count"`
	// TotalRows is the total filtered row count across all pages.
	TotalRows int `json:"total_rows"`
	// Aggregates carries the page-level counters.
	Aggregates MemoryAggregates `json:"aggregates"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

MemoryListResponse is the wire response for the `memory.list` method.

type MemoryMetadata

type MemoryMetadata struct {
	// TTL is the record's configured time-to-live. The zero value
	// means the record has no TTL.
	TTL time.Duration `json:"ttl,omitempty"`
	// StrategyConfig is the bounded, strategy-named knob map surfaced
	// for the right-rail detail (e.g. budget tokens for `truncation`).
	StrategyConfig map[string]string `json:"strategy_config,omitempty"`
	// RelatedEventIDs are the recent event IDs touching this record's
	// key — for the right-rail "Inspect related events" deep-link.
	RelatedEventIDs []string `json:"related_event_ids,omitempty"`
}

MemoryMetadata carries the per-record metadata the Memory page's right-rail Selected-item-detail card renders.

type MemoryPutRequest added in v1.3.0

type MemoryPutRequest struct {
	// Identity is the request's identity scope. The triple is mandatory.
	Identity IdentityScope `json:"identity"`
	// Turn is the conversation turn to append.
	Turn MemoryTurnInput `json:"turn"`
}

MemoryPutRequest is the wire request for the `memory.put` method (Phase 108n / D-186) — the admin-gated, audited "add a memory turn" mutation. Identity is mandatory; admin scope is required (D-079).

type MemoryPutResponse added in v1.3.0

type MemoryPutResponse struct {
	// Key is the deterministic key of the appended turn — the value a
	// subsequent `memory.get` resolves.
	Key string `json:"key"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

MemoryPutResponse is the wire response for the `memory.put` method.

type MemoryScope

type MemoryScope string

MemoryScope is the typed enum of the three memory-record scopes the `memory.list` filter accepts. Memory is session-scoped by default (CLAUDE.md §6 rule 4); user- and tenant-scoped records exist only through an explicit declared promotion policy. The Protocol owns its own vocabulary (RFC §5.1 / CLAUDE.md §13 single-source rule) — this wire enum never re-exports a runtime Go type.

const (
	MemoryScopeSession MemoryScope = "session"
	MemoryScopeUser    MemoryScope = "user"
	MemoryScopeTenant  MemoryScope = "tenant"
)

Canonical memory-record scopes. The set is closed.

type MemoryStrategyName

type MemoryStrategyName string

MemoryStrategyName is the typed enum of the memory strategies a `memory.list` filter facet accepts. The three V1 values map onto the runtime-side `memory.Strategy` taxonomy (Phase 24); the overlay-chip names (`pinned`, `episodic`, `recent`, `persistent`) are reserved for post-V1 strategies and intentionally NOT in the closed set — a filter naming an unshipped strategy is rejected with CodeInvalidRequest, not silently dropped.

const (
	MemoryStrategyNone           MemoryStrategyName = "none"
	MemoryStrategyTruncation     MemoryStrategyName = "truncation"
	MemoryStrategyRollingSummary MemoryStrategyName = "rolling_summary"
)

Canonical V1 memory-strategy names — the wire projection of the `memory.Strategy` taxonomy shipped at Phase 24.

type MemoryStrategyTrace added in v1.3.0

type MemoryStrategyTrace struct {
	// Strategy is the configured memory strategy — one of the
	// MemoryStrategyName values.
	Strategy string `json:"strategy"`
	// Summary is the rolling-summary text the strategy injects into the
	// planner's LLM call — the compaction OUTPUT. Empty under `none` /
	// `truncation` (which keep no rolling summary) or before any
	// compaction has occurred.
	Summary string `json:"summary"`
	// RecentTurnCount is the number of conversation turns the strategy
	// currently keeps verbatim (NOT folded into the summary).
	RecentTurnCount int `json:"recent_turn_count"`
	// EstimatedTokens is the strategy's current estimate of the tokens
	// `GetLLMContext` would inject — the planner compares this against its
	// context-window budget.
	EstimatedTokens int `json:"estimated_tokens"`
	// Health is the memory FSM health state for this identity —
	// "healthy" | "degraded" | "recovering".
	Health string `json:"health"`
}

MemoryStrategyTrace is the wire projection of how the configured memory strategy is compacting the caller's session memory RIGHT NOW (Phase 108n / D-186). It is the honest, read-only projection of the strategy's live `GetLLMContext` + `Health` output — NOT a fabricated per-step "selection with rejections" (the `rolling_summary` strategy summarises; it does not select-and-reject candidates). Every field is real runtime state; an empty session projects an empty trace, never a synthesised one (CLAUDE.md §13).

type MemoryStrategyTraceRequest added in v1.3.0

type MemoryStrategyTraceRequest struct {
	// Identity is the request's identity scope. The triple is mandatory;
	// an incomplete triple fails closed with CodeIdentityRequired (401).
	Identity IdentityScope `json:"identity"`
}

MemoryStrategyTraceRequest is the wire request for the `memory.strategy_trace` method (Phase 108n / D-186). Identity is mandatory; the verified identity in ctx is preferred and the body Identity is defended against it.

type MemoryStrategyTraceResponse added in v1.3.0

type MemoryStrategyTraceResponse struct {
	// Trace is the live strategy-compaction projection.
	Trace MemoryStrategyTrace `json:"trace"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

MemoryStrategyTraceResponse is the wire response for the `memory.strategy_trace` method.

type MemoryTurnInput added in v1.3.0

type MemoryTurnInput struct {
	// UserMessage is the turn's user message text.
	UserMessage string `json:"user_text"`
	// AssistantResponse is the turn's assistant response text.
	AssistantResponse string `json:"assistant_text"`
}

MemoryTurnInput is the operator-supplied conversation turn the `memory.put` admin method appends (Phase 108n / D-186). It carries only the user / assistant text — never trajectory internals; the runtime owns the timestamp.

type MetricsSnapshot

type MetricsSnapshot struct {
	// Counters is the flat counter-metric slice.
	Counters []NamedCounter `json:"counters"`
	// Histograms is the flat histogram-metric slice.
	Histograms []NamedHistogram `json:"histograms"`
	// Gauges is the flat gauge-metric slice.
	Gauges []NamedGauge `json:"gauges"`
	// SnapshotAt is the unix-millis timestamp the metrics were read.
	SnapshotAt int64 `json:"snapshot_at"`
}

MetricsSnapshot is the metrics.snapshot response: a Protocol-shaped projection over the Phase 56 telemetry.MetricsRegistry. The wire shape is a flat slice per metric kind — counters, histograms, gauges — carrying plain numbers. NO OpenTelemetry SDK type crosses the Protocol boundary (RFC §5.1 / CLAUDE.md §13 single-source rule).

func (MetricsSnapshot) HasHighCardinalityLabel

func (m MetricsSnapshot) HasHighCardinalityLabel() (metric, label string, found bool)

HasHighCardinalityLabel reports the first (metric-name, label-key) pair in the snapshot that carries a forbidden high-cardinality label key, or empty strings + false when the snapshot is clean. It is the `cardinalitylint`-style guard for the metrics.snapshot wire boundary: a projection that lets a `run_id` / `trace_id` / `span_id` label reach the wire is a cardinality-explosion bug.

type NamedCounter

type NamedCounter struct {
	// Name is the metric name.
	Name string `json:"name"`
	// Value is the counter's current value.
	Value float64 `json:"value"`
	// Labels carries the metric's low-cardinality label set. A
	// high-cardinality label (run_id / trace_id / span_id) never appears
	// here — the Phase 56 cardinality firewall gates it on the SDK side,
	// and MetricsSnapshot.HasHighCardinalityLabel is the wire-boundary
	// cardinalitylint guard (exercised by the posture type tests).
	Labels map[string]string `json:"labels,omitempty"`
}

NamedCounter is one counter metric in a MetricsSnapshot: a name, its current monotonic value, and its low-cardinality labels.

type NamedGauge

type NamedGauge struct {
	// Name is the metric name.
	Name string `json:"name"`
	// Value is the gauge's current value.
	Value float64 `json:"value"`
	// Labels carries the metric's low-cardinality label set.
	Labels map[string]string `json:"labels,omitempty"`
}

NamedGauge is one gauge metric in a MetricsSnapshot.

type NamedHistogram

type NamedHistogram struct {
	// Name is the metric name.
	Name string `json:"name"`
	// Count is the total observation count.
	Count uint64 `json:"count"`
	// Sum is the sum of all observed values.
	Sum float64 `json:"sum"`
	// Buckets is the cumulative per-bucket count slice.
	Buckets []HistogramBucket `json:"buckets,omitempty"`
	// Labels carries the metric's low-cardinality label set.
	Labels map[string]string `json:"labels,omitempty"`
}

NamedHistogram is one histogram metric in a MetricsSnapshot.

type PauseArtifactRef

type PauseArtifactRef struct {
	// ID is the content-addressed identifier (`{namespace}_{sha256[:12]}`).
	ID string `json:"id"`
	// MimeType is the IANA media type, when known.
	MimeType string `json:"mime_type,omitempty"`
	// SizeBytes is the length of the referenced bytes.
	SizeBytes int64 `json:"size_bytes,omitempty"`
	// Filename is metadata only (never used for path construction).
	Filename string `json:"filename,omitempty"`
	// SHA256 is the full hex digest of the referenced bytes.
	SHA256 string `json:"sha256,omitempty"`
}

PauseArtifactRef is the by-reference shape a `PauseSnapshot` carries when the pause record's `Payload` serialised size meets or exceeds the configured heavy-content threshold (D-026). It mirrors a subset of `internal/artifacts.ArtifactRef` but is a flat wire type — the Protocol owns its vocabulary; runtime Go structs never leak (RFC §5.1 / CLAUDE.md §13 single-source rule). It is the same flat shape `SearchResultRow.Ref` (`SearchArtifactRef`) uses, kept as a distinct type so a future divergence in either surface does not whipsaw the other.

type PauseFilter

type PauseFilter struct {
	// Status filters by lifecycle state; empty defaults to ["paused"].
	// Each value must be a canonical PauseSnapshotState.
	Status []string `json:"status,omitempty"`
	// TenantIDs narrows to a tenant set; empty defaults to the
	// caller's own tenant. A foreign tenant OR len>1 requires admin.
	TenantIDs []string `json:"tenant_ids,omitempty"`
	// UserIDs narrows to a user set within the visible tenants.
	UserIDs []string `json:"user_ids,omitempty"`
	// SessionIDs narrows to a session set.
	SessionIDs []string `json:"session_ids,omitempty"`
	// RunIDs narrows to a run set.
	RunIDs []string `json:"run_ids,omitempty"`
	// Reasons narrows to one or more canonical pause reasons.
	Reasons []string `json:"reasons,omitempty"`
	// Since is an optional lower bound on PausedAt (inclusive).
	Since time.Time `json:"since,omitempty"`
	// Until is an optional upper bound on PausedAt (inclusive).
	Until time.Time `json:"until,omitempty"`
}

PauseFilter narrows the `pause.list` response. An empty filter means "the caller's own identity scope, status=paused" — the intervention-queue default. Supplying a `TenantIDs` value that reaches OUTSIDE the caller's own tenant (or naming more than one tenant) requires the `auth.ScopeAdmin` scope claim (D-079); a missing-claim cross-tenant request is rejected loudly with `CodeIdentityScopeRequired` (HTTP 403) — NEVER silently downgraded to an empty result set.

type PauseListRequest

type PauseListRequest struct {
	// Identity is the request's identity scope. The triple is
	// mandatory; an incomplete triple fails the request closed at the
	// Protocol edge with CodeIdentityRequired (401).
	Identity IdentityScope `json:"identity"`
	// Filter narrows the snapshot. Empty filter = caller's own
	// identity scope, status=paused.
	Filter PauseFilter `json:"filter,omitempty"`
	// Page is the 1-based page number; defaults to 1 when zero. A
	// negative Page is rejected with CodeInvalidRequest (400).
	Page int `json:"page,omitempty"`
	// PageSize is the per-page row count. Defaults to
	// DefaultPauseListPageSize (50) when zero; values above
	// MaxPauseListPageSize (200) — or negative — are rejected with
	// CodeInvalidRequest (400). Never silently clamped.
	PageSize int `json:"page_size,omitempty"`
}

PauseListRequest is the wire request for the `pause.list` method.

Identity is mandatory at the Protocol edge per RFC §5.5 — the request flows out of an auth-verified identity in ctx, never trusted from the body. The `Identity` field exists for the Phase 60 trust-based carrier-header posture and for body-side echo; the pause-list handler reads the verified identity from ctx (preferred) and defends the body identity against it.

type PauseListResponse

type PauseListResponse struct {
	// Snapshots is the page of pause records, ordered PausedAt
	// descending (newest first) for a deterministic intervention
	// queue.
	Snapshots []PauseSnapshot `json:"snapshots"`
	// Page is the 1-based page number this response covers.
	Page int `json:"page"`
	// PageSize is the per-page row count applied.
	PageSize int `json:"page_size"`
	// PageCount is the total number of pages over the filtered set.
	PageCount int `json:"page_count"`
	// TotalRows is the total filtered row count across all pages.
	TotalRows int `json:"total_rows"`
	// Truncated is true when a status=resumed filter aged out beyond
	// the in-memory registry's retention. The Coordinator's
	// resumed-records retention is bounded by the destructive-on-resume
	// contract (Phase 50 / coordinator.go) — a resumed Token is
	// queryable only until the Coordinator clears it. Operators
	// inspecting historical resume activity should use
	// `events.subscribe` on the `pause.resumed` topic instead.
	Truncated bool `json:"truncated,omitempty"`
}

PauseListResponse is the wire response for the `pause.list` method.

type PauseSnapshot

type PauseSnapshot struct {
	// Token is the opaque runtime-issued pause Token (RFC §6.3). A
	// client never constructs or parses it; it is the handle the
	// Phase 54 `resume` / `approve` / `reject` methods take.
	Token string `json:"token"`
	// Reason is one of the four canonical pause reasons (RFC §6.3).
	Reason string `json:"reason"`
	// State is the lifecycle state — "paused" or "resumed".
	State PauseSnapshotState `json:"state"`
	// Identity is the (tenant, user, session [, run]) the pause was
	// recorded under. Flat strings — never a re-export of the runtime
	// identity quadruple.
	Identity IdentityScope `json:"identity"`
	// PausedAt is the wall-clock time the pause was recorded.
	PausedAt time.Time `json:"paused_at"`
	// ResumedAt is the wall-clock time Resume was called; the zero
	// value (omitted) unless State == "resumed".
	ResumedAt time.Time `json:"resumed_at,omitempty"`
	// Payload is the sanitised pause payload INLINE when its serialised
	// size is below the heavy-content threshold. Otherwise the runtime
	// routes it through the ArtifactStore and ships PayloadRef instead
	// (D-026 — context-window safety net applied to Protocol snapshots).
	// Exactly one of Payload / PayloadRef is populated for a pause
	// carrying a payload; both are empty for a payload-free pause.
	Payload map[string]any `json:"payload,omitempty"`
	// PayloadRef is populated when the pause record's Payload exceeded
	// the heavy-content threshold (D-026). The Console fetches the
	// bytes via `artifacts.get` / `artifacts.get_ref` when it wants
	// them. When PayloadRef is set, Payload is nil.
	PayloadRef *PauseArtifactRef `json:"payload_ref,omitempty"`
}

PauseSnapshot is the wire projection of a single Coordinator pause record. Cross-package single source per CLAUDE.md §8 + D-002; the typed Protocol client (D-093) regenerates from this without hand-editing.

type PauseSnapshotState

type PauseSnapshotState string

PauseSnapshotState is the typed enum of pause-record lifecycle states the `pause.list` snapshot projects. It is the wire projection of the runtime-internal `pauseresume.State`; the Protocol owns its own vocabulary (RFC §5.1 / CLAUDE.md §13 single-source rule) so the wire shape never re-exports a runtime Go type.

const (
	PauseStatePaused  PauseSnapshotState = "paused"
	PauseStateResumed PauseSnapshotState = "resumed"
)

Canonical pause-snapshot states. The set is closed — a pause record is either still parked or already resumed.

type RateLimitView

type RateLimitView struct {
	// Capacity is the bucket ceiling (max reservable tokens). 0 disables
	// the rate limit even if the refill knobs are set.
	Capacity int `json:"capacity"`
	// RefillTokens are added to the bucket every refill tick.
	RefillTokens int `json:"refill_tokens"`
	// RefillIntervalMS is the refill tick duration in milliseconds. The
	// Go side holds a time.Duration; this is its millisecond projection.
	RefillIntervalMS int64 `json:"refill_interval_ms"`
}

RateLimitView is the wire projection of a tier's token-bucket configuration. The internal `governance.RateLimitConfig` carries a `time.Duration` for the refill interval; the wire type carries the equivalent milliseconds as an int64 so the JSON is unambiguous across language clients (a `time.Duration` marshals as a raw nanosecond integer, which a non-Go client cannot interpret).

type RunOverrides

type RunOverrides struct {
	// SessionID is the session the override applies to. Mandatory — an
	// empty SessionID fails the request closed at the Protocol edge
	// (identity is mandatory, CLAUDE.md §6 rule 9). The tenant and user
	// components of the isolation triple are inferred from the verified
	// JWT; only the session is named on the wire.
	SessionID string `json:"session_id"`
	// ReasoningEffort, when non-nil, overrides the LLM reasoning-effort
	// hint for the next message. Values follow the bound LLM provider's
	// taxonomy (e.g. `low` / `medium` / `high`); the runtime validates
	// the string against the provider's accepted set and rejects an
	// unknown value with CodeInvalidRequest.
	ReasoningEffort *string `json:"reasoning_effort,omitempty"`
	// Temperature, when non-nil, overrides the sampling temperature for
	// the next message. The runtime rejects a value outside the closed
	// range [0, 2] with CodeInvalidRequest.
	Temperature *float64 `json:"temperature,omitempty"`
	// MaxTokens, when non-nil, overrides the per-message MaxTokens
	// governance ceiling for the next message. The runtime rejects a
	// non-positive value with CodeInvalidRequest.
	MaxTokens *int `json:"max_tokens,omitempty"`
	// SystemPromptOverride, when non-nil, replaces the agent's system
	// prompt for the next message only. An empty string is a valid
	// override (it clears the system prompt for that one message);
	// nil means "leave the agent's configured system prompt in place".
	SystemPromptOverride *string `json:"system_prompt_override,omitempty"`
}

RunOverrides is the wire projection of the next-message override parameters the Console Playground page records via `runs.set_overrides`.

Every tuning field is a pointer so the absent / present distinction is preserved on the wire: a nil field means "leave the runtime default in place"; a non-nil field means "apply this value to the next message". This is deliberate — an operator who sets only reasoning effort must not implicitly zero the temperature.

The override is session-scoped and one-shot: it applies to the NEXT `user_message` / `start` in the session and is consumed at that point. It does NOT apply retroactively to past messages.

type RunSetOverridesRequest

type RunSetOverridesRequest struct {
	// Identity is the request's identity scope. The triple is mandatory;
	// the runtime cross-checks Identity.Session against
	// Overrides.SessionID and rejects a mismatch with CodeScopeMismatch
	// (a caller cannot set an override for a session outside its own
	// verified scope).
	Identity IdentityScope `json:"identity"`
	// Overrides is the next-message override payload.
	Overrides RunOverrides `json:"overrides"`
}

RunSetOverridesRequest is the wire request for the `runs.set_overrides` Protocol method. It carries the request's identity scope plus the override payload.

type RunSetOverridesResponse

type RunSetOverridesResponse struct {
	// AppliedAt is the runtime timestamp at which the override was
	// recorded. It is the moment the override entered the session's
	// pending-override slot — not the moment a subsequent message
	// consumed it.
	AppliedAt time.Time `json:"applied_at"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// with, so a Console can assert wire compatibility.
	ProtocolVersion string `json:"protocol_version"`
}

RunSetOverridesResponse is the wire response for the `runs.set_overrides` Protocol method.

type RuntimeCounters

type RuntimeCounters struct {
	// EventsPerSecond is the recent bus-emit rate.
	EventsPerSecond float64 `json:"events_per_second"`
	// TasksRunning is the count of foreground/background tasks
	// currently in a running state.
	TasksRunning int64 `json:"tasks_running"`
	// BackgroundJobsActive is the count of background jobs in flight.
	BackgroundJobsActive int64 `json:"background_jobs_active"`
	// MCPConnectionsHealthy is the count of healthy MCP southbound
	// connections.
	MCPConnectionsHealthy int64 `json:"mcp_connections_healthy"`
	// SessionsActive is the count of currently-active sessions.
	SessionsActive int64 `json:"sessions_active"`
	// SnapshotAt is the unix-millis timestamp the counters were read.
	SnapshotAt int64 `json:"snapshot_at"`
}

RuntimeCounters is the runtime.counters response: the low-cardinality live counters the Console footer / sidebar chips render. Every field is a roll-up — never a per-run / per-task / per-session breakdown (the Phase 56 cardinality firewall posture, mirrored at the Protocol boundary).

type RuntimeDrivers

type RuntimeDrivers struct {
	// Subsystems is the per-subsystem driver slice.
	Subsystems []SubsystemDriver `json:"subsystems"`
}

RuntimeDrivers is the runtime.drivers response: the configured driver names per persistence-shaped subsystem so an operator can see whether the Runtime is dev (in-mem) or production (Postgres) without grepping config.

type RuntimeHealth

type RuntimeHealth struct {
	// Subsystems is the per-subsystem readiness slice — one entry per
	// subsystem the runtime knows about.
	Subsystems []SubsystemHealth `json:"subsystems"`
}

RuntimeHealth is the runtime.health response: a per-subsystem readiness rollup across the runtime's registered subsystems.

type RuntimeInfo

type RuntimeInfo struct {
	// InstanceID is a stable per-deployment identifier minted at boot.
	// A Console managing several Runtimes keys each attachment by it.
	InstanceID string `json:"instance_id"`
	// DisplayName is the operator-configured friendly name for this
	// Runtime. Empty when the operator configured none — never the
	// host's machine name without explicit operator config.
	DisplayName string `json:"display_name,omitempty"`
	// BuildVersion is the Harbor build version string (e.g. a release
	// tag or a `v0.0.0-dev` dev marker).
	BuildVersion string `json:"build_version"`
	// BuildCommit is the VCS revision the binary was built from, or
	// "unknown" when the build carried no VCS stamp.
	BuildCommit string `json:"build_commit"`
	// BuildDate is the build timestamp (RFC 3339), or empty when the
	// build carried no date stamp.
	BuildDate string `json:"build_date,omitempty"`
	// BuildGoVersion is the Go toolchain version the binary was built
	// with.
	BuildGoVersion string `json:"build_go_version"`
	// ProtocolVersion is the pinned Harbor Protocol version the Runtime
	// speaks (the ProtocolVersion constant). A client parses it and
	// checks Version.Compatible against its own.
	ProtocolVersion string `json:"protocol_version"`
	// Capabilities is the set of Protocol surfaces the Runtime
	// advertises as live — the same set CurrentHandshake() carries.
	Capabilities []Capability `json:"capabilities"`
	// UptimeSeconds is the number of whole seconds since the Runtime
	// process started.
	UptimeSeconds int64 `json:"uptime_seconds"`
}

RuntimeInfo is the runtime.info response: the Runtime's build identity, Protocol version, advertised capabilities, uptime, and operator-facing identifiers. A Console attached to multiple Runtimes uses InstanceID as the per-attachment stable key.

type RuntimeInfoRequest

type RuntimeInfoRequest struct {
	// Identity is the caller's identity scope. The PostureSurface
	// validates the triple and gates cross-tenant reads on the admin
	// scope claim.
	Identity IdentityScope `json:"identity"`
}

RuntimeInfoRequest is the shared request shape for the five Phase 72f posture methods. It carries only the identity scope — the methods are read-only and take no payload.

Identity is mandatory at the Protocol edge (RFC §5.5). The Tenant field is required for every posture method; the User and Session fields are required when the projection is session-scoped (runtime.counters returns tenant-wide rollups for a Tenant-only scope, the session's slice when a Session is supplied). A cross-tenant request — Identity.Tenant differing from the caller's verified tenant — requires the admin scope per D-079.

type SearchArtifactRef

type SearchArtifactRef struct {
	// ID is the content-addressed identifier (`{namespace}_{sha256[:12]}`).
	ID string `json:"id"`
	// MimeType is the IANA media type, when known.
	MimeType string `json:"mime_type,omitempty"`
	// SizeBytes is the length of the referenced bytes.
	SizeBytes int64 `json:"size_bytes,omitempty"`
	// Filename is metadata only (never used for path construction).
	Filename string `json:"filename,omitempty"`
	// SHA256 is the full hex digest of the referenced bytes.
	SHA256 string `json:"sha256,omitempty"`
}

SearchArtifactRef is the by-reference shape a `SearchResultRow` carries when the underlying entity's preview payload would exceed the heavy-content threshold (D-026). It mirrors a subset of `internal/artifacts.ArtifactRef` but is a flat wire type — the Protocol owns its vocabulary; runtime Go structs never leak (RFC §5.1 / CLAUDE.md §13 single-source rule).

type SearchFacet

type SearchFacet struct {
	// Key is the facet dimension name (e.g. `tasks.status`).
	Key string `json:"key"`
	// Value is the facet's selected value (e.g. `running`).
	Value string `json:"value"`
}

SearchFacet is a per-index dimension selector — e.g. `{Key:"tasks.status", Value:"running"}` or `{Key:"events.type", Value:"tool.failed"}`. Unknown facets are silently ignored at V1 (post-V1 may tighten to error).

type SearchFilter

type SearchFilter struct {
	// TenantIDs narrows the search to these tenants; empty defaults to
	// the caller's authenticated tenant. A value outside the caller's
	// own tenant requires the `auth.ScopeAdmin` claim.
	TenantIDs []string `json:"tenant_ids,omitempty"`
	// UserIDs narrows the search to these users; empty defaults to the
	// caller's authenticated user.
	UserIDs []string `json:"user_ids,omitempty"`
	// SessionIDs narrows the search to these sessions; empty defaults to
	// the caller's authenticated session.
	SessionIDs []string `json:"session_ids,omitempty"`
	// Since is the inclusive lower bound of the result time-window; the
	// zero value imposes no lower bound.
	Since time.Time `json:"since,omitempty"`
	// Until is the inclusive upper bound of the result time-window; the
	// zero value imposes no upper bound.
	Until time.Time `json:"until,omitempty"`
}

SearchFilter narrows results to the caller's identity scope and optional time-window. The TenantIDs / UserIDs / SessionIDs fields default to the caller's authenticated triple; supplying values that reach OUTSIDE the caller's own scope requires the `auth.ScopeAdmin` scope claim (D-079 closed two-scope set; D-108 reuse for search). A missing-claim cross-tenant request is rejected loudly with `CodeAuthRejected` (HTTP 403) — NEVER silently downgraded to an empty result set.

type SearchIndex

type SearchIndex string

SearchIndex is the typed enum of canonical search indexes the runtime-side `search.*` cluster ships in Phase 72c. Four indexes — sessions, tasks, events, artifacts — match the high-cardinality runtime-side split from Brief 11 §CC-4. Console-side Tools / Agents / Flows / MCP catalog searches do NOT appear here: those land in their per-page Stage-2 Console phases (73c/d/e/f/g/i/k) per the split.

const (
	SearchIndexSessions  SearchIndex = "sessions"
	SearchIndexTasks     SearchIndex = "tasks"
	SearchIndexEvents    SearchIndex = "events"
	SearchIndexArtifacts SearchIndex = "artifacts"
)

Canonical search-index values. The set is closed; a new index is a new Protocol-surface phase.

type SearchRequest

type SearchRequest struct {
	// Query is the free-text query — substring / prefix match against
	// the searched fields per index. Empty Query is permitted (lists
	// everything in scope subject to filters).
	Query string `json:"query,omitempty"`
	// Indexes selects which runtime-side indexes `search.query` should
	// fan out to. Empty means "all four." Ignored by the four per-index
	// methods. Unknown index values are rejected with
	// `CodeInvalidRequest`.
	Indexes []SearchIndex `json:"indexes,omitempty"`
	// Filter narrows results. Identity defaulting + cross-tenant gating
	// happens in the search handler — the wire surface accepts every
	// caller's filter and rejects elevated requests loudly.
	Filter SearchFilter `json:"filter,omitempty"`
	// Facets are optional per-index dimension selectors. The runtime
	// applies whichever facets are recognised for the index being
	// searched and silently ignores the rest.
	Facets []SearchFacet `json:"facets,omitempty"`
	// Page is the 1-based page number; defaults to 1 when zero.
	Page int `json:"page,omitempty"`
	// PageSize is the per-page row count. Defaults to
	// `DefaultSearchPageSize` (20) when zero; values above
	// `MaxSearchPageSize` (200) are rejected with `CodeInvalidRequest`.
	PageSize int `json:"page_size,omitempty"`
}

SearchRequest is the shared wire shape for all five `search.*` methods. `search.query` honours `Indexes` (the palette dispatcher selects 1..4 of the runtime-side indexes); the four per-index methods ignore `Indexes` and operate on their own index.

Identity is mandatory at the Protocol edge per RFC §5.5 — the request flows out of an auth-verified identity in ctx, never trusted from the body. The `Filter` field supplies optional scope-narrowing within the caller's verified identity (and, with the admin claim, cross-tenant expansion).

func (SearchRequest) PageBounds

func (r SearchRequest) PageBounds() (page, size int)

PageBounds returns the normalised (page, size) pair without mutating the receiver. Useful for handlers that need to validate-then-pass.

type SearchResponse

type SearchResponse struct {
	// Rows is the page slice — at most `PageSize` rows. Empty when
	// the filter matched nothing.
	Rows []SearchResultRow `json:"rows"`
	// Page echoes the (defaulted) request page.
	Page int `json:"page"`
	// PageSize echoes the (defaulted) per-page size.
	PageSize int `json:"page_size"`
	// PageCount is the total page count given TotalCount + PageSize.
	PageCount int `json:"page_count"`
	// TotalCount is the total matching row count BEFORE pagination.
	TotalCount int64 `json:"total_count"`
	// HasMore is a convenience flag — true when Page < PageCount.
	HasMore bool `json:"has_more"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

SearchResponse is the uniform response shape returned by every `search.*` method. Pagination is identical across the cluster.

func (SearchResponse) MarshalJSON

func (r SearchResponse) MarshalJSON() ([]byte, error)

MarshalJSON is the standard json.Marshaler — kept explicit so the SearchResponse shape stays stable across a refactor that might reorder fields. Round-trip is verified by search_test.go.

type SearchResultRow

type SearchResultRow struct {
	// Index identifies which subsystem produced the row. Required.
	Index SearchIndex `json:"index"`
	// ID is the entity identifier (session ID / task ID / event ID
	// (composed `<session>:<sequence>`) / artifact ID).
	ID string `json:"id"`
	// TenantID + UserID + SessionID + RunID flatten the runtime's
	// identity quadruple so a Protocol client never round-trips a
	// runtime Go struct. RunID is empty for session-scoped entities.
	TenantID  string `json:"tenant_id"`
	UserID    string `json:"user_id"`
	SessionID string `json:"session_id"`
	RunID     string `json:"run_id,omitempty"`
	// OccurredAt is the row's anchor timestamp — for sessions, the
	// open / last-seen / close time; for tasks, UpdatedAt; for events,
	// OccurredAt; for artifacts, the put time (mirrored by the
	// driver's UpdatedAt when known).
	OccurredAt time.Time `json:"occurred_at,omitempty"`
	// Preview is the redacted short summary (≤ heavy-content
	// threshold). Empty when Ref is populated.
	Preview string `json:"preview,omitempty"`
	// Ref is populated when the underlying entity's preview would
	// exceed the heavy-content threshold (D-026). The Console fetches
	// the bytes via `artifacts.get` / `artifacts.get_ref` when it
	// wants them.
	Ref *SearchArtifactRef `json:"ref,omitempty"`
	// Facets carries per-index dimension values relevant to the row
	// (e.g. `{"status":"running"}` for tasks). The set of populated
	// keys per index is documented per Searcher implementation.
	Facets map[string]string `json:"facets,omitempty"`
}

SearchResultRow is the uniform result-row shape across all five `search.*` methods. `Preview` is REDACTED via `audit.Redactor` before emission. Heavy payloads (≥ D-026 threshold) ship as a populated `Ref` field, NEVER inline bytes — `Preview` is then empty.

type SessionFilter

type SessionFilter struct {
	// Statuses restricts to sessions whose Status is in this set.
	Statuses []SessionStatus `json:"statuses,omitempty"`
	// AgentIDs restricts to sessions whose AgentID is in this set.
	AgentIDs []string `json:"agent_ids,omitempty"`
	// UserIDs restricts to sessions whose UserID is in this set.
	UserIDs []string `json:"user_ids,omitempty"`
	// TenantIDs restricts to sessions whose TenantID is in this set.
	// A TenantIDs entry naming a tenant other than the caller's
	// verified tenant requires the `auth.ScopeAdmin` claim (D-079).
	TenantIDs []string `json:"tenant_ids,omitempty"`
	// StartedWindow filters by the session's StartedAt timestamp.
	StartedWindow Window `json:"started_window,omitempty"`
	// HasIntervention, when non-nil, restricts to sessions that do
	// (true) / do not (false) have a pending intervention.
	HasIntervention *bool `json:"has_intervention,omitempty"`
	// HasFailedTask, when non-nil, restricts to sessions that do
	// (true) / do not (false) have a failed task.
	HasFailedTask *bool `json:"has_failed_task,omitempty"`
	// CostAboveCents, when non-nil, restricts to sessions whose
	// TotalCostCents is strictly above this threshold.
	CostAboveCents *int64 `json:"cost_above_cents,omitempty"`
	// Query is a free-text substring filter over session id + agent
	// name + user. When non-empty, the runtime forwards it to the
	// `search.sessions` index (Brief 11 §CC-4) and the SessionFilter
	// axes are post-search refinements (D-122 — forward then filter).
	Query string `json:"query,omitempty"`
}

SessionFilter is the server-enforced filter on `sessions.list`. An empty facet slice matches every value on that axis. The filter is applied AFTER the identity-scope predicate — it never widens visibility (CLAUDE.md §6).

type SessionRow

type SessionRow struct {
	// SessionID is the stable session identifier.
	SessionID string `json:"session_id"`
	// Status is the session's lifecycle status.
	Status SessionStatus `json:"status"`
	// AgentID is the registered agent identifier the session ran under
	// ("" when no agent is bound).
	AgentID string `json:"agent_id"`
	// AgentName is the planner-facing agent display name.
	AgentName string `json:"agent_name"`
	// UserID is the user component of the session's identity triple.
	UserID string `json:"user_id"`
	// TenantID is the tenant component of the session's identity triple.
	TenantID string `json:"tenant_id"`
	// StartedAt is the session-open timestamp.
	StartedAt time.Time `json:"started_at"`
	// LastActivityAt is the timestamp of the most-recent activity.
	LastActivityAt time.Time `json:"last_activity_at"`
	// Duration is the elapsed span (LastActivityAt-StartedAt for closed
	// sessions, now-StartedAt for live ones). Marshalled as int64
	// nanoseconds (Go's time.Duration JSON form).
	Duration time.Duration `json:"duration"`
	// TasksCount is the number of tasks the session has spawned.
	TasksCount int `json:"tasks_count"`
	// EventsCount is the number of events the session has emitted.
	EventsCount int `json:"events_count"`
	// TotalCostCents is the session's accumulated LLM cost in US cents.
	TotalCostCents int64 `json:"total_cost_cents"`
	// TotalTokens is the session's accumulated LLM token count.
	TotalTokens int64 `json:"total_tokens"`
	// HasPendingIntervention reports whether the session has a pause
	// awaiting resume / approval.
	HasPendingIntervention bool `json:"has_pending_intervention"`
	// HasFailedTask reports whether the session has at least one failed
	// task.
	HasFailedTask bool `json:"has_failed_task"`
	// Identity is the impersonation triplet (Phase 72b / D-107). When
	// the session is a normal non-impersonated run, only the top-level
	// Tenant/User/Session carry meaning and Impersonating is nil; when
	// the session is an admin-initiated impersonated run, Actor carries
	// the verified admin identity and Impersonating carries the target
	// identity the run executed under. The Console Sessions-page
	// Identity column renders the Actor triple plus a separate
	// `impersonating` chip when Impersonating is non-empty.
	Identity IdentityScope `json:"identity"`
}

SessionRow is the catalog-row projection of a session. It is the row shape the Console Sessions-page table renders. Flat, low-cardinality fields — the Console branches on the enum fields.

There is NO Priority field — D-065 dropped session-level priority from V1.

type SessionSort

type SessionSort string

SessionSort is the wire enum for the `sessions.list` row ordering.

const (
	// SessionSortStartedDesc orders newest-first by StartedAt (default).
	SessionSortStartedDesc SessionSort = "started_desc"
	// SessionSortStartedAsc orders oldest-first by StartedAt.
	SessionSortStartedAsc SessionSort = "started_asc"
	// SessionSortLastActivityDesc orders most-recently-active first.
	SessionSortLastActivityDesc SessionSort = "last_activity_desc"
	// SessionSortCostDesc orders most-expensive first.
	SessionSortCostDesc SessionSort = "cost_desc"
)

Canonical session sort orders — the Sort-By toggle in the mockup.

type SessionStatus

type SessionStatus string

SessionStatus is the wire enum for a session's lifecycle status.

const (
	// SessionStatusRunning — the session has at least one running run.
	SessionStatusRunning SessionStatus = "running"
	// SessionStatusPaused — the session has a paused run awaiting
	// resume / approval.
	SessionStatusPaused SessionStatus = "paused"
	// SessionStatusCompleted — the session is closed and finished
	// cleanly.
	SessionStatusCompleted SessionStatus = "completed"
	// SessionStatusFailed — the session is closed and at least one run
	// failed.
	SessionStatusFailed SessionStatus = "failed"
)

Canonical session statuses — the closed set the Sessions-page status facet filters on and the table renders.

type SessionsInspectRequest

type SessionsInspectRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// SessionID is the session to inspect.
	SessionID string `json:"session_id"`
}

SessionsInspectRequest is the `sessions.inspect` request body.

type SessionsInspectResponse

type SessionsInspectResponse struct {
	// Row is the session's catalog-row projection (same shape as a
	// `sessions.list` row).
	Row SessionRow `json:"row"`
	// RecentInterventions is the capped slice of recent interventions
	// (≤ MaxSessionInterventionSummaries), most-recent first.
	RecentInterventions []InterventionSummary `json:"recent_interventions"`
	// RecentArtifacts is the capped slice of recent artifacts
	// (≤ MaxSessionArtifactSummaries), most-recent first.
	RecentArtifacts []ArtifactRefSummary `json:"recent_artifacts"`
}

SessionsInspectResponse is the `sessions.inspect` reply — the full per-session snapshot the Console Sessions detail view renders. The Row carries the same projection as a `sessions.list` row; the two capped slices feed the right-rail Recent Interventions / Recent Artifacts cards.

type SessionsListRequest

type SessionsListRequest struct {
	// Identity is the (tenant, user, session) scope the listing is
	// projected for. Mandatory — an incomplete triple fails closed.
	Identity IdentityScope `json:"identity"`
	// Filter is the optional facet filter; the zero value lists every
	// visible session.
	Filter SessionFilter `json:"filter"`
	// Sort selects the row ordering; an empty value applies
	// SessionSortStartedDesc.
	Sort SessionSort `json:"sort,omitempty"`
	// Cursor is the opaque pagination cursor returned by a previous
	// SessionsListResponse.NextCursor. Empty starts from the first page.
	Cursor string `json:"cursor,omitempty"`
	// Limit is the rows-per-page; a non-positive value applies
	// DefaultSessionListLimit. A value above MaxSessionListLimit is a
	// 400 (CodeInvalidRequest) — never a silent clamp.
	Limit int `json:"limit,omitempty"`
}

SessionsListRequest is the `sessions.list` request body.

type SessionsListResponse

type SessionsListResponse struct {
	// Rows is the page of session rows, in the requested sort order.
	Rows []SessionRow `json:"rows"`
	// NextCursor is the opaque cursor for the next page; "" when this
	// is the last page.
	NextCursor string `json:"next_cursor"`
	// Truncated is true when the candidate set hit Limit+1 rows — the
	// honest "there are more" signal, NEVER a silent exact total.
	Truncated bool `json:"truncated"`
}

SessionsListResponse is the `sessions.list` reply: a page of catalog rows plus the opaque next-page cursor.

There is NO exact total count — D-026 fail-loudly: an exact O(N) count under high cardinality is not promised. The server emits `Truncated: true` when the candidate set hit Limit+1 rows; the page lazily fetches more pages until NextCursor == "".

type SizeRange

type SizeRange struct {
	// MinBytes, when set, excludes artifacts strictly smaller than it.
	MinBytes *int64 `json:"min_bytes,omitempty"`
	// MaxBytes, when set, excludes artifacts strictly larger than it.
	MaxBytes *int64 `json:"max_bytes,omitempty"`
}

SizeRange is an optional byte-size filter for artifacts.list. Both bounds are inclusive; a nil bound is unbounded on that side.

type StartRequest

type StartRequest struct {
	// Identity is the request's identity scope. The triple is mandatory;
	// Run is ignored (a `start` mints the run). Scope is ignored.
	Identity IdentityScope `json:"identity"`
	// Query is the user-facing query that starts the run. Optional —
	// some runs are kicked off without a natural-language query.
	Query string `json:"query,omitempty"`
	// Description is an operator-facing description of the task.
	// Optional.
	Description string `json:"description,omitempty"`
	// Priority is the task's initial scheduling priority. Zero is the
	// default priority.
	Priority int `json:"priority,omitempty"`
	// IdempotencyKey, when non-empty, deduplicates the spawn: a second
	// `start` with the same key (namespaced by session) returns the
	// existing task handle with Reused=true. Empty disables dedup.
	IdempotencyKey string `json:"idempotency_key,omitempty"`
	// InputArtifactIDs (Round-7 F11 / D-166) attach operator-uploaded
	// artifacts as multimodal inputs the run consumes on its first
	// planner turn. The runtime's per-MIME materializer routes each
	// id: `image/*` bytes inline as `ImagePart.DataURL`; everything
	// else stays an `ArtifactStub` the LLM routes through the tool
	// catalog. The Playground composer's chat-attach control plumbs
	// uploaded ids through this field. Empty is the text-only default.
	InputArtifactIDs []string `json:"input_artifact_ids,omitempty"`
}

StartRequest is the wire request for the `start` Protocol method — it asks the Runtime to spawn a new task / foreground run. It maps onto the Phase 20 tasks.TaskRegistry.Spawn surface.

type StartResponse

type StartResponse struct {
	// TaskID is the runtime-assigned task identifier for the spawned
	// (or, on an idempotency-key match, the existing) task.
	TaskID string `json:"task_id"`
	// Reused is true when an IdempotencyKey match returned an existing
	// task rather than spawning a fresh one.
	Reused bool `json:"reused"`
	// ProtocolVersion echoes the Protocol version the Runtime answered
	// under so a client can detect a version skew.
	ProtocolVersion string `json:"protocol_version"`
}

StartResponse is the wire response for the `start` Protocol method.

type SubsystemDriver

type SubsystemDriver struct {
	// Subsystem names the persistence-shaped subsystem ("state",
	// "artifacts", "memory", "eventlog").
	Subsystem string `json:"subsystem"`
	// Driver is the configured driver name ("inmem", "sqlite",
	// "postgres", ...). Never the DSN / connection string — only the
	// driver name leaks across the Protocol boundary.
	Driver string `json:"driver"`
	// Mode is an optional posture detail ("readwrite", "readonly",
	// "embedded"). Empty when the subsystem reports none.
	Mode string `json:"mode,omitempty"`
}

SubsystemDriver is one persistence-shaped subsystem's configured driver entry in a RuntimeDrivers readout.

type SubsystemHealth

type SubsystemHealth struct {
	// Subsystem names the runtime subsystem (e.g. "events", "state",
	// "tasks").
	Subsystem string `json:"subsystem"`
	// Status is the structural readiness — one of "ready", "degraded",
	// or "unavailable". Read from the subsystem's own posture seam, not
	// from a synthetic deep-check probe.
	Status string `json:"status"`
	// Detail is an optional human-readable explanation — populated for
	// a degraded / unavailable subsystem with the reason.
	Detail string `json:"detail,omitempty"`
}

SubsystemHealth is one subsystem's readiness entry in a RuntimeHealth rollup.

type TaskCostRollup

type TaskCostRollup struct {
	// TotalTokens is the total token count (prompt + output).
	TotalTokens int64 `json:"total_tokens"`
	// PromptTokens is the prompt-side token count.
	PromptTokens int64 `json:"prompt_tokens"`
	// OutputTokens is the output-side token count.
	OutputTokens int64 `json:"output_tokens"`
	// USD is the total dollar cost.
	USD float64 `json:"usd"`
	// PerStep is the cost breakdown, one entry per planner step.
	PerStep []TaskCostStep `json:"per_step"`
}

TaskCostRollup is the per-task cost aggregation `tasks.get` returns — the Console Tasks-page right-rail "Cost Breakdown" card. The rollup carries only sums + a per-step breakdown; heavy per-event payloads stay on the event bus and are never inlined here.

type TaskCostStep

type TaskCostStep struct {
	// StepIndex is the 0-based planner-step index.
	StepIndex int `json:"step_index"`
	// Tokens is the total token count attributed to the step.
	Tokens int64 `json:"tokens"`
	// USD is the dollar cost attributed to the step.
	USD float64 `json:"usd"`
}

TaskCostStep is one planner-step entry in a TaskCostRollup — the aggregated cost of a single planner step within the task.

type TaskDetail

type TaskDetail struct {
	// Task is the compact row projection (same shape `tasks.list`
	// returns).
	Task TaskRow `json:"task"`
	// ParentSession is the parent-session reference card.
	ParentSession TaskParentSessionRef `json:"parent_session"`
	// ParentTask is the parent-task reference; nil when the task is not
	// a child of a SpawnTask group.
	ParentTask *TaskParentTaskRef `json:"parent_task,omitempty"`
	// Cost is the per-task cost rollup aggregated from
	// `llm.cost.recorded` events scoped to the task.
	Cost TaskCostRollup `json:"cost"`
	// PlannerSnapshot is the planner-checkpoint reference at spawn time;
	// nil when no checkpoint exists.
	PlannerSnapshot *TaskPlannerSnapshotRef `json:"planner_snapshot,omitempty"`
	// ResultRef references the task's result payload by artifact stub
	// when the result exceeds the heavy-content threshold (D-026); nil
	// when the task has no result or the result is inlined small.
	ResultRef *ArtifactRef `json:"result_ref,omitempty"`
	// ResultInline carries the task's result payload directly when it is
	// below the heavy-content threshold ("" when absent or referenced).
	ResultInline string `json:"result_inline,omitempty"`
	// Trajectory is the projected planner reasoning-trace snapshot;
	// nil when the trajectory is unavailable (evicted or not captured).
	Trajectory *TaskTrajectoryRef `json:"trajectory,omitempty"`
}

TaskDetail is the enriched payload `tasks.get` returns. It carries the compact TaskRow projection plus the four enrichment fields the Console Tasks-page detail tabs + right-rail cards render. Heavy payload content is referenced via ArtifactRef (D-026) — `tasks.get` MUST NOT inline bytes that exceed the heavy-content threshold.

type TaskFilter

type TaskFilter struct {
	// Statuses restricts to tasks whose Status is in this set.
	Statuses []TaskStatus `json:"statuses,omitempty"`
	// Kinds restricts to tasks whose Kind is in this set; empty matches
	// both foreground and background.
	Kinds []TaskKind `json:"kinds,omitempty"`
	// ParentTaskID drills into a SpawnTask group — restricts to tasks
	// whose ParentTaskID equals this value ("" = no parent-task filter).
	ParentTaskID string `json:"parent_task_id,omitempty"`
	// Identities scopes the query. A query naming more than one distinct
	// tenant is a cross-tenant fan-in and requires the `auth.ScopeAdmin`
	// claim (D-079). Empty = the caller's own identity scope.
	Identities []IdentityScope `json:"identities,omitempty"`
	// Since is an optional lower bound on StartedAt (zero = unbounded).
	Since time.Time `json:"since,omitempty"`
	// Until is an optional upper bound on StartedAt (zero = unbounded).
	Until time.Time `json:"until,omitempty"`
	// ErrorClasses facets on TaskRow.ErrorClass for Failed tasks.
	ErrorClasses []string `json:"error_classes,omitempty"`
	// LatencyAboveMS facets on DurationMS — restricts to tasks whose
	// DurationMS is at or above this value (0 = no latency filter).
	LatencyAboveMS int64 `json:"latency_above_ms,omitempty"`
	// Search is a free-text substring filter over the task's
	// description + query, routed to the runtime search.tasks index.
	Search string `json:"search,omitempty"`
	// GroupID drills into one `TaskGroup` — restricts to tasks whose
	// GroupID equals this value ("" = no group filter). The Background
	// Jobs page's per-job right-rail "Related Sessions" tab issues a
	// `tasks.list` with this facet set to surface the sibling tasks
	// (foreground + background) under the same group. Identity scope is
	// still enforced — a cross-tenant `group_id` lookup never widens
	// visibility. Phase 73h (D-128).
	GroupID string `json:"group_id,omitempty"`
	// HasPendingApproval, when non-nil, restricts to tasks whose
	// HasPendingApproval row field equals the pointee. nil = no
	// approval filter; *true = only tasks with an open approval gate;
	// *false = only tasks with none. The Background Jobs page's `Has
	// pending approval` facet chip binds this. Phase 73h (D-128).
	HasPendingApproval *bool `json:"has_pending_approval,omitempty"`
}

TaskFilter is the server-enforced facet filter on `tasks.list`. An empty facet slice matches every value on that axis. The filter is applied AFTER the identity-scope predicate — it never widens visibility.

type TaskGetRequest

type TaskGetRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the task identifier to project.
	ID string `json:"id"`
}

TaskGetRequest is the `tasks.get` request body.

type TaskKind

type TaskKind string

TaskKind is the wire enum discriminating a foreground task (a run inside a session's primary turn) from a background task (a spawned-without-blocking task). The Protocol projection of the runtime-internal `tasks.TaskKind`.

const (
	TaskKindForeground TaskKind = "foreground"
	TaskKindBackground TaskKind = "background"
)

Canonical task kinds — the closed set.

type TaskListAggregates

type TaskListAggregates struct {
	// Pending is the count of filtered tasks in the Pending column.
	Pending int64 `json:"pending"`
	// Running is the count of filtered tasks in the Running column.
	Running int64 `json:"running"`
	// Paused is the count of filtered tasks in the Paused column.
	Paused int64 `json:"paused"`
	// Failed is the count of filtered tasks in the Failed column.
	Failed int64 `json:"failed"`
	// Complete is the count of filtered tasks in the Done column.
	Complete int64 `json:"complete"`
	// Cancelled is the count of filtered tasks that were cancelled.
	Cancelled int64 `json:"cancelled"`
}

TaskListAggregates carries the per-status counters the kanban renders at each column header, computed over the FILTERED view.

type TaskListCursor

type TaskListCursor struct {
	// NextPageToken is the opaque continuation token; empty when there
	// are no more pages.
	NextPageToken string `json:"next_page_token,omitempty"`
}

TaskListCursor is the opaque pagination cursor for `tasks.list`.

type TaskListRequest

type TaskListRequest struct {
	// Identity is the (tenant, user, session) scope the task list is
	// projected for. Mandatory — an incomplete triple fails closed.
	Identity IdentityScope `json:"identity"`
	// Filter is the optional facet filter; the zero value lists every
	// visible task.
	Filter TaskFilter `json:"filter"`
	// PageSize is the rows-per-page; a non-positive value applies
	// DefaultTaskListPageSize. A value above MaxTaskListPageSize is a
	// 400 (CodeInvalidRequest) — never a silent clamp.
	PageSize int `json:"page_size,omitempty"`
	// Cursor is the pagination cursor; the zero value requests the
	// first page.
	Cursor TaskListCursor `json:"cursor"`
	// IncludeStatusCounterStrip opts the response into carrying the
	// Phase 73b (D-126) TasksListStatusCounterStrip aggregate. It is
	// off by default — the Console Live Runtime page sets it on its
	// initial-load `tasks.list` call and then maintains the strip live
	// from the `task.*` SSE stream (the aggregate is the initial-load
	// shape only; see the phase-73b plan's "tasks.list aggregate cost"
	// risk). The Tasks page (73d) never sets it — its kanban renders
	// the filtered-view TaskListAggregates instead.
	IncludeStatusCounterStrip bool `json:"include_status_counter_strip,omitempty"`
}

TaskListRequest is the `tasks.list` request body.

type TaskListResponse

type TaskListResponse struct {
	// Rows is the page of task rows, sorted by StartedAt descending
	// (newest first).
	Rows []TaskRow `json:"rows"`
	// Cursor carries the continuation token for the next page.
	Cursor TaskListCursor `json:"cursor"`
	// Aggregates carries the per-status counters for the filtered view.
	Aggregates TaskListAggregates `json:"aggregates"`
	// StatusCounterStrip carries the Phase 73b (D-126) header-strip
	// aggregate — non-nil ONLY when the request set
	// IncludeStatusCounterStrip. It is computed over the FULL identity-
	// scoped task set (not the filtered view) and is the Console Live
	// Runtime page's header five-chip strip. nil on a request that did
	// not opt in (the Tasks page never opts in).
	StatusCounterStrip *TasksListStatusCounterStrip `json:"status_counter_strip,omitempty"`
}

TaskListResponse is the `tasks.list` reply: a paginated slice of task rows, the continuation cursor, and the filtered-view per-status aggregates.

type TaskParentSessionRef

type TaskParentSessionRef struct {
	// SessionID is the parent session's identifier.
	SessionID string `json:"session_id"`
	// AgentName is the agent the session runs.
	AgentName string `json:"agent_name"`
	// Status is the parent session's lifecycle status.
	Status string `json:"status"`
	// StartedAt is the parent session's start timestamp.
	StartedAt time.Time `json:"started_at"`
	// LatestEventAt is the timestamp of the most recent event on the
	// parent session.
	LatestEventAt time.Time `json:"latest_event_at"`
}

TaskParentSessionRef is the parent-session reference card `tasks.get` returns — the Console Tasks-page right-rail "Parent Session" card.

type TaskParentTaskRef

type TaskParentTaskRef struct {
	// TaskID is the spawning task's identifier.
	TaskID string `json:"task_id"`
	// Kind is the spawning task's kind.
	Kind TaskKind `json:"kind"`
	// Status is the spawning task's lifecycle status.
	Status TaskStatus `json:"status"`
}

TaskParentTaskRef is the parent-task reference `tasks.get` returns when the task is a child spawned by a planner `SpawnTask`.

type TaskPlannerSnapshotRef

type TaskPlannerSnapshotRef struct {
	// CheckpointID is the planner-checkpoint identifier (resolvable via
	// state.load_planner_checkpoint).
	CheckpointID string `json:"checkpoint_id"`
	// Summary is the pre-truncated checkpoint summary.
	Summary string `json:"summary"`
}

TaskPlannerSnapshotRef is the planner-checkpoint reference `tasks.get` returns — it points at the planner checkpoint that existed at task spawn time. Heavy checkpoint content is fetched on demand via the existing Phase 73 `state.load_planner_checkpoint` method, never inlined in the `tasks.get` response.

type TaskRow

type TaskRow struct {
	// ID is the unified task identifier (foreground run or background
	// task; one TaskID namespace).
	ID string `json:"id"`
	// Kind discriminates foreground vs background.
	Kind TaskKind `json:"kind"`
	// Status is the task's lifecycle state.
	Status TaskStatus `json:"status"`
	// Priority is the TASK-level priority (D-072 — the `prioritize`
	// control method). NEVER a session-level priority (D-065 carve-out).
	Priority int `json:"priority"`
	// Identity is the (tenant, user, session) triple the task runs
	// within — the Console truncates it for display on the card.
	Identity IdentityScope `json:"identity"`
	// ParentSessionID is the session the task belongs to.
	ParentSessionID string `json:"parent_session_id"`
	// ParentTaskID is set when the task was spawned by a planner
	// `SpawnTask` — it names the spawning task ("" when not a child).
	ParentTaskID string `json:"parent_task_id,omitempty"`
	// Description is the planner-facing task summary.
	Description string `json:"description"`
	// Query is the originating query / prompt text.
	Query string `json:"query"`
	// StartedAt is the task's creation timestamp.
	StartedAt time.Time `json:"started_at"`
	// UpdatedAt is the timestamp of the most recent lifecycle transition.
	UpdatedAt time.Time `json:"updated_at"`
	// DurationMS is the elapsed wall-clock time in milliseconds
	// (StartedAt → UpdatedAt).
	DurationMS int64 `json:"duration_ms"`
	// ErrorClass is the short failure-class string; set only when
	// Status is "failed" ("" otherwise).
	ErrorClass string `json:"error_class,omitempty"`
	// ToolCount is the count of child tool tasks spawned by this task.
	ToolCount int `json:"tool_count"`
	// BackgroundAcknowledged latches true once a completed background
	// task has been acknowledged (the `task.background_acknowledged`
	// event).
	BackgroundAcknowledged bool `json:"background_acknowledged"`
	// GroupID is the TaskGroup the task is a member of ("" when the
	// task is not a group member).
	GroupID string `json:"group_id,omitempty"`
	// Progress is the planner-emitted numeric progress hint in the
	// [0,1] range. It is a pointer so the wire shape distinguishes "the
	// planner emitted progress 0.0" from "the planner emitted no
	// progress at all" — nil ⇒ no hint, and the Console renders an
	// indeterminate Progress mini-bar rather than a 0% bar. Phase 73h
	// (D-128): the Background Jobs page's Progress column.
	Progress *float64 `json:"progress,omitempty"`
	// Tags is the slice of short labels the Background Jobs page renders
	// in its Tags column — the parent task type plus any planner-emitted
	// labels. Empty slice ⇒ no tags. Phase 73h (D-128).
	Tags []string `json:"tags,omitempty"`
	// LastActivityAt is the timestamp of the most recent activity on the
	// task — the max of UpdatedAt and any event on the run's stream. The
	// Background Jobs page's `Stuck > 1h` saved-filter chip derives off
	// this field (a Console-local rule — D-061). Phase 73h (D-128).
	LastActivityAt time.Time `json:"last_activity_at"`
	// IsBackground mirrors `Kind == "background"` — a convenience
	// boolean so a Console row-renderer branches without re-comparing
	// the enum. Phase 73h (D-128): the Background Jobs queue is the
	// `IsBackground == true` projection of the unified task set.
	IsBackground bool `json:"is_background"`
	// HasPendingApproval is true when the task's run has at least one
	// open HITL approval / tool-approval gate. The Background Jobs
	// page's `Has pending approval` facet filters on it, and the
	// per-job right-rail's Pending-approvals tab is populated when it is
	// true. Phase 73h (D-128).
	HasPendingApproval bool `json:"has_pending_approval"`
}

TaskRow is the compact projection returned by `tasks.list`. It is the row shape the Console Tasks-page kanban card + list-mode table render. Wire-only — never the internal `tasks.Task` struct (CLAUDE.md §8 — the Console never reads internal runtime objects). Heavy fields (the result / error payloads) stay on TaskDetail; the row is compact for kanban + table density.

NO session-level priority field appears here — D-065 carve-out. Only Priority (the task-level priority shipped via the Phase 54 `prioritize` method, D-072) is rendered.

type TaskStatus

type TaskStatus string

TaskStatus is the wire enum for a task's lifecycle state. It is the Protocol projection of the runtime-internal `tasks.TaskStatus`.

const (
	TaskStatusPending   TaskStatus = "pending"
	TaskStatusRunning   TaskStatus = "running"
	TaskStatusPaused    TaskStatus = "paused"
	TaskStatusComplete  TaskStatus = "complete"
	TaskStatusFailed    TaskStatus = "failed"
	TaskStatusCancelled TaskStatus = "cancelled"
)

Canonical task statuses — the closed lifecycle set the kanban board and list-mode table render.

type TaskTrajectoryRef added in v1.2.0

type TaskTrajectoryRef struct {
	Steps []TaskTrajectoryStep `json:"steps"`
}

TaskTrajectoryRef is the projected reasoning-trace snapshot from the planner's in-memory trajectory, carried on TaskDetail.Trajectory. The projection is narrow — per-step index + reasoning-trace string only; full action / observation projection is a later expansion. Phase 107a.

type TaskTrajectoryStep added in v1.2.0

type TaskTrajectoryStep struct {
	Index          int    `json:"index"`
	ReasoningTrace string `json:"reasoning_trace"`
}

TaskTrajectoryStep maps one planner trajectory step to the wire. Steps with an empty ReasoningTrace are filtered out before the wire — the Console never sees a box that says "no reasoning here."

type TasksListStatusCounterStrip

type TasksListStatusCounterStrip struct {
	// Pending is the count of identity-scoped tasks in the Pending state.
	Pending int `json:"pending"`
	// Running is the count of identity-scoped tasks in the Running state.
	Running int `json:"running"`
	// Completed is the count of identity-scoped tasks in the Complete
	// state (the strip's `completed` chip — see the type godoc on the
	// `complete` → `completed` vocabulary choice).
	Completed int `json:"completed"`
	// Paused is the count of identity-scoped tasks in the Paused state.
	Paused int `json:"paused"`
	// Failed is the count of identity-scoped tasks in the Failed state.
	Failed int `json:"failed"`
}

TasksListStatusCounterStrip is the Phase 73b (Wave 13 / D-126) status-counter-strip aggregate the Console Live Runtime page renders as its header-level five-chip strip (`pending / running / completed / paused / failed`). It is an OPT-IN projection on the `tasks.list` response — a caller requests it via TaskListRequest.IncludeStatusCounterStrip.

The strip is distinct from TaskListAggregates in two deliberate ways:

  • It is computed over the FULL identity-scoped task set, NOT the filtered view. The Live Runtime header strip reports session-wide posture ("how many tasks are running in this session right now"), so it never narrows with the page's facet filter.
  • It keys on the canonical lifecycle vocabulary the Live Runtime page-spec mockup uses (`completed` rather than `complete`); the `cancelled` status is folded out — the strip is a five-chip present-tense posture, not the six-status kanban tally.

The aggregate is identity-scoped and computed server-side per request (CLAUDE.md §6 rule 2): the counter NEVER crosses the isolation boundary — a second session never sees the first's counts.

type TimeRange

type TimeRange struct {
	// After, when non-zero, excludes artifacts created strictly before
	// it.
	After time.Time `json:"after,omitempty"`
	// Before, when non-zero, excludes artifacts created strictly after
	// it.
	Before time.Time `json:"before,omitempty"`
}

TimeRange is an optional created-at filter for artifacts.list. Both bounds are inclusive; a zero bound is unbounded on that side.

type Tool

type Tool struct {
	// ID is the stable catalog key (the tool's registered name).
	ID string `json:"id"`
	// Name is the planner-facing display name (equal to ID in V1).
	Name string `json:"name"`
	// Version is the tool descriptor version string ("" when unset).
	Version string `json:"version"`
	// Description is the planner-facing summary.
	Description string `json:"description"`
	// Scope is the tool's visibility scope: "tenant" | "agent" | "session".
	Scope string `json:"scope"`
	// Transport discriminates the tool's source.
	Transport ToolTransport `json:"transport"`
	// OAuthStatus is the tool's OAuth binding status.
	OAuthStatus ToolOAuthStatus `json:"oauth_status"`
	// ApprovalPolicy is the tool's HITL approval gate.
	ApprovalPolicy ToolApprovalPolicy `json:"approval_policy"`
	// ReliabilityTier is the operator-facing reliability label
	// (derived from the tool's side-effect class / cost hint).
	ReliabilityTier string `json:"reliability_tier"`
	// Owner is the configured owner / source identifier ("" when unset).
	Owner string `json:"owner"`
	// LastUsedAt is the timestamp of the most recent invocation; the
	// zero value means "never used".
	LastUsedAt time.Time `json:"last_used_at"`
}

Tool is the catalog-row projection of a registered tool descriptor. It is the row shape the Console Tools-page catalog table renders and the payload `tools.get` returns. Flat, low-cardinality strings — the Console branches on the enum fields.

type ToolAggregates

type ToolAggregates struct {
	// Total is the count of tools matching the filter.
	Total int64 `json:"total"`
	// Active is the count of tools with a non-zero LastUsedAt.
	Active int64 `json:"active"`
	// PendingApproval is the count of tools whose ApprovalPolicy is
	// "gated".
	PendingApproval int64 `json:"pending_approval"`
	// AwaitingOAuth is the count of tools whose OAuthStatus is
	// "Required" or "Expired".
	AwaitingOAuth int64 `json:"awaiting_oauth"`
}

ToolAggregates carries the four catalog counters the Tools-page right-rail overview card renders, computed over the FILTERED view.

type ToolApprovalPolicy

type ToolApprovalPolicy string

ToolApprovalPolicy is the wire enum for a tool's approval gate.

const (
	// ToolApprovalAuto — the tool runs without a HITL gate.
	ToolApprovalAuto ToolApprovalPolicy = "auto"
	// ToolApprovalGated — every invocation pauses for HITL approval.
	ToolApprovalGated ToolApprovalPolicy = "gated"
	// ToolApprovalDenied — the tool is administratively denied.
	ToolApprovalDenied ToolApprovalPolicy = "denied"
)

Canonical approval policies — the closed set `tools.set_approval_policy` accepts and the catalog table renders.

type ToolContentBucket

type ToolContentBucket struct {
	// MaxBytes is the inclusive upper bound of this bucket in bytes.
	MaxBytes int64 `json:"max_bytes"`
	// Count is the number of recent results that fell in this bucket.
	Count int64 `json:"count"`
}

ToolContentBucket is one power-of-two size bucket in the per-tool result-size histogram.

type ToolContentStats

type ToolContentStats struct {
	// ID echoes the requested tool ID.
	ID string `json:"id"`
	// Histogram is the result-size distribution, one bucket per
	// power-of-two byte range, ascending.
	Histogram []ToolContentBucket `json:"histogram"`
	// HeavyThresholdBytes is the configured heavy-content threshold
	// (D-026) — results at or above this size route through the
	// ArtifactStore by-reference.
	HeavyThresholdBytes int64 `json:"heavy_threshold_bytes"`
	// HeavyCount is the number of recent results at or above the
	// heavy-content threshold.
	HeavyCount int64 `json:"heavy_count"`
	// NegotiatedDisplay maps a MIME type to its negotiated MCP-Apps
	// DisplayMode (D-062); empty for non-MCP tools.
	NegotiatedDisplay map[string]string `json:"negotiated_display"`
}

ToolContentStats is the `tools.content_stats` reply — the per-tool distribution of recent result sizes vs the heavy-content threshold (RFC §6.5 / D-026) plus the negotiated DisplayMode snapshot (D-062).

type ToolContentStatsRequest

type ToolContentStatsRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the catalog key of the tool to report content stats for.
	ID string `json:"id"`
}

ToolContentStatsRequest is the `tools.content_stats` request body.

type ToolDescribeRequest

type ToolDescribeRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the catalog key of the tool to describe.
	ID string `json:"id"`
}

ToolDescribeRequest is the `tools.describe` request body.

type ToolFilter

type ToolFilter struct {
	// Scopes restricts to tools whose Scope is in this set.
	Scopes []string `json:"scopes,omitempty"`
	// Transports restricts to tools whose Transport is in this set.
	Transports []ToolTransport `json:"transports,omitempty"`
	// OAuthStatuses restricts to tools whose OAuthStatus is in this set.
	OAuthStatuses []ToolOAuthStatus `json:"oauth_statuses,omitempty"`
	// ApprovalPolicies restricts to tools whose ApprovalPolicy is in this set.
	ApprovalPolicies []ToolApprovalPolicy `json:"approval_policies,omitempty"`
	// ReliabilityTiers restricts to tools whose ReliabilityTier is in this set.
	ReliabilityTiers []string `json:"reliability_tiers,omitempty"`
	// Search is a free-text substring filter over tool name + version.
	Search string `json:"search,omitempty"`
}

ToolFilter is the server-enforced facet filter on `tools.list`. An empty facet slice matches every value on that axis. The filter is applied AFTER the identity-scope predicate — it never widens visibility.

type ToolGetRequest

type ToolGetRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the catalog key of the tool to project.
	ID string `json:"id"`
}

ToolGetRequest is the `tools.get` request body.

type ToolListRequest

type ToolListRequest struct {
	// Identity is the (tenant, user, session) scope the catalog is
	// projected for. Mandatory — an incomplete triple fails closed.
	Identity IdentityScope `json:"identity"`
	// Filter is the optional facet filter; the zero value lists every
	// visible tool.
	Filter ToolFilter `json:"filter"`
	// Page is the 1-based page index; a non-positive value means page 1.
	Page int `json:"page,omitempty"`
	// PageSize is the rows-per-page; a non-positive value applies
	// DefaultToolListPageSize. A value above MaxToolListPageSize is a
	// 400 (CodeInvalidRequest) — never a silent clamp.
	PageSize int `json:"page_size,omitempty"`
}

ToolListRequest is the `tools.list` request body.

type ToolListResponse

type ToolListResponse struct {
	// Tools is the page of catalog rows, sorted by Name.
	Tools []Tool `json:"tools"`
	// Page is the 1-based page index this response covers.
	Page int `json:"page"`
	// PageSize is the rows-per-page applied.
	PageSize int `json:"page_size"`
	// PageCount is the total number of pages for the filtered view.
	PageCount int `json:"page_count"`
	// TotalRows is the total row count for the filtered view.
	TotalRows int64 `json:"total_rows"`
	// Aggregates carries the four catalog counters for the filtered view.
	Aggregates ToolAggregates `json:"aggregates"`
}

ToolListResponse is the `tools.list` reply: a paginated slice of catalog rows plus the filtered-view aggregates.

type ToolManifest

type ToolManifest struct {
	// Tool is the catalog-row projection (same shape as `tools.get`).
	Tool Tool `json:"tool"`
	// SideEffect is the declared side-effect class
	// ("pure" | "read" | "write" | "external" | "stateful").
	SideEffect string `json:"side_effect"`
	// ArgsSchema is the raw JSON-Schema (object) for the tool's
	// argument shape, as a JSON string ("" when the tool declares none).
	ArgsSchema string `json:"args_schema"`
	// OutSchema is the raw JSON-Schema (object) for the tool's result
	// shape, as a JSON string ("" when the tool declares none).
	OutSchema string `json:"out_schema"`
	// Examples carries the canonical argument-shape examples, each a
	// JSON string.
	Examples []string `json:"examples"`
	// AuthScopes lists the scopes a planner step's identity must carry
	// for the tool to be visible.
	AuthScopes []string `json:"auth_scopes"`
	// OAuthBindingScope is the tool's OAuth binding scope per D-083
	// ("user" | "agent" | "" when the tool requires no OAuth).
	OAuthBindingScope string `json:"oauth_binding_scope"`
	// RetryAttempts is the reliability shell's configured retry budget
	// (D-024).
	RetryAttempts int `json:"retry_attempts"`
	// TimeoutMS is the reliability shell's per-attempt timeout in
	// milliseconds (0 when the policy applies its default).
	TimeoutMS int64 `json:"timeout_ms"`
	// LoadingMode is the prompt-time loading mode ("always" | "deferred").
	LoadingMode string `json:"loading_mode"`
	// DisplayModes maps a MIME type to its negotiated MCP-Apps
	// DisplayMode (D-062); empty for non-MCP tools.
	DisplayModes map[string]string `json:"display_modes"`
}

ToolManifest is the full descriptor projection `tools.describe` returns — the read-only manifest the Tools-page Manifest / Inputs / Outputs tabs render.

type ToolMetrics

type ToolMetrics struct {
	// ID echoes the requested tool ID.
	ID string `json:"id"`
	// Window echoes the resolved observation window.
	Window ToolMetricsWindow `json:"window"`
	// ErrorRate1h is the fraction of failed invocations over the last 1h.
	ErrorRate1h float64 `json:"error_rate_1h"`
	// ErrorRate24h is the fraction of failed invocations over the last 24h.
	ErrorRate24h float64 `json:"error_rate_24h"`
	// ErrorRate7d is the fraction of failed invocations over the last 7d.
	ErrorRate7d float64 `json:"error_rate_7d"`
	// Invocations is the total invocation count over the selected window.
	Invocations int64 `json:"invocations"`
	// Failures is the failed-invocation count over the selected window.
	Failures int64 `json:"failures"`
	// Status is the health pill for the selected window.
	Status ToolStatus `json:"status"`
}

ToolMetrics is the `tools.metrics` reply — per-tool error-rate gauges over the three fixed windows plus a status pill for the selected window.

type ToolMetricsRequest

type ToolMetricsRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the catalog key of the tool to report metrics for.
	ID string `json:"id"`
	// Window selects the observation window; an empty value applies
	// ToolWindow1h.
	Window ToolMetricsWindow `json:"window,omitempty"`
}

ToolMetricsRequest is the `tools.metrics` request body.

type ToolMetricsWindow

type ToolMetricsWindow string

ToolMetricsWindow is the wire enum for the `tools.metrics` selectable observation window.

const (
	ToolWindow1h  ToolMetricsWindow = "1h"
	ToolWindow24h ToolMetricsWindow = "24h"
	ToolWindow7d  ToolMetricsWindow = "7d"
)

Canonical metrics windows — the 1h / 24h / 7d toggle in the mockup.

type ToolOAuthStatus

type ToolOAuthStatus string

ToolOAuthStatus is the wire enum for a tool's OAuth binding status.

const (
	// ToolOAuthBound — the tool requires OAuth and a live binding exists.
	ToolOAuthBound ToolOAuthStatus = "Bound"
	// ToolOAuthRequired — the tool requires OAuth but no binding exists.
	ToolOAuthRequired ToolOAuthStatus = "Required"
	// ToolOAuthExpired — the tool requires OAuth and the binding lapsed.
	ToolOAuthExpired ToolOAuthStatus = "Expired"
	// ToolOAuthNotApplicable — the tool does not require OAuth.
	ToolOAuthNotApplicable ToolOAuthStatus = "n/a"
)

Canonical OAuth statuses surfaced in the catalog table.

type ToolRevokeOAuthRequest

type ToolRevokeOAuthRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the catalog key of the tool whose OAuth bindings to revoke.
	ID string `json:"id"`
}

ToolRevokeOAuthRequest is the `tools.revoke_oauth` request body. ADMIN method — requires the verified `auth.ScopeAdmin` claim (D-079).

type ToolRevokeOAuthResponse

type ToolRevokeOAuthResponse struct {
	// ID echoes the tool ID whose bindings were revoked.
	ID string `json:"id"`
	// RevokedCount is the number of OAuth bindings revoked.
	RevokedCount int64 `json:"revoked_count"`
}

ToolRevokeOAuthResponse is the `tools.revoke_oauth` reply.

type ToolSetApprovalPolicyRequest

type ToolSetApprovalPolicyRequest struct {
	// Identity is the (tenant, user, session) scope. Mandatory.
	Identity IdentityScope `json:"identity"`
	// ID is the catalog key of the tool to update.
	ID string `json:"id"`
	// Policy is the new approval policy; must be a valid
	// ToolApprovalPolicy or the request is rejected with
	// CodeInvalidRequest.
	Policy ToolApprovalPolicy `json:"policy"`
}

ToolSetApprovalPolicyRequest is the `tools.set_approval_policy` request body. ADMIN method — requires the verified `auth.ScopeAdmin` claim (D-079).

type ToolSetApprovalPolicyResponse

type ToolSetApprovalPolicyResponse struct {
	// ID echoes the updated tool ID.
	ID string `json:"id"`
	// Policy echoes the applied approval policy.
	Policy ToolApprovalPolicy `json:"policy"`
}

ToolSetApprovalPolicyResponse is the `tools.set_approval_policy` reply.

type ToolStatus

type ToolStatus string

ToolStatus is the wire enum for a tool's health pill.

const (
	ToolStatusHealthy  ToolStatus = "Healthy"
	ToolStatusDegraded ToolStatus = "Degraded"
	ToolStatusOffline  ToolStatus = "Offline"
)

Canonical tool health statuses surfaced by `tools.metrics`.

type ToolTransport

type ToolTransport string

ToolTransport is the wire enum for a tool's transport. It is the Protocol projection of the runtime-internal `tools.TransportKind`.

const (
	ToolTransportInProc ToolTransport = "in-proc"
	ToolTransportHTTP   ToolTransport = "HTTP"
	ToolTransportMCP    ToolTransport = "MCP"
	ToolTransportA2A    ToolTransport = "A2A"
	ToolTransportFlow   ToolTransport = "flow"
)

Canonical tool transports — the closed set the catalog supports.

type TopologyEdge

type TopologyEdge struct {
	// From is the upstream node's Name.
	From string `json:"from"`
	// To is the downstream node's Name.
	To string `json:"to"`
	// QueueDepth is the number of envelopes currently buffered on the
	// (From → To) channel — len(channel) at projection time.
	QueueDepth int `json:"queue_depth"`
	// QueueCapacity is the bounded buffer size of the (From → To)
	// channel — cap(channel). A consumer renders QueueDepth /
	// QueueCapacity as a saturation indicator.
	QueueCapacity int `json:"queue_capacity"`
}

TopologyEdge is one directed edge of the projected graph plus its live bounded-channel state. QueueDepth / QueueCapacity are the liveness fields the Live Runtime canvas renders as a fill bar.

type TopologyNode

type TopologyNode struct {
	// Name is the node's unique identifier within the engine.
	Name string `json:"name"`
	// Kind is the node's role tag — inlet / node / outlet.
	Kind TopologyNodeKind `json:"kind"`
}

TopologyNode is one vertex of the projected graph — a name plus a role tag. Status / latency / selection are deliberately absent: they are per-run overlays the consumer composes from the event stream.

type TopologyNodeKind

type TopologyNodeKind string

TopologyNodeKind tags a node's role in the graph. The V1 set is closed — inlet (no parent), node (intermediate), outlet (no child).

const (
	// NodeKindInlet tags a node with no incoming edge — an entry point
	// where an external Emit lands.
	NodeKindInlet TopologyNodeKind = "inlet"
	// NodeKindNode tags an intermediate node — it has both a parent and
	// a child.
	NodeKindNode TopologyNodeKind = "node"
	// NodeKindOutlet tags a node with no outgoing edge — an exit point
	// that writes to the engine's egress.
	NodeKindOutlet TopologyNodeKind = "outlet"
)

The V1 node-kind constants. A node with no parent is an inlet; a node with no child is an outlet; every other node is a plain node.

type TopologyProjection

type TopologyProjection struct {
	// EngineID identifies the engine the projection describes. In V1
	// (one engine per Runtime process) it is the Runtime's engine id;
	// the field exists so a post-V1 multi-engine Runtime can scope a
	// projection without a wire-shape break.
	EngineID string `json:"engine_id"`
	// OccurredAt is the wall-clock instant the projection was built.
	// On the `topology.changed` event it is the construction / edge-
	// change time; on a `topology.snapshot` reply it is the snapshot
	// time.
	OccurredAt time.Time `json:"occurred_at"`
	// Nodes is the engine's node set, sorted lexicographically by Name
	// for byte-stability across snapshots of the same engine.
	Nodes []TopologyNode `json:"nodes"`
	// Edges is the engine's directed edge set, sorted lexicographically
	// by (From, To) for byte-stability.
	Edges []TopologyEdge `json:"edges"`
}

TopologyProjection is the canonical Protocol wire shape of an engine's node graph (Phase 74 / D-114). It is the projection a Protocol client — the Live Runtime topology canvas (Phase 73b), the Playground trace toggle (Phase 73n), a third-party Console — renders the engine's static graph + live per-edge queue depth from. It is NOT a re-export of any internal Runtime type: the Runtime constructs a TopologyProjection from its private adjacency list + per-edge channel state at request / emit time, and the consumer never sees those internals (CLAUDE.md §8; RFC §5.1 — a Protocol type that mapped 1:1 onto an internal Go struct would be the reject-on-sight smell).

The projection is engine-scoped, not run-scoped: it carries the static graph plus the live channel depth, both byte-stable across runs of the same engine. Per-run overlays (node status, latency, selection state) are NOT here — the consumer composes those from the existing event taxonomy (`tool.invoked`, `task.spawned`, `pause.requested`, ...). See D-114.

TopologyProjection is the wire shape on BOTH Phase 74 surfaces: the `topology.snapshot` Protocol method (request → reply) returns one, and the `topology.changed` canonical event carries one in its payload.

func (*TopologyProjection) SortDeterministic

func (p *TopologyProjection) SortDeterministic()

SortDeterministic sorts the projection's Nodes (by Name) and Edges (by From then To) in place so two projections of the same engine marshal to byte-identical JSON. The Runtime calls this before returning a projection on either Phase 74 surface; callers constructing a projection by hand (tests) call it to get the canonical ordering.

type TopologySnapshotRequest

type TopologySnapshotRequest struct {
	// Identity is the mandatory caller identity scope. An incomplete
	// triple fails the request closed with CodeIdentityRequired.
	Identity IdentityScope `json:"identity"`
}

TopologySnapshotRequest is the wire request for the `topology.snapshot` Protocol method. It carries the flat identity scope the runtime-side surface translates into the runtime's identity triple at the edge — identity is mandatory (RFC §5.5). The request targets the Runtime's engine; a cross-tenant snapshot (Identity.Tenant ≠ the engine's tenant) requires the verified `auth.ScopeAdmin` claim (D-079).

type Version

type Version struct {
	// Major is bumped on a breaking Protocol change. Two versions are
	// Compatible iff their Major components are equal.
	Major int
	// Minor is bumped on a backward-compatible surface addition (a new
	// method, a new capability, a new optional wire field).
	Minor int
	// Patch is bumped on a backward-compatible fix with no surface
	// change.
	Patch int
}

Version is the parsed, comparable form of a Harbor Protocol version: a `MAJOR.MINOR.PATCH` triple of non-negative integers. The string ProtocolVersion is the pinned source of truth and the RFC-change trip-wire; Version is what a client uses to *reason* about a version — to detect skew (Compatible) or order two versions (Compare).

Version is an immutable value type — safe to copy, compare, and share across goroutines without synchronisation.

func ParseVersion

func ParseVersion(s string) (Version, error)

ParseVersion parses a `MAJOR.MINOR.PATCH` string into a Version. Each component must be a non-negative base-10 integer; anything else (empty input, wrong arity, a non-numeric or negative component, surrounding whitespace) fails loudly with a wrapped ErrInvalidVersion.

func (Version) Compare

func (v Version) Compare(o Version) int

Compare orders two versions component-wise (Major, then Minor, then Patch). It returns -1 if v sorts before o, +1 if after, 0 if equal.

func (Version) Compatible

func (v Version) Compatible(o Version) bool

Compatible reports whether a client speaking version o can talk to a Runtime speaking version v. The rule is same-Major: a Major bump is a breaking change (which is why bumping it is an RFC change, RFC §5.3), so a client and a Runtime are compatible iff their Major components match — Minor / Patch differences are backward-compatible by construction. Compatible is symmetric: v.Compatible(o) == o.Compatible(v).

func (Version) String

func (v Version) String() string

String renders the Version back to its canonical `MAJOR.MINOR.PATCH` form. String(ParseVersion(s)) == s for every well-formed s.

type VersionHandshake

type VersionHandshake struct {
	// ProtocolVersion is the version string the Runtime speaks — the
	// ProtocolVersion constant. A client parses it (ParseVersion) and
	// checks Compatible against its own.
	ProtocolVersion string `json:"protocol_version"`
	// Capabilities is the set of Protocol surfaces the Runtime
	// advertises as live — deterministically sorted (Capabilities()).
	Capabilities []Capability `json:"capabilities"`
}

VersionHandshake is the capability-negotiation wire shape: the Protocol version the Runtime speaks plus the set of surfaces it advertises. A Protocol client compares the handshake's version against its own (Version.Compatible) to detect skew, and checks Accepts(cap) before exercising a surface — so a third-party Console built against an older Protocol negotiates explicitly instead of discovering a missing surface by a 404.

VersionHandshake is a wire type — it round-trips through JSON; a Phase 60 transport adapter serves CurrentHandshake() at the negotiation entry point.

func CurrentHandshake

func CurrentHandshake() VersionHandshake

CurrentHandshake builds the Runtime's VersionHandshake from the pinned ProtocolVersion and the advertised Capabilities() set. It is the value a negotiation entry point (Phase 60) returns to a connecting client.

func (VersionHandshake) Accepts

func (h VersionHandshake) Accepts(c Capability) bool

Accepts reports whether the handshake advertises capability c — i.e. whether the Runtime that produced this handshake has the corresponding Protocol surface live.

type Window

type Window struct {
	// From is the inclusive lower bound; nil ⇒ unbounded below.
	From *time.Time `json:"from,omitempty"`
	// To is the inclusive upper bound; nil ⇒ unbounded above.
	To *time.Time `json:"to,omitempty"`
}

Window is a half-open time range filter. Both bounds are optional; a nil bound means "unbounded on that side". A non-nil From / To filters sessions whose StartedAt falls inside [From, To].

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL