Documentation
¶
Overview ¶
Package stream — addition: the admin-scoped `agent_config.*` agent-config control-plane HTTP handler. Like the governance handler, this is a one-shot request/response endpoint — POST JSON in, JSON out — sharing the same `resolveIdentity` + defence-in-depth body-identity machinery.
Route shape (POST):
POST /v1/agent_config/get — read the active revision POST /v1/agent_config/set_revision — write a new revision POST /v1/agent_config/list_revisions — the revision chain POST /v1/agent_config/diff — compare two revisions POST /v1/agent_config/rollback — repoint the active pointer POST /v1/agent_config/set_tool_exposure — set MCP pause/resume + per-tool policy POST /v1/agent_config/set_prompt_layers — set the layered system prompt (base + user) POST /v1/agent_config/add_mcp_connection — add a NEW MCP server connection (dial + handshake + OAuth) POST /v1/agent_config/skills/list — list the agent's skills POST /v1/agent_config/skills/upsert — upsert a skill (records a rev) POST /v1/agent_config/skills/delete — delete a skill (records a rev)
Every route is identity-mandatory AND admin-scoped (the whole family changes/reads what an agent can do — a capability surface): the verified `auth.ScopeAdmin` claim is required. A non-admin caller is rejected with CodeScopeMismatch (403) before the request reaches the service. Authority derives from the verified ctx, never the request body (authority from the verified ctx). The handler overlays the verified identity onto the request body.
AgentConfigHandler is a concurrency-safe compiled artifact — service / logger are set once at construction; ServeHTTP holds no per-request state.
Package stream — additions: the `agents.*` HTTP handler. Like `tools.*` and `memory.*`, the eight Agents-page methods are one-shot request/response — POST JSON in, JSON out — and the handler lives in the stream package because its identity + scope-claim gating reuses the same `resolveIdentity` / `auth.HasScope` machinery the subscription surface uses.
Route shape:
POST /v1/agents/{method}
where {method} is the canonical method's verb suffix:
list | get | tools | memory | governance | skills | permissions | metrics
The handler reads identity from r.Context() (auth.Middleware) or the X-Harbor-* carrier headers (fallback), decodes the JSON body into the method-specific wire request, dispatches into the agentsprotocol.Service, and encodes the response. On failure, a JSON error body with the canonical Protocol Code, identical in shape to the REST control transport's error body.
All eight `agents.*` methods are READ-ONLY projections of the Agent Registry. The five agent-control verbs the Console exposes (Pause / Drain / Restart / Force-Stop / Deregister) are NOT served here — they are the EXISTING shipped `registry.*` control verbs and Harbor mints no control method (CLAUDE.md §13).
Identity is mandatory: a missing / incomplete (tenant, user, session) triple fails closed with CodeIdentityRequired (401). `agent_id` is a registration identity, not an isolation filter — the runtime scopes by the tuple, never by `agent_id` (CLAUDE.md §6).
Package stream — additions: the `auth.*` HTTP handler. Like `tools.*` and `tasks.*`, the single `auth.*` method (`auth.rotate_token`) is one-shot request/response — POST JSON in, JSON out — and the handler lives in the stream package because its identity + scope-claim gating reuses the same `resolveIdentity` / `auth.HasScope` machinery the subscription surface uses.
Route shape:
POST /v1/auth/{method}
where {method} is the canonical method's verb suffix:
rotate_token
`auth.rotate_token` is the ONE net-new Protocol method Harbor ships — the Console Settings page is otherwise a pure consumer of the 72f / 72g posture surfaces. It is an ADMIN method: it rotates the operator's current Protocol-auth token and requires the verified `auth.ScopeAdmin` claim (closed two-scope set — there is NO `auth.admin` scope). A request without the claim is rejected 403 with the canonical CodeIdentityScopeRequired Code. Every successful rotation emits a redacted `audit.admin_scope_used` event through the shipped audit.Redactor (the emit lives in auth.RotateSurface — the handler never bypasses the audit redactor; CLAUDE.md §7 rule 6, §13).
Package stream — additions: the Console Flows-page HTTP handler. Like `events.aggregate` and `pause.list`, these are one-shot request/response endpoints — POST JSON in, JSON out. They live in the stream package because their identity + cross-tenant scope-claim gating is the same one Subscribe / Aggregate / PauseList use, and they share the route prefix family the Console surface registers.
Route shapes (all POST):
POST /v1/flows/list — paginated flow catalog POST /v1/flows/describe — a flow's engine-graph description POST /v1/flows/runs/list — a flow's paginated run history POST /v1/flows/runs/describe — a single run's per-node timeline POST /v1/flows/run — invoke a one-shot run (mutating) POST /v1/flows/metrics — a flow's sparkline metrics
Five routes are read-only; `flows/run` mutates and is gated on the verified `auth.ScopeAdmin` claim (closed two-scope set — NO new scope is minted). Every route is identity-mandatory.
The handler emits a per-page audit event on every dispatch: `flows.page_viewed` for the five reads, `flows.run_invoked` for the mutating run. The events flow through the canonical EventBus so the Console activity feed and the audit log see Flows-page traffic.
FlowsHandler is a concurrency-safe compiled artifact — surface / bus / logger are set once at construction; ServeHTTP holds no per-request state.
Package stream — addition: the admin-scoped `governance.*` tenant-default override HTTP handler. Like the Agents / Runs page handlers, this is a one-shot request/response endpoint — POST JSON in, JSON out — sharing the same `resolveIdentity` + defence-in-depth body-identity machinery.
Route shape (POST):
POST /v1/governance/set_tenant_overrides — set/clear a tenant default POST /v1/governance/get_tenant_overrides — read a tenant default
Both routes are identity-mandatory AND admin-scoped: they MUTATE / read the tenant control plane, so the verified `auth.ScopeAdmin` claim is required. A non-admin caller is rejected with CodeScopeMismatch (403) before the request reaches the service. The tenant whose defaults are set/read is the caller's verified tenant (the handler overlays the verified identity onto the request body).
GovernanceHandler is a concurrency-safe compiled artifact — service / logger are set once at construction; ServeHTTP holds no per-request state.
Package stream — additions: the `events.aggregate` HTTP handler. Unlike `events.subscribe` (long-lived SSE), this is a one-shot request/response — POST JSON in, JSON out. It lives in the stream package because it shares the same events- subsystem dependencies and route prefix (`/v1/events*`), and its scope-claim gating is the same one Subscribe uses.
Route shape:
POST /v1/events/aggregate
The handler reads identity from r.Context() (auth.Middleware) and gates cross-tenant filters on auth.HasScope(ScopeAdmin) OR auth.HasScope(ScopeConsoleFleet). The response body is the wire EventAggregateResponse JSON; on failure, a JSON error body with the canonical Protocol Code.
Package stream — additions: the three `memory.*` read handlers. Like `events.aggregate` and `pause.list`, these are one-shot request/response — POST JSON in, JSON out — and they live in the stream package because their identity + cross-tenant scope-claim gating is the same one Subscribe / Aggregate / PauseList use, and they share the route prefix family the Console subscription surface registers.
Route shapes:
POST /v1/memory/list POST /v1/memory/get POST /v1/memory/health
The handler reads identity from r.Context() (auth.Middleware) or the X-Harbor-* carrier headers (fallback), decodes the JSON body, gates cross-tenant filters on auth.HasScope(ScopeAdmin) OR auth.HasScope(ScopeConsoleFleet) — the admin closed two-scope set, NO new memory scope (audit B1) — projects the answer from the memory subsystem, and encodes the response. The response body is the wire types.Memory* JSON; on failure, a JSON error body with the canonical Protocol Code.
All three methods are READ-ONLY. The memory mutation surface (`memory.put` / `memory.delete`) is deferred to a later phase / post-V1 (page-memory.md §10); this handler ships no mutation path.
Package stream — additions: the `pause.list` HTTP handler. Like `events.aggregate`, this is a one-shot request/response — POST JSON in, JSON out — and it lives in the stream package because its identity + cross-tenant scope-claim gating is the same one Subscribe / Aggregate use, and it shares the route prefix family the Console subscription surface registers.
Route shape:
POST /v1/pause/list
The handler reads identity from r.Context() (auth.Middleware) or the X-Harbor-* carrier headers (fallback), decodes the JSON body into a types.PauseListRequest, gates cross-tenant filters on auth.HasScope(ScopeAdmin), projects the snapshot from the unified pause/resume Coordinator, applies the heavy-content bypass on each row, and encodes the response. The response body is the wire types.PauseListResponse JSON; on failure, a JSON error body with the canonical Protocol Code.
pause.list is READ-ONLY against the Coordinator — it does NOT call Resume, does NOT clear checkpoints. Resume actions continue through the `resume` / `approve` / `reject` control methods. The unified pause/resume primitive is never bypassed: pause.list reads the shipped Coordinator state, it does not reinvent pause coordination (CLAUDE.md §7 rule 4, §13).
Package stream — addition: the Console Playground-page `runs.set_overrides` HTTP handler. Like the Sessions / Tasks / Flows page handlers, this is a one-shot request/response endpoint — POST JSON in, JSON out. It lives in the stream package because its identity resolution + defence-in-depth body-identity check are the same `resolveIdentity` machinery the other Console-page handlers use.
Route shape (POST):
POST /v1/runs/set_overrides — record the next-message override
The route is identity-mandatory. The override's target session (`overrides.session_id`) MUST equal the caller's verified session; the runs/protocol.Service rejects a cross-session target with CodeScopeMismatch (403). `runs.set_overrides` is NOT an admin method — it records an override for the operator's OWN session, so no cross-tenant scope claim is consulted.
RunsHandler is a concurrency-safe compiled artifact — service / logger are set once at construction; ServeHTTP holds no per-request state.
Package stream — additions: the Console Sessions-page HTTP handler. Like `events.aggregate`, `pause.list`, and the Flows-page handler, these are one-shot request/response endpoints — POST JSON in, JSON out. They live in the stream package because their identity + cross-tenant scope-claim gating is the same `resolveIdentity` / `auth.HasScope` machinery the subscription surface uses.
Route shapes (both POST):
POST /v1/sessions/list — paginated, filtered session catalog POST /v1/sessions/inspect — a single session's full snapshot
Both routes are read-only and identity-mandatory. A cross-tenant `sessions.list` filter (a `tenant_ids` entry outside the caller's verified tenant) is gated on the verified `auth.ScopeAdmin` claim (closed two-scope set — NO new scope is minted); the sessions/protocol.Service emits an `audit.admin_scope_used` event on every successful admin-scope query.
SessionsHandler is a concurrency-safe compiled artifact — service / logger are set once at construction; ServeHTTP holds no per-request state.
Package stream is the Harbor Protocol SSE event transport — the server→client half of the wire binding RFC §5.4 resolves to (SSE for events + REST/JSON for control). It is a thin adapter over the events.EventBus: a Handler opens a triple-scoped events.Subscription and frames each events.Event as an SSE block (frame.go). The SSE transport adds the wire framing and the connection lifecycle; it adds NO second event channel — the "one bus, no parallel observability channel" is load-bearing.
The route shape ¶
GET /v1/events
The identity triple is carried in request headers (X-Harbor-Tenant / X-Harbor-User / X-Harbor-Session) — a header carrier, not a query string, so the triple is not logged in access logs by default and the JWT validation slots in at the same choke point. An optional X-Harbor-Event-Type header (repeatable) narrows the subscription's event-type selector.
Identity at the edge (RFC §5.5, CLAUDE.md §6) ¶
The handler resolves the triple from the headers and rejects a request with any missing component closed — HTTP 401, before any subscription is opened. The SSE stream is ALWAYS triple-scoped: events.Filter.Admin (cross-tenant fan-in) is NOT exposed on the wire in a later phase — it needs the cryptographic scope claim Harbor adds. resolveIdentity is the single choke point slots JWT validation into.
Reconnect cursor ¶
SSE's native reconnect mechanism is the Last-Event-ID header: a client that drops echoes back the `id:` of the last frame it saw. The handler maps that onto an events.Cursor and, when the bus driver implements events.Replayer, replays the events strictly newer than the cursor before live-tailing — so a reconnecting client does not miss the gap. When the driver does not support replay (or replay is configured off), the handler live-tails from the reconnect point and emits a single explicit `stream.replay_unavailable` comment frame so the gap is SURFACED, never silently masked (CLAUDE.md §5).
Concurrent reuse ¶
Handler is a compiled artifact: the bus, the logger, the keepalive interval and the clock are set once at construction and never mutated. ServeHTTP holds no per-request state on the Handler — each request gets its own events.Subscription, its own keepalive ticker, and its own goroutine, all torn down before ServeHTTP returns. One Handler serves N concurrent streams safely; the goroutine for a stream is cancelled by that request's ctx, never by a shared handler-level ctx (CLAUDE.md §5 "Concurrency"). internal/protocol/transports/ concurrent_test.go pins it under -race.
Package stream — additions: the `tasks.*` HTTP handler. Like `tools.*` and `pause.list`, the two Tasks-page read methods are one-shot request/response — POST JSON in, JSON out — and the handler lives in the stream package because its identity + cross-tenant scope-claim gating reuses the same `resolveIdentity` / `auth.HasScope` machinery the subscription surface uses.
Route shape:
POST /v1/tasks/{method}
where {method} is the canonical method's verb suffix:
list | get
The handler reads identity from r.Context() (auth.Middleware) or the X-Harbor-* carrier headers (fallback), decodes the JSON body into the method-specific wire request, computes the verified `auth.ScopeAdmin` claim (consulted by `tasks.list` only for a cross-tenant fan-in), dispatches into the tasksprotocol.Service, and encodes the response. On failure, a JSON error body with the canonical Protocol Code, identical in shape to the REST control transport's error body.
The handler is READ-ONLY: both methods are pure reads. The Console Tasks page consumes the EXISTING task-control verbs (`cancel` / `pause` / `resume` / `prioritize` / `approve` / `reject`) for mutation through the control transport — there is NO `tasks.*` mutating method (CLAUDE.md §13 "no parallel implementations").
Package stream — additions: the `tools.*` HTTP handler. Like `pause.list` and `events.aggregate`, the seven Tools- page methods are one-shot request/response — POST JSON in, JSON out — and the handler lives in the stream package because its identity + cross-tenant scope-claim gating reuses the same `resolveIdentity` / `auth.HasScope` machinery the subscription surface uses.
Route shape:
POST /v1/tools/{method}
where {method} is the canonical method's verb suffix:
list | get | describe | metrics | content_stats | set_approval_policy | revoke_oauth
The handler reads identity from r.Context() (auth.Middleware) or the X-Harbor-* carrier headers (fallback), decodes the JSON body into the method-specific wire request, gates the two admin methods on the verified `auth.ScopeAdmin` claim (there is NO `tools.admin` scope), dispatches into the toolsprotocol.Service, and encodes the response. On failure, a JSON error body with the canonical Protocol Code, identical in shape to the REST control transport's error body.
The handler is READ-MOSTLY: five of the seven methods are pure reads. The two admin methods mutate runtime tool state and emit an `audit.admin_scope_used` event through the shipped audit.Redactor (the emit lives in toolsprotocol.Service — the handler never bypasses the audit redactor; CLAUDE.md §7 rule 6, §13).
Index ¶
- Constants
- Variables
- type AgentConfigHandler
- type AgentConfigOption
- type AgentsHandler
- type AgentsOption
- type AggregateHandler
- type AggregateOption
- type AuthHandler
- type AuthOption
- type FlowsHandler
- type FlowsOption
- type FlowsPageViewedPayload
- type FlowsRunInvokedPayload
- type GovernanceHandler
- type GovernanceOption
- type Handler
- type MemoryHandler
- func (h *MemoryHandler) DeleteHandler() http.Handler
- func (h *MemoryHandler) GetHandler() http.Handler
- func (h *MemoryHandler) HealthHandler() http.Handler
- func (h *MemoryHandler) ListHandler() http.Handler
- func (h *MemoryHandler) PutHandler() http.Handler
- func (h *MemoryHandler) StrategyTraceHandler() http.Handler
- type MemoryOption
- type Option
- type PauseListHandler
- type PauseListOption
- type RunsHandler
- type RunsOption
- type SessionsHandler
- type SessionsOption
- type TasksHandler
- type TasksOption
- type ToolsHandler
- type ToolsOption
Constants ¶
const ( // EventTypeFlowsPageViewed — emitted on every read dispatch // (flows.list / describe / runs.list / runs.describe / metrics). EventTypeFlowsPageViewed events.EventType = "flows.page_viewed" // EventTypeFlowsRunInvoked — emitted when a `flows.run` dispatch is // accepted. The mutating-action audit signal. EventTypeFlowsRunInvoked events.EventType = "flows.run_invoked" )
Flows-page audit event types. They flow through the canonical EventBus so the Console activity feed + audit log see Flows-page traffic. Registered from this package's init().
const ( MemoryListRoutePattern = "POST /v1/memory/list" MemoryGetRoutePattern = "POST /v1/memory/get" MemoryHealthRoutePattern = "POST /v1/memory/health" MemoryStrategyTraceRoutePattern = "POST /v1/memory/strategy_trace" MemoryPutRoutePattern = "POST /v1/memory/put" MemoryDeleteRoutePattern = "POST /v1/memory/delete" )
Memory route patterns the handler registers under. Exported so internal/protocol/transports can mount each route under the same pattern it documents.
const ( HeaderTenant = "X-Harbor-Tenant" HeaderUser = "X-Harbor-User" HeaderSession = "X-Harbor-Session" HeaderRun = "X-Harbor-Run" HeaderEventType = "X-Harbor-Event-Type" )
Identity-carrier header names. The triple travels in headers, not a query string, so it does not land in access logs by default and so the JWT validation replaces a single resolve step.
HeaderRun is optional — when present, the subscription is run-scoped (events.Filter.Run is set, so only events with a matching RunID flow through). When absent, the subscription is session-scoped (the default; every run in the session is observed). Added in PR #91per checkpoint audit WARN-5.
const AgentConfigRoutePattern = "POST /v1/agent_config/"
AgentConfigRoutePattern is the http.ServeMux prefix pattern the agent-config admin handler registers under. The handler internally branches on the trailing path segment to dispatch.
const AgentsRoutePattern = "POST /v1/agents/{method}"
AgentsRoutePattern is the http.ServeMux pattern the Agents handler registers under. The {method} wildcard is read via r.PathValue.
const AggregateRoutePattern = "POST /v1/events/aggregate"
AggregateRoutePattern is the http.ServeMux pattern the events-aggregate handler registers under. Exported so internal/protocol/transports can mount the handler under the same pattern it documents.
const AuthRoutePattern = "POST /v1/auth/{method}"
AuthRoutePattern is the http.ServeMux pattern the auth handler registers under. The {method} wildcard is read via r.PathValue.
const FlowsRoutePattern = "POST /v1/flows/"
FlowsRoutePattern is the http.ServeMux prefix pattern the Flows-page handler registers under. The handler internally branches on the trailing path segment to dispatch the six methods. Exported so internal/protocol/transports can mount the handler under the same prefix it documents.
const GovernanceRoutePattern = "POST /v1/governance/"
GovernanceRoutePattern is the http.ServeMux prefix pattern the governance admin handler registers under. The handler internally branches on the trailing path segment to dispatch.
const PauseListRoutePattern = "POST /v1/pause/list"
PauseListRoutePattern is the http.ServeMux pattern the pause-list handler registers under. Exported so internal/protocol/transports can mount the handler under the same pattern it documents.
const RoutePattern = "GET /v1/events"
RoutePattern is the http.ServeMux pattern the SSE transport registers under. Exported so internal/protocol/transports can mount the handler under the same pattern it documents.
const RunsRoutePattern = "POST /v1/runs/"
RunsRoutePattern is the http.ServeMux prefix pattern the Runs-page handler registers under. The handler internally branches on the trailing path segment to dispatch.
const SessionsRoutePattern = "POST /v1/sessions/"
SessionsRoutePattern is the http.ServeMux prefix pattern the Sessions-page handler registers under. The handler internally branches on the trailing path segment to dispatch the two methods.
const TasksRoutePattern = "POST /v1/tasks/{method}"
TasksRoutePattern is the http.ServeMux pattern the Tasks handler registers under. The {method} wildcard is read via r.PathValue.
const ToolsRoutePattern = "POST /v1/tools/{method}"
ToolsRoutePattern is the http.ServeMux pattern the Tools handler registers under. The {method} wildcard is read via r.PathValue.
Variables ¶
var ErrAgentConfigMisconfigured = errors.New("stream: agent-config handler missing a mandatory dependency")
ErrAgentConfigMisconfigured — NewAgentConfigHandler was called with a nil service.
var ErrAgentsMisconfigured = errors.New("stream: agents handler missing a mandatory dependency")
ErrAgentsMisconfigured — NewAgentsHandler was called with a nil agentsprotocol.Service.
var ErrAggregateMisconfigured = errors.New("stream: aggregate handler missing a mandatory dependency")
ErrAggregateMisconfigured — NewAggregateHandler was called with a nil Aggregator.
var ErrAuthMisconfigured = errors.New("stream: auth handler missing a mandatory dependency")
ErrAuthMisconfigured — NewAuthHandler was called with a nil auth.RotateSurface.
var ErrFlowsMisconfigured = errors.New("stream: flows handler missing a mandatory dependency")
ErrFlowsMisconfigured — NewFlowsHandler was called with a nil mandatory dependency.
var ErrGovernanceMisconfigured = errors.New("stream: governance handler missing a mandatory dependency")
ErrGovernanceMisconfigured — NewGovernanceHandler was called with a nil service.
var ErrMemoryHandlerMisconfigured = errors.New("stream: memory handler missing a mandatory dependency")
ErrMemoryHandlerMisconfigured — NewMemoryHandler was called with a nil mandatory dependency (MemoryStore, ArtifactStore, or the heavy-content threshold was non-positive).
var ErrMisconfigured = errors.New("stream: SSE transport missing a mandatory dependency")
ErrMisconfigured — NewHandler was called with a nil EventBus.
var ErrPauseListMisconfigured = errors.New("stream: pause.list handler missing a mandatory dependency")
ErrPauseListMisconfigured — NewPauseListHandler was called with a nil mandatory dependency (Coordinator, ArtifactStore, or the heavy-content threshold was non-positive).
var ErrRunsMisconfigured = errors.New("stream: runs handler missing a mandatory dependency")
ErrRunsMisconfigured — NewRunsHandler was called with a nil runs/protocol.Service.
var ErrSessionsMisconfigured = errors.New("stream: sessions handler missing a mandatory dependency")
ErrSessionsMisconfigured — NewSessionsHandler was called with a nil sessions/protocol.Service.
var ErrTasksMisconfigured = errors.New("stream: tasks handler missing a mandatory dependency")
ErrTasksMisconfigured — NewTasksHandler was called with a nil tasksprotocol.Service.
var ErrToolsMisconfigured = errors.New("stream: tools handler missing a mandatory dependency")
ErrToolsMisconfigured — NewToolsHandler was called with a nil toolsprotocol.Service.
Functions ¶
This section is empty.
Types ¶
type AgentConfigHandler ¶ added in v1.5.0
type AgentConfigHandler struct {
// contains filtered or unexported fields
}
AgentConfigHandler serves the `POST /v1/agent_config/*` admin routes.
func NewAgentConfigHandler ¶ added in v1.5.0
func NewAgentConfigHandler(service *agentcfgprotocol.Service, opts ...AgentConfigOption) (*AgentConfigHandler, error)
NewAgentConfigHandler builds the agent-config admin handler over a *agentcfgprotocol.Service. service is mandatory — a nil fails loud with ErrAgentConfigMisconfigured (CLAUDE.md §5).
The returned *AgentConfigHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*AgentConfigHandler) ServeHTTP ¶ added in v1.5.0
func (h *AgentConfigHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler.
type AgentConfigOption ¶ added in v1.5.0
type AgentConfigOption func(*AgentConfigHandler)
AgentConfigOption configures NewAgentConfigHandler.
func WithAgentConfigLogger ¶ added in v1.5.0
func WithAgentConfigLogger(l *slog.Logger) AgentConfigOption
WithAgentConfigLogger sets the slog.Logger. A nil logger routes to slog.Default().
type AgentsHandler ¶
type AgentsHandler struct {
// contains filtered or unexported fields
}
AgentsHandler serves `POST /v1/agents/{method}`. It is the wire adapter over an agentsprotocol.Service: resolve identity, decode the request, dispatch, encode. The handler is a concurrency-safe compiled artifact — every field is set once at construction; ServeHTTP holds no per-request state.
func NewAgentsHandler ¶
func NewAgentsHandler(service *agentsprotocol.Service, opts ...AgentsOption) (*AgentsHandler, error)
NewAgentsHandler builds the Agents handler over an agentsprotocol.Service. service is mandatory — a nil fails loud with ErrAgentsMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5). The returned *AgentsHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*AgentsHandler) ServeHTTP ¶
func (h *AgentsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity, decodes the method-specific wire request, dispatches into the agentsprotocol.Service, and encodes the response.
type AgentsOption ¶
type AgentsOption func(*AgentsHandler)
AgentsOption configures NewAgentsHandler at construction.
func WithAgentsLogger ¶
func WithAgentsLogger(l *slog.Logger) AgentsOption
WithAgentsLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().
type AggregateHandler ¶
type AggregateHandler struct {
// contains filtered or unexported fields
}
AggregateHandler serves `POST /v1/events/aggregate`. It is the wire adapter over an *events.Aggregator: decode the request body, gate on scope claim if the filter is cross-tenant, dispatch, encode the response. The handler is a concurrency-safe compiled artifact — bus and logger are set once at construction; ServeHTTP holds no per-request state.
func NewAggregateHandler ¶
func NewAggregateHandler(aggregator *events.Aggregator, opts ...AggregateOption) (*AggregateHandler, error)
NewAggregateHandler builds the events-aggregate handler over an *events.Aggregator. aggregator is mandatory — a nil fails loud with ErrAggregateMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5).
The returned *AggregateHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*AggregateHandler) ServeHTTP ¶
func (h *AggregateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity from r.Context() (auth.Middleware) or the X-Harbor-* carrier headers ( fallback), decodes the JSON body into an EventAggregateRequest, gates on cross-tenant scope, dispatches to the Aggregator, and encodes the response.
type AggregateOption ¶
type AggregateOption func(*AggregateHandler)
AggregateOption configures NewAggregateHandler at construction.
func WithAggregateLogger ¶
func WithAggregateLogger(l *slog.Logger) AggregateOption
WithAggregateLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().
type AuthHandler ¶
type AuthHandler struct {
// contains filtered or unexported fields
}
AuthHandler serves `POST /v1/auth/{method}`. It is the wire adapter over an *auth.RotateSurface: resolve identity + scopes, decode the request, dispatch, encode. The handler is a concurrency-safe compiled artifact — every field is set once at construction; ServeHTTP holds no per-request state.
func NewAuthHandler ¶
func NewAuthHandler(surface *auth.RotateSurface, opts ...AuthOption) (*AuthHandler, error)
NewAuthHandler builds the auth handler over an *auth.RotateSurface. surface is mandatory — a nil fails loud with ErrAuthMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5). The returned *AuthHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*AuthHandler) ServeHTTP ¶
func (h *AuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity + scopes, decodes the method-specific wire request, dispatches into the auth.RotateSurface, and encodes the response.
type AuthOption ¶
type AuthOption func(*AuthHandler)
AuthOption configures NewAuthHandler at construction.
func WithAuthLogger ¶
func WithAuthLogger(l *slog.Logger) AuthOption
WithAuthLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().
type FlowsHandler ¶
type FlowsHandler struct {
// contains filtered or unexported fields
}
FlowsHandler serves the six `POST /v1/flows/*` routes. It is the wire adapter over a *flowprotocol.Surface: decode the request, dispatch to the surface, emit the per-page audit event, encode the response.
func NewFlowsHandler ¶
func NewFlowsHandler(surface *flowprotocol.Surface, opts ...FlowsOption) (*FlowsHandler, error)
NewFlowsHandler builds the Flows-page handler over a *flowprotocol.Surface. surface is mandatory — a nil fails loud with ErrFlowsMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5).
The returned *FlowsHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*FlowsHandler) ServeHTTP ¶
func (h *FlowsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity, branches on the trailing path segment, decodes the body, dispatches to the surface, emits the audit event, and encodes the response.
type FlowsOption ¶
type FlowsOption func(*FlowsHandler)
FlowsOption configures NewFlowsHandler at construction.
func WithFlowsBus ¶
func WithFlowsBus(b events.EventBus) FlowsOption
WithFlowsBus wires the canonical events.EventBus into the handler so every dispatch emits its per-page audit event. The bus is OPTIONAL — when not supplied the handler still serves every route, but the audit events are not emitted (the handler logs the dispatch at Info instead so Flows-page traffic is never fully silent).
func WithFlowsLogger ¶
func WithFlowsLogger(l *slog.Logger) FlowsOption
WithFlowsLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().
type FlowsPageViewedPayload ¶
type FlowsPageViewedPayload struct {
events.SafeSealed
// Method is the canonical Protocol method name that ran.
Method string
// FlowID is the targeted flow id, when the method targets one.
FlowID string
// AdminScoped reports whether the read used the admin scope claim.
AdminScoped bool
}
FlowsPageViewedPayload is the typed payload for EventTypeFlowsPageViewed. It records which read method ran and the flow it targeted (empty for `flows.list`). It is a SafePayload — it carries no raw run output / no tool arguments (CLAUDE.md §7 rule 7).
type FlowsRunInvokedPayload ¶
type FlowsRunInvokedPayload struct {
events.SafeSealed
// FlowID is the invoked flow.
FlowID string
// RunID is the identifier of the accepted run.
RunID string
}
FlowsRunInvokedPayload is the typed payload for EventTypeFlowsRunInvoked. It records the invoked flow + the accepted run id. SafePayload — no input form, no output.
type GovernanceHandler ¶ added in v1.5.0
type GovernanceHandler struct {
// contains filtered or unexported fields
}
GovernanceHandler serves the `POST /v1/governance/*` admin routes. It is the wire adapter over a *governanceprotocol.Service: resolve identity, enforce the admin scope, branch on the trailing path segment, decode, dispatch, encode.
func NewGovernanceHandler ¶ added in v1.5.0
func NewGovernanceHandler(service *governanceprotocol.Service, opts ...GovernanceOption) (*GovernanceHandler, error)
NewGovernanceHandler builds the governance admin handler over a *governanceprotocol.Service. service is mandatory — a nil fails loud with ErrGovernanceMisconfigured (CLAUDE.md §5).
The returned *GovernanceHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*GovernanceHandler) ServeHTTP ¶ added in v1.5.0
func (h *GovernanceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler.
type GovernanceOption ¶ added in v1.5.0
type GovernanceOption func(*GovernanceHandler)
GovernanceOption configures NewGovernanceHandler.
func WithGovernanceKeyRotate ¶ added in v1.5.0
func WithGovernanceKeyRotate(s *governanceprotocol.KeyRotateService) GovernanceOption
WithGovernanceKeyRotate wires the rotate-key service so the `POST /v1/governance/rotate_key` route is live. A nil service (the default) leaves the route returning CodeUnknownMethod (501) — the partial-build convention.
func WithGovernanceLogger ¶ added in v1.5.0
func WithGovernanceLogger(l *slog.Logger) GovernanceOption
WithGovernanceLogger sets the slog.Logger. A nil logger (the default) routes to slog.Default().
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is the Protocol SSE event transport. It is built once per Runtime process via NewHandler and shared across every stream request; ServeHTTP is safe for concurrent use by N goroutines.
func NewHandler ¶
NewHandler builds the Protocol SSE event transport over the events.EventBus. The bus is mandatory — a nil fails loud with ErrMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5).
The returned *Handler is immutable after construction and safe for concurrent use by N goroutines.
func (*Handler) ServeHTTP ¶
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves the identity triple at the edge, opens a triple-scoped events.Subscription, optionally replays from a Last-Event-ID reconnect cursor, and live-tails events as SSE frames until the client disconnects or the bus closes.
type MemoryHandler ¶
type MemoryHandler struct {
// contains filtered or unexported fields
}
MemoryHandler serves the three `memory.*` read routes. It is the wire adapter over the memory subsystem: decode the request, gate on the scope claim if the filter is cross-tenant, project the answer via internal/memory/protocol, encode the response. The handler is a safe for concurrent reuse compiled artifact — every field is set once at construction; ServeHTTP holds no per-request state.
func NewMemoryHandler ¶
func NewMemoryHandler(store memory.MemoryStore, artStore artifacts.ArtifactStore, threshold int, opts ...MemoryOption) (*MemoryHandler, error)
NewMemoryHandler builds the memory handler over a memory.MemoryStore + an artifacts.ArtifactStore. store and artStore are mandatory — a nil fails loud with ErrMemoryHandlerMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5). threshold is the configured heavy-content byte size (cfg.Artifacts.HeavyOutputThresholdBytes); a non-positive value fails loud (a zero threshold would route every value).
The returned *MemoryHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*MemoryHandler) DeleteHandler ¶ added in v1.3.0
func (h *MemoryHandler) DeleteHandler() http.Handler
DeleteHandler returns the http.Handler for `POST /v1/memory/delete`.
func (*MemoryHandler) GetHandler ¶
func (h *MemoryHandler) GetHandler() http.Handler
GetHandler returns the http.Handler for `POST /v1/memory/get`.
func (*MemoryHandler) HealthHandler ¶
func (h *MemoryHandler) HealthHandler() http.Handler
HealthHandler returns the http.Handler for `POST /v1/memory/health`.
func (*MemoryHandler) ListHandler ¶
func (h *MemoryHandler) ListHandler() http.Handler
ListHandler returns the http.Handler for `POST /v1/memory/list`.
func (*MemoryHandler) PutHandler ¶ added in v1.3.0
func (h *MemoryHandler) PutHandler() http.Handler
PutHandler returns the http.Handler for `POST /v1/memory/put`.
func (*MemoryHandler) StrategyTraceHandler ¶ added in v1.3.0
func (h *MemoryHandler) StrategyTraceHandler() http.Handler
StrategyTraceHandler returns the http.Handler for `POST /v1/memory/strategy_trace`.
type MemoryOption ¶
type MemoryOption func(*MemoryHandler)
MemoryOption configures NewMemoryHandler at construction.
func WithMemoryAggregator ¶
func WithMemoryAggregator(a *events.Aggregator) MemoryOption
WithMemoryAggregator wires the events Aggregator into the handler so the `memory.list` / `memory.health` 24-hour counters (identity-rejected / recovery-dropped) can be computed. OPTIONAL — when not supplied, those two counters report 0; the page still renders and the right-rail cards subscribe to the live event stream for the real-time view. A nil aggregator is treated as "WithMemoryAggregator not supplied".
func WithMemoryBus ¶ added in v1.3.0
func WithMemoryBus(b events.EventBus) MemoryOption
WithMemoryBus wires the events bus the admin mutation methods (`memory.put` / `memory.delete`) publish their audit events on (`memory.item_put` / `memory.item_deleted`). OPTIONAL — when not supplied, the mutations still apply but emit no audit event; the production wiring (`harbor dev`) always supplies it so the mutation is audited (page-memory.md §9). A nil bus is treated as "not supplied".
func WithMemoryDriverName ¶
func WithMemoryDriverName(name string) MemoryOption
WithMemoryDriverName sets the configured memory-driver name surfaced on each `memory.list` row's Driver field and in the `memory.health` per-scope driver mapping. Empty (the default) reports `inmem`.
func WithMemoryLogger ¶
func WithMemoryLogger(l *slog.Logger) MemoryOption
WithMemoryLogger sets the slog.Logger the handler logs decode / projection failures to. A nil logger (the default) routes to slog.Default().
type Option ¶
type Option func(*Handler)
Option configures a Handler at construction time.
func WithKeepalive ¶
WithKeepalive overrides the interval between SSE keepalive comment frames. A value below minKeepalive is clamped up to the floor; a non-positive value is ignored (the default is kept). Tests drive the keepalive path deterministically by supplying a short interval — the keepalive frame is observable on the wire, so a short interval makes the path testable without a time.Sleep-as-synchronisation antipattern.
func WithLogger ¶
WithLogger sets the slog.Logger the handler logs subscription / streaming failures to. A nil logger (the default) routes to slog.Default().
type PauseListHandler ¶
type PauseListHandler struct {
// contains filtered or unexported fields
}
PauseListHandler serves `POST /v1/pause/list`. It is the wire adapter over a pauseresume.Coordinator: decode the request, gate on scope claim if the filter is cross-tenant, project the snapshot, apply the heavy-content bypass per row, encode the response. The handler is a concurrency-safe compiled artifact — every field is set once at construction; ServeHTTP holds no per-request state.
func NewPauseListHandler ¶
func NewPauseListHandler(coord pauseresume.Coordinator, store artifacts.ArtifactStore, threshold int, opts ...PauseListOption) (*PauseListHandler, error)
NewPauseListHandler builds the pause-list handler over a pauseresume.Coordinator + an artifacts.ArtifactStore. coord and store are mandatory — a nil fails loud with ErrPauseListMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5). threshold is the configured heavy-content byte size (cfg.Artifacts.HeavyOutputThresholdBytes); a non-positive value fails loud (a zero threshold would route every payload).
The returned *PauseListHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*PauseListHandler) ServeHTTP ¶
func (h *PauseListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity from r.Context() (auth.Middleware) or the X-Harbor-* carrier headers (fallback), decodes the JSON body into a PauseListRequest, gates cross-tenant filters on scope, projects the Coordinator snapshot, applies the heavy-content bypass, and encodes the response.
type PauseListOption ¶
type PauseListOption func(*PauseListHandler)
PauseListOption configures NewPauseListHandler at construction.
func WithPauseListBus ¶
func WithPauseListBus(b events.EventBus) PauseListOption
WithPauseListBus wires the canonical events.EventBus into the handler so the heavy-content bypass can publish a `pause.payload_artifact_routed` observation when a heavy payload is routed through the ArtifactStore. The bus is OPTIONAL — when not supplied, the bypass still happens (the heavy payload is still routed to the ArtifactStore and shipped by-reference) but the observation event is not emitted; the handler logs the bypass at Info instead so the routing is never fully silent. A nil bus is treated as "WithPauseListBus not supplied".
func WithPauseListLogger ¶
func WithPauseListLogger(l *slog.Logger) PauseListOption
WithPauseListLogger sets the slog.Logger the handler logs decode / projection failures to. A nil logger (the default) routes to slog.Default().
type RunsHandler ¶
type RunsHandler struct {
// contains filtered or unexported fields
}
RunsHandler serves the `POST /v1/runs/*` routes. It is the wire adapter over a *runsprotocol.Service: resolve identity, branch on the trailing path segment, decode the request, dispatch, encode.
func NewRunsHandler ¶
func NewRunsHandler(service *runsprotocol.Service, opts ...RunsOption) (*RunsHandler, error)
NewRunsHandler builds the Runs-page handler over a *runsprotocol.Service. service is mandatory — a nil fails loud with ErrRunsMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5).
The returned *RunsHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*RunsHandler) ServeHTTP ¶
func (h *RunsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity, branches on the trailing path segment, decodes the body, dispatches to the service, and encodes the response.
type RunsOption ¶
type RunsOption func(*RunsHandler)
RunsOption configures NewRunsHandler at construction.
func WithRunsLogger ¶
func WithRunsLogger(l *slog.Logger) RunsOption
WithRunsLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().
type SessionsHandler ¶
type SessionsHandler struct {
// contains filtered or unexported fields
}
SessionsHandler serves the two `POST /v1/sessions/*` routes. It is the wire adapter over a *sessionsprotocol.Service: resolve identity, branch on the trailing path segment, decode the request, dispatch, encode.
func NewSessionsHandler ¶
func NewSessionsHandler(service *sessionsprotocol.Service, opts ...SessionsOption) (*SessionsHandler, error)
NewSessionsHandler builds the Sessions-page handler over a *sessionsprotocol.Service. service is mandatory — a nil fails loud with ErrSessionsMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5).
The returned *SessionsHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*SessionsHandler) ServeHTTP ¶
func (h *SessionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity, branches on the trailing path segment, decodes the body, dispatches to the service, and encodes the response.
type SessionsOption ¶
type SessionsOption func(*SessionsHandler)
SessionsOption configures NewSessionsHandler at construction.
func WithSessionsLogger ¶
func WithSessionsLogger(l *slog.Logger) SessionsOption
WithSessionsLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().
type TasksHandler ¶
type TasksHandler struct {
// contains filtered or unexported fields
}
TasksHandler serves `POST /v1/tasks/{method}`. It is the wire adapter over a tasksprotocol.Service: resolve identity, decode the request, compute the admin-scope claim, dispatch, encode. The handler is a safe for concurrent reuse compiled artifact — every field is set once at construction; ServeHTTP holds no per-request state.
func NewTasksHandler ¶
func NewTasksHandler(service *tasksprotocol.Service, opts ...TasksOption) (*TasksHandler, error)
NewTasksHandler builds the Tasks handler over a tasksprotocol.Service. service is mandatory — a nil fails loud with ErrTasksMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5). The returned *TasksHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*TasksHandler) ServeHTTP ¶
func (h *TasksHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity, decodes the method-specific wire request, dispatches into the tasksprotocol.Service, and encodes the response.
type TasksOption ¶
type TasksOption func(*TasksHandler)
TasksOption configures NewTasksHandler at construction.
func WithTasksLogger ¶
func WithTasksLogger(l *slog.Logger) TasksOption
WithTasksLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().
type ToolsHandler ¶
type ToolsHandler struct {
// contains filtered or unexported fields
}
ToolsHandler serves `POST /v1/tools/{method}`. It is the wire adapter over a toolsprotocol.Service: resolve identity, decode the request, gate admin methods on scope, dispatch, encode. The handler is a safe for concurrent reuse compiled artifact — every field is set once at construction; ServeHTTP holds no per-request state.
func NewToolsHandler ¶
func NewToolsHandler(service *toolsprotocol.Service, opts ...ToolsOption) (*ToolsHandler, error)
NewToolsHandler builds the Tools handler over a toolsprotocol.Service. service is mandatory — a nil fails loud with ErrToolsMisconfigured rather than building a handler that would nil-panic on the first request (CLAUDE.md §5). The returned *ToolsHandler is immutable after construction and safe for concurrent use by N goroutines.
func (*ToolsHandler) ServeHTTP ¶
func (h *ToolsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler. It resolves identity, decodes the method-specific wire request, gates admin methods on scope, dispatches into the toolsprotocol.Service, and encodes the response.
type ToolsOption ¶
type ToolsOption func(*ToolsHandler)
ToolsOption configures NewToolsHandler at construction.
func WithToolsLogger ¶
func WithToolsLogger(l *slog.Logger) ToolsOption
WithToolsLogger sets the slog.Logger the handler logs decode / dispatch failures to. A nil logger (the default) routes to slog.Default().