Releases: artfusion/ccgrapher
Release list
v0.5.0 — the picture becomes evidence
The graph has always been the argument. Up to now it only travelled as a fixed-size PNG — unreadable past a handful of nodes, and useless for showing the drift between what a spec declared and what a run actually did. This release closes both gaps.
Zoomable, everywhere the picture goes
ccg render examples/research-desk.yaml -o diagram.htmlThe same hand-drawn SVG, wrapped in a self-contained page: cursor-anchored wheel zoom, drag to pan, no CDN, no server. It opens as a chat attachment or a browser tab and stays legible at any size.
The audit learns the graph, not only the capabilities
ccg trace audit already held a run against the capabilities its spec declared. It now holds the run against the spec's nodes and edges too:
NODE_NEVER_RAN— a declared node with no evidence it ran in any matched run.UNDECLARED_NODE— anode_startedfor an id the spec doesn't know.ORDER_VIOLATION— a node started before its declared predecessor finished, though the spec says it should wait. The strongest of the four: it means the graph's core promise wasn't honoured.OBSERVED_SERIALISATION— two nodes with no declared path between them that consistently never overlap across several runs. A candidate hidden edge, backed by evidence rather than a guess.
HIDDEN_EDGE stops missing cross-layer collisions
The rule used to compare nodes on the same layout rank only, on the assumption that rank meant "runs at the same time." True for ccg run and every codegen target, which both execute a rank behind a barrier — not true in general. It now compares every pair of nodes with no declared path between them, wherever they land.
Also in this release
render-excalidraw's README says how to open the file it produces (excalidraw.com, or the VS Code extension) and that edits made there don't write back to the spec.
@ccgrapher/web (private, unpublished) moves to 0.4.0 alongside this: a static export, a spec carried in the URL fragment, and a read-only viewer mode, now live at ccgrapher.artfusion.com/app.
apps/web v0.4.0 — the canvas gets a URL
The canvas has had cursor-anchored zoom and live lint since the JointJS move — the one thing it never had was a URL. This release gets it one, without a new subdomain or a server.
next buildnow produces a static export. Nothing about how the app runs changed; it has always been client-only.- A spec carried in the URL fragment (
#spec=<base64>) loads directly and switches the page into a read-only viewer: the example dropdown, file picker, and YAML textarea hide, and the repair toggle and live-run bar stay. A fragment never reaches a server log, and needs no CORS. - Deployed at ccgrapher.artfusion.com/app — a subdirectory of the existing marketing site,
basePath: "/app"doing the rewriting. A two-level subdomain turned out not to be provisionable on the current host; this reuses infrastructure already proven to work.
No published @ccgrapher/* package changed — this app stays private and unpublished.
apps/web v0.3.0 — the canvas learns to move under you
Not a package release. Nothing under packages/* changed since v0.4.0 beyond
test files, so the npm train stays at 0.4.0 and this tag, like apps-web-v0.2.0
before it, sits outside it. It marks what the canvas gained since the JointJS
migration.
What's new
Mouse-wheel zoom and drag-to-pan. The canvas stopped being a fixed window.
Scroll to zoom around the pointer, drag empty space to pan. Nodes still cannot
be moved by hand, and that is not an omission: the picture remains a consequence
of the in:/out: declarations.
Open a spec file directly into the canvas. Point the editor at a spec on
disk and it loads straight in, rather than starting from the built-in example
and pasting over it.
Also
jsdom smoke tests for the editor, and direct coverage for the graph model, so
the two bugs the JointJS migration surfaced now have the kind of tests that
would have caught them.
Upgrading
Nothing to change for the CLI or any published package; none of them moved.
pnpm --filter @ccgrapher/web devThere is now a CHANGELOG
covering every release to date.
apps/web v0.2.0 — the canvas moves to JointJS
Not a package release — nothing under packages/* changed, and apps/web stays private and
unpublished, so this tag sits outside the npm-publishable vX.Y.Z train. It marks a real
milestone for the canvas on its own.
What moved
The web canvas was React Flow. It's JointJS now — same picture, same overlays (run state, heat,
capability), same lint findings. core, lint and layout haven't changed, so nothing here
touches what the CLI computes or reports.
What's new
Every node's declared in:/out: fields are real ports now, not one anonymous handle per node.
Drag a link from one port to another and the edge lints as you draw — the field it carries is
written straight back into the YAML pane, and a spec problem it creates (a fan-in with no
expects guard, say) shows up in the findings list immediately, the same way editing the YAML
directly always has.
Dragging a node does nothing to the spec. The picture is a consequence of the in:/out:
declarations, never something a human moved — only a connection is a real edit.
Two bugs the migration surfaced, not two features
Both were caught live, with a real drag, not by a type checker:
- A brand-new link's
source/targetare set at construction, which JointJS/Backbone doesn't
treat as a "change" — so the first pass at wiring this up watched for change events and never
saw a new connection land. Fixed by also watching for the link itself being added. - Watching that event synchronously turned up a second bug: the canvas seeds its graph one
cell at a time on load, and reading the link list from inside the very firstaddevent in
that burst caught the graph mid-seed — briefly wipingedges:in the YAML pane on every fresh
load. Fixed by batching the read to run once the seed has actually settled.
Upgrading
Nothing to change if you're using the CLI, or any of the published packages — this release
doesn't touch them.
pnpm --filter @ccgrapher/web devv0.4.0 — the runtime stops being opaque
A workflow spec has always said what each step reads and writes. It has never said what the step needed to exist around it — an MCP server, a skill, a plugin, another agent. When one of those is missing, a run does not stop. It quietly does something worse and reports success.
This release makes that auditable.
Declaring
A node can say what it depends on:
- id: research
kind: worker
uses: ["mcp:search/query", "skill:house-style"]Opaque, namespaced ids. What counts as a capability belongs to the runtime, not to the schema.
Reporting
Three new trace events, additive within v: 1. capability_available and capability_lost are run-scoped, because whether a thing exists is a fact about the environment rather than about any one step. capability_invoked carries an optional node: a runner knows which node called, an adapter watching a live session knows only that a tool was used, and a contract demanding a node id would have excluded the second while calling itself general.
ccg run emits them natively. @ccgrapher/adapter-claude-code is new, and turns a Claude Code session into the same trace through its hooks, so the tools an agent actually reached for become a run you can serve, read and audit like any other.
Auditing
ccg trace audit runs/my-run.jsonl --spec spec.yamlCAPABILITY_GAP when a node ran while something it declares was reported gone. UNUSED_CAPABILITY when a node ran and never reached for what it declares. UNDECLARED_CAPABILITY when something was used that was never declared. Exit 0 clean or warnings, 1 on an error, 2 on bad usage. The six lint rules stay six: an audit finding needs a run as well as a spec.
What it refuses to say
Two rules run through all of it, and they are the point rather than a detail.
A capability nothing reported on is unknown, never missing. A gap needs positive evidence that something went away. And UNUSED_CAPABILITY stays quiet unless the run reported at least one invocation somewhere, because a producer that never reports them has not told you a declaration went unused, it has told you nothing.
An audit is only honest about the run it was given. A trace records which spec it came from. One naming a different spec is left out and reported; a file where every run names a different spec is bad usage rather than a report. Two unrelated workflows need only share a node name to appear to disagree, and that finding would be confident, specific and false. A run that recorded no spec at all is audited anyway: it made no claim to contradict, and refusing it would be the same error pointed the other way.
Also
The SSE transport now forwards event types it has never heard of, with their sequence numbers intact, so they survive a reconnect. The contract promised additive-only within v: 1 and the transport quietly broke that promise one layer below where it was made.
Upgrading
Nothing to change. uses: is optional, the events are additive, and a spec carrying capabilities still parses under older tools, which strip the field. An older reader folds the new events as no update.
npx @ccgrapher/cli lint <spec.yaml>v0.3.1 — a mistyped flag stops looking like a failing check
A patch release with one fix in it, worth shipping on its own.
Fixed
An unknown flag printed a Node stack trace and exited 1. Exit 1 is the code that means the workflow has lint errors, so a typo in a flag was indistinguishable from a failing check to anything reading exit codes, which is precisely what CI does. The unknown-command path exited 2 correctly all along, so the two halves of the same documented contract disagreed with each other.
$ ccg lint plan.yaml --nope
ccg lint: unknown option '--nope'
Run `ccg --help` for usage.
Exit 2, matching the README, and no stack trace. Every command parses through the same wrapper now, so all of them agree rather than one of them being fixed.
--help after a subcommand prints usage and exits 0 instead of being rejected. Asking for help is never bad usage.
Upgrading
Nothing to change. Same API, same flags, same output on every path that already worked.
npx @ccgrapher/cli lint <spec.yaml>v0.3.0 — retro, dataflow edge recovery, and the trace contract
Eleven packages move together. @ccgrapher/web stays private and unpublished.
What is new
ccg retro <owner/repo> rebuilds the as-merged workflow from a repository pull request history, with edges only where two changes touched the same files. Point it at a repository and it draws what the work actually was, without anyone writing a spec. The first live run on this repository went from fifteen layers to five.
@ccgrapher/trace is a new package: a versioned JSONL event contract and the reducer that folds it back into state. It is additive-only within v: 1, and treated as a compatibility surface rather than an internal detail.
@ccgrapher/runner executes a graph. ccg run walks a spec and writes a trace, and ccg serve streams that trace over SSE in a way that survives a dropped connection.
Ingest now recovers edges from dataflow rather than variable names, which is the difference between a round-trip validator for our own output and something you can point at a stranger's code. It also warns when nodes parse but no dependency does, instead of quietly drawing an edgeless graph.
One expects rule across three runtimes. There were three implementations and two different comparisons. The guard is now a floor everywhere.
Fixed
A release path that would have shipped ten of eleven packages without saying so. tools/publish.sh kept a hand-maintained list, and a new package missing from it published nothing, printed a success, and surfaced later as an install that could not resolve. The script now refuses to run while any non-private workspace package is absent from the list.
Install
npx @ccgrapher/cli lint <spec.yaml>
npx @ccgrapher/cli retro your-org/your-repo --lintKnown issue
--help after a subcommand, as in ccg retro --help, exits 1 with a Node stack trace instead of printing usage. Use ccg --help for now.
v0.2.0 — plan, and a Claude Code skill
First public release. A linter for agent workflows, and a Claude Code skill that
makes an agent apply it to its own plans before executing them.
The skill
git clone https://github.com/artfusion/ccgrapher.git
ln -s "$PWD/ccgrapher/skills/parallel-plan" ~/.claude/skills/parallel-planBefore executing a plan of five steps or more, the agent checks which steps
actually depend on each other and runs the independent ones concurrently.
ccg plan
lint says what is wrong with a workflow; plan says how to run it.
wave 1 scope
wave 2 ×6 together pr_hotfix, pr_landing, pr_new_site, pr_pricing, pr_byok, pr_compare
wave 3 ×3 together pr_credits, pr_copy, pr_links
wave 4 ci
wave 5 release
5 waves for 12 steps — 7 fewer than doing them one at a time
Without --fix it reports the shape as written and says how much of that is
fake, so the number is never quietly flattering. --json for tooling.
Also in this release
- Six lint rules with a two-pass repair pipeline — repairs repoint to the
nearest supplier rather than deleting, which would leave a step starting
before its real dependency. - Four render targets: hand-drawn SVG, Mermaid, Excalidraw, plus the web canvas.
- Codegen for Claude Code workflows, plain TypeScript and LangGraph.
ingest— ts-morph reads existing orchestration code back into a spec.
Round-trip is lossless and asserted for every fixture.examples/release-session.yaml— nine pull requests shipped one after
another. Six were never waiting on anything.
Install
npx @ccgrapher/cli lint your-workflow.yaml250 tests, CI on Node 22 and 24. Apache-2.0.
Note: 0.1.0 on npm is deprecated and broken — it shipped with the
workspace: protocol unresolved. Use 0.2.0.