# Python Port Worklog

## 2026-07-01

- Active goal continued for architecture quality after public-beta package
  proof: keep applying Cosmic Python, `MANUAL.md`, the live agreement, and
  useful `../almanac` patterns until remaining cleanup is genuinely
  diminishing returns.
- Added slice-121 wiki-dispatch boundary plan after rereading Cosmic Python
  chapters 4 and 13 and checking `../almanac/clients/cli`. The applied lesson
  is that the CLI edge should translate parsed args to service requests through
  small command-family dispatchers, not a single growing wiki module.
- Split `cli/dispatch/wiki.py` by command family: `topics.py` owns topic
  subcommands, `workspaces.py` owns local registry list/drop commands, and
  `serve.py` owns local viewer startup.
- Added an architecture guard that keeps topic/workspace request construction
  and uvicorn startup out of `dispatch/wiki.py`.
- Added slice-120 run-store factory/query boundary plan after rereading Cosmic
  Python chapter 6 and the run-ledger live agreement. The applied lesson is
  that `RunStore` is the repository facade over durable run state, while
  run-id construction and queue/list selection are mechanics with separate
  reasons to change.
- Split `services/runs/factory.py` for run-id and initial `RunRecord`
  construction and `services/runs/queries.py` for sorted record listing plus
  oldest spec-backed queued-run selection.
- Tightened the run-ledger architecture guard so `store.py` cannot regrow
  `uuid4`, `strftime`, `run_log_reference_path`, record sorting, or direct
  `ledger.iter_records` query mechanics.
- Added slice-119 wiki-topic YAML boundary plan after rereading Cosmic Python
  chapter 2. The applied lesson is that `topics.yaml` persistence has a
  forgiving read/index path and a strict round-trip mutation path, and those
  mechanics should not live beside the topic Pydantic model in one module.
- Split `services/wiki/topics.py` into `topic_models.py`, `topic_read.py`, and
  `topic_file.py`, keeping `topics.py` as a small import facade.
- Added an architecture guard that keeps PyYAML reads, ruamel round-trip
  mutation, `CommentedMap`, and topic model definitions in their owning modules.
- Added slice-118 server-route boundary plan after rereading the live
  agreement, `MANUAL.md`, `.almanac/README.md`, and Cosmic Python chapters 4
  and 13. The applied lesson is that `server/app.py` should be the FastAPI
  composition root, while HTTP route bodies, static package asset mechanics,
  and exception mapping get named modules.
- Split `server/app.py` into `api_routes.py`, `static_routes.py`,
  `static_assets.py`, and `errors.py` while preserving `serve` API/static
  behavior.
- Added an architecture guard that keeps route decorators, package resource
  reads, viewer request models, `CodeAlmanacError`, `ValidationError`, and
  HTTP response/error mechanics out of `server/app.py`.
- Added slice-117 automation-service boundary plan after rereading the live
  agreement, `MANUAL.md`, `.almanac/README.md`, and Cosmic Python chapter 4.
- Split automation internals into `services/automation/selection.py` for task
  defaulting and install validation, `definitions.py` for static task metadata,
  and `jobs.py` for `ScheduledJob` construction.
- Added an architecture guard that keeps scheduler command construction,
  launch PATH assembly, plist paths, interval policy, and validation mechanics
  out of `AutomationService`.
- Added slice-116 source-address family boundary plan after rereading Cosmic
  Python chapter 3/4 guidance on simple abstractions and service-layer
  orchestration. `address_resolution.py` is now a small dispatcher facade.
- Split source-address internals into family modules for Git, GitHub, web URL,
  local path, transcript, prompt hints, and shared positive-integer parsing.
- Added an architecture guard to keep URL validation, hashing, GitHub/Git/path
  parser definitions, prompt hints, and runtime adapter contracts out of the
  address dispatcher facade.
- Added slice-115 topic-service boundary plan after rereading
  `.almanac/README.md`, `MANUAL.md`, the live agreement, and Cosmic Python
  chapter 4. The service-layer lesson applied here is that `TopicsService`
  should stay the use-case entrypoint while graph mechanics and workspace
  selection get named homes.
- Split topic internals into `services/topics/graph.py` for existence,
  self-parent, and DAG-cycle rules, `services/topics/read_model.py` for derived
  index topic-slug lookup, and `services/topics/workspace.py` for current-repo
  vs explicit `--wiki` resolution.
- Added an architecture test to keep `TopicDefinition`, `SelectWorkspaceRequest`,
  graph helper definitions, read-model helper definitions, and workspace helper
  definitions out of `services/topics/service.py`.
- Added slice-73 page-run workflow plan after comparing current
  `ingest`/`garden` duplication with `../almanac`'s page-run workflow shape.
- Extracted `workflows/page_run/` so shared page-writing lifecycle execution
  owns running-state transition, mutation preflight, harness invocation,
  harness transcript/event recording, mutation validation, index refresh,
  terminal success, and failure recording.
- Kept `IngestWorkflow` responsible for source resolution, source runtime, and
  ingest prompt payloads. Kept `GardenWorkflow` responsible for index/health
  context and garden prompt payloads.
- Added architecture tests that prevent `ingest` and `garden` from importing
  shared run/harness plumbing directly, and keep the page-writing workflow
  services small.
- Verified slice 73 with focused ingest, garden, architecture tests and
  focused ruff checks before broad verification.
- Ran an isolated live service dogfood with a fake Codex harness. Ingest
  finished `done`, wrote `page-run-dogfood`, and preserved the expected run
  event sequence: `status,status,message,message,message,output,status`.
- Added slice-74 jobs control plan and implementation. `jobs attach` now
  replays durable log events plus current status; `jobs cancel` marks
  queued/running runs cancelled through `RunsService`; `RunStore.finish(...)`
  returns already-cancelled runs unchanged so later workflow finalization cannot
  resurrect a cancelled job.
- Verified slice 74 focused behavior with runs-service, CLI, and architecture
  tests before broad verification.
- Ran an isolated CLI dogfood for `jobs attach` and `jobs cancel` against a
  temporary repo. Attach replayed the queued job log and current status; cancel
  marked the job `cancelled`; `jobs show` read back the cancelled record.
- Added slice-79 setup/uninstall instruction foundation after rereading the
  live agreement, `MANUAL.md`, Cosmic Python service/command/composition-root
  chapters, and archived setup behavior. `SetupService` now owns setup verbs,
  while `FileInstructionInstaller` owns Codex/Claude filesystem instruction
  artifacts behind a service-owned port.
- Python setup now installs a `codealmanac` managed Codex AGENTS block and a
  Claude `~/.claude/codealmanac.md` guide plus `CLAUDE.md` import. Python
  uninstall removes only current setup-owned `codealmanac` artifacts; old
  `almanac` artifacts are not compatibility scope and may belong to a separate
  product install.
- Focused slice-79 tests cover idempotence, Codex override selection, Claude
  import installation, uninstall preserving user content, CLI setup/uninstall,
  and public-contract next-agent freshness.
- Added slice-80 setup terminal renderer after rereading the live agreement,
  `MANUAL.md`, Cosmic Python service/command/composition-root chapters, and
  archived setup output helpers. The setup service stays UI-agnostic; Rich is
  used only in `cli/render/setup.py` for branded panels, status rows, and a
  next-steps box.
- Added an architecture test that keeps Rich imports inside the CLI render edge,
  so terminal UI polish cannot leak into services, workflows, integrations, or
  stores.
- Added slice-81 multi-wiki serve after rereading the live agreement,
  `MANUAL.md`, Cosmic Python service/read-view/composition-root references, and
  the current viewer/server code. `ViewerService` now exposes the selected wiki
  plus available registered local wikis, the FastAPI edge accepts `wiki` query
  selectors, and the static viewer can switch wikis without restarting
  `codealmanac serve`.
- Focused slice-81 tests cover available-wiki listing, skipping unavailable
  registry entries, `workspace_id` selection, and `serve --wiki` narrowing.
- Slice-81 live dogfood exposed concurrent first-read `database is locked`
  failures when overview and page requests refreshed the same wiki index at the
  same time. `connect_sqlite(...)` now sets a 30-second SQLite busy timeout
  before WAL mode, and `tests/test_database.py` guards the PRAGMA.
- Added slice-82 rich harness event logs after comparing the current Python
  display-only `HarnessEvent` with the archived Codex app-server event model.
  `HarnessEvent` now carries structured tool display, actor attribution, usage,
  provider session, failure metadata, agent trace, and raw JSON payload fields.
  `RunLogEvent` persists the readable row plus optional nested `harness_event`
  JSON, preserving text `jobs logs` while making JSON logs the CodeAlmanac-owned
  inspectable transcript surface for future app-server and Claude SDK adapters.
- Focused slice-82 tests cover structured event persistence through a real
  ingest workflow and direct run-service logging.
- Added slice-83 Codex app-server harness after rereading the live agreement,
  `MANUAL.md`, `.almanac/README.md`, the full codebase-wiki spec, Cosmic
  Python chapters 11 and 13, and the archived TypeScript app-server provider.
  The default Codex adapter now uses `codex app-server --listen stdio://`
  instead of `codex exec`, while readiness remains `codex login status`.
- The Codex integration is split by responsibility: `adapter.py` wraps the
  service port and Git changed-file accounting, `app_server.py` owns run
  semantics, `rpc.py` owns the line-oriented JSON-RPC child process,
  `events.py` maps notifications, `display.py` maps structured tool display,
  and `failures.py`/`usage.py`/`fields.py` hold focused boundary helpers.
- Focused slice-83 tests use a fake Codex app-server executable to verify the
  JSON-RPC handshake, `mcp_servers={}` isolation, internal-session env,
  ephemeral thread, workspace-write/no-network sandbox, noninteractive approval
  responses, ChatGPT token-refresh refusal, base64 output decoding, usage
  parsing, root/helper turn handling, and startup/turn timeouts.
- Added slice-84 Claude SDK harness after rereading the live agreement,
  `MANUAL.md`, `.almanac/README.md`, the codebase-wiki spec, Cosmic Python
  chapters 4 and 13, the current harness port/model, Codex app-server adapter,
  and the archived TypeScript Claude SDK provider.
- Added `claude-agent-sdk` as an internal runtime dependency. The default
  Claude adapter now wraps `ClaudeSdkClient` for execution and keeps Git
  changed-file accounting in the adapter, matching the Codex app-server split.
- The Claude SDK client runs with `setting_sources=[]`, `strict_mcp_config=True`,
  `mcp_servers={}`, `permission_mode="dontAsk"`, partial-message streaming, and
  the local edit/search tool set. It maps SDK dataclasses into normalized
  provider-session, text-delta, text, tool-use, tool-result, usage, helper
  agent, error, and done events.
- Focused slice-84 tests use typed fake SDK streams to verify SDK option
  isolation, provider session recording, tool display, helper completion,
  usage, failure classification, timeout handling, API-key readiness fallback,
  changed-file wrapping, and default app wiring.
