feat(skills): Agent Skills support with orchestrator-driven activation#954
Open
Spherrrical wants to merge 2 commits into
Open
feat(skills): Agent Skills support with orchestrator-driven activation#954Spherrrical wants to merge 2 commits into
Spherrrical wants to merge 2 commits into
Conversation
… helpers, warn on dropped picks Addresses the code-review findings on 7f5bf64: - Honor skills-only decisions: RouteDecision.route_name is now Option<String> and the orchestrator emits a decision when routes is empty but skills is non-empty. The LLM handler falls back to the originally-requested model and still injects activated skill bodies, matching the contract in docs/source/resources/skills.rst. - Warn on allow-list misses: resolve_for_route now returns a SkillResolution that splits drops into "not allow-listed for this route" vs "not in catalog (hallucinated)". brightstaff logs each bucket so misconfigured routing_preferences[].skills lists become visible instead of vanishing silently. - Consolidate runtime: common::skills_runtime is now the single source of truth (referenced_skills_catalog, resolve_for_route, resolve_selected_skills, augment_system_prompt_with_skills). brightstaff drops its local re-implementations and calls into common. - Tests: 11 new tests in common::skills_runtime (catalog union, allow-list intersection, dedup, hallucination handling, XML escaping, body size cap) and 6 new tests in brightstaff::handlers::llm::model_selection cover inject_activated_skills_into_request, including the first-system-message rule and the Parts->Text flatten — both now documented on the function. - Cap skill body size at 32 KiB with a UTF-8-safe tail-trim + marker so an oversized SKILL.md cannot blow the downstream context window. - XML-escape skill name and base_dir in the <skill_content> wrapper as defense-in-depth (names are validated upstream, but the wrapper sits inside the system prompt). - Bound find_project_root at \$HOME plus a 30-parent depth cap so CLI invocations outside HOME no longer walk to /.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Integrates Agent Skills into Plano as a first-class capability: skills are discovered from
.plano/skills,~/.plano/skills, and the universal~/.agents/skills(wherenpx skills addinstalls), attached torouting_preferences[].skillsallow-lists, selected per-request by Plano-Orchestrator alongside the existing<routes>block, and injected as<skill_content>wrappers into the upstream system prompt — all native, no WASM hop, no synthetic tool calls.Two commits, second one addresses code-review feedback on the first:
7f5bf641— featurecli/planoai/):planoai skills add | list | remove | trust, three discovery scopes (projectrequires explicit trust;userandagentsare auto-trusted), lenientSKILL.mdparsing with diagnostics, snapshot-diff post-install attribution sonpx-installed skills are picked up regardless of where they land.config/plano_config_schema.yaml): documentsmodel_metrics_sources(cost / latency providers) sinceselection_policy.prefer: cheapest|fastestnow requires it at startup.routing_preferences[].skillsis a typed allow-list.crates/common/src/skills_runtime.rs,crates/brightstaff/):SkillRefconfig model, orchestrator V1 system prompt extended with a<skills>XML block (parsed as{"route": [...], "skills": [...]}),OrchestratorService::with_routing_and_skillsseeds the catalog from the union of every route's allow-list, and the LLM handler prepends activated skill bodies into the upstream request before serialization.docs/source/resources/skills.rst): end-to-end walkthrough, scope precedence table, and routing flow.cli/planoai/templates/skills_routing.yaml): ready-madeplanoai init --template skills_routingbootstrap.5e8d27f— review fixesRouteDecision.route_nameis nowOption<String>; when the orchestrator returns{"route": [], "skills": [...]}the request falls back to the originally-requested model and skills still inject, matching the contract documented inskills.rst:153-155.common::skills_runtime::resolve_for_routereturns aSkillResolutionthat splits drops intodropped_not_allowedvsdropped_unknown; brightstaff logs each via dedicatedwarn!s with the offending route + skill names — no more silent filtering.common::skills_runtimeownsreferenced_skills_catalog,resolve_for_route,resolve_selected_skills, andaugment_system_prompt_with_skills. brightstaff's parallel re-implementations are gone.inject_activated_skills_into_requestnow spells out the first-system-message rule and theParts → Textflatten; 6 new tests cover both. 11 new tests inskills_runtimecover catalog union, allow-list intersection, dedup, hallucination handling, XML escape, and body cap.MAX_SKILL_BODY_BYTES = 32 KiBper-skill UTF-8-safe tail-trim guards the downstream context window; skillname/base_dirare XML-attribute-escaped in the<skill_content>wrapper as defense-in-depth;cli/planoai/skills.py::find_project_rootbounds the walk at\$HOME(plus a 30-parent hard cap) so it no longer climbs to/.Wire shape (orchestrator system prompt, abbreviated)
Activated
SkillRefbodies are then wrapped into the upstream system prompt:Test plan
cd crates && cargo fmt --all -- --check(passed locally — pre-commit hook)cd crates && cargo clippy --locked --all-targets --all-features -- -D warnings(passed locally)cd crates && cargo test --lib— 53common+ 173brightstaff(passed locally)cd cli && uv run pytest -v— 123 tests (passed locally)digitalocean/anthropic-claude-opus-4.7+requesting-code-reviewskill: orchestrator picks the skill, brightstaff logsinjecting activated Agent Skills into upstream system prompt, and the model returns a structured code review. Verified locally with a 30+ KB streaminggit diffpayload (stream: true+curl -N).no route determined; activating skills against default modeland the originally-requested model is used.skills:lists, prompt cross-route, confirmwarn!(skills not on this route's allow-list)appears.planoai skills add openai/skillsfollowed byplanoai upfrom outside the plano repo — config templates resolve, brightstaff loads the catalog, skills appear in the orchestrator<skills>block.