LifeStarter
LifeStarter
Jekyll static site on GitHub Pages — consumer life-stages content with financial
calculators (calculators/, fin_calc/, tools/) organised around life events:
first apartment, college freshman, new parent, retirement.
Commands
make serve # local preview
make build # jekyll build
make lint # stylelint (assets/css) + markdownlint (_posts)
make check # lint + test ← the gate; run before committing
make test # build, then htmlproofer + frontmatter/content checks
# + scripts/check-rendered-affiliate.sh on the built _site
make clean
Gotchas
- Uses the
github-pagesgem, not plain Jekyll. Plugin versions are pinned by GitHub, so a plugin that works locally can still be unsupported on Pages. Add plugins only ifgithub-pagesalready bundles them. - Content is YMYL (financial advice adjacent). Calculator logic and any figure presented as guidance needs a real source, not a plausible number. This is the category where an invented rate becomes someone’s actual decision.
llms.txtand the “For AI Agents” footer link are deliberate, added for AI discoverability — do not remove them as cruft._site/is build output; gitignored, never edit.
SEO pre-commit hooks
This repo is audited by the shared tooling in ~/Sites/agency (the emaxon/epm-agency
repo). It supersedes epm-seo-audit, which is retired. The installed
.git/hooks/pre-commit runs both checks on staged files:
~/Sites/agency/.venv/bin/python3 \
~/Sites/agency/lib/audit_precommit/audit_frontmatter.py --repo-path . --only-staged
~/Sites/agency/.venv/bin/python3 \
~/Sites/agency/lib/audit_precommit/audit_content.py --repo-path . --only-staged
Frontmatter completeness and content quality are enforced there, not in make lint.
Install or remove the hook with
bash ~/Sites/agency/lib/audit_precommit/install_hooks.sh --repo-path . [--uninstall].
Automated PRs from the agency repo
~/Sites/agency also runs the pipelines that open PRs here — tasks/seo_autofix.py,
tasks/gumroad_link_autofix.py, tasks/amazon_link_autofix.py. They run against their
own clone, so their commits arrive via origin, not from this working copy.
One line in _posts/2026-04-04-how-to-evaluate-a-job-offer.md went through three of them:
#38 (Gumroad autofix) stripped a dead product link, #39 (title_too_long) reintroduced
it, and #61 (broken_ext_link) stripped it again, leaving a bold call to action that
linked nowhere.
When fixing a link one of them touched, prefer a relative in-repo target such as
/product/<kit>/. Both strip handlers match an exact dead URL supplied by a finding, so
neither rewrites a relative path. That is not blanket immunity: seo_autofix has a
separate broken_internal_link handler, so the destination has to actually exist.