Skip to content

Upstream provenance & drift

Quartermaster answers: where did this skill/agent/MCP/rule come from, what version was it based on, is there a newer upstream, has my local copy drifted, was the drift local or upstream, and what should I do next? Everything here is local-first and preview-first — nothing writes artifact files, and nothing touches the network unless you explicitly enable it.

An artifact’s upstream is the source it was installed from — a GitHub repo

  • path, an npm/PyPI package, a Docker image, or an MCP registry entry. Quartermaster records this as an upstream source plus a link tying it to the local item, with the installed ref/version/commit and a baseline tree hash.

Provenance auto-links at scan time: artifacts inside git clones link to the clone’s remote, plugin-cache bundles link to their marketplace clone’s remote, and items with no breadcrumb inherit the origin of identical-content siblings. The first-seen tree becomes the drift baseline.

The most authoritative provenance signal is a sidecar file next to the artifact:

{
"schema": "quartermaster-origin/v1",
"source": { "kind": "github_repo", "repo": "acme/pdf-demo", "path": "skills/pdf-demo", "ref": "v1.0.0", "commit": "<sha>" },
"installed_files": {},
"installed_at": "2026-06-01T00:00:00Z"
}

A sidecar yields a confidence: 1.0 candidate. Without one, Quartermaster falls back to git origin, package/MCP config source, public-catalog matches, and content fingerprints.

  • find_upstream({ itemId }) — ranked candidates[] (highest confidence first), each with matchMethod, confidence, and evidence. Confidence tiers: sidecar 1.00, git remote+path+commit 0.98, exact tree hash 0.95, repo URL 0.90, primary-file hash 0.85, catalog name 0.80, normalized-Markdown 0.75, package name 0.65, known-path 0.50, fuzzy name 0.40.
  • link_upstream({ itemId, candidate }) — persists a selected candidate as the artifact’s upstream link. DB metadata only; no files are written.

check_updates({ itemId | all, allowNetwork?, refreshSnapshot?, limit? }) compares each linked item’s installed version/commit to the latest upstream. Cache-only by default (network: "disabled"); with ALLOW_NETWORK_UPDATES=1 and allowNetwork: true it resolves the latest from GitHub/npm/PyPI and (with refreshSnapshot) stores an upstream-latest snapshot. Each row reports status (current · update_available · unknown · source_missing · source_moved), pinned, warnings, and evidence.

Verification is git-native and cheap: local snapshots carry git blob hashes, so upstream comparison uses one GitHub tree-listing call per repo — no file downloads. Latest-commit lookups use git ls-remote (any git host), and plugin bundles verify offline against the local marketplace clone.

explain_drift({ itemId, persist? }) returns the full status taxonomy, file-level changes, conflicts, semantic findings, risk, and a recommendation:

statusmeaning
current_cleancurrent matches the latest (or the baseline when no latest is known)
outdated_cleanno local edits; the latest upstream applies cleanly
patched_currentlocal edits, no newer upstream
patched_outdatedlocal edits and a newer upstream, no file conflict
forkedthe same file changed locally and upstream
unknown_originno baseline yet — link an upstream first
source_missing / source_movedthe upstream source is gone or relocated
suspicious_drifta high-risk semantic change (below) overrides the above

scan_drift({ itemIds | allLinked, persist? }) computes (and by default persists) reports for many linked items at once; they appear at GET /api/drift and the dashboard’s Drift tab.

Beyond file hashes, Quartermaster flags meaningful changes: allowed_tools_expanded, script_added / script_modified, mcp_command_changed, mcp_source_ref_changed, mcp_destructive_tool_added, local_path_introduced, secret_like_token_introduced. Any high-severity finding (or a locally modified script/config) classifies the artifact as suspicious_drift. Secrets and local paths in the evidence are redacted before storage or display.

  • pin_version({ itemId, upstreamSourceId, ref?|version?|commit?, reason? }) sets the link’s pinned flag and records the reason. For an unpinned MCP server, the response includes a suggested pinned config preview — Quartermaster never rewrites MCP config files.
  • unpin_version clears the flag.

A pinned artifact still reports update_available, but check_updates and preview_update recommend staying pinned until you unpin.

preview_update({ itemId, persist? }) is the canonical dry-run merge planner: baseline → current → latest → rich drift → operations (add_file · replace_file · remove_file · manual_merge · preserve_local) → policy findings. It always returns dryRun: true, writes: []. Script changes and conflicts become manual_merge.

The repo ships a repeatable end-to-end demo: docs/UPSTREAM_DRIFT_DEMO.md, with fixtures in test/fixtures/upstream-demo/ — three views of one skill (installed baseline, locally edited copy with a sidecar, newer upstream):

reindex # discover the local pdf-demo skill
find_upstream # sidecar is the top candidate (confidence 1.0)
link_upstream # persist the link
check_updates # v1.0.0 vs v1.1.0 -> update_available (cache-only)
explain_drift # -> patched_outdated (local SKILL.md edit + upstream README.md change)
preview_update # replace_file README.md + preserve_local SKILL.md (dry-run)
scan_drift # persist reports -> dashboard Drift tab

The automated version is test/e2e-upstream-drift.test.mjs (runs with npm test, no network at any step).