CtrlK
BlogDocsLog inGet started
Tessl Logo

tessleng/skill-insights

Scan a directory or workspace for SKILL.md files across all agents and repos, capture supporting files (references, scripts, linked docs), dedupe vendored copies, enrich each Tessl tile with registry signals, and emit a canonical JSON inventory validated by JSON Schema. Then run four analytical phases in parallel against the inventory — staleness + git provenance (history, broken refs, contributors), quality (Tessl `skill review`), duplicates (similarity + LLM judgement), registry-search (per-standalone-skill registry suggestions, HTTP only) — and render a self-contained interactive HTML report with a top-of-report health overview, top-issues panel, recently-changed list, and per-tessl.json manifests view.

84

1.44x
Quality

90%

Does it follow best practices?

Impact

97%

1.44x

Average score across 2 eval scenarios

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

SKILL.mdskills/registry-search/

name:
registry-search
description:
For every skill in a discovery.json with source_type: "standalone", query the Tessl registry's hybrid search endpoint for the closest matching skill AND the closest matching tile, surface their eval / quality / impact / security scores, and emit the higher-aggregate-score hit as best_match. Output (registry-search.json) is one record per standalone skill, suitable for the report renderer to flag where a published Tessl tile or skill could replace the local one. Stdlib + HTTP only — no LLM, no auth. One of the parallel analytical phases that run after discovery. Use when asked to suggest registry replacements, find similar skills on the registry, or evaluate whether locally-authored standalone skills overlap with published Tessl tiles.

Registry Search

For every standalone skill in a discovery.json, query the Tessl registry's /experimental/search endpoint twice (once for the skill index, once for the tile index) and record the single higher-aggregate-score hit as best_match. Output conforms to registry-search.schema.json (currently schema_version: "1.2").

Fully programmatic — no LLM, no agent judgement. The script validates its input (discovery.json) against discovery.schema.json and its output against registry-search.schema.json at the IO boundary.

Which skills are searched

Only skills with source_type: "standalone" are searched. Anything inside a tile or an agent-harness directory (tessl_tile_skill, claude_skill, cursor_skill, agents_skill, claude_plugin_skill) is skipped — the user has already chosen its source by either authoring it as a tile or installing it via tessl.json, so a registry suggestion would be noise. Standalone skills are the ones that don't yet belong to anything, which is exactly when a registry alternative is useful.

The skipped count is recorded in metadata.skills_skipped_non_standalone.

Inputs

  • --discovery <path> (required) — discovery.json produced by discover-skills (schema 1.4).
  • --output <path> — defaults to <dirname(discovery)>/registry-search.json.
  • --registry-base-url <url> — defaults to https://api.tessl.io (or $TESSL_API_BASE_URL).
  • --concurrency <n> — parallel HTTP workers, default 8.

The script never sends an Authorization header. /experimental/search accepts anonymous calls and returns public registry data, which is everything the report needs to surface registry suggestions; skipping auth keeps the script free of credential state and stale-token failure modes.

Run

python3 <skill-dir>/scripts/registry_search.py \
  --discovery "$DISCOVERY_PATH" \
  --output "$OUTPUT_PATH"

Stdlib + Python ≥ 3.9. jsonschema is a soft dep used for IO contract validation. Runtime is dominated by HTTP latency: at concurrency 8, a typical estate of 30 non-published skills completes in ~5–10s.

What it queries

For each candidate, the query string is "<skill name> <skill description>" trimmed to 480 chars. Two parallel GET requests:

GET {base}/experimental/search?q=<query>&searchMode=hybrid&filter[type][eq]=skill&page[size]=1
GET {base}/experimental/search?q=<query>&searchMode=hybrid&filter[type][eq]=tile&page[size]=1

The two top-1 hits are compared on scores.aggregate and only the higher one is recorded as best_match (with a kind: "skill" | "tile" discriminator). Both per-query errors are still surfaced in search_errors[] for diagnostics, but the schema records exactly one suggestion per source skill.

Output shape

{
  "schema_version": "1.2",
  "metadata": {
    "scan_id": "scan-...",
    "tool_version": "skill-insights@0.11.0",
    "registry_base_url": "https://api.tessl.io",
    "search_mode": "hybrid",
    "skills_searched": 3,
    "skills_skipped_non_standalone": 79
  },
  "matches": [
    {
      "source_skill_id": "<repo>::<skill-name>",
      "source_skill_name": "skill-name",
      "source_tile_name": "workspace/tile-name",
      "source_query": "skill-name <description>",
      "best_match": { "kind": "tile", "id": "...", "name": "...", "full_name": "ws/name", "latest_version": { "version": "0.4.1", ... }, "scores": { "aggregate": 0.94, "evalAvg": 0.96, ... } },
      "search_errors": []
    }
  ],
  "stats": {
    "total_skills_searched": 12,
    "skills_with_match": 9,
    "skills_with_no_match": 3,
    "match_kinds": { "skill": 4, "tile": 5 },
    "search_errors": 0
  },
  "warnings": []
}

best_match is null when both queries fail or return zero results; otherwise it is the higher-aggregate-score hit, tagged with kind so consumers can read kind-specific fields (description/path for skills, full_name/latest_version for tiles) without re-querying. Per-request HTTP errors are captured in search_errors[] (target: "skill" or "tile") without aborting the phase.

Verify

jq -e '.schema_version == "1.2"' "$OUTPUT_PATH" > /dev/null
jq '.stats' "$OUTPUT_PATH"

matches.length should equal metadata.skills_searched.

Summary line

Registry search complete.
  Skills searched:        <N> (source_type=standalone)
  Skipped (non-standalone): <N>
  With match:             <N> (skill=<N>, tile=<N>)
  No match:               <N>
  Search errors:          <N>
  Output:                 <path>

Standalone testability

Needs only discovery.json and network access to api.tessl.io:

python3 <skill-dir>/scripts/registry_search.py \
  --discovery /path/to/.skill-insights/discovery.json \
  --output /tmp/registry-search.json

No other phases need to have run.

skills

README.md

tile.json