<?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: Aditya Chavan</title>
    <description>The latest articles on DEV Community by Aditya Chavan (@aditya_chavan).</description>
    <link>https://dev.to/aditya_chavan</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%2F1142022%2F304793dd-ad7a-44f5-a9f4-126b66c2fa37.jpg</url>
      <title>DEV Community: Aditya Chavan</title>
      <link>https://dev.to/aditya_chavan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aditya_chavan"/>
    <language>en</language>
    <item>
      <title>The Dog Community: A Home for Dog Owners, Where the Resident Know-It-All Is a Golden Retriever Running on Gemini</title>
      <dc:creator>Aditya Chavan</dc:creator>
      <pubDate>Sun, 16 Aug 2026 08:43:26 +0000</pubDate>
      <link>https://dev.to/aditya_chavan/the-dog-community-a-home-for-dog-owners-where-the-resident-know-it-all-is-a-golden-retriever-446j</link>
      <guid>https://dev.to/aditya_chavan/the-dog-community-a-home-for-dog-owners-where-the-resident-know-it-all-is-a-golden-retriever-446j</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-08-13"&gt;Weekend Challenge: Dog Days Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;The Dog Community&lt;/strong&gt; — a home on the internet for people who own dogs, built&lt;br&gt;
around a member called &lt;strong&gt;Barkley&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Barkley is a golden retriever. He has a user row, a bcrypt password hash nobody&lt;br&gt;
holds, an avatar, a card in the community's dog rail alongside everyone else's&lt;br&gt;
pets, and a direct-message thread you can open like you'd open one with any&lt;br&gt;
other member. Nothing in the interface marks him out. There is no chat panel,&lt;br&gt;
no floating button in the corner, no "Ask AI" box. He is in the room, and he&lt;br&gt;
behaves like someone who is in the room — which is a very different design&lt;br&gt;
problem from putting a model behind a text field.&lt;/p&gt;

&lt;p&gt;I started from something I think is genuinely underserved. Dog owners have&lt;br&gt;
nowhere that is &lt;em&gt;theirs&lt;/em&gt;. They have general-purpose social networks where a&lt;br&gt;
photo of their dog competes with politics, and they have breed forums that&lt;br&gt;
feel like 2006. What they actually want is a place where the whole point is&lt;br&gt;
dogs: where you can post a picture of yours and people care, where you can ask&lt;br&gt;
why your four-month-old puppy has started shredding the sofa and get an answer&lt;br&gt;
from three people who have lived through it, where you can find the other&lt;br&gt;
owners near you and end up walking together on Sunday. Real friendships,&lt;br&gt;
real meetups, real trips — the kind of thing that starts because two people&lt;br&gt;
found out their dogs are the same breed and both terrible on a lead.&lt;/p&gt;

&lt;p&gt;So the app is built for that, not for chatting in the abstract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Three channels that already know what they're for.&lt;/strong&gt; &lt;code&gt;#general&lt;/code&gt;, where the
pack hangs out. &lt;code&gt;#puppy-training&lt;/code&gt; — chewed furniture, shared wisdom. And
&lt;code&gt;#breed-talk&lt;/code&gt;, whose topic line is literally &lt;em&gt;"Ask Barkley, he has opinions."&lt;/em&gt;
The community arrives with somewhere to go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The pack rail&lt;/strong&gt; — a running gallery of every dog in the community, down
the side of the app at all times. Each card is a photo, a name, a breed, and
the owner it belongs to. You are never talking to usernames. You are talking
to Priya, who owns Maple, who is a corgi. That single piece of context
changes the register of a whole conversation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Photos everywhere, with captions.&lt;/strong&gt; Pick an image, it uploads, it attaches
to your draft so you can say something about it, and it lands in every open
window. Channels and DMs both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct messages&lt;/strong&gt; between any two members, so the community can go private
when it needs to — swapping a vet's number, arranging to meet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breeds that nobody types.&lt;/strong&gt; You add your dog by giving a name and a photo.
The breed is worked out from the picture. There is no dropdown of 400 breeds
and no chance to get your own dog's breed wrong in front of everyone.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And running through all of it, Barkley.&lt;/p&gt;
&lt;h2&gt;
  
  
  Spotlight: Barkley
