diff --git a/work-items/open/20260529-205540-spawnpod-profile-tool-description/artifacts/.gitkeep b/work-items/open/20260529-205540-spawnpod-profile-tool-description/artifacts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/work-items/open/20260529-205540-spawnpod-profile-tool-description/item.md b/work-items/open/20260529-205540-spawnpod-profile-tool-description/item.md new file mode 100644 index 00000000..4fee5af8 --- /dev/null +++ b/work-items/open/20260529-205540-spawnpod-profile-tool-description/item.md @@ -0,0 +1,79 @@ +--- +id: 20260529-205540-spawnpod-profile-tool-description +slug: spawnpod-profile-tool-description +title: SpawnPod profile selection and templated tool description +status: open +kind: feature +priority: P2 +labels: [pod, manifest, tools, workflow] +created_at: 2026-05-29T20:55:40Z +updated_at: 2026-05-29T20:55:40Z +assignee: null +legacy_ticket: null +--- + +## Background + +`SpawnPod` is becoming the main mechanism for hierarchical orchestration. The workflow model now distinguishes role-specific child Pods: lower orchestrators, coder Pods, and external reviewer Pods. These roles should be selectable by profile, but the current `SpawnPod` tool has no profile field and no LLM-visible route to discover profile selectors. + +A separate `ListProfiles` tool would expose mostly static or semi-static affordance information as another model action. The desired design is instead to make profile choices part of the `SpawnPod` tool's own guidance: render the available profile selectors into the tool description, and repeat the same selector list in invalid/ambiguous/no-default diagnostics. + +Current implementation notes: + +- Tool metadata is defined by `llm_worker::tool::ToolMeta`; `ToolDefinition` factories return `(ToolMeta, Arc)` and `ToolServerHandle::flush_pending()` materializes them before request construction. +- Tool descriptions are currently hard-coded strings/doc comments in each tool factory. `crates/pod/src/spawn/tool.rs` has a static `DESCRIPTION` and `SpawnPodInput` only contains `name`, `instruction`, `task`, and `scope`. +- `SpawnPod` currently builds an internal `PodManifestConfig` directly from the parent model, optional instruction override, and delegated scope, then launches the child with hidden `--spawn-config-json`. It does not use profile resolution. +- Prompt assets are centralized under `resources/prompts`; Pod-owned prompt injection strings are represented by `PodPrompt` and rendered by `PromptCatalog` through minijinja. `resources/prompts/internal.toml` has build-time coverage against `PodPrompt` variants. +- Profile discovery/resolution already exists in `manifest`: `ProfileDiscovery::for_cwd`, `ProfileRegistry`, `ProfileSelector`, `NixProfileResolver`, and source-qualified selectors such as `project:coder`, `project:reviewer`, and `builtin:default`. + +## Requirements + +- Add an optional `profile` field to `SpawnPodInput`. +- Make `SpawnPod`'s LLM-facing tool description include the currently discoverable profile selectors and the effective default profile. +- Do not add a separate `ListProfiles` tool for this feature. +- The profile list in the tool description must come from the same builtin/user/project profile discovery rules used by the profile launcher path. +- If profile discovery fails, the tool should still be registered with a clear diagnostic in its description rather than making Pod startup fail solely because the description could not list profiles. +- If `profile` is omitted, `SpawnPod` resolves the effective default profile. With the builtin default profile present, ordinary omission should keep working. +- If `profile` is invalid, ambiguous, unsupported, or omitted while no default can be resolved, the tool error must include a compact available-profile list and source-qualified suggestions. +- `SpawnPod.profile` should initially accept registry/default selectors only: `default`, `builtin:`, `user:`, `project:`, and unqualified names only when unambiguous. Raw path selectors, `path:`, relative paths, absolute paths, and `.nix` path-like values are rejected for the tool path. +- `SpawnPod.scope` remains the only delegated capability. A profile selected through `SpawnPod` must not be able to expand `scope.allow` beyond the explicit tool argument. +- `SpawnPod.name` always overrides `pod.name` in the resolved child manifest. +- `SpawnPod.instruction`, if present, is a typed override for the resolved profile's `worker.instruction` only; it must not replace the whole profile. +- Profile-selected spawn should preserve profile-owned role configuration such as model, worker settings, tools/memory/web policy, and prompt pack where applicable, subject to the explicit `name` and `scope` overrides. +- Existing hidden `--spawn-config-json` remains the internal launch handoff. `SpawnPod` resolves/merges profile data in the parent process and passes the resulting manifest config/snapshot to the child; it should not simply exec `insomnia-pod --profile`. +- Documentation/workflows should show `SpawnPod(profile = "project:coder")`, `SpawnPod(profile = "project:reviewer")`, and optionally `project:orchestrator` as role selectors, while keeping scope authority separate from profile role selection. + +## Tool description templating direction + +Use the existing prompt infrastructure rather than scattering another large hard-coded string. + +Acceptable implementation shape: + +- Add a Pod-owned prompt/catalog entry for the `SpawnPod` tool description, e.g. `spawn_pod_tool_description`, with minijinja variables such as `available_profiles`, `default_profile`, and `profile_diagnostic`. +- Render this prompt when registering `SpawnPod` in `register_pod_tools`, using the Pod cwd as the profile discovery base. +- Keep the rendered description as `ToolMeta.description`; the tool metadata still remains session-scoped after registration. +- The same formatter used for the description should be reusable by error diagnostics so invalid profile errors repeat the available selectors. + +If a more general tool-description catalog is introduced, keep the initial scope narrow: it must support `SpawnPod` without forcing every built-in tool to migrate in the same ticket. + +## Acceptance criteria + +- `SpawnPod` schema exposes optional `profile` with clear field docs. +- `SpawnPod` tool description includes a compact available-profile block and default-profile guidance. +- `SpawnPod` invalid/ambiguous/no-default profile errors include the same compact selector list and tell the model to use a listed selector. +- `SpawnPod(profile = "project:reviewer")` resolves the project reviewer profile and applies its role config while replacing `pod.name` and `scope.allow` with the explicit `SpawnPod` values. +- `SpawnPod` with omitted profile resolves the effective default profile. +- `SpawnPod(profile = "./reviewer.nix")`, `SpawnPod(profile = "path:./reviewer.nix")`, and absolute profile paths are rejected with an explanation that the tool accepts registry/default selectors only. +- Ambiguous unqualified profile names fail closed with source-qualified suggestions. +- A profile's `scope.allow` cannot grant access not present in `SpawnPod.scope`. +- Existing `SpawnPod` behavior that matters for lifecycle remains intact: registry reservation/rollback, scope revocation from the spawner, callback wiring, child socket wait, and initial `Method::Run` confirmation. +- Unit/integration tests cover description rendering, selector formatting, omitted default resolution, invalid selector diagnostics, profile config application, explicit instruction override, and scope authority replacement. +- Documentation and `.insomnia/workflow/` references explain profile-based coder/reviewer/orchestrator spawning without introducing a `ListProfiles` tool. + +## Non-goals + +- Do not introduce an LLM-callable `ListProfiles` tool. +- Do not enable arbitrary profile path evaluation through `SpawnPod`. +- Do not revive manifest cascade or generic overlay layers. +- Do not redesign prompt-loader source selection for `$user` / `$workspace` profile prompt refs in this ticket unless it is required to keep current behavior correct. +- Do not implement encrypted secret storage; profiles may still contain unresolved typed secret refs as currently documented. diff --git a/work-items/open/20260529-205540-spawnpod-profile-tool-description/thread.md b/work-items/open/20260529-205540-spawnpod-profile-tool-description/thread.md new file mode 100644 index 00000000..45fc8cc4 --- /dev/null +++ b/work-items/open/20260529-205540-spawnpod-profile-tool-description/thread.md @@ -0,0 +1,7 @@ + + +## Created + +Created by tickets.sh create. + +---