{"slug": "one-markdown-file-two-worlds-how-to-build-docs-for-both-humans-and-ai-assistants", "title": "One Markdown File, Two Worlds: How to Build Docs for Both Humans and AI Assistants", "summary": "A developer building LinkShift.app, a programmable redirect platform, created a single Markdown file that serves as a single source of truth for both human-readable documentation and AI assistant context. The rendering pipeline processes the file differently depending on the audience, using custom block directives like `:::ai-only` to include extra context for AI agents that remains hidden from human readers. This approach prevents the knowledge drift that typically occurs when maintaining separate knowledge bases for humans and AI assistants.", "body_md": "When building a modern SaaS product with an AI assistant (\"Ask our docs\"), you quickly hit a brutal realization about documentation design:\n\nThe classic approach? Maintain two separate knowledge bases. One for humans (a beautiful public CMS) and one for AI (prompts, vector databases, or markdown files tailored for the bot).\n\nThe result? Both sources drift apart within exactly one week.\n\nIn our project, we took a different route. **We write exactly one Markdown file**, but our rendering pipeline processes it differently depending on whether it’s being read by a human in a browser or ingested by an AI agent into our RAG (Retrieval-Augmented Generation) context.\n\nHere is how we built the simplest possible Single Source of Truth (SSoT) for both humans and AI.\n\nWe are building [LinkShift.app](https://linkshift.app/) — a programmable redirect platform. Think of it as a smart layer on the edge where you define traffic routing using rules, dynamic link maps, and regex, instead of hard-coding messy redirects in your app or CDN.\n\nFor a developer tool like this, documentation isn't just an afterthought; it's a core feature. Our users build complex routing logic, so the UI needs to be crystal clear. At the same time, our AI assistant must understand the deep mechanics behind our rules engine, batch simulations, and fallback scenarios. We simply couldn't afford a knowledge gap between what the developer reads and what our AI knows.\n\nOur `MarkdownRendererComponent`\n\n(built with Angular and the `marked`\n\nparser) is not just a dumb Markdown-to-HTML translator. Before the text ever hits the screen, it goes through a lightweight pre-processing pass.\n\nThe entire process is controlled using simple, custom block directives (`:::block-name`\n\n).\n\nHere is how the roles are split depending on who the audience is:\n\n| Document Element | Human Reader (Docs UI) | AI Assistant (RAG Context) |\n|---|---|---|\nStandard Markdown |\n✅ Yes (Rendered to HTML) | ✅ Yes (Raw text) |\nInfoboxes (`:::info` ) |\n✅ Yes (Styled callouts) | ✅ Yes (Textual context) |\nMermaid Diagrams |\n✅ Yes (Graphical render) | ✅ Yes (Raw text flow syntax) |\nHidden from Humans (`:::ai-only` ) |\n❌ Hidden (CSS `display: none` ) |\n✅ Yes (Full text for LLM) |\nAuthor Scratchpad (`:::hidden-on-purpose` ) |\n❌ Stripped entirely | ❌ Stripped entirely |\n\nFor the technical writer or developer, it’s still just a standard `.md`\n\nfile in the Git repository. However, they get to use a few \"superpowers.\"\n\n`:::ai-only`\n\n)\nThis is the secret sauce. This is where we drop extra context that would feel repetitive or bloated to a human engineer, but is absolute gold for an LLM.\n\n``` python\n### API Integration\n\nTo import domains, you need to hit the POST `/domains` endpoint.\n\n:::ai-only\n⚠️ Context for the bot: Remember to instruct the user that before calling \nPOST `/domains`, they MUST first generate an organization token via \n`/auth/org-token`, otherwise they will receive a 403. Humans have this covered \nin the \"Quickstart\" section, but remind them in the chat if they ask about 403 errors.\n:::\n```\n\n**How it works:**\n\n`<div class=\"docs-ai-hidden\" aria-hidden=\"true\">`\n\n. A simple CSS rule applies `display: none`\n\n. The text is physically there in the DOM (so if someone opens DevTools, they can see it—this is not for security!), but it doesn't ruin the page's readability.Instead of uploading static images (which LLMs cannot read out of the box in a standard text-based RAG pipeline), we stick to Mermaid code blocks.\n\nNote:We use standard Markdown code fences specifying`mermaid`\n\nas the language to draw flowcharts. (Dev.to’s parser currently struggles with rendering nested Mermaid blocks within examples, so I'm omitting the exact snippet here to keep this post readable!).\n\nWhen our pipeline reads that Mermaid block:\n\n`mermaid.run()`\n\nexecutes on hydration, rendering a gorgeous visual chart for the human reader.`:::hidden-on-purpose`\n\n)\nSometimes, documentation writers need to leave notes for themselves or the team (e.g., \"TODO: update this after the v2.4 release\").\n\n```\n:::hidden-on-purpose\nLeaving this here because we are changing the edge engine logic in June \nand this entire paragraph will need a rewrite. ~Mark\n:::\n```\n\nA utility function called `stripHiddenOnPurposeMarkdown()`\n\nruns a regex pass that nukes these blocks **both before rendering the UI and before sending data to the bot**. It is a private playground that stays strictly in the codebase.\n\n`npm run docs:sync`\n\n) builds the frontend bundle and simultaneously refreshes the AI bot's knowledge base in our backend.`ai-only`\n\nblocks are hidden via client-side CSS. Do not put API keys, passwords, or highly sensitive internal business strategies there. For truly confidential data (like internal infrastructure runbooks), we use a completely separate, private directory that never gets bundled into the public documentation repo.`shared/utils/`\n\n), so a regex adjustment in one place doesn't accidentally break formatting in the other.You don't need to adopt heavy, complex headless CMS platforms or enterprise-grade documentation frameworks just to survive the AI era. Sometimes, all it takes is taking good old Markdown, writing a dozen lines of pre-processing code, and elegantly decoupling your data layer from your presentation layer.\n\nBy doing this, our users get a clean, minimalist reading experience, while our AI assistant handles highly specific technical edge cases like an absolute expert. Everybody wins.\n\nCurious to see how this dual-view system looks in production? Head over to the [LinkShift Documentation](https://linkshift.app/docs) and try asking the AI agent a technical question about our programmable redirects. See if you can spot the difference between the visual docs and the bot's deep context! 😉\n\nIf you are dealing with similar RAG vs. UI documentation challenges, let me know in the comments how you solved them!", "url": "https://wpnews.pro/news/one-markdown-file-two-worlds-how-to-build-docs-for-both-humans-and-ai-assistants", "canonical_source": "https://dev.to/p-zielinski/one-markdown-file-two-worlds-how-to-build-docs-for-both-humans-and-ai-assistants-52fi", "published_at": "2026-06-03 21:19:17+00:00", "updated_at": "2026-06-03 21:41:32.946584+00:00", "lang": "en", "topics": ["ai-products", "ai-tools", "ai-agents", "ai-startups", "generative-ai"], "entities": ["LinkShift.app", "LinkShift", "Angular", "RAG", "SSoT"], "alternates": {"html": "https://wpnews.pro/news/one-markdown-file-two-worlds-how-to-build-docs-for-both-humans-and-ai-assistants", "markdown": "https://wpnews.pro/news/one-markdown-file-two-worlds-how-to-build-docs-for-both-humans-and-ai-assistants.md", "text": "https://wpnews.pro/news/one-markdown-file-two-worlds-how-to-build-docs-for-both-humans-and-ai-assistants.txt", "jsonld": "https://wpnews.pro/news/one-markdown-file-two-worlds-how-to-build-docs-for-both-humans-and-ai-assistants.jsonld"}}