Runtime State Home Implementation Plan
Goal: Keep committed almanac/ as source-only Markdown and move derived
runtime state under ~/.codealmanac/repos/<workspace-id>/.
Architecture: Workspace selection still owns repo identity and almanac/
source paths. A small runtime-path seam maps a workspace id to local machine
state. Index, runs, and sync ledger stores receive runtime paths explicitly
instead of treating almanac_path as both source and state.
Cosmic Python repository rule applied here: keep persistence concerns behind
stores so domain/service code does not know database or ledger file mechanics.
See docs/reference/cosmic-python/chapter_02_repository.md.
Runtime Shape#
~/.codealmanac/
|-- registry.json
|-- config.toml
`-- repos/
`-- <workspace-id>/
|-- index.db
|-- index.db-wal
|-- index.db-shm
`-- runs/
|-- <run-id>.json
|-- <run-id>.jsonl
|-- <run-id>.spec.json
|-- sync-ledger.json
`-- worker.lock/
`-- owner.jsonIn tests, AppConfig(registry_path=<tmp>/.codealmanac/registry.json) makes
<tmp>/.codealmanac/ the runtime state root.
Task 1: Add Runtime Path Seam#
Files:
- Create
src/codealmanac/services/workspaces/runtime.py - Modify
src/codealmanac/app.py - Modify
src/codealmanac/services/workspaces/models.pyonly if the runtime path should be exposed onWorkspace
Steps:
- Add
WorkspaceRuntimePaths.repo_dir(workspace)as the single mapping from workspace identity to runtime directory. - Instantiate it from
app_config.registry_path.parent. - Inject it into services that need runtime state.
Task 2: Move The Index DB#
Files:
src/codealmanac/services/index/service.pysrc/codealmanac/services/index/store.pysrc/codealmanac/services/index/schema.pytests/test_read_model.pytests/test_cli.pytests/test_build_workflow.py
Steps:
- Change
index_db_pathto accept a repo runtime directory. - Keep page loading from
workspace.almanac_path. - Run all index reads against
runtime/index.db. - Update stale-schema and refresh tests to inspect the runtime DB.
Task 3: Move Run Records, Logs, Specs, Locks#
Files:
src/codealmanac/services/runs/service.pysrc/codealmanac/services/runs/store.pysrc/codealmanac/services/runs/paths.pysrc/codealmanac/services/runs/io.pysrc/codealmanac/services/runs/locks.pysrc/codealmanac/services/runs/transitions.pysrc/codealmanac/services/runs/queries.pysrc/codealmanac/services/runs/factory.pytests/test_runs_service.pytests/test_run_queue_workflow.pytests/test_cli.py
Steps:
- Rename store/path arguments from
almanac_pathtoruntime_path. - Store run files under
<runtime>/runs/. - Keep public
RunRecord.log_pathas a readable runtime-relative path:runs/<run-id>.jsonl. - Update worker lock tests to assert locks live under runtime.
Task 4: Move Sync Ledger#
Files:
src/codealmanac/workflows/sync/store.pysrc/codealmanac/workflows/sync/evaluation.pysrc/codealmanac/workflows/sync/execution.pytests/test_sync_workflow.pytests/test_cli.py
Steps:
- Store
sync-ledger.jsonunder<runtime>/runs/. - Thread runtime paths into sync evaluation/execution through workspace lookup.
- Keep transcript candidates tied to source
almanac_path; only ledger IO moves.
Task 5: Remove Repo Gitignore Runtime Entries#
Files:
src/codealmanac/services/wiki/templates.pysrc/codealmanac/services/wiki/service.pytests/test_build_workflow.pytests/test_public_contract.pyREADME.mdalmanac/architecture/indexing.mdalmanac/architecture/lifecycle-runs.md
Steps:
- Stop adding
almanac/index.dbandalmanac/jobs/to repo.gitignore. - Keep existing user
.gitignorecontent untouched. - Update docs to state runtime state is outside the repo.
Verification#
uv run pytest tests/test_read_model.py tests/test_runs_service.py tests/test_run_queue_workflow.py tests/test_sync_workflow.py tests/test_cli.py tests/test_build_workflow.py tests/test_public_contract.py tests/test_viewer_service.py
uv run pytest
uv run ruff check .
tmp_home=$(mktemp -d)
HOME="$tmp_home" uv run codealmanac health
find almanac -name index.db -o -path 'almanac/jobs/*'Expected:
almanac/contains only source wiki files.- Index DB, run files, worker locks, and sync ledger live under runtime.
- Missing runtime state rebuilds from Markdown source.
- No init/build path writes runtime ignore entries into repo
.gitignore.