← Back to blog
Product July 30, 2026 by Javier Arancibia

The Skill Graph — Why My Agent Was Using the Wrong Skill

I have 197 skills. They live in ~/.agents/skills/, each a directory with a SKILL.md file — a name, a description, and instructions for an AI agent to follow. Some are mine (jar-dk1-manage, jar-intrane-fr-maintenance), some are from tools I've adopted (add-feedback-command, supercli-rtk), some are framework skills. 67 namespaces, 264 nodes, 6,065 edges when I graph them.

The problem: my agents were using the wrong skill half the time.

Not because the skills are bad — because finding the right one is hard. An agent lands in a repo, needs to update a landing page on intrane.fr, and reaches for superlandings-sl-cli (the generic CLI skill) instead of jar-intrane-fr-maintenance (the specific one with the Mongo URI, the cache invalidation steps, the gotchas). Same domain, wrong depth. Or worse: the agent doesn't know any skill exists and reinvents the workflow from scratch, missing the credentials file, the deploy steps, the rollback procedure.

I shipped memgraph to fix this.

The itch

Skills are the agent equivalent of a senior developer's muscle memory. When I sit down to fix something on dk1, I don't read the SSH config from scratch — I know it. Skills encode that knowledge so any agent can have it. But the discovery layer was broken.

The existing approach was filename matching: the agent greps the skills directory for keywords in the filename. Search for "feedback" and you get add-feedback-command — but also jar-feedback-relay-manage, and the agent has no way to know which one it actually needs. Search for "intrane" and you get 12 skills, none ranked. Search for "update the landing page" and you get nothing, because no skill is named that.

The agent needs semantic discovery, not lexical. It needs to understand that jar-intrane-fr-maintenance is about landing pages even though the words "landing page" don't appear in the filename. It needs to rank jar-intrane-fr-maintenance above superlandings-sl-cli when the task is specifically about intrane.fr, and rank the reverse when the task is about a different landing. And it needs to do this in milliseconds, from a single binary, with JSON on stdout.

memgraph — a skill discovery engine

memgraph is a Go binary that does three things:

  1. Ingest — scan a directory of SKILL.md files, parse the YAML frontmatter, build a knowledge graph where each skill is a node and edges connect skills that share tags, namespaces, or semantic overlap.
  2. Rank — given a task description, score every node using TF-IDF on the skill's name + description + tags, then boost skills that are connected to other high-scoring skills (graph boost). The top-N results are the skills the agent should read first.
  3. Serve — a daemon with an embedded galaxy visualization (a phyllotaxis spiral where each star is a skill, colored by namespace, connected by edges) and a JSON API for agents to query.

The CLI contract is the agent-first CLI spec, end to end:

memgraph query "update the intrane.fr landing page" --json
# {"version":"1.0","data":{"count":5,"results":[
#   {"id":"jar-intrane-fr-maintenance","name":"jar-intrane-fr-maintenance",
#    "score":236,"description":"Maintain and update the intrane.fr landing page..."},
#   {"id":"superlandings-sl-cli","name":"superlandings-sl-cli",
#    "score":107,"description":"Generic CLI usage for the SuperLandings platform"},
#   ...
# ]}}

The agent gets ranked results on stdout, reads the top skill's SKILL.md, and has the full workflow — Mongo URI, cache invalidation, deploy steps — in its context before it starts. No guessing, no reinventing, no superlandings-sl-cli when it needs jar-intrane-fr-maintenance.

Why TF-IDF + graph boost, not embeddings

I considered embeddings. Every skill's description → 1536-dim vector → cosine similarity to the query. It's the obvious approach, and it works. But it has three problems for this use case:

1. Latency. Embedding a query requires a network call to an embedding API. memgraph's ranking is local, sub-millisecond, and works offline. An agent shouldn't wait 200ms to discover which skill to read.

2. Precision. Embeddings are great for "find me something similar to X" but bad at "find me the skill that handles X specifically." TF-IDF with exact token matching gives higher weight to skills that literally contain the query terms in their name or tags. When I search for "intrane", the skill jar-intrane-fr-maintenance should rank above superlandings-sl-cli because it has "intrane" in its name — not because it's semantically adjacent in embedding space.

3. Dependency. Embeddings require a model, an API key, and a network connection. memgraph is a single Go binary with zero runtime dependencies. It works on a fresh machine with nothing but the binary.

The graph boost is the secret sauce. When two skills share tags or namespaces, they're connected by an edge. If jar-intrane-fr-maintenance scores high on a query, skills connected to it get a boost — because if the task is about intrane.fr, skills in the same namespace (jar-intrane-fr-blog-manage, jar-grepapi-intrane-manage) are probably relevant too. It's PageRank for skills, but simpler: the boost is additive, not iterative.

The galaxy