- Added slice-85 Claude event-boundary split after rereading the live
  agreement, `MANUAL.md`, `.almanac/README.md`, and Cosmic Python chapters 4
  and 13. The service-facing harness port stayed unchanged; `events.py` became
  a thin SDK-message dispatcher and re-export surface.
- Split Claude SDK event normalization into explicit provider-edge modules:
  `sdk_messages.py`, `state.py`, `actors.py`, `result.py`, `message_events.py`,
  `stream.py`, `tool_events.py`, `task_events.py`, and `raw.py`.
- Added an architecture test that keeps Claude harness modules below 220 lines
  and prevents `events.py` from regrowing block mapping or raw conversion
  logic.
- Slice-85 review found that `ClaudeSdkClient` still imported state and result
  helpers through `events.py`. The review fix moved those imports to
  `state.py`, `sdk_messages.py`, and `result.py`, and expanded the architecture
  test so `events.py` remains dispatch-only.
- Added slice-86 Codex default and setup plan after finding that the live
  agreement said Codex but `DEFAULT_HARNESS` still selected Claude. Config
  defaults now choose Codex for no-flag lifecycle runs.
- Moved shared automation cadence constants into
  `services/automation/defaults.py` so setup can recommend the same sync/garden
  commands that automation uses.
- Added typed setup plan facts to `SetupResult`: default harness, selected
  instruction targets, automation recommendations, and next commands. Rich text
  and JSON setup output now render those service facts instead of duplicating
  command strings in the renderer.
- Added slice-87 setup automation options after rereading the live agreement,
  `MANUAL.md`, `.almanac/README.md`, Cosmic Python command guidance, and the
  archived setup automation branch.
- Setup now installs scheduled sync/Garden automation when the user passes
  `--install-automation` or explicit sync/Garden timing flags. The setup
  service calls an automation service port directly; it does not shell out to
  `codealmanac automation install`.
- Uninstall now removes scheduled automation by default and exposes
  `--keep-automation` as the escape hatch, so setup has a complete reverse path
  for the scheduler state it can create.

## 2026-06-29

- Active goal created for a full Python rewrite using
  `docs/python-port-live-agreement.md`, Cosmic Python guidance, slow
  development, frequent review, tests, live CLI checks, and small verified
  commits.
- Current branch is `codex/python-port-archive-existing-code`.
- Existing TypeScript/Node implementation is staged under `archive/code/`.
- Local Cosmic Python reference exists as Markdown-only files under
  `docs/reference/cosmic-python/`.
- Read `MANUAL.md`, `CLAUDE.md`, `.almanac/README.md`,
  `docs/python-port-live-agreement.md`, and the CodeAlmanac Cosmic Python
  guide.
- First implementation pressure is the Python spine: packaging, CLI entrypoint,
  application composition root, workspace service, and a test harness.
- Committed archive/docs baseline as `4520812`.
- Added the first Python scaffold: `pyproject.toml`, `src/codealmanac/`,
  `tests/`, `codealmanac` console script, `create_app(...)`, workspace registry
  service, wiki scaffold service, and build workflow-backed `init`.
- Verified first scaffold with `uv run pytest`, `uv run ruff check .`,
  `uv run codealmanac --help`, and an isolated live `codealmanac init` plus
  `codealmanac list` smoke run.
- Committed the first Python scaffold as `a803f63`.
- Review pass tightened the workspace registry write path: temp files now use
  unique same-directory names, duplicate workspace names compare
  case-insensitively, and selector helpers have explicit registry-entry types.
- Re-verified the review fix with `uv run pytest`, `uv run ruff check .`, and
  an isolated live `codealmanac init` plus `codealmanac list` smoke run.
- Sent a Relayforge Discord checkpoint through Doppler-injected
  `almanac/dev` credentials describing the Cosmic Python patterns applied so
  far: composition root, thin CLI adapter, repository/store boundary, and
  deferred Unit of Work machinery.
- Added slice-2 read-model plan in `docs/python-port/slice-2-read-model.md`.
- Added SQLite read-model services: `index` owns SQLite schema and query store,
  `search` and `pages` own user-facing read verbs, and CLI renders service
  results without knowing SQL exists.
- Added `python-frontmatter` after checking for a known frontmatter parsing
  library; Pydantic validates parsed metadata and `StrEnum` names wikilink
  kinds.
- Dogfood found a stale-schema bug against this repo's existing `.almanac/index.db`.
  The Python schema now uses a high version so old Node-era DBs rebuild cleanly.
- Verified slice-2 work with `uv run pytest`, `uv run ruff check .`, an isolated
  live `search`/`show`/`--mentions`/backlink smoke, and dogfood
  `codealmanac search python --limit 5` against this repo.
- Slice-2 review fixed two correctness issues: `show --body` now wins over
  metadata/field flags, and full index rebuild clears stale topic rows.
  Re-verified with 14 passing tests, ruff, isolated live `show --body --meta`,
  and dogfood search in this repo.
- Read Cosmic Python chapter 3 on abstractions before slice 3 and sent a
  Relayforge Discord checkpoint. The applied lesson: keep interrogation,
  decision, and mutation separate. Slice 3 therefore adds read-only
  `topics`/`health`; tag/frontmatter mutation stays out of scope.
- Added slice-3 read-only topics and health: `topics`, `topics show`,
  `topics show --descendants`, `health`, and `health --json`.
- Verified slice 3 with 17 passing tests, ruff, isolated live topics/health,
  and dogfood `codealmanac topics` plus `codealmanac health` in this repo.
  Dogfood health currently reports dead refs to archived TypeScript paths,
  which is expected product signal after the Python rewrite archive move.
- Slice-3 review fixed path safety and resilience: file refs now stay
  repo-relative (`/x` becomes `x`, `../x` is ignored), and malformed
  `topics.yaml` no longer breaks read commands. Re-verified with 19 tests,
  ruff, live `health --json`, and dogfood health.
- Added slice-4 `tag`/`untag` frontmatter mutation using `ruamel.yaml` for
  round-trip YAML editing. Verified body preservation, comment preservation,
  CRLF preservation, idempotence, no-frontmatter pages, CLI smoke, 24 tests,
  and ruff.
- Slice-4 review fixed frontmatter closing fences at EOF and no-op untag
  summaries. Re-verified with 25 tests, ruff, and a live EOF/no-op smoke.
- Read Cosmic Python chapter 5 on service-layer tests and sent a Relayforge
  Discord checkpoint. The applied lesson: behavior tests should mostly drive
  service-layer request models, with lower-level tests reserved for fragile
  implementation boundaries such as YAML round-tripping.
- Added slice-5 topic metadata mutation: `topics create`, `topics describe`,
  `topics link`, and `topics unlink`. The service owns parent existence,
  ad-hoc topic promotion, cycle rejection, and result enums; the wiki helper
  owns round-trip `.almanac/topics.yaml` mutation with `ruamel.yaml`.
- Verified slice 5 with 32 passing tests, ruff, `git diff --check`, isolated
  live topic create/describe/link/unlink/show, CLI help, and dogfood
  `codealmanac topics show cli --descendants` in this repo.
- Read Cosmic Python chapter 6 on Unit of Work and sent a Relayforge Discord
  checkpoint. The applied lesson: topic rewrite operations need an explicit
  operation boundary. Because filesystem writes cannot roll back like a
  database transaction, slice 6 builds a full page-rewrite plan before any
  write, writes `topics.yaml` first, then writes affected pages.
- Added slice-6 topic rewrite mutation: `topics rename` and `topics delete`.
  Rename refuses implicit merge into an existing topic; delete removes topic
  edges and page tags without deleting pages or child topics.
- Verified slice 6 with 39 passing tests, ruff, `git diff --check`, isolated
  live topic rename/delete/show, CLI help, and dogfood
  `codealmanac topics show cli --descendants` in this repo.
- Read Cosmic Python chapter 12 on CQRS and sent a Relayforge Discord
  checkpoint. The applied lesson: committed markdown is the write-side truth,
  `.almanac/index.db` is a derived read model, and `reindex` is an explicit
  command that mutates only that projection.
- Added slice-7 local maintenance commands: `build` and `reindex`. `build`
  refreshes deterministic wiki scaffold files, registers the workspace, and
  rebuilds the SQLite projection. `reindex` forces a full projection rebuild
  and supports JSON output.
- Verified slice 7 with 42 passing tests, ruff, `git diff --check`, isolated
  live build/reindex/search/help, and top-level `codealmanac --help` in this
  repo.
- Read Cosmic Python chapter 13 on dependency injection and sent a Relayforge
  Discord checkpoint. The applied lesson: keep dependencies explicit and wired
  in `app.py`; do not hide diagnostics probes in CLI code or add a DI framework.
- Added slice-8 `doctor`: a local diagnostics service and CLI command with text
  and JSON output. The Python v1 doctor checks package/runtime basics, registry
  path, current or named wiki resolution, index summary, and health problem
  count. It deliberately omits archived Node/npm/provider/hosted checks.
- Verified slice 8 with 46 passing tests, ruff, `git diff --check`, dogfood
  `doctor` text/JSON in this repo, and isolated live no-wiki plus built-wiki
  doctor checks.
- Read Cosmic Python chapter 4 on service layers and sent a Relayforge Discord
  checkpoint. The applied lesson: `serve` is an HTTP entrypoint over a viewer
  service, not a second parser, SQLite client, or CLI shell-out.
- Added slice-9 local `serve`: FastAPI server adapter, Uvicorn CLI runtime,
  `ViewerService`, explicit Pydantic viewer DTOs, markdown-it-py rendering with
  HTML disabled, and bundled static assets.
- Verified slice 9 with 53 passing tests, ruff, `git diff --check`, live
  `codealmanac serve --port 49217`, API dogfood for overview/search/page,
  CLI help, serve help, and `uv build` wheel inspection confirming viewer
  assets are packaged. Browser-harness could not attach because Chrome requires
  the manual remote-debugging permission click.
- Slice-9 review fixed index freshness semantics exposed by `serve`.
  `ensure_fresh` now computes a source signature and skips SQLite projection
  writes when page fingerprints and `topics.yaml` are unchanged; `reindex`
  remains the explicit forced rebuild. Re-verified with 55 passing tests, ruff,
  live `codealmanac serve --port 49219`, API dogfood for overview/search/page,
  and a SQLite trigger proving warm read traffic did not rewrite `pages`.
- Read Cosmic Python chapters 6, 8, and 10 before the first lifecycle seam and
  sent a Relayforge Discord checkpoint for the Commands vs Events pattern. The
  applied lesson: future lifecycle starts are commands that fail loudly, while
  run-log entries are past-tense facts recorded by the `runs` service.
- Added slice-10 runs ledger and `jobs` read surface: `RunsService`, JSON/JSONL
  run storage under `.almanac/jobs/`, typed run records/events/status enums,
  and `codealmanac jobs`, `jobs show`, and `jobs logs`.
- Verified slice 10 with focused runs/CLI tests, 59 passing full tests, ruff,
  `git diff --check`, and an isolated live dogfood run that created a run
  through `RunsService` and read it back through `codealmanac jobs`, `jobs show`,
  `jobs logs`, and `jobs --json`.
