Skip to content

fernandoxavier02/skill-advisor

Repository files navigation

FX Studio AI

An FX Studio AI plugin for Claude Code

Skill Advisor — one task, the right skills, never mixed

Powered by Obsidian Built for Claude Code Local first

Platform Version Skills Indexed Tests Node License

What's new in v0.5.0 (2026-04-27)

Architectural overhaul closing a 10-finding audit. Quality bar lifted from 7.5 → 9+/10 with zero functional regression.

  • Hot-path hook 387 → 85 lines. Scoring/fusion/discovery/replay logic extracted into the pure module lib/advisor-nudge-core.js. Hook is now a true I/O shim. Determinism is provable: same opts + fixed now() → deeply equal SuggestionResult.
  • 4 architectural guards CI-enforced on every push and PR: DI-1 (constants module load is fs-pure), DI-2 (no domain code imports from builders), DI-3 (package.json and .claude-plugin/plugin.json agree on SemVer), vault env single source (paths.js no longer reads env directly).
  • Module-scoped mtime + size keyed cache (lib/mtime-cache.js) memoizes embeddings/graph loaders for long-lived consumers; defeats stale-cache class on coarse filesystems (FAT32, sub-ms CI rebuilds).
  • Unified filesystem walker (lib/walk.js) replaces two private walkers in build-index/build-catalog. Side effect: index now visible at 546 entries (up from 163) — the legacy walker was silently dropping skills past its visit-count cap.
  • Vault env single source. SKILL_ADVISOR_VAULT_PATH is now canonical; legacy SKILL_ADVISOR_VAULT works with a one-time deprecation warning, removal in 0.6.0.
  • Performance gate (npm run test:perf) — ceiling p95 ≤ 250ms + headroom 1.15× baseline, 300 spawns × 2 fixtures, ~60s. Default npm test stays at ~2.3s for fast TDD iteration.
  • 812 tests (+24% from 654). Full perf gate green: short80 p95 ≈ 170ms, long500 p95 ≈ 157ms.

BREAKING (restorable). Default prompt-length threshold raised 5 → 12. Prompts of 5–11 characters that previously surfaced advisor nudges now silently early-exit. Restore the old behavior with ADVISOR_PROMPT_LENGTH=5 in your shell env.

Deprecations (both targeting 0.6.0 removal): SKILL_ADVISOR_VAULT env var (use SKILL_ADVISOR_VAULT_PATH); build-index.inferCategory re-export (use lib/category.inferCategory).

See CHANGELOG.md for full migration notes.

TL;DR · Features · Obsidian · How it works · Quickstart · Commands · Changelog

You have 200+ skills installed. You use 10. Skill Advisor finds the other 190 — and knows which ones not to mix.

86 skills indexed, 500 tests passing, 5 orchestrated plugins isolated, sub-50ms hook latency


TL;DR

Skill Advisor routes any Claude Code task to the right combination of skills, plugins, MCP servers, and agents. Instead of one monolithic pipeline, you get a proportional loadout sized to the task, with a per-step picker so you choose which skill runs at each position. It enforces a hard invariant: skills from orchestrated plugins (Superpowers, Kiro, SDD, Compound Engineering, Pipeline Orchestrator) never get mixed — if you pick one, the loadout collapses to that plugin's native flow.

You type:  /advisor "fix the login regression"

Advisor:   Task classified → simple. Standalone composition.
           Loadout: /investigate → /fix → /review

           Per-step picker:
           Step 1: /investigate (Recomendado) | /systematic-debugging | /kiro-debug
           Step 2: /fix (Recomendado)         | /simplify              | /ce-work
           Step 3: /review (Recomendado)      | /code-review          | /simplify
           → pick each with arrow keys, Enter, Voltar to abort

Three steps. No monolithic gate. No cross-plugin contamination.


Features

