Spaces:
Runtime error
A newer version of the Gradio SDK is available: 6.26.0
Graphify Auto-Update — Status Surfacing
Documents how
gsd-plannerandgsd-phase-researchersurface the opt-in graphify auto-update state (issue #3347). The status surface lives insidegraphifyStatus()ingsd-core/bin/lib/graphify.cjs; no planner-side prompt changes are required.
Why this exists
The graph at .planning/graphs/graph.json is consumed automatically (every gsd-planner and gsd-phase-researcher step) but produced manually (/gsd-graphify build per session at best). Without auto-update, the producer-consumer gap silently widens with every commit. The existing stale: true annotation tells the consumer the mtime is old; it cannot tell the consumer whether the auto-build hook has been running, just failed, or is in flight.
When graphify.auto_update: true, the bundled hooks/gsd-graphify-update.sh PostToolUse hook fires after HEAD-advancing git operations on the default branch and dispatches graphify update . in a detached subprocess. The hook writes a status file synchronously before detach; the detached process rewrites it on completion.
The status file
.planning/graphs/.last-build-status.json:
{
"ts": "2026-05-15T14:02:23Z",
"status": "running" | "ok" | "failed",
"exit_code": null | <int>,
"duration_ms": null | <int>,
"head_at_build": "<commit-sha>",
"graphify_version": null | "<version>"
}
The hook writes status: "running" synchronously before detach, so the next planner invocation can see the in-flight signal even if graphify update . has not finished. The detached hooks/lib/gsd-graphify-rebuild.sh rewrites the file to ok or failed on completion (with exit_code and duration_ms).
How the planner surfaces it (zero new prompt content)
graphifyStatus() in gsd-core/bin/lib/graphify.cjs reads .last-build-status.json and folds the running / failed states into the existing stale: true signal:
const autoUpdateStale =
lastBuildAutoUpdate &&
(lastBuildAutoUpdate.status === 'failed' || lastBuildAutoUpdate.status === 'running');
return {
...
stale: age > STALE_MS || Boolean(autoUpdateStale),
...
last_build_auto_update: lastBuildAutoUpdate || null,
};
The planner and researcher already run node ... graphify status inside their <step name="load_graph_context"> blocks and already have the rule:
If the status response has
stale: true, note for later: "Graph is{age_hours}hold — treat semantic relationships as approximate."
That rule now fires correctly in three additional cases:
| Trigger | What user sees |
|---|---|
Auto-build status = failed |
Existing "treat as approximate" note fires (because stale: true). The full last_build_auto_update object is in the JSON for callers that want exit-code / duration / commit-sha context. |
Auto-build status = running |
Same — the next planner invocation knows the graph is mid-rebuild and treats it as approximate until the detached process completes. |
Auto-build status = ok AND mtime < 24h |
Annotation is silent — the graph is fresh and the most recent auto-build succeeded. |
The file-missing case is silent (the operator either has not opted in or has not yet triggered a HEAD-advancing git op since enabling).
Why this design
- No planner-side prompt changes. Folding into
stale: truereuses the existing rule, which means no new content inagents/gsd-planner.md(which is already at the< 48Kdecomposition limit perDEFECT.AGENT-FILE-SIZE-CAP-BREACH). - Tests catch regressions on the seam.
tests/feat-3347-graphify-auto-update-config.test.cjspinsgraphifyStatusbehavior for status=failed/running/ok/ file-missing. - Backwards compatible. Callers that don't read
last_build_auto_updatesee the same shape as before, withstalereflecting both mtime AND auto-build state. No consumer breakage.
Opt-in reminder
The auto-update mechanism is opt-in (graphify.auto_update: false by default per issue #3347). Users who haven't opted in will never produce this file. graphifyStatus() returns last_build_auto_update: null and falls back to the mtime-only stale rule.