Proposal
Skein currently maintains a duplicate runtime state location: the primary .skein/changes/<slug>/ AND a compat mirror openspec/changes/<slug>/.skein/ via NewWithCompat. This creates confusion, stale state, and makes the codebase harder to understand.
The goal is to have ONE source of truth: .skein/changes/<slug>/ for Skein runtime state, and openspec/changes/<slug>/ for OpenSpec planning content (proposal.md, tasks.md, specs/). No duplication.
Current state:
NewWithCompat(runtimeBase, specBase) in defaults.go writes to both locations
HasFlag, FlagMtime read from both (primary first, compat fallback)
SetFlag, ClearFlag, SetBlocked, WriteTextFile, AppendTextFile, SetPriority write to both
isInitializedChange in openspec/load.go checks for .skein/ in the openspec dir as a marker
resolveStatus in openspec/load.go has store-first path + legacy file fallback
resolveStatusWithStore in auditor/auditor.go has store-first path + legacy file fallback
- Migrate command exists to copy state from compat→primary
What to do:
-
Remove compat writes — Change NewWithCompat to New in defaults.go and all callers. Remove the specBase field and all compat write logic from file_store.go.
-
Update isInitializedChange — Instead of checking for .skein/ in the openspec dir, check if .skein/changes/<slug>/ exists (via changestate.Current().RuntimeDir(slug)). Keep the proposal.md / tasks.md checks for hand-authored changes.
-
Remove compat reads — Remove the compat directory fallback from HasFlag, FlagMtime in file_store.go.
-
Remove legacy fallback — In resolveStatus in openspec/load.go, remove the legacy file check fallback and only use the store path. Same for resolveStatusWithStore in auditor/auditor.go.
-
Run the Migrate command on existing repos to copy compat state → primary, then clean up the compat directories.
-
Update tests — Tests that use NewWithCompat should use New. Tests that check for compat writes should be updated.
-
Clean up comments — Remove references to "Slice 8" and "compat" and "legacy" throughout.
Key files:
internal/port/adapter/defaults.go — change NewWithCompat to New
internal/infra/changestate/file_store.go — remove compat logic
internal/openspec/load.go — update isInitializedChange, remove legacy fallback
internal/auditor/auditor.go — remove legacy fallback
internal/cli/intake_test.go — update test
internal/cli/migrate_state.go — can be simplified/removed after migration
Caution: This is a breaking change for repos that have only compat state. The Migrate command should be run first on existing repos.
Disposition (2026-09-18)
Archived — superseded/obsolete. Misfiled — targets the skein Go repo (internal/port/adapter, changestate).
Tasks
Unchecked items above: see Disposition in proposal.md (2026-09-18).
Proposal
Skein currently maintains a duplicate runtime state location: the primary
.skein/changes/<slug>/AND a compat mirroropenspec/changes/<slug>/.skein/viaNewWithCompat. This creates confusion, stale state, and makes the codebase harder to understand.The goal is to have ONE source of truth:
.skein/changes/<slug>/for Skein runtime state, andopenspec/changes/<slug>/for OpenSpec planning content (proposal.md, tasks.md, specs/). No duplication.Current state:
NewWithCompat(runtimeBase, specBase)indefaults.gowrites to both locationsHasFlag,FlagMtimeread from both (primary first, compat fallback)SetFlag,ClearFlag,SetBlocked,WriteTextFile,AppendTextFile,SetPrioritywrite to bothisInitializedChangeinopenspec/load.gochecks for.skein/in the openspec dir as a markerresolveStatusinopenspec/load.gohas store-first path + legacy file fallbackresolveStatusWithStoreinauditor/auditor.gohas store-first path + legacy file fallbackWhat to do:
Remove compat writes — Change
NewWithCompattoNewindefaults.goand all callers. Remove thespecBasefield and all compat write logic fromfile_store.go.Update
isInitializedChange— Instead of checking for.skein/in the openspec dir, check if.skein/changes/<slug>/exists (viachangestate.Current().RuntimeDir(slug)). Keep theproposal.md/tasks.mdchecks for hand-authored changes.Remove compat reads — Remove the compat directory fallback from
HasFlag,FlagMtimeinfile_store.go.Remove legacy fallback — In
resolveStatusinopenspec/load.go, remove the legacy file check fallback and only use the store path. Same forresolveStatusWithStoreinauditor/auditor.go.Run the Migrate command on existing repos to copy compat state → primary, then clean up the compat directories.
Update tests — Tests that use
NewWithCompatshould useNew. Tests that check for compat writes should be updated.Clean up comments — Remove references to "Slice 8" and "compat" and "legacy" throughout.
Key files:
internal/port/adapter/defaults.go— changeNewWithCompattoNewinternal/infra/changestate/file_store.go— remove compat logicinternal/openspec/load.go— updateisInitializedChange, remove legacy fallbackinternal/auditor/auditor.go— remove legacy fallbackinternal/cli/intake_test.go— update testinternal/cli/migrate_state.go— can be simplified/removed after migrationCaution: This is a breaking change for repos that have only compat state. The Migrate command should be run first on existing repos.
Disposition (2026-09-18)
Archived — superseded/obsolete. Misfiled — targets the skein Go repo (internal/port/adapter, changestate).
Tasks