@miadi/relational-git-repository-mapper
v0.7.0
Published
A git repository as Miadi sees it (git, never a database Repository or Data Mapper): the rows its owner hub holds (@medicine-wheel/developer-repository-mapping) beside the agent sessions that worked in it (the witness team's session inventory), joined by
Readme
@miadi/relational-git-repository-mapper
A git repository as Miadi sees it: the rows its owner's hub holds, beside the agent sessions that worked in it.
"Repository" in this package always means a git repository: a project such as
jgwill/Miadi, cloned, committed to, pushed. It never means a database repository: not
the DDD Repository pattern, not a Data Mapper, not a persistence layer. Nothing here
stores records in a database. The name leaves out GitHub on purpose: today the owners
and names are GitHub's, and the mapping is meant to hold other git hosts too.
Formerly @miadi/relational-repository-mapper (0.1.x, deprecated on npm in favour of this
package). The CLI keeps its name, miadi-repomap.
- The rows come from a repository mapping hub, read with
@medicine-wheel/developer-repository-mapping:<owner>/<owner>/.miadi/repository-mapping/, and for a meta hub (jgwill/jgwill) every hub it registers. Lifecycle, purpose, git drift, features, relations. - The sessions come from the witness team's session inventory, read with
@miadi/hooks-interpreter(readInventoryRecords): one record per Claude session. - The join: a record's
repo(owner/name) and the repository of each commit itslinks.tracenames (owner/name@sha), case-folded, matched torepository:<owner>/<name>. A session that committed to two repositories appears under both, with the commits it made in each (commits). Records that name no repository are counted, not shown.
Per session it carries session_id, tmux_session_name, status, the team
(team_fit.team.id, else team), mission, date (as YYYY-MM-DD), the titles of work_completed, the
ending (disposition.proposed, disposition.decided) and links.evidence refs. The
keeper's descriptions and file lists stay in the record.
When no hub is configured, or the hub clone holds no mapping folder yet, every repository reads "no mapping yet" and still lists its sessions.
The address of a capability
Each capability has an address that an episode, an issue, an inquiry, a ceremony
diary entry or a circle turn cites it by (Episode 568, decided by William on
2026-11-01): miadi-capability://<owner>/<repo>/<kind>/<name>, for example
miadi-capability://jgwill/medicine-wheel/skill/fire-keeper-check. capabilities
prints it under each row, capabilityAddress() makes it, and findCapability()
reads the row an address names. In the app it opens
/capabilities/<owner>/<repo>/<kind>/<name>; the grammar is
@miadi/inquiry-weave/references (parseCapabilityUri).
Capabilities defined in code
A repository that defines capabilities in code, not in files of their own, is read
by a reader written for that file (CODE_READERS), never guessed. The first is the
medicine wheel's cli/skills.ts, whose 13 skills mw skill install writes out as
SKILL.md files.
Lineage: which git repository learned from which
A lineage is not a dependency. learned-from says that one repository took what another
explored and carries it on its own, sometimes with another way of knowing, without
importing it. Dependencies (consumes) stay in the owner hubs.
miadi-repomap lineage jgwill/medicine-wheel # what did the medicine wheel learn from?
miadi-repomap lineage # every lineage, the whole forestThe rows this package ships come from William's word in Episode 297
(screenwalk 2610221013, 10:03–11:21): jgwill/coaiajs learned from
avadisabelle/coaia-narrative, and jgwill/medicine-wheel learned from both. None
depends on another. Every row is pending until William reads it. A host adds or corrects
rows with a JSONL file (--lineage <file> or MIADI_REPOSITORY_LINEAGE), read first: the
first file to name a pair speaks for it. Each row carries the attribution of
@medicine-wheel/capabilities, a description of at most 55 words, and
"type": "learned-from".
In the app: GET /api/repositories/lineage[?repository=owner/name], and the lineage
field of GET /api/repositories/{owner}/{name}, shown as a Lineage card on its page.
Capabilities: what a git repository provides
Each repository's packages, CLIs and skills are capability nodes of
@medicine-wheel/capabilities (capability:package-…, capability:cli-…,
capability:skill-…), and the repository provides each one.
miadi-repomap capabilities jgwill/medicine-wheel # what does the medicine wheel provide?
miadi-repomap capabilities # every capability, and who provides it
miadi-repomap scan <clone>... --by "<who>" # read a clone's default branch, print JSONL rowsscan takes a repository's own .miadi/capabilities.jsonl first when the commit holds one,
merged with what the commit's files say. Anyone writes that file with
npx @medicine-wheel/developer-repository-mapping capabilities scan --write, which is where the
scan now lives, so it runs without the Factory. scan reads a repository's default branch
(origin/HEAD) from git objects, never its
working tree, so a clone on another branch or with edits of its own reads the same. It reads
the packages the repository declares (workspaces, or pnpm-workspace.yaml), each
package's bin, and every SKILL.md outside node_modules and archives. A statement is the
file's own description, kept only within 55 words; longer, the row is needs-resolution
without one. Every row names the commit it was read at and stays pending until a person
reads it.
The package ships a scan of jgwill/Miadi and the three lineages (avadisabelle/coaia-narrative,
jgwill/coaiajs, jgwill/medicine-wheel), regenerated with
node scripts/ship-capabilities.mjs <scan.jsonl> <scan.log> <packages.jsonl> (and the host readings with node scripts/ship-hosts.mjs <hosts.jsonl>). A host's JSONL
(--capabilities or MIADI_REPOSITORY_CAPABILITIES) is read first; the first source to name
a capability speaks for it.
In the app: GET /api/repositories/capabilities[?repository=owner/name] answers with the
capabilities and their provides edges, GET /api/repositories/{owner}/{name} carries them,
and the repository page's Lineage card lists them by kind.
Which capabilities a commit changed
import { capabilitiesOfCommit } from "@miadi/relational-git-repository-mapper";
capabilitiesOfCommit("jgwill/Miadi@b746c9a4", "/a/src/Miadi").capabilities.map((c) => c.address);
// → miadi-capability://jgwill/Miadi/package/@miadi/inquiry-weave, miadi-capability://jgwill/Miadi/package/miadi-projectGiven owner/name@sha and a local clone whose origin is that repository (GitHub, or a
host's own git server), it reads the commit against its first parent and answers the
registry's rows whose defining files changed: for a package any file in its folder (a file
counts for the deepest package folder that holds it), for a CLI its bin entry point (and
for a dist/<x>.js entry its src/<x> source), for a skill its SKILL.md. A lockfile, and
a package.json whose version or dependency ranges alone moved, define nothing, so a commit
that changes only those answers skipped: "versions-only". Each answer carries an
attribution of @medicine-wheel/capabilities with revision pending, grounded in the commit
and its files. It never fetches: a clone that does not hold the commit, or whose origin names
another repository, is refused (CommitReadError). changedCapabilities is the pure half.
A record's capabilities[] is read back: capabilitySessions(address, records) lists the
sessions whose record names a capability, each with every entry its record holds for it
(entries: relation, version, evidence, in the record's order), and findCapability(parts, { sessions: true })
carries them. The app's /api/repositories/capability answers them to the write tier only.
Where a repository lives
A name like jgwill/episodes does not say where the repository is. miadi-repomap where
checks each repository the mapper names: on GitHub (with a token from GH_TOKEN,
GITHUB_TOKEN or gh auth token, so a private one is seen), else as a bare repository on
this host (/srv/git, or MIADI_HOST_GIT_ROOTS). Each reading says github, host-git,
missing (a 404 a token could have seen, and no bare repository) or unchecked. Only a
GitHub repository gets a GitHub link. list and the /repositories page set the missing
ones apart: a session record named a repository that does not exist, and the record is what
needs correcting. The package ships the readings of its last check; a host's own
(where --write <file>, read through --hosts or MIADI_REPOSITORY_HOSTS) come first.
What a version bump touches
miadi-repomap impact @miadi/hooks-interpreter --bump minorThe scan reads each package's version and the ranges it declares on other packages it
read, across repositories. impact answers what a package consumes (upstream), who
consumes it, directly and through others (downstream), and with --bump, what each direct
consumer needs: nothing (its range already reaches the new version), a wider range, or a
new release because workspace:* and workspace:^ publish the version current at the
time. In the app: GET /api/repositories/impact?package=…&bump=….
Episodes
A repository's view lists the episodes its sessions worked in, as their inventory records
name them (miadi-chronicle://<number>), linked to the chronicle page.
Configuration
| variable | default | |
|---|---|---|
| MIADI_REPOSITORY_MAPPING_HUB | none | a hub clone (…/jgwill/jgwill) or its mapping folder |
| MIADI_SESSION_INVENTORY_DIR | ~/workspace/.mino/session-inventory | the inventory records |
| MIADI_REPOSITORY_LINEAGE | none | a lineage JSONL read before the shipped rows |
| MIADI_REPOSITORY_CAPABILITIES | none | a capability JSONL read before the shipped rows |
| MIADI_REPOSITORY_HOSTS | none | a where JSONL (where --write) read before the shipped readings |
| MIADI_REPOSITORY_PACKAGES | none | a package readings JSONL (mw-repomap capabilities map --packages) read before the shipped ones |
| MIADI_HOST_GIT_ROOTS | /srv/git | where where looks for bare repositories, colon-separated |
CLI
miadi-repomap list [--hub <path>] [--inventory <dir>] [--lineage <file>] [--json]
miadi-repomap show <owner/name> [--hub <path>] [--inventory <dir>] [--lineage <file>] [--json]
miadi-repomap lineage [<owner/name>] [--lineage <file>] [--json]
miadi-repomap capabilities [<owner/name>] [--capabilities <file>] [--json]
miadi-repomap scan <clone>... [--ref <ref>] [--repository <owner/name>] [--by <who>] [--packages <file>]
miadi-repomap where [<owner/name>...] [--write <file>] [--json]
miadi-repomap impact <package> [--bump major|minor|patch] [--json]Exit codes: 0 done, 1 show: the repository is in no hub, no record and no lineage, 2 usage error.
Library
import { repositoryListing, repositoryDetail, sessionsByRepository, repositoryView } from "@miadi/relational-git-repository-mapper"sessionsByRepository, repositoryView and listRepositories are pure;
repositoryListing and repositoryDetail read the hub and the inventory.
In the Miadi app: GET /api/repositories, GET /api/repositories/{owner}/{name} (write
access, as session missions are), and the pages /repositories and
/repositories/{owner}/{name}.
