Original Reddit post

CLAUDE.md files. System prompts. README files with setup instructions. Architecture docs. API references. Runbooks. Onboarding guides. If you’ve written a markdown file meant for an AI to read, it almost certainly contains values that were true when you wrote them and are no longer true now. The port your dev server runs on. The current version of the package. Which env vars are actually set. How many tests exist. Whether a service is running. These things change constantly, and markdown doesn’t know it. So developers do what honest writers do - they add caveats. “Check package.json if this is stale.” “Verify before running.” “New packages may have been added since this was written.” The intent is good. The effect is a list of things the AI has to go verify before it can do anything you actually asked for. We counted them in a real CLAUDE.md. There were seven. And CLAUDE.md is just one file type - the same problem exists everywhere AI reads markdown today. The Pre-Flight Tax Here’s a representative CLAUDE.md. Nothing here is invented - these are patterns from real production repos:

CLAUDE.md > Before starting any session: Read ~/projects/api-core/SYNC.md first and check for > pending cross-project items. Update it after completing work. ## Project Overview Acme API - TypeScript REST API. Current version: 1.4.2 (check package.json if this is stale). ## Build and Run Commands # Development (API runs on port 3001, website on port 3000) # Note: PORT is set in .env - verify before running npm run dev:api npm run dev:web # Tests - currently 47 tests across 12 files npm run test:run Before running tests, make sure the test database is not already running on port 27018. Check with: docker ps | grep mongo-test ## Environment Variables | Variable | Required | Notes | |--------------|----------|-----------------------| | DATABASE_URL | YES | MongoDB connection | | JWT_SECRET | YES | Min 32 characters | | PORT | No | Defaults to 3001 | Check .env before assuming anything is configured. ## Architecture npm workspaces monorepo. Packages: - packages/api/ - packages/web/ - packages/shared/ - packages/db/ When in doubt about file counts or structure, run ls packages/ to check - new packages may have been added since this was written. ## Docker Check docker ps to see if a test container is still running from a previous session before starting a new build.

Before Claude touches a single line of code, it has to: Open ~/projects/api-core/SYNC.md

  • cross-project lookup Read package.json
  • version check Read .env
  • port verification Check all env var statuses - is DATABASE_URL actually set? Run npm run test:run
  • or trust a number that’s probably wrong Run docker ps | grep mongo-test
  • pre-test check Run ls packages/
  • structure verification Seven tool calls. Each one costs a couple of seconds of latency. The test run alone can take ten. Add it up and Claude spends close to half a minute just getting to the starting line - consuming context and generating output before the actual task begins. And that’s the obvious tax. The hidden one is subtler: every one of those checks can generate a follow-up. The .env read reveals WEBHOOK_SECRET isn’t set. Now Claude has to decide whether to flag it or proceed. The docker ps shows a leftover container. Now Claude has to clean it up. Each verification spawns decisions, and each decision costs more context. The Same File, Rewritten MarkdownAI is a superset of Markdown. Any .md file that starts with @markdownai becomes live - directives resolve at render time, before Claude ever sees the file. Here’s what the same CLAUDE.md looks like rewritten: @markdownai v1.0 @prompt role=“context” This document is live. Every value was resolved at render time. Do not look up package.json, .env, or docker ps - current values are already below. @end # CLAUDE.md > Before starting: sync status is live in the Cross-Project Sync section below. ## Project Overview Acme API - version { read ./package.json path=“version” }}. ## Build and Run Commands API on port {{ read .env key=“PORT” fallback=“3001” }}, web on {{ read .env key=“WEB_PORT” fallback=“3000” }}. @list ./package.json path=“scripts” mode=“entries” columns=“key:Command,value:Runs” as=“table” Test suite (live): @query "npm run test:run – --reporter=verbose 2>&1 tail -3" @cache session Mongo test container: @query "docker ps --format '{{.Names} {.Status}}’ grep mongo-test || echo ‘not running - port 27018 is clear’" @cache session ## Environment Variables @if file.exists “.env” | Variable | Required | Status | |--------------|----------|-------------------------------------------------------------| | DATABASE_URL | YES | {{ env.DATABASE_URL != “” ? “set” : “MISSING - will not start” } | | JWT_SECRET | YES | { env.JWT_SECRET != “” ? “set” : “MISSING - auth will fail” }} | NODE_ENV | No | {{ env.NODE_ENV fallback=“development” } | @else WARNING: No .env file found. App will not start. @endif ## Architecture @list ./packages/ type=“dirs” depth=1 as=“list” @tree ./packages/ depth=2 match=“.ts,.tsx” @constraint id=“no-direct-mongo” severity=“critical” NEVER import mongodb directly. All DB access goes through packages/db/src/index.ts. @end @constraint id=“api-versioning” severity=“critical” Every route MUST use /api/v1/ prefix. Unversioned routes are bugs. @end ## Docker Running containers: @query "docker ps --format 'table {.Names}}\t{{.Status}}\t{{.Ports}}'" @cache session @define preflight-cmd "PORT=… && docker build -t acme-api . -q && docker run … && curl -sf …/health && echo ‘PASSED’ | echo ‘FAILED’ ; docker stop && docker rm …" @end @query {{ preflight-cmd } @cache session @if query({{ preflight-cmd }}) match /PASSED/ docker push $DOCKER_HUB_REPO:latest @else @prompt role=“instruction” Container test FAILED. Stop immediately. Do not proceed with any deployment. @end @endif ## Cross-Project Sync @include ./sync-status.md @cache session The directive syntax reads like plain English. @read for file values. @env for environment checks. @query for live shell output. @constraint for rules you want Claude to treat as machine-readable, not prose to skim. @if/@else for conditional context - including the Docker section that hides the push command entirely if the preflight test failed. What Claude Actually Receives mai render runs before the file reaches Claude’s context window. This is what lands:

