Shipped the engine behind this very site: a bilingual portfolio whose content is curated automatically from real work sessions. A session-end hook evaluates each Claude Code session against a relevance rubric; when something clears the bar, it is written up in two languages, sanitized, and committed as a draft that publishes with one command.
Outcome: The site you are reading was produced by this pipeline.
Technical detail
Three components: an Astro static site (i18n EN/PT, feed/projects/CV rendered from JSON at build time), a Python MCP server exposing five tools (log_activity, review_and_publish, add_project, update_now, get_portfolio_state) that write through the GitHub Contents API, and a Stop hook that embeds the rubric verbatim so criteria changes require no code changes. Validation runs three layers deep: JSON Schema, bilingual completeness (a missing translation fails the build, by design), and a local denylist as a deterministic backstop behind the LLM's category-based sanitization.
astromcppythonclaude-codei18n
First real-world use of CSS scroll-driven animations: this feed's timeline draws itself as you scroll, with zero JavaScript. The motion concept for the site — pulse, trace, breath — had to communicate 'alive' without a single animation library.
Outcome: Feed timeline draws on scroll in ~20 lines of CSS; zero JS, zero libraries.
Technical detail
animation-timeline: view() maps an animation's progress to an element's position in the viewport — the timeline border scales from 0 to full height as each entry crosses it. Wrapped in @supports so unsupported browsers just see the static border, and disabled under prefers-reduced-motion. The rest of the motion system is a ~30-line inline IntersectionObserver (staggered reveal) gated behind an html.js class, so a JavaScript failure can never leave content hidden.
cssscroll-driven-animationsprogressive-enhancement
My portfolio needed to update itself without becoming a server to maintain. The decision: no CMS, no database, no backend — content lives as JSON in a git repository, every update is a commit, and the site is a static build triggered by pushes. A drafts branch acts as a mandatory buffer: automation can write, but nothing goes public without a human merge.
Outcome: Zero infrastructure to operate; every content change is auditable in git history.
Technical detail
A competent peer might reasonably have chosen a headless CMS or a small API. Git-as-database won on three fronts: full history and rollback for free, zero infrastructure cost, and a deploy pipeline (push → rebuild) that static hosts provide out of the box. The drafts branch exists for confidentiality, not relevance — client work must never auto-publish without a human glance. Trade-off accepted: no real-time updates, which a portfolio doesn't need.
architecturestatic-sitegitastro