<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aryan Duntley</title>
    <description>The latest articles on DEV Community by Aryan Duntley (@aryanduntley).</description>
    <link>https://dev.to/aryanduntley</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4225210%2Fa22fce7a-c751-4619-93d8-7211783a6d6f.jpg</url>
      <title>DEV Community: Aryan Duntley</title>
      <link>https://dev.to/aryanduntley</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aryanduntley"/>
    <language>en</language>
    <item>
      <title>Stop being your AI's eyes and hands: pwa-debug lets Claude debug your live, logged-in browser</title>
      <dc:creator>Aryan Duntley</dc:creator>
      <pubDate>Wed, 04 Nov 2026 01:50:20 +0000</pubDate>
      <link>https://dev.to/aryanduntley/stop-being-your-ais-eyes-and-hands-pwa-debug-lets-claude-debug-your-live-logged-in-browser-4hc9</link>
      <guid>https://dev.to/aryanduntley/stop-being-your-ais-eyes-and-hands-pwa-debug-lets-claude-debug-your-live-logged-in-browser-4hc9</guid>
      <description>&lt;p&gt;If you've debugged a web app with an AI assistant, you know the loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The AI asks what the console says. You copy and paste it.&lt;/li&gt;
&lt;li&gt;It asks what the component's state is. You open React DevTools and describe it.&lt;/li&gt;
&lt;li&gt;It asks you to click the button and report what happens. You click it.&lt;/li&gt;
&lt;li&gt;It asks for a screenshot. You take one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;You end up as the AI's eyes and hands.&lt;/strong&gt; That's slow, it loses information, and it doesn't work at all for the bugs that hurt most in PWAs: stale caches, service workers that won't update, install failures, and version skew after a deploy.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://github.com/aryanduntley/pwa-debug-layer" rel="noopener noreferrer"&gt;pwa-debug&lt;/a&gt;&lt;/strong&gt; to remove that loop. It's an open-source (MIT) MCP server plus a browser extension that gives an AI agent like Claude Code &lt;strong&gt;direct, structured access to your live, logged-in browser&lt;/strong&gt;. That covers the DOM, console, network, framework state, store state, service workers, caches, and storage, and the agent can also interact with the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; @aryanduntley/pwa-debug@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;📦 &lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@aryanduntley/pwa-debug" rel="noopener noreferrer"&gt;&lt;code&gt;@aryanduntley/pwa-debug&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐙 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/aryanduntley/pwa-debug-layer" rel="noopener noreferrer"&gt;aryanduntley/pwa-debug-layer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The questions it answers
&lt;/h2&gt;

&lt;p&gt;These are the PWA problems people search for most. pwa-debug answers them by reading the runtime directly, without screenshots or OCR:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You ask&lt;/th&gt;
&lt;th&gt;The agent calls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Why won't my service worker update? Why are some users on old code?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sw_status&lt;/code&gt;, &lt;code&gt;pwa_update_analyze&lt;/code&gt; (waiting-vs-active versions, version-skew verdict)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Why is my cache stale? Why are chunks 404ing after a deploy?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;cache_list&lt;/code&gt; / &lt;code&gt;cache_inspect&lt;/code&gt; / &lt;code&gt;cache_match&lt;/code&gt; (entries with age, size, cache-control)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Why won't my PWA install?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pwa_installability&lt;/code&gt; (structured &lt;code&gt;{ gaps[], fixes[] }&lt;/code&gt;, not just "manifest invalid")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;What's actually in IndexedDB right now?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;idb_list&lt;/code&gt; / &lt;code&gt;idb_query&lt;/code&gt;, &lt;code&gt;storage_get&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Why does this component have the wrong state?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;react_get_state&lt;/code&gt;, &lt;code&gt;vue_get_state&lt;/code&gt;, &lt;code&gt;store_get_state&lt;/code&gt;, &lt;code&gt;redux_get_state&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;Does anything break at 360px, in dark mode, in Spanish?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;layout_sweep&lt;/code&gt; (one call, every page × width × scheme × state)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Highlights
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔐 It runs in your real browser profile
&lt;/h3&gt;