Feature What it does Since
Per-step loadout picker AskUserQuestion menu per position — recommendation + 2 alternatives + Voltar. Swap one skill without restarting the whole flow. 0.3.2
Pipeline-owner isolation Curated list (superpowers, kiro, sdd, compound-engineering, pipeline-orchestrator). A loadout can never mix skills from two owners. Picking one triggers collapse to its canonical flow. 0.3.2
Task-complexity-aware sizing Router classifies simple / medium / complex and sizes standalone loadouts to 1-2 / 3 / 4-5 skills. No more 4-step ceremony for a one-line fix. 0.3.2
Fingerprint-match routing Each pipelined plugin has a functional fingerprint (best_for, typical_tasks, not_for, complexity_match). The router recognizes when a task fits a plugin end-to-end and recommends the canonical flow unprompted. 0.3.2
Prompt-injection sanitizer lib/escaping.js implements the BEGIN/END marker contract, backtick redaction, control-char stripping, and field length caps from Rule 12. No more prose-only defense. 0.3.3
First-run setup wizard /advisor-setup slash command + SessionStart hook drive a 6-step wizard: build index, embeddings, owners curation, vault opt-in, threshold tuning, full smoke. State persisted in ~/.claude/advisor/setup.json, idempotent on re-run. 0.3.5
Extensible pipeline-owners User-curated ~/.claude/advisor/pipeline-owners-user.json extends the hardcoded base. Append-only — user owners colliding with base are filtered with a stderr warning. 0.3.5
Heuristic plugin detection lib/detect-owners.js scans installed plugins through 5 heuristics (H1 explicit metadata · H2 sequential naming · H3 spec+impl+validate triad · H4 named pipeline/orchestrator skill · H5 shared-prefix cluster). Threshold to flag: confidence ≥ 0.5. 0.3.5
Vault bounded context lib/vault-config.js validates an Obsidian vault path (exists, is dir, has .obsidian/ or .md). Resolution cascade: SKILL_ADVISOR_VAULT_PATH env beats setup.json vault_config.path. 0.4.0
Threshold tuning lib/threshold-config.js with presets strict=0.7 / balanced=0.5 / chatty=0.3. Hook reads cascade: ADVISOR_THRESHOLD env beats wizard-persisted value beats compiled default. 0.4.0
Full smoke runner lib/smoke-runner.js validates all artifacts + loads constants.js + traverses lite index with canned tasks. Returns typed SmokeTestResult { passed, checks[], reason }. 0.4.0
Hook nudge Sub-50ms scan of every user prompt surfaces underused high-signal skills via advisor-nudge.cjs. Zero network, local-only. 0.1+
Semantic search 384-dim embeddings over skill cards via @huggingface/transformers. Weighted with keyword + graph traversal. 0.2+

Powered by Obsidian

Obsidian

Skill Advisor uses your Obsidian vault as a first-class input. Every wikilink in your notes becomes an edge in vault-graph/adjacency.json; the router traverses this graph up to two hops from alias-matched seed nodes, giving you recommendation signal that pure semantic search cannot produce on its own.

Why Obsidian specifically. Obsidian's wikilink discipline means your notes already encode the relationships the advisor needs. A note titled xau-trading.md that links to [[ict-silver-bullet]], [[risk-sizing]], and [[atr-regime-filter]] tells the graph search: "if the user task touches XAU, those three topics are one hop away." The BFS surfaces skills registered against any of those topics, scored by hop distance and convergence.

What flows into the router.

  • Alias seeds — your task prompt is tokenized (PT-BR + EN synonym expansion) and matched against the vault's alias index
  • Adjacency traversal — BFS with SCORE_BY_HOP = [1.0, 0.7, 0.4] and a convergence boost of +0.15 per additional seed hitting the same node
  • Category boost — if the matched nodes share a category with the inferred task type, the top score gets +0.2

Fusion. Graph signal is one of three layers fused via weighted average: semantic 0.5, keyword 0.3, graph 0.2. The graph never decides alone — it pulls the recommendation toward the conceptual neighborhood your vault already maps.

Point it at your vault.

# Set the vault path once
export SKILL_ADVISOR_VAULT_PATH="/path/to/your/Obsidian/vault"

# Rebuild the graph after major vault reorganizations
node lib/build-graph.js

No vault? The advisor degrades gracefully — keyword + semantic layers continue to score; graph layer contributes zero until a vault is connected.

Obsidian® is a trademark of Dynalist Inc. Used here to indicate integration, not endorsement.


How it works

Architecture flow: Obsidian vault, installed skills, and MCP servers feed the advisor pipeline — build-index, router with fingerprint match, per-step gate — which emits a loadout that the execution layer runs

Three inputs flow in from the left: your Obsidian vault (wikilinks parsed into a 2-hop adjacency graph), every installed skill across global/plugin/project scopes, and every MCP server surfaced by .mcp.json. The pipeline in the middle runs three passes — build-index (keyword + semantic + graph), advisor-router (classify + fingerprint match + compose), advisor-gate (per-step picker with isolation enforcement) — and emits a typed loadout that the execution layer invokes step by step. The same stack runs in under 50ms as a hook on every prompt, no network involved.

Three Mermaid diagrams below zoom into the three decision points the SVG abstracts.

Router — from task to loadout

flowchart LR
    A[User task] --> B[Router]
    B --> C{Classify<br/>task_complexity}
    C -->|simple 1-2 skills| D[Standalone<br/>composition]
    C -->|medium 3 skills| D
    C -->|complex 4-5 skills| D
    B --> F{Fingerprint<br/>match?}
    F -->|yes| E[Canonical flow<br/>of owner]
    F -->|no| D
    D --> G[Loadout JSON]
    E --> G
    G --> H[Gate]