Skill discovery is for agents. But sometimes a human wants to see the graph — to understand what skills exist, how they cluster, where the gaps are. So memgraph has a serve command that starts a daemon with an embedded UI: a phyllotaxis spiral where each star is a skill, positioned by its index in the graph, colored by namespace, sized by its connection count. Drag a star and its edges follow. Toggle edge visibility. Search and the matching stars brighten.

It's not a dashboard. It's a map. You look at it once and understand the shape of your skill library — that jar-* skills cluster together, that add-* skills are the spec adoption skills, that the supercli-* namespace is its own island. The galaxy is rendered with Three.js, served from the same Go binary, and it's the only piece of memgraph that needs a browser.

Dogfooding the agent-first specs

memgraph is the sixth tool to adopt the agent-first CLI specs — and the first one that started as a spec adoption exercise and became a product.

The output spec was already there: --json on every command, typed errors with {"error":{"code":85,"type":"invalid_argument","message":"...","recoverable":false}}, semantic exit codes (0 = success, 80-89 = input/validation, 90-99 = precondition, 110-119 = internal). stdout is data, stderr is context. An agent that ignores stderr entirely still gets the full result.

The feedback spec was the one I added last. memgraph feedback "the galaxy viz is slow with 500+ nodes" --kind bug --context "browsing a large skill graph" dual-writes to the tool's own endpoint (if configured) and to the central relay at feedback.intrane.fr. Same idempotency key on both writes. Never fails the caller — exit 0 even when the relay is down. The agent can report a bug without the human watching a dashboard.

memgraph feedback "test feedback from CI" --kind note --context "smoke test" --json
# {"data":{"id":"0e4873b8aada7f3e9a5915f5c7a2876c","stored":0,"relayed":1},"ok":true}

That's a real submission. It landed in the relay. I can read it back with the admin token:

curl -s -H "Authorization: Bearer $FEEDBACK_ADMIN_TOKEN" \
  "https://feedback.intrane.fr/v1/feedback?app=memgraph"
# {"ok":true,"feedback":[{"id":"0e4873b8...","app":"memgraph",
#   "version":"1.4.0","kind":"note","message":"test feedback from CI",
#   "context":"smoke test","reporter":"jarancibia","created":1785348577}]}

Open intake, admin-gated reads, idempotent on a client-generated id. The agent files the feedback; I read it when I want. No dashboard, no email, no Slack — just a JSON endpoint and a SQLite table.

What I learned building it

The ranking is the product. The graph ingestion, the serve daemon, the galaxy visualization — none of that matters if the ranking is wrong. I spent more time on the scoring function than on everything else combined. The golden-corpus test (7 fixed queries against a stable fixture, pinning the top-N ordering) was the single best investment — it caught three ranking regressions during development that I would have shipped otherwise.

Code duplication is a ranking bug. The ranking logic was originally triplicated across handleQuery, handleRecommend, and apiSearchHandlerV2. They drifted. The same query gave different results depending on which entry point you used. Consolidating into a single rankNodes function fixed three bugs and made the golden test possible — you can't pin ranking order when there are three different rankings.

"Not implemented" is a stability bug. The memgraph remember command had a not_implemented code path — no --text flag, no positional args, and it returned exit 110 with "not_implemented". A core command with a broken path. I found it grepping for TODO|FIXME|not_implemented before cutting the stable release. Fixed it to read from stdin, added a test, shipped. The grep is now part of my pre-release checklist.

34 tests is enough for a 1.0. Not 34 tests for coverage's sake — 34 tests that pin the contracts: graph build determinism, query scoring, ranking order (golden corpus), serve API JSON-error shape, end-to-end ingest, memory write, feedback dual-write. Each test guards a specific promise to the user. If the test passes, the promise holds. If it fails, I broke a promise and the CI is red.

Where it goes next

memgraph is v1.4.0 — stable public API. The CLI flags, JSON output shapes, and ranking weights are frozen. It's in the Intrane toolkit, it's on the central feedback relay, and it's the skill discovery engine I dogfood every day.

The next specs to adopt are cli-guide-spec (an embedded mental model so agents learn the tool without reading docs) and cli-update-spec (content-hash self-update so the binary stays current without an installer). The help-json command from the output spec is also missing — agents currently read --help text and parse it, which works but isn't ideal.

If you have skills — in ~/.agents/skills/, .claude/skills/, .devin/skills/, or anywhere else with a SKILL.md — point memgraph at them and see what your graph looks like:

memgraph graph-from-dir ~/.agents/skills
memgraph query "your next task" --json
memgraph serve  # see the galaxy

And if something's wrong — the ranking is off, a skill is missing, the galaxy is slow — there's a command for that:

memgraph feedback "the ranking for X is wrong, Y should be higher" --kind bug

It lands in my relay. I read it. No dashboard required.

Previous in this series: Four Specs That Make Any CLI Agent-First — the specs that memgraph adopts.

Enjoyed this post?

Follow for more on agent-first engineering, self-hosted systems, and building for autonomy.

Follow @javimosch