- Read Cosmic Python chapter 11 on external events before the source-input
  slice and sent a Relayforge Discord checkpoint. The applied lesson: raw
  outside-world inputs should be translated at the boundary into typed messages
  before workflows or agents see them.
- Added slice-11 source input contracts: `SourcesService`, `SourceAddress`,
  `SourceRef`, `SourceBrief`, source kind/provenance enums, local path
  observations and fingerprints, GitHub PR/issue refs and URLs, generic web
  URLs, git range/diff refs, and transcript refs. URL decomposition uses
  `urlsplit`, while validity uses Pydantic `AnyHttpUrl`.
- Verified slice 11 with focused source tests, 64 passing full tests, ruff,
  `git diff --check`, and a live service dogfood run that resolved a mixed
  source input tuple into typed source briefs.
- Read Cosmic Python chapters 4 and 13 before the harness seam and sent a
  Relayforge Discord checkpoint. The applied lesson: use cases belong behind
  services/workflows, while `app.py` wires dependencies.
- Added slice-12 harness contracts: `HarnessKind`, `HarnessRunStatus`,
  `HarnessReadiness`, `HarnessRunResult`, `RunHarnessRequest`,
  `HarnessAdapter`, and `HarnessesService`.
- Verified slice 12 with focused harness tests, 68 passing full tests, ruff,
  `git diff --check`, and a live fake-adapter dogfood run through
  `HarnessesService.check()` and `HarnessesService.run(...)`.
- Read Cosmic Python chapters 8 and 10 before wiring `ingest`. The applied
  lesson: `RunIngestRequest` is a command that fails loudly, while run ledger
  entries are events that record facts.
- Added slice-13 internal ingest workflow. It starts a run, resolves sources,
  renders a Pydantic JSON prompt payload, calls the harness service, validates
  changed files under `.almanac/`, refreshes the index, and marks the run done
  or failed.
- Refactored the app composition surface to `app.workflows.build` and
  `app.workflows.ingest`, matching the live agreement.
- Verified slice 13 with focused ingest/harness tests, 73 passing full tests,
  ruff, `git diff --check`, and an isolated fake-harness dogfood run that wrote
  a wiki page, refreshed the index, and read back search plus run-log state.
- Read Cosmic Python chapter 3 before the first concrete harness adapter and
  sent a Relayforge Discord checkpoint. The applied lesson: workflows depend on
  the `HarnessAdapter` abstraction while Claude subprocess details stay in
  `integrations/harnesses/claude`.
- Added slice-14 Claude CLI adapter. It uses `claude auth status` for readiness,
  `claude -p --output-format json` for runs, Pydantic models for external JSON,
  and git porcelain status snapshots to report changed files.
- Added an architecture test that prevents `cli/`, `workflows/`, and
  `services/` from importing concrete integrations.
- Dogfooded real Claude ingest in a temp Git repo. Claude wrote one
  `.almanac/pages` page, ingest finished successfully, the index refreshed to
  two pages, and search found the new page. The run exposed a naming prompt bug
  (`almanac CLI`), so the ingest prompt now states the public CLI name is
  `codealmanac`, never `almanac` or `alm`.
- Read Cosmic Python chapter 6 before hardening ingest mutation safety and sent
  a Relayforge Discord checkpoint. The applied lesson: a lifecycle write needs
  a stable operation snapshot, but filesystem writes cannot honestly roll back
  like database transactions.
- Added slice-15 ingest mutation safety. `WorkspaceChangeProbe` is a
  workspace-owned port, `GitWorkspaceChangeProbe` parses `git status
  --porcelain=v1 -z --untracked-files=all`, and `IngestMutationPolicy` requires
  Git change tracking, clean `.almanac/` preflight, and no non-wiki mutations
  during the harness run.
- Verified the slice-15 focused behavior with parser, ingest workflow, and
  architecture tests. The workflow allows pre-existing dirty app files when
  unchanged, rejects harness mutation to dirty app files, rejects dirty
  `.almanac/` preflight, and rejects non-Git lifecycle writes.
- Dogfooded slice-15 in a temp Git repo with a dirty `src/app.py` and a fake
  harness writing `.almanac/pages/safety-dogfood.md`. The run finished `done`,
  `result.safety.changed_files` contained only the wiki page, `src/app.py`
  preserved the user's dirty edit, and search found `safety-dogfood`.
- Read Cosmic Python chapters 4 and 10 before exposing public ingest. No new
  pattern checkpoint was sent because the applied command-vs-event and thin
  service-layer lessons were already recorded in earlier slices.
- Added slice-16 public `codealmanac ingest`. The CLI adapts argv into
  `RunIngestRequest`, defaults `--using` to `claude`, accepts `--using codex`
  as the existing harness enum for future adapter parity, and renders a short
  run/source/wiki-change summary.
- Real CLI dogfood exposed two issues before the final success: Claude prompt
  input had to move from a positional argument to stdin because `--tools` is
  variadic, and workflow errors needed to include harness output text. Both are
  fixed and covered by focused tests.
- Dogfooded real `codealmanac ingest note.md --using claude` in a temp Git repo
  after backing up and restoring the local registry. Claude created
  `.almanac/pages/ingest-cli-thin-adapter.md`, search found
  `ingest-cli-thin-adapter`, and Git status showed only that wiki page changed.
- Read Cosmic Python chapter 2 before Codex adapter work and sent a Relayforge
  Discord checkpoint. The applied lesson: the port is the application-facing
  interface, adapters are concrete implementations behind it, and fakes are
  design feedback when they are hard to write.
- Added slice-17 Codex CLI adapter. `CodexCliHarnessAdapter` uses
  `codex login status` for readiness and `codex exec` for runs. It sends the
  prompt on stdin, requests ephemeral workspace-write execution, disables user
  MCP servers with `--config mcp_servers={}`, sets noninteractive approval via
  `--config approval_policy="never"`, and reads the final assistant message
  from `--output-last-message`.
- Moved shared command runner and Git-status delta helpers out of the Claude
  adapter into `integrations/harnesses/command.py` and
  `integrations/harnesses/git_status.py`, so Claude and Codex are peer adapters
  behind the same port.
- Real Codex smoke exposed that this installed `codex exec` rejects
  `--ask-for-approval` and `-a` even though broader help text advertises an
  approval option. The adapter uses the accepted config override instead.
- The first Codex dogfood attempt used `uv run --directory`, which changed the
  process cwd to the CodeAlmanac checkout instead of the temp repo. The run was
  interrupted, and its relevant generated page was kept as
  `.almanac/pages/codex-cli-harness-adapter.md`. Future temp-repo dogfood should
  call the venv `codealmanac` executable directly or otherwise preserve cwd.
- Corrected real `codealmanac ingest note.md --using codex` dogfood in a temp
  Git repo created `.almanac/pages/codex-adapter.md`, search found
  `codex-adapter`, and Git status showed only that wiki page changed.
- Review during slice-17 found an ingest safety ordering bug: failed harness
  results were validated before the after-run Git snapshot. The workflow now
  checks mutation safety before harness status, so failed providers cannot hide
  non-wiki file mutations behind an `ExecutionFailed`.
- Read the live agreement, lifecycle wiki pages, and archived Garden operation
  reference before slice 18. No new Cosmic checkpoint was sent because the
  service-layer, command/event, and adapter-port lessons were already being
  applied directly.
- Added slice-18 public `codealmanac garden`. `GardenWorkflow` prepares index
  and health context, records a run, validates clean `.almanac/` preflight,
  calls the selected harness, validates mutations, refreshes the index, and
  marks the run done or failed.
- Added packaged prompt resources under `src/codealmanac/prompts/`. Ingest and
  Garden now compose shared base doctrine plus operation-specific Markdown and
  typed runtime JSON through `PromptRenderer`.
- Generalized ingest mutation safety into `LifecycleMutationPolicy`, so Garden
  reuses the same Git snapshot guard without inheriting ingest-specific error
  language.
- Verified slice 18 with 101 passing tests, ruff, `git diff --check`, CLI
  help for top-level and `garden`, package build with prompt Markdown in the
  wheel, and real temp-repo `codealmanac garden --using codex` dogfood. The
  dogfood run added the existing `concepts` topic to
  `.almanac/pages/thin-dogfood-note.md` and changed no application files.
- Read the live agreement, current sync/product notes, and Cosmic Python
  chapter 13 before slice 19. The applied lesson: `app.py` wires transcript
  discovery adapters into the source service, while CLI only adapts flags into
  `RunSyncStatusRequest`.
- Added slice-19 read-only `codealmanac sync status`. It discovers local Codex
  and Claude transcript JSONL files, maps sessions back to repos with
  `.almanac/`, applies a quiet window, reads the per-repo sync cursor ledger,
  and reports ready/skipped/needs-attention status without invoking AI or
  writing wiki content.
- Added `services/sources/ports.py` and transcript discovery adapters under
  `integrations/sources/transcripts/`. Raw provider JSON stays at the
  integration edge and becomes typed `TranscriptCandidate` models before the
  sync workflow sees it.
- Added `humanfriendly` for `--quiet` duration parsing instead of hand-rolling
  a duration grammar.
- Deliberately did not expose full `codealmanac sync` execution in this slice.
  Safe execution needs provider transcript identity feedback from harness runs
  so sync can skip CodeAlmanac's own Ingest/Garden transcripts.
- Verified slice 19 with focused transcript discovery, sync workflow, CLI, and
  architecture tests, 107 passing full tests, ruff, `git diff --check`, CLI
  help/status smoke, package build, and an isolated synthetic Codex transcript
  dogfood.
- Added slice-20 harness transcript feedback. `HarnessRunResult` can now carry
  a typed `HarnessTranscriptRef`, and `RunRecord` persists it as
  `harness_transcript`.
- `RunsService.record_harness_transcript(...)` records provider transcript
  identity before a lifecycle run is marked done or failed. Ingest and Garden
  call it immediately after the harness returns, before mutation validation or
  provider-status validation.
- Claude attaches the structured `session_id` from `claude -p --output-format
  json`. Codex uses a best-effort local transcript lookup over `.codex/sessions`
  after `codex exec` starts, matching fresh JSONL session metadata by `cwd` and
  skipping subagent sessions.
- `codealmanac jobs show <run-id>` now displays the stored harness transcript
  session id and path when present.
- Verified slice 20 with focused runs, Ingest, Garden, Claude adapter, Codex
  adapter, and jobs CLI tests, full pytest, ruff, `git diff --check`, and a
  live temp-repo `jobs show` smoke that displayed the stored transcript id.
- Added slice-21 internal lifecycle transcript exclusion to `sync status`.
  `SyncWorkflow` now loads repo-local run records through `RunsService` and
  skips discovered transcripts that match a stored `harness_transcript` by
  provider kind plus session id or transcript path.
- The skip reason is `internal-lifecycle-transcript`. This keeps the
  read-only status gate aligned with the future write-capable sync path without
  starting Ingest yet.
