Data Model: ~/.kittify Runtime Centralization

Feature: 036-kittify-runtime-centralization Date: 2026-02-09

Entities

GlobalRuntime

Represents the user-global ~/.kittify/ directory and its state.

FieldTypeDescription
home_pathPathAbsolute path to ~/.kittify/ (or override)
versionstrCLI version string from cache/version.lock
managed_dirslist[str]Package-managed directory names (software-dev, research, etc.)
managed_fileslist[str]Package-managed file names (AGENTS.md)
user_dirslist[str]User-owned directory names (custom/)
user_fileslist[str]User-owned file names (config.yaml)

Invariants:

  • version matches CLI version after ensure_runtime() completes
  • managed_dirs are fully overwritten on update
  • user_dirs and user_files are never modified by updates

VersionLock

Represents the state of ~/.kittify/cache/version.lock.

FieldTypeDescription
versionstrCLI version string written after successful update
pathPathAbsolute path to the lock file

States:

  • Missing: ~/.kittify/ not yet populated or interrupted update → trigger full bootstrap
  • Stale: Version does not match current CLI → trigger update with file lock
  • Current: Version matches CLI → fast path return

ResolutionTier

Enum representing the four resolution tiers.

ValuePriorityLocationDescription
OVERRIDE1 (highest).kittify/overrides/{type}/{name}Explicit project customization
LEGACY2.kittify/{type}/{name}Pre-centralization project assets (deprecation window)
GLOBAL3~/.kittify/missions/{mission}/{type}/{name}User-global shared assets
PACKAGE_DEFAULT4 (lowest)PACKAGE_DIR/defaults/{type}/{name}Bootstrap before first ensure_runtime()

AssetDisposition

Represents the classification of a file during spec-kitty migrate.

ValueActionCondition
IDENTICALRemoveFile is byte-identical to global version
CUSTOMIZEDMove to overridesFile differs from global version
PROJECT_SPECIFICKeepFile is at a project-specific path (config, metadata, memory, etc.)
UNKNOWNKeep + warnFile not in any known category

ResolutionResult

Return type from the 4-tier resolver.

FieldTypeDescription
pathPathAbsolute path to the resolved file
tierResolutionTierWhich tier resolved the file
missionstrMission context used for resolution (if applicable)

MigrationReport

Return type from spec-kitty migrate.

FieldTypeDescription
removedlist[Path]Files removed (identical to global)
movedlist[tuple[Path, Path]]Files moved (from, to) to overrides
keptlist[Path]Files kept (project-specific)
unknownlist[Path]Files kept with warnings
dry_runboolWhether this was a dry-run

DoctorCheck

Individual health check result for spec-kitty doctor.

FieldTypeDescription
namestrCheck name (e.g., "global_runtime_exists")
passedboolWhether the check passed
messagestrHuman-readable result message
severitystr"error", "warning", or "info"

Relationships

GlobalRuntime 1──* MissionDirectory (managed or user-custom)
GlobalRuntime 1──1 VersionLock
ResolutionTier 1──* ResolutionResult (one result per resolution)
MigrationReport 1──* AssetDisposition (one per classified file)
DoctorReport 1──* DoctorCheck (one per health check)

State Transitions

VersionLock States

MISSING ──(ensure_runtime)──> CURRENT
STALE   ──(ensure_runtime)──> CURRENT
CURRENT ──(pip upgrade)──> STALE
CURRENT ──(corruption)──> MISSING

ensure_runtime() Flow

start
  ├─ version.lock exists AND matches? → return (fast path, <100ms)
  └─ version.lock missing or stale?
       ├─ acquire file lock (non-blocking attempt)
       │   ├─ lock acquired
       │   │   ├─ re-check version.lock → if match, release lock, return
       │   │   └─ build temp dir → merge into ~/.kittify/ → write version.lock → release lock
       │   └─ lock busy (another process updating)
       │       └─ wait for lock → re-check version.lock → return
       └─ (lock always released via context manager)