software = science + art + people
The project plan for turning the codecraft.co WordPress export into a curated, professional anthology of essays. Tick items as they’re completed. See AGENTS.md for vision and principles.
Created 2026-06-01.
The funnel: 124 essays → mechanically clean → owned images → rich metadata
→ curated to N published → SEO’d + cross-linked + PDF’d → M selected into a book.
Locked decisions: images case-by-case (own/generate/redraw/drop); comments →
collapsed appendix; prose = mechanical fixes only; public archive is itself
curated (status: published | retired, book: true subset).
AGENTS.md (vision, principles, mechanical-only guardrail, conventions)CLAUDE.md redirect to AGENTS.mdROADMAP.md (this file)docs/conventions.mdCC-XXX-YYMMOO item-id convention → docs/conventions.mdscripts/ + tests/ + requirements.txttags (controlled vocab of 10), not mutually-exclusive categories — see docs/conventions.mditem_id (CC-YYMMOO, no category segment) + tags to every essay — scripts/assign_ids.py, data in scripts/tags.yml--- fences; unquoted title:/author: values with colons) — scripts/fix_frontmatter.py. Unblocked dates/IDs.[caption] shortcodes to clean <figure> markup (19 blocks in 17 essays) — scripts/lint_wordpress.py, test tests/test_no_wordpress_residue.pyscripts/lint_wordpress.py (245 lines across 33 essays; « marker), test test_no_pingback_comments<details> appendix in _layouts/default.html (also fixed the stray </h2>); test tests/test_layout.pyassets/): resolve wp-content refs, fix malformed image URLs (staticfliccom, static.flickr.com), normalize <img> tagsM1 pure items complete; remaining M1 work folded into M2.
inventory_images.py → assets/image-triage.yml — 157 refs catalogued (39 local, 32 wp, 84 external, 2 malformed); 70 auto-marked own, 87 blank to triage. Also emits a browsable images_inventory.html contact sheet (thumbnail/orig URL/license/local path/disposition + filters; gitignored). Test tests/test_image_inventory.py (6 tests).wp-content image refs → assets/ (1 scn-shot-… needs a judgment call), fix the 2 malformed image URLs, normalize <img> tags — drive from the manifestdisposition per image for the 87 blanks (own / generate / redraw / drop)apply_image_triage.py: localize, generate, redraw, or drop + reflowassets/CREDITS.ymlcategory (per frozen taxonomy) to each essaykeywords, abstract, version, revision_datedatestatus: published | retiredindex.md (published only)README.md list with the themed TOCjekyll-seo-tag (title/description/keywords)Article/BlogPosting) in the layoutsitemap.xml, canonical URLs, corrected robots.txtredirect_from URLs still resolvepandoc.py + LaTeX headers from ../papers, adapted to essay metadataEach quality goal gets a fixer script (--check-only capable) and a prover test.
Live suite: tests/ (run pytest) — 10 tests green covering frontmatter parse,
item-id format/uniqueness/determinism, and tag validity/coverage.
validate_frontmatter.py ↔ test: tests/test_frontmatter.py covers required-now fields (title/date/slug/item_id/tags); M3 fields (status/keywords/abstract/version/revision_date) still to enforceassign_ids.py ↔ test: tests/test_item_ids.py + tests/test_tags.py — unique, well-formed, deterministic ids; controlled tagscheck_links.py ↔ test: no broken internal/external linkscheck_images.py ↔ test: no external images; all local images exist + alt-text + qualitygenerate_index.py ↔ test: index/TOC in sync with corpuscheck_crossrefs.py ↔ test: related-essay links resolvecheck_citations.py ↔ test: external sources well-formed + reachable/archivedcheck_seo.py ↔ test: required SEO fields present + within length, no dupesbuild_pdfs.py ↔ test: a current PDF exists per published essaylint_wordpress.py ↔ test: no [caption], wp-content, or WP residue.github/workflows/ci.yml runs pytest + the --check-only guards on every push/PR; status badge in README. Keep scheduled link-check.checkout@v6, setup-python@v6; verified setup-python@v5 is node20)book: truetools/migration/ (don’t extend them)lycheeverse/lychee-action v1.10.0 → v2.8.0 (arbitrary code injection in < 2.0.2); also bumped actions/checkout v4 → v6 (node20 → node24)../tti/home for a working example; orthogonal to dependency hygiene