<?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: Geetansh Vikram</title>
    <description>The latest articles on DEV Community by Geetansh Vikram (@geetansh_vikram_836d7f761).</description>
    <link>https://dev.to/geetansh_vikram_836d7f761</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%2F3960431%2F6fd3b3d4-ae10-4d6d-b108-6765a2ff5d5d.png</url>
      <title>DEV Community: Geetansh Vikram</title>
      <link>https://dev.to/geetansh_vikram_836d7f761</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geetansh_vikram_836d7f761"/>
    <language>en</language>
    <item>
      <title>I Had Never Heard of Cognee. Then I Spent 5 Days Breaking It Wide Open.</title>
      <dc:creator>Geetansh Vikram</dc:creator>
      <pubDate>Sun, 05 Jul 2026 18:00:49 +0000</pubDate>
      <link>https://dev.to/geetansh_vikram_836d7f761/i-had-never-heard-of-cognee-then-i-spent-5-days-breaking-it-wide-open-4j0j</link>
      <guid>https://dev.to/geetansh_vikram_836d7f761/i-had-never-heard-of-cognee-then-i-spent-5-days-breaking-it-wide-open-4j0j</guid>
      <description>&lt;p&gt;&lt;em&gt;By Geetansh Vikram | WeMakeDevs × Cognee Hackathon&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎥 Watch the full video demo here:&lt;/strong&gt; &lt;a href="https://youtu.be/FW6hriWAz40?si=oAQuVVhegkSAwJ4F" rel="noopener noreferrer"&gt;ContextRot-Bench Demo on YouTube&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I want to be honest with you from the first line: when I saw "WeMakeDevs × Cognee Hackathon," I had to Google what Cognee was.&lt;/p&gt;

&lt;p&gt;I'm a third-year CSE student at NIT Silchar. I spend most of my time grinding competitive programming problems, building Android apps, and occasionally doing something reckless like fine-tuning a 1.5B parameter RL model for a hackathon. I knew what vector stores were. I knew what knowledge graphs were. But "memory layer for AI agents"? I read the landing page three times before it clicked.&lt;/p&gt;

&lt;p&gt;And then it &lt;em&gt;really&lt;/em&gt; clicked. And I couldn't stop.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Moment I Got Hooked
&lt;/h2&gt;

&lt;p&gt;The hackathon description had this line that stuck with me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Your AI wakes up every morning with no memory of last night."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm a CP guy. I think in test cases. And immediately I started thinking: what's the &lt;em&gt;adversarial&lt;/em&gt; test case for AI memory? Not "can the agent remember a fact" — that's the easy case. The hard case is: &lt;strong&gt;what happens when the agent has been told two different things about the same subject, and one of them is wrong now?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's context rot. And the more I read about it, the more I realized this is not a toy problem. This is the reason support bots quote outdated return policies. This is the reason coding assistants suggest deprecated APIs. This is why "AI memory" demos always show you adding facts but never show you what happens when facts &lt;em&gt;change&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I decided that's what I was going to build. Not another chatbot-with-memory demo. A proof — something with a number attached to it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learning Cognee From Zero
&lt;/h2&gt;

&lt;p&gt;I cloned the repo on day one and started reading.&lt;/p&gt;

&lt;p&gt;Cognee's public API is beautifully simple on the surface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cognee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cognee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cognify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# builds the knowledge graph
&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cognee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some question&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cognee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;improve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# enriches / resolves contradictions
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four functions. I thought: okay, this is going to be a quick weekend build.&lt;/p&gt;

&lt;p&gt;I was wrong in the best possible way.&lt;/p&gt;

&lt;p&gt;The first thing I learned is that Cognee is not just a vector store with a nice API wrapper. Under the hood it's running a hybrid store — LanceDB for vector embeddings, Kuzu for the graph database — and &lt;code&gt;cognify()&lt;/code&gt; is actually running LLM-based entity and relationship extraction to &lt;em&gt;build a real knowledge graph&lt;/em&gt; from your raw text. That's not a small thing. That means when you add "Alice lives in New York," Cognee doesn't just embed that sentence — it extracts &lt;code&gt;Alice&lt;/code&gt; as an entity, &lt;code&gt;lives in&lt;/code&gt; as a relationship, and &lt;code&gt;New York&lt;/code&gt; as a node, and stores those structural connections in the graph.&lt;/p&gt;