AI Instructions: This document is live. Do not look up package.json, .env, > or docker ps - the current values are already below. # CLAUDE.md ## Project Overview Acme API - version 1.4.2. ## Build and Run Commands API on port 3001, web on 3000. | Command | Runs | |--------------|------------------------------------------| | dev:api | tsx watch packages/api/src/index.ts | | dev:web | vite --port 3000 | | test:run | vitest run | | test:e2e | playwright test | | build | tsc -b | Test suite (live): Tests 52 passed (52) Duration 3.42s Mongo test container: not running - port 27018 is clear ## Environment Variables | Variable | Required | Status | |--------------|----------|-----------------------------------| | DATABASE_URL | YES | set | | JWT_SECRET | YES | set | | NODE_ENV | No | development | | WEBHOOK_SECRET | YES (prod) | not set - required for production | ## Architecture - packages/api - packages/db - packages/shared - packages/web packages/ api/src/index.ts api/src/routes/auth.ts api/src/routes/orders.ts db/src/index.ts shared/src/types.ts web/src/App.tsx Constraints: | ID | Severity | Rule | |------------------|----------|---------------------------------------------------------------| | no-direct-mongo | CRITICAL | NEVER import mongodb directly. All DB access through packages/db. | | api-versioning | CRITICAL | Every route MUST use /api/v1/ prefix. Unversioned routes are bugs. | ## Docker Running containers: mongo-dev Up 3 hours 0.0.0.0:27017->27017/tcp redis-dev Up 3 hours 0.0.0.0:6379->6379/tcp Pre-push test: PASSED docker push $DOCKER_HUB_REPO:latest ## Cross-Project Sync api-core sync status (2026-05-18): No pending items for this repo. Last sync: 2026-05-16 - packages/shared v2.1.0. The version is live. Test count is live. Env var statuses are live. Running containers are live. The sync file was resolved inline - not referenced. The push command is present because the container test passed. If it had failed, that line wouldn’t exist and Claude would have received a hard stop instruction instead. What This Actually Saves Time Those seven pre-flight tool calls are gone. No reads, no shell commands, no waiting on npm test to finish before Claude knows how many tests exist. The session starts with a complete, accurate picture of the project state. A few seconds per call adds up faster than it sounds. Run Claude on a project daily and those pre-flight checks happen every single session - for every developer on the team. The bigger cost is the interruption: Claude doesn’t go straight to the task, it goes to verification first, and verification generates decisions, and decisions consume context that should be going toward actual work. Tokens Every tool call produces output Claude has to read and process. Docker container lists, npm test output, file contents, env var values - each one adds tokens before the task even starts. Remove the tool calls and that context headroom goes toward the work instead. The constraints table is also denser than the prose it replaces. “NEVER import mongodb directly” as a CRITICAL row in a structured table takes fewer tokens than three bullet points and a bolded heading saying the same thing - and Claude processes it more reliably because it’s structured, not buried in prose. The compound effect The pre-flight tax isn’t always seven calls. Sometimes it’s two. Sometimes it’s ten, because one check reveals something unexpected and spawns more checks. The rendered file eliminates the variance. Claude gets the same complete picture every session, and it can trust that picture because it was assembled a moment ago from the actual sources - not written by a developer who was going to update it later and didn’t. It’s Not Just CLAUDE.md CLAUDE.md is the most obvious example because it’s explicitly written for AI consumption. But the same problem exists in every markdown file an AI reads. A README with setup instructions: “run npm install , start the server on port 3000.” Is port 3000 still right? Did a new required env var get added last sprint? An architecture doc: “the database lives at db.internal .” Did that hostname change in the last migration? An onboarding guide: “there are currently 12 microservices.” How long ago was that accurate? Every one of those files was written by someone who was correct at the time. None of them have a mechanism to stay correct. When an AI reads them, it either trusts stale data or stops to verify - which means more tool calls, more context consumed, more time before anything useful happens. MarkdownAI works on any of these files. Add @markdownai to the first line of a README and it can pull the current version from package.json , read the actual port from .env , count the real services in your cluster. The same directive syntax works whether the file is a CLAUDE.md, a runbook, an onboarding doc, or an API reference. Anything written for an AI to read is a candidate. The Part People Miss MarkdownAI looks like a documentation tool. The insight that matters here is different: the render happens before the context window is populated. mai runs, resolves every directive, and hands Claude a finished document. Claude never sees the directive syntax. It receives facts, not instructions to go find facts. That distinction - resolution before context, not during - is why the @prompt at the top of the source file works. It tells Claude “the work has already been done.” And Claude can trust that, because the rendered output proves it. What’s the worst pre-flight tax you’ve seen in a CLAUDE.md? Curious how much time people are burning before Claude even gets started. MarkdownAI Directives All 27 directives available in MarkdownAI: Document Structure Variables and Environment Data Sources Processing and Output AI-Native Caching Phase Events GitHub repo Full manual submitted by /u/TheDecipherist

Originally posted by u/TheDecipherist on r/ClaudeCode