Description
ipctl export agent-project / ipctl import agent-project round-trips an agent project's
agents[].tools[] list. Some tool entries carry a decoratorId — a foreign key into a
separate Tool Registry decorators collection that customizes a tool's exposed
description/input schema for the agent (e.g. narrowing a generic adapter method down to just
the fields/guidance an agent needs).
Source inspection confirms this is unhandled: pkg/services/agent_projects.go,
pkg/resources/agent_projects.go, and internal/runners/agent_projects.go contain zero
references to "decorator" anywhere. The export bundle passes through whatever bare
decoratorId was already present on the tool object from the source instance's API
response, but never fetches, exports, or recreates the actual decorator content, and never
remaps the ID for the destination. This silently degrades any promoted agent's decorated
tools with no error surfaced anywhere.
Reproduction Steps
ipctl export agent-project "<name>" --profile <source> on a project containing a tool
with a decoratorId (e.g. a ConfigurationManager:runCompliancePlan tool decorated to
narrow its input schema). The exported bundle contains only the bare decoratorId
string — no decorator content.
ipctl import agent-project "<file>" --profile <destination> — the project imports
successfully, but the tool's decoratorId now references a decorator that does not
exist on the destination instance.
- Confirmed the decorator API lives under a separate surface, not touched by the
agent-project commands:
GET /tools/decorators/{decoratorId} — get single decorator
GET /tools/{referenceId}/decorators — get all decorators for a tool
GET /tools/decorators/bulk/export — paginated ({skip, limit, total, data})
POST /tools/decorators/bulk/import — body {decorators: [...]}
- Note:
/flowai/decorators is an unrelated route namespace on this platform version —
not the correct one, despite the similar name.
- Manually reproduced a working import via
bulk/import: sending the decorator objects
WITH their original _id and audit fields (created, createdBy, etc.) intact
succeeds ({"inserted":2,"skipped":0}) and preserves the original _id. Stripping
_id before import causes the entries to be silently skipped instead
({"inserted":0,"skipped":2}), with no error explaining why.
Expected Behavior
ipctl export agent-project should walk every tools[].decoratorId in the bundle and
include the full decorator objects (via /tools/{referenceId}/decorators or by fetching
each decoratorId directly) in the exported bundle.
ipctl import agent-project should bulk-import those decorators (via
/tools/decorators/bulk/import, sending objects with _id and audit fields intact) as
part of the same import operation, so a promoted agent project's decorated tools work
identically on the destination without a separate manual step.
Environment
- OS: macOS (Darwin 25.5.0)
- Version: ipctl v0.12.0-132-gca82f65
- Go Version (if applicable): go1.26.5 darwin/arm64
Checklist
Description
ipctl export agent-project/ipctl import agent-projectround-trips an agent project'sagents[].tools[]list. Some tool entries carry adecoratorId— a foreign key into aseparate Tool Registry decorators collection that customizes a tool's exposed
description/input schema for the agent (e.g. narrowing a generic adapter method down to just
the fields/guidance an agent needs).
Source inspection confirms this is unhandled:
pkg/services/agent_projects.go,pkg/resources/agent_projects.go, andinternal/runners/agent_projects.gocontain zeroreferences to "decorator" anywhere. The export bundle passes through whatever bare
decoratorIdwas already present on the tool object from the source instance's APIresponse, but never fetches, exports, or recreates the actual decorator content, and never
remaps the ID for the destination. This silently degrades any promoted agent's decorated
tools with no error surfaced anywhere.
Reproduction Steps
ipctl export agent-project "<name>" --profile <source>on a project containing a toolwith a
decoratorId(e.g. aConfigurationManager:runCompliancePlantool decorated tonarrow its input schema). The exported bundle contains only the bare
decoratorIdstring — no decorator content.
ipctl import agent-project "<file>" --profile <destination>— the project importssuccessfully, but the tool's
decoratorIdnow references a decorator that does notexist on the destination instance.
agent-project commands:
GET /tools/decorators/{decoratorId}— get single decoratorGET /tools/{referenceId}/decorators— get all decorators for a toolGET /tools/decorators/bulk/export— paginated ({skip, limit, total, data})POST /tools/decorators/bulk/import— body{decorators: [...]}/flowai/decoratorsis an unrelated route namespace on this platform version —not the correct one, despite the similar name.
bulk/import: sending the decorator objectsWITH their original
_idand audit fields (created,createdBy, etc.) intactsucceeds (
{"inserted":2,"skipped":0}) and preserves the original_id. Stripping_idbefore import causes the entries to be silently skipped instead(
{"inserted":0,"skipped":2}), with no error explaining why.Expected Behavior
ipctl export agent-projectshould walk everytools[].decoratorIdin the bundle andinclude the full decorator objects (via
/tools/{referenceId}/decoratorsor by fetchingeach
decoratorIddirectly) in the exported bundle.ipctl import agent-projectshould bulk-import those decorators (via/tools/decorators/bulk/import, sending objects with_idand audit fields intact) aspart of the same import operation, so a promoted agent project's decorated tools work
identically on the destination without a separate manual step.
Environment
Checklist