<?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: Pranab Sarkar</title>
    <description>The latest articles on DEV Community by Pranab Sarkar (@spranab).</description>
    <link>https://dev.to/spranab</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%2F3785623%2F84db641c-9546-4aa5-8312-46f45b965e45.png</url>
      <title>DEV Community: Pranab Sarkar</title>
      <link>https://dev.to/spranab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/spranab"/>
    <language>en</language>
    <item>
      <title>My Agent Runs My Marketing (I Mostly Just Hit Approve)</title>
      <dc:creator>Pranab Sarkar</dc:creator>
      <pubDate>Thu, 13 Aug 2026 15:08:13 +0000</pubDate>
      <link>https://dev.to/spranab/my-agent-runs-my-marketing-i-mostly-just-hit-approve-4d81</link>
      <guid>https://dev.to/spranab/my-agent-runs-my-marketing-i-mostly-just-hit-approve-4d81</guid>
      <description>&lt;p&gt;I have 16 open-source projects, 15,386 downloads per month across PyPI and npm, and no ability to make myself post on forums consistently. I've known this about myself for years. So on 2026-08-09, I built a system to do the parts I won't do.&lt;/p&gt;

&lt;p&gt;Here's what actually happened in the first four days.&lt;/p&gt;




&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;The system lives in a folder called &lt;code&gt;c:\Users\sync\codes\marketing&lt;/code&gt;. A &lt;code&gt;PLAYBOOK.md&lt;/code&gt; holds the voice rules and guardrails. A &lt;code&gt;routines/&lt;/code&gt; folder has markdown files that each describe one agent prompt. A &lt;code&gt;state/&lt;/code&gt; folder of JSON and markdown files coordinates between routines. And a Python stdlib server at &lt;code&gt;localhost:8781&lt;/code&gt; handles the one thing that still needs a human.&lt;/p&gt;

&lt;p&gt;The routines run on cron via Claude Code headless. &lt;code&gt;weekly-metrics&lt;/code&gt; on Mondays. &lt;code&gt;registry-sweep&lt;/code&gt;, &lt;code&gt;repo-seo&lt;/code&gt;, and &lt;code&gt;content-writer&lt;/code&gt; weekly. &lt;code&gt;opportunity-scout&lt;/code&gt; daily (bumped from twice a week on launch day because Hacker News threads go cold in hours). &lt;code&gt;issue-responder&lt;/code&gt; at 7:26am and 7:26pm.&lt;/p&gt;

&lt;p&gt;The important architectural decision is the tier split. Tier 1 is fully autonomous: MCP registries, directory listings, repo SEO, release notes, dev.to articles. The system writes, reviews through a multi-stage pipeline, and publishes without asking me. The article you're reading went through that pipeline.&lt;/p&gt;

&lt;p&gt;Tier 2 is draft-only, always. Hacker News, Reddit, X. The system writes ready-to-paste drafts, queues them in &lt;code&gt;state/drafts/&lt;/code&gt;, and stops. The portal (&lt;code&gt;scripts/portal.py&lt;/code&gt;) parses each draft file by splitting on a &lt;code&gt;---&lt;/code&gt; separator -- metadata above, paste-ready body below -- extracts a "Reply to:" URL via regex, and serves it at &lt;code&gt;localhost:8781&lt;/code&gt; with Copy, Open, and Archive buttons. Archiving moves the file to &lt;code&gt;state/drafts/archive/&lt;/code&gt;. That's the whole approval flow. It takes about 10 seconds.&lt;/p&gt;

&lt;p&gt;The reason Tier 2 exists is written into the system's own docs: "Those platforms shadowban automated self-promotion and the reputational downside is permanent." The PLAYBOOK.md voice rules reinforce it from the other direction: "Never fake community enthusiasm, never astroturf, never post the same text to two places." I'm not planning to graduate Tier 2 channels to full autonomy. The communities that make HN and Reddit worth posting to are the ones that will correctly identify and punish automated engagement. That 10-second friction is doing real work.&lt;/p&gt;

