Problem
Agent metadata has no batch read path. #27897 asks for a plain per-agent GET, but a consumer inspecting many workspaces still makes N+1 requests per pass: one GET /api/v2/workspaces?q=... to find the workspaces, then one metadata read per agent.
The server already has everything in one table (workspace_agent_metadata, kept fresh by the agent's report loop regardless of watchers), and the workspaces list response already embeds the agents. Only the metadata values are missing.
Concrete use case
An external daemon sweeps workspaces created from a template (filtered with param:"...") and reads one metadata item per workspace (a status channel: working, serving, done <code>) to decide when each workspace can be reaped. Every workspace matching the param filter is of interest, so server-side filtering by metadata is not needed; the sweep just needs the values in the list it already fetches.
Proposal
An opt-in, key-scoped query parameter on the workspaces list:
GET /api/v2/workspaces?q=param:"pool=demo"&include_agent_metadata=status,vscode
When present, each agent in the response carries the requested items, e.g. on codersdk.WorkspaceAgent:
Metadata []WorkspaceAgentMetadata `json:"metadata,omitempty"`
Opt-in and key-scoped because metadata values can be large (64KiB value cap per item) and most list consumers do not want them; the default response is unchanged.
One indexed query against workspace_agent_metadata for all agent IDs in the page keeps it a single round trip server-side.
Related: #27897 (single-agent GET; complementary, this covers the batch shape).
Problem
Agent metadata has no batch read path. #27897 asks for a plain per-agent
GET, but a consumer inspecting many workspaces still makes N+1 requests per pass: oneGET /api/v2/workspaces?q=...to find the workspaces, then one metadata read per agent.The server already has everything in one table (
workspace_agent_metadata, kept fresh by the agent's report loop regardless of watchers), and the workspaces list response already embeds the agents. Only the metadata values are missing.Concrete use case
An external daemon sweeps workspaces created from a template (filtered with
param:"...") and reads one metadata item per workspace (a status channel:working,serving,done <code>) to decide when each workspace can be reaped. Every workspace matching the param filter is of interest, so server-side filtering by metadata is not needed; the sweep just needs the values in the list it already fetches.Proposal
An opt-in, key-scoped query parameter on the workspaces list:
When present, each agent in the response carries the requested items, e.g. on
codersdk.WorkspaceAgent:Opt-in and key-scoped because metadata values can be large (64KiB value cap per item) and most list consumers do not want them; the default response is unchanged.
One indexed query against
workspace_agent_metadatafor all agent IDs in the page keeps it a single round trip server-side.Related: #27897 (single-agent GET; complementary, this covers the batch shape).