{"id":"f125174c-5a4b-48ec-9d65-6bc6decc782e","slug":"graphcompose-ai-flow","kind":"skill","name":"graphcompose-ai-flow","summary":"Installable AI harness for Claude Code and Codex that turns document references into maintainable GraphCompose Java templates with deterministic rendering, visual verification, revisions, and document","owner":"DemchaAV","repoUrl":"https://github.com/DemchaAV/graphcompose-ai-flow","license":"MIT","licenseTier":"permissive","trust":"community","stars":4,"match":null,"fewStars":true,"format":"skill","createdAt":"2026-05-18T09:46:48.000Z","addedAt":"2026-10-21T17:24:01.219Z","logoUrl":"https://avatars.githubusercontent.com/u/132658418?u=cd53e3db1b5f31a86726752d9b61ef826b3abc30&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["files-documents","developer-tools"],"tags":["agent-workflow","ai-agents","ai-workflow","developer-tools","document-generation","document-layout","java","llm"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T00:59:15.349Z","sample":false,"url":"https://conduits.dev/tools/graphcompose-ai-flow","language":"JavaScript","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# GraphCompose AI Flow\n\n[![ci](https://github.com/DemchaAV/graphcompose-ai-flow/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/DemchaAV/graphcompose-ai-flow/actions/workflows/ci.yml)\n\nInstall a GraphCompose harness into your coding agent. Drop in a\ndocument reference. Ask Claude Code, Codex or Gemini CLI to recreate it.\nThe agent generates, renders, compares and iterates until the template is\nready for your approval.\n\n```text\nCreate a GraphCompose CV template from resume.png\n```\n\nThe output is not a drawing that happens to match one screenshot. It is\na maintainable Java template built from semantic GraphCompose primitives\n— sections, rows, weights, anchors — with the content in a JSON data\nfile, the assets resolved and recorded, and every revision kept.\n\nhttps://github.com/user-attachments/assets/881eebc2-779f-4518-bc61-4dcbef6022c3\n\n*AI doesn't draw PDFs. It compiles them. — also [on YouTube](https://www.youtube.com/watch?v=v61r7uecA00) in full HD.*\n\n---\n\n## Install\n\n### Claude Code\n\n```text\n/plugin marketplace add DemchaAV/graphcompose-ai-flow\n/plugin install graphcompose-flow@graphcompose\n```\n\nThen, once, **inside the installed plugin** — Claude Code puts it under\n`~/.claude/plugins/cache/graphcompose/graphcompose-flow/<version>/`:\n\n```bash\ncd ~/.claude/plugins/cache/graphcompose/graphcompose-flow/<version>\nnpm run setup\n```\n\nTwo of the tools are TypeScript compiled into `dist/`, which is not\ncommitted, so a fresh install has no build output; until setup has run,\nthose two exit with code 69 and say so. Every `/plugin update` lands a\nnew `<version>` directory, so run it again after updating — or let the\nfirst `preflight` of a run do it, which it will. Full instructions and\ntroubleshooting: [`docs/plugin-installation.md`](docs/plugin-installation.md).\n\n### Codex\n\n```bash\ngit clone https://github.com/DemchaAV/graphcompose-ai-flow\ncd graphcompose-ai-flow\nnpm run setup\nnode adapters/codex/install.mjs\n```\n\nThat copies the runtime to `~/.codex/graphcompose-flow/<version>/` and\ninstalls four skills pointing into it, so **the clone is not needed\nafterwards** — move it, rename it or delete it and the skills keep\nworking. See [`adapters/codex/README.md`](adapters/codex/README.md).\n\n### Gemini CLI\n\n```bash\ngit clone https://github.com/DemchaAV/graphcompose-ai-flow\ncd graphcompose-ai-flow\nnpm run setup\nnode adapters/gemini/install.mjs\n```\n\nGemini has extensions rather than plugins, so that writes one to\n`~/.gemini/extensions/graphcompose-flow/` — four slash commands, the\nworkflow skill, the telemetry hooks and the runtime inside it — and the\nclone is not needed afterwards either. Restart Gemini CLI, then\n`gemini extensions list`. See\n[`adapters/gemini/README.md`](adapters/gemini/README.md).\n\nYou need Node 20+, Java 21+, Maven and ImageMagick, plus a Java project\nthat pins GraphCompose — the version in *your* build file decides which\nskill pack the agent authors against.\n\n**Never done any of this before?** Start with\n[`docs/getting-started-from-zero.md`](docs/getting-started-from-zero.md):\nwhich agent to pick, every tool with its download and its check, the\nfirst template step by step, and what each error means.\n\n### Sixty seconds, end to end\n\nOpen your Java project — the one whose `pom.xml` or `build.gradle` pins\n`io.github.demchaav:graph-compose` — in Claude Code, and:\n\n```text\n1.  node scripts/preflight.mjs --project-dir .        # version, pack, tools; builds what is unbuilt\n2.  node scripts/init-workspace.mjs --project-dir . --project my-invoice\n3.  drop the reference in the chat and say: \"Create a GraphCompose invoice template from this\"\n```\n\nThe workspace step matters more than it looks: without it the work lands\ninside the plugin install, which is replaced on the next update. From\nthere the skill runs the loop — analyse, author, render, compare, fix one\ncause, repeat — and stops at `READY_FOR_APPROVAL` with the paths to\n`output.pdf` and `output.png`. Say \"approve\" when it is right, and the\nbundle lands under `graphcompose-flow/templates/`.\n\n### Keep the document open while it works\n\nEvery render rewrites `current.pdf` next to the project's\n`template-project.json`, so one open window follows the whole run — you\nwatch the layout arrive instead of hunting for the newest file under\n`revisions/`. `current-debug.pdf` beside it is the same page with layout\nguides drawn on.\n\nThat only works in a viewer which reloads a file when it changes **and\ndoes not hold it open**. A viewer that keeps a lock on the PDF makes the\nnext render fail, which reads as a harness bug and is not one. On Windows\nthe one to use is [SumatraPDF](https://www.sumatrapdfreader.org/) — free,\nopen source, reloads on change, and lets go of the file. On macOS and\nLinux, Preview and Evince both reload in place.\n\nOpen it once, at the start, and leave it there.\n\n## Use\n\nOpen your Java project in the agent, give it the reference, and say what\nyou want. The skills fire from the words, so no command is needed:\n\n| You say | What happens |\n|---|---|\n| \"An invoice like the one we did before\" | the catalog of published templates is checked **first** — a match is a file copy into your project, not the loop |\n| \"Create this in GraphCompose\" (+ a screenshot) | analyse → architecture → assets → code → compile → render → diff → fix the largest mismatch → repeat |\n| \"Make the sidebar wider\" | a new revision under the narrowest scope that fits, gated against the right baseline |\n| \"What's still different?\" | a measured verdict and a ranked mismatch list, without changing anything |\n| \"approve\" | DRAFT → APPROVED, the previous approved superseded, the bundle published |\n\nReuse is checked before reconstruction because the two cost different\norders of magnitude. `node scripts/templates.mjs` lists what has already\nbeen published and `inspect <id>` says how to use it;\n`node scripts/use-template.mjs <id> --target <java-project>` copies the\nsources, assets and data in, or `--new-project <dir>` stands up a\nrunnable project from scratch. A published bundle carries no dependency\non this harness — it is Java, a JSON data file and a pom.\n\nSee [`docs/demo.md`](docs/demo.md) for a real transcript of the\ndeterministic half — version resolution, workspace creation, the chain,\nthe loop gate.\n\n## What it produces\n\nTwo runs against the current harness. The middle column is what **one\nrequest** produced — the reference, the sentence \"create this\", and no\nfurther input. The right column is after the corrections.\n\nThat split is the thing worth judging. A first render is never right; the\nquestion is how close one request gets, and what it costs to close the\nrest.\n\n### The whole loop, as it actually ran\n\nThree runs on 2.2.0, recorded revision by revision. The left panel is the\nreference; the right is what the harness rendered; the rail underneath is\nevery revision it took to get there. Nothing in either frame is\nregenerated imagery — each step is the render that revision actually\nproduced.\n\n![Northpoint invoice: one reference, twelve recorded revisions](assets/readme/v0.6/invoice-revision-flow.gif)\n\n**Invoice — 12 revisions, 113 minutes.** The first two did not compile,\nwhich is the point of recording them: `revision-001` and `revision-002`\nare FAILED and still on disk, with what broke and what was tried. The\nlast two were plain sentences with no instructions attached — *\"пропали\nразделители почему то\"* (the dividers disappeared), then a note that the\nSVG logo aligned left where the PNG did not. Approved at `revision-012`.\n\n![Professional sidebar CV: one reference, ten recorded revisions](assets/readme/v0.6/sidebar-cv-revision-flow.gif)\n\n**CV — 10 revisions, 120 minutes**, from a screenshot and the sentence\n\"Create this screenshot as a GraphCompose template.\" The corrections in\nthe second half are the ones worth reading: initials that must derive\nfrom the name rather than be hardcoded, a LinkedIn href that has to apply\nto the icon as well as the text, a timeline rail that should not run\nabove its first marker. Approved at `revision-010`.\n\n![Charcoal and gold CV: one reference, nine recorded revisions](assets/readme/v0.6/charcoal-gold-cv-revision-flow.gif)\n\n**Charcoal and gold CV — 9 revisions, and the ninth was one sentence.**\nThe loop declared itself ready at `revision-008`, after seven passes that\neach named one thing and fixed it: calibrate the type scale against the\nfirst render, calibrate the vertical rhythm against the measured line\nboxes, drop the main column's uniform 9px offset, seat the skill bullets\nin their own column. Then one sentence closed it — *\"Кольцо таймлайна\nдолжно закрывать рельс, а не пропускать его сквозь себя\"* (the timeline\nring should close over the rail, not let it pass through). Approved at\n`revision-009`.\n\nNo duration is quoted for that one. The session stayed open across a\nlong gap between `revision-003` and `revision-004`, so the telemetry\nmeasures the window rather than the work, and a number that measures\nthe wrong thing is worse than no number.\n\nAll three were published as standalone bundles — template, typed spec,\ndata JSON, assets, previews — which is what the harness exists to\nproduce. The document is Java you can read and change; the content is a\nJSON file next to it.\n\n### Two-column CV with a photo, navy sidebar and a timeline rail\n\n| Reference | One request | After 2 corrections |\n|---|---|---|\n| ![reference](assets/readme/v0.5/navy-reference.jpg) | ![after one request](assets/readme/v0.5/navy-one-request.png) | ![final](assets/readme/v0.5/navy-final.png) |\n\nFive revisions on its own, then it stopped and asked. The corrections\nwere about the timeline: the rail overran its markers, and a job title\ndrifted off centre. Three more revisions closed both. **8 revisions,\n77 minutes end to end.**\n\nThe interesting part is what the loop did unprompted. Twice it could not\ntell a layout fault from a painting fault, so it wrote a probe — a\nthrowaway document that renders one arrangement and measures the pixels —\nand settled it. That is how it found that a shape container paints its\nbottom margin *above* its box, and that an over-tall child is clamped to\nthe top rather than centred. Both are now\n[recorded observations](observations/README.md) with probes that\nre-confirm them, so the next run does not pay for them again.\n\n### Single-column CV with a serif headline, skill bars and icon rows\n\n| Reference | One request | After 3 corrections |\n|---|---|---|\n| ![reference](assets/readme/v0.5/serif-reference.jpg) | ![after one request](assets/readme/v0.5/serif-one-request.png) | ![final](assets/readme/v0.5/serif-final.png) |\n\nEight revisions on its own — the reference is denser: a display serif\nagainst a sans body, proportional skill bars, five icon-badged\ncertification cards, three achievement rows. Then three corrections, each\na plain sentence about what looked wrong, none of them explaining how to\nfix it:\n\n> вот только sertification и achivment разделитель вертикальный\n\nThe measured cost of that run, from the harness's own telemetry:\n\n```text\ncreate from the reference   68 min · 280.4k output · 61.0M cache read · 211 requests\nfirst correction             7 min ·  25.2k output · 16.0M cache read ·  32 requests\nsecond correction           10 min ·  36.4k output · 21.8M cache read ·  39 requests\napprove and publish          2 min ·   8.1k output ·  6.5M cache read ·  11 requests\n```\n\nA correction costs roughly a tenth of the original run. That ratio is the\none to watch, and it is why the harness measures itself rather than\nguessing — see [telemetry](scripts/telemetry/README.md) and\n[the benchmark protocol](docs/benchmarks.md).\n\n### What this does not claim\n\nNeither run was pixel-perfect from one request, and the pixel-similarity\nfigure stayed unimpressive throughout both: the references are rasterised\nin typefaces no bundled family reproduces, so glyph edges dominate the\ncomparison. What the runs show is that one request gets close enough to\ncorrect in sentences, and that correcting it is cheap. Judge the images.\n\n## How it works\n\nThe host agent supplies the model, the reasoning and the shell. This\nproject supplies the workflow, the GraphCompose knowledge and the gates.\nAnything a script can decide is decided by a script:\n\n```text\n   your words              the loop                        the gate\n   ──────────              ────────                        ────────\n   reference    →   analyse · architect · code   →   render · diff · evaluate\n                              ↑                              │\n                              └────── fix one mismatch ──────┘\n                                                             │\n                                              READY_FOR_APPROVAL / BLOCKED\n```\n\nFive things make that more than a prompt:\n\n- **The version decides the API.** `scripts/resolve-version.mjs` reads\n  your `pom.xml` or `build.gradle`, maps the line to a skill pack, and\n  stops if there is no pack — rather than authoring against an API your\n  version does not have.\n- **The gate is arithmetic.** A refactor must produce `AE == 0` against\n  its parent. A data edit may differ only in the regions it touched. The\n  metric is quoted, never paraphrased.\n- **The loop is bounded.** `scripts/iterate-status.mjs` counts the\n  iterations, the consecutive build failures and the repeats of the same\n  mismatch, and answers 0 ready / 2 revise / 3 blocked. An agent going\n  round in circles is the last thing qualified to notice it.\n- **Nothing is overwritten.** Every change opens a revision; approving\n  supersedes rather than replaces; a single component can be restored\n  from any earlier one.\n- **The geometry is measured, not guessed at.** The renderer writes\n  GraphCompose's own post-layout snapshot beside the PDF, so \"this block\n  is too far right\" is arithmetic rather than an argument about a\n  screenshot. `node scripts/layout.mjs explain <node> x` answers it with\n  the additive chain — `canvas.margin.left 0 + Sidebar.padding.left 17 +\n  Heading.padding.left 9 = 26` — naming the node that *owns* the offset\n  rather than the one that shows it. `diff` says whether a patch moved\n  only what it meant to, `doctor` says whether the geometry sits on the\n  node that owns it, and each of them will answer \"I cannot derive this\"\n  rather than produce a number it cannot support.\n\n[`docs/architecture.md`](docs/architecture.md) has the full picture,\nincluding what this project deliberately does **not** build: no LLM API\nintegration, no MCP server, no standalone runtime.\n\n## What is proven, and what is not\n\n- **Claude Code** is the host the loop was tuned on: sixteen templates —\n  invoices, proposals, CVs, a poster — carried to an approved published\n  bundle in one workspace, and every number above is from that corpus.\n- **Codex** runs the same workflow to the same standard — templates\n  carried to an approved published bundle — and the install is\n  self-contained with the clone deleted. Recommended alongside Claude Code.\n- **Gemini CLI** is packaged, and the workflow runs on it; the templates\n  it produces are noticeably weaker — more passes, more corrections, more\n  hand-finishing. That is the model behind the host, not the harness:\n  the skills and tools are identical on all three. Usable; not where to\n  start.\n- The pinned line is **GraphCompose 2.4**, and its pack is a knowledge\n  pack: API surfaces, routing and claims imported from the release\n  bundle, and no prose. How-to comes from the 2.2 pack, which `preflight`\n  names explicitly — the 2.4 allow-list still decides what exists.\n- The **2.2 pack** ships with five fixtures rendering identically to\n  their baselines; its conceptual skills stay `needs-validation` on\n  coverage — five fixtures are a subset of what fourteen skills\n  describe. Those fixtures pin `2.2.0`, so skill validation runs two\n  lines behind the pack.\n- The pixel figure never reaches zero against a rasterised reference and\n  never will; the perceptual figure beside it is provisional until it has\n  been measured against a person's judgement. Both are quoted, neither is\n  a gate — [`docs/how-similarity-is-measured.md`](docs/how-similarity-is-measured.md)\n  says exactly what each number is.\n- Scope limits: [`docs/limitations.md`](docs/limitations.md). The measured\n  baseline and what would move it: [`docs/benchmarks.md`](docs/benchmarks.md).\n\n## For agents\n\n[`AGENTS.md`](AGENTS.md) dispatches: which skill owns the task, the\nseven invariants, the commands, and where each contract is declared.\nStart there, not here.\n\n## Working on the harness itself\n\nClone it, run `npm run setup`, and read\n[`docs/quickstart.md`](docs/quickstart.md) — that is the contributor\npath, where the workspace is this repository's own `examples/` rather\nthan a user's project. `npm run verify` runs every gate CI runs.\n\n## Repository\n\n| Path | What |\n|---|---|\n| [`skills/workflows/`](skills/workflows/README.md) | the four workflow skills and their shared references |\n| [`skills/versions/`](skills/) | GraphCompose knowledge, one pack per library line |\n| [`config/pipeline.json`](config/pipeline.json) | scope → stages, gates, loop bounds, failure categories |\n| [`schemas/`](schemas/) | every on-disk contract |\n| [`tools/`](tools/) | revision manager, renderer, visual diff, asset resolver |\n| [`scripts/`](scripts/) | version resolver, workspace init, render, pipeline, loop gate, publish, verify |\n| [`examples/cv-reference/`](examples/cv-reference/) | a worked chain — revisions 001 → 009 |\n\n## License\n\n[MIT](LICENSE).\n"}