- Verified slice 21 with focused sync workflow tests, 109 passing full tests,
  ruff, `git diff --check`, and an isolated `sync status` dogfood where
  `internal-session` was skipped and `ordinary-session` was ready.
- Added slice-22 foreground `codealmanac sync`. `SyncWorkflow.run(...)` reuses
  the status evaluator, calls `IngestWorkflow.run(...)` for each ready
  transcript, and advances `.almanac/jobs/sync-ledger.json` only after Ingest
  succeeds.
- Sync passes transcript source material as `transcript:<absolute path>` and
  adds cursor guidance telling Ingest which transcript line range is new.
- Deliberately kept pending cursor state out of this foreground slice. The
  archived TypeScript pending model requires a real background owner and
  reconciliation loop; without those, commit-after-success is the safer Unit of
  Work boundary.
- Verified slice 22 with focused sync workflow and CLI tests, 111 passing full
  tests, ruff, `git diff --check`, and an isolated foreground sync dogfood that
  wrote `foreground-sync-dogfood.md` and advanced the sync ledger.
- Added slice-23 local automation. `AutomationService` owns the scheduled task
  plan for `sync` and `garden`, while `LaunchdSchedulerAdapter` is a concrete
  port implementation that writes plist files through Python `plistlib` and
  calls launchctl.
- `codealmanac automation install|status|uninstall` now exists. Default
  install selects sync plus Garden; explicit task selection accepts only
  `sync` and `garden` in v1. Garden install resolves the current wiki root as
  launchd `WorkingDirectory`; status and uninstall can run outside a repo.
- Deliberately did not add update automation or legacy capture migration.
  Python `codealmanac update` and background sync reconciliation are separate
  product debts.
- Verified slice 23 with focused automation service, CLI automation, and
  architecture tests, 118 passing full tests, full ruff, `git diff --check`,
  and a safe `automation status --json` smoke under a temporary `HOME`.
  The smoke showed plist state and launchd loaded state are independent: a
  same-label job may be loaded even when the temp HOME has no plist.
- Added slice-24 Git source runtime. `SourceRuntime` snapshots now sit after
  `SourceBrief`, and `IngestWorkflow` includes both source briefs and runtime
  snapshots in the agent prompt.
- Added `SourceRuntimeAdapter` under `services/sources/ports.py` and a concrete
  Git CLI adapter under `integrations/sources/git/`. The adapter captures
  status, stats, diffs, and commit lists for `git:diff`, `git:diff:<target>`,
  and `git:range:<range>`.
- Deliberately did not add GitHub PR/issue fetching in slice 24. GitHub should
  reuse the same source-runtime port through `gh` or another local
  source-access adapter.
- Verified slice 24 with focused source, ingest, CLI ingest, and architecture
  tests, 120 passing full tests, full ruff, `git diff --check`, and a temp-repo
  dogfood where real Git runtime carried a dirty `git:diff` into the Ingest
  prompt before a fake harness wrote `git-runtime-dogfood.md`.
- Added slice-25 GitHub source runtime. `GitHubSourceRuntimeAdapter` reads PR
  and issue refs through GitHub CLI, validates `gh --json` output with Pydantic
  models, renders bounded source text, and returns `unavailable` runtime
  snapshots when local GitHub access is missing.
- Moved the shared subprocess runner from `integrations/harnesses/command.py`
  to `integrations/command.py` after GitHub became the second non-harness
  caller. Harness Git-status helpers remain under `integrations/harnesses/`.
- Verified slice 25 focused behavior with GitHub runtime, source service,
  ingest prompt, and architecture tests. Full verification and live dogfood are
  recorded in `verification-matrix.md`.
- Added slice-26 transcript source runtime. `TranscriptSourceRuntimeAdapter`
  resolves `transcript:<path>` refs, reads local provider JSONL through the
  `jsonlines` package, validates known Codex and Claude line shapes with
  Pydantic models, renders line-numbered source material, and truncates from
  the tail because sync transcript sources are append-only.
- Foreground sync now benefits from source runtime directly: it still passes
  `transcript:<absolute path>` and cursor guidance to Ingest, but the Ingest
  prompt also includes readable transcript content before the harness runs.
- Added slice-27 web source runtime. `WebSourceRuntimeAdapter` fetches generic
  `SourceKind.WEB_URL` refs with `httpx`, parses HTML/text material at the
  integration edge, validates the normalized response with Pydantic models,
  strips non-readable HTML nodes with Beautiful Soup, and returns bounded
  `SourceRuntime` snapshots or `unavailable` diagnostics for HTTP/binary
  failures.
- Verified slice 27 with focused web/source/ingest/architecture tests, 134
  passing full tests, full ruff, diff hygiene, package build, wheel dependency
  inspection, and a temp-repo dogfood where real `https://example.com/` content
  reached the Ingest prompt before a fake harness wrote
  `web-runtime-dogfood.md`.
- Added slice-28 filesystem source runtime. `FilesystemSourceRuntimeAdapter`
  reads selected path files and bounded directory material through the same
  source-runtime port, decodes text with `charset-normalizer`, applies
  gitignore-style directory filtering with `pathspec`, skips generated/private
  directories during traversal, and makes ordinary `note.md` Ingest inputs
  available in the prompt instead of skipped runtime metadata.
- Verified slice 28 with focused filesystem/source/ingest/architecture tests,
  140 passing full tests, full ruff, diff hygiene, package build plus wheel
  dependency inspection, and a temp-repo dogfood where local `notes.md` and
  `src/` inputs reached the Ingest prompt while `.gitignore`d text stayed out.
- Added slice-29 manual update command. `services/updates` now plans foreground
  package-manager updates from install metadata, supports uv tool and pip
  installs, refuses editable/source installs, and delegates metadata reads plus
  command execution to `integrations/updates/`.
- Verified slice 29 focused behavior with update service, CLI update, doctor,
  and architecture tests, focused ruff, and live editable-install checks:
  `update --check`, `update --check --json`, and default `update` which
  refused mutation with `run: git pull && uv sync`.
- Added slice-30 viewer file route. `ViewerService.file(...)` returns pages
  that mention a file or folder reference through the existing index mentions
  query. `/api/file?path=src/foo.py` and frontend `#/file/<path>` restore the
  old viewer graph-navigation behavior without reading repo source contents.
- Verified slice 30 focused behavior with viewer service/server tests and
  focused ruff before full verification.
- Added slice-31 Git-backed filesystem directory listing. Directory runtime now
  asks Git for `--cached --others --exclude-standard` files when the selected
  directory is inside a worktree, then falls back to the bounded Python/pathspec
  walk when Git cannot answer. Runtime metadata records `listing_source: git`
  or `listing_source: walk`.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 13 pattern
  applied in slice 31: explicit dependency on a `CommandRunner` abstraction
  instead of hardcoded subprocess calls or monkeypatching.
- Added slice-32 changed-first filesystem directory selection. Git-listed
  directories now ask `git status --porcelain=v1 -z --untracked-files=all` for
  the selected path, rank changed and untracked files before unchanged files,
  and annotate the runtime tree with `changed` or `unchanged` state.
- Dogfood against this repo's dirty `src/codealmanac/` directory selected the
  changed filesystem adapter and selector files first before unchanged
  `app.py` and `cli/main.py`, proving broad-directory prompt material now
  follows the current slice instead of alphabetical path order.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 5 pattern
  applied in slice 32: high-gear tests drive the source service runtime
  contract instead of freezing private selector helper details.
- Added slice-33 public contract guards. `tests/test_public_contract.py`
  verifies the only script entry point is `codealmanac`, hosted and alias
  commands are rejected by the parser, and the Python package does not expose
  `sdk` or `mcp` modules.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 4 pattern
  applied in slice 33: the CLI stays an outer adapter over local service-layer
  use cases rather than growing hosted product modes.
- Added slice-34 manual surface. `src/codealmanac/manual/` now packages the
  wiki-maintenance rulebook, `WikiService.initialize(...)` copies missing
  files into `.almanac/manual/`, `DiagnosticsService` reports bundled and
  workspace manual readiness, and lifecycle prompts point agents at the
  operation-specific manual files.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 13 pattern
  applied in slice 34: `ManualLibrary` is wired once in `app.py` and injected
  into services instead of making CLI/build/doctor locate resources directly.
- Added slice-35 sync pending claims. Foreground `sync` now writes a durable
  pending ledger entry before invoking Ingest, records owner/start/range
  fields, skips active pending transcript ranges, reports stale pending ranges
  as needs-attention, and clears pending fields on success or failure.
- Dogfood for slice 35 exposed a macOS temp-path mismatch: a ledger entry
  written with `/var/...` did not match transcript discovery returning
  `/private/var/...`. Sync ledger keys now use normalized paths, and lookup can
  match a stored entry by normalized app/session/transcript identity.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 6 pattern
  applied in slice 35: sync needs an explicit durable pending claim before the
  side-effecting Ingest run, so the cursor update has an atomic checkpoint.
- Added slice-36 run lifecycle state. `RunsService` now exposes
  `mark_running(...)`, `RunStore` enforces `queued -> running -> terminal`
  transitions, and Ingest/Garden mark run records running before their
  side-effecting work begins.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 7 pattern
  applied in slice 36: the run record is the consistency boundary for
  lifecycle state, so future sync reconciliation can trust status instead of
  inferring execution from logs.
- Added slice-37 sync pending run linkage. `IngestWorkflow` now has an internal
  `start(...)` plus `run_with_run(...)` split beneath the existing public
  `run(...)` method. Foreground `sync` creates the Ingest run, writes a pending
  ledger claim with `pending_run_id`, claimed byte size, prefix hash, and line
  range, then executes Ingest with that run id.
- Sync status now reports linked active runs as `sync-pending-run-active` and
  linked terminal done runs as `sync-pending-run-done`. Foreground sync
  reconciles terminal linked runs before cursor evaluation, promoting done
  pending cursors or clearing failed/cancelled pending claims so retry starts
  from the last successful cursor.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 8 pattern
  applied in slice 37: run lifecycle transitions are durable facts, and sync
  reconciliation reacts to those facts at the workflow boundary rather than
  hiding policy inside transcript adapters or CLI glue.
- Added slice-38 database boundary. `codealmanac.database` now owns SQLite
  connection setup, row factory/PRAGMA policy, parent directory creation, and
  typed migration application. `services/index/store.py` still owns the
  `index.db` schema, FTS/search/topic/health SQL, and row conversion.
- Added an architecture guard that rejects direct `sqlite3` imports outside
  `database/`. This keeps future stores from bypassing the shared SQLite
  mechanics while still allowing store-owned schemas and queries.
- Sent a Relayforge Discord checkpoint for the Cosmic Python chapter 2 and
  chapter 6 patterns applied in slice 38: the store remains the repository for
  product persistence behavior, while database mechanics and migration
  application are infrastructure owned by `database/`.
- Added slice-39 local config boundary. `services/config` now owns
  `~/.almanac/config.toml` and `.almanac/config.toml` parsing through
  `pydantic-settings`, validates values with a frozen settings model, and
  merges defaults, user config, and selected-project config before CLI flags
  apply.
