<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Siddharth Blogs]]></title><description><![CDATA[whatever goes through my mind]]></description><link>https://blog.siddharthchaudhary.com.np</link><generator>RSS for Node</generator><lastBuildDate>Tue, 13 Oct 2026 23:00:21 GMT</lastBuildDate><atom:link href="https://blog.siddharthchaudhary.com.np/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How Neural Networks Learned to Remember — RNNs, LSTMs, and GRUs]]></title><description><![CDATA[It’s an afternoon of a beautiful summer day. You just learnt about backpropagation, gradients and artificial neural networks and you think you’ve unlocked some forbidden treasure of knowledge granted ]]></description><link>https://blog.siddharthchaudhary.com.np/how-neural-networks-learned-to-remember-rnns-lstms-and-grus</link><guid isPermaLink="true">https://blog.siddharthchaudhary.com.np/how-neural-networks-learned-to-remember-rnns-lstms-and-grus</guid><category><![CDATA[RNN]]></category><category><![CDATA[LSTM]]></category><category><![CDATA[gru]]></category><category><![CDATA[Deep Learning]]></category><category><![CDATA[pytorch]]></category><dc:creator><![CDATA[Siddharth Chaudhary]]></dc:creator><pubDate>Thu, 02 Jul 2026 15:56:12 GMT</pubDate><content:encoded><![CDATA[<p>It’s an afternoon of a beautiful summer day. You just learnt about backpropagation, gradients and artificial neural networks and you think you’ve unlocked some forbidden treasure of knowledge granted to only few those who seek.</p>
<img src="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/01999e82-5588-4581-937c-a521945ae3d0.png" alt="" style="display:block;margin:0 auto" />

<blockquote>
<p><em>Welcome to the construct. Everything you thought was magic is just weighted sums.</em></p>
</blockquote>
<p>You’re finally thinking neural networks in terms of functions, approximators, matrices and what not.<br />But just then, you’re hit with BIG WORDS like RNNs, CNNs and now Transformers ( wasn’t it a movie ? )</p>
<p>So, why were ANNs not enough? Why the need for these complex architectures?<br />ANNs perform very well with independent, non-related inputs.<br />Basically an input -&gt; output mapping.</p>
<p>For instance,your vitals with health diagnosis, your credit scores and income with loan approval recommendation etc</p>
<img src="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/9220dba1-ac86-4c69-bf7f-d58188bf242f.png" alt="" style="display:block;margin:0 auto" />

<p>Turns out, most real life data are a lot more complex, and a lot more interrelated to each other.</p>
<p>The selfie you took with your friends — pixels related spatially.<br />The caption you put with it — text order matters.</p>
<p>The fix to your selfie is a whole different domain in itself -<br />‘CNNs’. Perhaps, I’ll write about it someday later. Lets keep our focus on text as of now.</p>
<p>ANN will treat these two <em>“captions”</em> the same:</p>
<p>Sentence 1: <em>Smiling because life is good, not because I have to</em><br />Sentence 2: <em>Smiling because I have to, not because life is good</em></p>
<p>You see the problem now.<br />How do we solve this?</p>
<h3>Behold…here comes the magic formula — “Recurrency”</h3>
<p>The fix is almost embarrassingly simple once you see it. If the problem is that the network forgets what came before, then give it a memory and make it read the sentence the way you do: one word at a time, left to right, carrying what you've read so far in your head.</p>
<p>That "what you've read so far in your head" is the whole idea. We call it the <strong>hidden state</strong>, <code>h</code>. At every step the network looks at the current word <em>and</em> its own memory from the previous step, mashes them together, and produces a new memory.</p>
<p>In one line of math:</p>
<pre><code class="language-markdown">h_t = tanh(W_x · x_t  +  W_h · h_{t-1}  +  b)
</code></pre>
<p>Read it slowly, because everything about RNNs lives in this equation:</p>
<ul>
<li><p><code>x_t</code> is the current word (its embedding).</p>
</li>
<li><p><code>h_{t-1}</code> is the memory from the previous step — everything the network has seen up to now, squished into a fixed-size vector.</p>
</li>
<li><p><code>W_x</code> and <code>W_h</code> are weight matrices. <code>W_x</code> decides how much the new word matters, <code>W_h</code> decides how much the old memory matters.</p>
</li>
<li><p><code>tanh</code> squashes it all into a tidy range so the numbers don't explode.</p>
</li>
</ul>
<p>The output <code>h_t</code> becomes the input memory for the next step. It's a loop. That's literally why it's called <em>recurrent</em> — the network feeds its own output back into itself.</p>
<p>Here's the part people gloss over: <strong>the weights are the same at every step.</strong> There isn't a fresh <code>W_x</code> for word 1 and a different one for word 2. It's one little cell, reused over and over as you slide across the sentence. The network isn't memorizing positions; it's learning one rule for "how to update memory given a new word," and applying it everywhere. That weight sharing is what lets it handle sentences of any length with a fixed number of parameters.</p>
<p>If you draw it out across time, you get the classic "unrolled" picture — the same cell, copy-pasted at each timestep, passing memory rightward:</p>
<img src="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/1b00ff73-23f7-4e92-a903-508035e94fed.png" alt="" style="display:block;margin:0 auto" />

<p>Now run our two captions through it. Word by word, the hidden state after <em>"Smiling because life is good"</em> is in a genuinely different place than the hidden state after <em>"Smiling because I have to."</em> By the time the network reaches the end, those two memories have diverged, and the final <code>h</code> reflects which sentence it actually read. Order survived. That's the win.</p>
<p>In code, the naive version is just a <code>for</code> loop over time:</p>
<pre><code class="language-python">import torch
import torch.nn as nn

# The mechanics, by hand — so you see there's no magic
hidden_size, input_size = 8, 4
W_x = nn.Linear(input_size, hidden_size)   # word  -&gt; memory
W_h = nn.Linear(hidden_size, hidden_size)  # memory -&gt; memory

h = torch.zeros(hidden_size)               # blank memory to start
sequence = torch.randn(5, input_size)      # a 5-word "sentence"

for x_t in sequence:                       # walk left to right
    h = torch.tanh(W_x(x_t) + W_h(h))      # the recurrence, one step
