Artifact migration guide (upgrading an existing project)¶
Audience: operators — anyone upgrading an existing project's dev-team plugin
install across the .claude/-scoped runtime artifact change (issue #1406, plan
opt-in-metrics-and-claude-scoped-artifacts.md). This is not a maintainer doc —
see developer-notes.md for plugin-development docs.
What changed¶
Two coordinated changes:
- Consent flips from on-by-default to off-by-default, gated by a single
user-level config file:
~/.claude/telemetry.json.telemetry.jsonlandartifact-usage.jsonmove to~/.claude/metrics/. - Every other project-scoped runtime artifact directory (
metrics/,memory/,plans/) moves under the project's own.claude/instead of the repo root, and the reports domain (reports/+DEV_TEAM_REPORTS/) consolidates into a new top-level.dev-team-reports/.
Each pre-existing file falls into exactly one of three treatments below — never assume a file you rely on was auto-migrated; check which bucket it's in.
1. One-time move (writers with a real Python touchpoint)¶
These files are moved — not copied — from their old bare path into
.claude/<category>/ the first time their owning hook/script writes (or, for
one case, reads) after upgrade. The move is per-file, never a directory
sweep, and skips any file that is git-tracked (a tracked legacy file is left in
place rather than silently moved out from under version control).
| File | Old path | New path |
|---|---|---|
cost-metering.jsonl |
metrics/cost-metering.jsonl |
.claude/metrics/cost-metering.jsonl |
{date}-task-log.jsonl |
metrics/{date}-task-log.jsonl |
.claude/metrics/{date}-task-log.jsonl |
config-changelog.jsonl |
metrics/config-changelog.jsonl |
.claude/metrics/config-changelog.jsonl |
pending-review.jsonl |
metrics/pending-review.jsonl |
.claude/metrics/pending-review.jsonl |
learning-loop-state.json |
metrics/learning-loop-state.json |
.claude/metrics/learning-loop-state.json |
| boundary-events log | metrics/boundary-events.jsonl |
.claude/metrics/boundary-events.jsonl |
/test-improve's phase-state tree |
memory/test-improve/<slug>/ |
.claude/memory/test-improve/<slug>/ (directory-migrated file-by-file on the next resume; refactor-backlog.md is excluded — see § 2) |
The shared mechanism is hooks/lib/artifact_paths.py's resolve_file() (single
file) and migrate_dir() (whole subtree, one call per invocation, still
file-by-file — never overwrites an existing destination). Both are fail-open:
a failed move logs one diagnostic line to stderr and the calling operation
proceeds unaffected — it never blocks or raises.
verify-log.jsonl is a deliberate exception: it stays at the bare
metrics/verify-log.jsonl and is not part of this migration at all (it
was never moved, gated, or relocated).
2. Documented clean break (agent-instruction-driven writers, no Python write call site)¶
These files are written by agent instructions (skill/agent markdown telling
Claude where to Write), not by a Python hook. There is no code path that can
migrate them, so pre-existing top-level content is left in place
permanently — it is not moved, and new writes after upgrade go straight to
the new location, meaning old and new content end up split across two paths
with no automatic reconciliation.
| File / tree | Old path | New path (new writes only) |
|---|---|---|
review-value.jsonl |
metrics/review-value.jsonl |
.claude/metrics/review-value.jsonl |
build-phase.json |
memory/build-phase.json |
.claude/memory/build-phase.json (read side uses migrate=False deliberately — it never moves the legacy file) |
refactor-backlog.md (/test-improve) |
memory/test-improve/<slug>/refactor-backlog.md |
.dev-team-reports/test-improve/<slug>/refactor-backlog.md (a report, not runtime state — explicitly excluded from migrate_dir()'s .claude/memory/ sweep; see the reports-domain row below) |
/test-improve reports output |
reports/test-improve/<slug>/ |
.dev-team-reports/test-improve/<slug>/ |
/test-improve plan artifacts |
plans/test-improve/ |
.claude/plans/test-improve/ |
DEV_TEAM_REPORTS/-domain writers (/review-agent, /code-review interactive, /triage, /report-pdf, /ship, /exploratory-testing, /session-review) |
DEV_TEAM_REPORTS/... / reports/... |
.dev-team-reports/... |
Practical consequence: if a project has an in-flight /build session (a
recorded build-phase.json) or unresolved review-value/reports content at the
moment it crosses the upgrade boundary, that in-flight state is effectively
orphaned at the old path — /build's phase tracking for that session will
behave as if no phase is recorded. There is no data-loss risk (nothing is
deleted), but the record will not be picked up post-upgrade.
3. Dual-read fallback (transition-window self-healing)¶
Three reader commands tolerate the split between old and new locations without any manual step:
/cost-reportand/harness-auditreadcost-metering.jsonl,review-value.jsonl, andconfig-changelog.jsonlby preferring.claude/metrics/<file>, falling back to the baremetrics/<file>if the new path doesn't exist yet. This self-heals during the transition window — no operator action needed./artifact-lifecyclereadsartifact-usage.jsonexclusively from~/.claude/metrics/artifact-usage.json(home-scoped). This file was already home-scoped as of the telemetry-consent change, so there is no legacy project-scoped fallback to read — any older doc reference to a project-scoped path was a documentation bug, now corrected to point at the one location the file has ever actually been written to.
Consent-file migration is manual — not automatic¶
If a project previously had a .claude/telemetry.json (or, pre-this-change,
any project-level telemetry consent setting) with {"enabled": true}, that
setting is not carried forward. Consent is now resolved exclusively from
~/.claude/telemetry.json (home-scoped). DEV_TEAM_TELEMETRY also has no
effect any more.
Action required: if you want telemetry after upgrading, re-opt-in at the new location:
Nothing reads or migrates a project's old consent file automatically — an un-migrated project simply defaults to telemetry disabled (fail-open), which is the deliberate new default posture, not a bug.
Quick reference: what to check after upgrading¶
- [ ] If you rely on telemetry, artifact-usage, or cost data: re-opt-in via
~/.claude/telemetry.json(see above) — nothing carries over. - [ ] If you have an in-flight
/buildsession across the upgrade: expect its phase-tracking state to reset (§ 2,build-phase.json). - [ ] Old top-level
reports/,DEV_TEAM_REPORTS/,memory/,plans/test-improve/content stays exactly where it is — read it from the old path, or move it by hand if you want it under the new tree. - [ ]
.gitignorerules for these directories were rewritten to match the new paths; if you have local overrides, re-check them against the new.claude/-scoped and.dev-team-reports/-scoped paths.