- `ingest`, `garden`, `sync`, `sync status`, and `automation install` now
  resolve lifecycle defaults through `app.config` instead of embedding product
  defaults in argparse. The first supported config fields are
  `[harness].default` and `[sync].quiet`.
- User clarified after slice 39 that the Python rewrite is for new users, not
  backward compatibility with old TypeScript installs. The repo Almanac root
  must become configurable and default to `almanac/`, with `docs/almanac/` or
  `.almanac/` available only by configuration. At that point, hard-coded
  `.almanac/` assumptions in workspace paths, prompts, tests, safety checks,
  and dogfood docs became product debt, not the target shape.
- Added slice-40 CLI edge split. `src/codealmanac/cli/main.py` now only owns
  parser invocation, known error formatting, and app dispatch. Parser
  construction lives under `cli/parser/` and is split into lifecycle, wiki, and
  admin command domains. Dispatch and render moved out of `main.py` into
  `cli/dispatch/root.py` and `cli/render/root.py`; they remain broad but are no
  longer mixed into the process entrypoint.
- Added slice-41 configurable Almanac root. `services/workspaces` now owns
  repo-relative root validation and nearest-root discovery. New repos default
  to `almanac/`; `init --root docs/almanac` and explicit
  `init --root .almanac` are supported setup choices. The registry stores
  `almanac_root`, downstream services use `workspace.almanac_path`, sync
  transcript candidates carry `almanac_path`, project config lives under the
  configured root, run log references use the configured root, prompts/manual
  say "configured Almanac root", and index health no longer assumes
  `almanac_path.parent` is the repo root.
- Added slice-42 source runtime context. `InspectSourceRuntimeRequest` now
  carries `SourceRuntimeContext`, Ingest fills it from
  `workspace.almanac_root`, and filesystem directory runtime applies those
  ignored directories for both Git listing and Python/pathspec traversal. The
  filesystem adapter no longer hard-codes `almanac/`, `docs/almanac/`, or
  `.almanac/` as product roots.
- Added slice-43 scheduled sync retry policy. Automation now installs scheduled
  sync with a stable claim owner, a 24h pending timeout, and a failed-attempt
  budget of 3. `SyncLedgerEntry.failed_attempts` increments after failed
  transcript Ingest attempts and exhausted failed entries report
  `sync-retry-budget-exhausted` instead of retrying forever.
- Added slice-44 clean directory diversity. Filesystem runtime now ranks
  changed/untracked candidates first, then interleaves clean directory groups
  and prefers role-bearing files. Dogfood against `src/codealmanac/` now keeps
  the changed filesystem files first and then includes service/workflow groups
  instead of spending the bound on shallow package files.
- Added slice-45 viewer renderer token-safety tests. The local viewer rewrites
  wikilinks through `markdown-it-py` tokens, touches only inline text tokens,
  leaves inline/fenced code untouched, and relies on renderer escaping for link
  labels.
- Added slice-46 serve visual port. The local viewer now borrows the
  UseAlmanac alpine dashboard visual language while keeping CodeAlmanac's
  existing local wiki model: sidebar navigation, page/topic/search/file-reference
  routes, page graph context, and repo-owned read-only pages.
- Downloaded Bulletproof React Markdown reference into
  `docs/reference/bulletproof-react/` and added a CodeAlmanac note. It is a
  structure reference for future frontend growth, not a mandate to add
  React/Next.js to the current static viewer.
- Verified slice 46 with focused viewer/server tests, focused ruff, 221
  passing full tests, full ruff, `git diff --check`, `uv build`, wheel asset
  inspection, and browser-harness desktop/mobile checks.
- Added slice-47 viewer frontend modules. `app.js` is now a small ES module
  entrypoint, nested package assets under `server/assets/viewer/` split API,
  routing, shared DOM components, and screen renderers, and the FastAPI server
  validates nested asset paths before serving them.
- Verified slice 47 with 12 focused viewer/server tests, focused server ruff,
  222 passing full tests, full ruff, `git diff --check`, `uv build`, wheel
  inspection for nested viewer modules, and browser-harness desktop/mobile
  checks that loaded `/app.js` plus `/assets/viewer/*.js`.
- Slice-47 review fixed malformed hash handling. Route parsing now runs inside
  the viewer error boundary, and title updates use cached DOM elements instead
  of re-querying the document. The branch-head package build still includes all
  nested viewer modules.
- Added slice-48 update install dogfood. A wheel-installed pip venv and a
  throwaway uv tool install both report non-editable metadata correctly and
  plan the expected package-manager commands. Dogfood showed a successful uv
  upgrade can say `Nothing to upgrade`, so update run status now reports
  `completed` for exit code 0 instead of over-claiming `updated`.
- Added slice-49 CLI admin edge split. `doctor`, `update`, `jobs`, and
  `automation` now dispatch through `cli/dispatch/admin.py`; admin rendering
  lives in `cli/render/admin.py`; shared CLI config/duration helpers live in
  `cli/dispatch/config.py`. Architecture tests keep admin request/result types
  out of root dispatch/render, matching the Cosmic Python entrypoint-adapter
  reading from chapters 4 and 13.
- Added slice-50 index read views. `IndexStore` remains the facade and
  projection writer, while `services/index/views.py` owns read-only SQL for
  search, pages, topics, and health. Architecture tests keep the view module
  free of markdown loading, migrations, and write SQL, matching Cosmic Python
  chapter 12's read-view split without adding full CQRS machinery.

## Current Hypothesis

