New:Socket for Asana Is Now Available.Learn more
Get Started

@tpypan/graphcraft

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tpypan/graphcraft - npm Package Compare versions

Comparing version
0.1.1
to
0.1.5
+17
.agents/plugins/marketplace.json
{
"name": "graphcraft",
"interface": { "displayName": "Graphcraft" },
"plugins": [
{
"name": "graphcraft",
"source": {
"source": "npm",
"package": "@tpypan/graphcraft",
"version": "0.1.5",
"registry": "https://registry.npmjs.org"
},
"policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" },
"category": "Productivity"
}
]
}
{
"name": "graphcraft",
"owner": { "name": "Tony Pan" },
"description": "Durable, inspectable execution for long-running coding-agent workflows.",
"plugins": [
{
"name": "graphcraft",
"displayName": "Graphcraft",
"source": {
"source": "npm",
"package": "@tpypan/graphcraft",
"version": "0.1.5",
"registry": "https://registry.npmjs.org"
},
"description": "Progress-aware execution for durable coding agents.",
"author": { "name": "Tony Pan", "url": "https://github.com/tpypan" },
"homepage": "https://github.com/tpypan/graphcraft",
"repository": "https://github.com/tpypan/graphcraft",
"license": "MIT",
"keywords": ["ai-agents", "coding-agents", "graph-engineering"],
"category": "productivity"
}
]
}
{
"name": "graphcraft",
"version": "0.1.5",
"description": "Progress-aware execution for durable coding agents.",
"author": { "name": "Tony Pan", "url": "https://github.com/tpypan" },
"homepage": "https://github.com/tpypan/graphcraft",
"repository": "https://github.com/tpypan/graphcraft",
"license": "MIT",
"keywords": ["ai-agents", "coding-agents", "graph-engineering"]
}
{
"name": "graphcraft",
"version": "0.1.5",
"description": "Progress-aware execution for long-running coding agents.",
"author": { "name": "Tony Pan", "url": "https://github.com/tpypan" },
"homepage": "https://github.com/tpypan/graphcraft",
"repository": "https://github.com/tpypan/graphcraft",
"license": "MIT",
"mcpServers": { "graphcraft": { "command": "node", "args": ["dist/mcp.mjs"], "cwd": "." } },
"keywords": ["ai-agents", "coding-agents", "graph-engineering", "long-running-agents"],
"interface": {
"displayName": "Graphcraft",
"shortDescription": "Keep coding agents making verified progress.",
"longDescription": "Graphcraft is a progress-aware execution layer for durable, grounded, token-efficient coding-agent workflows.",
"developerName": "Tony Pan",
"category": "Productivity",
"capabilities": ["Write"],
"defaultPrompt": ["Use Graphcraft for this long-running repository task."]
}
}
{
"mcpServers": {
"graphcraft": { "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp.mjs"] }
}
}
{
"schemaVersion": 2,
"id": "stable-v1",
"version": 4,
"description": "Versioned local corpus for matched Codex and Claude baseline-versus-Graphcraft trials.",
"tasks": [
{
"id": "bug-empty-input",
"family": "bug",
"task": "Fix normalizeName so empty input returns an empty string, preserve non-empty trimming, add or update regression coverage, and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-bug-empty-input\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"src.js": "export function normalizeName(value) { return value.trim() || 'unknown'; }\n",
"verify.mjs": "import { normalizeName } from './src.js'; if (normalizeName('') !== '' || normalizeName(' Ada ') !== 'Ada') process.exit(1);\n",
"score.mjs": "import { normalizeName } from './src.js'; if (normalizeName('') !== '' || normalizeName(' Ada ') !== 'Ada') process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "contains", "path": "src.js", "value": "return value.trim()" },
{ "kind": "not_contains", "path": "src.js", "value": "unknown" }
],
"repetitions": 3
},
{
"id": "bug-inclusive-range",
"family": "bug",
"task": "Fix range so it includes the requested end value without changing its start behavior, add regression coverage, and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-bug-inclusive-range\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"range.js": "export function range(start, end) { return Array.from({ length: end - start }, (_, index) => start + index); }\n",
"verify.mjs": "import { range } from './range.js'; if (JSON.stringify(range(2, 4)) !== '[2,3,4]') process.exit(1);\n",
"score.mjs": "import { range } from './range.js'; if (JSON.stringify(range(2, 4)) !== '[2,3,4]') process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [{ "kind": "contains", "path": "range.js", "value": "end - start + 1" }],
"repetitions": 3
},
{
"id": "feature-uppercase-slug",
"family": "feature",
"task": "Add an exported upperSlug helper that trims input, replaces whitespace with hyphens, uppercases the result, and passes the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-feature-uppercase-slug\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"slug.js": "export function slug(value) { return value.trim().replace(/\\s+/g, '-').toLowerCase(); }\n",
"verify.mjs": "import { upperSlug } from './slug.js'; if (upperSlug(' hello world ') !== 'HELLO-WORLD') process.exit(1);\n",
"score.mjs": "import { upperSlug } from './slug.js'; if (upperSlug(' hello world ') !== 'HELLO-WORLD') process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "contains", "path": "slug.js", "value": "export function upperSlug" },
{ "kind": "contains", "path": "slug.js", "value": "toUpperCase" }
],
"repetitions": 3
},
{
"id": "feature-summary-report",
"family": "feature",
"task": "Add report.js with an exported summarize function returning count and total for numeric inputs, reject non-numeric values, and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-feature-summary-report\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"index.js": "export const version = 1;\n",
"verify.mjs": "import { summarize } from './report.js'; const value = summarize([2,3,5]); if (value.count !== 3 || value.total !== 10) process.exit(1); let rejected = false; try { summarize([1,'x']); } catch { rejected = true; } if (!rejected) process.exit(1);\n",
"score.mjs": "import { summarize } from './report.js'; const value = summarize([2,3,5]); if (value.count !== 3 || value.total !== 10) process.exit(1); let rejected = false; try { summarize([1,'x']); } catch { rejected = true; } if (!rejected) process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "exists", "path": "report.js" },
{ "kind": "contains", "path": "report.js", "value": "count" },
{ "kind": "contains", "path": "report.js", "value": "total" }
],
"repetitions": 3
},
{
"id": "migration-client-v3",
"family": "migration",
"task": "Migrate every createClientV2 use to createClientV3, remove the v2 export, preserve behavior, and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-migration-client-v3\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"client.js": "export const createClientV2 = () => ({ version: 2 }); export const createClientV3 = () => ({ version: 3 });\n",
"app.js": "import { createClientV2 } from './client.js'; export const client = createClientV2();\n",
"verify.mjs": "const app = await import('./app.js'); const source = await import('node:fs/promises').then(fs => fs.readFile('client.js','utf8')); if (app.client.version !== 3 || source.includes('createClientV2')) process.exit(1);\n",
"score.mjs": "const app = await import('./app.js'); const source = await import('node:fs/promises').then(fs => fs.readFile('client.js','utf8')); if (app.client.version !== 3 || source.includes('createClientV2')) process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "contains", "path": "app.js", "value": "createClientV3" },
{ "kind": "not_contains", "path": "client.js", "value": "createClientV2" }
],
"repetitions": 3
},
{
"id": "migration-timeout-key",
"family": "migration",
"task": "Migrate the timeoutSeconds configuration to timeoutMs everywhere, convert the value correctly, remove the old key, and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-migration-timeout-key\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"config.json": "{\"timeoutSeconds\":5}\n",
"config.js": "import data from './config.json' with { type: 'json' }; export const timeout = data.timeoutSeconds * 1000;\n",
"verify.mjs": "import { timeout } from './config.js'; const data = JSON.parse(await import('node:fs/promises').then(fs => fs.readFile('config.json','utf8'))); if (timeout !== 5000 || data.timeoutMs !== 5000 || 'timeoutSeconds' in data) process.exit(1);\n",
"score.mjs": "import { timeout } from './config.js'; const data = JSON.parse(await import('node:fs/promises').then(fs => fs.readFile('config.json','utf8'))); if (timeout !== 5000 || data.timeoutMs !== 5000 || 'timeoutSeconds' in data) process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "contains", "path": "config.json", "value": "timeoutMs" },
{ "kind": "not_contains", "path": "config.json", "value": "timeoutSeconds" },
{ "kind": "contains", "path": "config.js", "value": "timeoutMs" }
],
"repetitions": 3
},
{
"id": "refactor-shared-clamp",
"family": "refactor",
"task": "Refactor the duplicated clamp logic into one shared exported helper without changing behavior and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-refactor-shared-clamp\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"values.js": "export function volume(value) { return Math.max(0, Math.min(100, value)); } export function brightness(value) { return Math.max(0, Math.min(100, value)); }\n",
"verify.mjs": "import { volume, brightness, clamp } from './values.js'; if (volume(120) !== 100 || brightness(-2) !== 0 || clamp(40) !== 40) process.exit(1);\n",
"score.mjs": "import { volume, brightness, clamp } from './values.js'; if (volume(120) !== 100 || brightness(-2) !== 0 || clamp(40) !== 40) process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "contains", "path": "values.js", "value": "export function clamp" },
{ "kind": "contains", "path": "values.js", "value": "return clamp(value)" }
],
"repetitions": 3
},
{
"id": "audit-api-boundary",
"family": "audit",
"task": "Audit the API boundary for validation, error handling, and missing tests; return a read-only report with Findings, Evidence, and Unknowns grounded in api.js; run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-audit-api-boundary\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"api.js": "export async function handle(input) { return JSON.parse(input); }\n",
"verify.mjs": "import { handle } from './api.js'; const value = await handle('{\"ok\":true}'); if (value.ok !== true) process.exit(1);\n",
"score.mjs": "import { handle } from './api.js'; const value = await handle('{\"ok\":true}'); if (value.ok !== true) process.exit(1); let malformed = false; try { await handle('{'); } catch (error) { malformed = error instanceof SyntaxError; } const nonStringResult = await handle(null); if (!malformed || nonStringResult !== null) process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "summary_contains", "value": "Findings" },
{ "kind": "summary_contains", "value": "Evidence" },
{ "kind": "summary_contains", "value": "Unknowns" },
{ "kind": "summary_contains", "value": "api.js" },
{ "kind": "summary_contains", "value": "JSON.parse" },
{ "kind": "summary_contains", "value": "SyntaxError" },
{ "kind": "summary_contains", "value": "null" },
{ "kind": "summary_contains", "value": "non-string" },
{
"kind": "equals",
"path": "api.js",
"value": "export async function handle(input) { return JSON.parse(input); }\n"
}
],
"repetitions": 3
},
{
"id": "pr-repair-email-validation",
"family": "pr_repair",
"task": "Address review feedback by making parseEmail reject values without exactly one @ separator, preserve trimming and lowercase normalization, and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-pr-repair-email-validation\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"email.js": "export function parseEmail(value) { return value.trim().toLowerCase(); }\n",
"REVIEW.md": "Review: parseEmail currently accepts malformed addresses. Require exactly one @ separator.\n",
"verify.mjs": "import { parseEmail } from './email.js'; if (parseEmail(' A@B.COM ') !== 'a@b.com') process.exit(1); for (const bad of ['abc','a@@b']) { let rejected = false; try { parseEmail(bad); } catch { rejected = true; } if (!rejected) process.exit(1); }\n",
"score.mjs": "import { parseEmail } from './email.js'; if (parseEmail(' A@B.COM ') !== 'a@b.com') process.exit(1); for (const bad of ['abc','a@@b']) { let rejected = false; try { parseEmail(bad); } catch { rejected = true; } if (!rejected) process.exit(1); }\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "contains", "path": "email.js", "value": "split" },
{ "kind": "contains", "path": "email.js", "value": "throw" }
],
"repetitions": 3
},
{
"id": "pr-repair-null-owner",
"family": "pr_repair",
"task": "Address review feedback by making ownerLabel handle a null owner as Unassigned while preserving named-owner output, add regression coverage, and run the declared checks.",
"finishLine": "local_verified",
"initialFiles": {
"package.json": "{\"name\":\"benchmark-pr-repair-null-owner\",\"private\":true,\"type\":\"module\",\"scripts\":{\"test\":\"node verify.mjs\"}}\n",
"owner.js": "export function ownerLabel(owner) { return `Owner: ${owner.name}`; }\n",
"REVIEW.md": "Review: owner can be null for imported records. Render Unassigned instead of throwing.\n",
"verify.mjs": "import { ownerLabel } from './owner.js'; if (ownerLabel(null) !== 'Unassigned' || ownerLabel({name:'Ada'}) !== 'Owner: Ada') process.exit(1);\n",
"score.mjs": "import { ownerLabel } from './owner.js'; if (ownerLabel(null) !== 'Unassigned' || ownerLabel({name:'Ada'}) !== 'Owner: Ada') process.exit(1);\n"
},
"checks": [{ "command": "node", "scorerPath": "score.mjs" }],
"acceptance": [
{ "kind": "contains", "path": "owner.js", "value": "Unassigned" },
{ "kind": "contains", "path": "owner.js", "value": "owner.name" }
],
"repetitions": 3
}
]
}
+12
-2
{
"name": "@tpypan/graphcraft",
"version": "0.1.1",
"version": "0.1.5",
"description": "Progress-aware execution for durable coding agents.",

@@ -30,2 +30,8 @@ "license": "MIT",

"files": [
".agents/plugins/marketplace.json",
".claude-plugin/marketplace.json",
".claude-plugin/plugin.json",
".codex-plugin/plugin.json",
".mcp.json",
"benchmarks/stable-v1.json",
"dist/graphcraft.mjs",

@@ -43,7 +49,9 @@ "dist/mcp.mjs"

"build": "node scripts/build.mjs",
"check": "pnpm format:check && pnpm typecheck && pnpm test && pnpm build && pnpm check:context && pnpm check:package",
"check": "pnpm format:check && pnpm typecheck && pnpm build && pnpm test && pnpm check:plugins && pnpm check:context && pnpm check:package",
"check:context": "node scripts/check-context-budget.mjs",
"check:package": "node scripts/check-package.mjs",
"check:plugins": "node scripts/generate-plugin-artifacts.mjs --check",
"format": "prettier --write .",
"format:check": "prettier --check .",
"generate:plugins": "node scripts/generate-plugin-artifacts.mjs",
"graphcraft": "tsx packages/cli/src/bin.ts",

@@ -57,3 +65,5 @@ "mcp": "tsx packages/mcp/src/bin.ts",

"devDependencies": {
"@types/cross-spawn": "6.0.6",
"@types/node": "26.1.1",
"cross-spawn": "7.0.6",
"esbuild": "0.28.1",

@@ -60,0 +70,0 @@ "prettier": "3.9.5",

+74
-19

@@ -8,9 +8,13 @@ # Graphcraft

> [!WARNING]
> Graphcraft v0.1 is an alpha. It supports local verification and atomic-commit finish lines. It does not yet push, open pull requests, monitor CI, merge, or deploy.
> Graphcraft v0.1 is an alpha. It supports local verification, atomic commits, normal non-force pushes, idempotent pull-request opening, token-free waiting for an exact pull request to reach required-check green, bounded review-first or actionable-CI repair pushes, journaled review replies and resolutions, and justified infrastructure or cancellation reruns. It does not merge or deploy.
## Install the alpha
Requirements: Git, Node.js 22+, and an authenticated Codex or Claude Code CLI.
Requirements: Git, Node.js 22+, and an authenticated, protocol-qualified Codex or Claude Code CLI.
The current exact profiles are Codex CLI 0.144.6 and Claude Code 2.1.212; other versions fail
closed until their structured output, streaming, usage, cancellation, and resume behavior is
qualified. `graphcraft doctor` reports the supported versions without invoking a model.
Remote `pushed`, `pr_open`, and `pr_green` finish lines additionally require an authenticated GitHub CLI (`gh`).
The public npm package is `@tpypan/graphcraft`; the unscoped `graphcraft` name belongs to an unrelated project. Once the first npm publication is live, install it globally with either package manager:
The public npm package is `@tpypan/graphcraft`; the unscoped `graphcraft` name belongs to an unrelated project. Install it globally with either package manager:

@@ -27,11 +31,20 @@ ```bash

Until that registry publication is complete, install the same executable directly from GitHub:
If the npm registry is unavailable, install the versioned package asset from the matching
workflow-verified GitHub release:
```bash
npm install --global https://github.com/tpypan/graphcraft/archive/refs/heads/main.tar.gz
GRAPHCRAFT_VERSION=0.1.5
npm install --global "https://github.com/tpypan/graphcraft/releases/download/v${GRAPHCRAFT_VERSION}/tpypan-graphcraft-${GRAPHCRAFT_VERSION}.tgz"
graphcraft install --host codex
```
For a one-shot installation, use `npx @tpypan/graphcraft install --host codex` or `pnpm dlx @tpypan/graphcraft install --host claude` after publication. The installer copies its MCP runtime to `~/.graphcraft/runtime/<version>/` before host registration, so clearing the package-manager cache does not break Graphcraft.
Each release publishes `SHA256SUMS` beside the tarball for independent verification before install.
Direct npm, pnpm, and GitHub installation is the permanent supported fallback even when a host
marketplace is unavailable. Graphcraft also ships version-locked Codex and Claude marketplace
catalogs; [marketplace distribution](https://github.com/tpypan/graphcraft/blob/v0.1.5/docs/MARKETPLACES.md) records their validation and the
separate boundary for hosted public-directory submission.
For a one-shot installation, use `npx @tpypan/graphcraft install --host codex` or `pnpm dlx @tpypan/graphcraft install --host claude`. The installer copies its MCP runtime to `~/.graphcraft/runtime/<version>/` before host registration, so clearing the package-manager cache does not break Graphcraft.
Installation registers one local MCP tool; Graphcraft does not inject a large prompt or install a skill. Start a new coding-agent session after installation.

@@ -50,11 +63,28 @@

- Compiles a user request into linked execution and governance graphs.
- Lets the selected host propose a task-specific execution graph from bounded repository evidence, then validates and displays the actual plan before approval.
- Keeps the finish line, permissions, repository policy, and acceptance anchors outside worker control.
- Creates an isolated Git worktree without stashing, cleaning, or resetting the current checkout.
- Stores a hashed append-only event log and rebuildable state under the repository's local `.graphcraft/` directory.
- Gives each worker a small context capsule instead of replaying raw transcripts.
- Runs deterministic repository probes and classifies progress as advanced, learning, stalled, regressed, oscillating, blocked, or done.
- Schedules one evidence-driven repair when verification fails, then stops if the changed strategy does not clear the failure.
- Resumes interrupted runs without repeating accepted nodes and can switch between Codex and Claude Code.
- Tracks cached, uncached, output, reasoning, and total tokens when the host exposes them.
- Creates an isolated Git worktree without stashing, cleaning, or resetting the current checkout. Repeatable `--include` and `--exclude` globs become enforced runtime policy: actual tracked, untracked, and explicitly excluded ignored paths are content-snapshotted around every worker, while unauthorized HEAD, branch, index, read-only, or node-scope changes block acceptance and remain preserved for inspection.
- Stores a hashed append-only event log and rebuildable state under the repository's local `.graphcraft/` directory. Individual events, the event log, and the materialized state have explicit growth limits; Graphcraft reserves enough log capacity to persist one accurate blocker before refusing further appends.
- Applies one durable artifact policy to logs, transcripts, capsules, reports, and content-addressed evidence. Ordinary artifacts are redacted before sizing and safely truncated with source/stored-byte metadata, identity-bound artifacts fail closed instead of changing hashes, and a bounded inventory plus recoverable publication journal keeps run-wide quotas inspectable across interruption.
- Redacts known credential formats, authorization headers, credential-bearing URLs, password assignments, private keys, and configured sensitive environment values before model-visible summaries, durable events/transcripts/artifacts/reports, terminal/MCP output, and viewer/export responses. Integrity-hashed probe definitions reject secret-like content instead of being silently rewritten.
- Gives each worker a grounded, size-bounded context capsule, records what was selected, omitted, and reused, and never replays raw transcripts or probe logs.
- Infers deterministic, task-family-specific progress and completion probes from repository evidence, then lets users inspect or replace the versioned probe plan before approval.
- Keeps executable completion definitions in an integrity-hashed held-out plan, gives planner graphs only opaque references, and blocks omitted, substituted, or weakened checks before acceptance.
- Runs approved probes outside model context and classifies progress as advanced, learning, stalled, regressed, oscillating, blocked, or done.
- Persists task-specific evidence vectors and strategy trajectories across restarts, distinguishes advancing A→B→done work from A→B→A churn, and returns a concise decision packet when autonomous progress stops.
- Uses a fresh read-only semantic verifier only when structural probes cannot ground reported progress or completion, and persists its verdict and cost separately.
- Enforces control edges during scheduling and acceptance: observers record evidence, vetoes block without gaining write authority, target owners must approve, and user-owned arbitrators resolve explicit conflicts through durable decision packets.
- Applies evidence-backed add, supersede, split, fuse, and dependency amendments only to unfinished work, preserves governance anchors and completion probes, and stops repeated repair signatures.
- Runs sequentially by default and can overlap at most two independent read-only branches; all shared-worktree writes and Git side effects remain sequential.
- Optimizes the approved shape deterministically by fusing redundant bounded reads, splitting safely partitionable broad writes, recording concurrency choices, and reusing a durable host context only for tightly dependent same-authority reasoning with reconciled cost evidence.
- Checkpoints host sessions and results during execution, resumes the same host session when safe, and falls back to repository evidence when switching hosts or native continuation is unavailable.
- Accepts pause or stop from another CLI process, terminates the active child with bounded escalation, and records the exact cause and outcome before releasing the run lock.
- Executes explicit time, file-exists, and file-changed wait nodes without a model call while state is unchanged; wake conditions, content baselines, observations, and the next wake time survive restart in the event log.
- Runs approved work under an optional detached local supervisor with atomic PID/heartbeat records, mode-`0600` logs, stale-process replacement, and the same coordinated pause/stop channel. Supervisor files are operational projections; run events remain authoritative.
- Uses the authenticated `gh` CLI for a read-only GitHub preflight and fully paginated pull-request snapshot: exact head/base SHAs, required checks, reviews, review threads, mergeability, permissions, branch protection, and rate limits. Snapshots are marked untrusted and rejected when either SHA moves.
- Journals atomic commits, normal pushes, pull-request creation, review replies, thread resolutions, and check reruns as durable claim–act–confirm side effects. Exact remote preconditions and action markers reconcile mutations where GitHub supports them; reruns use a durable dispatch checkpoint and stop uncertain rather than risk a duplicate request. PR creation binds exact head/base SHAs, fully paginates existing branch PRs, and recovers an existing exact open PR.
- Classifies exact-SHA PR lifecycle state deterministically, giving current review feedback precedence over same-head CI failures and separating pending, actionable, infrastructure, cancelled, stale, human-decision, and green outcomes. `pr_green` waits with persisted bounded backoff and no model calls while checks or approvals are pending. Review and actionable-CI changes receive bounded, fully reverified repair pushes; unchanged signatures stop. Verified review fixes receive an exact reply and resolution, infrastructure or cancelled GitHub check runs receive at most one justified rerun, changes-requested decisions remain sticky until approval, and base movement is durably rebound without inferring rebase or merge authority.
- Serves `graphcraft view [run]` only on `127.0.0.1` as a read-only live projection of verified run files. The accessible local viewer distinguishes dependency and governance edges, exposes node context/probes/evidence, revisions, recovery and side-effect timelines, per-phase/per-node token dimensions, redacted on-demand artifacts, and a redacted self-contained export without writing to the run.
- Tracks cached, uncached, output, reasoning, and total tokens with explicit provider availability, and reports planning, worker, repair, semantic-verification, and Graphcraft-overhead costs by phase and node.
- Provides an experimental matched benchmark harness with a versioned ten-task public corpus, fresh deterministic fixtures, explicit model/effort controls, immutable fixture-bound scoring, atomic checkpoints, resumable randomized trials, deterministic blinded-review packets, and digest-bound Markdown publication.

@@ -65,20 +95,45 @@ ## Commands

graphcraft install --host <codex|claude>
graphcraft run <task>
graphcraft update --host <codex|claude>
graphcraft run <task> [--include <glob>] [--exclude <glob>] [--finish-line <local_verified|committed|pushed|pr_open|pr_green>] [--max-workers 2] [--background]
graphcraft runs [--json]
graphcraft status [run]
graphcraft inspect [run]
graphcraft probes [run] [--set probe-plan.json]
graphcraft amend [run] --set amendment.json [--approve]
graphcraft decide [run] --source <id> --target <node> --verdict <approve|veto> --reason <text>
graphcraft pause [run]
graphcraft resume [run]
graphcraft resume [run] [--background]
graphcraft supervisors [run]
graphcraft stop [run]
graphcraft delete <run> [--yes]
graphcraft prune --completed-before <date> [--keep <count>] [--confirm-run <id>...] [--yes]
graphcraft trace [run]
graphcraft view [run] [--no-open] [--port <port>]
graphcraft doctor
graphcraft github-snapshot [pull-request]
graphcraft benchmark <suite> --host both --codex-model <model> --claude-model <model> --effort <level>
graphcraft benchmark-review <report> [--suite <suite>] --blinding-key-stdin --output <blinded-review.json>
graphcraft benchmark-report <report> [--suite <suite>] --blinding-key-stdin --labels <review-labels.json> --output <report.md>
graphcraft uninstall --host <codex|claude>
```
Small localized tasks bypass Graphcraft by default. Pass `--force` when you deliberately want a durable graph.
`runs`, `status`, `inspect`, and `trace` are concise human-readable views by default. Pass `--json` when a script or another tool needs the stable structured form. `runs` orders durable runs by their last update and prints an unambiguous run prefix that every run-specific command accepts.
`--background` detaches only after contract approval. `status` shows the current supervisor and `supervisors` shows every supervisor instance, including stale replacements and local log paths. A machine restart does not auto-launch a process; rerun `graphcraft resume <run> --background` to recover the persisted wait and continue without repeating accepted work. Filesystem wait paths are resolved inside the isolated worktree, whose exact path is exposed with the wait state.
`delete` and `prune` remove only Graphcraft-owned run state, never the preserved worktree or its branch. Both commands are read-only dry runs unless `--yes` is supplied. Deletion requires the exact reviewed run ID; pruning additionally requires every selected run ID through repeatable `--confirm-run` options and revalidates terminal state, cutoff, locks, and supervisors before removal.
`github-snapshot` itself is read-only. The separate `pushed`, `pr_open`, and `pr_green` finish lines perform only the approved normal push and optional PR creation after GitHub preflight. `pr_green` adds token-free lifecycle polling, bounded reverified repair pushes, exact review replies and resolutions, and one justified rerun for a rerunnable infrastructure or cancelled check. Unchanged repair signatures, non-rerunnable checks, sticky human decisions, uncertain mutations, and base conflicts stop with classified evidence. These finish lines never force-push, reopen, rebase a published branch, merge, deploy, or edit an unrelated PR.
Small localized tasks bypass Graphcraft by default using measured task-shape signals rather than request length. Pass `--force` when you deliberately want a durable graph.
Use `stable-v1` as the bundled benchmark suite name. A dry run validates and prints its schedule without requiring model options. Real trials require an explicit model for every selected host and one shared `low`, `medium`, `high`, or `xhigh` effort policy; reports remain local under `.graphcraft/benchmarks/` unless `--output` is supplied.
`benchmark-review` and `benchmark-report` accept the blinding key only through standard input when `--blinding-key-stdin` is explicit. Supply the same private high-entropy 32-byte key to both commands as exactly 64 lowercase hexadecimal characters, with an optional final LF or CRLF, from a protected external source such as a secret manager. Graphcraft bounds the input, does not accept a key-file path, and does not persist or print the key. Packet IDs use domain-separated HMAC; artifacts contain only the key digest. The review export is separate and create-only, removes explicit host/model/mode/session/usage metadata, and includes packet digests for external review. After every packet has one digest-bound reviewer verdict, `benchmark-report` validates the same key digest and exact packet coverage, then renders a separate create-only report containing raw/blinded/label provenance, per-task and aggregate results, blinded defect findings, uncertainty intervals, unsuccessful trials, and the existing quantitative gate. Neither command modifies the raw report, performs model calls, publishes results, or turns a passing quantitative gate into a stable-release claim.
## Evidence and scope
The [v0.1 implementation report](docs/V0.1.md) records the acceptance boundary, architecture, tests, real-host dogfood, and known gaps. The [product plan](docs/PLAN.md) remains authoritative for the path to stable. Research and competitive rationale live under [docs/research](docs/research).
The [v0.1 implementation report](https://github.com/tpypan/graphcraft/blob/v0.1.5/docs/V0.1.md) records the acceptance boundary, architecture, tests, real-host dogfood, and known gaps. Research and competitive rationale live under [docs/research](https://github.com/tpypan/graphcraft/tree/v0.1.5/docs/research).
Graphcraft does not yet claim the stable plan's reliability or 20% token-savings gate. Those require the matched multi-task, dual-host benchmark described in the plan.
Graphcraft does not yet claim stable reliability or a 20% token-savings gate. The harness, public fixtures, and blinded-review/publication tooling exist, but repeated real Codex and Claude trials, completed independent defect review, published evidence, and a passing stable gate remain outstanding.

@@ -85,0 +140,0 @@ ## Development

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display