# FlowGraph

> Agent-native knowledge-graph canvas. Read and write a local graph through ONE governed,
> lock-aware write path — a human-approved atom is immutable to AI. AI proposes, you decide,
> your agents can trust it.

FlowGraph exposes an MCP server so AI agents read and write your knowledge graph through the
SAME governed path a human edit takes: every write is provenance-stamped and lock-aware. A
write to a human-approved (locked) atom — or one the agent lacks the `modify` capability for —
is REJECTED. **Mermaid diagrams are accepted as input and output**, so an LLM can hand FlowGraph
a diagram it already knows how to emit (https://flow-graph.com/tools/mermaid-to-flowgraph).

## Docs
- [API reference](https://flow-graph.com/docs/api): the human-readable API reference — MCP tools, the .fgraph data model, REST endpoints, plan tiers, and an auth quickstart.
- [api.md](https://flow-graph.com/api.md): the raw-markdown mirror of the API reference (fewer tokens than the HTML page).
- [AGENTS.md](https://flow-graph.com/AGENTS.md): the full agent guide — connect the MCP server, the write contract, every tool with read/write annotations, the .fgraph data model.
- [OpenAPI](https://flow-graph.com/openapi.json): machine-readable schema for every MCP tool + REST endpoint.
- [MCP server metadata](https://flow-graph.com/.well-known/mcp/server.json): the registry descriptor.
- [Mermaid → FlowGraph](https://flow-graph.com/tools/mermaid-to-flowgraph): paste Mermaid, get a living graph — no upload.

## MCP tools
- `list_canvases` (read): List canvases in the vault (id, name, node count).
- `get_canvas` (read): Get a canvas — its nodes and edges — by id.
- `query_graph` (read): Edge-aware query: text · facet · tags · relType · traverse(up/down). Returns matching node ids + titles.
- `flowgraph_retrieve` (read): Graph-CCR retrieval (READ-ONLY): pull exactly the sub-graph you need. Give a `query` (semantic/keyword seed → structural expansion) OR a `handle` (a retrieval handle "canvasId::nodeId" from an assembled context packet) → its original atom + neighbourhood. A STALE handle returns a recovery hint, never an error. Output is governance-aware (atoms without an AI use-as-context grant come back degraded, no body) and provenance-stamped.
- `create_canvas` (read): Create a new empty canvas; returns its id.
- `apply_graph_patch` (write): Apply a GraphPatch (ops[]) through the GOVERNED, provenance-stamped, lock-aware write path. A write to a human-approved (locked) atom — or one the AI lacks the "modify" capability for — is REJECTED.
- `refresh_codebase_map` (write): Refresh a multi-repo (fleet) codebase map: pass each repo's label + package name + declared dependencies (with the manifest line each is declared on), and this stages a governed ghost-draft that (re)builds one card per repo and the typed `depends` cross-repo edges, each carrying its manifest-line receipt. Reconciled against the target canvas — existing repo cards update, new repos add, the edge set recomputes — so a scheduled re-run is idempotent and never duplicates. A human accepts it in the Review Inbox (agents never auto-apply). Use it as the cron/agent codebase-refresh recipe.
- `get_canvas_digest` (read): Read a canvas as an FDG digest (READ-ONLY): the anchored knowledge grammar the in-app AI reads and writes. Every card, section, entry and group carries a short anchor ([c3], [c3.f2], [c3.f2.i4], [g1]) you cite when you write back with `submit_knowledge_draft`. `nodeIds` focuses the read (those cards + their neighbours render in FULL, the rest as an outline); `hops` widens that full-fidelity ring; `budget` caps the characters (an honest tail line says what was withheld — never a silent truncation). Returns the digest text, the anchor→atom map, per-card fidelity, stats, and a `digestId` — pass that back to `submit_knowledge_draft` so your anchors mean the atoms you actually read. The cheap way to orient before writing; complements `flowgraph_retrieve`.
- `submit_knowledge_draft` (write): WRITE KNOWLEDGE, NOT OPS — the preferred way to write anything content-bearing. Submit a draft in FDG (the markdown grammar `get_canvas_digest` speaks) and a DETERMINISTIC compiler turns it into a GraphPatch applied through the same governed, lock-aware, provenance-stamped path as every other write; a locked atom is refused. `mode:"apply"` (default) writes it; `mode:"stage"` lands it as a Review-Inbox ghost-draft for a human to accept. On ANY compile or validation problem NOTHING is written — you get indexed errors[], every dropped block with its line and reason, and a fix hint, so you can correct and resubmit. Returns applied/newCards/anchorMap/dropped/depth/questions/suggestions, so your [anchors] stay addressable and you can relay the AI's questions or chain its suggested next moves. `apply_graph_patch` remains for surgical, programmatic ops.
- `add_card` (write): Convenience: add one card to a canvas.
- `connect` (write): Convenience: connect two cards with a typed relationship.
- `list_skills` (read): List reusable SKILLS (promoted action items) — name, the card/canvas they live on, their inner-canvas id, and whether they are READY (inner canvas non-empty). The agent capability catalog.
- `list_due_reviews` (read): The ranked review agenda — scheduled reviews across the vault joined with attention state, bucket (overdue/today/week/later), blast-radius and owner. The same agenda the human sees.
- `schedule_review` (write): Propose a review date on an atom (ISO date or relative like "in 2 weeks"). A GOVERNED write: stamped provenance.kind=ai, REJECTED on human-approved (locked) atoms, surfaced for the human in the calendar / Review Inbox — agents never silently sign off.
- `reschedule_review` (write): Move an atom’s existing review to a new date WITH A REQUIRED REASON (lands in the atom’s history). Governed; rejected on locked atoms. Use to sequence a review after an upstream one resolves.
- `complete_review` (write): Propose marking a scheduled review DONE plus optional findings — as a governed write the human sees. NEVER approves or locks (only a human signs off); just records that the agent did a first-pass review.
- `list_actions` (read): EVERY action across the vault (not just promoted skills): its address 4-tuple {canvasId,nodeId,facetId,itemId}, text, binding, current test status, unmet prerequisites, and strategy. The agent’s runnable-work catalog.
- `get_action` (read): One action’s FULL contract (binding + schemas, test, inputs, loop policy, strategy) plus its recorded runs, by address 4-tuple.
- `run_action_test` (write): Run the DRY-RUN pipeline (precondition → contract-check → deterministic; no world touched, no network) against an action. Returns the full ActionRun; writes `action.test` through the governed patch and records the run in the agent ledger. It can never approve, lock, or execute live.
- `report_action_run` (write): Driver B: report a run YOU executed with your own tools — steps, verdict, artifacts, tokens/cost, and your identity. Schema-validated; recorded as ActionRun{driver:"agent"} + a RunSummary. A “live” claim is labeled AGENT-CLAIMED (never presented as app-verified execution). Requires the `execute` AI capability on the action atom — WITHOUT it the report stages as a ghost-draft for human accept. Idempotent on runId.
- `list_runs` (read): The Control-Tower read: recorded runs (app + agent) filtered by canvas / action address / verdict / driver, newest first.
- `ifc_inventory` (read): A Smart IFC model’s data-first inventory (READ): schema, element/storey/space/type counts, per-class counts, storeys, and materials — DERIVED from the parsed model (never AI-guessed). `modelId` is a registered model id OR the model’s sha256 (content identity).
- `ifc_query` (read): Run the FlowGraph IFC query grammar over a model’s element index (READ): e.g. `class:IfcDoor storey:"Level 2" Pset_DoorCommon.FireRating=EI30`. Returns matched elements (GlobalId · class · name · storey), their GlobalIds, a mini-QTO quantity summary, and honest parse warnings. Pure — no geometry, no wasm on the caller, no network.
- `ifc_element` (read): One element’s full properties/psets/quantities by GlobalId (READ), derived from the parsed model. Absent properties are honestly absent, never fabricated.
- `ifc_create_set` (write): Create a selection set on a model card (WRITE → staged for human accept). Give a `query` (a dynamic set — the query IS the set) OR explicit `globalIds` (a static snapshot). Lands as an IfcAnchor set item on the card’s model facet — never applied directly; a locked atom is refused.
- `ifc_link` (write): Link a model item (a pin/set/viewpoint) to another card with a typed relationship (WRITE → staged for human accept). A governed edge from the item’s handle → the target card; default relType `appears_in`. Never applied directly; a locked atom is refused.
- `ifc_viewpoint` (write): Save a named viewpoint on a model card (WRITE → staged for human accept): an engine-neutral IfcAnchor view item (BCF-shaped `camera` optional). Never applied directly; a locked atom is refused.
- `ifc_project` (write): Project a model’s structure INTO the graph (WRITE → staged ghost-diff for human accept): deterministic storey cards + top type-summary cards + contains/located_at edges, every atom provenance `derived`. Never applied directly; reject leaves the vault unchanged.
- `aps_translate` (write): Request an APS (Autodesk cloud) translation of a proprietary model (.rvt/.nwd/.dwg/.dgn) so it can be viewed + graphed (WRITE → staged for human accept). It NEVER translates directly: cloud translation sends bytes off-device and spends the user’s Autodesk credits, so it always stages a ghost-draft the human accepts in the app. Returns the staged request. Once translated, query it with the `ifc_*` tools.
- `aps_browse` (read): Browse Autodesk Construction Cloud / BIM360 (READ): hubs → projects → folders → items. Answers from an OPTIONAL cached browse file (`_aps-browse.json`) in the vault when present (the tool stamps source:"cached" itself, so the cache can’t forge the label); absent ⇒ an honest not-configured notice — the 3-legged OAuth session lives in the FlowGraph app, never the folder-vault MCP server, so hubs are never fabricated (charter #8).
- `object_story` (read): One object’s biography (READ): the nine spine answers in reading order — What it is · Why · Where · Part of and made of · Feeds and fed by · Who is responsible · State and history · If it fails · How we know — each with its plain answer, provenance TIER (from the model / from documents / confirmed / computed / AI guess, unconfirmed) and the RECEIPTS backing it (the record or lifecycle card, its link tier, and the element GlobalId), plus the record + lifecycle timeline. Pure projection — nothing is written. `nodeId` is the model card, `globalId` the element.
- `object_coverage` (read): One object’s coverage + ranked open questions (READ): the story-coverage score (answered / askable weight over the asked spine slots) and the OPEN questions ranked by severity (blast radius × importance × answerability), each with its honest one-line why and — when the bank can ask it in-app — the `qid` you answer with `object_answer`. A question with no `qid` (answerableInApp:false) has no in-app form yet: route it to a person with `object_route_ask`. Pure — nothing is written.
- `object_answer` (write): File an answer to one OPEN spine question (WRITE → staged for human accept). Give the `qid` from `object_coverage` (answerableInApp:true) + your `answer`. It NEVER writes a fact directly: an agent-supplied answer stages as a Review-Inbox ghost-draft with provenance kind:"ai" (labeled AI, unconfirmed at every depth — provenance never launders, docs/50 §8), which a human accepts to turn into a fact with a receipt. Refused honestly for an unknown/already-answered qid or a locked atom.
- `object_lifecycle_event` (write): Record a lifecycle event about an object (WRITE → staged for human accept): installed / inspected / replaced / commissioned … As an ordinary FACT — a small card carrying the event + a `documented_in` element receipt, so it interleaves into the SAME Story timeline + Lifeline ribbon the app shows (never a parallel surface). `validTime` = when it happened (ISO or a plain date). Staged with provenance kind:"ai", tier ai-confirmed; a human accepts it. A locked model card is refused.
- `object_route_ask` (write): Route ONE open question about an object to the person who knows it (WRITE → staged for human accept). It NEVER sends directly: the recipient link + email ride the app’s authenticated session (the /s/* rails), which the folder-vault MCP server does not hold — so the routed ask stages as a ghost-draft {audience, question, object} the human sends from the app (the aps_translate pattern). Use it for a high-severity question `object_coverage` reports as answerableInApp:false. Returns the staged request.

## Notes
- Honest expectations (docs/31 §P5b): `llms.txt` is near-useless for search ranking (~97% of such files get zero requests); it exists to serve docs-navigating coding agents, and it cost an hour. We ship it as a cheap option, not a growth plan.