&lt;/h2&gt;

&lt;p&gt;He deserves his own section, because he is the reason this is a community and&lt;br&gt;
not a message board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;He greets every new dog personally, and by breed.&lt;/strong&gt; The moment you add your&lt;br&gt;
dog, Barkley sees the photo — the actual photo, not a description of it — and&lt;br&gt;
welcomes them into &lt;code&gt;#general&lt;/code&gt; by name, with something specific about that&lt;br&gt;
breed that shows he knows what he's talking about. A beagle gets told about&lt;br&gt;
its nose. A corgi gets told about the herding. It's the first thing that&lt;br&gt;
happens to a new member, and it lands in the main channel where everyone sees&lt;br&gt;
it, which means the new arrival gets a welcome from the room too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every single thing he says has a dog in it.&lt;/strong&gt; The persona is fixed: warm,&lt;br&gt;
enthusiastic, a bit smug about how much he knows, and every so often derailed&lt;br&gt;
by the fact that he is a dog. One to three sentences, plain text, no bullet&lt;br&gt;
points, no "As an AI." He never breaks character and he never explains what&lt;br&gt;
he is. The result is that a serious answer about crate training arrives with a&lt;br&gt;
joke about the crate, and the mood of the channel goes up rather than flat.&lt;br&gt;
That is not decoration — it is the difference between a member and a lookup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tag him and he answers immediately.&lt;/strong&gt; &lt;code&gt;@barkley&lt;/code&gt; anywhere, in any channel, in&lt;br&gt;
any DM, and he replies to what was just said. A typing indicator appears with&lt;br&gt;
his name on it while he thinks, exactly as it would for a person.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DM him and he's always there.&lt;/strong&gt; Open a direct message with Barkley and he&lt;br&gt;
answers &lt;em&gt;every&lt;/em&gt; message — no tagging, no prefix, no command. It's a private&lt;br&gt;
conversation with the one member who is always awake. This is where the&lt;br&gt;
embarrassing questions go, and where a new owner at 2am asks the thing they&lt;br&gt;
wouldn't ask the whole channel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;He interrupts you when it matters.&lt;/strong&gt; This is the part I care about most.&lt;br&gt;
Barkley watches for a set of things that genuinely hurt dogs — chocolate,&lt;br&gt;
grapes, raisins, xylitol, ibuprofen, onions — and if one of them shows up in a&lt;br&gt;
message, he cuts into the conversation &lt;strong&gt;uninvited&lt;/strong&gt;. Nobody tagged him.&lt;br&gt;
Nobody asked. Someone mentions giving the dog a bit of their chocolate brownie&lt;br&gt;
and Barkley is suddenly in the channel, alarmed, explaining theobromine in his&lt;br&gt;
own words. Every one of those substances is stored with the fact he must not&lt;br&gt;
get wrong, and that fact goes into the prompt — so the warning is written&lt;br&gt;
fresh in his voice every time, but the pharmacology underneath it is fixed and&lt;br&gt;
correct. It cannot drift, and it never reads like a canned string.&lt;/p&gt;

&lt;p&gt;He does the same thing to &lt;strong&gt;pictures&lt;/strong&gt;. Post an uncaptioned photo of a bowl of&lt;br&gt;
grapes with no text at all and he'll still warn you, because he looked at it.&lt;br&gt;
There is nothing in the words that could have triggered that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And — this is deliberate — he shuts up the rest of the time.&lt;/strong&gt; Plain&lt;br&gt;
conversation between members gets silence. He is not in your chat. He is in&lt;br&gt;
the room, and he speaks when he's spoken to, when a photo needs comment, or&lt;br&gt;
when something dangerous is on the table. A member who answers everything&lt;br&gt;
isn't a member; he's a search box wearing a face. Restraint is the whole&lt;br&gt;
design, and it's enforced in one function.&lt;/p&gt;

