[{"id":44,"slug":"anthropic-academy-certifications","title":"Anthropic Academy \u2014 Six Certifications Completed","summary":"I completed six Anthropic Academy courses covering the Claude API, Model Context Protocol, subagents, agentic workflows, Claude Code, and AI fluency \u2014 each with a verified certificate from Anthropic Education.","reading_time":0,"published_at":"2026-05-31T07:48:59.000000Z","cover_image":null,"tags":[{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":44,"post_tag_id":7}},{"id":8,"name":"RAG","slug":"rag","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":44,"post_tag_id":8}},{"id":19,"name":"Career","slug":"career","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":44,"post_tag_id":19}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":44,"post_tag_id":27}}]},{"id":43,"slug":"prompt-versioning-production-llm","title":"Prompt Versioning in Production: Managing LLM Prompts Like Code","summary":"How EasyCommerce manages LLM prompts across Claude, OpenAI, and DeepSeek with a versioned registry, structured evals in CI, and a rollback path that does not require a deployment.","reading_time":0,"published_at":"2026-05-25T04:03:10.000000Z","cover_image":null,"tags":[{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":43,"post_tag_id":2}},{"id":3,"name":"WordPress","slug":"wordpress","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":43,"post_tag_id":3}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":43,"post_tag_id":7}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":43,"post_tag_id":25}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":43,"post_tag_id":27}}]},{"id":42,"slug":"rag-without-framework-pgvector-claude","title":"RAG Without a Framework: A Minimal pgvector Pipeline with Claude","summary":"How to build a complete RAG pipeline in Python without LangChain or LlamaIndex \u2014 chunking, embedding with text-embedding-3-large, pgvector retrieval, and grounded generation with Claude \u2014 with the tradeoffs that matter at production scale.","reading_time":0,"published_at":"2026-05-25T04:02:08.000000Z","cover_image":null,"tags":[{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":42,"post_tag_id":7}},{"id":8,"name":"RAG","slug":"rag","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":42,"post_tag_id":8}},{"id":10,"name":"pgvector","slug":"pgvector","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":42,"post_tag_id":10}},{"id":13,"name":"Performance","slug":"performance","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":42,"post_tag_id":13}}]},{"id":41,"slug":"python-mcp-server-claude-code","title":"Building a Claude Code MCP Server in Python: Lessons from codebase-research-agent","summary":"How codebase-research-agent exposes a tool-using AI agent as a Claude Code MCP server \u2014 JSON-RPC over Streamable HTTP, tool registration, streaming SSE, and the four things that broke in production before it worked reliably.","reading_time":0,"published_at":"2026-05-25T04:01:05.000000Z","cover_image":null,"tags":[{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":41,"post_tag_id":7}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":41,"post_tag_id":25}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":41,"post_tag_id":27}}]},{"id":40,"slug":"legal-rag-edit-distance","title":"How I Cut Edit Distance from 168 to 43 in a Legal Document RAG Pipeline","summary":"Three architectural changes that brought average edit distance from 168 to 43 in a legal document RAG pipeline \u2014 section-scoped chunking, section-scoped exemplar prompting, and switching from a general embedding model to a legal-domain one \u2014 with a CI eval suite that made the improvement trajectory visible and reproducible.","reading_time":0,"published_at":"2026-05-22T03:35:53.000000Z","cover_image":null,"tags":[{"id":10,"name":"pgvector","slug":"pgvector","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":40,"post_tag_id":10}}]},{"id":39,"slug":"codebase-research-agent-react","title":"Designing a ReAct-Style Codebase Research Agent with Tool Use","summary":"How codebase-research-agent uses a ReAct loop to orchestrate semantic search, AST navigation, symbol lookup, grep, and git blame as callable tools \u2014 the hybrid retrieval substrate it operates on, and why framing RAG as a tool rather than a pipeline changes the architecture fundamentally.","reading_time":0,"published_at":"2026-05-22T03:35:49.000000Z","cover_image":null,"tags":[]},{"id":38,"slug":"jobpulse-rag-pipeline","title":"Building a 12-Source Job Discovery Pipeline with RAG and pgvector","summary":"How JobPulse aggregates job listings across 12 sources in three tiers, embeds your resume into pgvector, and generates grounded cover letters via Claude \u2014 including the async adapter protocol, composite scoring model, and the three retrieval failure modes that shaped the final architecture.","reading_time":0,"published_at":"2026-05-22T03:35:44.000000Z","cover_image":null,"tags":[{"id":10,"name":"pgvector","slug":"pgvector","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":38,"post_tag_id":10}}]},{"id":37,"slug":"laravel-mcp-tool-registry-at-scale","title":"Scaling a Laravel MCP Tool Registry to 46 Tools","summary":"The May 12 post covered the MCP server architecture. This one goes inside the tool registry: class-per-tool structure, Sanctum ability scoping, JSON Schema validation before dispatch, tag-based auto-discovery, and the three things that broke when the registry hit 46 tools.","reading_time":0,"published_at":"2026-05-14T07:09:23.000000Z","cover_image":null,"tags":[{"id":1,"name":"Laravel","slug":"laravel","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":37,"post_tag_id":1}},{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":37,"post_tag_id":2}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":37,"post_tag_id":7}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":37,"post_tag_id":25}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":37,"post_tag_id":27}}]},{"id":36,"slug":"heading-aware-chunking-rag","title":"Stop Using Fixed-Size Chunks for Technical Documentation","summary":"Why naive fixed-size chunking breaks on code-heavy documentation, and the heading-aware approach with paragraph fallback and overlap that replaced it in this portfolio's RAG pipeline.","reading_time":0,"published_at":"2026-05-14T07:08:11.000000Z","cover_image":null,"tags":[{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":36,"post_tag_id":2}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":36,"post_tag_id":7}},{"id":8,"name":"RAG","slug":"rag","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":36,"post_tag_id":8}},{"id":13,"name":"Performance","slug":"performance","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":36,"post_tag_id":13}}]},{"id":35,"slug":"voyage-vs-openai-embeddings-rag-php","title":"Voyage AI vs OpenAI Embeddings for Technical RAG in PHP","summary":"Why I switched from OpenAI text-embedding-3-small to Voyage AI voyage-code-3 for this portfolio's RAG layer \u2014 model comparison, the input_type asymmetry Voyage requires, measured retrieval improvement, and the migration path that keeps search live throughout.","reading_time":0,"published_at":"2026-05-14T07:07:26.000000Z","cover_image":null,"tags":[{"id":1,"name":"Laravel","slug":"laravel","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":35,"post_tag_id":1}},{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":35,"post_tag_id":2}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":35,"post_tag_id":7}},{"id":8,"name":"RAG","slug":"rag","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":35,"post_tag_id":8}},{"id":10,"name":"pgvector","slug":"pgvector","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":35,"post_tag_id":10}},{"id":13,"name":"Performance","slug":"performance","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":35,"post_tag_id":13}}]},{"id":34,"slug":"claude-tool-calling-loop-laravel","title":"A Claude Tool-Calling Loop in Laravel: From First Request to Final Answer","summary":"The exact pattern for registering tools, dispatching multi-turn Claude conversations, and processing tool results in a Laravel service \u2014 including the three production failure modes the happy path does not cover.","reading_time":0,"published_at":"2026-05-14T07:05:44.000000Z","cover_image":null,"tags":[{"id":1,"name":"Laravel","slug":"laravel","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":34,"post_tag_id":1}},{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":34,"post_tag_id":2}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":34,"post_tag_id":7}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":34,"post_tag_id":25}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":34,"post_tag_id":27}}]},{"id":33,"slug":"llms-wordpress-plugin-async-architecture","title":"Embedding LLMs in a WordPress Plugin: EasyCommerce's Async Architecture","summary":"How EasyCommerce wires LLM calls \u2014 product description generation, fraud detection, and inventory forecasting \u2014 into a WordPress plugin using async dispatch and a provider abstraction that survives outages and scales across catalogues.","reading_time":0,"published_at":"2026-05-14T06:56:58.000000Z","cover_image":null,"tags":[{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":33,"post_tag_id":2}},{"id":3,"name":"WordPress","slug":"wordpress","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":33,"post_tag_id":3}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":33,"post_tag_id":7}},{"id":13,"name":"Performance","slug":"performance","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":33,"post_tag_id":13}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":33,"post_tag_id":25}}]},{"id":31,"slug":"mcp-servers-for-laravel-a-production-pattern","title":"MCP Servers for Laravel: A Production Pattern","summary":"How I built the MCP server that powers AI access to this portfolio \u2014 JSON-RPC over Streamable HTTP, Sanctum bearer auth, an ability-scoped tool registry, and the gotchas worth knowing before you ship.","reading_time":0,"published_at":"2026-05-12T02:38:14.000000Z","cover_image":null,"tags":[{"id":1,"name":"Laravel","slug":"laravel","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":31,"post_tag_id":1}},{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":31,"post_tag_id":2}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":31,"post_tag_id":7}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":31,"post_tag_id":25}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":31,"post_tag_id":27}}]},{"id":16,"slug":"sqlite-rag-php-cosine-similarity","title":"RAG on SQLite: Pure-PHP Cosine Similarity Without pgvector","summary":"How I built RAG retrieval against a SQLite database using pure-PHP cosine similarity \u2014 when it scales, when it doesn't, and the migration path to pgvector.","reading_time":9,"published_at":"2026-04-25T09:00:00.000000Z","cover_image":null,"tags":[{"id":1,"name":"Laravel","slug":"laravel","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":16,"post_tag_id":1}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":16,"post_tag_id":7}},{"id":8,"name":"RAG","slug":"rag","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":16,"post_tag_id":8}},{"id":13,"name":"Performance","slug":"performance","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":16,"post_tag_id":13}},{"id":26,"name":"SQLite","slug":"sqlite","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":16,"post_tag_id":26}}]},{"id":17,"slug":"multi-provider-ai-driver-pattern-laravel","title":"A Multi-Provider AI Driver Pattern for Laravel","summary":"A clean driver pattern for switching between Claude, OpenAI, Groq, and Ollama in a Laravel app \u2014 with failover, testing, and a single calling interface.","reading_time":10,"published_at":"2026-03-10T09:00:00.000000Z","cover_image":null,"tags":[{"id":1,"name":"Laravel","slug":"laravel","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":17,"post_tag_id":1}},{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":17,"post_tag_id":2}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":17,"post_tag_id":7}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":17,"post_tag_id":25}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":17,"post_tag_id":27}}]},{"id":18,"slug":"claude-prompt-caching-laravel","title":"Cutting Claude API Costs by 89% with Prompt Caching","summary":"A practical Laravel integration of Anthropic prompt caching \u2014 what to cache, the 1024-token minimum, multi-breakpoint strategies, and real cost numbers.","reading_time":8,"published_at":"2026-02-05T09:00:00.000000Z","cover_image":null,"tags":[{"id":1,"name":"Laravel","slug":"laravel","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":18,"post_tag_id":1}},{"id":7,"name":"AI \/ LLMs","slug":"ai-llms","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":18,"post_tag_id":7}},{"id":13,"name":"Performance","slug":"performance","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":18,"post_tag_id":13}},{"id":27,"name":"Anthropic","slug":"anthropic","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":18,"post_tag_id":27}}]},{"id":13,"slug":"gutenberg-block-development-2025","title":"Building Production Gutenberg Blocks in 2025","summary":"A practical guide to building Gutenberg blocks with the v3 API \u2014 block.json, dynamic blocks, deprecations, and the testing strategies that actually work.","reading_time":10,"published_at":"2026-01-22T09:00:00.000000Z","cover_image":null,"tags":[{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":13,"post_tag_id":2}},{"id":3,"name":"WordPress","slug":"wordpress","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":13,"post_tag_id":3}},{"id":6,"name":"React","slug":"react","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":13,"post_tag_id":6}},{"id":28,"name":"Gutenberg","slug":"gutenberg","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":13,"post_tag_id":28}}]},{"id":14,"slug":"dokan-multi-vendor-commission-engine","title":"Building Custom Commission Logic in Dokan Multi-Vendor","summary":"How Dokan's commission system actually works, the filters you need, per-category and tiered commission patterns, and what to never do.","reading_time":11,"published_at":"2025-11-18T09:00:00.000000Z","cover_image":null,"tags":[{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":14,"post_tag_id":2}},{"id":3,"name":"WordPress","slug":"wordpress","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":14,"post_tag_id":3}},{"id":4,"name":"WooCommerce","slug":"woocommerce","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":14,"post_tag_id":4}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":14,"post_tag_id":25}},{"id":29,"name":"Dokan","slug":"dokan","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":14,"post_tag_id":29}}]},{"id":15,"slug":"wordpress-plugin-security-checklist","title":"WordPress Plugin Security: Lessons from Two Disclosures","summary":"The exact security checklist I run every plugin through before release \u2014 capability checks, escaping, nonces, and the disclosed bugs that taught me each lesson.","reading_time":10,"published_at":"2025-09-08T09:00:00.000000Z","cover_image":null,"tags":[{"id":2,"name":"PHP","slug":"php","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":15,"post_tag_id":2}},{"id":3,"name":"WordPress","slug":"wordpress","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":15,"post_tag_id":3}},{"id":16,"name":"Open Source","slug":"open-source","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":15,"post_tag_id":16}},{"id":24,"name":"Security","slug":"security","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":15,"post_tag_id":24}}]},{"id":1,"slug":"tailwind-v4-migration-css-first","title":"Tailwind v4 Migration: From v3 Config to CSS-First Tokens","summary":"A practical guide to migrating a real Laravel app from Tailwind v3 to v4 \u2014 what breaks, the new @theme syntax, plugin migration, and the 5\u00d7 build speedup.","reading_time":8,"published_at":"2025-08-12T09:00:00.000000Z","cover_image":null,"tags":[{"id":13,"name":"Performance","slug":"performance","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":1,"post_tag_id":13}},{"id":20,"name":"Tailwind CSS","slug":"tailwind-css","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":1,"post_tag_id":20}},{"id":25,"name":"Architecture","slug":"architecture","created_at":"2026-05-11T09:35:51.000000Z","updated_at":"2026-05-11T09:35:51.000000Z","pivot":{"post_id":1,"post_tag_id":25}}]}]