Three Operation Architecture Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Make CodeAlmanac have exactly three internal wiki operations: build, ingest, and garden; make codealmanac init the public front door for the internal build operation; copy Kushagra's July 2026 init prompt and manual material literally from git history, changing only the current Python/nested-almanac/ format facts.
Architecture: Public commands and internal operations are separate concepts. init is a public command that starts a build run. sync is transcript intake that creates ingest runs. update is product maintenance. Only build, ingest, and garden are stored as run operations, prompt operations, queue operations, and viewer/job operation labels.
Tech Stack: Python 3.12, Pydantic, pytest, ruff, package resources via importlib.resources, local harness adapters, SQLite-backed runtime state under ~/.codealmanac/.
Non-Negotiable Product Truth#
- Internal wiki operations are exactly:
build,ingest,garden. syncis not an operation. It is a transcript intake command/scheduled task that startsingestruns.captureis legacy language. It must not appear in current user-facing docs, manual, setup copy, command help, or AGENTS guide.updateis not a wiki operation. It is product maintenance.codealmanac initis the front-facing command for the internalbuildoperation.- There is no public
codealmanac buildcommand. - No backwards compatibility shims, aliases, hidden compatibility commands, or dual docs.
- Kushagra's prompt/manual material is copied literally first from commit
4c6157180409af7ab734b7d6e74c1eccaa656ec0(docs(init): tune first-wiki planning and writing prompts, July 4, 2026). Edits are limited to required product-format changes:- command name:
almanac->codealmanac; - internal operation heading:
Init Operation->Build Operation; - page layout:
pages/<slug>.mdunder an Almanac root -> browseable nested Markdown directly underalmanac/; [[...]]wiki links -> Markdown links and structured source evidence;- runtime state paths ->
~/.codealmanac/; - operation wording -> exactly
build,ingest, andgarden.
- command name:
Task 1: Correct The Written Source Of Truth#
Files:
- Modify:
notes.md - Modify:
implementation-tickets.md - Create:
docs/plans/2026-07-06-three-operation-architecture.md
Step 1: Remove the wrong init/build decision from notes.md
Replace the current wrong claim that "build should not remain public-facing" with:
`codealmanac init` is the public command for the first wiki build. Internally it
starts a `build` operation. There are exactly three internal wiki operations:
`build`, `ingest`, and `garden`. `sync` is transcript intake that creates
`ingest` runs. `update` is product maintenance. `capture` is retired language.Step 2: Replace Ticket 13 in implementation-tickets.md
Rewrite Ticket 13 as:
## Ticket 13: Restore Three Operation Architecture
Goal: make `init` delegate to a model-backed `build` operation and make
`build`, `ingest`, and `garden` the only internal wiki operations.
Non-negotiables:
- `codealmanac init` is public.
- `codealmanac build` is not public.
- run records use only `build`, `ingest`, or `garden`.
- `sync` creates `ingest` runs and is not a run operation.
- Kushagra's prompt/manual material from commit `4c615718` is copied literally
first and adapted only for Python/nested `almanac/` format.Step 3: Run the docs grep
Run:
rg -n "build should not remain|RunOperation\\.SYNC|capture|absorb|\\.almanac/pages|files:" notes.md implementation-tickets.md docs src/codealmanac/manual src/codealmanac/promptsExpected:
- no stale source-of-truth claim that public
buildreplacesinit; - no current manual/doc reference to
capture; - no current manual/doc reference to legacy
absorb; - remaining
.almanac/pagesorfiles:hits are only inside explicit migration history.
Step 4: Commit
git add notes.md implementation-tickets.md docs/plans/2026-07-06-three-operation-architecture.md
git commit -m "docs: lock three operation architecture"Task 2: Copy Kushagra's July Prompt And Manual Sources#
Files:
- Source commit:
4c6157180409af7ab734b7d6e74c1eccaa656ec0 - Related Kushagra commit:
cfef4867d9d2c65685b4029701ca367625deb76d - Related Kushagra commit:
597f95deab54cddc31f3c6cc0925515ced3ab911 - Related Kushagra commit:
6683b4011ede92b197b40ad7b00d5ea4be5e4a72 - Source:
4c615718:src/codealmanac/prompts/base/kernel.md - Source:
4c615718:src/codealmanac/prompts/operations/init.md - Source:
4c615718:src/codealmanac/prompts/operations/ingest.md - Source:
4c615718:src/codealmanac/prompts/operations/garden.md - Source:
4c615718:src/codealmanac/manual/README.md - Source:
4c615718:src/codealmanac/manual/architecture.md - Source:
4c615718:src/codealmanac/manual/concepts.md - Source:
4c615718:src/codealmanac/manual/decisions.md - Source:
4c615718:src/codealmanac/manual/evidence.md - Source:
4c615718:src/codealmanac/manual/garden.md - Source:
4c615718:src/codealmanac/manual/how-to-guides.md - Source:
4c615718:src/codealmanac/manual/how-to-write.md - Source:
4c615718:src/codealmanac/manual/ingest.md - Source:
4c615718:src/codealmanac/manual/links.md - Source:
4c615718:src/codealmanac/manual/reference.md - Source:
4c615718:src/codealmanac/manual/sources.md - Source:
4c615718:src/codealmanac/manual/topics.md - Replace:
src/codealmanac/prompts/base/kernel.md - Create:
src/codealmanac/prompts/operations/build.md - Replace:
src/codealmanac/prompts/operations/ingest.md - Replace:
src/codealmanac/prompts/operations/garden.md - Replace:
src/codealmanac/manual/README.md - Replace:
src/codealmanac/manual/architecture.md - Replace:
src/codealmanac/manual/concepts.md - Replace:
src/codealmanac/manual/decisions.md - Replace:
src/codealmanac/manual/evidence.md - Replace:
src/codealmanac/manual/garden.md - Replace:
src/codealmanac/manual/how-to-guides.md - Replace:
src/codealmanac/manual/how-to-write.md - Replace:
src/codealmanac/manual/ingest.md - Replace:
src/codealmanac/manual/links.md - Replace:
src/codealmanac/manual/reference.md - Replace:
src/codealmanac/manual/sources.md - Replace:
src/codealmanac/manual/topics.md - Modify:
src/codealmanac/prompts/models.py - Modify:
src/codealmanac/manual/models.py - Test:
tests/test_prompt_manual_kushagra_port.py - Test:
tests/test_manual.py
Step 1: Copy first, before editing
Run:
git show 4c615718:src/codealmanac/prompts/base/kernel.md > src/codealmanac/prompts/base/kernel.md
git show 4c615718:src/codealmanac/prompts/operations/init.md > src/codealmanac/prompts/operations/build.md
git show 4c615718:src/codealmanac/prompts/operations/ingest.md > src/codealmanac/prompts/operations/ingest.md
git show 4c615718:src/codealmanac/prompts/operations/garden.md > src/codealmanac/prompts/operations/garden.md
git show 4c615718:src/codealmanac/manual/README.md > src/codealmanac/manual/README.md
git show 4c615718:src/codealmanac/manual/architecture.md > src/codealmanac/manual/architecture.md
git show 4c615718:src/codealmanac/manual/concepts.md > src/codealmanac/manual/concepts.md
git show 4c615718:src/codealmanac/manual/decisions.md > src/codealmanac/manual/decisions.md
git show 4c615718:src/codealmanac/manual/evidence.md > src/codealmanac/manual/evidence.md
git show 4c615718:src/codealmanac/manual/garden.md > src/codealmanac/manual/garden.md
git show 4c615718:src/codealmanac/manual/how-to-guides.md > src/codealmanac/manual/how-to-guides.md
git show 4c615718:src/codealmanac/manual/how-to-write.md > src/codealmanac/manual/how-to-write.md
git show 4c615718:src/codealmanac/manual/ingest.md > src/codealmanac/manual/ingest.md
git show 4c615718:src/codealmanac/manual/links.md > src/codealmanac/manual/links.md
git show 4c615718:src/codealmanac/manual/reference.md > src/codealmanac/manual/reference.md
git show 4c615718:src/codealmanac/manual/sources.md > src/codealmanac/manual/sources.md
git show 4c615718:src/codealmanac/manual/topics.md > src/codealmanac/manual/topics.mdStep 2: Apply only required current-product edits
Edit only the copied files. Apply these exact categories:
Init Operation heading -> Build Operation heading
init operation wording -> build operation wording where it names the internal operation
pages/<slug>.md paths -> nested Markdown paths directly under almanac/
pages/ folder wording -> browseable nested almanac/ tree wording
[[page]] links -> Markdown links
[[file/path.py]] file links -> structured sources evidence or Markdown file links
configured Almanac root aliases -> almanac/ only
sync/capture legacy wording -> sync is transcript intake; capture is retired
operation list -> build, ingest, garden onlyDo not rewrite style, voice, examples, algorithms, coverage-map requirements, writing-subagent requirements, topic guidance, page-type manuals, or article-quality language except where the old format is factually wrong for the current product.
Step 3: Keep Kushagra's kernel base prompt shape
Update src/codealmanac/prompts/models.py:
class PromptName(StrEnum):
BASE_KERNEL = "base/kernel.md"
OPERATION_BUILD = "operations/build.md"
OPERATION_INGEST = "operations/ingest.md"
OPERATION_GARDEN = "operations/garden.md"Delete OPERATION_INIT from the prompt enum. codealmanac init renders OPERATION_BUILD.
Step 4: Keep Kushagra's manual inventory
Update src/codealmanac/manual/models.py:
class ManualDocumentName(StrEnum):
README = "README.md"
HOW_TO_WRITE = "how-to-write.md"
EVIDENCE = "evidence.md"
LINKS = "links.md"
TOPICS = "topics.md"
CONCEPTS = "concepts.md"
ARCHITECTURE = "architecture.md"
HOW_TO_GUIDES = "how-to-guides.md"
DECISIONS = "decisions.md"
REFERENCE = "reference.md"
SOURCES = "sources.md"
INGEST = "ingest.md"
GARDEN = "garden.md"
MANUAL_DOCUMENTS: tuple[ManualDocumentName, ...] = (
ManualDocumentName.README,
ManualDocumentName.HOW_TO_WRITE,
ManualDocumentName.EVIDENCE,
ManualDocumentName.LINKS,
ManualDocumentName.TOPICS,
ManualDocumentName.CONCEPTS,
ManualDocumentName.ARCHITECTURE,
ManualDocumentName.HOW_TO_GUIDES,
ManualDocumentName.DECISIONS,
ManualDocumentName.REFERENCE,
ManualDocumentName.SOURCES,
ManualDocumentName.INGEST,
ManualDocumentName.GARDEN,
)Delete any obsolete manual documents not in this inventory.
Step 5: Add Kushagra-port tests
Create tests/test_prompt_manual_kushagra_port.py with tests that:
- read each source file from commit
4c615718usinggit show; - read each Python destination file;
- assert destination manual documents preserve Kushagra's headings;
- assert
src/codealmanac/prompts/operations/build.mdpreserves the phrases "Phase 1: Scan And Plan", "coverage-map.md", "Use read-only research sub-agents", "Use writing sub-agents", and "The main agent is the orchestrator"; - assert no destination contains public
codealmanac build; - assert no destination contains
captureas a current command; - assert no destination contains stale
pages/layout instructions after the nested-tree adaptation; - assert no destination contains
[[link syntax after the Markdown-link adaptation.
Step 6: Run focused tests
uv run pytest tests/test_manual.py tests/test_prompt_manual_kushagra_port.py -q
uv run ruff check src/codealmanac/prompts src/codealmanac/manual tests/test_prompt_manual_kushagra_port.pyExpected: pass.
Step 7: Commit
git add src/codealmanac/prompts src/codealmanac/manual tests/test_manual.py tests/test_prompt_manual_kushagra_port.py
git commit -m "feat: port Kushagra init prompt and manual"Task 3: Make RunOperation Exactly Build, Ingest, Garden#
Files:
- Modify:
src/codealmanac/services/runs/models.py - Modify:
tests/test_runs_service.py - Modify:
tests/test_public_contract.py - Modify:
tests/test_sync_workflow.py - Modify:
tests/test_run_queue_workflow.py
Step 1: Remove SYNC from RunOperation
Update:
class RunOperation(StrEnum):
BUILD = "build"
INGEST = "ingest"
GARDEN = "garden"Step 2: Update RunSpec.validate_operation_payload
Use this operation payload contract:
@model_validator(mode="after")
def validate_operation_payload(self) -> "RunSpec":
if self.version != 1:
raise ValueError("run spec version must be 1")
if self.operation == RunOperation.BUILD:
if len(self.inputs) > 0:
raise ValueError("build run spec does not accept inputs")
return self
if self.operation == RunOperation.INGEST:
if len(self.inputs) == 0:
raise ValueError("ingest run spec requires inputs")
return self
if self.operation == RunOperation.GARDEN:
if len(self.inputs) > 0:
raise ValueError("garden run spec does not accept inputs")
return self
raise ValueError(f"unsupported queued run operation: {self.operation.value}")Step 3: Add public contract test
Add:
def test_run_operations_are_only_build_ingest_garden():
assert tuple(operation.value for operation in RunOperation) == (
"build",
"ingest",
"garden",
)Step 4: Add sync contract test
Add or update a sync test so a ready transcript creates a queued run with:
assert run.operation == RunOperation.INGESTand never creates a run with operation "sync".
Step 5: Run focused tests
uv run pytest tests/test_runs_service.py tests/test_run_queue_workflow.py tests/test_sync_workflow.py tests/test_public_contract.py -qExpected: pass.
Step 6: Commit
git add src/codealmanac/services/runs/models.py tests/test_runs_service.py tests/test_run_queue_workflow.py tests/test_sync_workflow.py tests/test_public_contract.py
git commit -m "refactor: restrict wiki operations to build ingest garden"Task 4: Split Public Commands From Internal Operations#
Files:
- Modify:
src/codealmanac/cli/parser/lifecycle.py - Modify:
src/codealmanac/cli/dispatch/lifecycle.py - Modify:
src/codealmanac/cli/dispatch/build.py - Modify:
src/codealmanac/cli/render/lifecycle.py - Modify:
src/codealmanac/cli/render/root.py - Modify:
tests/test_cli.py - Modify:
tests/test_public_contract.py
Step 1: Keep public lifecycle commands explicit
Public lifecycle commands are:
init
ingest
garden
syncThe public parser still rejects:
build
capture
absorbinit maps to RunOperation.BUILD.
ingest maps to RunOperation.INGEST.
garden maps to RunOperation.GARDEN.
sync maps to transcript intake and produces ingest runs.
Step 2: Add build operation flags to init
In src/codealmanac/cli/parser/lifecycle.py, make init accept the model-backed operation controls:
init.add_argument("path", nargs="?", default=".")
init.add_argument("--name")
init.add_argument("--description", default="")
init.add_argument("--using", choices=tuple(kind.value for kind in HarnessKind))
init.add_argument("--title")
init.add_argument("--guidance")
init.add_argument("--force", action="store_true")
init.add_argument("--background", action="store_true")
init.add_argument("--foreground", action="store_true")
init.add_argument("--json", action="store_true")Step 3: Make dispatch naming honest
dispatch_init calls the build workflow operation runner, not deterministic indexing:
def dispatch_init(args: argparse.Namespace, app: CodeAlmanac) -> int:
request = build_request(args)
if args.background:
result = app.workflows.queue.start_build_background(request)
render_queued_operation(result, json_output=args.json)
return 0
result = app.workflows.build.run(request)
render_build_operation(result)
return 0Use the actual project render names during implementation. The behavior is fixed: foreground by default, background by explicit flag.
Step 4: Keep codealmanac build rejected
Test:
with pytest.raises(SystemExit):
parser.parse_args(("build",))
assert "invalid choice: 'build'" in capsys.readouterr().errStep 5: Update init CLI tests
codealmanac init now:
- starts a
buildrun; - records operation
build; - invokes the harness with the Kushagra-derived build prompt;
- writes pages through the harness;
- refreshes index;
- renders run status and wiki path.
Step 6: Run focused tests
uv run pytest tests/test_cli.py tests/test_public_contract.py -q
uv run ruff check src/codealmanac/cli tests/test_cli.py tests/test_public_contract.pyExpected: pass.
Step 7: Commit
git add src/codealmanac/cli tests/test_cli.py tests/test_public_contract.py
git commit -m "feat: route init to build operation"Task 5: Implement Model-Backed Build Workflow#
Files:
- Modify:
src/codealmanac/workflows/build/service.py - Modify:
src/codealmanac/workflows/build/models.py - Create:
src/codealmanac/workflows/build/requests.py - Modify:
src/codealmanac/workflows/build/__init__.py - Modify:
src/codealmanac/app.py - Modify:
src/codealmanac/workflows/page_run/service.py - Modify:
src/codealmanac/workflows/lifecycle_mutation.py - Modify:
tests/test_build_workflow.py
Step 1: Add build request models
Create src/codealmanac/workflows/build/requests.py:
from pathlib import Path
from pydantic import field_validator
from codealmanac.core.models import CodeAlmanacModel
from codealmanac.core.text import required_text
from codealmanac.services.harnesses.models import HarnessKind
from codealmanac.services.runs.models import RunId
class RunBuildRequest(CodeAlmanacModel):
cwd: Path
harness: HarnessKind
wiki: str | None = None
name: str | None = None
description: str = ""
title: str | None = None
guidance: str | None = None
force: bool = False
auto_commit: bool = True
@field_validator("name", "description", "title", "guidance")
@classmethod
def require_optional_text(cls, value: str | None) -> str | None:
if value is None:
return None
return required_text(value, "build request text")
class RunBuildWithRunRequest(RunBuildRequest):
run_id: RunIdStep 2: Add build result and payload models
Update src/codealmanac/workflows/build/models.py:
from pathlib import Path
from codealmanac.core.models import CodeAlmanacModel
from codealmanac.services.harnesses.models import HarnessRunResult
from codealmanac.services.index.models import IndexRefreshResult
from codealmanac.services.runs.models import RunRecord
from codealmanac.services.workspaces.models import Workspace
from codealmanac.workflows.lifecycle import LifecycleMutationReport
from codealmanac.workflows.lifecycle_commit import LifecycleCommitPolicy
class BuildPromptPayload(CodeAlmanacModel):
workspace_name: str
workspace_root: Path
almanac_root: Path
source_control: LifecycleCommitPolicy
guidance: str | None = None
class BuildResult(CodeAlmanacModel):
workspace: Workspace
run: RunRecord
harness: HarnessRunResult
safety: LifecycleMutationReport
index: IndexRefreshResultStep 3: Wire build workflow like ingest/garden
BuildWorkflow receives:
workspaces: WorkspacesService
wiki: WikiService
index: IndexService
runs: RunsService
page_runs: PageRunWorkflow
prompts: PromptRendererBuildWorkflow.run(request) performs:
- resolve/register/scaffold
almanac/through existing workspace/wiki services; - reject populated wiki unless
request.forceis true; - start run with
operation=RunOperation.BUILD; - preflight allowed mutations under the configured
almanac/; - render prompt from base
kernel, operationbuild, and runtime context; - run harness in repo root;
- validate changed files stay under
almanac/; - validate harness success;
- refresh index;
- run health validation;
- finish run.
Step 4: Render build prompt from Kushagra's kernel plus build prompt
Use:
BUILD_PROMPT_SECTIONS = (
PromptName.BASE_KERNEL,
PromptName.OPERATION_BUILD,
)The runtime context includes:
Runtime context:
{
"workspace_name": "...",
"workspace_root": "...",
"almanac_root": ".../almanac",
"source_control": {...},
"guidance": "..."
}Step 5: Keep deterministic scaffold as a private helper
The deterministic scaffold remains inside workspace/wiki initialization. It is not called build, not rendered as a build result, and not exposed as a lifecycle operation.
Step 6: Add build workflow tests
Tests in tests/test_build_workflow.py:
test_init_runs_model_backed_build_operationtest_build_prompt_uses_kushagra_build_prompttest_build_rejects_populated_wiki_without_forcetest_build_force_allows_existing_wikitest_build_records_run_operation_buildtest_build_rejects_harness_mutation_outside_almanactest_build_refreshes_index_after_harness_writes_pagestest_build_respects_auto_commit_policy
Use a fake harness that writes:
---
title: Getting Started
topics: [getting-started]
sources:
- type: file
path: pyproject.toml
---
# Getting Started
This wiki starts with the Python package metadata.to almanac/getting-started.md.
Step 7: Run focused tests
uv run pytest tests/test_build_workflow.py tests/test_cli.py -q
uv run ruff check src/codealmanac/workflows/build src/codealmanac/app.py tests/test_build_workflow.pyExpected: pass.
Step 8: Commit
git add src/codealmanac/workflows/build src/codealmanac/workflows/page_run src/codealmanac/workflows/lifecycle_mutation.py src/codealmanac/app.py tests/test_build_workflow.py tests/test_cli.py
git commit -m "feat: implement model backed build operation"Task 6: Add Build To Queue And Worker#
Files:
- Modify:
src/codealmanac/workflows/run_queue/service.py - Modify:
src/codealmanac/workflows/run_queue/models.py - Modify:
src/codealmanac/services/runs/models.py - Modify:
src/codealmanac/cli/dispatch/worker.py - Modify:
tests/test_run_queue_workflow.py
Step 1: Allow queued build specs
RunSpec already accepts RunOperation.BUILD after Task 3. Add queue methods:
def queue_build(self, request: RunBuildRequest) -> RunRecord:
return self.runs.queue(
QueueRunRequest(
cwd=request.cwd,
wiki=request.wiki,
title=request.title or "Build wiki",
spec=RunSpec(
operation=RunOperation.BUILD,
cwd=request.cwd,
wiki=request.wiki,
harness=request.harness,
title=request.title,
guidance=request.guidance,
auto_commit=request.auto_commit,
),
)
)Add:
def start_build_background(self, request: RunBuildRequest) -> RunQueueStartResult:
run = self.queue_build(request)
worker = self.spawn_worker(request.cwd, request.wiki)
return RunQueueStartResult(run=run, worker=worker)Step 2: Drain build specs
In run_one, add:
if spec.operation == RunOperation.BUILD:
result = self.build.run_with_run(
RunBuildWithRunRequest(
cwd=spec.cwd,
wiki=spec.wiki,
harness=spec.harness,
title=spec.title,
guidance=spec.guidance,
auto_commit=spec.auto_commit,
run_id=queued.record.run_id,
)
)
return result.runStep 3: Construct queue with build workflow
Update CodeAlmanacWorkflows.queue construction in src/codealmanac/app.py so RunQueueWorkflow receives build, ingest, and garden.
Step 4: Test queued build
Add tests:
- background init queues operation
build; - worker drains queued build;
- queued build writes
almanac/getting-started.md; - queued build records operation
build.
Step 5: Run focused tests
uv run pytest tests/test_run_queue_workflow.py tests/test_build_workflow.py tests/test_cli.py -qExpected: pass.
Step 6: Commit
git add src/codealmanac/workflows/run_queue src/codealmanac/services/runs/models.py src/codealmanac/cli/dispatch/worker.py src/codealmanac/app.py tests/test_run_queue_workflow.py
git commit -m "feat: queue build operation"Task 7: Clean Sync Into Transcript Intake Only#
Files:
- Modify:
src/codealmanac/workflows/sync/service.py - Modify:
src/codealmanac/workflows/sync/execution.py - Modify:
src/codealmanac/workflows/sync/models.py - Modify:
src/codealmanac/cli/parser/lifecycle.py - Modify:
src/codealmanac/cli/dispatch/sync.py - Modify:
src/codealmanac/cli/render/lifecycle.py - Modify:
tests/test_sync_workflow.py - Modify:
tests/test_cli.py
Step 1: Rename sync language in code comments and render copy
Use "transcript intake" for sync descriptions:
sync quiet local transcripts into ingest runsDo not call sync a lifecycle operation in help text, renderer text, tests, or docs.
Step 2: Keep sync execution creating ingest requests
sync_ingest_request remains the only run-producing path:
return RunIngestRequest(
cwd=item.candidate.repo_root,
inputs=(f"transcript:{item.candidate.transcript_path}",),
harness=request.harness,
wiki=request.wiki,
title=sync_ingest_title(item.candidate),
guidance=sync_ingest_guidance(item),
auto_commit=request.auto_commit,
)Step 3: Add tests that sync never records operation sync
Test:
runs = app.runs.list(ListRunsRequest(cwd=repo))
assert all(run.operation == RunOperation.INGEST for run in runs)Step 4: Run focused tests
uv run pytest tests/test_sync_workflow.py tests/test_cli.py -q
uv run ruff check src/codealmanac/workflows/sync src/codealmanac/cli tests/test_sync_workflow.pyExpected: pass.
Step 5: Commit
git add src/codealmanac/workflows/sync src/codealmanac/cli tests/test_sync_workflow.py tests/test_cli.py
git commit -m "refactor: make sync transcript intake only"Task 8: Clean Automation Naming Around Tasks, Not Operations#
Files:
- Modify:
src/codealmanac/services/automation/models.py - Modify:
src/codealmanac/services/automation/definitions.py - Modify:
src/codealmanac/services/automation/jobs.py - Modify:
src/codealmanac/services/automation/service.py - Modify:
src/codealmanac/services/setup/planning.py - Modify:
src/codealmanac/cli/render/setup.py - Modify:
tests/test_automation_service.py - Modify:
tests/test_setup_service.py - Modify:
tests/test_cli.py
Step 1: Keep automation values as scheduled tasks
Scheduled task values remain:
sync
garden
updateMeaning:
syncscheduled task runs transcript intake and createsingestoperations;gardenscheduled task createsgardenoperations;updatescheduled task updates the product and creates no wiki operation.
Step 2: Rename user copy
Setup screen copy:
How should your wikis be updated?Automatic side:
sync agent sessions
garden wiki structureManual side:
run them yourself
no wiki schedulesProduct update screen:
Keep CodeAlmanac itself up to date?Automatic side:
install product updater
new versions arrive automaticallyManual side:
update yourself
no product update scheduleDo not use "operation" in setup copy for scheduled tasks.
Step 3: Add tests
Tests assert:
- setup output contains "sync agent sessions";
- setup output contains "garden wiki structure";
- setup output does not say "initialized";
- setup output does not call sync an operation;
- automation job for
syncrunscodealmanac sync; - automation job for
gardenrunscodealmanac garden; - automation job for
updaterunscodealmanac update --scheduled.
Step 4: Run focused tests
uv run pytest tests/test_automation_service.py tests/test_setup_service.py tests/test_cli.py -q
uv run ruff check src/codealmanac/services/automation src/codealmanac/services/setup src/codealmanac/cli/render/setup.pyExpected: pass.
Step 5: Commit
git add src/codealmanac/services/automation src/codealmanac/services/setup src/codealmanac/cli/render/setup.py tests/test_automation_service.py tests/test_setup_service.py tests/test_cli.py
git commit -m "fix: separate scheduled tasks from wiki operations"Task 9: Update AGENTS Guide And Installed Instructions#
Files:
- Modify:
src/codealmanac/services/setup/agent-guide.md - Modify:
src/codealmanac/integrations/setup/guide.py - Modify:
tests/test_setup_service.py - Modify:
tests/test_public_contract.py
Step 1: Rewrite operation model in guide
The guide says:
CodeAlmanac has three internal wiki operations:
- `build`: first substantial wiki construction, started by `codealmanac init`
- `ingest`: update the wiki from explicit sources or synced agent transcripts
- `garden`: maintain structure, topics, links, stale claims, and page boundaries
`sync` is transcript intake. It scans quiet agent sessions and starts `ingest`
runs. `update` is product maintenance. Neither is a wiki operation.Step 2: Update commands in guide
Normal agent commands:
codealmanac search "<query>"
codealmanac show <page-path>
codealmanac topics
codealmanac healthLifecycle commands:
codealmanac init
codealmanac ingest <source...>
codealmanac gardenTranscript intake:
codealmanac sync
codealmanac sync statusNo capture. No absorb. No almanac binary in installed guide.
Step 3: Test installed guide
Tests assert the rendered guide:
- includes the three operation bullets;
- includes
codealmanac init; - includes
sync is transcript intake; - excludes
capture; - excludes
absorb; - excludes
.almanac/pages; - excludes
files:.
Step 4: Run focused tests
uv run pytest tests/test_setup_service.py tests/test_public_contract.py -qExpected: pass.
Step 5: Commit
git add src/codealmanac/services/setup/agent-guide.md src/codealmanac/integrations/setup/guide.py tests/test_setup_service.py tests/test_public_contract.py
git commit -m "docs: install correct agent operation guide"Task 10: Update README, Concepts, And Public Docs#
Files:
- Modify:
README.md - Modify:
docs/concepts.md - Modify:
CONTRIBUTING.md - Modify:
tests/test_public_contract.py
Step 1: Public docs command model
Docs state:
`codealmanac init` builds the first wiki for a repo. Internally that run is
recorded as operation `build`.
The only internal wiki operations are `build`, `ingest`, and `garden`.Step 2: Public docs sync model
Docs state:
`codealmanac sync` scans quiet local agent transcripts and starts ordinary
`ingest` runs. Sync is intake, not an operation.Step 3: Public docs setup model
Docs state:
`codealmanac setup` is machine-level onboarding. It installs agent instructions,
scheduled wiki maintenance, product updates, and commit policy instructions.
It does not initialize a repo. Run `codealmanac init` inside a repo.Step 4: Update public contract fragments
Required fragments include:
- "Internal wiki operations:
build,ingest,garden" - "
codealmanac initstarts the build operation" - "
codealmanac syncstarts ingest runs"
Forbidden fragments include:
- "
codealmanac build" - "almanac capture"
- "absorb"
- ".almanac/pages"
- "files:"
Step 5: Run docs tests
uv run pytest tests/test_public_contract.py -q
rg -n "codealmanac build|almanac capture|\\babsorb\\b|\\.almanac/pages|files:" README.md docs src/codealmanac/manual src/codealmanac/services/setup/agent-guide.mdExpected:
- pytest passes;
- grep returns only approved explicit migration-history references.
Step 6: Commit
git add README.md docs/concepts.md CONTRIBUTING.md tests/test_public_contract.py
git commit -m "docs: document init as build operation"Task 11: End-To-End Smoke Tests#
Files:
- Modify:
tests/test_cli.py - Modify:
tests/test_build_workflow.py - Modify:
tests/test_sync_workflow.py
Step 1: Add CLI smoke for init/build
Test script:
result = run_cli(("init", str(repo), "--using", "codex"))
assert result.exit_code == 0
runs = app.runs.list(ListRunsRequest(cwd=repo))
assert runs[0].operation == RunOperation.BUILD
assert (repo / "almanac/getting-started.md").is_file()Step 2: Add CLI smoke for sync/ingest
Test script:
result = run_cli(("sync", "--foreground", "--using", "codex"))
assert result.exit_code == 0
runs = app.runs.list(ListRunsRequest(cwd=repo))
assert all(run.operation == RunOperation.INGEST for run in runs)Step 3: Add CLI smoke for setup next step
Setup final panel says:
Navigate to your repo of choice
codealmanac initIt does not list codealmanac build.
Step 4: Run full tests
uv run pytest -q
uv run ruff check .
git diff --checkExpected:
- full pytest passes;
- ruff passes;
- whitespace check passes.
Step 5: Commit
git add tests/test_cli.py tests/test_build_workflow.py tests/test_sync_workflow.py
git commit -m "test: cover operation architecture end to end"Task 12: Manual Product Feel Check#
Files:
- No source changes after this task except fixes discovered by smoke commands.
Step 1: Clean setup smoke
Run:
tmp_home=$(mktemp -d)
HOME="$tmp_home" uv run codealmanac setup --target codex --sync-off --garden-off --no-auto-update --yesExpected output:
- figlet banner appears;
- tagline says "The self-updating wiki for your coding agents";
- no
initializedwording; - no
buildcommand in next steps; - next steps include only:
cd /path/to/your/repo
codealmanac initStep 2: Clean init smoke
Run:
tmp_home=$(mktemp -d)
tmp_repo=$(mktemp -d)
cd "$tmp_repo"
git init
printf '[project]\nname = "sample"\n' > pyproject.toml
HOME="$tmp_home" uv run --directory /Users/rohan/Desktop/Projects/codealmanac codealmanac init --using codex --foregroundExpected:
- a run is recorded as operation
build; - generated wiki files live under
almanac/; - no runtime files appear under committed
almanac/; codealmanac search gettingreturns a result.
Step 3: Clean sync smoke
Run a test with fake transcript fixtures through pytest, not real user transcripts:
uv run pytest tests/test_sync_workflow.py -qExpected:
- sync starts ingest runs;
- no sync operation record exists.
Step 4: Final grep
Run:
rg -n "RunOperation\\.SYNC|operation: sync|operation=RunOperation\\.SYNC|codealmanac build|almanac capture|\\babsorb\\b|\\.almanac/pages|files:" src tests README.md docs notes.md implementation-tickets.mdExpected:
- no live product hits;
- explicit historical docs are outside this grep scope.
Step 5: Final commit
Commit any smoke fixes:
git add .
git commit -m "fix: align smoke behavior with three operations"Final Verification Gate#
Run:
uv run pytest -q
uv run ruff check .
git diff --check
uv build --out-dir dist
uvx twine check dist/*Expected:
- pytest passes;
- ruff passes;
- diff check passes;
- package build passes;
- twine check passes.
Then run:
git log --oneline -12
git status --short --branchExpected:
- task commits appear in order;
- working tree is clean.