&lt;p&gt;The effect is that the community feels &lt;em&gt;hosted&lt;/em&gt;. Someone knowledgeable and&lt;br&gt;
good-natured is always present, welcomes every arrival, keeps the mood up, and&lt;br&gt;
steps in when a dog might get hurt.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;A full walkthrough of the community — adding a dog and watching a breed appear&lt;br&gt;
that nobody typed, Barkley welcoming it by name, an unprompted interruption&lt;br&gt;
about chocolate, a mention, and a direct message:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/byn048W1M9Q"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The community, and the pack rail:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp8i6d1cbdett83bzu6tf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp8i6d1cbdett83bzu6tf.png" alt="The #general channel, with the dog rail on the right" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#breed-talk — where Barkley does most of the talking:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz7dj9oig4llpifp2hs2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz7dj9oig4llpifp2hs2r.png" alt="#breed-talk" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A direct message with him — no tag needed, he answers everything:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89o9vu6bw2a312pd0wrh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89o9vu6bw2a312pd0wrh.png" alt="A direct message with Barkley" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And a photo shared in a DM:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1atzyp8pxd6sv6rzln8i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1atzyp8pxd6sv6rzln8i.png" alt="Sharing a photo in a direct message" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every word Barkley says in those screenshots was generated by the model&lt;br&gt;
against the live app. None of it is written by me.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/git-aditya-star" rel="noopener noreferrer"&gt;
        git-aditya-star
      &lt;/a&gt; / &lt;a href="https://github.com/git-aditya-star/the-dog-community" rel="noopener noreferrer"&gt;
        the-dog-community
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;The Dog Community&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A small chat community for dog owners, with one unusual member: &lt;strong&gt;Barkley&lt;/strong&gt;
a golden retriever who lives in the database as a real user row and knows
every dog in the room.&lt;/p&gt;
&lt;p&gt;Upload a photo of your dog and the app works out the breed for you. Barkley
notices the new arrival, welcomes it by name with something breed-specific
and quietly interrupts if anyone mentions feeding their dog chocolate.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/git-aditya-star/the-dog-community/docs/02-general.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fgit-aditya-star%2Fthe-dog-community%2FHEAD%2Fdocs%2F02-general.png" alt="The #general channel, with the dog rail on the right"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What it does&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Photos everywhere&lt;/strong&gt; — pick an image and it uploads, attaches to the draft
so it can carry a caption, and lands in every open window over the same
socket as text. Channels and DMs both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Channels and DMs over one WebSocket&lt;/strong&gt; — send and delivery share a single
connection, so a message is in both windows before the sender's spinner
would have finished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Photo in, breed out&lt;/strong&gt; — adding a dog runs one vision…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/git-aditya-star/the-dog-community" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;FastAPI, React with Vite, PostgreSQL, one WebSocket, and Gemini through Google&lt;br&gt;
AI Studio doing both the seeing and the speaking.&lt;/p&gt;