The read and organization paths now cover the main local wiki management loop:
search/show, topic reads, health, tag/untag, topic DAG mutation including
rename/delete, explicit `build`, `reindex`, `doctor`, and a first read-only
local `serve` viewer. The first lifecycle/runs spine now exists as a ledger and
read surface. Source inputs, prompt rendering, harness execution, mutation
safety, and run logging now have typed service/workflow boundaries. Claude and
Codex CLI adapters are wired through the app composition root. Public `ingest`
and `garden` commands reach their workflows without making the CLI an internal
API. Run records now move through queued, running, and terminal states under
the `runs` service. `sync status` now exposes read-only local transcript readiness behind the
same service/workflow/adapter boundaries, and it skips provider transcripts
that came from CodeAlmanac lifecycle runs. Lifecycle runs retain optional
provider transcript identity for that exclusion. Foreground `sync` now runs
ordinary Ingest work for ready transcripts, writes a durable pending claim
before Ingest, stores the linked run id plus claimed cursor, reconciles terminal
linked runs against run state, advances the sync ledger after success, and
reports stale or unreconciled pending work as needs-attention. Local automation now installs scheduler
entries for foreground sync and Garden through a service-owned task plan and a
launchd adapter. Git,
GitHub, transcript, web URL, and local path source refs now produce bounded
runtime snapshots before Ingest starts the harness. Manual `update` now exists
as a conservative package-manager command and does not install scheduled update
automation. The viewer file route is now graph navigation over indexed file
references, not source-code preview. Filesystem directory runtime now uses Git
listing inside worktrees before falling back to Python/pathspec traversal, and
Git-listed directories rank changed material before unchanged files. The
local-only public surface now has executable guards for hosted verbs,
compatibility aliases, SDK modules, and MCP modules. The manual surface now
exists as packaged doctrine plus workspace manual files without adding a public
command. The database spine now exists for SQLite connection
and migration mechanics, with `IndexStore` supplying the first store-owned
typed migration for the derived read model. Index read queries now live in
`services/index/views.py`, so projection writes and read-only views have
separate reasons to change. The local config seam now exists
for typed user/project TOML defaults, with no public `config` command or
hosted/account configuration surface. The target root has changed: new repos
should default to `almanac/` and all wiki docs plus local runtime artifacts
should resolve through the configured Almanac root.
The CLI edge now follows the same parser/dispatch/render package shape as the
sibling Almanac CLI, with architecture tests preventing `main.py` and parser
root from growing back into all-purpose modules. Admin dispatch/render is now
split by command domain for `doctor`, `update`, `jobs`, and `automation`, while
wiki/lifecycle dispatch stays in root until a concrete command change creates
pressure. The configured-root slice now
implements the new default `almanac/` root across setup, registry, index,
manual, runs, sync ledger, config, prompts, and lifecycle safety. Source
runtime now receives configured wiki-root ignore policy from Ingest rather than
guessing root names inside the filesystem adapter. Scheduled sync now remains
ordinary foreground sync but carries explicit unattended policy from automation
into the workflow request and durable ledger. Clean directory runtime now uses
adapter-local diversity selection before any future recency machinery. Viewer
wikilink rendering is now covered as a token-stream rewrite rather than a raw
HTML/string rewrite. The served viewer now has the intended visual direction:
UseAlmanac-style shell polish over CodeAlmanac's local sidebar/wiki graph IA,
not the hosted UseAlmanac page-list/search UX. The browser shell now has static
module boundaries that match the current UI size without adding React, Next.js,
or a build step. Slice 51 tightens that shell toward the earlier CodeAlmanac
sidebar interaction: repo-owned wiki rail wording, local knowledge graph scope,
active page/topic rail state, compact mobile rail density, and no
viewport-scaled type in served CSS.
Slice 52 adds manual drift diagnostics without changing the manual mutation
policy. `ManualLibrary.workspace_status(...)` now reports files that differ
from bundled package resources; `doctor` reports those differences as
informational review work while keeping missing manual files as build-fixable
problems. Build/init still copy missing manual files only and preserve existing
workspace manual text.
Slice 53 adds explicit registry cleanup to `codealmanac list`. Real-repo
source-runtime dogfood against `src/codealmanac/`, `services/sources/`, and
`integrations/sources/filesystem/` showed the current changed-then-diverse
selection was coherent enough for local v1. The stronger local-product gap was
registry hygiene: stale temp entries made `list` hard to use, while read
commands should not silently prune them. `WorkspacesService` now owns registry
status plus explicit drop/drop-missing use cases, and the CLI exposes
`list --json`, `list --drop <selector>`, and `list --drop-missing`.
Slice 54 hardens lifecycle run logs. `ingest` and `garden` now record the
returned harness status and first output line before mutation-safety validation
and harness success validation. Failed harness runs now leave an `output` event
before the terminal `error`, including the case where a failed harness also
mutates a non-wiki file and the run error correctly remains the safety failure.
Slice 55 turns that log line into a normalized harness event contract.
`HarnessRunResult.events` now carries typed text/tool/usage/warning/error/done
events. At slice 55, the Codex and Claude CLI adapters emitted terminal `done`
events, and `ingest`/`garden` persisted all returned events in order before
later validation. That kept `codex exec` acceptable until actual transcript
event completeness made Codex app-server necessary in slice 83.
Slice 56 shifts the work toward public-release proof. The old README still
advertised the Node/npm `almanac` and hosted-dashboard path, which would
mislead Python users. `README.md` now documents the Python `codealmanac` local
surface, `pyproject.toml` declares the README and license file, public-contract
tests guard the README against stale install language, and
`docs/python-port/public-release-readiness.md` names the release gate.
Slice 57 runs real Codex ingest dogfood through the Python service layer. The
first run proved the workflow, mutation safety, search/show, and jobs log path
with `CodexCliHarnessAdapter`, but `health` caught broken `[[workos]]` and
`[[autumn]]` page links. The fix stayed at the prompt/manual contract: page
wikilinks must resolve, and entity names stay plain text unless a real page
exists or is created in the same run. A second real Codex run on the same
source shape produced a health-clean page. The slice also removes predefined
empty scaffold topics so fresh init does not start with health noise.
Slice 58 runs real Claude ingest dogfood through the same Python service-layer
path. `ClaudeCliHarnessAdapter` wrote `incident-window-policy.md`, updated
`topics.yaml`, preserved mutation safety, recorded provider output in
`jobs logs`, and left `health --json` clean. The public CLI readback
(`jobs logs`, `search`, `show`, and `health --json`) worked against the temp
repo with an isolated registry. No prompt or code patch was needed.
Slice 59 runs real foreground sync dogfood against a transcript-shaped Codex
JSONL file in a temp home. Sync discovered one ready transcript, started real
Claude-backed Ingest run `ingest-20260629231810-40e74df3`, advanced the
sync ledger to `done`, then skipped the same transcript as `unchanged` on the
second status run. The generated `sync-workflow.md` page was health-clean, and
public CLI readback worked for `sync status`, `jobs logs`, `jobs show`,
`search`, `show`, and `health --json` when the unpublished branch was selected
with `uv run --project /Users/rohan/Desktop/Projects/codealmanac`.
Slice 60 reruns the current local `serve` viewer through browser-harness after
the lifecycle and sync evidence slices. A temp wiki with page links, topics,
searchable content, and file refs rendered correctly in desktop Chrome for the
overview, page, topic, search, and file routes. A 390px mobile page route also
rendered without horizontal overflow. No viewer code or CSS patch was needed.
Slice 61 runs the final package rehearsal from built artifacts. Wheel and
sdist builds passed after package metadata moved from deprecated license-table
syntax to SPDX `Apache-2.0` plus `license-files = ["LICENSE.md"]`. The
artifacts included README, license, server assets, manual files, prompts, and
the `codealmanac` console script. Clean Python 3.12.9 installs from both wheel
and sdist passed installed CLI smoke for `init`, `search`, `show`, `topics`,
`health`, `jobs`, `sync status`, `doctor`, and `serve`. A Python 3.11 install
attempt failed with the expected `requires-python >=3.12` guard.
Slice 62 cleans the release path after the package rehearsal exposed a
maintainer-facing mismatch. `RELEASE.md` still described the archived npm
release flow, so it now documents the Python/PyPI flow: pytest, ruff, diff
check, `uv build`, `uvx twine check`, clean wheel/sdist install smoke, and
`uvx twine upload`. `pyproject.toml` now includes PyPI-facing author,
keyword, classifier, repository, and issue metadata. The first classifier pass
included the old Apache license classifier, and setuptools rejected it because
PEP 639 license expressions supersede license classifiers. The final metadata
keeps SPDX `Apache-2.0` and removes the license classifier. Public-contract
tests guard the Python release guide and package metadata.
Slice 63 fixes a local diagnostics/read-model hygiene gap found by dogfooding
`codealmanac doctor` in this repo before the repo's default `almanac/` root had
been built. The old path treated a registered workspace as available if the
configured root directory existed, so `doctor` could create
`almanac/index.db`, then `list --json` would report that derived-only directory
as an available wiki. Root discovery and registry status now require a wiki
marker pair (`topics.yaml` plus `pages/`), `IndexStore` refuses to open
SQLite for a missing root, and `doctor` reports the missing registered root
without cascading into index/manual/health checks. This repo's `.gitignore`
also ignores default-root runtime artifacts under `almanac/`.
Slice 64 tightens the public README after release-surface review found that the
"What Gets Created" tree mixed `init` scaffold files with runtime artifacts.
A live temp-repo `codealmanac init` created `.gitignore`, `README.md`,
`topics.yaml`, `pages/getting-started.md`, and bundled manual files, but not
`config.toml`, `jobs/`, or `index.db`. The README now separates
`What Gets Created By Init` from `Runtime State`, and public-contract tests
guard that the init section stays source-only.
Slice 65 dogfoods the README quickstart itself. A fresh temp repo proved that
`codealmanac search "auth"` returns zero results immediately after `init`,
because the starter wiki contains `getting-started`, not an auth page. The
quickstart now uses `codealmanac search "getting"` so a new user sees the
starter page on the first search. Public-contract tests guard the quickstart
section against drifting back to a non-starter search term.
Slice 66 checks the README lifecycle examples against the source abstraction.
`codealmanac ingest docs/adr.md --using codex` parsed but resolved as a missing
path in this checkout because `docs/adr.md` does not exist. The README now uses
`codealmanac ingest README.md --using codex`, which resolves as a real
`path.file`, while `github:pr:123` remains valid as the supported GitHub PR
shorthand. Public-contract tests now parse the lifecycle examples and resolve
the documented source refs through `SourcesService`.
Slice 67 makes the next-agent brief part of the public continuation contract.
The brief had lagged behind the actual slice trail: its top checkpoint still
said slice 62 after slices 63 through 66 had landed. Public-contract tests now
discover the newest `docs/python-port/slice-N-*.md` file and require the
brief's current-state section to mention that slice number.
Slice 68 turns the public beta gate into a concrete audit. The new
`docs/python-port/public-beta-gate-audit.md` records status, evidence, and
remaining risk for every row in `public-release-readiness.md`. The audit says
the local product gates are mostly covered, but public beta should still wait
for a current-head package rehearsal and one more real lifecycle dogfood pass
against a non-toy project source shape. Public-contract tests now compare the
gate areas in the readiness doc against the audit so the audit cannot silently
fall out of coverage.
Slice 69 completes the current-head package rehearsal. `uv build` produced a
wheel and sdist under `/tmp/codealmanac-release-slice69`; `twine check` passed;
stdlib package inspection confirmed README, Apache-2.0 license metadata,
license file, server assets, manual files, and prompt files. Clean uv-managed
Python 3.12.9 environments installed both artifacts and ran installed CLI smoke
for `--help`, `init`, `search`, `show`, `topics`, `health`, `jobs`,
`sync status`, `doctor`, `serve`, and `update --check`. The shell did not have
`python3.12`, so the smoke used `uv venv --python 3.12`.
Slice 70 closes the remaining lifecycle dogfood blocker. A temp repo copied
real CodeAlmanac source-runtime, filesystem adapter, ingest workflow, prompt,
and live-agreement files, then public `codealmanac ingest ... --using claude`
created `almanac/pages/source-runtime-flow.md`. The page accurately described
`SourceAddress -> SourceRef -> SourceBrief -> SourceRuntime`, `SourcesService`,
filesystem runtime selection, ingest prompt consumption, and source-runtime
gotchas. `health --json` was clean and `jobs logs` recorded queued, running,
preflight, source resolution, runtime loading, Claude success, and done events.
The dogfood also exposed that default user config still pointed at
`~/.almanac/config.toml`, where this machine had stale old-product `[agent]`
config. The fix moves default user/global state to `~/.codealmanac/` while
keeping repo wiki roots under `almanac/`.
Slice 71 reruns current-head package proof after the slice 70 README and
state-path changes. `uv build` produced wheel and sdist artifacts under
`/tmp/codealmanac-release-slice71`; `twine check` passed; package inspection
confirmed Apache-2.0 metadata, `>=3.12`, README metadata containing
`~/.codealmanac/`, server assets, manual docs, prompts, and `core/paths.py`.
Clean Python 3.12.9 wheel and sdist installs ran installed CLI smoke for
`--help`, `init`, `search`, `show`, `topics`, `health`, `jobs`, `sync status`,
`doctor`, `update --check`, and live `serve` HTTP routes. Both installed
artifacts wrote registry state under `~/.codealmanac/registry.json` and did not
create `~/.almanac/registry.json` in the temp homes.

## Next Hypothesis

