Folder catalogs recursively parse every non-hidden .json, .toml, and .kdl
file as a potential Agent Spec. That includes files under an agent's
resources/ tree. A normal structured resource that happens to carry
spec-shaped keys can therefore become a phantom agent.
This is deterministic on current main.
Minimal reproduction
https://github.com/schickling-repros/2026-07-st2-dynamic-agent-spec-lifecycle
git clone https://github.com/schickling-repros/2026-07-st2-dynamic-agent-spec-lifecycle
cd 2026-07-st2-dynamic-agent-spec-lifecycle
./repro.sh
The first half creates one canonical declaration:
catalog/agents/example-host/worker/agent.kdl
and one resource:
catalog/agents/example-host/worker/resources/context/checkpoint.json
whose synthetic contents are:
{"identity":"phantom","host":"example-host","command":"true"}
st2 agents --json reports both example-host.worker and
example-host.phantom.
Why this matters
The catalog is also the native bus/state tree. Structured context, controller
receipts, or other resources can acquire fields such as identity, type, or
command without intending to declare an agent. Discovery then changes the
fleet merely because unrelated resource data crossed RawSpec::looks_like_spec.
The supervisor watcher already has a narrower declaration boundary: it wakes
for canonical agent.kdl paths and _templates, not arbitrary JSON/TOML/KDL
resources. Discovery and watcher classification therefore disagree about what
constitutes desired-state input.
This is particularly hazardous for policy-mediated dynamic seats: putting a
typed request or receipt near the seat can mutate the roster before the
publisher has admitted or compiled anything.
Expected
A folder catalog should have an explicit declaration boundary. Runtime/resource
files should never become agents merely because their data resembles a spec.
Possible directions
A. Canonical agent.kdl discovery by default (preferred)
For folder catalogs, discover only files whose basename is agent.kdl. Keep
single-file Agent Spec and eval entrypoints separate.
This fixes the resource hazard without requiring the exact
agents/<host>/<identity>/ layout immediately.
B. Introduce validate --canonical, then make it the default
Provide one migration release that reports legacy spec candidates which
canonical discovery would ignore. This is safer if noncanonical folder layouts
are actively used.
C. Maintain recursive discovery with an ignore mechanism
This is the least attractive option: every new runtime/resource namespace must
be taught to discovery, and unknown future state remains unsafe by default.
Whichever path is chosen, the watcher, validator, and discovery predicates
should share one definition of a declaration path.
Version
- st2
0.1.0+a77776a
- source
a77776ac553af9b9b04149f2bc9f6c269a008b83
- Linux
Posted on behalf of @schickling
| field |
value |
agent_name |
co2-pine |
agent_session_id |
cdd15622-c01a-4731-bbfe-ab8cce0cad54 |
agent_tool |
Codex CLI |
agent_tool_version |
0.145.0 |
agent_runtime |
Codex CLI 0.145.0 |
agent_model |
unknown |
runtime_profile |
/nix/store/ph8rlhdj25mg71v81jsfzy6dq4xpcs9m-coding-agent-runtime-profile/share/coding-agents/profile.json |
skills_manifest |
/nix/store/lsykz8x5481xrpbgk280xh3pypk1c5jy-agent-skills-corpus/share/agent-skills/manifest.json |
worktree |
tmp |
machine |
dev3 |
tooling_profile |
dotfiles@3649b53 |
Folder catalogs recursively parse every non-hidden
.json,.toml, and.kdlfile as a potential Agent Spec. That includes files under an agent's
resources/tree. A normal structured resource that happens to carryspec-shaped keys can therefore become a phantom agent.
This is deterministic on current main.
Minimal reproduction
https://github.com/schickling-repros/2026-07-st2-dynamic-agent-spec-lifecycle
git clone https://github.com/schickling-repros/2026-07-st2-dynamic-agent-spec-lifecycle cd 2026-07-st2-dynamic-agent-spec-lifecycle ./repro.shThe first half creates one canonical declaration:
and one resource:
whose synthetic contents are:
{"identity":"phantom","host":"example-host","command":"true"}st2 agents --jsonreports bothexample-host.workerandexample-host.phantom.Why this matters
The catalog is also the native bus/state tree. Structured context, controller
receipts, or other resources can acquire fields such as
identity,type, orcommandwithout intending to declare an agent. Discovery then changes thefleet merely because unrelated resource data crossed
RawSpec::looks_like_spec.The supervisor watcher already has a narrower declaration boundary: it wakes
for canonical
agent.kdlpaths and_templates, not arbitrary JSON/TOML/KDLresources. Discovery and watcher classification therefore disagree about what
constitutes desired-state input.
This is particularly hazardous for policy-mediated dynamic seats: putting a
typed request or receipt near the seat can mutate the roster before the
publisher has admitted or compiled anything.
Expected
A folder catalog should have an explicit declaration boundary. Runtime/resource
files should never become agents merely because their data resembles a spec.
Possible directions
A. Canonical
agent.kdldiscovery by default (preferred)For folder catalogs, discover only files whose basename is
agent.kdl. Keepsingle-file Agent Spec and eval entrypoints separate.
This fixes the resource hazard without requiring the exact
agents/<host>/<identity>/layout immediately.B. Introduce
validate --canonical, then make it the defaultProvide one migration release that reports legacy spec candidates which
canonical discovery would ignore. This is safer if noncanonical folder layouts
are actively used.
C. Maintain recursive discovery with an ignore mechanism
This is the least attractive option: every new runtime/resource namespace must
be taught to discovery, and unknown future state remains unsafe by default.
Whichever path is chosen, the watcher, validator, and discovery predicates
should share one definition of a declaration path.
Version
0.1.0+a77776aa77776ac553af9b9b04149f2bc9f6c269a008b83Posted on behalf of @schickling
agent_nameagent_session_idagent_toolagent_tool_versionagent_runtimeagent_modelruntime_profileskills_manifestworktreemachinetooling_profile