Skip to content

Graph Movement

Graph movement commands support reusable planning templates and project memory. This page describes the unpublished 0.6.0 candidate; final platform/security qualification is still required. Windows remains unqualified.

They are powerful enough to change graph shape, so treat them as planned operations with receipts.

Common surfaces include:

Terminal window
mdkg graph clone --help
mdkg graph fork --help
mdkg graph import-template --help
mdkg fix ids --help
  • Preserve ids when moving a graph into a separate repository.
  • Rewrite ids when importing a template into the same graph.
  • Preserve links during rewrite.
  • Prefer explicit --dry-run receipts before --apply.

A legacy graph has no .mdkg/graph.json. Format v2 separates numeric aliases from immutable graph/node UUIDs and supports stable mdkg://<graph-id>/<node-id> selectors. Indexes derive identities from authored headers; reading or indexing never performs a migration.

Use mdkg graph migrate --help for the explicit migration contract. Preview requires a reviewed graph namespace and distinct branch origin UUIDs. Git graphs also require an accepted local ancestor. Common ancestor nodes share identity; independently created aliases do not. Unproven legacy references or rename/recreation histories block conversion instead of guessing.

Migration inspects the full local ancestor-to-HEAD history and merge boundary parents, plus stage-0 index and working-tree nodes. A deletion followed by a revert, equal body text, or a rename/alias change followed by restoration is not automatic proof of one continuous entity. Ambiguity appears in continuity_reviews, with observations, reasons and an exact review_hash. Supply a repository-contained --decisions <path> JSON object keyed by legacy QID. Each entry requires take (restore-ancestor or new-identity), a nonempty reason, and that exact review_hash. Review current inbound references too: the choice binds all current structured links to the selected identity, while historical bodies and external receipt text remain unchanged. Preview again with the decisions file before applying its new plan hash with the same file.

restore-ancestor retains the accepted ancestor identity; new-identity creates a deterministic origin-scoped recreation identity. Unknown/unused decisions and changed review inputs fail closed. Missing, shallow, grafted or partial/promisor history requires a separate local history audit; no fetch is attempted. History inspection uses the existing 2,048-commit/4,096-revision bounds and the configured index.limits.max_total_bytes budget for retained compact lineage observations. Unrecorded unlink/recreate operations leaving no committed or staged trace are indistinguishable from ordinary edits; mdkg does not invent that provenance.

Application requires the exact reviewed plan hash and unchanged graph/control inputs. Durable mappings live under .mdkg/identity/migrations/. Private before/after journals live under .mdkg/state/identity-transactions/ and are excluded from bundles. mdkg graph recover <plan-hash> inspects metadata; explicit --resume or --rollback refuses changed or unowned bytes. Successful application/recovery strictly validates authored state before rebuilding caches. None of these commands stages files or changes Git history.

Reviewed v2 migration also installs the schema2 configuration writer fence as the first authored operation; rollback restores the exact old configuration last. Upgrade every writer before adoption. Published0.5.2 clients that honor config versions refuse, but old init/force-init cannot be controlled retroactively. For pre-fence v2 graphs, preview mdkg upgrade --only .mdkg/config.json --json and apply only the exact reviewed plan. Reads do not silently add this fence.

graph recover inspection reports mode-specific recovery.resume / recovery.rollback evidence readiness and lock_evidence hashes. ready: true means evidence is reviewable, not that mdkg proved all writers stopped. Before any recovery write, stop all checkout writers and explicitly pass --confirm-quiescent plus the requested mode’s exact fresh --lock-evidence <sha256> with --resume or --rollback. This also applies to unfinished journals whose previous lock was released after a caught error. No-lock terminal repeats remain observational and need neither approval flag.

The versioned approval binds checkout identity, lock presence/absence and chain, journal inventory, current authored/control/dependency bytes and requested mode. The private journal records the operator assertion separately from evidence. It is not authentication or OS-proven orphanhood. Node PID probes only reject observably live, suspended/reused or ambiguous owners; an absent local PID does not prove another host/namespace is inactive. No OS utilities or platform allowlist establish eligibility. Complete legacy lock/journal evidence remains inspectable and requires a new approval and assertion; old approvals are not silently upgraded. Foreign checkouts, unknown/partial metadata and changed bytes refuse. Never delete evidence to bypass recovery. Complete published transaction boundaries, not universal power-loss recovery, ACL/owner preservation or hostile ancestor-replacement fencing, are the supported contract.

New Git-backed migration application/resume requires reviewed continuity evidence. An older interrupted journal without it remains inspectable and can roll back exact owned before-bytes, but cannot resume the unreviewed mapping. Rollback still refuses changed or unowned files; it is not identity approval.

Migration and reconciliation share a versioned candidate-validation contract. Before any journal or authored write, the complete proposed graph is validated against exact template inputs, canonical skills, enabled local workspace skill metadata, mounted source snapshots, archive payloads and durable event history. Missing imported targets are errors; registering an alias does not prove a node exists. Root skill resolution is unchanged: a child workspace skill does not automatically satisfy a root node’s skill requirement.

