brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
understand-explainExplains one file, function, class, table or folder of a codebase in depth, starting from the knowledge graph built by the Understand-Anything plugin and confirming every statement in the source. Use when someone says "explain this file", "how does this function work", "walk me through the scheduler module", "what is this class for and who uses it", "run /u…
Independent GitHub snapshot · Automated classification · Original documentation governs
Understand-Anything is an open-source plugin for coding agents. /understand analyses a repository once and saves a knowledge graph as JSON; /understand-explain takes one target, such as src/services/scheduler.ts or src/services/scheduler.ts:bookSlot, and explains it.
Reading a file tells what its lines do. It does not tell why the file exists, which requests end up in it, what it is allowed to assume about its inputs, or what would break if it changed. The graph holds exactly that surrounding picture: the node's summary and tags, its architectural layer, the tour step that introduces it, and every relationship in and out. This skill pulls that picture in one query, then reads the code and writes an explanation in which the context comes from the graph and every statement about behaviour comes from a line that was opened.
Graph fields it reads:
| Field | Role in the explanation |
|---|---|
nodes[]: id, type, name, filePath, lineRange, summary, tags, complexity, languageNotes | finding the target and its exact lines; a first hypothesis of its purpose |
edges[]: source, target, type | what the target relies on and what uses it |
layers[]: name, description, nodeIds | where it sits in the architecture |
tour[]: order, title, nodeIds, languageLesson | whether the analysis considered it part of the main story |
project.gitCommitHash | whether the graph still matches the file |
No graph in the project: install the plugin (in Claude Code, /plugin marketplace add Egonex-AI/Understand-Anything and /plugin install understand-anything) and run /understand. Installation on other hosts and the analysis options are covered in the understand-chat skill.
The target comes from the request. Accept any of these forms:
| Given | Meaning |
|---|---|
src/lib/time.ts | a file |
src/lib/time.ts:overlaps | a function or class inside a file |
overlaps or SlotTakenError | a bare name, to be looked up |
src/db/ | everything under a folder |
| "the booking logic", "whatever sends reminders" | a description; turn it into names first by matching tags and summary |
Decide who is reading, because it changes the depth and the vocabulary. If the request does not say, assume the second row.
| Reader | Write |
|---|---|
| Knows programming, not this language | the standard explanation plus a plain reading of each idiom; use languageNotes when the node has it |
| Engineer new to this codebase | purpose, position, walkthrough, contracts, dependants, risks |
| Maintainer or reviewer about to change it | the same, plus invariants, failure modes, the tests that pin behaviour and the places that must change together |
G=.ua/knowledge-graph.json
[ -d .understand-anything ] && G=.understand-anything/knowledge-graph.json
T='src/services/scheduler.ts:bookSlot'
jq -r --arg t "${T%/}" '
($t | split(":")) as $parts
| .nodes[]
| select(.filePath == $t or .name == $t
or (($parts | length) == 2 and .filePath == $parts[0] and .name == $parts[1])
or ((.filePath // "") | startswith($t + "/")))
| [.id, .complexity, (.lineRange // [] | join("-"))] | @tsv' "$G"
Run it from the directory that holds the data folder (the repository root, or the analysed subdirectory of a monorepo). What comes back decides the next move:
path:name target, or a file line followed by its members for a path: continue with the first id.jq -r '.nodes[].filePath // empty' "$G" | sort -u | grep -i scheduler. A file that exists on disk but has no node is new, generated, or excluded by .understandignore. Explain it from source alone and state that the graph had no context for it.Save this filter as ua-dossier.jq. It prints the target, its layer and tour steps, the symbols it contains, and its relationships in both directions. For a file it treats the file and its members as one unit, so calls made by its functions count as the file's own.
(.nodes | map({key: .id, value: .}) | from_entries) as $n
| $n[$id] as $me
| ([$id] + [.edges[] | select(.type == "contains" and .source == $id) | .target]) as $scope
| def inside: . as $x | $scope | index($x) != null;
def links(f; g): [.edges[] | select(.type != "contains" and .type != "exports")
| select((f | inside) and (g | inside | not)) | " \(.type) \(g) -- \($n[g].summary)"] | unique[];
"TARGET \($me.id) [\($me.complexity)] \($me.filePath // "-") \($me.lineRange // [] | join("-"))",
"SUMMARY \($me.summary)",
"TAGS \($me.tags | join(", "))" + (if $me.languageNotes then "\nNOTES \($me.languageNotes)" else "" end),
(.layers[] | select(any(.nodeIds[]; $n[.].filePath == $me.filePath)) | "LAYER \(.name): \(.description)"),
(.tour[] | select(any(.nodeIds[]; inside)) | "TOUR step \(.order): \(.title)"),
"MEMBERS", ($scope[1:][] | " \(.) lines \($n[.].lineRange // [] | join("-")) [\($n[.].complexity)]"),
"RELIES ON", links(.source; .target),
"USED BY", links(.target; .source)
jq -r --arg id 'function:src/services/scheduler.ts:bookSlot' -f ua-dossier.jq "$G"
Reading the two relationship lists: RELIES ON is every edge that starts at the target, USED BY every edge that ends at it. For imports, calls, reads_from and writes_to those headings are literally true. A tested_by line under RELIES ON names the test that covers the target, and a documents or configures line under USED BY names the document or config file that refers to it.
A function with an empty USED BY list is not necessarily unused. Import edges are recorded between files, so run the dossier for the file node as well before saying anything about callers.
SHA=$(jq -r '.project.gitCommitHash' "$G"); FILE=src/services/scheduler.ts
git rev-parse --verify --quiet "$SHA^{commit}" >/dev/null && git diff --stat "$SHA" -- "$FILE"
git status --porcelain -- "$FILE"
No output means the file is as analysed, and lineRange can be trusted. If the file changed, find the symbol again with grep -n "function bookSlot" "$FILE" and treat the summary as a description of an older version. If the hash does not resolve, say that freshness could not be checked and rely on the source.
nl -ba src/services/scheduler.ts | sed -n '23,31p'
Line numbers in the output are what the explanation cites. Read in this order, and stop when the reader's question is answered:
MEMBERS ranges, then the helpers they call.RELIES ON callee, enough to know what it returns and what it can throw.USED BY, to see which arguments arrive in practice and how errors are handled by the caller.While reading, note three things the graph cannot know: what the code assumes without checking, what it changes outside itself (database, files, network, shared state), and what happens on the failure paths.
For a function, class or single file, use these labelled blocks in this order (Example 1 shows one filled in):
| Label | Content |
|---|---|
| first line | the name, then one sentence saying what it is for in the project's own terms |
Where it sits | layer, path with line range, and the entry point or caller it is reached from |
What it does | numbered steps, each ending with the line or lines it describes |
Contract | inputs and what they must satisfy, the return value, the errors it can raise |
Side effects | writes, messages sent, state changed; or "none" |
Leans on | each callee with what the target gets from it |
Leaned on by | each caller with what it expects back |
Watch out | unchecked assumptions, races and edge cases, with line numbers |
Tests | the test file and the behaviour it pins, or "no test is linked to this file" |
Basis | the graph's short hash and date, and the files and line ranges read in source |
For a folder, replace the walkthrough with a table of its files (path, role in one line, complexity), followed by how data moves between them, the folder's entry points from outside (the USED BY lines whose source is outside the folder), and the single file to read first.
Order matters: purpose before mechanics, mechanics before caveats. Keep quoted code to the lines being discussed. Name things as the code names them, and define a project term the first time it appears.
grep -n "bookSlot" -r src tests)./understand-explain src/services/scheduler.ts:bookSlotProject clinic-booking, a Fastify booking API. Step 2 returns function:src/services/scheduler.ts:bookSlot complex 23-31. The dossier:
TARGET function:src/services/scheduler.ts:bookSlot [complex] src/services/scheduler.ts 23-31
SUMMARY Re-checks availability, inserts the appointment and queues its reminder.
TAGS booking, write-path
LAYER Booking Rules: Scheduling logic and reminders; the only place where availability is decided.
TOUR step 3: Booking an appointment
MEMBERS
RELIES ON
calls function:src/db/appointments-repo.ts:insertAppointment -- Inserts an appointment row and returns it.
calls function:src/services/reminders.ts:queueReminder -- Schedules a reminder message ahead of the appointment start.
calls function:src/services/scheduler.ts:findFreeSlots -- Walks the day in slot-sized steps and keeps the ones no booked appointment overlaps.
USED BY
calls file:src/routes/appointments.ts -- POST /appointments books a slot (409 when taken); DELETE /appointments/:id cancels.
Step 4 prints nothing. After reading lines 23-31, the three callees and the route, the reply is:
bookSlot: turns "this patient wants this start time with this practitioner" into a stored appointment, or refuses.
Where it sits Booking Rules layer; src/services/scheduler.ts:23-31; reached from POST /appointments (src/routes/appointments.ts:13)
What it does 1. Cuts the calendar day out of the start time as a UTC date string (line 24)
2. Recomputes that day's free slots for the practitioner (line 25)
3. Looks for a free slot starting at exactly the requested millisecond (line 26)
4. Throws SlotTakenError when there is none (line 27)
5. Inserts the appointment using the slot's own start and end, never the caller's (line 28)
6. Queues the reminder and returns the stored row (lines 29-30)
Contract takes a practitioner id, a patient e-mail and a Date; returns the Appointment with its database id;
fails with SlotTakenError, or whatever the database driver throws
Side effects one row in appointments; one entry in the in-memory reminder queue
Leans on findFreeSlots: the list of open intervals; insertAppointment: the write; queueReminder: the reminder time
Leaned on by the POST /appointments handler, which maps SlotTakenError to HTTP 409 (line 16) and rethrows the rest
Watch out lines 25-28 check and then insert with no transaction and no unique constraint in schema.sql, so two
simultaneous requests for one slot can both succeed; a start time that is not on a 30-minute boundary
is reported as "taken"; the reminder queue lives in process memory and is lost on restart
Tests tests/scheduler.test.ts covers findFreeSlots only; nothing exercises bookSlot
Basis graph 7c41e0d of 2026-09-28; read scheduler.ts 1-35, appointments.ts 10-19, reminders.ts 7-15, schema.sql in source
The graph called the function "complex" and summarised it as a re-check plus insert. The race between the check and the insert appears nowhere in the graph; it came from reading lines 25-28 next to the table definition.
Request: "explain the appointments table and who touches it". Step 2 with T=appointments returns table:src/db/schema.sql:appointments moderate 6-13. Its dossier has an empty RELIES ON and:
USED BY
reads_from function:src/db/appointments-repo.ts:findByDay -- Booked appointments of one practitioner on one day.
writes_to function:src/db/appointments-repo.ts:insertAppointment -- Inserts an appointment row and returns it.
writes_to function:src/db/appointments-repo.ts:markCancelled -- Sets status to cancelled for a booked appointment.
The explanation lists the six columns from schema.sql:6-13, states that all access goes through one repository file (confirmed with grep -rn "appointments" src, which finds no other SQL), describes the life of a row (inserted as booked, flipped to cancelled, never deleted), and flags that status is free text with no check constraint while the TypeScript type allows only two values.
/understand-explain src/services/waitlist.ts returns no line. The file exists and was created two days after the graph's analyzedAt. The agent explains it from source, finds its importer with grep -rn "waitlist" src, labels the answer "explained from source only; this file is newer than the knowledge graph", and offers an incremental /understand so that the next question about it has context.
complexity, layer assignments and most calls edges were written by a model at analysis time; only what is read in step 5 is evidence.outputLanguage in the data folder's config.json). Match descriptions against that language, and answer in the language the user writes in..env files, key stores or other secrets to explain configuration. Describe which variables the code reads and where they are consumed.