Proposal: split agent configuration into Harness and AgentTemplate CRDs
Summary
This proposal separates authored agent behavior from the runtime that executes
it:
Harness defines a reusable runtime implementation and infrastructure policy.
AgentTemplate defines one logical agent and its ordinary MCP or
AgentTemplate-backed tools.
The root AgentTemplate is always the public entrypoint. AgentTemplate-backed
tools recursively form the owned composition. A template with no such tools is
the ordinary single-agent case; composition does not require another resource
kind or creation API.
Harness + rooted AgentTemplate tree
│
preparation
│
one prepared runtime plan
│
CreateAgentInstance (gRPC)
│
one AgentInstance + one public A2A conversation
The public invariant is:
one AgentInstance = one rooted AgentTemplate tree = one public conversation
The controller may use one or more internal runtime boundaries to satisfy the
template's isolation requirements. Processes, pods, Actors, and Substrate
topology do not appear in the authored AgentTemplate API.
Why change the current API?
The current API combines reusable behavior, runtime configuration, compute
lifecycle, and conversation state. The split lets teams reuse behavior across
runtime offerings, validate complete AgentTemplate trees before use, and keep live
conversation state outside Kubernetes reconciliation.
The proposed split gives each concern one owner:
| Concern |
Owner |
| Runtime implementation and infrastructure policy |
Harness CRD |
| Model, prompt, plugins, tools, and skills |
AgentTemplate CRD |
| Preparation and runtime compilation |
Kagent controller |
| Live identity and lifecycle |
Kagent gRPC AgentInstance API |
| Conversation and Tasks |
A2A v1 gRPC |
Harness
A Harness defines a reusable runtime implementation and its infrastructure
policy.
Rules:
- Exactly one typed runtime variant is present.
- The controller derives runtime capabilities; authors do not claim them.
- Image overrides must be digest-pinned.
- Each environment entry contains either a literal or a credential reference.
- Preparation retains credential references but never reads secret values.
- Omitted admission accepts no AgentTemplates.
- Every runtime variant consumes the same internal resolved-bundle contract.
- A Harness creates no compute merely by existing.
AgentTemplate
An AgentTemplate defines portable agent behavior and its available tools. A
tool may come from an MCP server or another AgentTemplate.
Conceptual shape:
type AgentTemplateSpec struct {
ModelConfig LocalObjectReference `json:"modelConfig"`
SystemPrompt PromptValue `json:"systemPrompt,omitempty"`
PromptTemplate PromptTemplateSpec `json:"promptTemplate,omitempty"`
Tools []ToolBinding `json:"tools,omitempty"`
Skills []Skill `json:"skills,omitempty"`
Plugins []PluginBundle `json:"plugins,omitempty"`
Harnesses HarnessAttachments `json:"harnesses,omitempty"`
}
type PluginBundle struct {
Source ArtifactSource `json:"source"`
Skills []string `json:"skills"`
}
type ToolBinding struct {
MCP *MCPToolBinding `json:"mcp,omitempty"`
Agent *AgentToolBinding `json:"agent,omitempty"`
}
type AgentToolBinding struct {
Name string `json:"name"`
Description string `json:"description"`
TemplateRef LocalObjectReference `json:"templateRef"`
Isolation AgentToolIsolation `json:"isolation,omitempty"`
}
Rules:
modelConfig is the only required behavioral field initially.
- References are same-namespace.
- Each tool binding contains exactly one of
mcp or agent.
- MCP bindings select tools explicitly.
- AgentTemplate labels are copied to new AgentInstances for discovery only.
- Labels do not authorize access or attach resources.
- The root AgentTemplate is always the public entrypoint.
- Each agent binding creates a distinct logical tool, even when two
bindings reference the same AgentTemplate.
description is required and tells the parent when to use that binding.
Shared compiles the referenced template into the Harness's native sub-agent
configuration in the parent's runtime boundary.
Dedicated creates a separate runtime boundary and presents it to the parent
as a binding-scoped MCP invoke tool. Omitted isolation is Shared.
- Portable V2 supports one native sub-agent level per runtime boundary: a
template reached through Shared may contain Dedicated, but not Shared,
agent bindings. A Dedicated edge begins a new boundary and resets the limit.
- Agent references form a same-namespace rooted tree; cycles are rejected.
- Referenced templates inherit the selected root Harness and must request and be admitted
by it.
- Existing Go-template and ConfigMap prompt composition is reused; preparation
renders and pins its inputs.
- Plugin packages conform to the vendor-neutral Agent Plugins 1.0.0 format:
root plugin.json, Agent Skills under skills/, and optional mcp.json.
- V1 is a conformant skills-only Agent Plugins client. It exposes explicitly
selected Agent Skills and ignores mcp.json and client extensions; MCP and
agent composition remain in the existing typed tool bindings.
- Plugin sources are immutable OCI digests, full Git commits, or version-pinned
S3 objects. S3 sources contain bucket, key, and versionId; ETag is not a
substitute for an S3 version ID.
- Template inheritance and a
BaseContext CRD are deferred.
Example plugin selection:
plugins:
- source:
bucket:
s3:
bucket: agent-content
key: plugins/repository-practices.zip
versionId: 3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY
skills:
- code-review
This is package ingestion, not a kagent extension SDK. There is no
AgentPlugin CRD, marketplace controller, or OpenClaw-style in-process plugin
mechanism in this proposal. Agent Plugins 1.0.0 is currently a Working Draft,
so support targets its exact canonical schema identifier rather than an
unspecified compatible version.
Harness input contract
Harnesses do not consume the authored AgentTemplate graph directly. Preparation
compiles one internal resolved bundle per runtime boundary. A bundle contains
its root configuration, direct native sub-agent definitions, and binding-scoped
MCP configuration for dedicated agent tools. For CLI Harnesses, preparation
generates ordinary Claude --agents JSON or Codex custom-agent TOML rather than
requiring SDK integration. Dedicated endpoints expose only the bound child and
retain its private conversation continuity; Actor addresses and credentials are
not exposed to the model. This bundle is compiler output, not another CRD.
An agent tool has a deliberately small portable contract: the parent supplies a
natural-language task and receives one terminal result or error. Native Shared
invocation remains model-driven. Dedicated MCP exposes the same contract as
invoke(task); streaming child Tasks and child INPUT_REQUIRED are deferred.
Harness capabilities and conformance
Harness compatibility is visible but not user-authored. Kagent maintains
versioned capability metadata for each supported adapter and pinned runtime,
verifies it with executable conformance tests, and publishes the resulting
capabilities in Harness status. Preparation and user interfaces consume that
same record rather than inferring behavior from the Harness name.
The initial vocabulary covers native Shared agent tools and maximum depth,
Dedicated MCP tools and MCP injection, streaming, interruption, input-required
and approval handling, modalities, resume behavior, and complete checkpoint
coverage. Capabilities describe supported behavior; conditions describe current
adapter and dependency health.
Preparation derives requirements from the actual runtime bundle and reports the
unsupported field and a stable reason. A Harness without native sub-agents may
still prepare an MCP-only template, while a Shared binding fails precisely.
The conformance suite exercises a real pinned runtime: basic turns, streaming,
MCP and agent tools, interruption, approvals, resume, and checkpoint restoration.
A capability is enabled for a release only after its behavior passes.
Attachment and preparation
A root pair is eligible for preparation only when:
- the root and every referenced AgentTemplate explicitly include the Harness;
- the Harness selector admits every template in the tree;
- every resource is in the same namespace;
- the references resolve to a rooted, acyclic tree; and
- every resolved runtime bundle is compatible with the Harness.
The explicit request plus admission selector lets both resource owners approve
the relationship without adding an attachment CRD. Wildcard attachment is not
proposed initially.
For each accepted root pair, the controller:
- resolves the complete AgentTemplate tree and rejects cycles;
- resolves every prompt, plugin, tool, skill, and non-secret dependency;
- derives compatibility requirements for each runtime boundary;
- compiles native sub-agents and dedicated MCP bindings into runtime bundles;
- creates an immutable Substrate
ActorTemplate for each bundle; and
- records one prepared revision.
The revision pins:
- the Harness UID and generation;
- every AgentTemplate UID and generation;
- rendered prompts and resolved non-secret inputs;
- selected plugin contents and source digests or object versions;
- credential references, never credential values;
- agent-tool bindings and isolation requirements; and
- every ActorTemplate name, UID, generation, spec digest, and readiness state.
Minimum conditions are Accepted, ResolvedRefs, Compatible, and Prepared.
Failures identify the source, field path, and stable reason without exposing
credential values.
Changing any pinned input prepares a new revision. Existing AgentInstances stay
pinned. New creation uses the latest successfully prepared revision; whether a
previous successful revision remains usable during preparation is an open
question.
Example
apiVersion: kagent.dev/v1alpha2
kind: Harness
metadata:
namespace: agent-team
name: python-runtime
spec:
python: {}
workload:
image: registry.example.com/agent-runtime@sha256:0000000000000000000000000000000000000000000000000000000000000000
allowedAgentTemplates:
selector:
matchLabels:
example.com/runtime: python
---
apiVersion: kagent.dev/v1alpha2
kind: AgentTemplate
metadata:
namespace: agent-team
name: incident-coordinator
labels:
example.com/runtime: python
example.com/context: operations
example.com/purpose: incident
spec:
modelConfig:
name: default-model
systemPrompt: Coordinate the incident investigation.
tools:
- agent:
name: researcher
description: Research the available evidence before conclusions are drawn.
templateRef:
name: incident-researcher
isolation: Shared
- agent:
name: reviewer
description: Review a proposed conclusion for unsupported claims.
templateRef:
name: incident-reviewer
isolation: Dedicated
plugins:
- source:
bucket:
s3:
bucket: agent-content
key: plugins/repository-practices.zip
versionId: 3HL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY
skills:
- code-review
harnesses:
include:
- name: python-runtime
The agent-tool references point to ordinary reusable AgentTemplates:
apiVersion: kagent.dev/v1alpha2
kind: AgentTemplate
metadata:
namespace: agent-team
name: incident-researcher
labels:
example.com/runtime: python
spec:
modelConfig:
name: default-model
systemPrompt: Investigate the available evidence.
harnesses:
include:
- name: python-runtime
---
apiVersion: kagent.dev/v1alpha2
kind: AgentTemplate
metadata:
namespace: agent-team
name: incident-reviewer
labels:
example.com/runtime: python
spec:
modelConfig:
name: default-model
systemPrompt: Review the investigation for unsupported conclusions.
harnesses:
include:
- name: python-runtime
Live instances are not CRDs
CreateAgentInstance(namespace, harness, agent_template, request_id) selects the
latest prepared tree and creates all required runtime members. The returned
AgentInstance is one namespaced gRPC resource persisted by kagent and exposes one
public A2A conversation through its root template.
This keeps high-churn conversation and lifecycle state out of Kubernetes while
leaving shared authored configuration under normal Kubernetes RBAC and GitOps.
Creation is idempotent through request_id. Editing or deleting source CRDs does
not mutate or cascade-delete existing instances.
Lifecycle operations apply to the complete tree. Kagent fences every runtime
member before suspend or checkpoint and publishes no checkpoint until the
public history head and complete internal snapshot set are committed. These
coordination details remain in the lifecycle API rather than the CRDs.
Deliberate initial limits
This proposal does not add:
- multiple conversations per AgentInstance;
- cyclic or shared-DAG AgentTemplate graphs;
- different Harnesses within one AgentTemplate tree;
- more than one consecutive native
Shared level per runtime boundary;
- native multi-profile host management;
- template inheritance or
BaseContext;
- shared-store or shared-filesystem CRDs;
- channel routing;
- resume-or-create;
- native in-process or gateway plugin extensions;
- bucket providers other than S3; or
- a public Thread or Session resource.
Shared mutable data remains behind explicitly selected external MCP tools. A
Dedicated agent tool also uses MCP, but its child Actor and private conversation
are owned and checkpointed with the AgentInstance. A later hosted
agent design may add AgentHost and HostedAgent if native multi-profile sharing
becomes a demonstrated requirement.
Questions for review
- Is the Harness/AgentTemplate responsibility split understandable?
- Is bilateral attachment worth the extra declaration on both resources?
- Where should per-pair preparation status live so it remains useful through
kubectl without duplicating unbounded status?
- Should creation continue using the last successful prepared revision while a
newer revision is still preparing?
- Is one native
Shared level per runtime boundary the right portable
intersection for CLI Harnesses, with deeper composition using Dedicated?
- Is a rooted tree sufficient initially, or is shared-DAG composition required?
- Is a skills-only Agent Plugins 1.0.0 client the right initial portable
subset, with standard mcp.json support deferred?
Context
Proposal: split agent configuration into Harness and AgentTemplate CRDs
Summary
This proposal separates authored agent behavior from the runtime that executes
it:
Harnessdefines a reusable runtime implementation and infrastructure policy.AgentTemplatedefines one logical agent and its ordinary MCP orAgentTemplate-backed tools.
The root AgentTemplate is always the public entrypoint. AgentTemplate-backed
tools recursively form the owned composition. A template with no such tools is
the ordinary single-agent case; composition does not require another resource
kind or creation API.
The public invariant is:
The controller may use one or more internal runtime boundaries to satisfy the
template's isolation requirements. Processes, pods, Actors, and Substrate
topology do not appear in the authored AgentTemplate API.
Why change the current API?
The current API combines reusable behavior, runtime configuration, compute
lifecycle, and conversation state. The split lets teams reuse behavior across
runtime offerings, validate complete AgentTemplate trees before use, and keep live
conversation state outside Kubernetes reconciliation.
The proposed split gives each concern one owner:
HarnessCRDAgentTemplateCRDAgentInstanceAPIHarnessA Harness defines a reusable runtime implementation and its infrastructure
policy.
Rules:
AgentTemplateAn AgentTemplate defines portable agent behavior and its available tools. A
tool may come from an MCP server or another AgentTemplate.
Conceptual shape:
Rules:
modelConfigis the only required behavioral field initially.mcporagent.bindings reference the same AgentTemplate.
descriptionis required and tells the parent when to use that binding.Sharedcompiles the referenced template into the Harness's native sub-agentconfiguration in the parent's runtime boundary.
Dedicatedcreates a separate runtime boundary and presents it to the parentas a binding-scoped MCP
invoketool. Omitted isolation isShared.template reached through
Sharedmay containDedicated, but notShared,agent bindings. A
Dedicatededge begins a new boundary and resets the limit.by it.
renders and pins its inputs.
root
plugin.json, Agent Skills underskills/, and optionalmcp.json.selected Agent Skills and ignores
mcp.jsonand client extensions; MCP andagent composition remain in the existing typed tool bindings.
S3 objects. S3 sources contain
bucket,key, andversionId; ETag is not asubstitute for an S3 version ID.
BaseContextCRD are deferred.Example plugin selection:
This is package ingestion, not a kagent extension SDK. There is no
AgentPluginCRD, marketplace controller, or OpenClaw-style in-process pluginmechanism in this proposal. Agent Plugins 1.0.0 is currently a Working Draft,
so support targets its exact canonical schema identifier rather than an
unspecified compatible version.
Harness input contract
Harnesses do not consume the authored AgentTemplate graph directly. Preparation
compiles one internal resolved bundle per runtime boundary. A bundle contains
its root configuration, direct native sub-agent definitions, and binding-scoped
MCP configuration for dedicated agent tools. For CLI Harnesses, preparation
generates ordinary Claude
--agentsJSON or Codex custom-agent TOML rather thanrequiring SDK integration. Dedicated endpoints expose only the bound child and
retain its private conversation continuity; Actor addresses and credentials are
not exposed to the model. This bundle is compiler output, not another CRD.
An agent tool has a deliberately small portable contract: the parent supplies a
natural-language task and receives one terminal result or error. Native Shared
invocation remains model-driven. Dedicated MCP exposes the same contract as
invoke(task); streaming child Tasks and childINPUT_REQUIREDare deferred.Harness capabilities and conformance
Harness compatibility is visible but not user-authored. Kagent maintains
versioned capability metadata for each supported adapter and pinned runtime,
verifies it with executable conformance tests, and publishes the resulting
capabilities in Harness status. Preparation and user interfaces consume that
same record rather than inferring behavior from the Harness name.
The initial vocabulary covers native Shared agent tools and maximum depth,
Dedicated MCP tools and MCP injection, streaming, interruption, input-required
and approval handling, modalities, resume behavior, and complete checkpoint
coverage. Capabilities describe supported behavior; conditions describe current
adapter and dependency health.
Preparation derives requirements from the actual runtime bundle and reports the
unsupported field and a stable reason. A Harness without native sub-agents may
still prepare an MCP-only template, while a
Sharedbinding fails precisely.The conformance suite exercises a real pinned runtime: basic turns, streaming,
MCP and agent tools, interruption, approvals, resume, and checkpoint restoration.
A capability is enabled for a release only after its behavior passes.
Attachment and preparation
A root pair is eligible for preparation only when:
The explicit request plus admission selector lets both resource owners approve
the relationship without adding an attachment CRD. Wildcard attachment is not
proposed initially.
For each accepted root pair, the controller:
ActorTemplatefor each bundle; andThe revision pins:
Minimum conditions are
Accepted,ResolvedRefs,Compatible, andPrepared.Failures identify the source, field path, and stable reason without exposing
credential values.
Changing any pinned input prepares a new revision. Existing AgentInstances stay
pinned. New creation uses the latest successfully prepared revision; whether a
previous successful revision remains usable during preparation is an open
question.
Example
The agent-tool references point to ordinary reusable AgentTemplates:
Live instances are not CRDs
CreateAgentInstance(namespace, harness, agent_template, request_id)selects thelatest prepared tree and creates all required runtime members. The returned
AgentInstance is one namespaced gRPC resource persisted by kagent and exposes one
public A2A conversation through its root template.
This keeps high-churn conversation and lifecycle state out of Kubernetes while
leaving shared authored configuration under normal Kubernetes RBAC and GitOps.
Creation is idempotent through
request_id. Editing or deleting source CRDs doesnot mutate or cascade-delete existing instances.
Lifecycle operations apply to the complete tree. Kagent fences every runtime
member before suspend or checkpoint and publishes no checkpoint until the
public history head and complete internal snapshot set are committed. These
coordination details remain in the lifecycle API rather than the CRDs.
Deliberate initial limits
This proposal does not add:
Sharedlevel per runtime boundary;BaseContext;Shared mutable data remains behind explicitly selected external MCP tools. A
Dedicated agent tool also uses MCP, but its child Actor and private conversation
are owned and checkpointed with the AgentInstance. A later hosted
agent design may add
AgentHostandHostedAgentif native multi-profile sharingbecomes a demonstrated requirement.
Questions for review
kubectlwithout duplicating unbounded status?newer revision is still preparing?
Sharedlevel per runtime boundary the right portableintersection for CLI Harnesses, with deeper composition using
Dedicated?subset, with standard
mcp.jsonsupport deferred?Context