<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Lakpriya Senevirathna · Blog</title>
    <link>https://lakpriya.com/blog</link>
    <atom:link href="https://lakpriya.com/rss.xml" rel="self" type="application/rss+xml" />
    <description>Short, practical notes on mobile, payments and leading small teams.</description>
    <language>en</language>
    <lastBuildDate>Mon, 05 Oct 2026 00:00:00 GMT</lastBuildDate>
    <item>
      <title>HushReply: free comment-to-DM for Instagram and Facebook</title>
      <link>https://lakpriya.com/blog/hushreply-free-comment-to-dm</link>
      <guid isPermaLink="true">https://lakpriya.com/blog/hushreply-free-comment-to-dm</guid>
      <pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate>
      <description>The one ManyChat feature most creators use, as a self-hosted Cloudflare Worker with no contact limits and no monthly fee.</description>
      <content:encoded><![CDATA[<p>On Facebook and Instagram you post “Comment GUIDE and I’ll send it to you.” Someone comments GUIDE, and within a second they get a DM with the link, plus an optional “Check your DMs 📬” reply under their comment.</p><p>That is the one ManyChat feature most creators and businesses actually use. But ManyChat’s free plan now stops at 25 contacts, and one viral post can push you into a paid tier. HushReply does that one job, for free.</p><p>What it does</p><p>**Instagram and Facebook Pages** from one deployment. **Keyword rules** that ignore the word inside other words and handle emoji, so `LINK🙏` matches but `linked` doesn’t. **Public replies with rotating variations**, so it never looks copy-pasted. **Multiple accounts**, each with its own keywords. **A simple dashboard**: no code, and you can test a comment before it goes live. **Honest replies**: if the DM fails, the “check your DMs” reply is held back.</p><p>How it’s built</p><p>It runs as one small Worker in your own Cloudflare account, on the free plan, which covers about 500 keyword replies a day at $0. It uses Meta’s official private-replies API: no scraping, no browser automation and no password sharing. There is a one-click “Deploy to Cloudflare” button, and no Meta App Review is needed when you use it on your own accounts.</p><p>Under the hood</p><p>Each comment follows the same path through the Worker: webhook in, signature check, parse, find the account, find the rule, claim the comment, check the cooldown, send the DM, then post the public reply.</p><p>**Answer Meta first, work second.** Meta retries any webhook that responds slowly, so the Worker returns `200` immediately and does the Graph API calls in `ctx.waitUntil`. **Never DM twice.** Every comment id is claimed in Workers KV before anything is sent, so a redelivered webhook is ignored. A self-comment guard checks against every configured account, so two of your accounts can never get stuck replying to each other. **Signatures checked properly.** HMAC-SHA256 against each app secret, because Instagram Login uses a different secret from the Facebook app. **Emoji-aware matching.** JavaScript’s `\b` only understands ASCII, so the `word` match mode uses a hand-written Unicode word boundary. Other modes are contains, exact, starts-with, regex and any comment. **Stable replies.** The public reply variation is picked from the comment id, so a retried webhook posts the same text. **Tokens that don’t expire.** A daily cron refreshes Instagram’s long-lived tokens before their 60-day expiry. **Secrets stay out of `ps`.** The local dashboard only listens on 127.0.0.1 and passes tokens to `wrangler` through stdin or a `chmod 600` temp file, never as command-line arguments.</p><p>It ships with `DRY_RUN` on, and 82 unit tests run on Node’s built-in test runner.</p><p>To be honest about it: it is not a full ManyChat replacement. There is no flow builder and no broadcasts, and setup takes about an hour, mostly in Meta’s developer settings. But if all you need is “comment a keyword, get the DM”, you shouldn’t be paying monthly for it.</p><p>HushReply is open source under AGPL-3.0. Try it from the [website](https://lakpriya1s.github.io/hushreply/) or read the code on [GitHub](https://github.com/lakpriya1s/hushreply).</p>]]></content:encoded>
      <category>Open source</category>
      <category>Developer tools</category>
      <dc:creator>Lakpriya Senevirathna</dc:creator>
    </item>
    <item>
      <title>Agent Rack: one MCP interface for all your AI coding agents</title>
      <link>https://lakpriya.com/blog/agent-rack-one-mcp-interface-for-ai-coding-agents</link>
      <guid isPermaLink="true">https://lakpriya.com/blog/agent-rack-one-mcp-interface-for-ai-coding-agents</guid>
      <pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate>
      <description>Delegate tasks from Claude Code to Codex, opencode or Antigravity without copying context between tools.</description>
      <content:encoded><![CDATA[<p>When you are working in Claude Code, have you ever wanted to hand a task to Codex, get an alternative solution from Antigravity, or ask opencode to review your code? Usually that means opening several tools and copying context between them. That is why I built Agent Rack.</p><p>Agent Rack is an MCP server that wraps command-line coding agents. Claude Code, OpenAI Codex, opencode and Antigravity are built in, and any other CLI agent can be added with a small adapter. Point any MCP client at it, and your main agent can work with the others without leaving your workflow.</p><p>What you can do</p><p>Delegate quick tasks and get results straight back. Run long tasks as background sessions, and watch progress and live logs. Send follow-up instructions while an agent is running, or cancel it. Connect several profiles of the same agent as separate agents.</p><p>The real benefit is another agent’s context, not just another tool call. A sub-agent reads files, runs commands and reasons on its own budget, then hands back a result, so the work never fills your main conversation’s context window.</p><p>Structured code review</p><p>Agent Rack also does structured code reviews. Its adversarial review mode looks for hidden bugs, security issues, edge cases and release risks, and returns validated JSON instead of free text. The reviewing agent never changes your code; the final decision stays with you.</p><p>Built for Claude Code</p><p>In Claude Code it installs as a plugin, which adds the MCP server, tools and skills. You don’t need to remember tool names: describe what you want, and Claude Code delegates to the right agent, knowing when to run a quick task, when to start a background session and how to present review results. A terminal dashboard and a guided setup that detects installed agents come with it.</p><p>How it works under the hood</p><p>Agent Rack never calls a model or asks for an API key. It runs the agent CLIs already on your `$PATH`, with the logins you already have, and translates between them and MCP. It&apos;s written in TypeScript on the official MCP SDK, and its layers depend in one direction only: config, security, adapters, engine, tools, server, CLI.</p><p>Every agent speaks a different protocol, so each one gets its own adapter:</p><p>**Claude Code** streams newline-delimited JSON events, and follow-ups resume the same conversation with `claude --resume`. **Codex** runs through `codex exec` with JSON output and resumes by thread id. **OpenCode** only works interactively, so Agent Rack drives it through a real pseudo-terminal with `node-pty`. **Antigravity** has its own stream format.</p><p>Conversation ids are read from each CLI’s own output instead of being made up front, so a wrapper script configured in place of the real CLI keeps working.</p><p>Background sessions write to a ring buffer of 512 events with a byte budget. Clients read logs with a cursor that only moves forward, so they can tell when they missed something. Cancelling a session signals the whole process group, first with SIGINT and then SIGKILL (`taskkill /T` on Windows). A separate `cancelling` state keeps the concurrency limit honest while a process shuts down.</p><p>Security, stated plainly</p><p>Handing your terminal to another agent needs guard rails, and Agent Rack is explicit about which ones it has:</p><p>Workspaces are checked by their real path, and a single call can’t raise the execution policy above what the config allows (read-only, workspace-write or full access). Each agent gets an environment allow-list, and variables that look like secrets are stripped. Reviews always run read-only: Codex in its read-only sandbox, Claude Code in plan mode. The optional SSE endpoint, which the dashboard uses, needs a bearer token, accepts only loopback hosts and rejects requests with an `Origin` header, which blocks DNS-rebinding attacks from a browser.</p><p>It also says what it doesn’t do: a workspace allow-list isn’t a sandbox, only Codex enforces one at the OS level, and prompt injection isn’t solved.</p><p>Try it</p><p># guided setup: detects your agents and MCP clients
npx agent-rack setup</p><p># or, inside Claude Code
/plugin marketplace add lakpriya1s/agent-rack</p><p># watch every sub-agent live
agent-rack dashboard</p><p>It registers with Claude Code, Codex, Claude Desktop, Cursor, Antigravity and OpenCode, and prints a snippet for VS Code.</p><p>Agent Rack is open source on [GitHub](https://github.com/lakpriya1s/agent-rack) and on [npm](https://www.npmjs.com/package/agent-rack), where it has passed 8,000 downloads in its first year.</p>]]></content:encoded>
      <category>Developer tools</category>
      <category>AI apps</category>
      <category>Open source</category>
      <dc:creator>Lakpriya Senevirathna</dc:creator>
    </item>
    <item>
      <title>ccbar: see your Claude Code limits without leaving the prompt</title>
      <link>https://lakpriya.com/blog/ccbar-claude-code-usage-status-line</link>
      <guid isPermaLink="true">https://lakpriya.com/blog/ccbar-claude-code-usage-status-line</guid>
      <pubDate>Wed, 22 Jul 2026 00:00:00 GMT</pubDate>
      <description>A status line that shows context use and your 5-hour and 7-day limits as bars that turn from green to red.</description>
      <content:encoded><![CDATA[<p>Have you ever been deep in a Claude Code session and wondered how much usage you actually have left? Normally you stop, open the Claude website and check. Otherwise you keep spending context and limits without knowing how close you are to the edge. So I built ccbar.</p><p>What it shows</p><p>Model and effort level. Current workspace. Context-window usage. 5-hour and 7-day limits, with the time left until each resets.</p><p>The bars change from green to yellow to red, so you can read your remaining headroom at a glance. When your current pace would use up a limit before it resets, ccbar adds a warning with the estimated time. Styles and themes let it match your terminal.</p><p>Install</p><p>npx ccbar-cli</p><p>How it works</p><p>Claude Code can run any command as a status line and pipe it a JSON object on every refresh. That JSON already includes the model, effort level, working directory, context-window percentage, cost, and both rate limits with their `used_percentage` and `resets_at` time. ccbar is a single Bash script that reads those fields with `jq` and draws two lines of coloured bars.</p><p>{
  &quot;statusLine&quot;: {
    &quot;type&quot;: &quot;command&quot;,
    &quot;command&quot;: &quot;~/.local/bin/ccbar render&quot;,
    &quot;padding&quot;: 0
  }
}</p><p>**No network calls and no tokens.** Everything comes from the data Claude Code already passes in, so it’s instant and works offline. **Burn-rate warning.** From how much of a window you’ve used and how long is left until it resets, ccbar estimates whether your current pace runs out first, and when. **Local history.** It caches the last payload for `ccbar stats` and appends a small, throttled history file (at most once a minute, size-capped), so `ccbar history` can draw a 7-day sparkline with estimated cost. **One dependency.** Bash and `jq`. A small Node wrapper exists only so `npx` can install it.</p><p>The installer wires ccbar into your Claude Code settings, backing up the file first, and runs a short setup wizard. It is also available as a Claude Code plugin. The code is on [GitHub](https://github.com/lakpriya1s/ccbar).</p>]]></content:encoded>
      <category>Developer tools</category>
      <category>Open source</category>
      <dc:creator>Lakpriya Senevirathna</dc:creator>
    </item>
    <item>
      <title>Running a fraud-detection LLM entirely on the phone</title>
      <link>https://lakpriya.com/blog/fraud-detection-llm-on-device</link>
      <guid isPermaLink="true">https://lakpriya.com/blog/fraud-detection-llm-on-device</guid>
      <pubDate>Mon, 14 Jul 2025 00:00:00 GMT</pubDate>
      <description>How fine-tuned, quantised LLMs under 1B parameters reached 99.5% accuracy on mobile, offline. My RANLP 2025 paper in plain English.</description>
      <content:encoded><![CDATA[<p>My MSc research project was accepted for presentation at RANLP 2025: *Efficient Financial Fraud Detection on Mobile Devices Using Lightweight Large Language Models*. It tackles a simple question. Can a phone run an LLM good enough to catch scam messages, without sending anything to the cloud?</p><p>The problem</p><p>Digital transactions grow every day, and so do fraudulent SMS and emails. Traditional detection models are often cloud-dependent, which brings problems with efficiency, scale and especially privacy. Large language models understand language well, but they are usually too heavy for a phone.</p><p>The approach</p><p>Fine-tune compact LLMs, under 1B parameters, for one task: spotting fraud in unstructured text. Use LoRA and QLoRA so fine-tuning fits modest hardware. Convert to ONNX with Hugging Face Optimum, then quantise to INT8 and 4-bit. Run the models with ONNX Runtime inside a React Native app, fully offline.</p><p>Making it run on a phone</p><p>Getting a trained model onto a phone took more work than training it.</p><p>**Download only what’s needed.** The app reads a model list from GitHub and lets you pick a model and a quantisation level. It then fetches just the config, the tokenizer and that one `.onnx` file from Hugging Face, with resumable downloads and per-file progress. **Tokenising on Hermes.** The JavaScript tokenizer expected a browser, so I patched it to load only local files, rewrote Unicode regexes that Hermes doesn’t support, and added `TextEncoder` and `Buffer` polyfills. **Answer in a few tokens.** The model only needs to say “Yes” or “No”, so generation stops after five tokens, using greedy decoding with a KV cache in ONNX Runtime. The app shows how long each check took.</p><p>The results</p><p>The fine-tuned, quantised Llama-160M-Chat-v1 reached **99.47%** accuracy with a **168 MB** footprint. The fine-tuned, quantised Qwen1.5-0.5B-Chat reached **99.50%** at 797 MB. Optimised LLMs can deliver accurate, real-time fraud detection on a phone without compromising privacy.</p><p>Let’s make AI safer and smarter, right in our pockets.</p><p>The app, FraudShield, is live on the [App Store](https://apps.apple.com/app/id6745196395) and [Google Play](https://play.google.com/store/apps/details?id=lakpriya.fraudShield), and the paper is in the [ACL Anthology](https://aclanthology.org/2025.ranlp-1.126/). Thanks to my supervisor, Deshan Sumanathilaka, for his guidance from the first idea to deployment.</p>]]></content:encoded>
      <category>Research</category>
      <category>AI apps</category>
      <category>React Native</category>
      <dc:creator>Lakpriya Senevirathna</dc:creator>
    </item>
    <item>
      <title>Add an AI chat assistant to your React Native app</title>
      <link>https://lakpriya.com/blog/add-ai-chat-to-a-react-native-app</link>
      <guid isPermaLink="true">https://lakpriya.com/blog/add-ai-chat-to-a-react-native-app</guid>
      <pubDate>Thu, 22 Feb 2024 00:00:00 GMT</pubDate>
      <description>Sparkle AI Chat is an open-source, brandable chat screen for React Native that skips most of the OpenAI documentation.</description>
      <content:encoded><![CDATA[<p>Almost every platform is trying to add a ChatGPT-like assistant. To do it, developers have to work through the OpenAI documentation, which takes time. So I packaged the work into my first npm package: a React Native library that brings an AI assistant to your app.</p><p>Install</p><p>npm i react-native-sparkle-ai-chat @react-native-async-storage/async-storage</p><p>Use it</p><p>Give it a platform, an API key and instructions for the assistant, and brand it with your own name, logo and colours.</p><p>import SparkleChat from &apos;react-native-sparkle-ai-chat&apos;;</p><p>&lt;SparkleChat
  platform=&quot;openai&quot;
  apiKey={OPENAI_API_KEY}
  instruction=&quot;You help customers choose from the coffees on our menu.&quot;
  brand={{ name: &apos;Coffee Assistant&apos;, primaryColor: &apos;#FF5C5C&apos; }}
/&gt;</p><p>What’s inside</p><p>The library is the chat screen from my [Sparkle AI app](/blog/sparkle-ai-chatgpt-mobile-app), extracted into a package built with `react-native-builder-bob`, so it ships CommonJS, ES modules and TypeScript types.</p><p>**Streaming** over server-sent events with `react-native-sse`, so answers appear as they’re written. **History** kept in Redux Toolkit and persisted to AsyncStorage, which is why AsyncStorage is a peer dependency. **Token budget.** Older messages are trimmed so the conversation fits the model’s context window. **Your own backend.** `apiBaseUrl` and `organization` let you point it at a proxy or any OpenAI-compatible endpoint instead of shipping a key in the app, and `completionParams` passes model, temperature and other options straight through.</p><p>Tip: for a production app, put your key behind a small proxy and set `apiBaseUrl`. A key bundled in an app can be extracted.</p><p>Next: function calling, so users can trigger the app’s own features by asking the assistant, and support for more AI platforms such as Gemini.</p><p>It is open source, and contributions are welcome on [GitHub](https://github.com/lakpriya1s/react-native-sparkle-ai-chat).</p>]]></content:encoded>
      <category>React Native</category>
      <category>AI apps</category>
      <category>Open source</category>
      <dc:creator>Lakpriya Senevirathna</dc:creator>
    </item>
    <item>
      <title>Sparkle AI: a ChatGPT-style assistant for iOS and Android</title>
      <link>https://lakpriya.com/blog/sparkle-ai-chatgpt-mobile-app</link>
      <guid isPermaLink="true">https://lakpriya.com/blog/sparkle-ai-chatgpt-mobile-app</guid>
      <pubDate>Mon, 19 Jun 2023 00:00:00 GMT</pubDate>
      <description>An AI chat app built with React Native on the OpenAI API, with model choice, custom instructions and saved chats.</description>
      <content:encoded><![CDATA[<p>I built a ChatGPT-style mobile app with React Native and the OpenAI API. It acts as a personal assistant that helps you stay organised and productive, and it is live on the App Store and Google Play as Sparkle AI.</p><p>What it does</p><p>Choose the model for each conversation, GPT-3.5 Turbo or GPT-4. Set custom system messages to shape how the assistant answers. Save chats and come back to them later.</p><p>How it’s built</p><p>Sparkle AI is a bare React Native app (0.71 at launch) with TypeScript, and it calls the OpenAI Chat Completions API directly: you bring your own API key, so there’s no server in between.</p><p>**Streaming, word by word.** React Native has no built-in server-sent events, so the client streams completions with `react-native-sse`. Each delta is appended to the message in Redux as it arrives, a stop button closes the stream, and errors appear in the chat instead of failing silently. **Conversations that persist.** Chats are stored in Redux Toolkit with redux-persist on AsyncStorage. Each request rebuilds the conversation from the current chat, with your instructions as the system message, and trims it to the model’s token budget. **Feels like a native app.** Code blocks get syntax highlighting and a copy button, a long press copies any message, voice input uses the phone’s own speech recognition, and a light haptic tap scales with the size of each streamed chunk. **Smooth long chats.** An inverted list is the usual way to build a chat, but on Android it flips with `scaleY: -1`, which is a known source of jank. I patched it to rotate 180° instead.</p><p>If you want the same kind of assistant inside your own app, my open-source [React Native chat library](/blog/add-ai-chat-to-a-react-native-app) packages it as a single component.</p><p>Download Sparkle AI from the [App Store](https://apps.apple.com/app/id6450364523) or [Google Play](https://play.google.com/store/apps/details?id=lk.codescale.sparkle).</p>]]></content:encoded>
      <category>AI apps</category>
      <category>React Native</category>
      <dc:creator>Lakpriya Senevirathna</dc:creator>
    </item>
  </channel>
</rss>
