Repository navigation
wire-in: StrategyPlanner → skill_router for plan-time skill resolution (ADR-006) #7268
Description
Discovered during
ADR-006 drafting (2026-05-08) — articulating AutoBot's task-decomposition flow and finding that the live planner (StrategyPlanner) and the live skill resolver (skill_router) are not connected.
Finding
enhanced_orchestration.workflow_planning.StrategyPlanner is AutoBot's actively-used workflow planner (instantiated at orchestrator.py:251, consumed by workflow_runner.py:38). It produces WorkflowPlan objects whose steps target agents by AgentCapability via a static CAPABILITY_MAPPING.
Meanwhile, skills/builtin/skill_router.py is a 3-phase meta-skill that resolves a task description to a concrete BaseSkill:
- Phase 1 — keyword scoring against registered skills
- Phase 2 — LLM re-ranking of top-K candidates
- Phase 3 — gap-fill via
skill-researcher+autonomous-skill-development+ governance
StrategyPlanner does not import or call skill_router. WorkflowExecutor does not either. As a result:
- The
SkillRegistryis invisible to the planner - Capability gaps surface only at execution time (after planning has committed)
- The Phase 3 learning loop (
skill-researcher→autonomous-skill-development) is dormant for the planning path
Decision context
ADR-006: Skill-Bound Planning articulates the target state: the planner consults skill_router per step at plan time, binding each step to a concrete (skill_name, action) before the plan is finalized. Phase 3 is the learning loop that fills capability gaps.
This issue is the wire-in to realize ADR-006 against the active planner.
Sibling issue
#6820 tracks the orphan orchestration/workflow_planner.py (282 LOC, zero production callers — the dead twin of StrategyPlanner). #6820's resolution (wire-in or retire) is independent of this issue. Do not confuse the two; the active planner this issue targets is StrategyPlanner.
Acceptance criteria
-
StrategyPlanner.build_workflow_plan(or a successor method) iterates each produced step and resolves it viaskill_router.execute("route", {"task": <step intent>}) - Resolved
(skill_name, action)is attached to the step (new field on the activeWorkflowStep/AgentTaskshape; coordinate with refactor: unify 5 duplicate WorkflowStep/Task/Plan definitions + add first-class prompt/tools fields #6951 follow-ups before adding the field) - When
skill_routerPhase 3 fires (no skill match), the planner handles the response per ADR-006 — preferred default is async (returnWorkflowPlaninBLOCKED_ON_SKILL_GENERATIONstate withpending_skill_id) -
WorkflowExecutorconsumes the bound plan: per step,SkillRegistry.get(skill_name).execute(action, params)is invoked instead of (or in addition to) capability-based agent dispatch - Integration test: a known-skill task plans and executes end-to-end through the new path
- Integration test: an unknown-capability task triggers Phase 3, demonstrates the learning loop synthesizing and registering a skill, then completes execution
- ADR-006 status flipped from "Proposed" to "Accepted" at merge
Open questions (from ADR-006, must resolve before/during implementation)
- Sync vs async gap-fill default — async preferred, but executor needs a resume path
skill_routercache policy — per-session, per-tenant, or global? Invalidation on new skill registration?- Behavior when previously-resolved skill is removed/disabled between plan and execution — re-route at execution time, or fail the step?
Dependencies
- #6951 follow-ups must settle before adding a
skill_namefield to the canonical step type — otherwise the field is added to the wrong class. Specifically, #7121 (lifecycle methods on canonical) is the most relevant precondition. - #6820 (orphan
workflow_planner.py) is independent but should not be conflated with this work.
Priority
P2 — no current functional regression, but blocks the planning path from benefiting from the existing skill-routing + learning-loop infrastructure. Realizes ADR-006.
Related
- ADR-006: docs/adr/006-skill-bound-planning.md
- Wire-in 2 (separate, smaller): adding optional
skill_hintfield toWorkflowTemplatestep shape so authored templates can pre-bind skills (skipsskill_routerlookup for known mappings). May be filed separately if this issue scope grows.
Activity
mrveiss commentedon May 8, 2026
Design-blocker resolution (ADR-006 → Accepted)
The three open questions identified at filing time are now resolved in ADR-006. Status flipped from Proposed → Accepted.
Q1: Sync vs async gap-fill default → ASYNC
pending_skill_idto affected step, returnsWorkflowPlaninBLOCKED_ON_SKILL_GENERATIONstateskill_promoted; on matchingpending_skill_id, plan transitionsRUNNABLEand resumesPLAN_SYNC_GAP_FILL=truefor batch / offline use casesQ2:
skill_routercache policy → PER-TENANT, 1h TTL, registry-change invalidation(tenant_id, sha256(intent))SkillRegistry.reload()(existing feat(skills): autonomous skill development — self-gap detection and skill generation #951 method) clears tenant cache on registry changeQ3: Behavior when bound skill is unavailable at execute time → LATE RE-BIND, no Phase 3 at execute time
skill_router(Phase 1+2 only — keyword + LLM re-rank)Dependencies update:
WorkflowTaskis ready to receiveskill_name,skill_action,pending_skill_idfields.workflow_planner.py) — independent, not blocking wire-in: StrategyPlanner → skill_router for plan-time skill resolution (ADR-006) #7268. This issue targetsStrategyPlanner(the active planner) per ADR-006 implementation notes.Implementation can now proceed. The
skill_name/skill_action/pending_skill_idfield additions go on canonicalautobot_shared/workflow/types.py:WorkflowTask(per #7121 close). All aliases inherit automatically.feat(orchestration/planner): wire StrategyPlanner → skill_router for …
feat(orchestration/planner): wire StrategyPlanner → skill_router for …
feat(orchestration/planner): wire StrategyPlanner → skill_router for …
mrveiss commentedon May 10, 2026
Phase 1 landed —
ba934a72f(PR #7432)This issue stays OPEN. Phase 1 satisfies 2 of the 7 acceptance criteria; Phases 2 and 3 (filed as #7430 and #7431) cover the remaining 5.
Phase 1 scope (now done)
StrategyPlanner.build_workflow_planiterates each step and resolves it viaskill_router.execute("find_skill", {"task": …, "dry_run": True})(skill_name, action, method)attached to canonicalWorkflowTask(3 new fields, defaultsNone)Conservative defaults chosen (deferring the 3 open ADR-006 questions)
dry_run=True) — gap-fill is Phase 3's (#7431) async-resume problemRemaining acceptance criteria
BLOCKED_ON_SKILL_GENERATIONplan state + worker resume) → tracked at feat(orchestration/planner): async gap-fill resume path for blocked plans (#7268 Phase 3) #7431SkillRegistry.get(skill_name)instead of capability-based agent routing) → tracked at feat(orchestration/executor): wire skill_name dispatch into WorkflowExecutor (#7268 Phase 2) #7430When this issue closes
Once #7430 and #7431 land, this issue closes with a roll-up proof comment (commit hashes for all 3 PRs + ADR-006 status update). Don't close before then — Phase 1 alone leaves the bound
skill_namefield unread by the executor, which is partial wire-in.7 regression tests on Phase 1 pin the contract for Phase 2/3 to extend safely:
WorkflowTaskfield surfacebuild_workflow_planasync signaturedry_run=Truealways passed (no auto-enable at plan time — load-bearing for Phase 3 design)feat(orchestration/executor): wire skill_name dispatch into WorkflowE…
feat(orchestration/executor): wire skill_name dispatch into WorkflowE…
mrveiss commentedon May 10, 2026
Phase 2 landed —
e7efc6a61(PR #7468)5 of 7 acceptance criteria on this issue now met. Issue stays OPEN until #7431 (Phase 3 async gap-fill resume) ships.
Phase 2 scope (now done — see #7430 closure)
WorkflowExecutor(WorkflowRunner._execute_single_agent_task) checkstask.skill_namefirst; if set, dispatches viaSkillRegistry.get(skill_name).execute(action, params)instead of the capability-based agent pathWire-in now complete plan-time → execute-time
Acceptance progress (cumulative)
(skill_name, action, method)attached to canonical WorkflowTask (Phase 1)SkillRegistryenv setup (deferred)Testing — 12 regression tests now pin the contract across both phases
workflow_planning_test.py(Phase 1 surfaces)workflow_runner_test.py(Phase 2 dispatch paths)workflow_runner_test.py11/11 pass with no regressions on the 6 existing testsWhat's left
#7431 needs owner input on:
skill_router(per-session vs per-tenant vs global)Once #7431 ships, this issue closes with a roll-up proof comment for all 3 PRs (#7432 + #7468 + the eventual #7431 PR) + ADR-006 status update.
feat(workflow): add pending_skill_id field for async gap-fill marker (#…
feat(skills): pending_skills registry + trigger_gap_fill helper (#7431)
feat(workflow): #7431 Phase 3 — async gap-fill resume path for blocke…
mrveiss commentedon May 16, 2026
✅ Closed: merged in PR #7760 (commit 972f7b1).
Acceptance Criteria Met:
mrveiss commentedon May 16, 2026
Integration tests for Phases 2+3 are now merged to Dev_new_gui.
Commit: 0ef0ae0 — test(enhanced_orchestration): Phase 2+3 integration tests for GH#7268 — merged via PR #7770 at 2026-05-16T13:33:44Z
Tests cover:
execute_workflowwith skill-bound plan)try_resume_blocked_plan→ execution (5 tests)Note: GH#7268 was already closed by ADR-006 PR #7760. This comment records completion of the integration test deliverable tracked in MVA-419.