Project Learnings

SkillFiles & storage

Use PROACTIVELY, without being asked, at the START of any multi-step task in a git repo, project folder, or vault (before reading files) and at the END of one (to reflect and save). Applies whenever the user asks to implement, fix, refactor, debug, or investigate something in a project, whenever a first attempt was wrong or the user corrected the agent, and whenever the agent rediscovers something a previous session should have known. Retrieves what earlier sessions learned about operating in the project and saves durable insights (locations, traps, conventions, decisions with rationale, workflows, open questions, what to do differently) to an opt-in, append-only InfraNodus graph named learn- plus the project name. Also on "what do we know about this repo?", "what did I learn?", "save learnings", "remember this about the project", "start keeping learnings", "/learnings". Load before calling get_project_learnings, add_project_learnings, or enable_project_learnings directly. Never writes without the user's explicit per-project opt-in and review of each batch. Project knowledge only, never anything about the person.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Project Learnings skill

What this skill tells your AI

The instructions your AI receives, as published by infranodus/skills in skill-project-learnings/SKILL.md and read by ahel’s review.

An agent that works in a project keeps rediscovering the same things: which of nine files holds the model list, that the tests only exist as ad-hoc scripts, why a cache is per-process, which command actually deploys. This skill turns those rediscoveries into a learnings graph in the user's InfraNodus account — learn-<project> — that the next session reads before it starts and appends to when it finishes.

It is a graph rather than a notes file because learnings link to the same entities (file paths, modules, concepts) as everything else in the project: "which parts of the codebase accumulate traps" is a graph query, and the gaps between what is known and what the code contains show where nobody has looked yet.

Prerequisites