&lt;p&gt;Google's &lt;a href="https://github.com/ChromeDevTools/chrome-devtools-mcp" rel="noopener noreferrer"&gt;&lt;code&gt;chrome-devtools-mcp&lt;/code&gt;&lt;/a&gt; is great, but it starts a fresh automated Chrome. That browser has none of your cookies, sessions, or extensions, and none of your real service-worker state. If your app sits behind a login, that's a problem.&lt;/p&gt;

&lt;p&gt;pwa-debug attaches to &lt;strong&gt;your normal profile&lt;/strong&gt; by default, so the agent sees what you see: authenticated sessions, your real SW and cache state, and your extensions.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚛️ Framework and store state that CDP can't reach
&lt;/h3&gt;

&lt;p&gt;A script injected into the page's MAIN world reads each framework through its own devtools hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; fiber tree, props, state, and hooks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vue 3&lt;/strong&gt; component tree and reactive state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Svelte&lt;/strong&gt; components with source locations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solid&lt;/strong&gt; detection and element lookup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redux, Zustand, Pinia, Jotai&lt;/strong&gt;: read, subscribe to change deltas, and (opt-in) dispatch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every framework also supports find-by-text and find-by-role, so the agent can locate "the Submit button inside &lt;code&gt;&amp;lt;CheckoutForm&amp;gt;&lt;/code&gt;" without guessing selectors.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠️ The full PWA diagnostics suite
&lt;/h3&gt;

&lt;p&gt;This is the part the project is named for. It covers service-worker lifecycle and versions, CacheStorage contents and age, installability gaps with per-gap fixes, a live capability matrix (Push, Background Sync, Periodic Sync, Badging, File System Access, Window Controls Overlay), IndexedDB and web storage, and &lt;strong&gt;&lt;code&gt;pwa_update_analyze&lt;/code&gt;&lt;/strong&gt;. That last tool combines SW status, cache ages, and recent 404s into a verdict such as &lt;em&gt;"cached HTML is older than the JS it references"&lt;/em&gt;, which is the classic cause of "why are some users on old code."&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pwa_snapshot&lt;/code&gt; produces one capped blob of the whole runtime state, which is useful for repros and bug hand-offs.&lt;/p&gt;

&lt;h3&gt;
  
  
  👆 The agent drives the page itself
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pdl_click&lt;/code&gt;, &lt;code&gt;pdl_fill&lt;/code&gt;, &lt;code&gt;pdl_submit&lt;/code&gt;, &lt;code&gt;pdl_key_press&lt;/code&gt;, &lt;code&gt;pdl_type_sequence&lt;/code&gt;, &lt;code&gt;pdl_navigate&lt;/code&gt;, and &lt;code&gt;pdl_new_tab&lt;/code&gt; are available, along with touch gestures: &lt;strong&gt;tap, double-tap, long-press, swipe, drag, scroll, and pinch&lt;/strong&gt;. Events are dispatched as native-event sequences, so React's and Vue's delegated event systems fire properly. Targets use one locator format (selector, role, text, or a framework component id).&lt;/p&gt;

&lt;h3&gt;
  
  
  📱 Android phones over adb
&lt;/h3&gt;