Plans bind dependency contents and discovery inventories, including relevant absent files. Template body changes, skill additions/removals and event changes invalidate approval. Resulting nodes, identity receipts and graph/event totals must fit their configured limits. Recovery reconstructs the intended complete candidate from reviewed operations before resuming, rather than treating a partially migrated graph as valid. Older plans lacking this dependency contract remain inspectable and may restore exact owned before-bytes, but cannot resume.

Authored writes may not overlap validation dependencies. Derived cache outputs must be distinct from authored data, skills/templates, imported or disabled owners, execution state, journals and SQLite sidecar paths. Dedicated custom cache locations remain supported. Existing filesystem spelling and observed case behavior participate in collision checks; mdkg does not create probe files or silently case-fold distinct paths on a case-sensitive filesystem. Ambiguous ownership requires separate resolution before migration or rollback. Terminal authored/control/dependency checks also run after cache rebuilding.

This contract does not claim that old caches already represent the proposed graph, that native skill mirrors are synchronized, or that all applicable validation and qualification checks have passed. Those remain separate gates; consumer-specific validation profiles are not implemented by mdkg.

V2 same-project clones retain identities. Independent forks allocate new identities with lineage, preserving numeric aliases and historical bodies. Template imports allocate target-owned identities with durable mappings and rewrite only proven structured references. A v2 template requires a v2 target. Read-only mounts preserve source identity without granting source write access.

V2 node creation and lifecycle commands bind structured graph references to persisted identities. Alias/QID inputs remain convenient selectors; JSON node receipts also expose identity and stable_ref. Task/goal lifecycle events and explicit graph-reference events use stable targets. Existing historical event records and prose are not rewritten.

Loop materialization allocates fresh identities for the loop and every child before binding their cross-links. A loop-fork dry run does not reserve identities or write state: its identity values are explicitly provisional, not a reviewed integration mapping. Applying a fork creates a fresh independent group.

V2 goal selection stores a stable reference in checkout-local state. Readers follow that identity if its numeric alias changes; they never silently follow a replacement node that reuses the old alias. Missing/ambiguous identity bindings, including legacy selection files preserved by migration, require explicit reselection. Reads do not update the selection file. Supplying an explicit goal selector remains independent of saved selection.

Goal claims retain their existing durable graph meaning (active_node and related lifecycle), rather than becoming distributed execution leases. Selection, transient mutation locks and runtime delivery state are checkout-local controls; they are not merged as project knowledge. Selection is not execution authority.

The working-tree graph is authoritative before and after Git staging. No command uses Git’s staged blobs as a second mutation target. These are applicability boundaries, not a claim that every command accepts every node type:

SurfaceIdentity behaviorInvalid/unresolved graph
show/list/search, graph refs, pack, read-only MCPStable selectors and additive identity; read variants retain alias_qidAlias variants remain inspectable with diagnostics; ambiguous aliases fail
new/checkpoint/task/goal/loop authoringFresh identities or immutable existing identity; structured links bind before writingStrict loading blocks ambiguous mutation
goal current, status, doctorCheckout-local selection follows identity, never a reused aliasMissing/unbound selection is diagnosed, not reassigned
manifest/capability discoveryFresh authored identity, not cached capability authorityExplicit stable selectors inspect alias variants
archive show/list/targeted verifyStable selectors and additive identity on sidecarsTarget ambiguity fails; imported archives do not grant local filesystem access
work order status/receipt verify, work validateStable selectors and bound workflow linksStrict graph/typed validation required; no successful verification of an ambiguous graph
next and other execution routingOrdinary stable resolution on a valid graphStrict loading refuses an unresolved execution candidate
index/validateDerive identities from authored fields; never allocate themStrict validation fails; unresolved inspection indexes cannot be persisted
graph transportClone retains identity; fork/import maps target ownershipForeign identity and incompatible formats fail before adoption

Archive verification without a target remains a raw sidecar-integrity audit; it is not graph identity/reconciliation proof. Lifecycle operations apply only to their declared node types, and archive compression applies only to local archive sidecars. Event records, artifact bodies and historical evidence hashes are not rewritten merely because aliases change. artifact:// and opaque runtime policy/request labels remain external semantic references.

Manifest WORK-path compatibility is retained where it resolves uniquely. New v2 workflow authoring binds those links to stable identity, and template/fork transport preserves typed filenames such as WORK.md and MANIFEST.md. Default new work-order payload hashes bind graph input identities, so alias spelling does not change a newly computed invocation hash; historical/caller-supplied payload hashes are preserved. New v2 internal archive links bind to the sidecar’s identity, including explicit archive URIs in artifact lists. External artifact URLs and filesystem locators in those lists remain opaque and unchanged.

JSON/SQLite command fixtures compare exact stable targets and whole-fixture read hashes in untracked, staged and unstaged-alias-change states. Alias-change fixtures test ordinary resolution, not semantic reconciliation acceptance; reviewed two-branch integration is a separate proof gate.

