Query
A Query is a request to run work on an Ark resource. The CRD ships an input plus exactly one of target (a single agent / team / model / tool) or selector (picks a single target by label — first match wins, not a fan-out). For a task-oriented walkthrough see User Guide → Run queries / chat with agents and teams; this page is the field-by-field reference.
Spec
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
metadata:
name: example-query
spec:
# --- Required ----------------------------------------------------------
input: "What's the weather in {{.city}}?" # user message (string)
# Exactly ONE of target or selector is required.
target:
type: agent # agent | team | model | tool
name: weather-agent
# OR pick a single target by label (first match wins; not a fan-out).
# selector:
# matchLabels:
# role: reviewer
# --- Common optional fields --------------------------------------------
type: user # only 'user' is accepted (default)
parameters: # template values for {{.name}} in input
- name: city
value: Boston
conversationId: chat-alice-001 # thread queries into one conversation
memory:
name: broker # Memory resource that stores history
sessionId: user-session-123 # telemetry / tracking key (separate from conversationId)
serviceAccount: my-sa # RBAC for execution
timeout: 5m # default '5m'
ttl: 720h # default from ArkConfig/default (720h fallback)
cancel: false # set to true to cancel mid-flight
overrides: # HTTP header overrides for downstream model/MCP calls
- resourceType: model
headers:
- name: X-Trace-ID
value:
value: trace-xyz789Fields
| Field | Type | Required | Description |
|---|---|---|---|
spec.input | string | yes | The user message. Supports Go template substitution via {{.name}} against spec.parameters. |
spec.target | object | conditional | Single execution target. Either target or selector must be set — the validation webhook rejects queries with neither. |
spec.target.type | enum (agent, team, model, tool) | yes (when target set) | Resource kind to dispatch to. |
spec.target.name | string | yes (when target set) | Name of the target resource in the same namespace. |
spec.selector | LabelSelector | conditional | Pick a single target by label (alternative to target). Resolves to the first matching resource, checked in order Agent → Team → Model → Tool. Not a fan-out — it does not run against multiple matches. Empty match set fails with no matching resources found for selector. |
spec.type | enum (user) | no | Only user is accepted (default). The previous messages type is deprecated; the mutating webhook migrates it to user and stamps a migration-warning-input-type annotation. |
spec.parameters[] | list | no | Template values substituted into input (and into any agent prompt that references queryParameterRef). Each entry has a name and either a value or valueFrom (configMapKeyRef, secretKeyRef). |
spec.memory.name | string | no | Name of a Memory resource that stores conversation history keyed by conversationId. If unset, the completions executor falls back to a Memory named default in the same namespace; if that doesn’t exist either, it uses a no-op (in-process) store. |
spec.sessionId | string | no | Identifier for grouping queries in tracking / telemetry. Auto-derived from the Query UID if unset. Not the same as conversationId — sessionId is observability, conversationId is memory continuity. |
spec.conversationId | string | no | Conversation threading identifier. Sent to execution engines as the A2A contextId. With memory active, ties subsequent queries to the same history. Auto-generated by the memory backend if unset (a new conversation is created and the ID written back to status.conversationId). |
spec.serviceAccount | string | no | Kubernetes ServiceAccount used for RBAC during execution. |
spec.timeout | duration | no | Execution timeout (30s, 5m, 1h). Defaults to 5m. Applies to all targets in the query. |
spec.ttl | duration | no | How long the Query resource lingers after completion. Mutating webhook resolves the default from ArkConfig/default.spec.queryTTL (falls back to 720h). |
spec.cancel | bool | no | When true, indicates intent to cancel a running query. The controller transitions the query to phase: canceled. |
spec.overrides[] | list | no | HTTP header overrides applied when the query’s target calls its model or any MCP server. See Overrides. |
Targets
A query dispatches to exactly one target — named directly via spec.target, or picked by label via spec.selector. Supported type values: agent, team, model, tool.
spec:
input: "Summarise the news."
target:
type: team
name: news-teamPick by label (resolves to a single target — first match across Agent → Team → Model → Tool):
spec:
input: "Should we ship this feature?"
selector:
matchLabels:
role: reviewerThe webhook enforces that one of target / selector is set, and that the named resource exists when target is used.
Parameters
Parameters are substituted into spec.input (and into agent prompts that declare queryParameterRef) before dispatch. Sources:
spec:
input: "Hit {{.endpoint}} with token {{.key}}, mode {{.mode}}."
parameters:
- name: mode
value: "production" # direct value
- name: endpoint
valueFrom:
configMapKeyRef: # from ConfigMap
name: api-config
key: url
- name: key
valueFrom:
secretKeyRef: # from Secret
name: api-credentials
key: api-keyTemplate syntax is Go templates: {{.parameter_name}}. Names must match the parameters[].name field.
Wiring parameters into the agent
Agents can pull the same query parameters into their own prompt or system message using queryParameterRef:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Agent
metadata:
name: dynamic-agent
spec:
prompt: |
You are running in {{.mode}} mode against {{.environment}}.
parameters:
- name: mode
valueFrom:
queryParameterRef:
name: operation_mode
- name: environment
valueFrom:
queryParameterRef:
name: target_envThe matching query supplies them:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
metadata:
name: parameterised-q1
spec:
input: "Run a health check."
parameters:
- name: operation_mode
value: "production"
- name: target_env
value: "us-west-2"
target:
type: agent
name: dynamic-agentSee Agents → Pass parameter values at query time for the dashboard walkthrough.
Conversations + memory
conversationId threads queries together; Memory stores the history. By default the completions executor uses the Memory named default in the query’s namespace when spec.memory is unset — most Ark installs ship one backed by the in-cluster broker. Two queries with the same conversationId share context as long as they hit the same memory store:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
metadata:
name: chat-q1
spec:
input: "Hi, my name is Alice."
conversationId: chat-alice-001
memory:
name: broker
target:
type: agent
name: assistant
---
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
metadata:
name: chat-q2
spec:
input: "What's my name?"
conversationId: chat-alice-001 # same conversation
memory:
name: broker
target:
type: agent
name: assistantsessionId is a separate identifier for telemetry — same telemetry session can contain many distinct conversations.
If you set conversationId without spec.memory, the executor still resolves the default Memory (so continuity works out of the box on a standard install). The conversationId also flows through to execution engines as the A2A contextId — named engines (Claude Agent SDK, LangChain, …) can use it for their own session model.
If you set memory without conversationId, the controller auto-generates a fresh conversationId on each query.
Timeout
spec.timeout caps execution. Default is 5m. Format follows Go’s time.ParseDuration (30s, 5m, 1h).
- Completes within timeout →
status.phase: done. - Exceeds timeout →
status.phase: errorwith a timeout error message instatus.response.content.
For A2A agents the timeout flows through as a Go context deadline. A2A servers can also enforce their own per-server timeouts via A2AServer.spec.timeout — see Building A2A Servers → Timeout configuration.
Cancel
To cancel a running query, patch spec.cancel: true:
kubectl patch query slow-q1 --type='merge' -p='{"spec":{"cancel": true}}'The controller transitions the query to phase: canceled once the in-flight dispatch acknowledges. The dashboard chat panel does the same when you click Stop on an embedded chat.
Deletion and cleanup
When a Query is deleted, a controller finalizer removes the messages and operation events that query wrote to the broker, so deleting a Query does not leave orphaned history behind.
Messages go through the Memory contract:
- Memory resolution mirrors execution: the controller uses
spec.memoryif set, otherwise aMemorynameddefaultin the query’s namespace. If neither exists, cleanup is skipped. - The controller resolves the backend address from the
Memoryresource (status.lastResolvedAddress, falling back tospec.address) and issuesDELETE /queries/{queryId}/messagesagainst it — see the Memory delete endpoint.
Operation events are not part of the Memory contract, so they use a separate path:
- The controller discovers the broker endpoint from the
ark-config-brokerConfigMap and issuesDELETE /events/{queryId}directly against it. If no broker is configured for the namespace, cleanup is skipped. - Events are keyed by the Query’s UID, not its name (unlike messages), so
{queryId}here is the UID.
Both cleanups run independently and either can fail without blocking the other. A backend that does not implement a delete endpoint returns 404/405, which the controller treats as “not supported” and skips. Scope: messages and events only — chunks and traces are not affected. Failure policy: if a backend is unreachable the finalizer retries every 15s; after a 5-minute grace period it gives up and removes itself, so a Query is never stuck in Deleting.
This is complementary to spec.ttl: TTL expires history on a timer, while deletion cleans it up immediately when the Query is removed.
Status
status:
phase: done
conditions:
- type: Completed
status: "True"
reason: QuerySucceeded
message: Query completed successfully
conversationId: ctx-86e022b0-1f4f-49f5-bc4b-e0d6437a789b
duration: 1.82s
response:
target:
type: agent
name: weather-agent
content: "It's 72°F and sunny in New York"
raw: '[{"content":"...","role":"assistant","name":"weather-agent"}]'
phase: done
a2a:
contextId: ctx-86e022b0-1f4f-49f5-bc4b-e0d6437a789b
taskId: task-xyz789
tokenUsage:
promptTokens: 97
completionTokens: 20
totalTokens: 117Status fields
| Field | Description |
|---|---|
status.phase | One of pending, provisioning, running, done, error, canceled. |
status.conditions[] | Standard Kubernetes conditions. The Completed condition flips to True on success or failure. |
status.response | Single response object (singular — there is no responses[] array). A selector resolves to one target, so there is always exactly one response. |
status.response.content | The final assistant message. |
status.response.raw | The full conversation as a JSON-encoded array of messages — what the dashboard’s Debug tab renders. |
status.response.phase | Per-response phase (mirrors top-level phase). |
status.response.target | The target the response is for. |
status.response.a2a.contextId | A2A context ID returned by the engine. When conversationId is set on the spec, the engine receives it as the contextId and echoes it back here. |
status.response.a2a.taskId | Set when the target is an A2A agent and a task was created. References an A2ATask resource — see A2ATask. |
status.conversationId | Effective conversation ID — either the one you supplied, or the auto-generated one when memory is set without a conversationId. |
status.duration | Total wall-clock execution time. |
status.tokenUsage | promptTokens, completionTokens, totalTokens from the underlying model call. |
Phases
| Phase | Meaning |
|---|---|
pending | Resource accepted by admission, controller hasn’t picked it up yet. |
provisioning | Controller is preparing the dispatch (parameter resolution, target lookup). |
running | Dispatched to the executor; waiting for the response. |
done | Execution finished successfully. |
error | Execution failed; details in status.response.content. |
canceled | spec.cancel: true was honoured. |
Print columns
kubectl get queries prints Type, Phase, Duration, Age. Pipe through -o jsonpath for the content/raw fields.
Webhook validation
Enforced by ark/internal/validation/query.go:
- Exactly one of
spec.targetandspec.selectoris required. - When
spec.targetis set, the named resource must exist in the namespace andtarget.typemust be one ofagent,team,model,tool. - Parameter resolution must succeed (referenced ConfigMaps and Secrets must exist).
spec.overrides[]must reference real resources for anyvalueFromsource.
Mutating webhook
Enforced by ark/internal/validation/defaults.go:
spec.type: messagesis deprecated. The mutating webhook extracts the last user-message text, setsspec.type: user, replacesspec.inputwith that text, and stamps anark.mckinsey.com/migration-warning-input-typeannotation. UseconversationIdfor multi-turn instead.spec.ttlis defaulted fromArkConfig/default.spec.queryTTL(or720hif absent).