&lt;p&gt;Four decisions I'd defend in a review:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Barkley is a row, not a special case.&lt;/strong&gt; He is seeded on boot as a &lt;code&gt;users&lt;/code&gt;&lt;br&gt;
row with &lt;code&gt;is_bot = true&lt;/code&gt; and a &lt;code&gt;dogs&lt;/code&gt; row of his own. Every consequence falls&lt;br&gt;
out for free: he appears in the member list, so he appears in the DM picker,&lt;br&gt;
so DMing him works without a line of code written for it. His card in the pack&lt;br&gt;
rail is a real query result, not a hardcoded component. The only thing in the&lt;br&gt;
entire frontend that knows he's different is the avatar, which keeps his rust&lt;br&gt;
ring — and rust was deliberately held back from the palette of hashed tints&lt;br&gt;
that everyone else's initials get, so no member can accidentally look like&lt;br&gt;
staff. If you deleted his row, he'd simply be gone, and nothing would break.&lt;br&gt;
That property is the whole point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Direct messages live on the channel row, and that was the interesting call.&lt;/strong&gt;&lt;br&gt;
There is no &lt;code&gt;channel_members&lt;/code&gt; join table. Public channels and DMs are the same&lt;br&gt;
&lt;code&gt;channels&lt;/code&gt; table; a DM stores its two participants in &lt;code&gt;user_a_id&lt;/code&gt; /&lt;br&gt;
&lt;code&gt;user_b_id&lt;/code&gt;, always lower id first, with a partial unique index on the pair.&lt;br&gt;
Two kinds of membership are not the same problem — a public channel has an&lt;br&gt;
open-ended set of people and a DM has exactly two, forever — and modelling them&lt;br&gt;
identically costs you a join on every message load plus a permanent class of&lt;br&gt;
duplicate-conversation bugs. With the ordering constraint, "Maya and Dev&lt;br&gt;
already have a thread" is enforced by the database, not by code that has to&lt;br&gt;
remember to check. A member's entire channel list, public rooms and private&lt;br&gt;
threads together, is one query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One WebSocket, both directions.&lt;/strong&gt; The client sends a message over the same&lt;br&gt;
connection that delivers it. No POST-then-wait-for-the-echo, which means no&lt;br&gt;
optimistic update to reconcile and no reordering to get wrong. Fan-out is a&lt;br&gt;
dictionary of live connections: a public message goes to everyone connected, a&lt;br&gt;
DM to two user ids. Barkley's reply travels the identical path — it is just&lt;br&gt;
another message row, delivered the same way, which is why he needs no client&lt;br&gt;
support at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Barkley's trigger check is where the character actually lives.&lt;/strong&gt; Every&lt;br&gt;
message that arrives runs through one function that decides whether he has&lt;br&gt;
anything to say. A mention of &lt;code&gt;@barkley&lt;/code&gt;. A DM he is a participant of. A&lt;br&gt;
dangerous word matched on a word boundary — so "chocolate" fires and&lt;br&gt;
"chocolatier" doesn't. Anything else returns early and he stays quiet. A guard&lt;br&gt;
on his own user id means he can never answer himself, which is the failure mode&lt;br&gt;
that turns this kind of feature into an infinite loop at 3am. The mention and&lt;br&gt;
danger branches compose rather than firing twice: tag him about a chocolate&lt;br&gt;
brownie and you get one message that answers you &lt;em&gt;and&lt;/em&gt; warns you.&lt;/p&gt;

&lt;p&gt;His context is deliberately not a vector store. It's the last ten messages in&lt;br&gt;
the channel, plus a &lt;code&gt;SELECT&lt;/code&gt; over every dog in the community — name, breed,&lt;br&gt;
owner, and the description written when the photo was first seen — pasted into&lt;br&gt;
the prompt. The model already knows what a beagle is. There is nothing to&lt;br&gt;
retrieve. What it doesn't know is that Maple belongs to Priya and is a corgi,&lt;br&gt;
so that's what I give it, and that's why his welcomes and his answers name real&lt;br&gt;
dogs in the room.&lt;/p&gt;

&lt;p&gt;He dispatches as a detached task after the message has already been fanned out,&lt;br&gt;
so nobody waits on him. While he thinks, a typing frame goes to the same&lt;br&gt;
recipients — and the &lt;em&gt;off&lt;/em&gt; frame on failure is the detail I'm proudest of.&lt;br&gt;
If the model returns nothing, the indicator is explicitly cleared. Without&lt;br&gt;
that, one dead provider leaves "Barkley is thinking…" on screen forever, and&lt;br&gt;
the app looks broken rather than quiet. I verified it by booting a second&lt;br&gt;
backend pointed at a model id that doesn't exist: typing on, typing off 0.6&lt;br&gt;
seconds later, socket alive, no message row, no user-visible damage.&lt;/p&gt;