&lt;p&gt;That was the moment I realized this was going to be genuinely interesting to explore.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Assumption That Turned Into a Discovery
&lt;/h2&gt;

&lt;p&gt;My original plan was to build a benchmark: feed two pipelines the same stream of evolving facts (Alice lives in New York → then Chicago → then Seattle), ask them "where does Alice live now," and prove Cognee gives the right answer while a naive vector store hallucinates across all three cities.&lt;/p&gt;

&lt;p&gt;For Cognee's pipeline, I planned to use &lt;code&gt;improve()&lt;/code&gt; — the function the docs describe as "run post-ingestion enrichment, prune stale nodes, and adapt weights based on user feedback." Perfect. That would handle the contradiction resolution.&lt;/p&gt;

&lt;p&gt;So I built a verification script. I ingested a supersession fact. I called &lt;code&gt;improve()&lt;/code&gt;. Then I dumped the raw graph and counted the nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stale "New York" node was still there. The count had gone up, not down.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I stared at this for a while. Then I dug into Cognee's source code.&lt;/p&gt;

&lt;p&gt;What &lt;code&gt;improve()&lt;/code&gt; actually does — and this is fascinating once you understand it — is &lt;em&gt;LLM-side reconciliation&lt;/em&gt;. It adds resolution edges and enriches the graph with new context. When you query later, the LLM can &lt;em&gt;reason&lt;/em&gt; its way to the correct answer by reading the contradiction metadata. In a lot of cases, this works fine. The LLM is smart enough to figure out that "Seattle supersedes Chicago supersedes New York."&lt;/p&gt;

&lt;p&gt;But that's not the same as physical deletion. The stale node is still there. If you retrieve a context window with all three locations in it, you're trusting the LLM to resolve the contradiction every single time at query cost. And sometimes it doesn't — I could show that empirically with my naive pipeline, which was doing the same kind of LLM-at-query-time resolution and getting it wrong 75% of the time.&lt;/p&gt;

&lt;p&gt;So I built the missing piece myself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the Deep-Pruning Layer
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most proud of.&lt;/p&gt;

&lt;p&gt;Cognee exposes its underlying graph engine and vector engine as importable clients:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cognee.infrastructure.databases.graph.get_graph_engine&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_graph_engine&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;cognee.infrastructure.databases.vector.get_vector_engine&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_vector_engine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used these to build a custom pruning step that runs after every &lt;code&gt;cognify()&lt;/code&gt; call when a new fact supersedes an old one. The logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Query the Kuzu graph for any &lt;code&gt;Fact&lt;/code&gt; node where &lt;code&gt;subject&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; match the superseded values&lt;/li&gt;
&lt;li&gt;Delete that node from the graph&lt;/li&gt;
&lt;li&gt;Find all associated vector chunks across every LanceDB table (DocumentChunk, TextSummary, EdgeType) using the node ID&lt;/li&gt;
&lt;li&gt;Delete each chunk individually&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two stores, one atomic operation, zero stale data.&lt;/p&gt;

&lt;p&gt;Along the way I found another silent failure: if you install &lt;code&gt;fastembed&lt;/code&gt; as a standalone package but don't install &lt;code&gt;cognee[fastembed]&lt;/code&gt; (the plugin wrapper), Cognee silently falls back to building the graph without generating any vector embeddings at all. No error, no warning you'd notice, just an empty vector store. That cost me an afternoon and is now documented in the README.&lt;/p&gt;

&lt;p&gt;I also found that Cognee's LLM extraction sometimes rephrases predicates — "lives in" becomes "resides in" or "location" — which would break naive exact-string matching on the predicate field. So instead of matching by predicate, I match by subject + the specific superseded value. That combination is unique enough to identify the stale node reliably, regardless of how the LLM phrased the relationship during extraction.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Benchmark Actually Shows
&lt;/h2&gt;