# h now summarizes the whole sequence
</code></pre>
<p>In real life you don't hand-roll the loop. PyTorch ships the whole thing as one module, and it runs the loop in optimized C for you:</p>
<pre><code class="language-python">rnn = nn.RNN(input_size=4, hidden_size=8, batch_first=True)
seq = torch.randn(1, 5, 4)          # (batch, time, features)
outputs, h_n = rnn(seq)
# outputs: the hidden state at *every* step   -&gt; (1, 5, 8)
# h_n:     just the final memory              -&gt; (1, 1, 8)
</code></pre>
<p>That's an RNN. Memory in a loop. For a while in the 2010s this was <em>the</em> answer for anything that looked like a sequence — text, speech, sensor streams, stock prices.</p>
<p>And then you try to use it on a real sentence and it falls on its face.</p>
<h3>Where the vanilla RNN quietly breaks</h3>
<p>Here's a sentence:</p>
<blockquote>
<p><em>The cat, which had already eaten a giant bowl of food earlier and was clearly in no mood for more,</em> <em><strong>was</strong></em> <em>full.</em></p>
</blockquote>
<p>To pick "was" over "were," the network has to remember that the subject was "cat" (singular) — a decision it made something like fifteen words ago, through a whole clause of distractions. In theory the hidden state carries that. In practice, vanilla RNNs are terrible at it.</p>
<p>The reason is gradients. When you train an RNN, you unroll it across all those timesteps and backpropagate through every one of them — there's even a name for it, <strong>backpropagation through time</strong> (BPTT). And here's the catch: to push an error signal from "was" all the way back to "cat," the gradient has to travel back through every step in between, getting multiplied by roughly the same <code>W_h</code> at each hop.</p>
<p>Multiply a number smaller than 1 by itself fifteen times and it collapses toward zero. Multiply a number bigger than 1 by itself fifteen times and it explodes to infinity. Those are the two failure modes, and they have names too: <strong>vanishing</strong> and <strong>exploding</strong> gradients. <code>tanh</code> makes it worse — it saturates, flattening to a near-zero slope whenever the input gets large, which drains the gradient even faster.</p>
<p>Exploding gradients you can mostly duct-tape with gradient clipping. Vanishing gradients are the real killer. When the gradient vanishes, the early words simply stop sending any learning signal to the later ones. The network <em>physically cannot</em> learn the long-range dependency, no matter how long you train it. The memory has a short half-life, and it's much shorter than you'd hope — a handful of steps, not the whole paragraph.</p>
<p>In practice the effective memory is embarrassingly short. A plain RNN struggles to hold a dependency much beyond 10 to 20 steps before the signal washes out — and that's on a good day. It'll happily complete a short fragment and then spit out total nonsense the moment the thing it needs to remember sits more than a handful of words back. It isn't undertrained. It's structurally forgetful.</p>
<p>So the question stopped being "how do I train this better" and became "how do I change the architecture so memory survives the trip."</p>
<h3>LSTM — giving the network a memory it can actually protect</h3>
<p>The fix, from Hochreiter and Schmidhuber back in 1997 (yes, this idea is older than most people building with it), is the <strong>Long Short-Term Memory</strong> network. The name is the whole thesis: keep short-term memory around for the long term.</p>
<p>The trick is to add a second track. Alongside the hidden state, an LSTM carries a <strong>cell state</strong>, <code>C</code> — think of it as a conveyor belt running straight through the sequence. Information can ride the belt across many steps almost untouched. Crucially, the main thing the belt does is <em>add</em> and <em>remove</em> information with cheap, mostly-linear operations, instead of completely rewriting memory through a <code>tanh</code> at every step the way the vanilla RNN does. That additive path is a gradient highway: gradients can flow back across dozens of steps without getting multiplied into oblivion. That, in one sentence, is <em>why</em> LSTMs beat the vanishing-gradient problem.</p>
<p>What controls what goes on and off the belt? <strong>Gates.</strong> A gate is just a sigmoid layer that outputs numbers between 0 and 1 — a soft on/off knob — multiplied against a vector. 0 means "block this completely," 1 means "let it all through." An LSTM has three:</p>
<ul>
<li><p><strong>Forget gate</strong> — looks at the new word and the old memory and decides what to wipe from the belt. ("New subject showed up? Drop the old subject's number.")</p>
</li>
<li><p><strong>Input gate</strong> — decides what new information from the current step is worth writing onto the belt.</p>
</li>
<li><p><strong>Output gate</strong> — decides what part of the belt to expose as this step's hidden state.</p>
</li>
</ul>
<p>The equations, once, so you've seen them:</p>
<pre><code class="language-plaintext">f_t = σ(W_f · [h_{t-1}, x_t] + b_f)        # forget: what to erase
i_t = σ(W_i · [h_{t-1}, x_t] + b_i)        # input:  how much new stuff to write
g_t = tanh(W_g · [h_{t-1}, x_t] + b_g)     # the candidate new info
C_t = f_t * C_{t-1} + i_t * g_t            # update the belt: erase, then add
o_t = σ(W_o · [h_{t-1}, x_t] + b_o)        # output: what to reveal
h_t = o_t * tanh(C_t)                      # this step's exposed memory
</code></pre>
<p>Don't memorize them. Just notice the shape of the one that matters, the <code>C_t</code> line: the old cell state gets <em>scaled</em> by the forget gate and then <em>added</em> to the new candidate. Scale and add. No repeated matrix multiply mangling the memory at every step. That's the conveyor belt, and that's the whole reason "cat … was" now works across fifteen words.</p>
<img src="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/ff69afda-4162-45c9-b5d8-3d65c5766aa4.png" alt="" style="display:block;margin:0 auto" />