Loading

The router is a single Claude subagent call. It reads the task description, classifies complexity, checks each PIPELINE_FINGERPRINT for a match, and emits a loadout. If a fingerprint matches (e.g., "create a spec for the auth refactor" → kiro), the loadout is the plugin's canonical flow. Otherwise it composes standalone skills sized to complexity.

Gate — per-step picker

sequenceDiagram
    autonumber
    participant User
    participant Gate
    participant Loadout
    Loadout->>Gate: Loadout arrives (standalone OR canonical)
    alt canonical flow
        Gate->>User: Single summary (Sim/Nao/Alterar/Sugerir)
        User-->>Gate: decide
    else per-step loop
        loop for each position N
            Gate->>User: AskUserQuestion
            Note right of Gate: Recomendado + 2 alts + Voltar
            User-->>Gate: pick
            alt same-owner alternative
                Gate->>Gate: swapAtPosition(N)
            else cross-owner alternative
                Gate->>Gate: collapseToCanonicalFlow(newOwner)
                Gate->>User: new canonical flow (Sim/Nao)
                User-->>Gate: confirm
            else Voltar
                Gate->>Gate: discard picks, restore original
                Gate->>User: classic 4-option menu
            end
        end
    end
    Gate-->>User: final gate_output JSON
Loading

The gate uses the native AskUserQuestion tool — arrow-key selection, automatic "Other" free-text option. Three outcomes: all recommendations kept (decision: "approve"), at least one alternative picked (decision: "custom"), or collapse to a canonical flow (decision: "custom" with the new loadout).

Pipeline-owner isolation — why loadouts never mix

Pipeline-owner isolation matrix showing standalone skills freely mixable, and five orchestrated plugins (superpowers, kiro, sdd, compound-engineering, pipeline-orchestrator) each with its own canonical flow that never mixes with another owner

flowchart TD
    classDef ok fill:#e5ffe5,stroke:#2a2,stroke-width:2px,color:#000
    classDef forbidden fill:#ffe5e5,stroke:#d22,stroke-width:2px,color:#000
    classDef warn fill:#fff5d5,stroke:#d80,stroke-width:2px,color:#000

    A[Skill in index] --> B{pipeline_owner?}
    B -->|null<br/>standalone| C[Can compose freely]:::ok
    B -->|non-null<br/>e.g. kiro| D{Loadout has<br/>other owners?}
    D -->|no — same owner only| E[Canonical flow emitted]:::ok
    D -->|yes — mixed| F[REJECTED by validator]:::forbidden
    F --> G[Router re-spawned once<br/>with last_error]:::warn
    G --> H{Still mixed?}
    H -->|no| E
    H -->|yes| I["gate_output.error:<br/>'invalid_loadout'"]:::forbidden
Loading

A skill from superpowers and a skill from sdd in the same loadout would break both plugins' contracts — each assumes it owns the entire flow. The router self-validates; the gate re-validates; if both miss it, lib/schemas.js rejects with mixed_pipeline_owners. The retry budget (single re-spawn) is documented separately from the malformed-JSON retry.


Quickstart

Installation

Via the FX Studio AI marketplace:

# In Claude Code
/plugin install skill-advisor@FX-studio-AI

Or direct from source:

git clone https://github.com/fernandoxavier02/skill-advisor.git
cd skill-advisor
npm install
npm run index   # scan installed skills/plugins and build the index

First use

/advisor "your task in plain language"

The advisor will:

  1. Route — classify complexity, check fingerprints, compose a loadout
  2. Present — dry-run with flow, confidence, alternatives per position
  3. Gate — per-step picker if standalone, summary if canonical
  4. Execute — invoke the approved loadout in order

Example tasks that route differently:

Task Classification Loadout
"fix typo in auth.ts line 47" simple /investigate → /fix
"add retry logic with exponential backoff" medium /investigate → /writing-plans → /test-driven-development → /review
"create a spec for the auth refactor" fingerprint: kiro /kiro-discovery → /kiro-spec-quick → /kiro-impl → /kiro-validate-impl
"audit security posture of this codebase" fingerprint: pipeline-orchestrator /pipeline-orchestrator:pipeline

Commands

Command What it does
/advisor <task> Main entry — route, gate, execute
/advisor --template <name> Load a saved workflow template and skip routing
/advisor-setup First-run wizard — 6 steps: index, embeddings, owners, vault, threshold, smoke. Idempotent on re-run
/advisor-index Rebuild the keyword + semantic + graph indexes
/advisor-catalog List all indexed skills grouped by plugin
/advisor-config Toggle hook, adjust thresholds, enable debug
/advisor-feedback Record outcome of the last pipeline execution
/advisor-stats Session analytics and skill usage heat map