&lt;p&gt;The model layer never raises. Timeout, 404, malformed JSON, no provider at all&lt;br&gt;
— every failure returns empty. A dead model means a dog that arrives without a&lt;br&gt;
breed and a Barkley who is having a quiet day. It never means a failed&lt;br&gt;
registration or a broken socket. Silence is a first-class return value here,&lt;br&gt;
which felt right for a character whose defining trait is knowing when not to&lt;br&gt;
speak.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Google AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The entire application runs on &lt;strong&gt;Gemini via Google AI Studio&lt;/strong&gt; —&lt;br&gt;
&lt;code&gt;gemini-3.5-flash-lite&lt;/code&gt;, called directly over the REST API. One model, and I&lt;br&gt;
want to be specific about the two structurally different jobs it does, because&lt;br&gt;
they have opposite performance profiles and I designed around that difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identity — seeing a dog once.&lt;/strong&gt; When you add your dog, its photo goes to&lt;br&gt;
Gemini with a prompt that asks for JSON: the most likely breed, and two or&lt;br&gt;
three warm sentences about how this particular dog looks and comes across. It&lt;br&gt;
comes back in about 2.3 seconds. That number is what let me run it&lt;br&gt;
&lt;em&gt;synchronously inside the request&lt;/em&gt; — no background job, no socket frame, no&lt;br&gt;
"breed pending" state in the rail. You submit the form, and by the time the&lt;br&gt;
modal closes your dog has a breed nobody typed. This result is identity: it&lt;br&gt;
doesn't change, so it's written to the dog row and read back as text forever&lt;br&gt;
after. It's also what gives Barkley his memory of the whole pack, at zero&lt;br&gt;
further cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Looking — seeing what's happening now.&lt;/strong&gt; This is a separate job and it runs&lt;br&gt;
live. On any turn where there's a photo in Barkley's context window, he reads&lt;br&gt;
that image and sends it with his prompt. Not a cached description — the actual&lt;br&gt;
bytes, every time. It has to work that way: a question about &lt;em&gt;that&lt;/em&gt; picture,&lt;br&gt;
right now, has nothing cacheable about it. Someone posts their dog looking&lt;br&gt;
guilty next to a destroyed cushion and asks what breed does this; someone posts&lt;br&gt;
a bowl of grapes with no caption at all. Measured, that's 1.8 seconds with an&lt;br&gt;
image against 1.0 without — Gemini's multimodal latency is low enough that&lt;br&gt;
looking at a photo is something a conversation can afford to do routinely&lt;br&gt;
rather than as a special mode.&lt;/p&gt;

&lt;p&gt;The cached identity pass is what makes the live looking affordable, not what&lt;br&gt;
replaces it. He knows every dog in the community from text, so the image&lt;br&gt;
budget is spent entirely on what's in front of him.&lt;/p&gt;

&lt;p&gt;Every line Barkley speaks is generated — the welcomes, the breed answers, the&lt;br&gt;
DMs, and the danger warnings. The safety facts are pinned in the prompt so&lt;br&gt;
they can't drift; the voice around them is Gemini's, fresh each time. That's&lt;br&gt;
why he can warn you about theobromine twice in one week and not say it the&lt;br&gt;
same way once.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Barkley is a good boy. He would like you to know that chocolate is not for&lt;br&gt;
dogs, and he would like to tell you again in a minute.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
    </item>
    <item>
      <title>Building a Self-Managing Notes System for Claude Code</title>
      <dc:creator>Aditya Chavan</dc:creator>
      <pubDate>Sat, 04 Jul 2026 14:38:41 +0000</pubDate>
      <link>https://dev.to/aditya_chavan/building-a-self-managing-notes-system-for-claude-code-4al8</link>
      <guid>https://dev.to/aditya_chavan/building-a-self-managing-notes-system-for-claude-code-4al8</guid>
      <description>&lt;p&gt;I got tired of Claude losing context every time a session ended, so I built a plugin that gives it a persistent, self-maintained notebook for each project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude keeps its own notes on the project as it works (architecture decisions, gotchas, TODOs, etc.)&lt;/li&gt;