The next high-pressure product slice is release review and prompt-quality
dogfood, not another root or sync migration. Scheduled update checks should wait
for a notifier policy. The remaining source-runtime pressure is lifecycle
dogfood, not a missing selection mechanism. The remaining serve risk is polish
and product review of navigation density, especially the compact mobile rail.
Browser-harness should still verify visual changes, using an isolated temporary
Chrome profile with explicit `BU_CDP_URL` when the default Chrome profile
requests the remote-debugging Allow prompt.
After slice 48, the next update pressure is no longer install detection; it is
the product policy for notification cadence, dismissal, and release channels
before any scheduled update automation exists. After slice 49, the next CLI
pressure is not "split every file"; it is to wait for wiki or lifecycle command
changes that justify their own dispatch/render domains. After slice 50, index
refresh cost is still a dogfood question, not something the read-view split
pretends to solve.
After slice 55, the next Codex harness pressure is event completeness, not
parity for its own sake. `codex exec` remains a one-shot writer transport;
Codex app-server belongs back on the table when jobs need normalized text,
tool, usage, actor, or root-turn events from the run itself.
After slice 61, public release should be measured against
`docs/python-port/public-release-readiness.md`: package proof has passed, so
remaining work is release judgment and prompt-quality review from more real
source shapes.
After slice 68, release judgment is recorded in
`docs/python-port/public-beta-gate-audit.md`. The next product pressure is not
another architecture seam; it is current-head package rehearsal plus one more
real lifecycle dogfood run.
After slice 69, current-head package rehearsal is done. After slice 70, the
remaining public-beta implementation gate is also covered. After slice 71,
package proof is current again after the state-path change. The next pressure
is release operations: version/changelog, PyPI credentials, and the human
publish decision. Any package data, prompt, manual, README, server asset, or
installed-behavior change before publish should trigger another package/install
smoke.
Slice 72 reopens architecture quality work under the new active goal. The CLI
root dispatcher is now a small delegator, lifecycle commands live in
`cli/dispatch/lifecycle.py`, and wiki/read commands live in
`cli/dispatch/wiki.py`. Architecture tests require the domain dispatch files to
exist, keep `dispatch/root.py` under 80 lines, and keep dispatch files under the
250-line split-review threshold. Focused ruff passed; focused pytest initially
failed only because `next-agent-brief.md` still pointed at slice 71. After the
brief update, focused pytest, focused ruff, `git diff --check`, full pytest
(`253 passed`), and full ruff all passed.
Slice 75 restores the queue core behind background jobs. `runs` now persists
`<run-id>.spec.json` next to run records, treats spec-backed queued records as
worker-eligible background work, selects the oldest eligible run, and uses a
per-wiki `worker.lock/owner.json` with stale-lock recovery. `RunQueueWorkflow`
drains in-process by dispatching persisted Ingest/Garden specs to the existing
operation workflows, which keeps prompt rendering, mutation safety, harness
events, index refresh, and terminal finalization in the shared lifecycle path.
Focused pytest covered run spec persistence, oldest selection, lock
exclusivity/stale recovery, cancelled queued skips, in-process ingest drain,
and architecture guards. Full pytest passed with 263 tests, full Ruff passed,
`git diff --check` passed, and a temp-repo app-level dogfood run queued an
ingest spec, drained one run, finished it as `done`, and found the generated
page through search.
Slice 76 adds detached worker spawning and explicit public background mode.
`RunQueueWorkflow` now accepts an injected worker spawner, `SubprocessRunWorkerSpawner`
launches `sys.executable -m codealmanac.cli.main __run-worker --cwd <repo>`,
and the hidden worker command drains the queue through the app composition root.
`codealmanac ingest --background` and `codealmanac garden --background` queue
spec-backed runs and spawn a worker; `--json` reports run id/status/child pid
for background starts. Focused tests cover the spawner command shape, workflow
background start, CLI background output, and hidden worker drain. Foreground
remains the default pending a separate product decision. Full pytest passed
with 268 tests, full Ruff passed, and `git diff --check` passed. Dogfood ran
the hidden worker command against an empty temp wiki and then ran public
`garden --background --json` in a non-Git temp repo; the public command queued a
run, spawned a child process, and the worker finalized the run as `failed` at
Git preflight without invoking a provider harness.
Slice 77 adds manual background sync. `RunSyncRequest` now carries
`SyncExecution`, `codealmanac sync --background` queues eligible transcript
ingests through `RunQueueWorkflow`, saves pending ledger claims before spawning
workers, and leaves plain `sync` foreground. Focused tests cover background
pending claims, queued run specs, no parent-process harness execution, spawn
failure cleanup, and CLI dispatch. Local automation still schedules foreground
sync until unattended background policy is explicitly reopened.
Focused pytest passed with 76 targeted tests, full pytest passed with 271 tests,
full Ruff passed, and `git diff --check` passed. Dogfood used an isolated HOME
with a fake Codex transcript and project-pinned `uv run`; public
`sync --background` discovered one transcript, queued one ingest, spawned a
worker, and the worker failed at non-Git preflight before any provider harness.
A follow-up foreground sync reconciled the pending claim into an `ingest-failed`
ledger entry.
Slice 78 restores structured page `sources:` as read-model provenance. The wiki
frontmatter parser now normalizes supported source entries into typed
`PageSource` values, file sources derive file refs for `search --mentions`, the
index projects `page_sources`, `show --meta` and viewer page APIs expose source
records, and health reports missing citations, unused sources, and duplicate
source ids. The slice deliberately skips migration commands, source snapshots,
and source-catalog query machinery.
Focused pytest passed with 78 targeted tests, full pytest passed with 273 tests,
full Ruff passed, and `git diff --check` passed. Dogfood used an isolated HOME
and temp repo: public `search --mentions src/auth/session.py` found a page
through `sources[type=file]`, `show --meta` and `show --json` displayed file
and web sources, and `health --json` reported no source warnings when citations
matched source ids.
Slice 88 fixes the docs drift introduced after setup gained automation install
flags in slice 87. README now documents explicit setup automation commands and
`uninstall --keep-automation`; `docs/concepts.md` lists setup/uninstall in the
Admin group and names their scheduler behavior; public-contract tests require
the new examples and reject the stale "does not install scheduled automation"
wording.
Slice 89 restores the first read-only jobs surface in the local viewer.
`ViewerService` now maps `RunRecord` and `RunLogEvent` values into viewer DTOs,
`serve` exposes `/api/jobs` and `/api/jobs/{run_id}`, and the static viewer
renders `#/jobs` plus job detail pages with normalized harness event summaries.
The slice keeps browser run control out of scope and adds an architecture test
that prevents viewer jobs code from importing run mutation requests.
Slice 90 deepens that read surface by rendering typed `HarnessEvent` fields
already present in the job-detail API. The browser now shows tool display rows
for command/path/status/summary, usage token counts, failure provider/code/fix
details, and agent trace parent/child/model/result rows. Raw provider payloads
remain hidden by default, and run control stays in the CLI.
Slice 91 makes the local `serve` jobs views refresh themselves while active
runs are visible. The polling timer lives in the static jobs viewer module, is
cleared by the route/wiki entrypoint, and calls only the existing read APIs.
The first dogfood attempt accidentally launched an older installed console
because `uv run` was executed from the temp repo; the corrected command pinned
the checkout with `uv run --project /Users/rohan/Desktop/Projects/codealmanac`.
Browser-harness then proved a job detail route moved from `running` to `done`
without a manual refresh after `RunsService.finish(...)` updated the durable
run record.
Slice 92 moves run-id validation out of the viewer adapter and into the runs
product model. `RunId` is now a Pydantic-constrained string type shared by run
records, log events, run request models, viewer job requests, and page-run
workflow requests, and `RunStore` revalidates path helper inputs with
`TypeAdapter(RunId)`. Focused tests prove path-shaped and dotted ids fail
request validation for service, CLI, viewer, server, and direct-store
boundaries. Isolated CLI dogfood initialized a temp repo and confirmed
`jobs show ../secret` and `jobs logs run.json` exit with validation errors
before any `almanac/jobs/` files are created.
Slice 93 removes the remaining Node/npm GitHub project surface. CI now sets up
Python 3.12 and uv, runs `uv sync --locked`, `ruff`, `pytest`,
`codealmanac --help`, and `git diff --check`. Package check builds Python
artifacts with `uv build --out-dir dist` and validates them with
`uvx twine check dist/*`. The disabled publish workflow now names the future
PyPI policy instead of npm tokens, the PR/issue templates ask for Python and
CodeAlmanac details, `.gitignore` ignores package `build/`, and
public-contract tests reject npm-era `.github/` language.
Slice 94 tightens that public project-surface proof. The exact CI sync command
`uv sync --locked` passed locally. The bug-report template now says
CodeAlmanac in the expected-behavior prompt, and public-contract tests parse
all `.github/workflows/*.yml` files with `ruamel-yaml` before asserting the
CI and package-check Python gate commands.
Slice 95 extracts deterministic sync ledger and cursor policy from
`SyncWorkflow`. `workflows/sync/service.py` now stays focused on discovery,
wiki scoping, run-record lookup, ledger load/save, foreground ingest,
background enqueue, worker spawn, and summary assembly. New
`workflows/sync/policy.py` owns ledger keys, transcript snapshot reading,
cursor hashing, pending/absorbed/failed entry transitions, pending-run
reconciliation, skip rows, and sync ingest cursor guidance. Focused sync and
architecture tests passed after the move, and an architecture guard now
prevents the service from regrowing cursor helpers or policy from importing
orchestration services.
Slice 96 splits the filesystem source-runtime adapter by reason to change.
`adapter.py` is now the `SourceRuntimeAdapter` implementation;
`documents.py` owns text document models, byte bounds, and charset detection;
`listing.py` owns ignore rules, Git listing, Python walking, status parsing,
and directory document assembly; `selection.py` keeps diversity ranking;
`rendering.py` owns prompt-facing filesystem runtime text; and `paths.py`
owns display/relative path helpers. Dogfood exposed that normalized source
refs could render absolute paths when `cwd` arrived through a symlink or macOS
`/var` alias; the adapter now normalizes `cwd` before delegated document or
listing work, and a symlink regression covers repo-relative display. Focused
filesystem runtime, directory selection, architecture tests, and lint passed
after the move.
Slice 99 makes generic page source `target:` a parser fallback instead of a
downstream read-model concern. `services/wiki/frontmatter.py` still prefers
type-specific source address fields such as `path:` and `url:`, then falls back
to `target:` and returns normalized `PageSource.target` values. Parser and
read-model tests now prove `sources[type=file].target` is projected into
`show.sources`, derives `file_refs`, and powers `search --mentions`. Isolated
CLI dogfood initialized a temp repo with isolated `HOME`, authored a page with
`sources[type=file].target`, and proved public `search --mentions` plus
`show --json` see the source target and derived file ref.
Slice 100 splits the Codex app-server event mapper by provider-edge
responsibility. `events.py` is now a small notification dispatcher; `state.py`
owns mutable run state; `actors.py` owns root/helper attribution;
`item_events.py` owns item completion and output-delta decoding;
`agent_events.py` owns helper-agent spawn/wait traces; and `result.py` owns
usage, provider-session, turn-completion, and done events. The app-server client
keeps importing the same dispatcher and result symbols, so public harness
behavior is unchanged. Focused Codex app-server, Codex adapter, architecture,
and Ruff checks passed after the split. A fake app-server dogfood run outside
pytest used `CodexAppServerClient` against a temporary fake `codex` binary and
produced the expected provider-session, tool, text, usage, and done events.
Slice 101 splits Codex app-server transport orchestration from provider policy
helpers. `app_server.py` now owns process startup, handshake requests,
JSON-RPC reads, and turn flow. `responses.py` owns noninteractive
server-request responses, `sandbox.py` owns sandbox mode/env policy and payload
construction, `turn_completion.py` owns root-turn detection, `run_result.py`
owns `CodexRunState`/failure projection to `HarnessRunResult`, and
`timeouts.py` owns tolerant timeout-env parsing. The Codex app-server wiki page
now cites the new module ownership. Focused Codex app-server, Codex adapter,
architecture, and Ruff checks passed after the split.
Slice 102 splits the index write side while keeping `IndexStore` as the public
store facade. `schema.py` owns derived `index.db` schema, migrations, and the
index connection helper; `sources.py` owns markdown page loading,
`topics.yaml` loading, skipped-file counts, and freshness signatures;
`projection.py` owns replacement writes and stored source signatures. Focused
architecture and read-model tests passed after the split. Public CLI dogfood
initialized a temp repo, added a page, searched original text, edited the page,
and searched changed text through implicit refresh. Full pytest, Ruff, and diff
hygiene passed.
Slice 103 keeps sync behavior unchanged while splitting deterministic sync
policy behind `workflows/sync/policy.py`. `decisions.py` owns cursor and
pending-run decisions, `entries.py` owns ledger-entry transitions,
`identity.py` owns workspace/session/ledger identity helpers, `snapshots.py`
owns transcript reading and hashes, `reporting.py` owns skip/start rows, and
`guidance.py` owns generated Ingest guidance. Focused sync workflow and
architecture tests passed. Public CLI dogfood initialized a temp repo, created
a temp Codex transcript, and confirmed `sync status --json` reported scanned 1,
eligible 1, and ready `codex-sync-103` lines 1-1.
Slice 104 keeps GitHub source runtime behavior unchanged while splitting
`GitHubSourceRuntimeAdapter` internals by responsibility. `adapter.py` remains
the `SourceRuntimeAdapter` implementation; `client.py` owns `gh` command
execution and typed payload retrieval; `models.py` owns Pydantic `gh --json`
payloads; `targets.py` owns `SourceRef` to `gh` target args; `rendering.py`
owns prompt-facing PR/issue runtime text; and `errors.py` owns unavailable
runtime diagnostics. Focused GitHub runtime, ingest, and architecture tests
passed. Fake-runner dogfood resolved and inspected a GitHub PR URL through the
service path and rendered file, comment, review, and diff material.
Slice 105 keeps transcript source runtime behavior unchanged while splitting
`TranscriptSourceRuntimeAdapter` internals by responsibility. `runtime.py`
remains the `SourceRuntimeAdapter` implementation; `models.py` owns typed
provider line and runtime-entry models; `reader.py` owns JSONL file reading;
`entries.py` owns known-provider line-to-entry normalization; `rendering.py`
owns prompt-facing transcript text and tail truncation; `paths.py` owns
transcript path resolution; and `errors.py` owns unavailable diagnostics.
Focused transcript runtime, sync, architecture, and lint checks passed.
Slice 106 keeps source resolution behavior unchanged while splitting
source-address syntax out of `SourcesService`. `service.py` remains the
resolve/discover/inspect facade over request models and injected ports.
`address_resolution.py` owns prompt hints, GitHub shorthand and URL parsing,
git diff/range parsing, transcript address parsing, web URL validation, local
path classification, and file fingerprinting. `transcripts.py` owns transcript
candidate ordering. Focused source service, source runtime, architecture, and
lint checks passed, and service-level dogfood resolved every current
source-address family.
Slice 107 keeps CLI output behavior unchanged while splitting ordinary render
internals by command domain. `cli/render/root.py` remains a re-export facade for
dispatcher imports; `lifecycle.py` owns build/ingest/garden/sync/job-start
output; `wiki.py` owns search/show/topics/health/tagging output;
`workspaces.py` owns local wiki registry list/drop output; and `common.py` owns
shared JSON/index/page-word helpers. Focused CLI and architecture tests passed,
and public CLI dogfood covered help, init, `list --json`, and empty search.
Slice 108 keeps filesystem directory runtime behavior unchanged while splitting
listing internals by mechanic. `listing.py` now assembles directory documents
and chooses Git-vs-walk source policy; `ignore.py` owns default/configured
ignore rules and `.gitignore` loading; `walk.py` owns recursive Python walking;
and `git.py` owns Git `ls-files`, Git status parsing, repo-root probing, and
command failure tolerance. Focused filesystem runtime, directory selection,
architecture, and lint checks passed. Service-level dogfood rendered a
repo-relative directory source while respecting `.gitignore` and configured
Almanac-root ignores.
Slice 109 keeps sync behavior unchanged while splitting run execution effects
out of `SyncWorkflow.service`. `service.py` remains the status/run/evaluate
orchestration surface. `execution.py` owns foreground Ingest execution,
background queueing, worker-spawn failure handling, pending/failed/absorbed
ledger writes, and started summary rows through explicit dependencies in
`SyncRunExecutor`. Focused foreground, background, worker-spawn failure,
ingest-failure, pending-claim, architecture, and lint checks passed. Public
`sync status --json` dogfood with an old synthetic Codex transcript returned
one ready transcript for lines 1-2.
Slice 110 keeps viewer behavior unchanged while splitting local reader
boundaries. `services/viewer/service.py` remains the
overview/page/search/file/topic/jobs use-case facade. `workspace_scope.py` owns
selected-wiki fallback, available-registry filtering, and multi-wiki navigation
ordering. `projections.py` owns index/workspace to viewer DTO conversion.
Focused viewer/server/architecture tests and lint passed, and live `serve` API
dogfood initialized two registered temp wikis and verified default overview
plus selected-wiki overview behavior.
Slice 111 keeps web source runtime behavior unchanged while splitting the
integration by responsibility. `adapter.py` remains the `SourceRuntimeAdapter`
implementation; `client.py` owns `httpx` streaming and bounded response reads;
`models.py` owns fetched-response and runtime-document Pydantic models;
`documents.py` owns content-kind classification, UTF-8 decoding, Beautiful Soup
HTML cleanup, and normalized text extraction; `rendering.py` owns prompt-facing
metadata/content rendering; and `errors.py` owns unavailable diagnostics.
Focused web runtime, Ingest web-source prompt, architecture, and lint checks
passed, and service-level dogfood inspected a mock web URL through
`SourcesService`.
Slice 112 keeps workspace behavior unchanged while splitting workspace service
mechanics. `services/workspaces/service.py` remains the initialization,
registration, selection, resolution, validation, listing, and drop use-case
facade. `identity.py` owns workspace names and ids, `selection.py` owns
selector matching and path containment, `status.py` owns registry availability
policy, and `store.py` now imports identity directly instead of importing back
from `service.py`. Focused workspace/build/read-model/architecture tests and
lint passed, and service-level dogfood covered configured-root init,
relative-path selection, path validation, missing-wiki drop, and explicit drop.
Slice 113 keeps harness behavior unchanged while splitting the service-owned
harness contract by meaning. `models.py` is now a 44-line import-compatible
facade. `kinds.py` owns provider/status enums, `actors.py` owns root/helper
attribution models, `events.py` owns normalized transcript event payloads, and
`results.py` owns readiness, transcript refs, run results, and terminal helper
events. Focused harness service, ingest event recording, run event persistence,
Codex app-server, Claude SDK, architecture, and lint checks passed.
Slice 114 keeps `doctor` behavior unchanged while splitting diagnostics by
check family. `DiagnosticsService` is now a 49-line facade over
`install_checks(...)` and `wiki_checks(...)`. `install.py` owns
install/runtime/manual-package checks, `wiki.py` owns selected-wiki registry,
index, workspace manual, and health checks, and `messages.py` owns shared
doctor message formatting. Focused diagnostics/CLI/architecture tests and lint
passed, and isolated CLI dogfood covered no-wiki plus initialized-wiki
`doctor --json`.
Slice 122 keeps wiki CLI output unchanged while splitting
`cli/render/wiki.py` by output family. `wiki.py` is now a facade;
`search.py` owns search/reindex output, `pages.py` owns show/page output,
`topics.py` owns topic list/show/mutation output, `health.py` owns health
sections, and `tagging.py` owns tag/untag summaries. Architecture tests keep
service model imports and render definitions out of the facade.
Slice 123 keeps admin CLI output unchanged while splitting
`cli/render/admin.py` by output family. `admin.py` is now a facade;
`automation.py` owns automation install/status/uninstall output,
`diagnostics.py` owns doctor output, `jobs.py` owns jobs output, `updates.py`
owns update output, and `setup.py` owns setup/uninstall result output plus Rich
presentation. Architecture tests keep service model imports and render
definitions out of the facade.
Slice 124 keeps admin CLI behavior unchanged while splitting
`cli/dispatch/admin.py` by command family. `admin.py` is now a facade;
`setup.py` owns setup/uninstall request construction, `diagnostics.py` owns
doctor request construction, `updates.py` owns update request construction,
`jobs.py` owns jobs request construction, and `automation.py` owns automation
request construction. Architecture tests keep service request imports and
command-family helpers out of the facade.
Slice 125 keeps lifecycle CLI behavior unchanged while splitting
`cli/dispatch/lifecycle.py` by command family. `lifecycle.py` is now a facade;
`build.py` owns init/build request construction, `operations.py` owns
ingest/garden foreground/background dispatch, `sync.py` owns sync and sync
status request construction, and `worker.py` owns the hidden queue-drain
entrypoint. Architecture tests keep workflow request imports and sync helpers
out of the facade.
Slice 126 keeps admin CLI flags unchanged while splitting `cli/parser/admin.py`
by command family. `admin.py` is now a facade; `setup.py` owns setup/uninstall
flags, `diagnostics.py` owns doctor flags, `updates.py` owns update flags,
`jobs.py` owns jobs flags, and `automation.py` owns automation flags and task
choices. Architecture tests keep command flag construction out of the facade.
Slice 127 removes archive/supersede page lineage from the active Python product
model. Frontmatter parsing ignores obsolete `archived_at` and `superseded_by`
keys, `PageDocument`, `SearchPageResult`, and `PageView` no longer carry page
lineage fields, the derived index schema drops archive columns, search no
longer exposes `--include-archive` or `--archived`, topic/health queries treat
every indexed page as current, and viewer page summaries no longer expose an
archive marker. Architecture tests keep active Python source from regrowing
page archive lineage fragments.
Slice 128 fixes current-repo workspace resolution. `WorkspacesService.resolve`
now checks nearest initialized roots before broad registry containment, and the
built-in discoverable roots are `almanac/`, `docs/almanac/`, and `.almanac/`.
A broad `/Users/rohan/Desktop/Projects` registry entry no longer shadows this
repo's `.almanac/`. Dogfood with `uv run codealmanac search "topic service"`
now returns pages from this checkout and auto-registers the checkout as a
`.almanac` workspace.
Slice 129 keeps health behavior unchanged while splitting index health read
views by finding family. `health_views.py` is now a 35-line `HealthReport`
facade, `health_graph_views.py` owns page/topic/link/file findings, and
`health_source_views.py` owns sources/citations findings. Focused health and
architecture tests passed, and real-checkout `codealmanac health --json`
returned the existing issue counts through the split modules.
Slice 135 changes `jobs attach` from a snapshot-style read into the streaming
control verb described by the live agreement and archived CLI. `jobs logs`
remains the snapshot command. `services/runs/streaming.py` owns polling
`RunStore.attach(...)`, emits only unseen events, and stops at `done`, `failed`,
or `cancelled`; `cli/render/jobs.py` owns text and JSON-line stream output.
Focused service, CLI, architecture, and public-contract tests passed. Full
`uv run pytest` reported `353 passed`; full Ruff and diff hygiene passed.
Temp-repo CLI dogfood confirmed attach replayed queued/message/done events
before exiting at `status: done`.
Slice 136 runs the real installed Codex app-server through the default Python
Codex harness and `IngestWorkflow`. The first real run reached model output and
then failed because real `item/agentMessage/delta` notifications can be
whitespace-only; `HarnessEvent.message` correctly rejects empty messages, so
the Codex provider edge now drops blank text and plan deltas. The rerun used a
temp registry with the real HOME/Codex auth, finished
`ingest-20260701163042-e849c0e6` as `done`, created
`webhook-idempotency-invariant.md`, search found the page, and all health
counts were zero. Focused Codex/public-contract tests, full pytest
(`353 passed`), full Ruff, and diff hygiene passed.
Slice 137 runs the real installed `claude-agent-sdk` and Claude CLI auth path
through the default Python Claude harness and `IngestWorkflow`. The run used a
temp registry with real HOME/Claude auth and a temp Git repo, finished
`ingest-20260701163930-cf193a0e` as `done`, created
`release-package-smoke.md`, search found the page, and all health counts were
zero. The run recorded 73 events and normalized provider session, text, text
delta, tool use/result, context usage, warning, and done harness events.
Slice 138 reruns current-head package proof after the rich provider dogfood
slices. `uv build` produced `codealmanac-0.1.0.dev0` wheel and sdist artifacts
under `/tmp/codealmanac-release-slice138`; `twine check` passed for both;
package inspection found expected metadata and bundled resources; clean
uv-managed Python 3.12.9 installs from both artifacts passed installed CLI
smoke for init, read commands, health, jobs, sync status, doctor, update check,
and serve. The installed smokes wrote registry state under isolated
`~/.codealmanac/` homes and did not create `~/.almanac/registry.json`.