The connected InfraNodus MCP server must expose these three tools (added after infranodus-mcp-server 1.7.4; hosted at https://mcp.infranodus.com or the npm package):

  • get_project_learnings — read (by prompt, by entity, overview, or list)
  • add_project_learnings — propose / write (dry run by default)
  • enable_project_learnings — create the graph, only on the user's explicit request

If they are missing from the tool list, say so once ("the connected InfraNodus server doesn't expose project learnings; update it or connect https://mcp.infranodus.com") and continue the task without this skill. Do not emulate the feature with memory_add_relations — that would bypass the consent model.

Consent — read before anything else

  1. Nothing is written unless the user enabled learnings for this project. add_project_learnings refuses (enabled: false) when the graph does not exist and never creates it. Never call enable_project_learnings on your own initiative — only when the user explicitly asks to start keeping learnings for a project. Before that call, tell them in two sentences what will be stored (project knowledge only), where (a private, append-only graph in their InfraNodus account that they can delete at any time), and that each batch is shown before it is saved.
  2. Show every batch before it is written. add_project_learnings is a dry run by default. Present the plan, ask, and only then call again with confirm: true. If the client supports MCP elicitation the server asks the user itself and writes in the same call. Skip the question only when the user has said, in this conversation, that they do not want to be asked.
  3. Project knowledge only. "The model list lives in nine files" is a learning. "The user prefers short answers" is not — that belongs in the client's own memory, never in a shared graph.
  4. No secrets, hostnames, env values, credentials, customer data, or verbatim error output. Paths and descriptions only. The server rejects secret-like statements and reports only their index.
  5. If get_project_learnings returns enabled: false, carry on with the task without this skill. At the end of a substantive task, if you hold at least one learning that passes the admission criteria below, say once — one sentence — that learnings are not enabled for this project and can be turned on with "start keeping learnings". Never repeat that in the same session, and never enable on your own. With nothing worth keeping, stay silent.

Workflow

1. Start of a substantive task — retrieve

Call get_project_learnings with the project name and the task as prompt. Use the same project name every time (the repo or folder name; call the tool with no project to see which names already exist in the account). The response carries the most relevant learnings, the areas that have accumulated knowledge (knownAreas), and the gaps. Read them before opening files. Skip for trivial tasks (a typo, a one-line answer).

2. Before touching an unfamiliar area — look up the entity

get_project_learnings with entity set to the file path, module, or concept returns every learning that mentions it. Cheap; do it before the first edit in an area this session has not visited.

3. End of a substantive task — reflect

A substantive task is multi-step, involved discovery, a correction from the user, or a non-obvious fix. Ask yourself four questions:

  • What did I have to discover that was not in the docs or obvious from the code?
  • Where did I go wrong first, and what was the actual cause?
  • What decision did I make, and why that one?
  • What would I check first next time?
  • Self-assessment: what about my approach worked well in this project and should be repeated, and what should I do differently next time — which check would have caught a mistake earlier, which order of steps saved effort, where did I over- or under-verify? Save these with type approach. Be as honest about what went well as about what did not: both are equally useful to the next session.

Draft 0–5 statements. Zero is a normal answer; do not pad. Each must pass all five admission criteria:

  1. Not derivable from the code, docs, or git history in a few reads
  2. Would have saved time if known at the start
  3. Survived verification — only after the thing actually worked
  4. About the project, never about the person
  5. Adds insight, not just a fact: prefer learnings that connect things that are not obviously connected — a cross-module dependency, a pattern that recurs across files, the non-obvious consequence of a design choice, a hypothesis about why something is the way it is. A location fact is admissible; a location fact plus the reason it is scattered is better.

Then add_project_learnings (dry run) → show the plan → confirm: true on agreement.

4. User-initiated

"Save what you learned", "remember this about the project", "/learnings": run step 3 immediately for the current session, whatever its size.

Statement contract

One statement per learning, at most two sentences, with at least two [[wikilinked]] entities — file paths, modules, functions, concepts, tools. Entities are what make the graph queryable, so link the things a future session would search for.

Each statement carries one type:

typeuse for
locationwhere X lives, especially when it is scattered or misnamed
trapwhat went wrong first and why
conventionhow things are done here that the code does not spell out
decisionwhat was chosen and the rationale
workflowhow to run, test, build, deploy, debug
questionopen, unresolved, worth a future session's attention
approachself-assessment: what worked well and should be repeated, or what to do differently next time

Example (a real one):

The list of available AI model names is duplicated in 9 places: the modelToUse enums in [[src/schemas/index.ts]], [[src/instructions.ts]], [[src/resources/about.ts]], [[README.md]], and the tool defaults in [[generateOntologyGraph.ts]] and [[analyzeLlmResults.ts]]. Source of truth is [[infranodus-app]] routes/ai.js getModelsAvailable, which keeps old names as aliases.location

Reading the tool responses

  • enabled: false → not enabled for this project; nothing written. Carry on (or, if the user asked to save, tell them it is not enabled and offer to enable it — they decide).
  • dryRun: true with wouldWrite → show it. Items marked reinforced are near-duplicates of something already known; they are written as a short "Confirmed again" statement, which raises the weight of the same links. That is deliberate: things that keep being rediscovered become central.
  • declined: true with a note → the user wants a change; adjust and try once more. Without a note → do not retry.
  • dryRun: true with an elicitation field → the server tried to ask the user directly but could not (dialog dismissed, client error). Not a decline: show the plan and ask in chat as usual.
  • rejected with indices → strip the secret-like content from those statements (the server never echoes it) and resubmit.
  • A stale learning is not deleted (the graph is append-only); it is superseded by a newer statement, and retrieval sorts newest first. If you find a learning that names a file that no longer exists, add the correction as a new statement.

Using the graph as a graph

Once a project has a few dozen learnings, the InfraNodus tools that work on any saved graph work on learn-<project> too:

  • get_project_learnings with no prompt/entity → overview: known areas, main concepts, gaps. Add type: "trap" for the fragile parts of the project, type: "question" for what previous sessions left open, type: "approach" for what worked and what to do differently.
  • analyze_existing_graph_by_name on the graph name → clusters, gaps, and the most influential entities across all learnings.
  • optimize_knowledge_base with graphName: "learn-<project>" and focus: "codebase" (or "procedural" for a rule-heavy project) → structural feedback on the learnings themselves: which areas of the project dominate what was learned, which are under-developed, which clusters of learnings never connect. Add compareWith: ["repo-<project>-structure"] when the infranodus skill built one to see the parts of the code base no learning has touched.
  • If the infranodus skill has built repo-<project>-* graphs, difference_between_texts with {graphName} contexts shows modules that have code but no learnings — unexplored territory — and the learnings graph can be added to that project's infranodus/manifest.json as a scope with policy: "learnings" so question routing sees it. Optional; nothing here depends on the manifest.

The type of each learning is stored as statement metadata (a category on the statement), not as a node — so the graph's nodes are only the real entities and the structure is not distorted by the labels. Filter by type through the tool's type parameter or the statement categories in the InfraNodus UI.

Relationship to other skills

  • infranodus — maps what a repo or vault contains (deterministic extraction). This skill records what an agent learned operating in it. They share entity names, so the graphs compose.
  • llm-wiki — authored knowledge pages compounding over time. Route there when the user wants prose, not one-line operational learnings.
  • Claude Code's own file memory — per-user, per-machine. Keep using it for user preferences and for project facts when learnings are not enabled; when they are, project-type facts go to both.

Who decides when this runs

This skill can only ask; every gate is the user's. Nothing here needs a hook or a CLAUDE.md entry to work, and the skill ships neither.

  • The real gate is server-side. Until the user enables learn-<project>, an automatic invocation is one read call that returns enabled: false, after which the skill goes dormant for the session. Nothing is written, nothing is created.
  • Manual only. Set disable-model-invocation: true in this file's frontmatter (the description leaves Claude's context; only /project-learnings invokes it), or per project in .claude/settings.local.json: "skillOverrides": { "project-learnings": "user-invocable-only" } ("off" hides it entirely).
  • Remove. Delete the skill folder or uninstall the plugin.
  • Every session, guaranteed. The user's own choice, never the skill's: a line in the project's CLAUDE.md such as Before any multi-step task call get_project_learnings for project <name>, or a SessionStart hook that injects the same sentence (the update-config skill can add one).

Reference: https://code.claude.com/docs/en/skills ("Control who invokes a skill", "Restrict Claude's skill access").

Example

User: start keeping learnings for this repo

Agent: I'll create a private, append-only graph learn-mcp-server-infranodus in your InfraNodus account. It will hold knowledge about operating in this project — where things live, traps, conventions, decisions — never anything about you, never secrets. I'll show each batch before saving, and you can delete the graph any time. Enabling now. (calls enable_project_learnings)

…later, after a task…

Agent: Two things from this session worth keeping:

  1. [trap] Reading a graph right after creating it can fail on infranodus.com: the app runs several instances with a per-process contexts-list cache ([[lib/middleware/getOwnerContextsList.js]]); [[src/utils/learnings.ts]] retries reads and treats any positive as authoritative.
  2. [workflow] There is no test runner in the repo; [[npm test]] builds with tsc and runs [[node --test]] over test/*.test.mjs against dist/.
  3. [approach] Testing the new tools through an in-memory [[MCP client]] with an intercepted [[fetch]] caught the body-shape and session-state bugs that unit tests of the pure helpers missed; do that before any live run in this project.

Save these? (dry run shown; on "yes" → confirm: true)

Signals

GitHub stars
119
Forks
30
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
project-learnings
Source
github.com/infranodus/skills