@miadi/inquiry-weave
v0.18.14
Published
Relate and sync IAIP inquiry artefacts, their GitHub issues, and miadi-chronicle episodes. Creates vessels and relations only — never inquiry content.
Readme
@miadi/inquiry-weave
Keep a question, its GitHub issue and the chronicle episode that carries it related to each other.
In the Miadi stack, work starts from a question. An inquiry artefact is a folder holding that
question and what is being learned about it; a GitHub issue is where it is discussed; an
episode is where the work around it is filed. inquiry-weave creates the issue with the gh
CLI, records the relation on both sides, syncs the artefact into the episode, and registers the
weave with the chronicle's medicine wheel. It also reads the chronicle as a catalog, answers
attention items, writes lineage between episodes, and files reviews into episodes.
Works with:
passages: births episodes (mkepisode) and turns them into stories.@miadi/episodic-memory-schema: the shapes of the catalog and manifests it builds.@miadi/attention-core/@miadi/attention-ui: show the attention items it reads and answers.
It does not depend on private host scripts or private cache folders.
Install
npm install -g @miadi/inquiry-weave passages
gh auth statuspassages owns canonical episode birth through mkepisode. inquiry-weave
owns issue/artefact/episode relation and offers a compatibility episode
scaffold for combined one-command inquiry flows.
Environment
export MIADI_CHRONICLE_ROOT=/path/to/miadi-chronicle
export MIADI_INQUIRY_DIR=/path/to/inquiry-artefacts
export MIADI_INQUIRY_GITHUB_REPO=owner/repo
export MIADI_CHRONICLE_MW_URL="${MIADI_CHRONICLE_MW_URL:-http://127.0.0.1:8040}"| Flag | Environment |
| --- | --- |
| --chronicle-root | MIADI_CHRONICLE_ROOT |
| --inquiry-root | MIADI_INQUIRY_DIR |
| --repo | MIADI_INQUIRY_GITHUB_REPO |
| --mw-url | MIADI_CHRONICLE_MW_URL |
| --stories-root | MIADI_STORIES_ROOT |
MIADI_INQUIRY_ROOT, INQUIRY_ROOT, and MIADI_INQUIRY_REPO remain fallback
aliases for older environments.
MIADI_CHRONICLE_MW_URL is the wheel variable of record and is read first
everywhere. MW_API_URL_OVERRIDE and MW_API_URL are legacy fallbacks, read
only when it is unset.
Words
- artefact: a folder on the shelf (
MIADI_INQUIRY_DIR) where research is saved. - inquiry: what an artefact pursues. It is followed in one GitHub issue,
recorded in the artefact's
.weave.yaml. - weave: make an artefact part of an episode. The episode keeps a copy under
inquiry/<artefact>/, both sides record the weave, and the wheel registers it.weave(CLI), the episode door and the room's Inquiries card all do it.relateis its first half (the records without the copy).promoteis its older name.
Open a folder as an inquiry: two issues, the weave, both pushes
cd "$MIADI_INQUIRY_DIR/ep295-a-question-261021-…"
inquiry-weave open --actions-file actions.md --actions-label enhancement --dry-run
inquiry-weave open --actions-file actions.md --actions-label enhancementopen turns a folder of documents with no issue into:
- the inquiry issue: the folder's documents as its body, titled by their
first
# heading, labelledinquiry(--labelreplaces it,--titlenames it); - the actions issue: the text of
--actions-file(its first line# <title>is the title), labelled by its type with--actions-label. Whoever read the folder writes it; this package never does. Its## Relatedsection gets the inquiry issue as its first line, and the inquiry issue gets a last line naming the actions issue. Each issue that does not already name the episode ends withWoven into miadi-chronicle://<N> (<episode folder>), and the output'swoven:line names the episode and both issues; - both recorded in the artefact's
.weave.yaml:issue(the inquiry) andrelated_issues(kind: actions).relate,status,registerand the episode door carryrelated_issuesto the episode'sinquiry/weave.yamland the wheel; - the weave through the episode door: relate, sync, register, and the chronicle
landed on
main. The episode is--episode <ref>, else the one the folder is already woven into, else the number of itsep<N>-prefix.--new-episode "<title>"mints one (--goaloptional, the issues are its references); - the folder committed (path-limited) and pushed in the shelf's own repository.
--no-landleaves both repositories as they are.
Exit 0 when both landings pushed, 1 with each owed landing named. Running it
again reuses the recorded issues and creates nothing twice. --artefact defaults
to the working directory.
Save a research report as an artefact
import { saveResearchArtefact } from "@miadi/inquiry-weave"
const saved = await saveResearchArtefact({
inquiryRoot, repo, title: "Decolonizing Data", markdown,
owner: { person_id, name }, // resolved by the caller's server, never from a request body
visibility: "private", // or "circle" with `circle`; "published" is refused
})
// saved.artefact, saved.issue_url, saved.shelf.state === "landed"Creates a folder <slug>-<YYMMDD>-<uuid> on the shelf holding report.md exactly as given,
records owner, visibility and source (kind, sha256, bytes, saved_at) in its .weave.yaml,
opens its inquiry issue (the report as body, or its opening when longer than an issue holds),
and commits and pushes the folder in the shelf's repository. The same owner saving the same
bytes gets the folder already saved. The folder is woven into an episode afterwards like any
other artefact. A .weave.yaml with no visibility reads as private (artefactVisibility).
Give an artefact its issue, before any episode
cd "$MIADI_INQUIRY_DIR/a-question"
inquiry-weave issue # --title, --body/--body-file, --repo, --dry-runCreates the GitHub issue the artefact's inquiry is followed in, in
MIADI_INQUIRY_GITHUB_REPO, and records it in the artefact's .weave.yaml with no
episode. When the artefact is later woven into an episode (the room's Inquiries
card, the door, weave or relate), the issue comes with it. An artefact whose
.weave.yaml already names its issue is left as it is. --issue owner/repo#N
records an issue that already exists. An artefact whose .hch/issue_<N>.env (left by
issue_add) names an issue is refused with that issue named, so it is recorded with
--issue rather than duplicated. --force creates another anyway.
The issue is then read and answered by the artefact alone, with no issue number:
inquiry-weave issue view # title, state, body, comments, episodes woven
inquiry-weave issue comment --body "…" # or --body-file notes.md; --dry-run| fn_github_issue.sh | inquiry-weave | record |
|---|---|---|
| issue_add "<title>" "<body>" | issue [--title] [--body] | .weave.yaml issue, issue_url |
| issue_info <id> / iuit | issue view | reads .weave.yaml |
| issue_comment <id> "<body>" | issue comment --body | the comment on GitHub |
| iut, iutg (all issues of a repo) | MCP inquiry_list_issues | the IAIP app at MIADI_INQUIRY_ISSUES_BASE |
The shell functions leave .hch/ side files that no reader treats as a record.
Create an issue and weave the current folder
From an existing inquiry artefact:
cd "$MIADI_INQUIRY_DIR/ep133-honcho-eval"
inquiry-weave inquire \
--artefact . \
--episode 133 \
--title "Honcho evaluation inquiry"This creates the issue in MIADI_INQUIRY_GITHUB_REPO, writes its identity to
.weave.yaml, writes the matching relation to
<episode>/inquiry/weave.yaml, and adds the episode backlink to AGENTS.md.
Before those writes, an unprefixed folder is renamed to
ep<episode-number>-<existing-folder-name>. The prefix is mandatory once the
episode identity is known; a destination collision stops the command.
By default, the artefact's Markdown, text, YAML, and JSON documents become the
issue body. Generated weave metadata, AGENTS.md, hidden directories, and
binary files are excluded. Use --body <text> or --body-file <path> to
override that derived body.
Create a new inquiry vessel and issue
inquiry-weave inquire \
--slug honcho-eval \
--episode 133 \
--title "Honcho evaluation inquiry"The new directory is named ep<NNN>-<slug>-<YYMMDD>-<uuid> beneath
MIADI_INQUIRY_DIR. It begins with relation metadata only; inquiry content is
written afterward by the people and practices conducting the inquiry.
Create the issue and a new episode together
Use an existing artefact:
inquiry-weave inquire \
--artefact . \
--new-episode honcho-eval-adequate-memories \
--title "Honcho evaluation inquiry"Or create the artefact vessel, issue, episode, and weave in one command:
inquiry-weave inquire \
--slug honcho-eval \
--new-episode honcho-eval-adequate-memories \
--title "Honcho evaluation inquiry"Both combined forms also sync the artefact snapshot into the new episode. When
MIADI_CHRONICLE_MW_URL (or --mw-url) is present, the command registers the episode card
and writes its .mw-registration.json receipt in the same run.
The combined form uses inquiry-weave's compatibility scaffold. For a fully
governed episode with an explicit goal and references, create it first with
mkepisode, then use inquire --episode:
mkepisode \
-n 133 \
-t "honcho eval adequate memories" \
-g "Establish adequate memories for the honcho evaluation." \
-r "owner/repo#133"Weave an issue that already exists
inquiry-weave relate \
--artefact "$MIADI_INQUIRY_DIR/ep133-honcho-eval" \
--episode 133 \
--issue owner/repo#133To weave the artefact and its already-recorded issue into a newly scaffolded episode:
inquiry-weave promote \
--artefact "$MIADI_INQUIRY_DIR/ep133-honcho-eval" \
--new-episode honcho-eval-adequate-memoriesSync, inspect, and register
inquiry-weave sync --episode 133 --all
inquiry-weave status --episode 133
inquiry-weave register --episode 133Sync is one-way from the IAIP artefact to the episode snapshot. The source artefact remains authoritative. Registration projects relation metadata to the Chronicle medicine wheel; it does not move inquiry content.
--dry-run previews mutating commands without filesystem, GitHub, or
medicine-wheel writes. --no-issue creates or relates the artefact without
opening GitHub.
Command surface
inquiry-weave open [--artefact <path>] [--episode <ref> | --new-episode <title> [--goal <text>]]
[--title <text>] [--label <a,b>]
[--actions-file <path> --actions-label <a,b> [--actions-title <t>]]
[--no-land] [--dry-run]
inquiry-weave issue [create|view|comment] [--artefact <path>] [--label <a,b>] …
inquiry-weave inquire (--episode <ref> | --new-episode <slug>)
(--artefact <path> | --slug <new-artefact-slug>)
[--title <text>] [--body <text> | --body-file <path>]
[--repo owner/repo] [--no-issue]
inquiry-weave relate --artefact <path> --episode <ref> [--issue owner/repo#N]
inquiry-weave promote --artefact <path> (--episode <ref> | --new-episode <slug>)
inquiry-weave sync (--artefact <path> [--episode <ref>] | --episode <ref> --all)
inquiry-weave status (--episode <ref> | --artefact <path>) [--json]
inquiry-weave register (--episode <ref> | --artefact <path>) [--dry-run]
inquiry-weave lineage --from <ref> --to <ref> --relation <sentence>
[--kind continues-from|relates-to] [--reverse]
inquiry-weave catalog [--series <name>] [--json]
inquiry-weave stories [--stories-root <dir>] [--json]
inquiry-weave resolve <miadi-chronicle:...> [--verify] [--json]Exit codes are 0 success, 1 operational failure, and 2 usage or identity
resolution failure.
Relation records
The artefact owns .weave.yaml; the episode owns inquiry/weave.yaml, which
also records sync hashes and counts. These files are authoritative. The
medicine wheel is their registered projection.
Chronicle attention through MCP
inquiry-weave-mcp exposes the same ATTENTION read/answer service used by the
Miadi API and passages attention answer:
chronicle_attention_list— open items across the Chronicle, optionally one episode;chronicle_attention_get— one item plus safe excerpts from episode-localdepth[]references;chronicle_attention_answer— one explicit answer, atomically written and projected.
Set MIADI_CHRONICLE_ROOT. Set MIADI_CHRONICLE_MW_URL (the legacy
MW_API_URL_OVERRIDE / MW_API_URL are read only if it is unset) to
the one Chronicle wheel. With no wheel URL, an answer still lands in the
authoritative file and the tool returns pending; it never falls back to a
repo-local wheel.
Episode lineage
inquiry-weave lineage \
--from 132 \
--to 133 \
--kind relates-to \
--relation "The evaluation carries the prior memory contract into practice." \
--reverse \
--dry-runDrop --dry-run to write both shores. The relation sentence must read
truthfully from both episode rooms.
The same edge is authored by POST /api/chronicle/episodes/{ref}/lineage, by
the MCP tool chronicle_episode_lineage, and from the Lineage card of an
episode page. The sentence is written to episode.yaml and to the wheel edge's
description. An edge the wheel already holds without words receives them on
the next authoring. MIADI_EPISODE_DOOR=http sends the MCP's episode tools
through the app at MIADI_INQUIRY_API_BASE even on a host that holds the
chronicle.
To read an episode's lineage for a page:
import { readEpisodeLineage, resolveLineage } from "@miadi/inquiry-weave"
const edges = await readEpisodeLineage(chronicleRoot, "2026-10-10-episode-551-learning-between-sessions")
// [{ kind: "related-to", label: "relates to", targetValue: "351", text, targetName, targetTitle }]
// Or, over a catalog already built:
const same = resolveLineage(entry, catalog.episodes)readEpisodeLineage reads the folder names, the one manifest asked for, and the
manifests its edges resolve to. It never builds the whole catalog, and it returns
what resolveLineage returns over that catalog. A path carried with an edge names
its folder. Otherwise a number or slug resolves only when one folder holds it. When
several do, the edge keeps its raw targetValue and lists them in candidates.
RELATION_LABELS holds the words for each kind.
Inquiry issues over MCP
inquiry_list_issues and inquiry_get_issue read the GitHub issues inquiries are
followed in from the app that serves /api/inquiry, the IAIP app. Set
MIADI_INQUIRY_ISSUES_BASE to it, for example http://127.0.0.1:9946. The episode tools
keep MIADI_INQUIRY_API_BASE, the Miadi episode door, which has no /api/inquiry. Without
it the issue tools read MIADI_INQUIRY_THREADS_BASE (the 0.16.2 name), then
MIADI_INQUIRY_API_BASE. The 0.16.2 tool names inquiry_list_threads and
inquiry_get_thread still answer, unlisted.
Reviews in an episode
A Miadi review enters an episode through the episode door (library attachEpisodeReview,
HTTP POST /api/chronicle/episodes/{ref}/reviews, MCP chronicle_episode_review). It reads
the review's public JSON from MIADI_REVIEW_BASE_URL (default
https://miadi-review-service.vercel.app), writes a reviews: entry in episode.yaml, puts the
review:<uuid> node and the chronicle:<episode> → review:<uuid> edge on the wheel, and lands.
A hold hook given by the app opens the talking circle about the review before landing, so its
note lands in the same commit. mintEpisode({ review }) births an episode from a review.
listEpisodeReviews reads both reviews: and references: miadi-review:<uuid>.
A mint dry run with a review reads it (a bad or missing review refuses), answers review: null
because nothing is attached, and adds wouldAttachReview: the version it would pin, the relation,
the node and edge ids, and what the live call would report for the ceremony.
Foundations in an episode
miadi-foundation:<slug>[/<file>][#place] names a foundation packet from @miadi/foundations;
miadi-chronicle:<episode>/foundations/<topic> names a packet an episode wrote under
foundations/<topic>/. inquiry-weave resolve miadi-foundation:<slug> prints its page on each
front, and its file when MIADI_FOUNDATIONS_ROOT holds it.
A packet enters an episode through attachEpisodeFoundation (HTTP
POST /api/chronicle/episodes/{ref}/foundations, MCP chronicle_episode_foundation). It writes a
foundations: entry in episode.yaml with the version read, puts a foundation:<slug> knowledge
node and the chronicle:<episode> → node edge on the wheel (relation grounded-by unless given),
and lands. source: "episode" holds the episode's own packet, which must already exist. The
packet lookup is the caller's (foundationLookup on the door context); without one the door reads
MIADI_FOUNDATIONS_ROOT, else GET <MIADI_WEB_URL>/api/foundations/<slug>.
listEpisodeFoundations also answers every packet the episode wrote under foundations/<topic>/
(a folder with a README.md) that its manifest does not record (declared: "folder", relation
grounded-by): an episode holds its own packets without anyone holding them by hand.
attachEpisodeFoundation with replaceRelation (HTTP PATCH) sets what the episode uses a packet
for, in the manifest and on the edge. removeEpisodeFoundation (HTTP DELETE) takes the entry and
the edge away. The packet's folder and its references: citations stay; foundations_not_held:
names the packet (<topic> or miadi-foundation:<slug>) until it is held again.
The address layer alone
@miadi/inquiry-weave/references exports the parsers, the text scanner and the markdown
directive pass (transformDirectives, linkBareReferences) with no fs, fetch or React, for a
browser bundle or another host's renderer. @miadi/reference-ui draws what it parses.