&lt;li&gt;Notes persist across sessions — no more re-explaining the same context every time you start a new chat&lt;/li&gt;
&lt;li&gt;Hooks into the Claude Code lifecycle to keep notes fresh and relevant automatically&lt;/li&gt;
&lt;li&gt;Lightweight, no external dependencies beyond Node&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/git-aditya-star/project-notes" rel="noopener noreferrer"&gt;https://github.com/git-aditya-star/project-notes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explainer page:&lt;/strong&gt; &lt;a href="https://git-aditya-star.github.io/project-notes/project-notes-explained.html" rel="noopener noreferrer"&gt;https://git-aditya-star.github.io/project-notes/project-notes-explained.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love feedback — especially if anyone tries it on a large/messy codebase and something breaks, or if the note-freshness logic feels off. Also open to feature requests.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Full disclosure: I'm the author, sharing because I think others might find it useful.)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>opensource</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to implement case insensitivity in PostgreSQL queries</title>
      <dc:creator>Aditya Chavan</dc:creator>
      <pubDate>Thu, 04 Jan 2024 15:54:09 +0000</pubDate>
      <link>https://dev.to/aditya_chavan/how-to-implement-case-insensitivity-in-postgresql-queries-2icj</link>
      <guid>https://dev.to/aditya_chavan/how-to-implement-case-insensitivity-in-postgresql-queries-2icj</guid>
      <description>&lt;p&gt;🚀 Must-read for PostgreSQL enthusiasts!&lt;br&gt;
&lt;a href="https://link.medium.com/8LwsRFaz5Fb" rel="noopener noreferrer"&gt;https://link.medium.com/8LwsRFaz5Fb&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>techtips</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to make postgresql queries case insensitive</title>
      <dc:creator>Aditya Chavan</dc:creator>
      <pubDate>Sat, 19 Aug 2023 15:58:54 +0000</pubDate>
      <link>https://dev.to/aditya_chavan/how-to-make-postgresql-queries-case-insensitive-lpl</link>
      <guid>https://dev.to/aditya_chavan/how-to-make-postgresql-queries-case-insensitive-lpl</guid>
      <description>&lt;p&gt;Scenarios when we want postgresql to act as case insensitive. We can convert columns to uppercase or lowercase using upper()/lower() to make comparisons case insensitive.&lt;br&gt;
Scenarios where we would need to make such changes -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where conditions&lt;/li&gt;
&lt;li&gt;Join conditions&lt;/li&gt;
&lt;li&gt;group by — here if put lower/upper on column then that column in select statement should have either lower/upper or other aggregate like max.&lt;/li&gt;
&lt;li&gt;order by columns&lt;/li&gt;
&lt;li&gt;having conditions&lt;/li&gt;
&lt;li&gt;ilike to make like case insensitive&lt;/li&gt;
&lt;li&gt;instead of select distinct lower(col1) from… use select distinct on (lower(col1)) col1 from… as it won’t convert value to lower case while being case insensitive.&lt;/li&gt;
&lt;li&gt;unique constraints are case sensitive. if using on conflict clause in insert queries then it would be case sensitive. the only solution is to remove the conflict and add extra where condition of “AND NOT EXISTS ( select 1 from … where unique constriants columns wrapped by lower())”. If on conflict () update then add update query before the insert query with extra conditions of lower() wrapped the unique constraint columns and “NOT EXISTS …” in the afterward insert query.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>postgres</category>
    </item>
    <item>
      <title>Changes in procedures/functions while migrating from MySQL to PostgreSQL</title>
      <dc:creator>Aditya Chavan</dc:creator>
      <pubDate>Sat, 19 Aug 2023 15:42:45 +0000</pubDate>
      <link>https://dev.to/aditya_chavan/changes-in-proceduresfunctions-while-migrating-from-mysql-to-postgresql-2ad9</link>
      <guid>https://dev.to/aditya_chavan/changes-in-proceduresfunctions-while-migrating-from-mysql-to-postgresql-2ad9</guid>
      <description>&lt;p&gt;So, I have listed some of the changes which are needed when migrating our procedures or functions in MySQL to PostgreSQL.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“ ( double quote ) in postgresql don’t signify text but are used to name case sensitive names of columns, tables, etc. as those are case insensitive in postgresql. Instead ‘ ( single quote ) is used for text.