On a format-v2 branch, preview against an explicitly accepted local ancestor and incoming commit. The target is the current authored checkout, including its uncommitted nodes; an optional target ref must resolve to current HEAD.

Terminal window
mdkg graph reconcile --ancestor <ref> --incoming <ref> --json
mdkg graph reconcile --ancestor <ref> --incoming <ref> --decisions <path> --json
mdkg graph reconcile --ancestor <ref> --incoming <ref> --apply --plan-hash <sha256> --json

Review the classifications, exact path treatment, dependency hashes, alias maps, excluded surfaces and plan hash. Decisions are a JSON object keyed by stable mdkg://<graph-uuid>/<node-uuid> references; each value contains take (target, incoming or delete) and a nonempty reason. Supply the same decisions file when applying that preview. Conflicting lifecycle/evidence changes are never resolved by timestamp or an automatic list union. Body text is preserved from the chosen input; only proven structured reference fields are rebound.

Receipts under .mdkg/identity/reconciliations/ record source revisions, semantic bases and immutable alias/path mappings. A receipt’s self-hash establishes byte consistency, not target acceptance. Local application additionally creates a target-owned binding under .mdkg/identity/acceptances/. Replay requires either the exact generated receipt of a verified applied local transaction, or that exact target-owned binding with target ancestry in the current checkout or local Git history. Later authored edits, including edits before the first commit, do not revoke acceptance or require retaining an intermediate output snapshot. Incoming bindings are copied byte-for-byte under .mdkg/identity/transported/, where they are inert evidence; importing another branch’s acceptance does not accept its choices on this target.

Repeated accepted input is a no-op, including after a committed integration was reverted. A newer incoming descendant uses its most recent uniquely proven accepted semantic base. Cherry-picked/deleted identities without such a receipt require explicit review before reintroduction. Missing source objects, shallow/grafted history, ambiguous bases, malformed receipts or a bounded-history inspection limit stop planning; mdkg does not fetch, rewrite history or guess the missing evidence.

Pre-binding v2 development receipts remain usable when their genuine applied local journal survives. Without that proof, their bytes remain evidence but cannot supply replay authority; re-plan from the accepted Git ancestor and review any resulting conflicts. No identities or receipt bodies are rewritten to invent historical acceptance. Independent forks retain old-graph receipts as inert provenance. Ordinary Git commits and same-project clone selection are explicit trust decisions over the target graph; these bindings are not signatures and do not defend against an actor authorized to rewrite target-owned files.

Application requires the exact unchanged reviewed hash and preserves Git staging, selection, queues and runtime state. It writes only reviewed authored nodes, additive immutable identity evidence, a private recovery journal, and validated local derived indexes. It does not transplant source/config/docs changes or copy, rebuild or refresh bundles and archive payloads. Missing archive payloads need a separately authorized exact transfer before a fresh preview can pass. Recovery uses graph recover and refuses changed or unowned bytes. This command is not a Git merge command; literal unresolved Git stages must be resolved separately.

Use separate native Git worktrees of one project repository, one writer per checkout. Pin target HEAD, incoming revision and common ancestor before review. Apply the accepted mdkg reconcile plan on the target before starting a Git merge; validate and explicitly commit that reviewed graph result. Then use native Git for an ancestry-preserving merge of the pinned incoming revision. Resolve each graph path against the exact reviewed result and source/configuration separately. Never use blanket ours treatment for .mdkg. Validate the combined tree before the merge commit, verify both parent ancestries and recheck repeated integration.

Keep local selection, indexes, locks, journals and live runtime DBs out of the shared graph merge. Stable identity is shared project knowledge, not shared execution ownership. Submodule/gitdir-indirection and required platforms have separate qualification gates; ordinary worktree tests do not prove those cases.

When importing a template that should become active work, use an explicit start goal.

Terminal window
mdkg graph import-template ./template --start-goal goal-1 --select-goal --dry-run --json
mdkg graph import-template ./template --start-goal goal-1 --select-goal --apply --json

The selected imported goal should activate cleanly and competing local active root goals should pause. Import should not leave multiple active root goals.

Numeric IDs are aliases, not proof of independent node creation. For an unresolved legacy Git merge, repair checks the common ancestor before proposing an add/add split. It preserves positional stage 2 and remaps stage 3; those positions do not imply that either branch is main. Same-node edits, rename/delete conflicts, and unproven ancestry require an explicit semantic decision.

Use repair planning before apply:

Terminal window
mdkg fix plan --json
mdkg fix ids --json
mdkg fix ids --apply --json

Without --apply, fix ids is read-only. An optional --base-ref must match the unique common ancestor during Git-stage repair. Repair leaves Git staging unchanged: review the resulting graph and reference notes, explicitly stage the resolution, and validate before committing. Do not use graph movement commands to bypass review. Reviewed identity reconciliation is separate from legacy numeric repair. V2 graphs refuse fix ids; use reviewed graph reconcile before native Git integration instead of changing immutable identities through numeric repair.