&lt;p&gt;I built 15 synthetic fact-stream scenarios: job application statuses, user locations, subscription plans, favorite programming languages, flight statuses — domains where facts naturally evolve and contradict each other. Each scenario has a ground truth answer (what's true &lt;em&gt;right now&lt;/em&gt;) and a set of stale values that should not appear in any answer.&lt;/p&gt;

&lt;p&gt;The results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pipeline&lt;/th&gt;
&lt;th&gt;Accuracy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Naive Vector Store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cognee + Deep-Pruning Layer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But the number I find more interesting is from the adversarial test. I ran three edge cases specifically designed to stress-test the system:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1 (Paraphrased query):&lt;/strong&gt; "What city is Alice currently residing in?" instead of "Where does Alice live?"&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Naive: &lt;em&gt;"There are multiple cities listed (New York, Seattle, Chicago), but only one can be current. The context does not specify which is current."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Cognee: &lt;em&gt;"Seattle."&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Case 2 (Stable fact):&lt;/strong&gt; "What is Alice's favorite color?" — a fact that was never updated&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Naive: "Blue" ✓&lt;/li&gt;
&lt;li&gt;Cognee: "Blue." ✓&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both pipelines get stable facts right. The failure is specifically on contradicted facts. That rules out "Cognee just got lucky" as an explanation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 3 (Recency bias):&lt;/strong&gt; "Where did Alice move to in 2025?" — phrased to give a recency-biased naive pipeline its best chance&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Naive: &lt;em&gt;"There is no information about Alice moving in 2025. The context only provides multiple current locations."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Cognee: &lt;em&gt;"Seattle."&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The naive pipeline couldn't resolve this even with a year hint. Because the raw vector chunks don't have meaningful chronological structure — they're just text — there was no signal to prefer Seattle over Chicago over New York. Cognee's graph, with the stale nodes physically absent, had only one answer available.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Open Source Part — Which Honestly Means a Lot to Me
&lt;/h2&gt;

&lt;p&gt;I've been doing competitive programming for two years. I've built Android apps. I've submitted to hackathons. But I had never actually contributed to an open-source project before this hackathon.&lt;/p&gt;

&lt;p&gt;That changed this week.&lt;/p&gt;

&lt;p&gt;While building ContextRot Bench, I spent so much time reading Cognee's migration source code — the &lt;code&gt;GraphitiSource&lt;/code&gt;, &lt;code&gt;Mem0Source&lt;/code&gt;, &lt;code&gt;ZepSource&lt;/code&gt; classes, the COGX memory standard — that I started to actually understand the codebase. Not just the high-level API, but the internals. How &lt;code&gt;import_source.py&lt;/code&gt; orchestrates the migration. How &lt;code&gt;COGXMemory&lt;/code&gt; vs &lt;code&gt;COGXFact&lt;/code&gt; vs &lt;code&gt;COGXEntity&lt;/code&gt; map to different kinds of knowledge.&lt;/p&gt;

&lt;p&gt;When I saw open issues asking for migration tutorials — "Tutorial: Migrate from Graphiti to Cognee," "Tutorial: Migrate from mem0 to Cognee" — I realized I was probably one of the few people outside the core team who had actually read those source files this week.&lt;/p&gt;

&lt;p&gt;So I went and claimed those issues. I have officially &lt;strong&gt;submitted two Pull Requests&lt;/strong&gt; to the main &lt;code&gt;topoteretes/cognee&lt;/code&gt; repository for these migrations, and they are currently under review by the core team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/topoteretes/cognee/pull/3798" rel="noopener noreferrer"&gt;Pull Request: Graphiti Migration Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/topoteretes/cognee/pull/3847" rel="noopener noreferrer"&gt;Pull Request: Mem0 Migration Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing code that will live in a public repository and help other developers — that's different from a hackathon project that only a few judges see. That's something that persists. That compounds. Someone six months from now who's trying to migrate their Graphiti knowledge graph into Cognee might run my tutorial script and it'll just work, and they'll never know a third-year student from NIT Silchar wrote it during a five-day hackathon.&lt;/p&gt;

&lt;p&gt;That thought is genuinely exciting to me in a way that's hard to articulate.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Tell Someone Starting With Cognee
&lt;/h2&gt;

&lt;p&gt;A few things I wish I'd known on day one:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Install &lt;code&gt;cognee[fastembed]&lt;/code&gt;, not just &lt;code&gt;fastembed&lt;/code&gt;.&lt;/strong&gt; The plugin wrapper matters and the failure is silent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;improve()&lt;/code&gt; is smarter than deletion, not equivalent to it.&lt;/strong&gt; It adds resolution context; it doesn't remove stale data. Depending on your use case, that might be exactly what you want. For an adversarial benchmark, it wasn't enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The hybrid graph-vector architecture is the real story.&lt;/strong&gt; Most "AI memory" tools are just vector stores with a chat interface. Cognee builds an actual knowledge graph during ingestion — entities, relationships, structural connections — which means your queries can traverse semantic similarity &lt;em&gt;and&lt;/em&gt; graph topology. That's a fundamentally different capability, not a marketing distinction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Go one level below the public API.&lt;/strong&gt; &lt;code&gt;get_graph_engine()&lt;/code&gt; and &lt;code&gt;get_vector_engine()&lt;/code&gt; let you inspect and manipulate the stores directly. That's where the interesting engineering lives.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Five days ago I didn't know what Cognee was.&lt;/p&gt;

&lt;p&gt;Now I've built a benchmark that proves one of its documented failure modes, engineered a custom pruning layer that fixes it, found and documented two bugs in the process, and submitted tutorials back to the open-source repo.&lt;/p&gt;

&lt;p&gt;I don't know if ContextRot Bench will win anything. But I know I understand AI memory systems in a way I didn't before, and I have open-source contributions on my GitHub that I'm genuinely proud of.&lt;/p&gt;

&lt;p&gt;That feels like a good week.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ContextRot Bench is open source. The benchmark, the deep-pruning layer, and all verification scripts are available on GitHub: *&lt;/em&gt;&lt;a href="https://github.com/Geetansh-12/cognee_hackathon" rel="noopener noreferrer"&gt;Geetansh-12/cognee_hackathon&lt;/a&gt;*&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built for the WeMakeDevs × Cognee Hackathon.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Built a Relationship Intelligence CRM with Claude Code + Coral — Here's the Route</title>
      <dc:creator>Geetansh Vikram</dc:creator>
      <pubDate>Sat, 30 May 2026 19:55:51 +0000</pubDate>
      <link>https://dev.to/geetansh_vikram_836d7f761/i-built-a-relationship-intelligence-crm-with-claude-code-coral-heres-the-route-2bd4</link>
      <guid>https://dev.to/geetansh_vikram_836d7f761/i-built-a-relationship-intelligence-crm-with-claude-code-coral-heres-the-route-2bd4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://coral-hackaton.onrender.com" rel="noopener noreferrer"&gt;coral-hackaton.onrender.com&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/Geetansh-12/coral_hackaton" rel="noopener noreferrer"&gt;github.com/Geetansh-12/coral_hackaton&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most people don't lose touch with contacts because they don't care — they lose touch because relationship data is scattered across Gmail, Slack, LinkedIn, calendar invites, and community servers. I built &lt;strong&gt;Coral CRM&lt;/strong&gt; for the Pirates of the Coral-bean hackathon to show what happens when you stop treating those surfaces as separate apps and start treating them as &lt;strong&gt;one SQL graph&lt;/strong&gt; powered by &lt;a href="https://withcoral.com" rel="noopener noreferrer"&gt;Coral&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post is the reproducible route: problem → architecture → Coral capabilities → live demo → custom Discord source spec.&lt;/p&gt;


&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Relationship intelligence breaks when every channel owns a slice of context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gmail knows what you said&lt;/li&gt;
&lt;li&gt;Calendar knows when you meet&lt;/li&gt;
&lt;li&gt;Slack knows what happened in DMs&lt;/li&gt;
&lt;li&gt;LinkedIn knows job changes&lt;/li&gt;
&lt;li&gt;Discord knows community engagement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An AI agent can't recommend "reach out to Sarah before Thursday's meeting" if it only sees one inbox. You need a &lt;strong&gt;unified graph&lt;/strong&gt; the agent can query safely.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why Coral (not just MCP connectors)
&lt;/h2&gt;

&lt;p&gt;MCP connectors are great for tool calls. Coral adds something different: &lt;strong&gt;SQL over APIs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of writing bespoke fetch logic for every source, Coral exposes tables you can &lt;code&gt;JOIN&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;health_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;public_repos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;followers&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;contacts&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;github_username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;health_score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That query runs in the SQL Explorer of Coral CRM and returns live GitHub profile data joined against local contacts — proof that federated joins aren't vaporware.&lt;/p&gt;

&lt;p&gt;Coral also gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Catalog discovery&lt;/strong&gt; — &lt;code&gt;coral.tables&lt;/code&gt;, &lt;code&gt;coral.columns&lt;/code&gt;, &lt;code&gt;coral.inputs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache/freshness observability&lt;/strong&gt; — &lt;code&gt;coral.query_log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One auth/retry/pagination layer&lt;/strong&gt; for agent workloads&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Architecture in 60 seconds
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Landing / Dashboard / Explorer / AI Chat
              ↓
        Next.js API routes (/api/query, /api/chat, /api/brief)
              ↓
     Demo Mode (mock)  OR  Live Mode (SQLite + coral CLI)
              ↓
   contact_relationship_graph  ← 6 seeded sources + live GitHub/Discord
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Demo Mode&lt;/strong&gt; works with zero API keys — judges can click through immediately.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Live Mode&lt;/strong&gt; seeds SQLite locally and spawns the real &lt;code&gt;coral&lt;/code&gt; binary for federated queries.&lt;/p&gt;

&lt;p&gt;Tech stack: Next.js 14, TypeScript, Tailwind, Gemini (free tier) for AI, better-sqlite3, Coral CLI.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step-by-step: run it yourself
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Geetansh-12/coral_hackaton.git
&lt;span class="nb"&gt;cd &lt;/span&gt;coral_hackaton
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run seed   &lt;span class="c"&gt;# optional — seeds SQLite for live mode&lt;/span&gt;
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open &lt;strong&gt;&lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/strong&gt;. The app starts in Demo Mode with 34 realistic contacts.&lt;/p&gt;
&lt;h3&gt;
  
  
  Switch to Live Mode
&lt;/h3&gt;

&lt;p&gt;Copy &lt;code&gt;.env.local.example&lt;/code&gt; → &lt;code&gt;.env.local&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEMO_MODE=false
GEMINI_API_KEY=your_key
GITHUB_TOKEN=ghp_...
DISCORD_BOT_TOKEN=your_bot_token   # for the custom Discord source
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the Discord source spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;coral &lt;span class="nb"&gt;source &lt;/span&gt;lint ./sources/discord/manifest.yaml
coral &lt;span class="nb"&gt;source &lt;/span&gt;add &lt;span class="nt"&gt;--file&lt;/span&gt; ./sources/discord/manifest.yaml &lt;span class="nt"&gt;--interactive&lt;/span&gt;
coral &lt;span class="nb"&gt;source test &lt;/span&gt;discord
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Coral capabilities we demonstrate (7/7)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. SQL interface over multiple sources
&lt;/h3&gt;

&lt;p&gt;Six seeded tables in &lt;code&gt;sql/schema.sql&lt;/code&gt;: Gmail threads, Calendar events, Slack messages, LinkedIn activity, Twitter activity, Notion contacts.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Cross-source JOINs
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;contact_relationship_graph&lt;/code&gt; materialized view LEFT JOINs all six on email and computes a &lt;code&gt;health_score&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Catalog discovery
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql_reference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;freshness&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;coral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Parameter hints
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;parameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;coral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Cache &amp;amp; freshness
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;query_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sources_joined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache_hit_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;avg_ms&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;coral&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query_log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Real CLI execution
&lt;/h3&gt;

&lt;p&gt;In Live Mode, &lt;code&gt;/api/query&lt;/code&gt; spawns &lt;code&gt;coral sql --format json&lt;/code&gt; asynchronously — no blocking the Next.js event loop on slow API calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Pluggable source architecture
&lt;/h3&gt;

&lt;p&gt;Settings page shows connector diagnostics per source. We added a &lt;strong&gt;custom Discord source spec&lt;/strong&gt; (see below).&lt;/p&gt;




&lt;h2&gt;
  
  
  The judge demo flow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;/dashboard&lt;/code&gt; → click &lt;strong&gt;Judge Demo&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Show &lt;strong&gt;Agent Plan&lt;/strong&gt; and &lt;strong&gt;Coral Capability Cockpit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;SQL Explorer&lt;/strong&gt; → run the cross-source GitHub JOIN recipe&lt;/li&gt;
&lt;li&gt;Open a contact → generate a &lt;strong&gt;pre-meeting brief&lt;/strong&gt; → export it&lt;/li&gt;
&lt;li&gt;Ask the chat agent: &lt;em&gt;"What Coral capabilities does this demo use?"&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Screenshots are in &lt;code&gt;docs/screenshots/&lt;/code&gt; in the repo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building a custom Discord source spec (bounty track)
&lt;/h2&gt;

&lt;p&gt;Coral ships Gmail, GitHub, Slack, etc. — but &lt;strong&gt;Discord wasn't in the catalog&lt;/strong&gt;. For the hackathon "Chart New Waters" track, I wrote a YAML source spec that maps Discord REST API v10 endpoints to SQL tables.&lt;/p&gt;

&lt;p&gt;File: &lt;code&gt;sources/discord/manifest.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tables exposed:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SQL table&lt;/th&gt;
&lt;th&gt;Discord API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discord.current_user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /users/@me&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discord.guilds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /users/@me/guilds&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discord.channels&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /guilds/{guild_id}/channels&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discord.messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /channels/{channel_id}/messages&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;discord.members&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /guilds/{guild_id}/members&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Auth pattern:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HeaderAuth&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Authorization&lt;/span&gt;
      &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;template&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bot {{input.DISCORD_BOT_TOKEN}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nested JSON → SQL columns&lt;/strong&gt; using Coral's &lt;code&gt;__&lt;/code&gt; convention:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;author__username&lt;/span&gt;
  &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Validation workflow:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;coral &lt;span class="nb"&gt;source &lt;/span&gt;lint ./sources/discord/manifest.yaml
coral &lt;span class="nb"&gt;source &lt;/span&gt;add &lt;span class="nt"&gt;--file&lt;/span&gt; ./sources/discord/manifest.yaml
coral &lt;span class="nb"&gt;source test &lt;/span&gt;discord
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example CRM query once installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;author__username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;discord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;channel_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'YOUR_CHANNEL_ID'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full docs: &lt;code&gt;sources/discord/README.md&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Upstream PR target: &lt;code&gt;withcoral/coral&lt;/code&gt; → &lt;code&gt;sources/community/discord/&lt;/code&gt;&lt;/p&gt;




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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with one table.&lt;/strong&gt; Guilds first, then channels, then messages. Run &lt;code&gt;coral source test&lt;/code&gt; after each addition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nested fields need explicit &lt;code&gt;expr&lt;/code&gt;.&lt;/strong&gt; Don't assume &lt;code&gt;author__username&lt;/code&gt; auto-flattens — declare the path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filters in URL paths&lt;/strong&gt; use &lt;code&gt;{{filter.guild_id}}&lt;/code&gt; — same pattern as other community specs (OSV, dbt Cloud).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo + Live dual mode&lt;/strong&gt; was the right call for hackathon judges — zero friction to explore, real CLI when credentials exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker on Render&lt;/strong&gt; beats serverless for a 150MB Coral binary — one container, authentic live URL.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open upstream PR for the Discord source spec&lt;/li&gt;
&lt;li&gt;Join Discord messages into &lt;code&gt;contact_relationship_graph&lt;/code&gt; on username/nickname&lt;/li&gt;
&lt;li&gt;OAuth device flow for Gmail/Calendar in production&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live app:&lt;/strong&gt; &lt;a href="https://coral-hackaton.onrender.com" rel="noopener noreferrer"&gt;coral-hackaton.onrender.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/Geetansh-12/coral_hackaton" rel="noopener noreferrer"&gt;Geetansh-12/coral_hackaton&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coral docs:&lt;/strong&gt; &lt;a href="https://withcoral.com/docs" rel="noopener noreferrer"&gt;withcoral.com/docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom source guide:&lt;/strong&gt; &lt;a href="https://withcoral.com/docs/guides/write-a-custom-source" rel="noopener noreferrer"&gt;Write a custom source spec&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hackathon:&lt;/strong&gt; &lt;a href="https://wemakedevs.org/hackathons/coral" rel="noopener noreferrer"&gt;WeMakeDevs × Coral&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>coral</category>
      <category>ai</category>
      <category>discord</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
