{"componentChunkName":"component---src-templates-blog-post-js","path":"/claude-md-best-practices-2/","result":{"data":{"site":{"siteMetadata":{"title":"Catwomaniya"}},"mdx":{"id":"d66596d6-1355-5fe2-894c-b88e0369fc11","excerpt":"Part 1 covered the fundamentals - how CLAUDE.md works, why shorter is better, and the structure that actually gets followed.\nThis part is about what to add when…","body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"CLAUDE.md Part 2: what to add when you're building a mobile app with AI\",\n  \"date\": \"2026-04-29\",\n  \"description\": \"A concise guide to structuring CLAUDE.md while creating mobile apps with AI\"\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"Part 1 covered the fundamentals - how CLAUDE.md works, why shorter is better, and the structure that actually gets followed.\\nThis part is about what to add when your app itself uses AI and the mobile-specific things, so your app doesn\\u2019t get hacked or your data doesn\\u2019t get leaked or something worst.\"), mdx(\"div\", {\n    \"style\": {},\n    \"height:\": \"\",\n    \"'550px',\": \"\",\n    \"margin:\": \"\",\n    \"'0\": \"\",\n    \"auto'\": \"\",\n    \"}}\": \"\"\n  }, \"\\n  \", mdx(\"span\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"gatsby-resp-image-wrapper\",\n    \"style\": {\n      \"position\": \"relative\",\n      \"display\": \"block\",\n      \"marginLeft\": \"auto\",\n      \"marginRight\": \"auto\",\n      \"maxWidth\": \"590px\"\n    }\n  }), \"\\n      \", mdx(\"a\", _extends({\n    parentName: \"span\"\n  }, {\n    \"className\": \"gatsby-resp-image-link\",\n    \"href\": \"/static/6a3d79eec9918e7d15e6c9603c54562f/15ec7/cc1.jpg\",\n    \"style\": {\n      \"display\": \"block\"\n    },\n    \"target\": \"_blank\",\n    \"rel\": \"noopener\"\n  }), \"\\n    \", mdx(\"span\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-background-image\",\n    \"style\": {\n      \"paddingBottom\": \"133.1081081081081%\",\n      \"position\": \"relative\",\n      \"bottom\": \"0\",\n      \"left\": \"0\",\n      \"backgroundImage\": \"url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQBAgMF/8QAFwEAAwEAAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQAAAB6tUmc7WJA5W9pWgZEv8A/8QAHBABAAICAwEAAAAAAAAAAAAAAQARAiIDECFC/9oACAEBAAEFAhEZfvHnqOl4Qu8Vl9fM/8QAFxEBAAMAAAAAAAAAAAAAAAAAABAREv/aAAgBAwEBPwFTEf/EABcRAQADAAAAAAAAAAAAAAAAAAAQERL/2gAIAQIBAT8BW1H/xAAXEAADAQAAAAAAAAAAAAAAAAACESAh/9oACAEBAAY/AnOjf//EABwQAQEAAQUBAAAAAAAAAAAAAAEAERAhMVFhQf/aAAgBAQABPyEQPstpIs9xbV4hWvdl5lkcGWeXtsHE6P/aAAwDAQACAAMAAAAQRx8D/8QAFxEBAQEBAAAAAAAAAAAAAAAAEQABUf/aAAgBAwEBPxCUF2M5f//EABgRAAIDAAAAAAAAAAAAAAAAAAARECEx/9oACAECAQE/EFYhhR//xAAbEAEAAwEBAQEAAAAAAAAAAAABABEhMVFBcf/aAAgBAQABPxBWMF1B1LpaxigWm+R62uK6nktOh1FLjAH0T7NG5+8hU6P5LixYcmQmMVt2f//Z')\",\n      \"backgroundSize\": \"cover\",\n      \"display\": \"block\"\n    }\n  })), \"\\n  \", mdx(\"img\", _extends({\n    parentName: \"a\"\n  }, {\n    \"className\": \"gatsby-resp-image-image\",\n    \"alt\": \"funny meme of cat building on a laptop\",\n    \"title\": \"funny meme of cat building on a laptop\",\n    \"src\": \"/static/6a3d79eec9918e7d15e6c9603c54562f/1c72d/cc1.jpg\",\n    \"srcSet\": [\"/static/6a3d79eec9918e7d15e6c9603c54562f/a80bd/cc1.jpg 148w\", \"/static/6a3d79eec9918e7d15e6c9603c54562f/1c91a/cc1.jpg 295w\", \"/static/6a3d79eec9918e7d15e6c9603c54562f/1c72d/cc1.jpg 590w\", \"/static/6a3d79eec9918e7d15e6c9603c54562f/15ec7/cc1.jpg 690w\"],\n    \"sizes\": \"(max-width: 590px) 100vw, 590px\",\n    \"style\": {\n      \"width\": \"100%\",\n      \"height\": \"100%\",\n      \"margin\": \"0\",\n      \"verticalAlign\": \"middle\",\n      \"position\": \"absolute\",\n      \"top\": \"0\",\n      \"left\": \"0\"\n    },\n    \"loading\": \"lazy\"\n  })), \"\\n  \"), \"\\n    \")), mdx(\"h2\", null, \"If your app makes AI calls, document the boundary\"), mdx(\"p\", null, \"This is the most important section to get right. And the principles are the same whether you end up using OpenAI, Gemini or something else.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Put all AI calls in one place\")), mdx(\"p\", null, \"Pick a folder -\"), mdx(\"div\", {\n    \"className\": \"gatsby-highlight\",\n    \"data-language\": \"text\"\n  }, mdx(\"pre\", _extends({\n    parentName: \"div\"\n  }, {\n    \"className\": \"language-text\"\n  }), mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-text\"\n  }), \"ai/, services/ai/\"))), mdx(\"p\", null, \"whatever fits your structure - and make it the only place in the codebase that talks to an AI provider. Document this explicitly in CLAUDE.md.\\nAll AI provider calls live here.\\nThis matters because AI outputs are probabilistic. The code that validates and handles those outputs - the deterministic shell around the AI - needs to be centralized. If Claude can casually add AI calls anywhere in the codebase, that shell falls apart.\"), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Decide how you\\u2019ll use models (before you pick one)\")), mdx(\"p\", null, \"You don\\u2019t need to pick a provider to decide how you\\u2019ll use models.\\nThe logic is usually simple. Cheap, fast models handle classification, tagging, and basic Q&A. More expensive models are for when reasoning actually matters.\\nPut that logic in config and point Claude to it. \"), mdx(\"h2\", null, \"Always validate AI output\"), mdx(\"p\", null, \"Treat model output like user input.\\nBefore it renders, gets stored, or gets passed anywhere else, it should go through a schema. If you\\u2019re in TypeScript, Zod is the obvious choice.\\nAlso worth stating explicitly: don\\u2019t show raw output directly to users, and don\\u2019t execute anything the model suggests without a confirmation step.\"), mdx(\"h2\", null, \"Stop rewriting AI error handling everywhere\"), mdx(\"p\", null, \"AI failures aren\\u2019t clean. You\\u2019ll hit rate limits, timeouts, and responses that fail validation.\\nThe easiest way to keep this sane is to route everything through a shared handler. Define it once, and make sure Claude uses that instead of writing new handling logic every time it touches AI.\"), mdx(\"h2\", null, \"Treat prompts like code\"), mdx(\"p\", null, \"Inline prompts feel fine at the start, but they don\\u2019t scale.\\nStore them in one place, give them names, version them when you change them. It sounds like overhead until something breaks and you have no idea what changed.\\nVersioning prompts is what lets you trace behavior instead of guessing.\"), mdx(\"h2\", null, \"Mobile-specific things worth calling out\"), mdx(\"p\", null, \"Most CLAUDE.md advice is written with web apps in mind. Mobile has a different set of constraints, and Claude won\\u2019t always infer them correctly.\"), mdx(\"p\", null, \"Start with platform scope. Whether you\\u2019re building for iOS, Android, or both and whether tablets are in scope, affects a lot of downstream decisions. It\\u2019s better to make that explicit upfront.\"), mdx(\"p\", null, \"Environment handling is another one that gets messy on mobile. Variables might live in \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \".env, app.config.js\"), \", or something like EAS secrets. Claude shouldn\\u2019t assume web style setups here.\"), mdx(\"p\", null, \"If your app uses native modules - camera, push notifications, biometrics, payments, it\\u2019s worth listing them. These come with platform specific quirks and sometimes OS-level limitations. Claude should know what\\u2019s already in play before suggesting alternatives.\"), mdx(\"p\", null, \"If you\\u2019re using OTA updates (like Expo Updates), there are limits. JavaScript and assets can update over the air. Native changes can\\u2019t. Without that context, Claude might suggest something that simply isn\\u2019t deployable the way it assumes.\"), mdx(\"p\", null, \"And then there\\u2019s app store policy. Both Apple and Google have started caring more about AI-generated content. If your app surfaces AI output, there may be disclosure requirements. Worth documenting so you don\\u2019t accidentally build something that gets flagged in review.\"), mdx(\"h2\", null, \"The security section: what CLAUDE.md can\\u2019t actually enforce\"), mdx(\"p\", null, \"This is where a lot of guides oversell things.\"), mdx(\"div\", {\n    style: {\n      textAlign: 'center'\n    }\n  }, mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"/b09b9ded0433f5cd4cde51e206ede675/cc2.gif\",\n    \"alt\": \"Funny gif related to security\"\n  })))), mdx(\"p\", null, \"Writing \\u201Cnever commit API keys\\u201D in CLAUDE.md helps, but it\\u2019s not a guarantee. It\\u2019ll work most of the time, until it doesn\\u2019t - context pressure, long sessions, edge cases.\\nCLAUDE.md is still just a prompt. Prompts can be ignored.\\nThe actual enforcement layer is hooks, shell commands that run before or after Claude takes an action. A hook that blocks a file write exits with a specific code that Claude cannot override, even in its most permissive mode.\\nThe simple rule: preferences go in CLAUDE.md, things that must never happen go in hooks.\\nA few examples of how that works in practice:\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"What you want\"), mdx(\"th\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Advisory (CLAUDE.md)\"), mdx(\"th\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Enforced (hook)\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"No secrets in code\"), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"\\u201CNever hardcode API keys\\u201D\"), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Scans file content for secret patterns before every write\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"No destructive commands\"), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"\\u201CAvoid rm -rf\\u201D\"), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Blocks matching bash commands before they run\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Tests before a PR\"), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"\\u201CRun tests before committing\\u201D\"), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Runs test suite before any PR creation\")))), mdx(\"p\", null, \"For mobile specifically: keep your signing certificates, provisioning profiles, and EAS credentials completely out of the repo and out of Claude\\u2019s reach. Document where they live and that Claude should not touch them.\"), mdx(\"h2\", null, \"CLAUDE.local.md - still useful\"), mdx(\"p\", null, \"This is your personal layer. Gitignored, loaded after the main file. Temporary context that\\u2019s genuinely helpful but has no place in the shared file, but doesn\\u2019t mean you shouldn\\u2019t be taking notes - save them here.\"), mdx(\"h2\", null, \"The thing that doesn\\u2019t change\"), mdx(\"p\", null, \"CLAUDE.md is an instruction budget.\\nEvery line takes up space in that budget, so it should be reserved for things Claude genuinely can\\u2019t infer - your boundaries around AI, your validation rules, your platform constraints.\\nEverything else, it can figure out by reading your code.\"));\n}\n;\nMDXContent.isMDXComponent = true;","frontmatter":{"title":"CLAUDE.md Part 2: what to add when you're building a mobile app with AI","date":"Apr 29, 2026","description":"A concise guide to structuring CLAUDE.md while creating mobile apps with AI"}}},"pageContext":{"slug":"/claude-md-best-practices-2/","previous":{"fields":{"collection":"blog","slug":"/claude-md-best-practices/"},"frontmatter":{"title":"CLAUDE.md: how to use Claude Code effectively (best practices)"}},"next":null}}}