Architecture

Directory layout

skill-advisor/
├── agents/
│   ├── advisor-router.md    # LLM subagent: task → loadout
│   └── advisor-gate.md      # LLM subagent: per-step picker
├── commands/                # Slash command definitions
├── hooks/
│   └── advisor-nudge.cjs    # <50ms hook on every user prompt
├── lib/
│   ├── constants.js         # PIPELINE_OWNERS, CANONICAL_FLOWS, FINGERPRINTS
│   ├── build-index.js       # Full + lite index builder
│   ├── build-embeddings.js  # Semantic vectors (384-dim, MiniLM-L6-v2)
│   ├── build-graph.js       # Obsidian vault graph
│   ├── semantic.js          # Cosine similarity search
│   ├── graph-search.js      # BFS 2-hop traversal
│   ├── schemas.js           # Router output + gate output validators
│   ├── loadout.js           # swapAtPosition + collapseToCanonicalFlow
│   └── escaping.js          # Prompt-injection sanitizer (Rule 12)
└── tests/                   # 500 tests — `npm test`

Data flow

Two execution paths coexist:

Hook path (real-time, ~<50ms): every user prompt goes through advisor-nudge.cjs, which reads the lite index, tokenizes with PT-BR→EN synonym expansion, runs semantic + keyword matching, and emits a nudge to stdout if the top score beats the threshold.

Command path (/advisor): richer — reads the full index, gathers git/project context, spawns the router subagent, presents the dry-run, spawns the gate subagent, executes the approved loadout. See commands/advisor.md for the 10-step contract.

Prompt-injection defenses

External fields (task_description, codebase_context, loadout_json, skill entries) pass through lib/escaping.js before any subagent spawn. The contract redacts runs of 3+ backticks, strips control characters, caps field lengths (task_description 2000, codebase_context 4000, per-skill 300, loadout_json 8000), and wraps each block in BEGIN/END markers that the subagent is instructed to treat as DATA.


Development

npm install
npm test          # 500 tests via node --test
npm run index     # rebuild keyword + lite indexes
node lib/build-embeddings.js     # rebuild semantic embeddings (~2-5 min first run)
node lib/build-graph.js          # rebuild Obsidian vault graph

Test runner: Node.js built-in --test pattern tests/*.test.js. No external test framework.

Contributing

  1. Fork the repo
  2. Create a feature branch — naming convention feat/<description> or fix/<description>
  3. Add tests for any new behavior (see tests/advisor-loadout-composition.test.js for the pattern)
  4. Run npm test locally before opening PR
  5. Commit with Conventional Commits format
  6. PR against main

Release history

See CHANGELOG.md for the full timeline.

Latest: v0.5.0 (2026-04-27) — architectural overhaul closing a 10-finding audit. Hot-path hook 387 → 85 lines via lib/advisor-nudge-core extraction; 4 CI-enforced architectural guards (DI-1 module purity, DI-2 layered direction, DI-3 manifest version coherence, vault env single source); module-scoped mtime+size cache for embeddings/graph; unified filesystem walker; 812 tests (+24% from 654); BREAKING (restorable): default prompt-length threshold 5 → 12. Prior milestones: v0.4.2 UX disambiguation (skill renamed advisor-skill → pipeline-suggest); v0.4.1 wired /advisor-setup through to v0.4.0 libs (Vault, Threshold, SmokeRunner); v0.4.0 added the three Approach B bounded contexts; v0.3.5 shipped the first-run wizard + extensible pipeline-owners + heuristic plugin detection; v0.3.1–0.3.4 added the per-step picker, pipeline-owner isolation, complexity-aware sizing, fingerprint routing, and the lib/escaping.js sanitizer.


Built by FX Studio AI

FX Studio AI

FX Studio AI — building Claude Code plugins that scale from solo developers to engineering teams.

Maintained by FX Studio AI FX Studio AI marketplace

Other plugins in the FX Studio AI marketplace: pipeline-orchestrator, cc-toolkit, engineering-context, tts-minimax.


License

MIT © FX Studio AI. See LICENSE.

FX Studio AI Built for Claude Code by FX Studio AI. Powered by semantic search, graph traversal, and a stubborn belief that the right tool matters.

About

Intelligent toolchain orchestrator for Claude Code — semantic + graph + keyword search across 200+ skills, plugins, MCP servers, and agents. Flagship of the FX Studio AI cross-platform suite.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors