Project Metadata (.navin/metadata)
Overview
Every serious project gets a .navin/metadata/ folder at its root: a machine-readable
map of what each file is, what it does, and what it depends on. The Dev
workbench renders it as an interactive metagraph (nodes = files, colored by
nature; edges = dependencies). Your job: build it once, keep it truthful, and
consult it before grepping when the user asks "where is X handled?".
The metagraph tool
You have a dedicated tool named metagraph that builds this graph live
(parsed imports + your .navin/metadata/index.json annotations). Use it FIRST:
metagraph(action="overview") - file counts by kind, the most connected
hub files, and whether .navin/metadata/ exists yet.
metagraph(action="file", path="navin/agent/loop.py") - one file's kind,
role, what it depends on, and what depends on it.
metagraph(action="find", query="checkpoint", kind="back") - locate files
by path fragment, role text, and/or kind
(front/back/sql/config/test/docs).
metagraph(action="annotate", files={...}) - record roles. This is the only
way to write .navin/metadata/index.json: it merges the entries you pass into
whatever is already there, validates them, and stamps each one with the file's
current size so a later run can tell which roles went stale. Never write that
file with write_file - a hand-written entry carries no stamp and is invisible
to staleness reporting.
Reach for grep only when the graph cannot answer (string literals, exact
code contents). The tool reads roles from .navin/metadata/index.json, so the
richer you keep the index, the better find answers become.
Files
.navin/metadata/
index.json # the knowledge base (format below)
ARCHITECTURE.md # human-readable summary: layers, entry points, data flow
index.json format
{
"version": 1,
"updated": "2026-07-22T10:00:00Z",
"files": {
"webui/src/App.tsx": {
"kind": "front",
"role": "Root React component: routing, view state, session wiring",
"depends_on": ["webui/src/lib/api.ts", "webui/src/components/Sidebar.tsx"],
"tags": ["entry"]
},
"navin/webui/ws_http.py": {
"kind": "back",
"role": "Gateway HTTP routes: sessions, files, settings, studio APIs",
"depends_on": ["navin/webui/file_tree.py"],
"tags": ["api"]
}
}
}
kind: one of front, back, sql, config, test, docs, asset, other.
role: ONE sentence, concrete - what the file does, not what it is named.
depends_on: project-relative paths this file imports/reads/calls. The
backend already parses Python/JS imports automatically; only list what static
parsing cannot see (SQL tables used, config files read, templates rendered,
HTTP endpoints called).
tags: optional, short (entry, api, schema, hot-path, deprecated).
Workflow
Init (new or existing project) - when starting work on a project that has
no .navin/metadata/:
- Call
metagraph(action="overview") and read the root and discovery line it
prints back. A count only means "the whole project" if the root is the project
you were asked about; when discovery says gitignored files were included, or
the file count is far below what you expect from the tree, say so instead of
reporting coverage as if the map were complete.
- For each significant source file, read enough to write an honest one-line
role. Batch-read; don't summarize files you haven't opened.
- Record them with
metagraph(action="annotate", files={...}), in batches, then
write ARCHITECTURE.md. Report coverage against the root you named in step 1
("214 of 226 files described, 12 skipped as assets").
Maintain - the runtime context tells you, every turn, which recorded roles
have gone stale and which code files have none. Annotate the files you touched as
part of finishing the work, in the same turn. Do not stop a task to work through
the whole backlog. A stale index is worse than none.
Answer questions - when the user asks where something lives or how parts
connect: call metagraph(action="find", ...) or metagraph(action="file", ...)
first, answer with the exact file list and the dependency chain. Grep only to
verify or when the graph lacks the answer, then backfill what you learned into
the index.
Rules
- Never index secrets or copy file contents into the index - roles only.
- Cap
role at ~120 chars; this is a map, not documentation.
- Don't index vendored/generated code (
dist/, lockfiles get kind config, no role needed).
ARCHITECTURE.md stays under one page: layers, entry points, main flows, where to start reading.
- The metagraph view in the Dev workbench reads this file live - after a big
refresh, tell the user to open the Graph tab to see it.
1---2name: project-metadata3description: Create and maintain the .navin/metadata project knowledge base - file roles, dependencies, and the metagraph index - so questions map instantly to the right files without grepping. Use at project start and whenever files are added, moved, or repurposed.4---56# Project Metadata (.navin/metadata)78## Overview910Every serious project gets a `.navin/metadata/` folder at its root: a machine-readable11map of what each file is, what it does, and what it depends on. The Dev12workbench renders it as an interactive **metagraph** (nodes = files, colored by13nature; edges = dependencies). Your job: build it once, keep it truthful, and14**consult it before grepping** when the user asks "where is X handled?".1516## The `metagraph` tool1718You have a dedicated tool named `metagraph` that builds this graph live19(parsed imports + your `.navin/metadata/index.json` annotations). Use it FIRST:2021- `metagraph(action="overview")` - file counts by kind, the most connected22 hub files, and whether `.navin/metadata/` exists yet.23- `metagraph(action="file", path="navin/agent/loop.py")` - one file's kind,24 role, what it **depends on**, and what **depends on it**.25- `metagraph(action="find", query="checkpoint", kind="back")` - locate files26 by path fragment, role text, and/or kind27 (`front`/`back`/`sql`/`config`/`test`/`docs`).28- `metagraph(action="annotate", files={...})` - record roles. This is the only29 way to write `.navin/metadata/index.json`: it merges the entries you pass into30 whatever is already there, validates them, and stamps each one with the file's31 current size so a later run can tell which roles went stale. Never write that32 file with `write_file` - a hand-written entry carries no stamp and is invisible33 to staleness reporting.3435Reach for `grep` only when the graph cannot answer (string literals, exact36code contents). The tool reads roles from `.navin/metadata/index.json`, so the37richer you keep the index, the better `find` answers become.3839## Files4041```42.navin/metadata/43 index.json # the knowledge base (format below)44 ARCHITECTURE.md # human-readable summary: layers, entry points, data flow45```4647## index.json format4849```json50{51 "version": 1,52 "updated": "2026-07-22T10:00:00Z",53 "files": {54 "webui/src/App.tsx": {55 "kind": "front",56 "role": "Root React component: routing, view state, session wiring",57 "depends_on": ["webui/src/lib/api.ts", "webui/src/components/Sidebar.tsx"],58 "tags": ["entry"]59 },60 "navin/webui/ws_http.py": {61 "kind": "back",62 "role": "Gateway HTTP routes: sessions, files, settings, studio APIs",63 "depends_on": ["navin/webui/file_tree.py"],64 "tags": ["api"]65 }66 }67}68```6970- `kind`: one of `front`, `back`, `sql`, `config`, `test`, `docs`, `asset`, `other`.71- `role`: ONE sentence, concrete - what the file does, not what it is named.72- `depends_on`: project-relative paths this file imports/reads/calls. The73 backend already parses Python/JS imports automatically; only list what static74 parsing cannot see (SQL tables used, config files read, templates rendered,75 HTTP endpoints called).76- `tags`: optional, short (`entry`, `api`, `schema`, `hot-path`, `deprecated`).7778## Workflow7980**Init (new or existing project)** - when starting work on a project that has81no `.navin/metadata/`:821. Call `metagraph(action="overview")` and read the root and discovery line it83 prints back. A count only means "the whole project" if the root is the project84 you were asked about; when discovery says gitignored files were included, or85 the file count is far below what you expect from the tree, say so instead of86 reporting coverage as if the map were complete.872. For each significant source file, read enough to write an honest one-line88 role. Batch-read; don't summarize files you haven't opened.893. Record them with `metagraph(action="annotate", files={...})`, in batches, then90 write `ARCHITECTURE.md`. Report coverage against the root you named in step 191 ("214 of 226 files described, 12 skipped as assets").9293**Maintain** - the runtime context tells you, every turn, which recorded roles94have gone stale and which code files have none. Annotate the files you touched as95part of finishing the work, in the same turn. Do not stop a task to work through96the whole backlog. A stale index is worse than none.9798**Answer questions** - when the user asks where something lives or how parts99connect: call `metagraph(action="find", ...)` or `metagraph(action="file", ...)`100first, answer with the exact file list and the dependency chain. Grep only to101verify or when the graph lacks the answer, then backfill what you learned into102the index.103104## Rules105106- Never index secrets or copy file contents into the index - roles only.107- Cap `role` at ~120 chars; this is a map, not documentation.108- Don't index vendored/generated code (`dist/`, lockfiles get kind `config`, no role needed).109- `ARCHITECTURE.md` stays under one page: layers, entry points, main flows, where to start reading.110- The metagraph view in the Dev workbench reads this file live - after a big111 refresh, tell the user to open the Graph tab to see it.