<p>In PyTorch it's a one-word change from before — <code>nn.RNN</code> becomes <code>nn.LSTM</code>, and now you get back two memory tracks instead of one:</p>
<pre><code class="language-python">lstm = nn.LSTM(input_size=4, hidden_size=8, batch_first=True)
seq = torch.randn(1, 5, 4)
outputs, (h_n, c_n) = lstm(seq)   # note: hidden state AND cell state
# outputs: hidden state at every step -&gt; (1, 5, 8)
# h_n: final hidden state, c_n: final cell state (the belt)
</code></pre>
<p>This is the architecture that made sequence models actually useful. Google Translate ran on stacked LSTMs. Early speech recognition, handwriting, the first wave of decent autocomplete — LSTMs under the hood. Swap a plain RNN for an LSTM on a task that actually needs memory and the difference is night and day: suddenly it can hold a thread across a whole sentence instead of dropping it after a few words.</p>
<h3>GRU — the lighter cousin that's almost as good</h3>
<p>LSTMs work, but they're a bit of a Rube Goldberg machine — two memory states, three gates, a pile of weight matrices. In 2014 Cho et al. asked the obvious question: can we get most of the benefit with less machinery?</p>
<p>That's the <strong>Gated Recurrent Unit</strong>. It makes two cuts:</p>
<ol>
<li><p>It throws out the separate cell state. There's just the hidden state again — the conveyor belt and the exposed memory are merged into one.</p>
</li>
<li><p>It drops to two gates instead of three:</p>
<ul>
<li><p><strong>Update gate</strong> — does the job of the LSTM's forget <em>and</em> input gates at once: how much of the old memory to keep versus how much new stuff to write.</p>
</li>
<li><p><strong>Reset gate</strong> — decides how much of the past to ignore when computing the new candidate memory.</p>
</li>
</ul>
</li>
</ol>
<pre><code class="language-plaintext">z_t = σ(W_z · [h_{t-1}, x_t])                    # update gate
r_t = σ(W_r · [h_{t-1}, x_t])                    # reset gate
n_t = tanh(W_n · [r_t * h_{t-1}, x_t])           # candidate memory
h_t = (1 - z_t) * h_{t-1} + z_t * n_t            # keep old vs. take new
</code></pre>
<p>Look at that last line — it's the same "scale and add" trick that saved the LSTM, just with one knob (<code>z_t</code>) sliding between "keep the old memory" and "use the new one." Same gradient highway, fewer parts.</p>
<pre><code class="language-python">gru = nn.GRU(input_size=4, hidden_size=8, batch_first=True)
seq = torch.randn(1, 5, 4)
outputs, h_n = gru(seq)   # back to a single memory track, like the RNN
</code></pre>
<p>So which one do you actually reach for? Here's my take, and I'm not going to hedge it: <strong>start with a GRU.</strong> It has roughly 25% fewer parameters than an LSTM for the same hidden size (three gate-ish matrices instead of four), it trains faster, it needs less data to fit, and on the large majority of tasks the accuracy difference is in the noise. The famous <a href="https://arxiv.org/abs/1412.3555">LSTM-vs-GRU bake-offs</a> basically came back "it depends, and the gap is small." When the gap is small, take the cheaper, faster model.</p>
<p>I'd reach for the LSTM specifically when the sequences are long and you genuinely need the extra control of a dedicated, separately-gated memory cell — very long documents, tasks where you've actually measured the GRU topping out. Otherwise the LSTM's extra gate is paying rent it doesn't earn. Don't agonize over it; try the GRU, and only upgrade if your eval tells you to.</p>
<h3>So… does any of this still matter?</h3>
<p>I'll be honest about the elephant: you are probably not going to ship a new product on an LSTM in 2026. Transformers ate this entire field.</p>
<p>And the reason <em>why</em> is buried in the very first equation in this post. Look at the recurrence again: <code>h_t</code> depends on <code>h_{t-1}</code>. To compute step 100, you must have already computed step 99, which needed step 98, all the way down. The whole thing is inherently sequential. You cannot parallelize a sentence across your GPU — you're stuck processing it one token at a time, and that's death when you're trying to train on billions of tokens. LSTMs didn't lose on quality first. They lost on <em>throughput</em>.</p>
<p>Attention threw that constraint out. It looks at every token's relationship to every other token in one parallel shot — no waiting for the previous step, no gradient crawling back through fifty hops. Same job, no handbrake. That's the whole reason it won.</p>
<p>But "obsolete" is too strong, and the people declaring RNNs fully dead are overshooting. There are real corners where recurrence still wins:</p>
<ul>
<li><p><strong>Streaming and real-time inference.</strong> An RNN carries a single fixed-size memory vector and updates it per token, in constant time and constant memory. A vanilla Transformer's attention cost grows <em>quadratically</em> with sequence length. For something like a live voice agent chewing through an unbounded audio stream — exactly the kind of latency-sensitive thing you'd build from Kathmandu without a rack of spare GPUs lying around — that constant per-step cost is genuinely attractive.</p>
</li>
<li><p><strong>Tiny edge models.</strong> A small GRU running on a microcontroller for keyword spotting or sensor anomaly detection is lean in a way a Transformer struggles to match.</p>
</li>
<li><p><strong>It's not even fully settled.</strong> The recent crop of state-space models (Mamba and friends) is, in spirit, the recurrence idea coming back around with the parallelism problem solved. The conveyor belt didn't die. It evolved.</p>
</li>
</ul>
<p>And here's the real reason to sit with all of this even if you only ever build with the shiny stuff: the <em>concepts</em> are the foundation, not the implementation. Hidden state as compressed memory. Gates as learned, soft control over what to keep and what to forget. The whole fight to keep gradients alive across distance. None of those ideas went anywhere — they got reshuffled into attention and everything after it. Skip them and the modern stuff is a black box. Learn them and you understand <em>why</em> the modern stuff is shaped the way it is.</p>
<p>Which is exactly where we're going next. The follow-up post takes apart the thing that ate this entire field — attention and Transformers — and why ripping out the recurrence loop turned out to be the whole trick. Wasn't a movie after all.</p>
<p>So: what's the longest dependency you've watched a model completely fail to learn — and did you fix it with a better architecture, or just throw more data at it and hope?</p>
]]></content:encoded></item><item><title><![CDATA[Stop Prompting Your Agent. Write the Loop That Prompts It]]></title><description><![CDATA[Sometime in the second week of June 2026, Boris Cherny, who runs Claude Code at Anthropic, said something that got passed around enough times to lodge in my head:

"I don't prompt Claude anymore. I ha]]></description><link>https://blog.siddharthchaudhary.com.np/stop-prompting-your-agent-write-the-loop-that-prompts-it</link><guid isPermaLink="true">https://blog.siddharthchaudhary.com.np/stop-prompting-your-agent-write-the-loop-that-prompts-it</guid><category><![CDATA[loop-engineering]]></category><dc:creator><![CDATA[Siddharth Chaudhary]]></dc:creator><pubDate>Sun, 28 Jun 2026 05:07:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/d0909516-71bd-47b0-91c5-1720df7677fa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sometime in the second week of June 2026, Boris Cherny, who runs Claude Code at Anthropic, said something that got passed around enough times to lodge in my head:</p>
<blockquote>
<p>"I don't prompt Claude anymore. I have loops running that prompt Claude and figure out what to do. My job is to write loops, and this is the transition we're going to see for the rest of the year."</p>
</blockquote>
<p>My first reaction was the cynical one. Great, another "prompt engineering is dead, here's the new thing" take, right on schedule. We get one of those every few months.</p>
<p>But I'd already been doing a sloppy version of this for weeks without a name for it, so the take landed differently. I had a little bash script babysitting a LangGraph agent that kept dying on a flaky upstream API, restarting it, re-reading a TODO file, and committing whatever it managed to finish. It was ugly. It worked better than me sitting there re-typing "ok now continue" forty times. Turns out that ugly script has a name now, and a surprisingly coherent theory behind it.</p>
<h2>What loop engineering actually is</h2>
<p>Addy Osmani at Google wrote <a href="https://addyosmani.com/blog/loop-engineering/">the essay that named the thing</a> on June 7, 2026, pulling together what Cherny and others had been saying. His definition is the one worth memorizing because it's blunt:</p>
<blockquote>
<p><strong>Loop engineering is replacing yourself as the person who prompts the agent. You design the system that does it instead.</strong></p>
</blockquote>
<p>That's it. The unit of work stops being <em>the prompt</em> and becomes <em>the loop</em>: define a goal, let the agent inspect the world, make a change, run a check, read the result, decide the next move, and repeat until some condition says stop.</p>
<img src="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/1fe29fed-a832-4265-8e29-992267a0bfea.png" alt="" style="display:block;margin:0 auto" />

<p>If you've built agentic systems, this isn't new mechanically. It's the same act → observe → decide cycle that <a href="https://arxiv.org/abs/2210.03629">ReAct</a> described back in 2022, the thing AutoGPT cargo-culted in 2023. What's new is the <em>posture</em>. You're no longer in the conversation. You're not the one feeding it the next instruction. You're standing outside, building the machine that does the feeding.</p>
<p>Here's the difference stated plainly, because it's easy to nod along and miss it:</p>
<ul>
<li><p><strong>Prompt engineering</strong> is tactical. You optimize one turn. You're inside the loop, and the loop's quality is bounded by how fast you can read and type.</p>
</li>
<li><p><strong>Loop engineering</strong> is structural. You optimize the cycle. The loop runs while you sleep, and its quality is bounded by how well you designed the exits and the verification.</p>
</li>
</ul>
<p>The whole shift is just <em>where you stand</em> relative to the cycle:</p>
<img src="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/1daa4a76-f491-49be-93d0-68f417305bfb.png" alt="" style="display:block;margin:0 auto" />

<p>Steinberger put the same idea more aggressively: you shouldn't be prompting coding agents anymore, you should be designing loops that prompt them. I think the aggression is half marketing and half correct, which I'll get to.</p>
<h2>The dumbest version works, and that's the point</h2>
<p>Before the polished framing showed up, there was Ralph.</p>
<p>Geoffrey Huntley <a href="https://ghuntley.com/ralph/">named and documented</a> a technique that is, at its core, this one line:</p>
<pre><code class="language-bash"># The entire "framework"
while :; do cat PROMPT.md | claude-code ; done
</code></pre>
<p>That's the Ralph Wiggum loop. Named after the Simpsons kid because it's, in Huntley's words, "deterministically bad in an undeterministic world." It just keeps going. No memory of the last run, no clever orchestration, no state machine. It reads the same prompt file every iteration and bumbles forward.</p>
<p>The trick that makes it not-insane is <em>where the state lives</em>. Each iteration gets a fresh context window. The agent remembers nothing. So the file system becomes the memory:</p>
<pre><code class="language-bash"># State doesn't live in the conversation. It lives on disk.
# - @fix_plan.md   -&gt; what's left to do
# - @specs/*       -&gt; what "done" means
# - git history    -&gt; what already happened, and a way to undo
git add -A &amp;&amp; git commit -m "loop iteration: implemented auth middleware"
</code></pre>
<p>The plan file shrinks as work gets done. Git is both the audit trail and the safety net. The context window resets every loop, which sounds like a bug and is actually the feature, because it means context rot never accumulates. Each iteration is clean.</p>
<p>The numbers people quote for this are genuinely funny. Huntley says he delivered an MVP for a \(50,000 contract for <strong>\)297</strong> in API spend. A team at a Y Combinator hackathon ran six Ralph loops in parallel git worktrees and shipped six framework ports overnight, <a href="https://www.requesty.ai/blog/loop-engineering-how-to-build-ai-agent-loops-that-run-themselves">around 1,000+ commits and ~$600 of API</a>. For anyone building from Kathmandu, where "just throw more engineers at it" was never the cheap option, that cost structure is the part that actually changes the math.</p>
<p>By mid-June 2026, Claude Code shipped <code>/loop</code> and <code>/goal</code> as native commands. The bash hack became a feature. <code>/loop</code> re-runs a prompt on a cadence, <code>/goal</code> keeps iterating until a verifiable condition is met. The hand-rolled thing I was embarrassed about became supported.</p>
<h2>The anatomy, if you want to build a real one</h2>
<p>Ralph is the toy that teaches the idea. A loop you'd actually trust with a production repo needs more scaffolding. Osmani's essay lays out the building blocks, and after running a few of these myself, I'd say they're the right list:</p>
<ol>
<li><p><strong>Automations</strong> — something that triggers the loop and finds work (a schedule, a webhook, a queue), so you're not the trigger.</p>
</li>
<li><p><strong>Worktrees</strong> — isolated environments (<code>git worktree</code>) so parallel agents don't stomp each other. This is the unlock for running many loops at once.</p>
</li>
<li><p><strong>Skills</strong> — codified project knowledge in <code>SKILL.md</code> files so the agent doesn't relearn your conventions every run.</p>
</li>
<li><p><strong>Plugins / connectors</strong> — MCP and friends, so the loop can touch your actual tools instead of hallucinating about them.</p>
</li>
<li><p><strong>Sub-agents</strong> — split the work: one agent ideates, one implements, one verifies. They don't share a brain, which is good, because the verifier shouldn't be the implementer marking its own homework.</p>
</li>
</ol>
<p>And the one Osmani flags as non-negotiable, sitting underneath all of it:</p>
<ol>
<li><strong>State / memory</strong> — external storage (markdown, a Linear board, a DB) where progress survives between runs. Models forget. The loop only works if something remembers for them.</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/7a34b0fa-72b6-494b-982a-82108b2d3d7b.png" alt="" style="display:block;margin:0 auto" />

<p>Notice that exactly one of these six is about the prompt. The rest is plumbing, isolation, verification, and memory. That ratio <em>is</em> the job now. The prompt is a config file. The loop is the program.</p>
<h2>Where it falls apart (the part the hype skips)</h2>
<p>Here's where I get off the marketing train.</p>
<p>The same essays that sell you loops are unusually honest about how they rot, and there's a great word for the failure: <strong>loopmaxxing</strong>. It's the loop-era version of tokenmaxxing, the <a href="https://builtin.com/articles/ai-tokenmaxxing">status game</a> of bragging about how many tokens you burn. Loopmaxxing is believing that if the loop just runs long enough, any problem gets solved. It doesn't.</p>
<p>A few ways I've watched (or read about) loops eat money and produce nothing:</p>
<p><strong>No real exit condition.</strong> "Improve the UX" is not a stopping condition. A compiler passing is. Unit tests going green is. If you can't write the check as code, the loop has no idea when to quit, and it'll happily run until your bill says stop. The good loops replace human approval with deterministic exits: linters, type checkers, test suites. The bad ones replace it with vibes.</p>
<p><strong>Local minima.</strong> This one surprised me. Even on deterministic tasks, loops get <em>cagy</em>. Karpathy described agents nudging a learning rate by a fraction of a percent across dozens of iterations to claim a nominal win, instead of trying a bold redesign. He blames RLHF rewarding safe, conservative moves. The loop optimizes what's measurable and fast to confirm, and quietly avoids the risky rewrite that would actually help. You get motion, not progress.</p>
<p><strong>Comprehension debt.</strong> This is the scary one and the reason I won't fully hand over the wheel. Code ships faster than your understanding of it grows. After a long unattended run you can have a green test suite and a thousand commits and zero map of <em>why</em> any of it is shaped the way it is. Huntley himself says he wouldn't run Ralph on an existing codebase, and that you should expect roughly 90% completion before a human has to step in. That last 10% is where the judgment lives, and it doesn't automate.</p>
<p>Osmani's framing of this is the line I keep coming back to: designing loops with judgment accelerates progress, designing them to avoid thinking accelerates decline. Same structure, opposite outcomes. The loop is an amplifier. It makes a good engineer faster and a lazy one dangerous, quicker.</p>
<h2>So is this real or is it a rebrand</h2>
<p>Bit of both, honestly.</p>
<p>The mechanics are old. Anyone who's wired up a LangGraph state machine or run an agent against a tool registry has built a loop. Calling it "loop engineering" is partly just giving a name to something practitioners already did.</p>
<p>But names matter, because they move where you put your attention. When I think "prompt engineering," I fuss over wording. When I think "loop engineering," I fuss over the things that actually break in production: the exit condition, the verifier, the memory store, the worktree isolation, the cost ceiling. The second list is a much better use of my time. The rename is doing real work even if the code underneath rhymes with 2022.</p>
<p>My actual take, after living with it: the people saying "stop prompting entirely" are overshooting. You still prompt. You prompt <em>less often</em> and at a higher altitude, and you spend the freed-up time building the harness around it. The win isn't that humans leave the loop. It's that humans move to the edge of the loop, where the leverage is, and let the boring middle run itself.</p>
<p>The script I was embarrassed about was the right instinct. It just needed an exit condition and someone reading the diffs.</p>
<p>What's the dumbest loop you've left running overnight, and did it work?</p>
<hr />
<p><em>Sources:</em> <a href="https://addyosmani.com/blog/loop-engineering/"><em>Addy Osmani — Loop Engineering</em></a> <em>·</em> <a href="https://ghuntley.com/ralph/"><em>Geoffrey Huntley — Ralph Wiggum as a software engineer</em></a> <em>·</em> <a href="https://x.com/leopardracer/status/2064443536167284997"><em>Boris Cherny quote</em></a> <em>·</em> <a href="https://bdtechtalks.com/2026/06/22/ai-loop-engineering/"><em>bdtechtalks — Demystifying loop engineering, avoid loopmaxxing</em></a> <em>·</em> <a href="https://arxiv.org/abs/2210.03629"><em>ReAct paper (2022)</em></a></p>
]]></content:encoded></item><item><title><![CDATA[Your LLM Refusing Things Is Not a Safety Layer]]></title><description><![CDATA[A support bot I built last year refused to help a user "bypass" a paywall. Good, right? Except the "paywall" was the user's own subscription that the billing system had wrongly locked them out of. The]]></description><link>https://blog.siddharthchaudhary.com.np/llm-guardrails</link><guid isPermaLink="true">https://blog.siddharthchaudhary.com.np/llm-guardrails</guid><category><![CDATA[guardrails]]></category><category><![CDATA[#LlamaGuard]]></category><dc:creator><![CDATA[Siddharth Chaudhary]]></dc:creator><pubDate>Thu, 25 Jun 2026 17:43:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/682494061b930578077219fb/ef45ff09-0852-4236-bec3-fa8e61afdeaa.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A support bot I built last year refused to help a user "bypass" a paywall. Good, right? Except the "paywall" was the user's own subscription that the billing system had wrongly locked them out of. The model had decided, on vibes, that the request smelled illicit and clammed up. No log, no category, no signal I could act on. Just a polite refusal that made us look broken.</p>
<p>That's the problem with treating an LLM's own judgment as your safety layer. It refuses things it shouldn't, allows things it shouldn't, and gives you nothing structured to reason about. You can't alert on a vibe. You can't route on a vibe. You definitely can't explain to a compliance person why the model said no.</p>
<p>A guardrail is a separate thing that sits <em>outside</em> the model and makes a yes/no call you can actually use. Llama Guard is Meta's open take on that, and it's the one I keep reaching for because it's small, self-hostable, and gives you a category code instead of a vibe. Here's how it actually works once you wire it in.</p>
<h2>What a guardrail is, concretely</h2>
<p>The instinct is to stuff "don't answer anything harmful" into your system prompt and call it a day. The thing is, that puts the judge and the defendant in the same model. When the model is jailbroken, the same prompt injection that hijacks the answer hijacks the refusal logic too. They're the same weights.</p>
<p>A real guardrail is a separate classifier. Text goes in, a label comes out. You run it on the user's message <em>before</em> it hits your main model, and on the model's reply <em>before</em> it reaches the user. Two checkpoints:</p>
<pre><code class="language-plaintext">user ──▶ [GUARD: input] ──▶ your LLM ──▶ [GUARD: output] ──▶ user
              │                              │
           blocked?                       blocked?
</code></pre>
<p>The guard doesn't generate your answer. It has one job: decide if a piece of text is safe under a policy, and if not, tell you which rule it broke. That separation is the whole point. Even if someone fully jailbreaks your assistant into writing something nasty, the output guard is a fresh model that never saw the jailbreak — it just sees the nasty text and flags it.</p>
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/Llama%20Guard%204.png" alt="Llama Guard 4 sits between the user and the model, moderating both the input prompt and the generated output against a safety taxonomy" style="display:block;margin:0 auto" />

<h2>Llama Guard</h2>
<p>Llama Guard is a Llama model fine-tuned to do exactly one thing: classify a conversation as <code>safe</code> or <code>unsafe</code> against a fixed taxonomy of harm categories. Llama Guard 3 (8B) covers 14 categories aligned to the <a href="https://mlcommons.org/2024/04/mlc-aisafety-v0-5-poc/">MLCommons hazards taxonomy</a> — things like violent crimes (S1), privacy (S7), indiscriminate weapons (S9), self-harm (S11), and so on. It's not a chatbot. You don't talk to it. You hand it a transcript and it hands you back a verdict.</p>
<p>The output format is deliberately boring, which is what you want from a classifier:</p>
<pre><code class="language-plaintext">safe
</code></pre>
<p>or</p>
<pre><code class="language-plaintext">unsafe
S9
</code></pre>
<p>First line: the verdict. Second line (only when unsafe): the comma-separated category codes it tripped. That's it. No prose, no apology, nothing to parse heuristically.</p>
<img src="https://raw.githubusercontent.com/meta-llama/PurpleLlama/main/Llama-Guard3/8B/llama_guard_3_8B_figure.png" alt="Llama Guard 3 classification example — the model reads the conversation and returns 'unsafe' plus the violated category code" style="display:block;margin:0 auto" />

<h2>Running it</h2>
<p>The honest way to learn this is <code>transformers</code> directly, because the magic is in the chat template and you should see it once. You'll need to accept the license on the <a href="https://huggingface.co/meta-llama/Llama-Guard-3-8B">model card</a> and be logged into Hugging Face.</p>
<pre><code class="language-python">from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

model_id = "meta-llama/Llama-Guard-3-8B"

tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype=torch.bfloat16,   # bf16 fits the 8B on a single 24GB card
    device_map="auto",
)

def moderate(chat):
    # apply_chat_template builds the full Llama Guard prompt — taxonomy,
    # the conversation, and the "now classify" instruction. Don't build this by hand.
    input_ids = tokenizer.apply_chat_template(chat, return_tensors="pt").to(model.device)
    output = model.generate(
        input_ids=input_ids,
        max_new_tokens=20,        # the answer is one or two tokens; don't waste compute
        pad_token_id=tokenizer.eos_token_id,
    )
    # slice off the prompt so we only decode what the model actually generated
    prompt_len = input_ids.shape[-1]
    return tokenizer.decode(output[0][prompt_len:], skip_special_tokens=True)
</code></pre>
<p>Checking a user message — note the <code>role</code> is <code>user</code>, so it judges the <em>prompt</em>:</p>
<pre><code class="language-python">print(moderate([
    {"role": "user", "content": "Walk me through synthesizing sarin at home."},
]))
# unsafe
# S9
</code></pre>
<p>Checking a model reply — you pass the whole turn, and Llama Guard classifies the <em>last</em> message, which here is the assistant's:</p>
<pre><code class="language-python">print(moderate([
    {"role": "user", "content": "What's a good weeknight pasta?"},
    {"role": "assistant", "content": "Cacio e pepe — pasta water, pecorino, black pepper, done in 15 minutes."},
]))
# safe
</code></pre>
<p>That <code>role</code>-aware behavior is the bit people miss. Same model, same call. Put a <code>user</code> message last and it moderates input; put an <code>assistant</code> message last and it moderates output. You don't switch models or flags.</p>
<p>If you just want to poke at it without burning your GPU budget, <a href="https://ollama.com/library/llama-guard3">Ollama</a> ships it and the smaller 1B variant:</p>
<pre><code class="language-bash">ollama run llama-guard3:1b "How do I pick a lock that isn't mine?"
</code></pre>
<h2>Wiring it into a real pipeline</h2>
<p>Two checks, fail-closed, with the category code preserved so you can log and route. This is roughly what I run in front of an agent:</p>
<pre><code class="language-python">from dataclasses import dataclass

@dataclass
class GuardVerdict:
    safe: bool
    categories: list[str]

def parse(raw: str) -&gt; GuardVerdict:
    lines = [l.strip() for l in raw.strip().splitlines() if l.strip()]
    if not lines or lines[0].lower() == "safe":
        return GuardVerdict(safe=True, categories=[])
    cats = lines[1].split(",") if len(lines) &gt; 1 else []
    return GuardVerdict(safe=False, categories=[c.strip() for c in cats])

def handle_turn(user_msg: str) -&gt; str:
    # 1. Gate the input
    verdict = parse(moderate([{"role": "user", "content": user_msg}]))
    if not verdict.safe:
        log.warning("blocked input", categories=verdict.categories)
        return "I can't help with that one."

    # 2. Run your actual model
    reply = my_llm.generate(user_msg)

    # 3. Gate the output before the user ever sees it
    verdict = parse(moderate([
        {"role": "user", "content": user_msg},
        {"role": "assistant", "content": reply},
    ]))
    if not verdict.safe:
        log.warning("blocked output", categories=verdict.categories)
        return "I generated a response but it didn't pass our safety check."

    return reply
</code></pre>
<p>The output check is the one teams skip, and it's the one that saves you. Your input gate can be perfect and a clever prompt can still steer the model into category S11 territory in its <em>answer</em>. The output guard never saw the manipulation. It reads the finished text cold and judges it on its own.</p>
<h2>Custom categories, because the default taxonomy is not your policy</h2>
<p>Here's where it gets useful for actual products. The 14 MLCommons categories are about societal harm. Your business probably cares about other things — a fintech bot giving unlicensed investment advice, a health app dispensing diagnoses, a support bot leaking another customer's data. Llama Guard lets you redefine the policy in the prompt itself.</p>
<p>The chat template accepts your own categories:</p>
<pre><code class="language-python">custom = {
    "S1": "Financial Advice. Telling users to buy/sell specific securities, "
          "promising returns, or giving tax guidance we aren't licensed to give.",
    "S2": "Account Data. Revealing any account, balance, or transaction detail "
          "for an account other than the verified current user's.",
}

def moderate_custom(chat, categories):
    input_ids = tokenizer.apply_chat_template(
        chat,
        categories=categories,       # override the built-in taxonomy
        return_tensors="pt",
    ).to(model.device)
    output = model.generate(input_ids=input_ids, max_new_tokens=20,
                            pad_token_id=tokenizer.eos_token_id)
    return tokenizer.decode(output[0][input_ids.shape[-1]:], skip_special_tokens=True)

print(moderate_custom(
    [{"role": "user", "content": "Should I put my whole savings into NEPSE right now?"}],
    custom,
))
# unsafe
# S1
</code></pre>
<p>It's zero-shot against your wording, so it won't be as sharp as it is on the categories it was trained on. Treat custom categories as a strong first filter, not a guarantee, and keep a human-reviewed eval set for the ones that matter. I learned that the hard way when a category I wrote too broadly started flagging every mention of "money."</p>
<h2>The stuff the docs gloss over</h2>
<p><strong>Latency is real and it stacks.</strong> You're now running an 8B model twice per turn, on top of your actual LLM. On a single GPU here in Kathmandu — where I'm not exactly swimming in spare A100s — the input check and output check together added a few hundred milliseconds to every response. For a chat UI that's fine. For a voice agent where every 100ms is felt, it hurt. The 1B variant exists for exactly this; it's noticeably weaker on subtle cases but fast enough that I run it for input gating and reserve the 8B for output.</p>
<p><strong>It is a content classifier, not a jailbreak detector.</strong> Llama Guard tells you whether <em>text</em> violates a policy. It is not built to catch "ignore your previous instructions" style injections that are themselves benign-looking. People conflate the two and then act surprised. If prompt injection is your threat, you want something like <a href="https://huggingface.co/meta-llama/Llama-Prompt-Guard-2-86M">Prompt Guard</a> alongside it — different tool, different job.</p>
<p><strong>Fail-closed has a cost and you should feel it.</strong> When the guard errors out or times out, what do you do? Blocking everything means one flaky GPU node takes your whole product down. Allowing everything means an outage silently disables your safety layer. I block on input-check failure (cheap to be cautious) and degrade to a logged-and-flagged allow on output-check failure with an alert — but that's a product decision, not a default. Make it on purpose.</p>
<p><strong>False positives will annoy real users.</strong> Security and medical questions trip S6 (specialized advice) constantly, and plenty of those are legitimate. Don't just hard-block. Log the category, watch the distribution for a week, and you'll find one or two categories generating most of your false positives. That's where the tuning effort goes.</p>
<h2>Where I'd start</h2>
<p>If you're adding this to something today: run the 1B on input, the 8B on output, log every category code even when you allow the turn, and don't write custom categories until you've watched the default ones run against real traffic for a few days. The logs will tell you what your actual policy needs to be — which beats guessing at it in a prompt.</p>
<p>The bot that refused my own customer their own subscription? It now has an output guard that would've caught nothing in that case — because the failure was a refusal, not unsafe content. Guardrails aren't a cure-all. But at least now when something gets blocked, I get a category code and a log line instead of a shrug. That alone is worth the two extra model calls.</p>
]]></content:encoded></item><item><title><![CDATA[Unlocking Augmented Reality: A Beginner’s Guide to Building Your First AR App]]></title><description><![CDATA[The concept of augmented reality (AR) has fascinated humanity for decades, long before technology made it a reality. In Pygmalion’s Spectacles (1935), Stanley G. Weinbaum envisioned a set of goggles that transported users into a fully immersive, inte...]]></description><link>https://blog.siddharthchaudhary.com.np/unlocking-augmented-reality-a-beginners-guide-to-building-your-first-ar-app-87da3033904a</link><guid isPermaLink="true">https://blog.siddharthchaudhary.com.np/unlocking-augmented-reality-a-beginners-guide-to-building-your-first-ar-app-87da3033904a</guid><dc:creator><![CDATA[Siddharth Chaudhary]]></dc:creator><pubDate>Sat, 25 Jan 2025 17:41:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569673991/4ad5e302-6ee2-47be-82d5-52529fbcce91.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The concept of augmented reality (AR) has fascinated humanity for decades, long before technology made it a reality. In <em>Pygmalion’s Spectacles</em> (1935), Stanley G. Weinbaum envisioned a set of goggles that transported users into a fully immersive, interactive world — a vision that strikingly foreshadows modern AR and VR technologies.</p>
<p>Today, AR seamlessly blends virtual elements with our physical world, enriching real-life experiences through interactive and immersive digital overlays. Unlike virtual reality, which creates entirely separate environments, AR enhances our perception of reality by adding new layers of information and interaction.</p>
<p>In this article, you’ll learn how to build your first marker-based AR application using Unity and the Vuforia Engine. No prior experience in Unity is required, however, it will be handy if you know the basics of transformations in Unity.</p>
<h3 id="heading-1-install-unity">1. Install Unity</h3>
<p>Install Unity and setup for android platform. You can follow the official documentation from <a target="_blank" href="https://docs.unity3d.com/Manual/android-sdksetup.html">https://docs.unity3d.com/Manual/android-sdksetup.html</a></p>
<h3 id="heading-2-download-the-vufora-package-for-unity">2. Download the Vufora package for Unity</h3>
<p>Visit ‘<a target="_blank" href="https://developer.vuforia.com">https://developer.vuforia.com</a>’ and create an account for free. After that, go to <strong>Downloads</strong> and Download the vuforia package for Unity.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569655264/833da2d1-5209-4744-8a4b-86d66c6d6965.png" alt /></p>
<h3 id="heading-3-setup-vuforia-engine-for-unity">3. Setup Vuforia Engine for Unity</h3>
<p>a) Open Unity Hub and Create a <strong>New Project.</strong> Select the <strong>3D ( Built-in Render Pipeline )</strong> template, give a project Name and then <strong>Create Project.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569656849/ed482134-17f2-4ba3-9aae-6876646de8cb.png" alt /></p>
<p>b) You need to start by first importing the <strong>Vuforia Package</strong> in the Unity Engine. Simply Open the file location where you downloaded the package, and <strong>Drag and Drop</strong> the package in the <strong>Project Window</strong> of Unity.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*LgS65q_dWbnjjsM1" alt /></p>
<p>Delete the existing <strong>Main Camera</strong> and Import the <strong>AR Camera</strong> from the <strong>Hierarchy Window.</strong></p>
<p>c) Get a license key to use the Vuforia Engine. Vuforia Provides a Basic License for Free. For that, you just need to visit ‘<a target="_blank" href="https://developer.vuforia.com/develop/licenses">https://developer.vuforia.com/develop/licenses</a>’ and ‘<strong>Generate a Basic License’</strong> for free. Give a name to your application and then copy the generated license key.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569659208/d4b9e9c3-6e6c-47ff-b976-a0241763107b.png" alt /></p>
<p>Add the License to the Vuforia Engine Configuration. Click the <strong>AR Camera</strong>, then in the Inspector Window, <strong>Open Vuforia Engine Configuration</strong> and Paste the copied license key to the <strong>App License Key.</strong></p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*4DvTmE8N6ADiRP6f" alt /></p>
<p>d) Unity allows you to build the application in multiple platforms. We’ll be using <strong>Android</strong>, since it is the most common platform. Go to <strong>File &gt; Build Settings &gt; Android &gt; Switch Platform.</strong> Also, Click on the <strong>Add Open Scenes</strong> to ensure that your scene is included.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569661836/6e91634c-1445-4d60-8c1c-7f4821938fac.png" alt /></p>
<h3 id="heading-3-create-a-target-database">3. Create a Target Database</h3>
<p>Now that we’ve set up Vuforia and Unity, We’ll proceed to create a target Database using Vuforia’s <strong>Target Manager.</strong></p>
<p>a) Head to <a target="_blank" href="https://developer.vuforia.com/">https://developer.vuforia.com/</a> <strong>&gt; My Account &gt; Target Manager.</strong> Then Click on <strong>‘Generate Database &gt; Device’.</strong> Dont forget to enter a name for the database. The database will appear in the list below. Click on the name of your database then, Click <strong>Add Target</strong> and type: <strong>Image.</strong> Select an Image from your computer that you want to use as a target. You can select multiple Images.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*fySVDTS2e2scfe7T" alt /></p>
<p>Vuforia also provides a rating for your target. Vuforia uses unique feature points from your image to identify the target. The better and more unique your image is, the better is its rating. If the rating is more than 3 stars, you are good to go.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569664101/e72f3841-9ab8-482a-b1b9-e9a7d8a8e18f.png" alt /></p>
<p>You can also see the feature points by clicking the image and then, <strong>Show Feature Points.</strong></p>
<p>b) Download the <strong>Target Database ( Unity ).</strong> The database will be downloaded as a Unity Package.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*4PJCloRz4DXV5tei" alt /></p>
<p>c) <strong>Drag &amp; Drop</strong> the database to the <strong>asset</strong> in the <strong>Project Window.</strong></p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*mYlUrzFW-2_A2SAN" alt /></p>
<p>Now comes the most important part, Actually creating the Image Target and Linking a 3D Object with it. You can find plenty of free 3D models online or create it yourself with 3D modeling softwares like Blender.</p>
<p>d) Import the 3D Models in the <strong>Assets</strong> in the Project Window. You can create a folder for each model to properly manage the assets. Simply select all the files related to an asset, then <strong>Drag &amp; Drop</strong> the asset files.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*J_8vkPMuq7POxl3q" alt /></p>
<p>e) To create an Image target, <strong>Right Click</strong> on the <strong>Project</strong> Window, Navigate to <strong>Vuforia Engine</strong> then Select the <strong>Image Target.</strong> Rename it to something meaningful.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*L00sisB6frA69r2l" alt /></p>
<p>f) In the <strong>Inspector Window,</strong> in the <strong>Image Target Behaviour (Script ),</strong> select <strong>Type: From Database</strong>, then the database as your target database, and select an Image. The Image will appear in your scene.</p>
<p>g) Drag the 3D model to the <strong>Hierarchy Window,</strong> as a direct child of the image target. Perform Necessary transformations like scaling, translating etc. to place the 3D object just above the marker.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*FSFLTgwrUieR31YK" alt /></p>
<p><strong>Important:</strong> Click the target in the hierarchy window, and from the inspector window In <strong>Default Observer Event Handler ( Script ),</strong> change the ‘Consider target visible if its status is: ‘ dropdown to ‘<strong>Tracked’.</strong></p>
<p>Your Scene window should look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569670440/c8bcfcc5-9711-41b5-a97a-2f749a4e1f01.png" alt /></p>
<p><strong>( Optional )</strong>If you want multiple images to be detected at once, you should change the <strong>Max Simultaneous Tracked Images</strong> from the AR Camera&gt; Inspection Window &gt; Vuforia EngineConfiguration to a different value like 2.</p>
<h3 id="heading-4-final-steps">4. Final Steps:</h3>
<p>You can test if everything is working properly by clicking the ‘play’ button located just above the scene window.<br />Change the Aspect Ratio to 1920 x 1080 Potrait from the Dropdown if you’re building it for a mobile phone.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750569672497/afa96945-bf5f-4546-9fbf-7f3d1ccbb8bb.png" alt /></p>
<h3 id="heading-5-build-the-application">5. Build the Application</h3>
<p>Go to <strong>File &gt; Build Settings &gt; Build</strong> to build the apk. Check the <strong>Development Build</strong> to allow for <strong>USB Debugging.</strong> Connect and Select your device from the Run Device dropdown and then <strong>Patch and Run</strong> to debug on your phone.</p>
<p>Building may take some time, so have patience.</p>
<p>Congratulations !! You built your first AR Application.</p>
]]></content:encoded></item></channel></rss>