[
  {
    "slug": "doom-osm-godmode-real-world-wad",
    "title": "I Turned Real Places Into Playable Doom Levels",
    "date": "2026-06-07",
    "tags": ["doom", "openstreetmap", "game-dev", "tools", "node", "gzdoom"],
    "summary": "doom-osm-godmode takes a place name, geocodes it through OpenStreetMap, projects the polygons into a room-and-corridor layout, and writes a PWAD you can load straight into GZDoom. Zero dependencies, Node 20 built-ins only.",
    "body": "<p align=\"center\"><img src=\"https://raw.githubusercontent.com/eoinjordan/doom-godmode/main/assets/header.png\" alt=\"DOOM OSM GODMODE\" style=\"max-width:100%;border-radius:4px;\"/></p><p>This one started as a question I couldn't let go of: could I turn a real place — a named street, a famous building, your school — into a playable Doom level, with no npm dependencies at all? The answer turned out to be yes, and the pipeline is simpler than it sounds once you stop fighting a 1993 game engine.</p><p><a href=\"https://github.com/eoinjordan/doom-godmode\" rel=\"noopener\">doom-osm-godmode</a> (on npm as <code>doom-osm-godmode</code>) does this:</p><ol><li>Takes a place name, a GeoJSON file, or a config</li><li>Geocodes through Nominatim, the public OpenStreetMap geocoder</li><li>Pulls polygon features from the Overpass API — buildings, parks, water, roads</li><li>Projects them from WGS84 into a flat Mercator grid</li><li>Assigns each feature to a room in a grid layout with corridors between them</li><li>Writes a UDMF text map and packages it as a binary PWAD</li></ol><p>You load the PWAD into GZDoom and walk through a spatial approximation of wherever you asked for.</p><pre><code>npx doom-osm-godmode build-place \"Colosseum, Rome, Italy\" --radius 450</code></pre><p>That's the whole install. No <code>npm install</code> — there are no dependencies. Just Node 20 built-ins: <code>fs</code>, <code>path</code>, <code>fetch</code>, <code>Buffer</code>. I kept it that way on purpose: a tool with zero supply chain is a tool a teacher can run on a locked-down school laptop without a security conversation.</p><h3>The UDMF geometry problem</h3><p>Getting GZDoom UDMF geometry right is not obvious. Doom's 2.5D engine has rules that aren't enforced at the file-format level but absolutely are enforced at render time — you get visual corruption instead of an error message, which is a much worse way to find out you were wrong.</p><p>The 1.2.0 release fixed most of them the hard way. Wall flickering from duplicate linedefs at cross junctions: fixed by replacing four overlapping rectangles with a single 12-vertex polygon. Invisible mid-walls on two-sided linedefs between same-floor sectors: fixed with <code>wrapmidtex = true</code> and <code>blocking = true</code>. Sky bleed at ceiling edges. Player stuck in zero-height pillar sectors, replaced with Thing type 30, the tall green column. Each one was its own debugging session.</p><p>So I wrote a validator. It catches 12 classes of these problems before GZDoom ever sees the file, plus a standalone diagnostic script for when the validator passes but something still looks wrong. That's the same instinct behind everything I build for learners: make the failure <em>inspectable</em> instead of mysterious.</p><h3>Hand-crafted buildings</h3><p>The OSM pipeline generates rooms from feature polygons automatically, which is great, but it produces blocky results for architecturally distinct buildings. So 1.2.0 added a hand-crafted example: Galway Cathedral. Cross-shaped floor plan as a 12-vertex polygon, green copper dome, twin towers, spire, raised chancel, nave pillars as Thing objects rather than sectors (sectors with floor=ceiling confuse the GZDoom node builder), teleporter-based catacombs. It lives in <code>scripts/build-galway-cathedral.js</code> as a reference for anyone who wants to build from a real floor plan rather than pulling from OSM.</p><h3>The agentic playtest</h3><p>The piece I'm most fond of is the automated playtest. <code>npm run playtest</code> runs an agent that builds a WAD and validates it without ever opening GZDoom — vertex references, sector references, one-sided versus two-sided linedef consistency — and produces a pass/fail report. It runs in CI on every push, so a regression in the geometry pipeline gets caught immediately instead of showing up as visual corruption hours later.</p><p>This is the pattern I keep coming back to: a <strong>tool</strong> is a single capability (build a WAD); a <strong>skill</strong> is the bounded, testable loop around it (build → validate → diagnose → fix → repeat). The AGENTS.md spells that loop out so an agent iterates on UDMF geometry the same disciplined way you'd iterate on any embedded target.</p><h3>Try it</h3><pre><code>git clone https://github.com/eoinjordan/doom-godmode.git\ncd doom-godmode\nnpm test\nnpm run demo</code></pre><p>The demo runs offline from a bundled GeoJSON, so it works without touching the OSM APIs — handy for a classroom with no open internet. The Freedoom IWAD installer (<code>node scripts/install-freedoom.js</code>) pulls a free IWAD so nobody needs a commercial Doom copy to play the output.</p><p>It turns out real cities make good Doom levels — the street grid does most of the level design for you. The only genuinely hard part was teaching a 30-year-old renderer to behave, and honestly that was the fun part.</p><p>If you could walk through one real place as a Doom level, what would you pick? I'm tempted to do a whole campus next.</p><h3>Links</h3><ul><li>Repo: <a href=\"https://github.com/eoinjordan/doom-godmode\" rel=\"noopener\">github.com/eoinjordan/doom-godmode</a></li><li>npm: <a href=\"https://www.npmjs.com/package/doom-osm-godmode\" rel=\"noopener\">doom-osm-godmode</a></li></ul>"
  },
  {
    "slug": "minecraft-mcp-real-world-bedrock-builder",
    "title": "Building Minecraft Worlds From Real Places With an Agentic Stack",
    "date": "2026-06-07",
    "tags": ["minecraft", "bedrock", "openstreetmap", "mcp", "agentic-ai", "ollama", "tools"],
    "summary": "minecraft-mcp geocodes real places through OpenStreetMap, converts them to Minecraft coordinates, and generates Bedrock behavior-pack commands an agent can execute in your world. Local-first with Ollama, a behavior pack for stable execution, and a WebSocket bridge for live control.",
    "body": "<p>Minecraft is where a lot of kids do their first real building. So I wanted to point an agent at a real place — not have it hand-place a recreation, but pull a layout straight from the map data — and have it built in their world. That's what <a href=\"https://github.com/eoinjordan/minecraft-mcp\" rel=\"noopener\">minecraft-mcp</a> does. You name an area (a park, a city block, a campus) and the planner geocodes it through OpenStreetMap, converts the coordinates into Minecraft block positions, and generates Bedrock-safe command plans an agent can execute.</p><p>The harder part was making that reliable enough to actually put in front of someone. Bedrock client support for live automation is inconsistent across versions; what you get from <code>/connect</code> and the WebSocket bridge varies by client build. So the architecture splits in two:</p><ol><li><strong>The MCP server</strong> — the planning and generation layer. It stores named landmarks and areas, geocodes through OSM, generates Bedrock-safe command plans, and can optionally talk to Bedrock live through the WebSocket bridge.</li><li><strong>The behavior pack</strong> — the in-world execution layer. It exports the build logic as <code>/function agentic_builder/...</code> commands that run stably on any Bedrock client, no <code>/connect</code> required.</li></ol><p>The split is the point. The server does the AI-assisted planning; the behavior pack gives you a dependable execution path even when the live bridge isn't available. You can build on PC and upload the world to a Realm for Switch play — which matters when the device in a kid's hands isn't the device you developed on.</p><h3>Local-first, so it works on a school network</h3><p>The default model path is Ollama: run a local model, no API key, no cloud dependency. OpenRouter and Groq are configured as fallbacks for constrained devices where a local model isn't practical. A Pi 4 with 4&nbsp;GB can run a small quantised model via Ollama and serve as both the MCP host and the planning backend for a whole classroom. That's deliberate — plenty of school networks block external API calls, and \"it needs an internet API key\" is where a lot of good lessons quietly die.</p><h3>Skills, not just tools</h3><p>The MCP surface is intentionally narrow: tools for planning (define area, add landmark, generate command plan), resources for inspecting state (current map, landmark list), and prompts for guided workflows. All state is explicit — planner state and a <code>MAP.md</code> file are the source of truth, not in-memory data that vanishes on restart.</p><p>I've standardised agent <strong>skill files</strong> across my MCP projects — reusable, multi-step workflows that encode the decisions a practitioner would actually make. The minecraft-mcp repo mirrors them for Claude, OpenCode, generic agents, and Clawdbot, all with the same scope and safety rules. The rule of thumb is the one I described in the <a href=\"https://www.edgeimpulse.com/blog/lessons-learned-from-building-an-agentic-ai-mcp-server-for-edge-impulse\" rel=\"noopener\">Edge Impulse MCP post</a>: skills are what agents reach for first, tools are what skills call, and raw tool sequences without skill scaffolding are the wrong way to drive the server. Skills make agentic loops predictable; tools without skills produce creative but unreliable results.</p><blockquote><strong>Safety note:</strong> treat an MCP server like executable code. <code>start:safe</code> binds to localhost only, and you should keep it pointed at a throwaway world, not the build you've spent six months on. Agents are confident; worlds are cheap to back up.</blockquote><h3>Getting started</h3><pre><code>git clone https://github.com/eoinjordan/minecraft-mcp.git\ncd minecraft-mcp\nnpm install\nnpm run start:safe</code></pre><p>The newcomer path: start the server, create a landmark or area through the HTTP API at <code>http://127.0.0.1:3093</code>, install the Bedrock behavior pack with <code>npm run install:bedrock</code>, enable it in your world, and run <code>/function agentic_builder/info</code>. From there the agent handles the planning and the behavior pack handles the execution. For the real-world path, any place name works: <code>create_area(\"Trinity College Dublin\", radius_meters=800)</code> and the planner does the rest.</p><p>The OSM-as-source-of-truth trick started with my Doom level generator. Minecraft turned out to be the gentler target — blocks are already a grid, so there's no 2.5D engine waiting to punish you for a malformed sector.</p><p>If you teach with Minecraft, what real place would your students want to walk into first — their town, their school, somewhere they'll never get to visit?</p><h3>Links</h3><ul><li>Repo: <a href=\"https://github.com/eoinjordan/minecraft-mcp\" rel=\"noopener\">github.com/eoinjordan/minecraft-mcp</a></li><li>Related: <a href=\"https://github.com/eoinjordan/doom-godmode\" rel=\"noopener\">doom-osm-godmode</a> · <a href=\"https://www.edgeimpulse.com/blog/lessons-learned-from-building-an-agentic-ai-mcp-server-for-edge-impulse\" rel=\"noopener\">Edge Impulse MCP lessons</a></li></ul>"
  },
  {
    "slug": "shelf-hardware-agentic-ai-education",
    "title": "The Hardware Is Already There. The Software Support Isn't.",
    "date": "2026-06-07",
    "tags": ["edge-ai", "education", "arduino", "raspberry-pi", "jetson", "lego", "microbit", "mcp", "agentic-ai"],
    "summary": "Universities have Raspberry Pis, Jetsons, Arduino boards, LEGO Mindstorms kits and micro:bits sitting on shelves. Students shouldn't have to wait for a vendor to catch up with agentic AI. The tools exist; the work is building the bridges.",
    "body": "<p>Go into any university lab that touches embedded systems, robotics, or maker-adjacent engineering and look at the shelves. You'll find the same hardware over and over: Raspberry Pis in various generations, an NVIDIA Jetson or two, a drawer of Arduino Unos and Nanos, some LEGO Mindstorms kits in varying states of completeness, a few micro:bits, maybe a box of ESP32 dev boards. Some of it bought last year, some of it bought eight years ago.</p><p>This is the hardware students actually learn on. It's what's affordable, what IT will approve, what has enough documentation to survive a semester, and what gets donated and kept when budgets get cut. It's not going away.</p><p>What bothers me is the assumption — implicit in most tooling decisions — that agentic AI, MCP servers, and the current wave of AI-assisted development are for the new stuff. That they're for cloud-connected enterprise hardware, not for the Arduino Nano 33 BLE in the component drawer.</p><p>That assumption is wrong, and it leaves students behind.</p><h3>What's actually on those shelves</h3><p>Let me be specific, because the hardware matters.</p><p><strong>Arduino.</strong> The Uno is a 16&nbsp;MHz AVR with 2&nbsp;KB RAM. Agentic AI can't run <em>on</em> it. But it absolutely can run <em>with</em> it. An MCP server that validates, compiles, and flashes Arduino sketches — using the Arduino CLI under the hood — turns any LLM into a tool that can iterate on embedded code against real hardware. Describe the behaviour you want, generate the sketch, validate it compiles for your FQBN, flash, watch the serial output, iterate. That's a meaningful agentic loop and it runs on a five-year-old laptop wired to a three-pound board. My <a href=\"https://github.com/eoinjordan/arduino-mcp\" rel=\"noopener\">Arduino MCP server</a> does exactly this.</p><p><strong>Raspberry Pi.</strong> From a 3B+ upward, these are real Linux machines. They run Ollama. They run small quantised models. They can be both the host of the MCP server and the inference target. A student with a Pi 4 has a complete agentic stack for basically nothing — local LLM, tool server, hardware target, all on one board. The gap is documentation and scaffolding, not compute.</p><p><strong>NVIDIA Jetson.</strong> The Orin Nano starts around $250 and has enough CUDA to run proper vision models locally. The ecosystem has TensorRT, DeepStream, and Triton — production inference tooling, on hardware a university can stock. The missing piece is agentic scaffolding that meets students where they are, rather than assuming they've already set up Kubernetes.</p><p><strong>LEGO Mindstorms and WeDo.</strong> EV3, NXT, SPIKE Prime, Robot Inventor, WeDo 2.0 — all programmable hardware with real sensors and actuators, and all with enough open-source firmware and protocol support to be first-class agentic AI targets. The <a href=\"https://github.com/eoinjordan/mindstorms-robot-creator\" rel=\"noopener\">Mindstorms Robot Creator</a> is my attempt at a unified code-generation and connection layer for the whole family, exposed to agents as MCP tools.</p><p><strong>micro:bit.</strong> V2 has a microphone, speaker, accelerometer, and BLE. The <a href=\"https://github.com/eoinjordan/microbit-mcp\" rel=\"noopener\">micro:bit MCP server</a> handles firmware generation and flashing. It's built for exactly the case where someone has thirty micro:bits and no budget for anything else — enough to teach embedded sensing, wireless comms, and agentic code generation in one session.</p><h3>The actual problem</h3><p>It isn't that the hardware can't do it. It's that the agentic tooling layer assumes you're starting fresh. Every major AI coding tool defaults to \"set up a new project.\" Every tutorial starts with \"first, provision your cloud instance.\"</p><p>Nobody at a resource-constrained university is provisioning cloud instances. They're plugging things into USB ports and hoping the driver works.</p><p>What they need is MCP servers that speak the language of the hardware they already have: Arduino CLI for Arduino boards, Web Serial for LEGO hubs, OpenOCD for SWD-accessible microcontrollers. The <a href=\"https://www.edgeimpulse.com/blog/lessons-learned-from-building-an-agentic-ai-mcp-server-for-edge-impulse\" rel=\"noopener\">Edge Impulse agentic work</a> showed what this looks like at the ML layer — tools that are thin wrappers over real actions, skills that encode the multi-step workflows a practitioner would follow, outputs that are inspectable rather than opaque. The same pattern works for embedded toolchains.</p><h3>The cheapest path to an agentic embedded stack right now</h3><p>If I were setting up a lab today for students who need to learn agentic AI with real hardware, this is the stack I'd build:</p><ul><li><strong>Arduino Nano 33 BLE Sense</strong> (~$35) — enough sensors to do real inference, BLE for wireless. Arduino CLI + MCP server handles the flash loop. Edge Impulse EON exports models that fit the 1&nbsp;MB flash.</li><li><strong>Raspberry Pi 4 (4&nbsp;GB)</strong> (~$55) — local LLM via Ollama (Llama 3.2 3B fits fine), MCP host, web dashboard. One Pi can serve a classroom if you set it up as a hotspot.</li><li><strong>micro:bit V2</strong> (~$15) — lowest barrier to entry. Blocks, Python, BLE, MCP server. Thirty of these and a Pi is a complete classroom setup for under $1000.</li><li><strong>LEGO kits from the shelf</strong> — whatever's there. EV3, NXT, SPIKE Prime, WeDo 2.0, Robot Inventor. The robot creator covers all of them. Don't throw out hardware that still works because the vendor's app got deprecated.</li></ul><p>The Jetson Orin Nano is the step up when you need vision — proper camera pipeline, TensorRT quantised inference, enough RAM for a vision-language model. But that's not the starting point. The starting point is what's already there.</p><h3>What \"enabling\" actually means</h3><p>\"Support\" for hardware usually means: it works, there's a tutorial, there's a forum. That's fine for getting started. What students need beyond that is to be <em>enabled</em> — to reach for the latest tools and have them work with the hardware in their hands, not the hardware in some vendor's reference design.</p><p>That means MCP servers that speak embedded protocols. It means code generators that know what 2&nbsp;KB of RAM implies. It means agentic loops that can flash firmware, read serial output, and iterate — not just write code and hand it back. It means block-based interfaces that work for a ten-year-old with a WeDo kit and Python generation that works for a student writing their first embedded ML pipeline on the same hardware.</p><p>The work isn't glamorous. Writing an MCP server for a 25-year-old serial protocol is not the kind of thing that goes on a keynote slide. But it's the difference between hardware that sits on a shelf for another decade and hardware that teaches the next generation of embedded engineers how to work with AI.</p><p>The hardware is already there. The software support is the work.</p><p>If you teach or run a club or lab: what's on your shelf that you wish an agent could already drive? That list is basically my backlog — tell me what to build next.</p><h3>Links</h3><ul><li><a href=\"https://github.com/eoinjordan/arduino-mcp\" rel=\"noopener\">arduino-mcp</a> · <a href=\"https://github.com/eoinjordan/microbit-mcp\" rel=\"noopener\">microbit-mcp</a> · <a href=\"https://github.com/eoinjordan/mindstorms-robot-creator\" rel=\"noopener\">mindstorms-robot-creator</a></li><li>Related: <a href=\"https://www.edgeimpulse.com/blog/lessons-learned-from-building-an-agentic-ai-mcp-server-for-edge-impulse\" rel=\"noopener\">Edge Impulse MCP lessons</a></li></ul>"
  },
  {
    "slug": "arduino-mcp-agentic-shelf-hardware",
    "title": "Giving the Arduino in the Drawer an Agentic Loop",
    "date": "2026-06-07",
    "tags": ["arduino", "mcp", "agentic-ai", "embedded", "education", "raspberry-pi", "edge-ai"],
    "summary": "arduino-mcp wraps the Arduino CLI in an MCP/HTTP service so an agent can validate, compile, and build sketches for real boards — a genuine describe → generate → flash → observe loop that runs happily on a Raspberry Pi.",
    "body": "<p>In my <a href=\"blog.html#shelf-hardware-agentic-ai-education\">shelf-hardware piece</a> I argued that the Arduino in the component drawer is a first-class agentic target, not a relic. This is the tool that makes that true: <a href=\"https://github.com/eoinjordan/arduino-mcp\" rel=\"noopener\">arduino-mcp</a> (on npm as <code>eoinedge-arduino-mcp</code>).</p><p>An Arduino Uno is a 16&nbsp;MHz AVR with 2&nbsp;KB of RAM. You're not running a language model on it. But you can wrap a clean loop <em>around</em> it: describe the behaviour you want, let an agent generate the sketch, validate it compiles for your board, build the binary, flash, read the serial output, and iterate. That loop is the whole game, and arduino-mcp is the bit in the middle that makes it dependable.</p><h3>What it actually exposes</h3><p>The server is a thin, honest wrapper over <code>arduino-cli</code>. Three endpoints, nothing clever hidden:</p><ul><li><strong><code>/health</code></strong> — is the toolchain present and ready</li><li><strong><code>/validate</code></strong> — does this sketch compile for the target FQBN, with the errors an agent can act on</li><li><strong><code>/build</code></strong> — compile and export the binary</li></ul><p>It defaults to the Arduino Nano 33 BLE (configurable via FQBN), auto-installs missing Arduino cores so the agent isn't blocked on a manual setup step, listens on port 3080, and allows a generous 600-second compile timeout because real boards and real cores are slow and that's fine.</p><h3>Built for the Pi</h3><p>The reason this matters for classrooms is where it runs. There's a multi-platform Docker image (linux/amd64 and linux/arm64), so a Raspberry Pi can be the whole rig: the MCP host, the build server, and — with Ollama alongside it — the model too. A student plugs a board into the Pi's USB port and has a complete, offline, agentic embedded stack for the price of a board and a Pi.</p><blockquote><strong>Safety note:</strong> a build server that compiles arbitrary code is exactly as powerful as it sounds. Run it in the Docker container, keep its filesystem access scoped to a sketch directory, and don't expose port 3080 beyond the machine that needs it.</blockquote><h3>Thin tools, testable skills</h3><p>This follows the same rule as the rest of my MCP work: a <strong>tool</strong> is one capability (validate a sketch); a <strong>skill</strong> is the bounded workflow built from tools (generate → validate → fix the compile errors → build → flash → read serial → iterate). When you give the agent skills instead of raw tools, the loop stays predictable and the student can read exactly what happened at each step. That inspectability is the educational point — the failure messages are a feature, not noise to hide.</p><h3>Getting started</h3><pre><code>npm install -g eoinedge-arduino-mcp\n# or run the container, then point your agent at port 3080</code></pre><p>From there the agent can validate against your FQBN, build a binary, and hand you serial output to reason about — the same flash-and-observe rhythm an embedded engineer already lives in, just with a collaborator who never gets bored of recompiling.</p><p>If you've got a drawer of Arduinos gathering dust, what's the first thing you'd wire an agent up to — a sensor logger, a blink-debugger, a little robot? Tell me and I'll make sure the skills cover it.</p><h3>Links</h3><ul><li>Repo: <a href=\"https://github.com/eoinjordan/arduino-mcp\" rel=\"noopener\">github.com/eoinjordan/arduino-mcp</a></li><li>npm: <a href=\"https://www.npmjs.com/package/eoinedge-arduino-mcp\" rel=\"noopener\">eoinedge-arduino-mcp</a></li><li>Related: <a href=\"blog.html#shelf-hardware-agentic-ai-education\">The hardware is already there</a> · <a href=\"https://www.edgeimpulse.com/blog/lessons-learned-from-building-an-agentic-ai-mcp-server-for-edge-impulse\" rel=\"noopener\">Edge Impulse MCP lessons</a></li></ul>"
  },
  {
    "slug": "microbit-mcp-classroom",
    "title": "Thirty micro:bits and a Pi: An MCP Server for the Classroom",
    "date": "2026-06-07",
    "tags": ["microbit", "mcp", "agentic-ai", "codal", "education", "embedded"],
    "summary": "microbit-mcp lets an agent edit CODAL C++ and regenerate MICROBIT.hex firmware for the BBC micro:bit v2 — REST plus stdio MCP, built for the case where a school has a class set of micro:bits and not much else.",
    "body": "<p>The BBC micro:bit is, for a lot of kids, the first computer they ever program that does something physical — a light, a sound, a message flung across the room over radio. There are millions of them in schools. So when I think about where agentic AI should meet learners, a drawer of thirty micro:bits is close to the top of the list. That's what <a href=\"https://github.com/eoinjordan/microbit-mcp\" rel=\"noopener\">microbit-mcp</a> (on npm as <code>microbit-claude-mcp</code>) is for.</p><h3>What it does</h3><p>It's an MCP server for BBC micro:bit v2 projects built on the CODAL toolchain. An agent can read and write the project's <code>source/main.cpp</code>, validate the project layout, run <code>build.py</code>, and produce a flashable <code>MICROBIT.hex</code> — the same artifact you'd drag onto the board's USB drive.</p><ul><li><strong>CODAL C++</strong> generation and editing, not just blocks — so the same board grows with the student from first lesson to real embedded code</li><li><strong>REST API</strong> on port 3040, plus an <strong>stdio MCP bridge</strong> so it drops into Claude or VS Code directly</li><li><strong>Project validation</strong> before build, so the agent fixes structure problems instead of producing a confusing compiler dump</li><li><strong>120-second build timeout</strong>; Python 3 required for the CODAL build</li><li>Plugin hooks for Clawdbot/Moltbot, and a MicroPython help-desk framing for classroom use</li></ul><h3>Why CODAL and not just blocks</h3><p>Block editors are a brilliant on-ramp — I've written before about how visual, low-code tools recenter programming on logic and ideas instead of semicolons. But the micro:bit's real superpower in a classroom is that the <em>same</em> board runs serious C++. An agent that can generate and regenerate CODAL firmware means a student can start with \"make the LEDs do a heartbeat\" and, later in the same term, end up reading an accelerometer in C and understanding why. The hardware doesn't change; the depth does.</p><blockquote><strong>Safety note:</strong> the server runs a real build toolchain. Keep it sandboxed, give it access only to the project directory, and treat any agent that can write <code>main.cpp</code> the way you'd treat a student with sudo — supervised, scoped, and easy to roll back.</blockquote><h3>The classroom maths</h3><p>This is the cheapest complete agentic stack I know of. A class set of micro:bit v2 boards is roughly $15 each; one Raspberry Pi can host the MCP server, the build, and a local model via Ollama and serve the room as a hotspot. Thirty boards and a Pi comes in under $1000 — no per-seat licences, no cloud API keys, nothing that trips a school firewall. That's a real embedded-AI lab for the cost of a single laptop.</p><h3>Getting started</h3><pre><code>npm install -g microbit-claude-mcp\n# REST on :3040, or wire the stdio MCP bridge into your agent</code></pre><p>Point your agent at it, ask for a behaviour, and let it generate the C++, build the hex, and hand it back for you to flash and inspect. Small change, visible output, explicit verification — the loop I want every learner to internalise.</p><p>Teachers: if you had an agent sitting next to a class set of micro:bits, what's the first lesson you'd hand it? #microbit #edtech — I read every reply.</p><h3>Links</h3><ul><li>Repo: <a href=\"https://github.com/eoinjordan/microbit-mcp\" rel=\"noopener\">github.com/eoinjordan/microbit-mcp</a></li><li>npm: <a href=\"https://www.npmjs.com/package/microbit-claude-mcp\" rel=\"noopener\">microbit-claude-mcp</a></li><li>Related: <a href=\"blog.html#shelf-hardware-agentic-ai-education\">The hardware is already there</a></li></ul>"
  },
  {
    "slug": "android-mcp-edge-impulse-inferencing",
    "title": "Letting an Agent Build and Deploy On-Device Inference Apps",
    "date": "2026-06-07",
    "tags": ["android", "mcp", "agentic-ai", "edge-ai", "edge-impulse", "gradle", "tools"],
    "summary": "android-mcp gives an agent the Gradle and ADB actions it needs to scaffold, build, and deploy an Edge Impulse on-device inferencing app — no Android Studio GUI, no clicking through wizards.",
    "body": "<p>There's a gap between \"I trained a model\" and \"it's running on a phone in someone's hand,\" and for a lot of learners that gap is an Android build system they've never met. <a href=\"https://github.com/eoinjordan/android-mcp\" rel=\"noopener\">android-mcp</a> (on npm as <code>eoinedge-android-mcp</code>) is my attempt to let an agent carry them across it.</p><p>It's an MCP bridge that wraps the host's Git, Gradle, and ADB tools so an agent can scaffold, validate, build, and deploy an Edge Impulse on-device inferencing app — the whole pipeline, headless, no Android Studio GUI required.</p><h3>The actions</h3><ul><li><strong><code>setup_base</code></strong> — pull the base app (<code>edgeimpulse/example-android-inferencing</code>) via a sparse Git checkout</li><li><strong><code>doctor</code></strong> — check the host has a working JDK and Android SDK/NDK before anything else fails confusingly</li><li><strong><code>gradle_tasks</code></strong> — list what the project can do</li><li><strong><code>assemble_debug</code></strong> — build the debug APK through the Gradle wrapper</li><li><strong><code>install_debug</code> / <code>adb_devices</code></strong> — see connected devices and push the build to one</li></ul><p>It listens on port 3094. One nice, very real detail: the base repo is pulled with a <strong>sparse checkout</strong> specifically to dodge Windows long-path issues — the kind of papercut that silently defeats a beginner on a school laptop and never shows up in a tutorial written on a Mac.</p><h3>Why hand this to an agent at all</h3><p>Because the Android build is precisely the part that isn't the lesson. The lesson is the model, the data, the inference, the thing the phone now understands. <code>doctor</code> exists so the agent can tell a student \"your NDK is missing\" in plain language instead of letting Gradle bury it in a stack trace. <code>assemble_debug</code> and <code>install_debug</code> turn \"forty minutes of environment yak-shaving\" into \"it's on your phone, go test it.\"</p><p>As ever: the tools here are thin wrappers over real actions, and the value is the <strong>skill</strong> that chains them — setup → doctor → assemble → install → observe. Every step produces an inspectable result, so when something breaks the student sees <em>where</em>, not just that the magic stopped working. That's the same human-in-the-loop principle behind all of this: support and empower, don't replace the thinking.</p><blockquote><strong>Safety note:</strong> this runs Gradle and ADB against your host and your connected devices. Keep it on a trusted machine, scoped to the project, and don't point <code>install_debug</code> at a phone you haven't unlocked for development on purpose.</blockquote><h3>Getting started</h3><pre><code>npm install\nnpm run setup:base\nnpm run start</code></pre><p>It pairs naturally with the <a href=\"https://www.edgeimpulse.com/blog/lessons-learned-from-building-an-agentic-ai-mcp-server-for-edge-impulse\" rel=\"noopener\">Edge Impulse MCP work</a>: train and export with one server, then build and deploy to a real device with this one, with an agent stitching the two ends together.</p><p>If you teach mobile or edge ML, where does your class lose the most time — training, or the deploy-to-device slog? I'd like the skills here to delete whichever one it is.</p><h3>Links</h3><ul><li>Repo: <a href=\"https://github.com/eoinjordan/android-mcp\" rel=\"noopener\">github.com/eoinjordan/android-mcp</a></li><li>npm: <a href=\"https://www.npmjs.com/package/eoinedge-android-mcp\" rel=\"noopener\">eoinedge-android-mcp</a></li><li>Base app: <a href=\"https://github.com/edgeimpulse/example-android-inferencing\" rel=\"noopener\">edgeimpulse/example-android-inferencing</a></li></ul>"
  },
  {
    "slug": "mindstorms-robot-creator-wedo2-eol",
    "title": "Building a Universal LEGO Robot IDE Before the WeDo 2.0 App Dies",
    "date": "2026-06-07",
    "tags": ["lego", "edge-ai", "tools", "embedded", "wedo2", "mcp", "blockly"],
    "summary": "WeDo 2.0 loses its official app on July 31 2026. I built a browser IDE, an Android app with a kid-friendly Simple Mode, a firmware repo, and an MCP server so the hardware doesn't go with it.",
    "body": "<p>The LEGO Education WeDo 2.0 app is being retired on July 31 2026. That's 54 days from when I'm writing this. It's the official programming environment for a robot kit that's in classrooms all over the world, and after that date, LEGO's position is essentially: good luck.</p><p>After 14 years teaching kids programming, electronics, and robotics, that's exactly the kind of thing that annoys me into building something. Perfectly good hardware shouldn't become e-waste because a piece of software reached end-of-life.</p><p>The result is <a href=\"https://github.com/eoinjordan/mindstorms-robot-creator\" rel=\"noopener\">Mindstorms Robot Creator</a> — a browser-based IDE that covers every programmable LEGO hub that ever existed, from the 1998 RCX brick to WeDo 2.0. It's on npm as <a href=\"https://www.npmjs.com/package/mindstorms-robot-creator\" rel=\"noopener\"><code>mindstorms-robot-creator</code></a>, and the <a href=\"https://eoinjordan.github.io/mindstorms-robot-creator/\" rel=\"noopener\">browser app</a> — now at v0.6 — runs on GitHub Pages with no install required.</p><h3>What it actually does</h3><p>The core idea is profile-driven code generation. You describe your robot as a JSON port map — motor on A, motion sensor on B, that kind of thing — and the app generates correct, runnable Python for whichever target you've picked. It's not AI-generated code; it's templated generation from known hardware configurations, which means it's reliable and inspectable. (That word again. It's the whole philosophy.)</p><p>Targets covered:</p><ul><li><strong>Robot Inventor 51515 / SPIKE Prime</strong> — mindstorms-module Python, Pybricks, Blockly visual programming, BLE REPL via Pybricks, USB serial via Web Serial</li><li><strong>WeDo 2.0</strong> — hub-module MicroPython for the official app, Pybricks CityHub as a migration path, Blockly with a WeDo-specific block palette, BLE connection to stock firmware</li><li><strong>EV3</strong> — Pybricks and ev3dev MicroPython</li><li><strong>NXT</strong> — Pybricks and nbc/nxc</li><li><strong>RCX</strong> — bytecode upload over a USB IR tower via Web Serial, with motor controls and a ping tester in the browser</li></ul><p>The RCX support is probably the most unnecessary thing I've ever built and I have absolutely no regrets about it.</p><h3>The WeDo 2.0 hardware situation</h3><p>The WeDo 2.0 Smart Hub (45301) is a Nordic nRF51822: Cortex-M0 at 16&nbsp;MHz, 256&nbsp;KB flash, 16&nbsp;KB RAM, BLE 4.0. That's a completely normal embedded target. The app might be going away, but the hardware is just a microcontroller, and there are several reasonable paths forward:</p><ul><li><strong>Use the official app while it's still available</strong> — obvious, but worth saying. July 31 isn't here yet.</li><li><strong>Pybricks CityHub firmware</strong> — reflash over SWD, full Python REPL over BLE, ongoing support. The clean long-term answer.</li><li><strong>Stock firmware over BLE</strong> — the WeDo 2.0 hub still speaks its native LEGO wireless protocol over BLE after the app is gone, so you can drive motors and the LED without reflashing anything. The browser IDE now runs whole Blockly programs this way: build your blocks, hit Run, and the commands go straight to the stock hub.</li><li><strong>Custom firmware</strong> — I put together a <a href=\"https://github.com/eoinjordan/wedo2-hub-firmware\" rel=\"noopener\">firmware repo</a> covering Zephyr, bare-metal C++, MicroPython, and three ML inference approaches. More on that below.</li></ul><h3>Blockly, and a Simple Mode for kids</h3><p>Blockly was already in the app for Robot Inventor and SPIKE Prime. WeDo 2.0 needed a completely separate block palette because the hub-module API is different: <code>hub.port.A.motor.run_for_seconds()</code>, <code>hub.motion.tilt_angles()</code>, and so on. The toolbox switches automatically when you select a WeDo 2.0 profile, and the intent system — beep hello, safe probe, drive forward, wave — generates appropriate starter blocks so nobody's staring at a blank canvas. The safe-probe intent tests each connected motor in both directions first, which saves a lot of \"why isn't my motor working\" debugging.</p><p>There's an Android build of the same thing now, with a one-tap <strong>Simple Mode</strong> that drops a child straight into a full-screen block canvas — fewer menus, bigger blocks, one Run button. That's the version I'd actually put in front of a ten-year-old, and the same kid can graduate to the full interface without changing tools or hardware.</p><h3>The MCP server</h3><p>Following on from the <a href=\"https://www.edgeimpulse.com/blog/lessons-learned-from-building-an-agentic-ai-mcp-server-for-edge-impulse\" rel=\"noopener\">Edge Impulse MCP work</a>, I added an MCP server that exposes the robot creator's code generation as tools a language model can call. Same pattern as always: tools are thin wrappers over real actions, skills are the reusable multi-step workflows. A session looks like: scan for known profiles → describe the robot → generate code for a chosen intent → optionally run it on the hub → observe → iterate. The handoff tool even generates step-by-step instructions for getting the code into the official app, including a note about the EOL date.</p><h3>Running inference on a 16&nbsp;KB device</h3><p>The <a href=\"https://github.com/eoinjordan/wedo2-hub-firmware\" rel=\"noopener\">custom firmware repo</a> covers four inference approaches, and the honest comparison matters because the nRF51822 is tight:</p><ul><li><strong>Roll your own</strong> — fixed-point INT8 MLP in a header file, ~4&nbsp;KB tensor budget. Fits easily. Full control.</li><li><strong>TFLite Micro</strong> — technically fits for a small MLP if you're careful with the tensor arena. About 50&nbsp;KB flash overhead for the FullyConnected + Softmax kernels. No CNNs.</li><li><strong>Edge Impulse EON</strong> — best option for anything trained in the cloud. The EON compiler optimises for your specific MCU before you download, and tells you flash and RAM usage <em>before</em> you commit. You know if it fits before you flash it.</li><li><strong>ExecuTorch</strong> — no. Minimum ~256&nbsp;KB RAM. The nRF51822 has 16&nbsp;KB. Not a close call.</li></ul><p>The repo also has a Python script that takes a Keras model, quantises the weights to INT8, and exports a C++ header you can include directly — useful if you want the roll-your-own path but don't fancy doing the quantisation by hand.</p><h3>What I'd actually tell a teacher right now</h3><p>If you have WeDo 2.0 kits and you're wondering what to do after July 31:</p><ol><li>Keep using the official app until it's gone. You have until the end of July.</li><li>Try the <a href=\"https://eoinjordan.github.io/mindstorms-robot-creator/\" rel=\"noopener\">browser IDE</a> for code generation — it works today, without the official app.</li><li>If you want a supported long-term path, <a href=\"https://pybricks.com\" rel=\"noopener\">Pybricks</a> CityHub firmware is the answer. You need SWD access to reflash — a one-time thing per hub, not a classroom activity.</li><li>If you have RCX or NXT bricks in a cupboard somewhere, those work too.</li></ol><p>The hardware isn't going anywhere. Whether the software ecosystem follows it is a different question — and as of July 31, it's partly an open-source problem now.</p><p>If you've got LEGO kits in a store cupboard you assumed were dead, tell me which generation — I want to make sure the creator covers the ones still in classrooms.</p><h3>Links</h3><ul><li>Repo: <a href=\"https://github.com/eoinjordan/mindstorms-robot-creator\" rel=\"noopener\">github.com/eoinjordan/mindstorms-robot-creator</a></li><li>Browser IDE: <a href=\"https://eoinjordan.github.io/mindstorms-robot-creator/\" rel=\"noopener\">eoinjordan.github.io/mindstorms-robot-creator</a></li><li>Firmware: <a href=\"https://github.com/eoinjordan/wedo2-hub-firmware\" rel=\"noopener\">wedo2-hub-firmware</a> · npm: <a href=\"https://www.npmjs.com/package/mindstorms-robot-creator\" rel=\"noopener\">mindstorms-robot-creator</a></li></ul>"
  },
  {
    "slug": "imagine-innovators-amsterdam-2026",
    "title": "Imagine Innovators Amsterdam 2026 — Taking Linux Edge AI into Production",
    "date": "2026-05-20",
    "tags": ["edge-ai", "linux", "production", "events"],
    "summary": "Roundtable reflections from Imagine Innovators Amsterdam on what it actually takes to move from a working edge AI prototype to a production-grade deployment.",
    "body": "<p>Last week I joined a livestream roundtable at Imagine Innovators Amsterdam alongside George Grey from Foundries.io, talking about how to take Linux-based Edge AI solutions from silicon all the way through to production deployment.</p><p>George's talk covered the full arc: hardware selection, software platforms, application deployment, and lifecycle management in the CRA era. The stat that keeps coming up — over 70% of IoT and edge projects fail to reach production — isn't surprising if you've been in the space long enough. The gap between a working prototype and something robust enough to ship is where most projects quietly die.</p><p>A few things stood out from the discussion:</p><ul><li><strong>Security is structural, not a checkbox.</strong> The CRA (Cyber Resilience Act) is making this unavoidable for anyone shipping into the EU market. Foundries.io's approach of treating update pipelines and attestation as first-class concerns from the start is the right call.</li><li><strong>The hardware decision is a long-term commitment.</strong> Choosing a chipset means choosing a support window, a BSP maintenance story, and an ecosystem. Edge AI adds inference requirements on top — so you're picking a platform that has to be supported for years, not months.</li><li><strong>Linux at the edge is genuinely different to Linux in the cloud.</strong> OTA, rollback, secure boot, and resource limits push you toward a different set of tradeoffs than cloud-native deployment assumes.</li></ul><p>Most of what I build sits at the other end of this pipeline — the small, cheap, on-a-shelf hardware where people are still trying to get the prototype working at all. But the production gap George described is the same gap, just scaled up: the distance between \"it runs on my bench\" and \"it survives in the field\" is where the real engineering lives. The full recording is on the Edge Impulse YouTube channel if you missed the livestream.</p><h3>Links</h3><ul><li>Related: <a href=\"blog.html#shelf-hardware-agentic-ai-education\">The hardware is already there</a></li></ul>"
  }
]