for example.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;select age from table1 where name = 'harry'; ( postgresql )
select age from table1 where name = "harry"; ( mysql )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;common json changes from MySQL to Postgresql include :
json_length MySQL = json_array_length
convert text variable to json using ::json
json_extract = -&amp;gt;&amp;gt; operator
json_unquote = trim(‘“’ from abc)
we also have json datatype in postgresql&lt;/li&gt;
&lt;li&gt;if we are using escape characters in string like \n, \t, etc. “E” should be applied before the string like
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;E'\t hello \n World'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;FIND_IN_SET(value, array) is replaced with
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;value = ANY(string_to_array(array, ',')::BIGINT[])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;“insert ignore” is replaced with “on conflict do nothing”. we can also specify unique columns separately after the conflict in () but not including means all unique constraints are included. Similarly, on duplicate key update is handled by on conflict do update set. EXCLUDED point to the new row for inserting.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insert into t1(s1,s2)
select a,b from t2
on conflict do nothing;

insert into t1(s1,s2)
select a,b from t2
on conflict (any unique columns/columns ) do update set
   s1 = EXCLUDED.a,
   s2 = EXCLUDED.b;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In mysql cursor we declare continue handler with a variable and have a condition where if the variable is equal to 1 we leave the loop&lt;br&gt;
But in postgresql both are not supported and the only change is to attach statement “exit when not found;” after fetching from the cursor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;loops in cursors can’t have names in postgresql&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;FOUND_ROWS() in replaced by ROW_COUNT.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get diagnostics count = ROW_COUNT;
concat('Inserted records are ', count) into var_output;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;for exceptions — declare handler is not supported in postgresql but can use
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;declare
begin
    statements;
exception
    when condition [or condition...] then
       handle_exception;
   [when condition [or condition...] then
       handle_exception;]
   [when others then
       handle_other_exceptions;
   ]
end;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In delete statement we can delete from the source table only ( unless cascade delete is applied on child tables ). Also, 1st “JOIN” keyword after table is replaced with “USING”. The joining columns of the source table need to be specified in the where clause.
for eg
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;delete from abc 
using def
join efg on def.name = efg.name
where abc.id = def.objectid and abc.col1 = efg.col1;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;enum support in postgresql is not provided like in MySQL. All enum columns should be declared as text or varchar.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In update statements, we can update the source table only because table prefix for columns is removed in postgresql. Also, 1st “JOIN” keyword after table is replaced with “FROM”. The joining columns of the source table need to be specified in the where clause. set clause is before the from clause. for eg&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;update abc a
set 
  col1 = o.name
  col2 = w.type
from def o
join fgh w on o.col3 = w.col3
where 
  a.addressid = o.id
and a.contactid = w.id;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;instr( string, sub_string ) is replaced by POSITION(sub_string IN string).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;While creating table instead of NOT NULL AUTO_INCREMENT use GENERATED ALWAYS AS IDENTITY&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cannot create index while creating table in postgresql, need to create index explicitly in new SQL statement. Also, cannot create index on variable length of column like col(255)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DROP TEMPORARY TABLE replaced by DROP TABLE. works for both types.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;group_concat = string_agg(string, ‘separator’)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In Information_Schema.columns, COLUMN_TYPE is replaced by DATA_TYPE&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;unique constrainst are created using unique indexes. So, first need the index to create the constraint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CURDATE() is replaced with CURRENT_DATE&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DATE_ADD() is replaced with date_var + anything. [ if anything is integer then days are added if anything is INTERVAL ‘1 WEEK’ then 1 week is added ]&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>mysql</category>
      <category>postgres</category>
      <category>procedures</category>
      <category>migration</category>
    </item>
  </channel>
</rss>