&lt;p&gt;The extension can't run in Android Chrome, so pwa-debug connects to phones over adb and CDP and injects the same page-world code there. One call does the setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pdl_android_attach({
  open_url: "http://localhost:5173",
  reverse_ports: [5173]      // phone's localhost:5173 → your dev server
})
→ { connectionId: "cdp:127.0.0.1:&amp;lt;port&amp;gt;:&amp;lt;tab&amp;gt;" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, &lt;strong&gt;every page tool works on the phone tab&lt;/strong&gt;, including React state, stores, PWA diagnostics, gestures, and console and network capture, and you can watch it happen on the device. I verified this live on a Galaxy S24 Ultra (Android 16, Chrome 156).&lt;/p&gt;

&lt;h3&gt;
  
  
  📐 Responsive layout sweep
&lt;/h3&gt;

&lt;p&gt;One &lt;code&gt;layout_sweep&lt;/code&gt; call goes through a matrix of &lt;strong&gt;pages × viewport widths × color schemes × app states&lt;/strong&gt; (plus extra dimensions such as language). For each view it emulates the viewport over CDP and measures the page for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;horizontal page overflow and off-screen elements&lt;/li&gt;
&lt;li&gt;tap targets below WCAG 2.2 minimums&lt;/li&gt;
&lt;li&gt;clipped or ellipsized text (useful when testing longer translations)&lt;/li&gt;
&lt;li&gt;fixed bars that aren't fully on screen&lt;/li&gt;
&lt;li&gt;clipped focus and selection rings&lt;/li&gt;
&lt;li&gt;unresolved copy like &lt;code&gt;{{name}}&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;[object Object]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;page errors during the view, plus optional WCAG AA contrast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It &lt;strong&gt;groups the results into distinct problems&lt;/strong&gt;, so 150 raw findings that come from two root causes are reported as two groups, with screenshots if you ask for them. You can also pass your own &lt;code&gt;custom_checks&lt;/code&gt; expressions. In the largest real test it swept an 83-page prototype across 4,812 views.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔌 Library popups, replay, and source maps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WalletConnect, RainbowKit, and SDK modals&lt;/strong&gt; that live in shadow roots or nested iframes can be recorded, replayed, and correlated with the console errors and failed requests that occurred while they were open (&lt;code&gt;popup_failures&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rrweb session recording and replay&lt;/strong&gt;, plus persistent ring buffers that survive navigations and reloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;source_map_resolve&lt;/code&gt;&lt;/strong&gt; maps minified stack frames back to &lt;code&gt;src/file.ts:line:col&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🤖 Built for agents, not humans
&lt;/h3&gt;

&lt;p&gt;Every tool returns &lt;code&gt;{ ok, data, error?, next_steps[] }&lt;/code&gt;. The &lt;code&gt;next_steps&lt;/code&gt; field tells the agent what to call next based on the actual result, so it recovers from setup gaps and errors without you stepping in. &lt;code&gt;pdl_help&lt;/code&gt; serves the whole usage guide as data, and filters keep each response to the slice the agent asked for instead of dumping the full DOM.&lt;/p&gt;




&lt;h2&gt;
  
  
  Works with chrome-devtools-mcp, doesn't replace it
&lt;/h2&gt;

&lt;p&gt;pwa-debug is &lt;strong&gt;complementary&lt;/strong&gt; to &lt;code&gt;chrome-devtools-mcp&lt;/code&gt;, and the two tool sets don't overlap. pwa-debug launches a browser with a live debug port, and &lt;code&gt;chrome-devtools-mcp&lt;/code&gt; attaches to that same port. Both then drive the same tab over separate channels: CDP for one, extension and page-world injection for the other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pdl_launch_browser({ browser: "brave", mode: "sandbox-persistent" })
pdl_register_chrome_devtools()   // pins chrome-devtools-mcp to the right port for you
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  As a Claude Code plugin (no clone, no build)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add aryanduntley/pwa-debug-layer
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;pwa-debug@pwa-debug
/reload-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Or with any MCP client
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add pwa-debug &lt;span class="nt"&gt;--scope&lt;/span&gt; user &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; @aryanduntley/pwa-debug@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then tell your agent:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Set up pwa-debug and open my app at &lt;a href="http://localhost:5173" rel="noopener noreferrer"&gt;http://localhost:5173&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The setup is agent-driven. It runs &lt;code&gt;pdl_check_setup&lt;/code&gt;, registers the native-messaging host, launches a browser with the extension preloaded, and confirms the round-trip with &lt;code&gt;session_ping&lt;/code&gt;. Each step's &lt;code&gt;next_steps&lt;/code&gt; tells it what to do next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser support:&lt;/strong&gt; Chromium-family browsers (Chrome, Chromium, Brave, Edge, Vivaldi, Opera) and Android Chrome over adb. Brave and Chromium give the smoothest experience, because Google Chrome 142+ removed &lt;code&gt;--load-extension&lt;/code&gt; and so needs one manual "Load unpacked" step.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Claude Code ──MCP──► Native host (MCP server, ring buffers, replay store)
                        │ native messaging
                        ▼
                     Extension service worker
                        │
          ┌─────────────┴──────────────┐
          ▼                            ▼
   Content script               Page-world script (MAIN world)
   DOM observe, actions         React/Vue hooks, fetch/XHR patch, stores
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;extension&lt;/strong&gt; handles the page: DOM, content scripts, and page-world hooks injected on every load.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;native host&lt;/strong&gt; handles persistence and the MCP server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; is the contract with the AI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole codebase is TypeScript written in a strict functional style: pure functions, immutable data, no classes, and side effects kept at the edges.&lt;/p&gt;




&lt;h2&gt;
  
  
  Help wanted 🙏
&lt;/h2&gt;

&lt;p&gt;Development happens on &lt;strong&gt;Linux&lt;/strong&gt;, where everything is live-tested. The &lt;strong&gt;macOS and Windows&lt;/strong&gt; code paths (browser detection, profile paths, native-messaging registration) are written and unit-tested but &lt;strong&gt;have never run on real hardware&lt;/strong&gt;. If you're on a Mac or a Windows machine, trying it and &lt;a href="https://github.com/aryanduntley/pwa-debug-layer/issues" rel="noopener noreferrer"&gt;opening an issue&lt;/a&gt; with the output would help more than anything else right now.&lt;/p&gt;

&lt;p&gt;Firefox support is on the roadmap (via WebDriver BiDi). Stars, issues, and PRs are all welcome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/aryanduntley/pwa-debug-layer" rel="noopener noreferrer"&gt;https://github.com/aryanduntley/pwa-debug-layer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@aryanduntley/pwa-debug" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/@aryanduntley/pwa-debug&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it on a PWA bug, I'd like to hear how it went in the comments, whether it worked or not.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Stop Paying the Re-Discovery Tax: How AIMFP Manages Context for AI Coding Agents</title>
      <dc:creator>Aryan Duntley</dc:creator>
      <pubDate>Wed, 04 Nov 2026 01:47:34 +0000</pubDate>
      <link>https://dev.to/aryanduntley/stop-paying-the-re-discovery-tax-how-aimfp-manages-context-for-ai-coding-agents-2p58</link>
      <guid>https://dev.to/aryanduntley/stop-paying-the-re-discovery-tax-how-aimfp-manages-context-for-ai-coding-agents-2p58</guid>
      <description>&lt;p&gt;Every AI coding session starts the same way. The assistant lists directories, opens files, greps for function names, reads the README again, and slowly rebuilds a picture of the project it already understood yesterday. On a small repo that costs a minute. On a large one it eats a real share of the context window before any work starts, and the picture it builds is still incomplete.&lt;/p&gt;

&lt;p&gt;I call this the &lt;strong&gt;re-discovery tax&lt;/strong&gt;, and I built &lt;strong&gt;AIMFP&lt;/strong&gt; (AI Modular Functional Procedural) to stop paying it.&lt;/p&gt;

&lt;p&gt;AIMFP is an MCP server (&lt;code&gt;pip install aimfp&lt;/code&gt;, or a Claude Code plugin) that gives the AI a persistent, structured database of the project: files, functions, types, call interactions, modules, tasks, decisions and notes. The AI keeps that database up to date as it works and reads from it in the next session, so it doesn't have to re-read the source tree.&lt;/p&gt;

&lt;p&gt;This post covers what AIMFP is, then spends most of its time on the part I think is most useful to other people building agent tooling: &lt;strong&gt;how it manages context&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AIMFP is, briefly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;An MCP server&lt;/strong&gt; with about 315 tools and 131 directives (step-by-step workflows), all stored in SQLite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Four databases:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;aimfp_core.db&lt;/code&gt; is read-only and ships in the wheel. It holds directives, helper definitions, and the next-step guidance attached to each tool.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;project.db&lt;/code&gt; holds the project's state: files, functions, interactions, types, themes, flows, modules, completion paths, milestones, tasks and notes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_preferences.db&lt;/code&gt; holds per-directive preferences and project settings.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_directives.db&lt;/code&gt; is optional. It's used for automation projects, where the AI generates code from rules you write in YAML/JSON.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An opinionated coding style:&lt;/strong&gt; functional-procedural code with pure functions, immutable data, no OOP, and side effects isolated at the edges. This is deliberate. Pure functions with explicit inputs and outputs are much easier to index, and an accurate index is what makes the rest of the system work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A modularity map.&lt;/strong&gt; Every piece of work is placed on the map before it's written:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;theme (stable project area)
  └─ flow (one behaviour, ≥ 1 theme)
       └─ files (declare their flows when reserved)
            └─ module (reusable domain code at a directory seam)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Completion paths move themes forward, milestones build flows, and tasks carry flow IDs. Feature files are thin orchestrators that compose module functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local only.&lt;/strong&gt; No network calls and no telemetry. All state lives in &lt;code&gt;.aimfp-project/&lt;/code&gt; inside your repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AIMFP also tracks its own development. Right now its own &lt;code&gt;project.db&lt;/code&gt; holds &lt;strong&gt;131 files, 1,303 functions, 2,920 call interactions, 16 modules, 20 flows, 9 themes and 74 completed tasks&lt;/strong&gt;. Most of the design decisions below came from running into problems while using it on itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  The core rule: the database is the index, source files are the last resort
&lt;/h2&gt;

&lt;p&gt;AIMFP's system prompt says this directly: &lt;em&gt;use DB tools before reading source files.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; src/ → &lt;span class="nb"&gt;cat &lt;/span&gt;12 files → &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"def calculate"&lt;/span&gt; → &lt;span class="nb"&gt;cat &lt;/span&gt;3 more files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the AI calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get_function_by_name("calculate_total")
→ file, purpose, parameters (typed), returns, notes attached to it

get_interactions_by_function(fn_id)
→ what it calls, what calls it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each answer is a short structured record instead of a file. The AI still opens source files when it has to edit them, but it opens them knowing what it's looking for.&lt;/p&gt;

&lt;p&gt;The rule is the easy part. The harder part was keeping all of this from flooding the context window anyway. A database of 1,300 functions can bury the AI just as thoroughly as a source tree if every call returns everything. The rest of this post covers how AIMFP avoids that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Context management, layer by layer
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. One call to start a session, with only the sections that need attention
&lt;/h3&gt;

&lt;p&gt;The first action of every session is a single call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aimfp_run(is_new_session=true)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns a &lt;strong&gt;session bundle&lt;/strong&gt;: project purpose and goals, the active path, milestone and task, the flows and themes of that work, infrastructure, recently changed files (each tagged with its flows, themes and module), metadata for recent notes, recent history, user settings, watchdog status, and the reference material the AI needs to work.&lt;/p&gt;

&lt;p&gt;The important part is what the bundle &lt;strong&gt;doesn't&lt;/strong&gt; include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sections with nothing to report are dropped.&lt;/strong&gt; A backup appears only if one was actually taken. A migration notice appears only if a migration is pending. A pure helper, &lt;code&gt;drop_empty&lt;/code&gt;, removes every &lt;code&gt;None&lt;/code&gt; and empty container before the payload goes out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The full directive catalogue isn't bundled.&lt;/strong&gt; There are 131 directives and 66 FP-style rules. The AI gets their names in its reference material and loads a directive's steps with &lt;code&gt;get_directive_by_name(name)&lt;/code&gt; only when it's about to run it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding-specific reference material is included only once there's code to write&lt;/strong&gt;, meaning once a milestone exists. Before that, the next step is project discovery, and the core reference already covers it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a trimmed version of the bundle AIMFP returned for its own repo today:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AIMFP Ongoing Development"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"milestone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Features"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"flows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Session Lifecycle Flow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"themes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Helper / MCP Tools"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tracking Audit Flow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"themes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Database Operations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Helper / MCP Tools"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"recent_files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/aimfp/helpers/project/tasks.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"flows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Project Tracking Flow"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"themes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Database Operations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Helper / MCP Tools"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"helpers_project"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"last_completed_task"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bump-version.py covers server.json (MCP Registry) versions"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"watchdog"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"reminders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deferred_notes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"reference_table"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"reference_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this one payload the AI knows where the work is, what was done last, what's deferred, and which parts of the map are involved, without opening a single file.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Status in tiers, sized to how often each one is called
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;aimfp_status&lt;/code&gt; has three tiers, and the tier is chosen by &lt;strong&gt;call frequency&lt;/strong&gt;, not by how much information exists:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;When it's used&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;quick&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;Inside work loops, "where am I?"&lt;/td&gt;
&lt;td&gt;Path, milestone, focused task with item names, its flows and themes, other open work, structure gap &lt;strong&gt;count&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;summary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;After lost or &lt;strong&gt;compacted&lt;/strong&gt; context&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;quick&lt;/code&gt; + purpose and goals, infrastructure, recent files with their map annotations, recent notes, history, active branches, core reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;detailed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;summary&lt;/code&gt; + the full work tree&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Focused-work descriptions are capped at 300 characters in &lt;code&gt;summary&lt;/code&gt;, and &lt;code&gt;quick&lt;/code&gt; omits them entirely. The &lt;code&gt;quick&lt;/code&gt; tier is the one that gets called many times per session, so it's the one kept smallest.&lt;/p&gt;

&lt;p&gt;Compaction is handled explicitly. When the client compacts the conversation, the AI has lost details but the database hasn't. &lt;code&gt;aimfp_status(type='summary')&lt;/code&gt; is the documented recovery call, and the Claude Code plugin's &lt;code&gt;SessionStart&lt;/code&gt; hook matches &lt;code&gt;startup|resume|compact&lt;/code&gt; so the AI is pointed back at AIMFP straight after a compaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Checkpoint calls that return nothing when nothing is wrong
&lt;/h3&gt;

&lt;p&gt;During work the AI calls &lt;code&gt;aimfp_run(is_new_session=false)&lt;/code&gt; at checkpoints. This call only returns &lt;strong&gt;watchdog alerts&lt;/strong&gt;. If there are none, the &lt;code&gt;data&lt;/code&gt; object is empty (&lt;code&gt;{}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;That's an intentional design choice. A checkpoint that always returns a status block teaches the model to skim it. A checkpoint that's usually empty gets read when something does come back.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Instructions arrive just in time, not all at once
&lt;/h3&gt;

&lt;p&gt;This is the part I'd most recommend to anyone building MCP tooling.&lt;/p&gt;

&lt;p&gt;Most agent setups put every rule in the system prompt and hope the model remembers the relevant one at the right moment. AIMFP keeps the system prompt short. It sets the non-negotiable rules and the session-start call, and the detail lives in two places:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Directives in the database.&lt;/strong&gt; A directive like &lt;code&gt;project_task_decomposition&lt;/code&gt; or &lt;code&gt;project_milestone_complete&lt;/code&gt; is a stored workflow with a main sequence, conditional branches and a fallback. The AI loads it by name right before running it. When the workflow is done, its steps can fall out of context without anything being lost, because they're still in the database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Return statements on tool results.&lt;/strong&gt; Every tool result can include &lt;code&gt;return_statements&lt;/code&gt;, which are short next-step instructions defined per tool in &lt;code&gt;aimfp_core.db&lt;/code&gt;. There are about 320 of them across the tool definitions. &lt;strong&gt;They're gated on the payload&lt;/strong&gt;, so a statement is sent only when the key it refers to is present. For example, the bundle above included &lt;code&gt;deferred_notes&lt;/code&gt;, so the result also included:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"data.deferred_notes lists deferred work (metadata only). Read the ones relevant to the
 current work with get_notes_comprehensive(note_id=X); resolved ones → update_note(note_type='completed')."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there had been no deferred notes, the AI wouldn't have seen that instruction at all. When &lt;code&gt;aimfp_run&lt;/code&gt; bundles sections owned by other tools, it attaches &lt;strong&gt;those tools'&lt;/strong&gt; gated return statements too, and removes duplicates.&lt;/p&gt;

&lt;p&gt;So the guidance the AI receives depends on the state of the project, not on everything it might ever need to know. Users can also attach their own return statements to any tool (&lt;code&gt;set_custom_return_statement&lt;/code&gt;) if they want a specific behaviour every time that tool is called.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Short reads by default, full detail on request
&lt;/h3&gt;

&lt;p&gt;Large reads are short by default, and the AI has to ask for full detail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Milestone getters, &lt;code&gt;get_all_flows&lt;/code&gt; and &lt;code&gt;get_tasks_by_milestone&lt;/code&gt; return &lt;code&gt;description: null&lt;/code&gt; unless the call passes &lt;code&gt;detail_level='full'&lt;/code&gt;. They can also return task counts per status from a single grouped query, so getting an overview never requires writing SQL.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;audit_tracking&lt;/code&gt;, which compares the database against the actual code, writes its &lt;strong&gt;full findings to a JSON file on disk&lt;/strong&gt; and returns counts, a few samples per category (&lt;code&gt;sample_limit&lt;/code&gt;, default 5), and the report path. The fix tool, &lt;code&gt;apply_audit_fixes&lt;/code&gt;, reads that report from disk, so the full list of findings never has to pass through the context window.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;search_notes&lt;/code&gt; returns &lt;strong&gt;capped previews&lt;/strong&gt;. The AI reads a specific note in full only when it looks relevant.&lt;/li&gt;
&lt;li&gt;Single-entity lookups (a file, function, type, flow or module) include &lt;strong&gt;references&lt;/strong&gt; to attached notes rather than the note bodies.&lt;/li&gt;
&lt;li&gt;Function parameters always come back in one normalized shape, a parsed list of &lt;code&gt;{name, type, required, default, description, kind}&lt;/code&gt;. Records written by different sessions in different formats don't make the AI spend tokens working out which format it's looking at.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Show the part of the map the work touches
&lt;/h3&gt;

&lt;p&gt;It would be easy to include the whole theme/flow/module map in every status call. AIMFP doesn't. From the status module's docstring:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Structure (themes, flows, modules) is attached to what the payload already shows. It is never listed whole: a full map every call is a list the AI has to sort for relevance itself, which buries the part that matters now.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the active milestone comes with &lt;em&gt;its&lt;/em&gt; flows, a recent file comes with &lt;em&gt;its&lt;/em&gt; flows, themes and module, and the full map is a separate call (&lt;code&gt;get_all_flows&lt;/code&gt;, &lt;code&gt;get_structure_health&lt;/code&gt;) for when the AI actually needs it.&lt;/p&gt;

&lt;p&gt;Structural gaps get the same treatment: flows without a theme, files without a flow, files outside their module, oversized flows. The watchdog turns them into &lt;strong&gt;one summary reminder with counts per gap type&lt;/strong&gt;, not one reminder per gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. A watchdog that keeps the index honest
&lt;/h3&gt;

&lt;p&gt;None of this is useful if the database is wrong. A stale index is worse than none, because the AI trusts it.&lt;/p&gt;

&lt;p&gt;When a session starts, &lt;code&gt;aimfp_run&lt;/code&gt; launches a detached &lt;strong&gt;filesystem watchdog&lt;/strong&gt; (the one runtime dependency is &lt;code&gt;watchdog&lt;/code&gt;). It compares the database with what's on disk and records reminders for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;new files that aren't tracked&lt;/li&gt;
&lt;li&gt;functions in the code that are missing from the database, and the reverse&lt;/li&gt;
&lt;li&gt;deleted files&lt;/li&gt;
&lt;li&gt;stale timestamps&lt;/li&gt;
&lt;li&gt;audit drift and structure gaps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before the first payload is built, the session-start call runs a synchronous reconciliation pass, so the first answer doesn't race the watcher. Checkpoint calls also &lt;strong&gt;link edited tracked files to whichever task is in progress&lt;/strong&gt;. Edits made without a tracking call still appear in that task's context and in its completion audit.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Writes are what make reads trustworthy
&lt;/h3&gt;

&lt;p&gt;All of the above saves tokens on reads only if the writes happen. AIMFP's write-side discipline is the file coding loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;reserve file (with flow_ids) → search_modules for overlap → reserve functions + types
→ write the code → finalize file → assign to module
→ finalize functions + types (purpose, params, returns) → add interactions → link types to functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AIMFP enforces this loop in a few ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Finalize gates.&lt;/strong&gt; Finalizing rejects a function with no purpose, parameters or return value, and warns when the recorded parameters don't match the actual signature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A completion gate.&lt;/strong&gt; Marking a task complete audits the files linked to it against the code. If the drift is serious enough to block completion, the refusal includes the exact tool calls that fix it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugin hooks.&lt;/strong&gt; A &lt;code&gt;PostToolUse&lt;/code&gt; hook on &lt;code&gt;Write|Edit&lt;/code&gt; reminds the AI to track source files, and a &lt;code&gt;Stop&lt;/code&gt; hook checks that &lt;code&gt;aimfp_end&lt;/code&gt; ran when you said "wrap up".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tracking work costs tokens. A continuation checkpoint is cheap (around 2k tokens), batch helpers like &lt;code&gt;reserve_files&lt;/code&gt; and &lt;code&gt;finalize_functions&lt;/code&gt; cut down on round-trips, and all analytics are opt-in. The trade is to spend a little on every write so the next session doesn't spend a lot re-reading. Past a handful of files, that trade pays for itself many times over.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this looks like in practice
&lt;/h2&gt;

&lt;p&gt;The user starts a session with "continue where we left off". The AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calls &lt;code&gt;aimfp_run(is_new_session=true)&lt;/code&gt; and reads the bundle.&lt;/li&gt;
&lt;li&gt;Knows the active milestone, the focused task and its open items, which flows are involved, and that note #103 is deferred work on file #96.&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;search_notes&lt;/code&gt; with the task's keywords to check for past decisions.&lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;get_function_by_name&lt;/code&gt; and &lt;code&gt;get_interactions_by_function&lt;/code&gt; to find exactly what to change.&lt;/li&gt;
&lt;li&gt;Opens &lt;strong&gt;only&lt;/strong&gt; the files it's about to edit.&lt;/li&gt;
&lt;li&gt;Writes the code, runs the tracking loop, marks items done, and completes the task through the audit gate.&lt;/li&gt;
&lt;li&gt;If the conversation gets compacted halfway through, calls &lt;code&gt;aimfp_status(type='summary')&lt;/code&gt; and carries on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At no point does it list the source tree.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons for anyone building agent tooling
&lt;/h2&gt;

&lt;p&gt;Some of these apply whether or not you ever use AIMFP:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick payload size by call frequency.&lt;/strong&gt; The call made fifty times a session should be the smallest one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leave out empty sections.&lt;/strong&gt; Every empty key is something the model has to read and ignore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send instructions with the state they're about.&lt;/strong&gt; Attaching guidance to tool results, gated on payload content, works better than a longer system prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep full reports on disk and return pointers.&lt;/strong&gt; Return counts, samples and a path, and let the fix tool read the file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show the relevant slice of the map, not the whole map.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make "nothing to report" an actual empty result.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan for compaction.&lt;/strong&gt; Have one documented call that rebuilds working context from durable state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An index has to be enforced to stay accurate.&lt;/strong&gt; Without gates and a watcher, it drifts out of date.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FP only.&lt;/strong&gt; AIMFP refuses OOP codebases. It's opinionated on purpose, since pure functions are what keep the index reliable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux only.&lt;/strong&gt; There's no platform-specific code, so other operating systems are untested, not just unsupported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;About 315 tools.&lt;/strong&gt; Claude Code asks for approval on each MCP tool the first time it's used. &lt;code&gt;get_claude_permissions&lt;/code&gt; produces an allowlist so that happens only once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It depends on the AI following the process.&lt;/strong&gt; Gates, hooks and return statements make that much more likely, but the system prompt is still what holds it together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License:&lt;/strong&gt; PolyForm Noncommercial 1.0.0 for every version after 1.66.1. Personal, research and educational use is free, and commercial use needs a license. Versions up to 1.66.1 remain MIT.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Claude Code (recommended):&lt;/strong&gt; you need &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;&lt;code&gt;uv&lt;/code&gt;&lt;/a&gt; installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add aryanduntley/aimfp
/plugin install aimfp@aimfp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ask: &lt;strong&gt;"Add the AIMFP system prompt"&lt;/strong&gt;, followed by &lt;strong&gt;"Initialize AIMFP for my project"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other MCP clients:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;aimfp
&lt;span class="c"&gt;# register: python3 -m aimfp  (stdio transport)&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; aimfp &lt;span class="nt"&gt;--system-prompt&lt;/span&gt;   &lt;span class="c"&gt;# paste into your client's instructions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/aryanduntley/aimfp" rel="noopener noreferrer"&gt;github.com/aryanduntley/aimfp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/aimfp/" rel="noopener noreferrer"&gt;pypi.org/project/aimfp&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd like to hear how other people are handling context in their agent setups, especially what you do after compaction. Let me know in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