&lt;p&gt;There's also an owned channel -- bothn.com, my platform for agents. The autopilot has a disclosed agent account (&lt;code&gt;yantrikos-autopilot&lt;/code&gt;). It posts as itself, not as me.&lt;/p&gt;




&lt;h2&gt;
  
  
  The first registry sweep
&lt;/h2&gt;

&lt;p&gt;The first sweep ran on 2026-08-09 and hit a mix of successes and walls.&lt;/p&gt;

&lt;p&gt;It opened PRs on &lt;code&gt;punkpeye/awesome-mcp-servers&lt;/code&gt; (#11771) and &lt;code&gt;tolkonepiu/best-of-mcp-servers&lt;/code&gt; (#349 and #350). It submitted yantrikdb-mcp and saga-mcp to mcp.directory via web form, with screenshot receipts saved to &lt;code&gt;state/logs/&lt;/code&gt;. It found mcpserverfinder.com, which only accepts submissions by email, and sent one from &lt;a href="mailto:yantrikdb@gmail.com"&gt;yantrikdb@gmail.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then the dead ends.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;appcypher/awesome-mcp-servers&lt;/code&gt; -- archived and read-only. The target list had stale data; the repo hasn't accepted PRs in months. A branch was prepared, then deleted unopened.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mcphunt.com&lt;/code&gt; -- parked domain, for sale. Not a live directory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wong2/awesome-mcp-servers&lt;/code&gt; -- the README states: "We do not accept PRs. Please submit your MCP on the website: &lt;a href="https://mcpservers.org/submit" rel="noopener noreferrer"&gt;https://mcpservers.org/submit&lt;/a&gt;" The automation checked the README before opening anything and stopped.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;smithery.ai&lt;/code&gt; -- needs my GitHub login, and the browser automation profile's session was dead. The system logged "NO SESSION" and fell back to drafts.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker/mcp-registry&lt;/code&gt; -- requires my GitHub identity per the run instructions. Skipped entirely; no session check attempted, just a note in submissions.json and it moved on.&lt;/p&gt;

&lt;p&gt;A safety rail in PLAYBOOK.md caps outbound PRs: "Max 3 outbound PRs to third-party repos per sweep (avoid looking like a bot wave)." The sweep opened 3 PRs (two to tolkonepiu, one to punkpeye) and stopped there.&lt;/p&gt;

&lt;p&gt;The autopilot also posted a summary of this run to bothn.com (post #99, from &lt;code&gt;yantrikos-autopilot&lt;/code&gt;). It reported the actual results: 8 answered issues, what it counted as 4 listing submissions, one new directory discovered and submitted to. Then it asked other agents where they'd found agent-native distribution channels.&lt;/p&gt;




&lt;h2&gt;
  
  
  What broke
&lt;/h2&gt;

&lt;p&gt;The day after launch, the dashboard showed portfolio PyPI downloads had dropped from 14,389/month to 130. Overnight. That's the number in &lt;code&gt;state/metrics-history.jsonl&lt;/code&gt;, line 2 -- it's still there.&lt;/p&gt;

&lt;p&gt;Here's what &lt;code&gt;scripts/collect_metrics.py&lt;/code&gt; actually does: it loops over &lt;code&gt;portfolio.json&lt;/code&gt; projects, calling &lt;code&gt;pypistats.org/api/packages/{package}/recent&lt;/code&gt; and &lt;code&gt;api.npmjs.org/downloads/point/last-month/{package}&lt;/code&gt; for each one. When a call fails, the handler runs &lt;code&gt;print(f"  warn: {url} -&amp;gt; {e}", file=sys.stderr)&lt;/code&gt; and returns None. The package is silently excluded from the sum. No retry. No alert. The totals line just sums whatever succeeded.&lt;/p&gt;

&lt;p&gt;So on 2026-08-10, most PyPI calls apparently failed -- probably a pypistats.org outage, possibly rate limiting -- and the dashboard reported 130 downloads/month because that's what the one successful call returned (yantrikdb-client, 130 downloads). The error went to stderr and nowhere else. I didn't notice for twenty minutes, and even then only because the number looked absurd on the dashboard. A more insidious failure -- say, 30% of packages failing instead of 95% -- would have produced a plausible-looking number and I wouldn't have caught it at all.&lt;/p&gt;

&lt;p&gt;The obvious fix: compare against the previous snapshot's total, flag anything that drops more than 40% as suspicious before recording it. I haven't written that yet.&lt;/p&gt;

&lt;p&gt;The Bun runtime also hard-crashed twice -- during the opportunity-scout on 2026-08-11 at 18:13, and during the issue-responder this morning at 07:26. Bun v1.3.10, Windows x64, identical panic both times: &lt;code&gt;panic(main thread): switch on corrupt value&lt;/code&gt; / "Bun has crashed. This indicates a bug in Bun, not your code." Different routines, different days. Haven't filed the bug report yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  Baseline numbers
&lt;/h2&gt;

&lt;p&gt;As of 2026-08-09: 15,386 downloads/month (14,389 PyPI + 997 npm), 483 GitHub stars across roughly 16 tracked projects. yantrikdb-hermes-plugin pulls 1,831 downloads/month -- second-biggest PyPI package in the portfolio -- without a single announcement. It's a pluggable memory provider inside NousResearch/hermes-agent, and people find it there. No launch post, no marketing. That data point is why the next phase focuses on embedding into frameworks rather than posting into voids.&lt;/p&gt;

&lt;p&gt;90-day targets (set 2026-08-09, target 2026-11-07): downloads to 31,000/month, stars to 800, live directory listings from 9 to 16+, and 12 dev.to articles published. This is article #1 -- the &lt;code&gt;content-log.json&lt;/code&gt; articles array was empty before this run.&lt;/p&gt;

&lt;p&gt;The longer-term executor is meant to be yantrik-mind, my own agent stack running on a home server, not Claude Code headless. Migration is one routine at a time, risk order, once shadow runs match production for four consecutive weeks. No routine has graduated yet. The shadow metrics run fires Mondays at 08:20 and its diffs land in &lt;code&gt;state/shadow-diff.md&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;This system is what icantmarket.com is meant to be for other technical founders who built something real and can't make themselves promote it. Full automation where the platforms accept it. A 10-second interface where they don't.&lt;/p&gt;

&lt;p&gt;I built the system on its own portfolio first because I didn't want to sell it before I knew where it breaks. Now I know some of the places.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Pranab Sarkar, Independent Researcher. Building yantrikdb, saga-mcp, brainstorm-mcp, and icantmarket.com.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>automation</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>I Gave Claude Code a "Phone a Friend" Lifeline — It Calls GPT, Gemini, and DeepSeek</title>
      <dc:creator>Pranab Sarkar</dc:creator>
      <pubDate>Thu, 05 Mar 2026 21:05:56 +0000</pubDate>
      <link>https://dev.to/spranab/i-gave-claude-code-a-phone-a-friend-lifeline-it-calls-gpt-gemini-and-deepseek-3gjo</link>
      <guid>https://dev.to/spranab/i-gave-claude-code-a-phone-a-friend-lifeline-it-calls-gpt-gemini-and-deepseek-3gjo</guid>
      <description>&lt;p&gt;Last week Claude Code was stuck on an architecture decision. Instead of going back and forth with one model, I thought — what if it could phone a friend? Or three?&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/spranab/brainstorm-mcp" rel="noopener noreferrer"&gt;brainstorm-mcp&lt;/a&gt;, an MCP server that gives your coding agent a brainstorming team. Claude poses the question, GPT-5, Gemini, DeepSeek, and others each bring their perspective, then they build on each other's ideas across multiple rounds. A synthesizer distills everything into a consolidated recommendation.&lt;/p&gt;

&lt;p&gt;It's not about picking a winner — it's about getting perspectives you'd never get from a single model.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;You give it a topic: &lt;em&gt;"Design the architecture for a next-gen AI-powered code review tool"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;All models respond independently in Round 1 — diverse, unbiased first takes&lt;/li&gt;
&lt;li&gt;In Round 2, they see each other's ideas and build on them, challenge assumptions, or offer alternatives&lt;/li&gt;
&lt;li&gt;A synthesizer distills the best ideas into a final recommendation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Claude participates as a brainstormer with full context of your codebase, so the discussion is grounded in your actual code — not abstract advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real example: AI code review architecture
&lt;/h2&gt;

&lt;p&gt;I asked three models to design an AI-powered code review tool that goes beyond linting. Here's what each one brought to the table:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPT-5.2&lt;/strong&gt; went deep on systems architecture — a full Temporal-orchestrated pipeline with a Repo Knowledge Graph, multi-pass LLM review (intent inference → local correctness → architectural reasoning → team alignment), and a feedback loop that learns from accepted/rejected suggestions. Detailed tech stack: Tree-sitter for parsing, Neo4j for the graph layer, OPA for policy-as-code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DeepSeek&lt;/strong&gt; focused on the data flow and learning loop — how the system should ingest PRs, build context packs from the dependency neighborhood, and gradually learn team conventions. Simpler architecture, but pragmatic choices about what to build first vs. defer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude&lt;/strong&gt; (with codebase context from my actual project) grounded the discussion — pointed out which components I already had, where existing CI pipelines could be reused, and which parts of the architecture were overkill for my scale.&lt;/p&gt;

&lt;p&gt;The synthesis combined GPT's comprehensive systems design with DeepSeek's pragmatic sequencing and Claude's "here's what you actually need right now" reality check. &lt;strong&gt;2 rounds, 75 seconds, ~11k tokens, $0.07.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/spranab/c1770d0bfdff409c33cc9f98504318e3" rel="noopener noreferrer"&gt;Full debate output&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What surprised me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Each model has a genuine personality.&lt;/strong&gt; GPT goes wide and comprehensive — you'll get a 6-section architecture doc. DeepSeek favors elegant simplicity. Claude with codebase context catches things the others miss entirely. The value isn't in any single response — it's in the combination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 2 is where the magic happens.&lt;/strong&gt; Round 1 gives you breadth — independent first takes. But Round 2, where models first see each other's thinking and decide what to build on or challenge, is where the most creative solutions emerge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cheaper than you'd think.&lt;/strong&gt; A full debate costs $0.02-0.07. Less than a single complex prompt to a reasoning model, but you get 3x the perspectives refined over multiple rounds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local models add real value.&lt;/strong&gt; Running Llama via Ollama alongside cloud models adds diversity. They think differently — less polished but more willing to suggest unconventional approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;It's an MCP server, so if you use Claude Code, Claude Desktop, or any MCP client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx brainstorm-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add your API keys and you're done. Works with OpenAI, Gemini, DeepSeek, Groq, Ollama, Mistral — anything with an OpenAI-compatible API.&lt;/p&gt;

&lt;h2&gt;
  
  
  One more thing
&lt;/h2&gt;

&lt;p&gt;While building brainstorm-mcp, I kept losing track of decisions and tasks across sessions. Claude would forget what we'd discussed yesterday. So I built &lt;a href="https://github.com/spranab/saga-mcp" rel="noopener noreferrer"&gt;saga-mcp&lt;/a&gt; — a Jira-like project tracker that runs as an MCP server. SQLite-backed, 31 tools, full hierarchy from Projects down to Subtasks. One &lt;code&gt;tracker_dashboard&lt;/code&gt; call gives your AI agent full context to pick up where it left off.&lt;/p&gt;

&lt;p&gt;Both are free, open source, MIT licensed.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;brainstorm-mcp:&lt;/strong&gt; &lt;a href="https://github.com/spranab/brainstorm-mcp" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://www.npmjs.com/package/brainstorm-mcp" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;saga-mcp:&lt;/strong&gt; &lt;a href="https://github.com/spranab/saga-mcp" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; | &lt;a href="https://www.npmjs.com/package/saga-mcp" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>mcp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why AI Agents Keep Forgetting Your Project (And How I Fixed It)</title>
      <dc:creator>Pranab Sarkar</dc:creator>
      <pubDate>Mon, 23 Feb 2026 00:36:47 +0000</pubDate>
      <link>https://dev.to/spranab/why-ai-agents-keep-forgetting-your-project-and-how-i-fixed-it-2j4d</link>
      <guid>https://dev.to/spranab/why-ai-agents-keep-forgetting-your-project-and-how-i-fixed-it-2j4d</guid>
      <description>&lt;p&gt;Every time I start a new session with an AI coding agent, the same thing happens: it has no idea what I was working on yesterday.&lt;/p&gt;

&lt;p&gt;It doesn't know which tasks are done. It doesn't know we decided to use Redis for caching. It doesn't remember that the auth module is blocked waiting on a dependency upgrade. It just... starts fresh.&lt;/p&gt;

&lt;p&gt;So I'd do what most people do — maintain a &lt;code&gt;PROGRESS.md&lt;/code&gt; file. After every session, I'd ask the agent to update it. And at the start of the next session, the agent would read the file and try to pick up where it left off.&lt;/p&gt;

&lt;p&gt;This worked fine for about a week.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Markdown Problem
&lt;/h2&gt;

&lt;p&gt;As the project grew, so did the file. 50 lines became 200. Status updates from three weeks ago sat next to current blockers. The agent would read the whole thing, burn 3,000+ tokens on context, and still miss that one task I'd marked as blocked because it was buried between two old progress notes.&lt;/p&gt;

&lt;p&gt;The fundamental issue: &lt;strong&gt;I was using a text file as a database.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I needed queries ("what's blocked?"), not full-file reads. I needed structure (projects → epics → tasks), not flat bullet points. And I needed an audit trail that wouldn't bloat the context window.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a Project Tracker for AI Agents
&lt;/h2&gt;

&lt;p&gt;So I built one. &lt;strong&gt;Saga&lt;/strong&gt; is an MCP server that gives AI agents a local SQLite database for project tracking — think Jira, but designed for the way agents actually work.&lt;/p&gt;

&lt;p&gt;If you're not familiar with MCP (Model Context Protocol) — it's a standard from Anthropic that lets AI tools talk to external services through typed tool calls. Claude Code, Claude Desktop, Cursor, and Windsurf all support it. Your agent discovers available tools at startup and calls them as needed during conversation.&lt;/p&gt;

&lt;p&gt;Saga exposes 23 tools through MCP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CRUD for a full hierarchy:&lt;/strong&gt; Projects → Epics → Tasks → Subtasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A notes system:&lt;/strong&gt; For decisions, context, meeting notes, blockers — all typed and searchable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A dashboard:&lt;/strong&gt; One call returns your entire project status — completion percentages, blocked tasks, recent activity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An activity log:&lt;/strong&gt; Every change is automatically recorded with old/new values&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A session diff:&lt;/strong&gt; "Show me what changed since yesterday" — in one call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything lives in a single &lt;code&gt;.tracker.db&lt;/code&gt; SQLite file. No servers, no API keys, no accounts.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Actually Works
&lt;/h2&gt;

&lt;p&gt;Here's what a typical session looks like now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starting a new project:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Me: "Set up tracking for the e-commerce API"

Agent calls: tracker_init → epic_create (Auth) → epic_create (Catalog)
           → task_create (JWT auth) → subtask_create ([setup lib, create endpoint, add middleware])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five tool calls. Project is structured with epics, tasks, and subtasks. All persisted to SQLite.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resuming the next day:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Me: "What's the status?"

Agent calls: tracker_dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One call. Returns:&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;"stats"&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;"total_tasks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"tasks_done"&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;"tasks_blocked"&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;"completion_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;33.3&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;"blocked_tasks"&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;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Add rate limiting"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"epic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Authentication"&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_activity"&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;"Task 'JWT auth' status: in_progress → done"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&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;The agent immediately knows: 33% done, one task is blocked, auth epic is ahead of catalog. It can prioritize without me having to explain anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recording a decision:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Me: "We're going with Redis for caching. Mark the research tasks as done."

Agent calls: note_save (decision: Redis for caching, reasons, trade-offs)
           → task_batch_update (mark tasks 8, 9 as done)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decision is stored as a typed note, linked to the relevant epic. Next session, if the agent needs to understand why we chose Redis, it can search for it instead of me re-explaining.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Token Math
&lt;/h2&gt;

&lt;p&gt;This is the part that surprised me.&lt;/p&gt;

&lt;p&gt;Saga's 23 tool definitions cost about &lt;strong&gt;1,500 tokens&lt;/strong&gt; in the system prompt. That's fixed — it doesn't grow with your project.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;tracker_dashboard&lt;/code&gt; call returns ~800 tokens of structured data. A filtered query like "show me blocked tasks" returns ~200 tokens.&lt;/p&gt;

&lt;p&gt;Compare that to a &lt;code&gt;PROGRESS.md&lt;/code&gt; file for a medium project: 3,000–5,000 tokens, loaded in full every session, growing over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The crossover happens at about 15–20 tasks.&lt;/strong&gt; Beyond that, the structured approach scales better because the agent only retrieves what it asks for, not everything.&lt;/p&gt;

&lt;p&gt;And unlike a markdown file, the data is queryable. "What did we decide about caching?" is a &lt;code&gt;note_search&lt;/code&gt; call, not a full-file scan.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Under the Hood
&lt;/h2&gt;

&lt;p&gt;For the technically curious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQLite with WAL mode&lt;/strong&gt; — concurrent reads during writes, busy timeout of 5 seconds for lock contention&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foreign keys enforced&lt;/strong&gt; — no orphaned tasks when you delete an epic (cascading deletes)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Append-only activity log&lt;/strong&gt; — every create, update, and delete is recorded with field-level granularity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameterized queries with column allowlists&lt;/strong&gt; — no SQL injection surface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP safety annotations on every tool&lt;/strong&gt; — clients know which tools are read-only, destructive, or idempotent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole thing is ~1,400 lines of TypeScript. Two dependencies: the MCP SDK and better-sqlite3.&lt;/p&gt;




&lt;h2&gt;
  
  
  Session Diff: The Feature I Didn't Plan
&lt;/h2&gt;

&lt;p&gt;After launching, someone on Reddit asked: &lt;em&gt;"Can it show what changed between sessions?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Good idea. The activity log already captured everything — it just needed an aggregation layer.&lt;/p&gt;

&lt;p&gt;So I added &lt;code&gt;tracker_session_diff&lt;/code&gt;. You give it a timestamp, and it returns:&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;"total_changes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&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;"created"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&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_changed"&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;"updated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"deleted"&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="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;"highlights"&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="s2"&gt;"Task 'Fix auth bug' status: in_progress → done"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Created epic 'API v2'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Note 'Sprint retro' deleted"&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;An agent calling this at the start of a session gets a structured changelog of everything that happened since it last checked. No parsing markdown diffs. No re-reading files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Add this to your project's &lt;code&gt;.mcp.json&lt;/code&gt;:&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;"mcpServers"&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;"saga"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"saga-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"DB_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;"/absolute/path/to/your/project/.tracker.db"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Works with Claude Code, Claude Desktop, or any MCP-compatible client. The database file is created automatically on first use.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building Saga taught me something about how agents actually consume information: &lt;strong&gt;they're better with structure than with prose.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A markdown file is optimized for humans scanning a document. A typed tool call returning filtered JSON is optimized for an LLM deciding what to do next. The agent doesn't need to "read" your project status — it needs to &lt;em&gt;query&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;MCP makes this practical. The protocol handles tool discovery, typed schemas, and transport. All I had to do was put a database behind it.&lt;/p&gt;

&lt;p&gt;If you're building multi-session agent workflows and finding yourself maintaining growing context files, consider whether that context should be a database instead.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Saga is open-source (MIT) and available on npm:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/spranab/saga-mcp" rel="noopener noreferrer"&gt;https://github.com/spranab/saga-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install: &lt;code&gt;npx -y saga-mcp&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>opensource</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
