<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Tausani Ah Chong</title>
    <link>https://tausani.net</link>
    <description>Personal portfolio and blog by Tausani Ah Chong</description>
    <language>en</language>
    <lastBuildDate>Sun, 29 Mar 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://tausani.net/feed.xml" rel="self" type="application/rss+xml"/>
    <image>
      <url>https://tausani.net/sani-headshot.jpg</url>
      <title>Tausani Ah Chong</title>
      <link>https://tausani.net</link>
    </image>
    <item>
      <title>Building a Coding Agent from Scratch</title>
      <link>https://tausani.net/blog/copilot/</link>
      <guid>https://tausani.net/blog/copilot/</guid>
      <pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate>
      <description>TLDR; My company uses M365 Copilot, and for good reason, enterprise guardrails matter. But it has no API, no terminal access, no agentic tooling. So I built my own coding agent around it. And it works...</description>
      <content:encoded><![CDATA[<hr>
<p><em>🇼🇸 Talofa! O lo'u igoa o Tausani Ah Chong, e sau mai le nu'u o Puipa'a ma Avao</em></p>
<p><em>📍 Central Tāmaki Makaurau, Aotearoa</em></p>
<p><em>💼 Intermediate Software Developer @ Vector ⚡️</em></p>
<p><em>👨‍👩‍👧‍👦 Proud dad of 2 kids</em></p>
<p><em>📝 Post #6 - Posting every week until my birthday in April 🎂</em></p>
<hr>
<p><em>Follow me on Instagram! <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>
<p><strong>TLDR;</strong></p>
<p>My company uses M365 Copilot, and for good reason, enterprise guardrails matter.</p>
<p>But it has no API, no terminal access, no agentic tooling.</p>
<p>So I built my own coding agent around it. And it works 🎉</p>
<p>Here’s what I learned.</p>
<h2>The constraint that I just couldn't shake</h2>
<p>No api. No cli. No agentic tooling.</p>
<p>That's the reality of working with M365 Copilot.</p>
<p>The only access you have is through the web or native app.</p>
<p>Which means you chat to it, if you like something then you copy and paste it to your IDE.</p>
<p>My cmd+c, cmd+v has never been faster 😅 up until last week though 👀</p>
<p>The contrast after playing with tools like Claude Code or Codex is crazy different.</p>
<p>I wanted more out of M365 Copilot since the above tools aren't approved to use at work.</p>
<p>Ive been trying to find a way to do something similar that can run in your terminal.</p>
<p>I finally cracked it.</p>
<p>I don't even remember when the idea popped in my head but I went and tried it and yup this was <em><strong>"the last ingredient I needed to make this work"</strong></em></p>
<p>I've pretty much closed the loop im making M365 Copilot agentic.</p>
<p>Meaning I run my application from my terminal, set a task, and away it goes reading and editing files until the task is complete.</p>
<p>So yeah, I'm building a coding agent from scratch. And it's been the most fun with constant learning.</p>
<p>In this post, Im going to share with you a few learnings I think every software engineer should know about.</p>
<p>I've already spent my small career learning to build apps, now it's time to learn to build the thing that builds the thing.</p>
<p>Here it is in action:</p>
<p><img src="https://tausani.net/blog/copilot/in-action.gif" alt="Agent in action"></p>
<p><img src="https://tausani.net/blog/copilot/in-action-1.png" alt="Agent in action screenshot 1"></p>
<p><img src="https://tausani.net/blog/copilot/in-action-2.png" alt="Agent in action screenshot 2"></p>
<h2>Non agentic development flow</h2>
<p>Let's take a look at what the current flow for any developer using M365 Copilot looks like:</p>
<p><img src="https://tausani.net/blog/copilot/non-agentic.png" alt="Non agentic development flow"></p>
<p>As you can see, it is very simple and linear.</p>
<p><strong>User -> M365 Copilot -> copy + paste -> IDE</strong></p>
<p>Bruz you could even swap out M365 Copilot for Stack Overflow 🫣 See what I mean - it feels old school already.</p>
<p>But hey it works, but we all know it can be a lot better. Read the room.</p>
<h2>Agentic development flow</h2>
<p>Below is where we introduce an agentic loop &#x26; <em><strong>"the last ingredient I needed to make this work"</strong></em>. This is the very same foundation of tools like Claude Code &#x26; Codex:</p>
<p><img src="https://tausani.net/blog/copilot/agentic.png" alt="Agentic development flow"></p>
<p>So a couple new terms to get used to if you are not already familiar:</p>
<h3>Agent loop</h3>
<p>Nothing fancy, it's just a while-loop with an AI assistant.</p>
<p>You start with a task, and the loop ends when the task is complete.</p>
<h3>Tool calling</h3>
<p>This part is 🔥</p>
<p>You tell the AI assistant you have some tools they can use during the loop.</p>
<p>Things like reading, editing, searching in files &#x26; running bash commands.</p>
<p>All it has to do is respond by calling the tool of choice. The loop returns back to the AI assistant the output of these tools.</p>
<p>From here an automated copy + paste loop is born.</p>
<p>You will notice if you use Claude on the web you can pick the built-in tool to browse the web.</p>
<h3>Human-on-the-loop</h3>
<p>There's a reason they called something YOLO mode for coding agents. To give full confidence and permission to control your machine 😬</p>
<p>Or you can sit in the driver's seat and approve tool calls, steering the ship.</p>
<p>There are tradeoffs but it's better to lean on smart defaults.</p>
<p>The loop will pause until human approval of tool calls.</p>
<h3>Example of my read_file tool:</h3>
<p><img src="https://tausani.net/blog/copilot/example-tool.png" alt="Example of a tool"></p>
<h2>The build</h2>
<p>Enterprise barriers? Hold my beer 🍺 (Shoutout to my toko Tino for giving me this feedback on this project)</p>
<p>The idea was the easy part.</p>
<p>There was already infrastructure to learn from in terms of foundations of agent loops, TUI and tool calling.</p>
<p>The hardest part was actually parsing the responses from Copilot.</p>
<p>Now please bear in mind this agent is still a young puppy, so it still doesn't work all the time for the range of responses the model returns to us. It is a work in progress.</p>
<p>The part I'm still learning about is the relationship between a model like Anthropic's Opus and agentic tooling like Claude Code.</p>
<p>For example, built into the api to call Claude models is a parameter for a list of tools:</p>
<p><img src="https://tausani.net/blog/copilot/claude-api-example.png" alt="Claude API example"></p>
<p>But because we are using <em><strong>"the last ingredient to make this work"</strong></em> we don't have an api to call.</p>
<p>The limitation is that the only option we have is to send our list of tools as part of our system prompt.</p>
<p>My guess is with the above api calls with tools baked into the api, there is some other mechanism on the other side of the api to manage the way the responses get given back as tool calls.</p>
<p>Models like Opus and Sonnet are trained to return tool calls as first class citizens, whereas with my approach without an api and just purely with a system prompt, all we can do is hope the model responds accordingly.</p>
<p>This is where non determinism could work against us.</p>
<p>Not because the code or system prompt was wrong but purely because my tool calls aren't first class citizens.</p>
<p>Read my previous post about <a href="https://tausani.net/blog/tdd-or-just-tests">determinism vs non determinism</a></p>
<p>You can see the errors in the screenshots below.</p>
<p>There's been a few times where we can't parse properly and our tool calls don't register even though the response we give to the user looks fine.</p>
<p>It comes down to what is in the full response. Sometimes the tool call is buried within the response.</p>
<p>We'll get there with more iterations and the more I tweak the system prompt maybe? I have a few ideas.</p>
<p><img src="https://tausani.net/blog/copilot/tool-error-1.png" alt="Tool error screenshot 1"></p>
<p><img src="https://tausani.net/blog/copilot/tool-error-2.png" alt="Tool error screenshot 2"></p>
<h2>"the last ingredient to make this work"</h2>
<p>There's slang in NZ that gets thrown around whenever you feel let down or led on by someone. You would call someone or something "Build ups".</p>
<p>Where they've hyped something up so much that the hype was more entertaining than the actual reveal 💀 You don't want to be build ups, not even your dad.</p>
<p>So I'm hoping this last ingredient isn't build ups.</p>
<p>Because I know you've read this far, and I thank you, you're the real deal.</p>
<p>So here goes..</p>
<p>My last ingredient...</p>
<p>...</p>
<p><strong>The ingredient is <a href="https://playwright.dev">Playwright</a></strong></p>
<p>...</p>
<p>All I needed was to automate copying and pasting requests and responses between the loop and M365 Copilot.</p>
<p>With Playwright you can spin up a browser and interact with a web page using code. Simple right?</p>
<p>So there we have it, some of the best ideas come from free rein and no restraints..but lets not forget about even greater ideas that come from restraints.</p>
<p>Enterprise barriers are there for good reason, and I fully agree that enterprises with big contracts and influence should be very critical of any new tech and tooling.</p>
<p>Last question for you:</p>
<p>Was my reveal build ups? 😆 let me know by commenting on my linkedIn post, since you made it this far 🫰</p>
<p>See you in the next one!</p>
<hr>
<p><em>Thanks for reading! If you enjoyed this, follow me on Instagram <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a> and connect with me on LinkedIn <a href="https://www.linkedin.com/in/tausaniahchong"><strong>Tausani Ah Chong</strong></a>.</em></p>
<p><em>I'm posting every week until my birthday in April - tune in for the next one!</em></p>]]></content:encoded>
      <media:content url="https://tausani.net/blog/copilot/in-action.gif" medium="image"/>
      <media:thumbnail url="https://tausani.net/blog/copilot/in-action.gif"/>
    </item>
    <item>
      <title>The Model Just Wants to Use Tools</title>
      <link>https://tausani.net/blog/the-model-just-wants-to-use-tools/</link>
      <guid>https://tausani.net/blog/the-model-just-wants-to-use-tools/</guid>
      <pubDate>Fri, 13 Mar 2026 00:00:00 GMT</pubDate>
      <description>&gt; The model just wants to use tools That&apos;s the part that stuck out for me from Boris Creator of Claude Code from his latest chat with Gergely Orosz on The Pragmatic Engineerhttps://newsletter.pragmati...</description>
      <content:encoded><![CDATA[<hr>
<p><em>🇼🇸 Talofa! O lo'u igoa o Tausani Ah Chong, e sau mai le nu'u o Puipa'a ma Avao</em></p>
<p><em>📍 Central Tāmaki Makaurau, Aotearoa</em></p>
<p><em>💼 Intermediate Software Developer @ Vector ⚡️</em></p>
<p><em>👨‍👩‍👧‍👦 Proud dad of 2 kids</em></p>
<p><em>📝 Post #4 - Posting every week until my birthday in April 🎂</em></p>
<hr>
<p><em>Follow me on Instagram! <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>
<blockquote>
<p>The model just wants to use tools</p>
</blockquote>
<p>That's the part that stuck out for me from Boris (Creator of Claude Code) from his latest chat with <a href="https://newsletter.pragmaticengineer.com/p/building-claude-code-with-boris-cherny">Gergely Orosz on The Pragmatic Engineer</a>.</p>
<p>This came up after he spoke about what tools or skills you will need to succeed in this new era of agents/AI.</p>
<p>He basically said it's more useful now to understand one level deeper than the current abstraction that you are working at. For example in the past if you were a frontend dev working with React, one level deeper would be understanding how it works under the hood to get the most gains.</p>
<p>But what does that look like now? Is it frameworks like Next.js or TanStack? Or is it literally understanding how AI models work? - Since the current abstraction is prompting agents</p>
<p>To which Boris decided to study what is going on under the hood for Claude Code, which is the model.</p>
<p>The finding - "The model just wants to use tools" - means don't just put it in a box and let it run. What you should be doing is setting it free and giving it tools to use.</p>
<p>Which led me to thinking ok, let's put this into practice - what tool should I build…</p>
<h2>Introducing… FAALUPEGA CLI 🎉</h2>
<p>So you're probably on one of 2 sides. One side you're probably like what is that? And the other side you're like 😬 ooh um are you tackling that?</p>
<p><strong>What is Faalupega?</strong> It is probably one of the most important records to Samoa. These are records of Samoan chiefly honourifics grouped by village called <em>O Le Tusi Faalupega o Samoa</em> or just a Faalupega. Before any records were written (before Samoan was a written language) it was all oral and passed down through generations and is still practiced to this day by master Orators, or we call Tulafale.</p>
<p>There are over 150 villages across Samoa and each with their set of Matai chiefly titles - so we need an easy way to search across villages and matai title names.</p>
<p>And just like the technology upgrade from oral to written to printed books, it is definitely time to adapt to the new era in AI. So it's important that this should be able to be easily used by both AI agents and other technical folks.</p>
<p>There were a few other ideas for tools that came to mind but thought I would go with the most unique and one that will actually help myself, and I'm sure others that are on the same journey as me learning about Faasamoa and Faamatai - the ways of Samoa and chiefly honourifics.</p>
<p>I figured it would be a great research tool and a foundational layer for both technical folks or AI agents to use. We'll get to a nice UI soon - or better yet you could build it using this tool 😉</p>
<p>Also why a CLI? Why not just build a website first? Because anyone can build a website or app, what's missing is the foundation and underlying platform. This CLI will be one of the first building blocks.</p>
<h2>Tradeoffs</h2>
<p>I've never built a CLI tool before, and instead of telling you what prompts I used, here are a couple tradeoffs I had to think about.</p>
<h3>1. Language</h3>
<p>It was basically TypeScript/Node vs Rust.</p>
<p>For example OpenAI's Codex was first built with TypeScript/Node but then rewritten in Rust.</p>
<p><strong>TypeScript:</strong></p>
<ul>
<li>Faster to prototype? (I don't think this is a thing anymore with AI coding agents imho)</li>
<li>I am already used to reading and understanding the Node &#x26; npm world</li>
</ul>
<p><strong>Rust:</strong></p>
<ul>
<li>Yeah definitely better performance so they say lol - I've never built anything with Rust</li>
<li>Apparently builds all the way down to a single binary - which means you only need to download 1 thing
<ul>
<li>As opposed to TypeScript, the user also needs to download Node - although you can package it together now with <a href="https://bun.com/docs/bundler/executables#cli">Bun</a></li>
</ul>
</li>
</ul>
<p>This decision would also influence the next tradeoff…</p>
<h3>2. Distribution</h3>
<p>I come from a web dev background where the only distribution is the browser, so I never needed to think about users needing to access apps I built. I'm just glad I fell into tech after the Internet Explorer era 🤏</p>
<p>Now with a CLI I had to think about different OS's - your Macs, Linux or Windows users. It seems like the way to go is to support all.</p>
<h3>3. API vs Local Storage</h3>
<p>I don't mean local storage from the browser context, but instead in-memory.</p>
<p>Sure I could create an API and store data in a database - this way even more users will be able to access the data.</p>
<p>The downside to in-memory is the size of bundle and also staleness of data. But the upside is I can continue to keep building on the small features and data I currently have.</p>
<h2>The CLI in Action</h2>
<p>I wanted to keep the CLI initial features very basic - just a couple text match searches, via village or matai title name. This is the main product: you would usually look up a village to study, or partial match on matai names across villages.</p>
<p>You will also notice a Version header at the top of results to let the user know what data source they a looking at</p>
<p><strong>Search by village:</strong></p>
<pre><code class="language-text">$ faalupega village puipaa

┌──────────────┐
│ Version 1930 │
└──────────────┘
════════════════════════════
  PUIPAʻA - Faleata, Upolu
════════════════════════════

Tulouna lau tofa ʻUlu ma lo outou aiga o Seiulialii ma Laufou

MALAE-FONO:
  Lepea - Fono o le manino (filemu)
  Vaitagutu - Fono o le ʻaʻava (taua)

MAOTA O ALII:
  Mataiʻa - Vaiala
  Faumuinā, Letele, Mataʻafa - Lepea
  Seiuli - Vaiusu
  Pepe, Fanene - Falefasa

O IGOA-IPU A ALII:
  Mataiʻa - Tolotūpō
  Faumuinā:
    1. Fai ʻava le ita
    2. Talitigā
    3. Numia ma Tumua
  Seiuli - Seufagafaga
  Le Mataʻafa - Pago talitali le ipu a e taute le Mataʻafa
  Galumalemana - Lagofaatasi
  Letele - Fotualagoataata
  Pepe - Taumailelei
  Fanene - E tapa fua
  Manuʻa - Alo talitali le ipu a e taute le Manuʻalesā
  Latafale - Tamaalii faaea Faleupolu
  Sāvali - Ulugia ma Faleʻafa

SAʻOTAMAʻITAʻI:
  Faumuinā - Letelesā
  Mataiʻa - Latafale
  Seiuli - Tooā
  Pepe, Fanene - Latafale (Safune)
  Leitulua - Muniao
  Une - Tonuu
  Leleua - Ufagafā
  Ale - Tauaiupolu
  ʻUlu - Alofasaupo
</code></pre>
<p><strong>Search by matai title name:</strong></p>
<pre><code class="language-text">$ faalupega matai ale

┌──────────────┐
│ Version 1930 │
└──────────────┘
════════════════════════════
  PUIPAʻA - Faleata, Upolu
════════════════════════════

  MAOTA O ALII:
    Pepe, Fanene - Falefasa
  O IGOA-IPU A ALII:
    Galumalemana - Lagofaatasi
    Manuʻa - Alo talitali le ipu a e taute le Manuʻalesā
    Latafale - Tamaalii faaea Faleupolu
    Sāvali - Ulugia ma Faleʻafa
  SAʻOTAMAʻITAʻI:
    Mataiʻa - Latafale
    Pepe, Fanene - Latafale (Safune)
    Ale - Tauaiupolu

═══════════════════════════
  TOAMUA - Faleata, Upolu
═══════════════════════════

  TULOU:
    Tulouna lau tofa Ale ma Inaʻilau na oo i lo outou aiga,
    o Tupalaimuli ma Tauaiupolu, ma le Aoaniu ma le Momoti
</code></pre>
<p><strong>--help command:</strong></p>
<pre><code class="language-text">$ faalupega --help

Usage: faalupega [options] [command]

Samoan Faalupega Lookup Tool

Faalupega is the traditional record of matai (chief) titles for each
village in Samoa. It documents the sacred hierarchy of titles, their
connections, ceremonial meeting grounds (malae-fono), houses of chiefs
(maota o alii), and high chief names (igoa-ipu a alii).

This tool provides a searchable reference for these records.
All searches are partial and case-insensitive. Samoan diacritics
(macrons: a, e, i, o, u and glottal stops: ʻ) are optional in queries
but preserved in output.

Usage examples:
  $ faalupega village Puipaa          Search by village name
  $ faalupega nuu Puipaa             Same search using Samoan alias
  $ faalupega village pui             Partial match
  $ faalupega matai Seiuli            Search by matai title
  $ faalupega suafa Fanene            Same search using Samoan alias
  $ faalupega village Puipaa --json   JSON output for agents

Options:
  -V, --version                 output the version number
  --data-version &#x3C;version>      Faalupega version year to query (e.g. 1930) (default: "1930")
  -h, --help                    Display help for command

Commands:
  village|nuu [options] &#x3C;name>  Look up a village's faalupega by name. (Samoan: nuu / nu'u)
                                Searches are partial and case-insensitive. Diacritics (macrons, glottal stops) are optional.
                                Examples: faalupega village Puipaa, faalupega nuu Puipaa, faalupega village pui
  matai|suafa [options] &#x3C;name>  Search for a matai (chief) title and find which villages it belongs to. (Samoan: suafa)
                                Searches across all sections: Tulou, Malae-Fono, Maota o Alii,
                                O Igoa-Ipu a Alii, and Saʻotamaʻitaʻi.
                                Partial and case-insensitive. Diacritics optional.
                                Examples: faalupega matai Seiuli, faalupega suafa Fanene, faalupega matai ulu
  setup                         Interactive setup for faalupega.
                                Displays a welcome banner and lets you choose the default version.
                                Your choice is saved to ~/.faalupega/config.json.
  help [command]                display help for command
</code></pre>
<h2>Versions and the Source of Truth</h2>
<p>Naturally there are parts about the Faalupega in general that are a bit controversial and people take pride (and they should) in the hierarchy and order of the honourifics based on who is most important. There is not one single source of truth. Since the records have been documented there are many versions, and also naturally each village or family may record their own separate Faalupega records.</p>
<p>So this was the next challenge and I hope that in the form of versions, much like how there are many English translations for the Bible, we would need to enforce that in this tool. A user should be able to toggle or search between versions.</p>
<p>There is a command that should be run when you first download it called <code>setup</code> here you get an interactive way to select you're default data source</p>
<p><strong>Setup command:</strong></p>
<pre><code class="language-text">$ faalupega setup
</code></pre>
<p>Output:</p>
<p><img src="https://tausani.net/blog/the-model-just-wants-to-use-tools/faalupega-setup.png" alt="faalupega-setup.png"></p>
<p>And in future I would hope they too can upload their own records alongside the publicly available ones - damn we could make a marketplace 🔥 but the main point is this tool would provide the platform to research regardless of the "correctness" - as that could get me cancelled aye 😬</p>
<h2>What's Next</h2>
<p>So yeah go check it out here: <a href="https://github.com/tausani-ah-chong/faalupega-cli">Faalupega CLI on GitHub</a> - it's all open source. I decided to go with TypeScript/Node for now as we build up features and add more villages to the data set. And may port to Rust eventually.</p>
<p>Next steps is to add more villages! I've got 3 down, 149 to go. I also am in week 3 of my 10 week Faamatai course - getting this up and running will help myself with my homework and in future hopefully anyone else wanting to learn too.</p>
<hr>
<p><em>Thanks for reading! If you enjoyed this, follow me on Instagram <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a> and connect with me on LinkedIn <a href="https://www.linkedin.com/in/tausaniahchong"><strong>Tausani Ah Chong</strong></a>.</em></p>
<p><em>I'm posting every week until my birthday in April - tune in for the next one!</em></p>]]></content:encoded>
      <media:content url="https://tausani.net/blog/the-model-just-wants-to-use-tools/faalupega-setup.png" medium="image"/>
      <media:thumbnail url="https://tausani.net/blog/the-model-just-wants-to-use-tools/faalupega-setup.png"/>
    </item>
    <item>
      <title>Genuine in a World of Generated Content</title>
      <link>https://tausani.net/blog/genuine-in-a-world-of-generated-content/</link>
      <guid>https://tausani.net/blog/genuine-in-a-world-of-generated-content/</guid>
      <pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate>
      <description>Ok I kind of lied to you in my previous post/blog/tdd-or-just-tests and I apologise So I thought you know writing these posts would be a breeze now because there are many AI tools to help you write, e...</description>
      <content:encoded><![CDATA[<hr>
<p><em>🇼🇸 Talofa! O lo'u igoa o Tausani Ah Chong, e sau mai le nu'u o Puipa'a ma Avao</em></p>
<p><em>📍 Central Tāmaki Makaurau, Aotearoa</em></p>
<p><em>💼 Intermediate Software Developer @ Vector ⚡️</em></p>
<p><em>👨‍👩‍👧‍👦 Proud dad of 2 kids</em></p>
<p><em>📝 Post #3 - Posting every week until my birthday in April 🎂</em></p>
<hr>
<p><em>Follow me on Instagram! <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>
<p>Ok I kind of lied to you in my <a href="https://tausani.net/blog/tdd-or-just-tests">previous post</a> and I apologise</p>
<p>So I thought you know writing these posts would be a breeze now because there are many AI tools to help you write, (even before we had grammarly)</p>
<p>Ok so here we go,</p>
<p>my previous post was edited and some parts written by AI</p>
<p>whoopty doo right? Everything is written or thrown over to AI to improvise these days, but should everything?</p>
<h2>AI, Writing, and What We're Losing</h2>
<p>In a world now where we have flooded the internet with AI generated content, we actually lose the humanness. Now yes AI is great for repetitive tasks, and automation. But for writing?</p>
<p>I think this might be one of the few last frontiers, one of the last things we have, to be as genuine as we can online (apart from things like music and livestreamed content).</p>
<p>I can honestly say AI didn't write or help edit this for me. You are reading my thoughts directly from me, as raw as they are, you can't get much more human and genuine than that.</p>
<h2>A Story from Outside My Day Job</h2>
<p>A similar thing happened in a role outside of my day job. I want to share a story of mine of when I decided to put my hand up to be Secretary for my kids A'oga Amata (Samoan preschool) committee. And yes it does get more technical later down the post.</p>
<p>I previously had been on as a parent representative, and the former secretary was leaving so there was a gap. I knew taking on the role would be more involved but I just knew I had to step up. I had a few ideas and thought why not and lets use AI to help with the role and tasks</p>
<p>The main tasks are to schedule meetings, and take minutes during those minutes. So I thought lets get AI to help with taking minutes. At my current role for my day job as a Software Engineer we have access to those tools via Microsoft Teams and now with Slack AI tools. They kind of work ok and get the job done. But this time I need to be very careful with what to feed to AI to get back both transcripts and summaries. Privacy and confidentiality would be a big requirement.</p>
<h2>Testing a Local AI Solution</h2>
<p>So I thought what about using an AI tool that runs on my local machine and never talks to third party servers.</p>
<p>I researched and ended up finding a <a href="https://github.com/ggerganov/whisper.cpp">Whisper port</a>, based off the O***AI (The company who should not be named iykyk) model but ported to C++ for better performance. Did a couple manual tests beforehand with random audio and thought I would try it with a real meeting. So before our meeting, I asked for permission first if I could record and feed into my local AI tool. I then dumped the 1 hour .wav file into the tool and let it do its thing.</p>
<p>I got to test a few different models that you could download that works with the tool and definitely found varying results, some even got stuck in loops. v3-turbo-q5 ended up giving me the best results. Some were just pretty bad imo</p>
<p>I then tried to get a summary from the transcript and try get some tasks out of it. But I soon realised the quality was pretty bad too and unusable, and missed some pretty important points. Not to the mention the added complexity of Samoan language used throughout the recording.</p>
<p>I could tell off the bat the performance and quality gains are definitely with paid models but you have to live by their rules of stealing and using your data to train etc say bye to your privacy. This exercise got me to question do we really need to use AI for everything? Should you really just offload all tasks for AI improvise?</p>
<h2>Where the Rigor Goes</h2>
<p>In this case I came to the conclusion - back to reference the "where does the rigor go?" from my <a href="https://tausani.net/blog/tdd-or-just-tests">previous post</a> here - that it was a lot more accurate and critical if I actually took the effort to decide what and what shouldn't be taken down as minutes.</p>
<p>No one actually goes back to listen to the whole 1 hour meeting or want to read through a full wall of text.</p>
<p>Sure AI can summarise but how do I in the moment say ok at 22minutes 33 seconds take mark this task down as it's important. I may as well just use my pen and take it down right there and then. Intentional.</p>
<p>Putting intention to actively listen and scribe is a skill in its self, and putting effort and rigor in to making sure important actions are captured is waaaay better than letting AI improvise that. Maybe im a few prompts away from finding the perfect product for my use case - maybe I have to build this myself? Maybe you?</p>
<p>But to sum up, I think I made a good decision as I can still be intentional, which is where the rigor is. And yes its more effort, but without effort how can you expect to get better and grow in whatever your role is.</p>
<p>In a world full of generated content, I really do hope genuine content becomes higher impact and accessible. And if you feel you want more raw authentic content please leave a comment, share and follow along the journey.</p>
<p>Ia manuia le aso</p>
<hr>
<p><em>Thanks for reading! If you enjoyed this, follow me on Instagram <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a> and connect with me on LinkedIn <a href="https://www.linkedin.com/in/tausaniahchong"><strong>Tausani Ah Chong</strong></a>.</em></p>
<p><em>I'm posting every week until my birthday in April - tune in for the next one!</em></p>]]></content:encoded>
    </item>
    <item>
      <title>TDD or Just Tests? What I Learned Building a TDD Agent in a Weekend</title>
      <link>https://tausani.net/blog/tdd-or-just-tests/</link>
      <guid>https://tausani.net/blog/tdd-or-just-tests/</guid>
      <pubDate>Mon, 23 Feb 2026 00:00:00 GMT</pubDate>
      <description>Being a parent but also a software engineer learning about AI, the kagamea clothes washing doesn&apos;t stop, a&apos;e sele 😆 but what I love about folding time is chucking on a podcast. That&apos;s when I had my m...</description>
      <content:encoded><![CDATA[<hr>
<p><em>🇼🇸 Talofa! O lo’u igoa o Tausani Ah Chong, e sau mai le nu’u o Puipa’a ma Avao</em></p>
<p><em>📍 Central Tāmaki Makaurau, Aotearoa</em></p>
<p><em>💼 Intermediate Software Developer @ Vector ⚡️</em></p>
<p><em>👨‍👩‍👧‍👦 Proud dad of 2 kids</em></p>
<p><em>📝 Post #2 - Posting every week until my birthday in April 🎂</em></p>
<hr>
<p><em>Follow me on Instagram! <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>
<p>Being a parent but also a software engineer learning about AI, the kagamea (clothes washing) doesn't stop, a'e sele 😆 but what I love about folding time is chucking on a podcast. That's when I had my most recent aha moment, the one that made LLMs and agents finally click for me.</p>
<h2>The Aha Moment</h2>
<p>The podcast was <a href="https://www.pragmaticengineer.com/">The Pragmatic Engineer</a> (Gergely Orosz) interviewing Martin Fowler: <em>"How AI Will Change Software Engineering."</em></p>
<p>It's been a hot topic for a minute now, with takes coming from all sides. I take most of it with a grain of salt and try to experiment and play around myself. But Martin Fowler walked through the brief history of programming languages:</p>
<blockquote>
<p>Assembly → Fortran → C → Java → JavaScript → English (LLM prompts)</p>
</blockquote>
<p>Then he mentioned two words I'd always overheard but never really stopped to understand: <strong>determinism</strong> vs <strong>non-determinism</strong>. I don't know why I never paused on them before, but hearing it in context, and a quick ChatGPT prompt later, I had my aha moment.</p>
<p>Here's the thing: determinism vs non-determinism has always been a concept in computer science, but it never really landed for me day-to-day. You wrote code, the code did what you told it, and the output was predictable. The compiler wasn't going to surprise you.</p>
<p>But now? Now we have non-deterministic systems, LLMs, directly writing our deterministic code. That tension didn't exist before. Every time Claude Code or Codex generates an implementation, it could produce something slightly different from the last run. Same prompt, different code. That's a new problem, and it's why this distinction suddenly matters to every engineer, not just academics.</p>
<h2>Why You Should Care About Determinism vs Non-Determinism</h2>
<p>Non-determinism is where LLMs shine. It's a quality we humans share: same input, and the output can vary each time. It's why ChatGPT, Claude, and other LLMs can sound so human.</p>
<p>But <em>some</em> software demands strict determinism: same input → same output, every time. That's how we get predictable, trustworthy behaviour.</p>
<p>When we use tools like Claude Code and Codex, we're trading some of that predictability for speed and output. And when you have critical software that must behave predictably, that trade-off becomes the biggest risk in the room.</p>
<h2>What Levers Can We Pull?</h2>
<p>A recent <a href="https://www.thoughtworks.com/content/dam/thoughtworks/documents/report/tw_future%20_of_software_development_retreat_%20key_takeaways.pdf">ThoughtWorks retreat</a>, where Martin Fowler has worked for many years, brought together senior engineering practitioners from major technology companies to confront the questions that matter most as AI transforms software development.</p>
<p>Their full document is worth reading, but the line that piqued my interest was:</p>
<blockquote>
<p><em>"Where does the rigor go?"</em><br>
Engineering quality doesn't disappear… it migrates to specs, tests, constraints, and risk management.</p>
</blockquote>
<p>I decided I wanted to tackle the <strong>tests</strong> part, specifically with Test-Driven Development (TDD).</p>
<h2>Can TDD Increase Determinism?</h2>
<p><img src="https://tausani.net/blog/tdd-or-just-tests/tdd-cycle.svg" alt="Comparison of all four TDD approaches across prompt, mechanism, tests generated, coverage, process verification, and audit trail"></p>
<p>This weekend I took Claude Code for a drive to see how much we can influence LLM outputs. Can TDD act as a guardrail that pushes AI-generated code toward more predictable, deterministic behaviour?</p>
<p>I tested four approaches, all given the same prompt:</p>
<blockquote>
<p><em>"Please complete this task: A user registration service that validates email, hashes a password, and saves to an in-memory store - split across validator.ts, hasher.ts, userStore.ts, registrationService.ts"</em></p>
</blockquote>
<p>Here's what happened with each.</p>
<hr>
<h3>1. Custom TDD Coding Agent</h3>
<p>This was the most fun and gave me the most challenge and learnings, not that I manually wrote any of the code, but the rigor was still there.</p>
<p>The agent wraps the Claude API directly and enforces strict red-green-refactor through phase gating: it only transitions between phases based on test outcomes, limits Claude to one <code>it()</code> block per turn, and enforces minimum implementation. Coming from a frontend web dev background, I quickly learned you need to treat LLM API responses just like any other API call. Account for failures, non-deterministic output, and what the experience looks like when there isn't a happy path.</p>
<p>It got me thinking: what should the user experience be when you're getting an LLM to do TDD? Should the user be in the driver's seat approving each cycle? Or fully commit and wait for the PR? That question led me to build history and snapshots of files during each cycle, a frame-by-frame replay of the TDD loop that's invaluable for review.</p>
<p>Every file write is archived in <code>sandbox/history/{runId}/iteration-{n}-{phase}-{filename}</code>. This gives a complete frame-by-frame replay of the TDD loop</p>
<p>The biggest downside is the lack of full capabilities like directory traversal, things Claude Code handles natively. But it's custom, and with more time you could craft a very focused TDD-style user experience.</p>
<p><img src="https://tausani.net/blog/tdd-or-just-tests/tdd-agent-demo.gif" alt="tdd-agent running the red-green-refactor loop"></p>
<p><strong>Source code:</strong> <a href="https://github.com/tausani-ah-chong/tdd-agent">tdd-agent</a></p>
<hr>
<h3>2. Claude Code with TDD Hooks</h3>
<p>This approach gets the best of both worlds: the power of Claude Code, plus stop gates that enforce TDD before the agent writes implementation code.</p>
<p>We wrote two hooks wired into Claude Code's <a href="https://code.claude.com/docs/en/hooks-guide">PreToolUse and PostToolUse events</a> that intercept all file writes. The pre-hook blocks any implementation write if a corresponding <code>.test.ts</code> file doesn't already exist. The post-hook runs <code>npm test</code> after every write. For test files it expects failure (red phase), for implementation files it blocks if tests fail and signals green if they pass.</p>
<p>This creates an enforcement loop that Claude Code shouldn't be allowed to bypass. No test file? No implementation. Blocking happens at the tool level, not the prompt level, making it much harder to avoid. And it works with any codebase or language; just change the test command.</p>
<p>The trade-off: no audit trail or cycle snapshots, and hooks verify test existence and pass/fail state, not test quality.</p>
<p>Below is what <code>settings.json</code> looks like to configure hooks</p>
<pre><code class="language-json">{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "tsx .claude/hooks/tdd-pre.ts"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "tsx .claude/hooks/tdd-post.ts"
          }
        ]
      }
    ]
  }
}
</code></pre>
<p><strong>Source code:</strong> <a href="https://github.com/tausani-ah-chong/tdd-hooks/tree/main/.claude/hooks">tdd-hooks</a></p>
<hr>
<h3>3. Vanilla Claude Code (No TDD)</h3>
<p>You guessed it, zero tests written. But in its defence, it stuck to what the prompt asked and wrote all the code in 8 seconds.</p>
<p>The untested code is still professional-looking: SCRYPT hashing, timing-safe comparison, UUID generation, email normalisation, sanitised return objects. But it's all unverifiable without tests and has no regression protection.</p>
<hr>
<h3>4. Claude Code with a TDD Prompt</h3>
<p>This was the most interesting approach, not because it's the best, but because it looked like TDD without actually being TDD.</p>
<p>Tests before files. All tests pass. Clean code. And it produced 29 tests, more than double the 13 from either enforcement approach. But the full suites were written in one batch.</p>
<p>As I watched, the "red" was triggered by missing imports, not failing assertions. This is a subtle but important distinction. Authentic TDD red means: "I have a working implementation, and this new test exposes a behaviour it doesn't yet handle." What happened here was: "The file doesn't exist, so the entire test suite crashes at import." The implementation was then written to make the full batch of tests green in one go.</p>
<p>It was the most pepelo (deceptive) of the results, and the most useful illustration of why "tests exist" ≠ "TDD was followed."</p>
<p>Because the full suite of tests was created upfront, this was closer to Spec-Driven Development (SDD), a legit workflow, but just a different process to red-green-refactor.</p>
<hr>
<h2>So, Did We Actually Increase Determinism?</h2>
<p><img src="https://tausani.net/blog/tdd-or-just-tests/tdd-comparison.png" alt="Side-by-side comparison of test counts and coverage across approaches"></p>
<h3>The one-<code>it()</code>-at-a-time constraint is everything</h3>
<p>This is what separates TDD from SDD. The custom agent enforces it explicitly, "add exactly ONE new <code>it()</code>." Hooks enforce it implicitly, the post-hook runs tests after each write, so Claude learns to write one test and get it green before writing the next. The prompt-only approach gets the file ordering right but misses the granularity, and that's why it produced 29 tests to the enforcement approaches' 13. More tests, but less discipline. Claude planned the full suite as a spec, then implemented against it in one go.</p>
<h3>Why this matters for non-determinism</h3>
<p>The real argument for TDD with AI isn't just about discipline, it's that the one-test-at-a-time constraint forces the LLM to make minimal, testable changes. That reduces the surface area for non-deterministic drift. Instead of generating an entire implementation in one shot (where the model has maximum freedom to vary), TDD pins the model to small, verifiable steps.</p>
<p>Think of it as a spectrum of enforcement strength:</p>
<pre><code class="language-text">No tests          Tests exist (unverified process)       Tests + verified process
    |                          |                                |
 no-hooks              tdd-prompt-only                tdd-hooks / tdd-agent
</code></pre>
<p>Without guardrails, the LLM's implementation strategy is entirely non-deterministic. SCRYPT vs SHA256, class vs function, sync vs async are all free choices with no specification to anchor them. With prompt-only TDD, the tests specify behaviour, but the process could vary between runs. With hook or agent enforcement, every step is constrained. The failing test at each phase narrows the next implementation decision, pushing toward convergence across runs.</p>
<p>We also saw this play out in a concrete way: the unconstrained approaches added methods that weren't part of the original prompt. Extra helpers, convenience functions, things the model decided were useful on its own. In some ways, that's the upside of non-determinism, like a colleague who went above and beyond and took initiative. But is that what you want all the time? Probably not. That's ultimately up to whoever's in the driver's seat.</p>
<h3>When to use what</h3>
<p>If you're just vibe-coding a prototype, skip TDD. If you already have a clear mental model of the interface and just want it tested, prompt-only TDD is probably good enough.</p>
<p>But if you have critical software where mistakes are expensive, or complex domain logic where the design needs to emerge test-by-test, that's where enforced TDD pays for itself.</p>
<p>Claude hooks are the practical middle ground. They enforce the process mechanically without requiring developers to trust the model's self-reporting, and they scale to any project without custom infrastructure. With the downside that you're locked in to only using Anthropic models and agents. After a quick search not even Codex has this feature, it was actually a <a href="https://github.com/openai/codex/pull/2904">rejected PR from OpenAI</a>.</p>
<p>The core finding in one sentence: <strong>prompt-only TDD gets you a tested codebase; enforced TDD gets you a codebase that was built by tests, and only the enforcement approaches can prove the difference.</strong></p>
<p>The possibilities are endless if you go full custom agent, which sounds like a viable approach for companies that care about their products.</p>
<hr>
<h2>What I Took Away</h2>
<p>I think we achieved it. The enforcement approaches (the custom agent and the hooks) demonstrably constrained the model's freedom at each step, and that's exactly what determinism is about: narrowing the space of possible outputs. Did both runs produce identical code? No. But they converged on the same structure, same coverage, same process. That's meaningful. The custom TDD agent flow could genuinely be its own product, with a proper UI and UX for reviewing each TDD cycle. I have more ideas now than I did before I started.</p>
<p>That's the move: start building, and let the experiments teach you.</p>
<hr>
<p><em>Thanks for reading! If you enjoyed this, follow me on Instagram <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a> and connect with me on LinkedIn <a href="https://www.linkedin.com/in/tausaniahchong"><strong>Tausani Ah Chong</strong></a>.</em></p>
<p><em>I'm posting every week until my birthday in April - tune in for the next one!</em></p>]]></content:encoded>
      <media:content url="https://tausani.net/blog/tdd-or-just-tests/tdd-cycle.svg" medium="image"/>
      <media:thumbnail url="https://tausani.net/blog/tdd-or-just-tests/tdd-cycle.svg"/>
    </item>
    <item>
      <title>First Post 2026 - Shipping Code Feels Safe, Sharing Opinions Feels Risky</title>
      <link>https://tausani.net/blog/first-post-2026/</link>
      <guid>https://tausani.net/blog/first-post-2026/</guid>
      <pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate>
      <description>Ok I&apos;m nervous my managers might read this. Because I&apos;m finally saying what I actually think. 👀 You know that whole, &quot;know your strengths and weaknesses&quot; thing? Straight up, writing about Software ac...</description>
      <content:encoded><![CDATA[<hr>
<p><em>🇼🇸 Talofa! O lo’u igoa o Tausani Ah Chong, e sau mai le nu’u o Puipa’a ma Avao</em></p>
<p><em>📍 Central Tāmaki Makaurau, Aotearoa</em></p>
<p><em>💼 Intermediate Software Developer @ Vector ⚡️</em></p>
<p><em>👨‍👩‍👧‍👦 Proud dad of 2 kids</em></p>
<hr>
<p><em>Follow me on Instagram! <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>
<p>Ok I'm nervous my managers might read this.<br>
Because I'm finally saying what I actually think. 👀</p>
<p><strong>You know that whole, "know your strengths and weaknesses" thing?</strong><br>
Straight up, writing about Software actually scares me.<br>
I would hand brake and side step if I was to run it straight to writing (Imagine <a href="https://www.instagram.com/runnation/">RunNation</a> but for technical writing)</p>
<p>Take this:</p>
<p>Me building software at speed, writing seki code, shipping features?<br>
<strong>On.</strong> Confidence through the roof.</p>
<p>Writing or getting asked about my honest thoughts and takes?<br>
<strong>Yeah Nah.</strong></p>
<p>If you've ever felt confident building but can't fully express yourself, then this might be for you.</p>
<p>This series of posts will be snapshots of the journey of how<br>
a half-caste Samoan,<br>
born in Central Auckland Aotearoa NZ,<br>
musician (producer/DJ/radio host) turned Software Engineer at 30,<br>
now a Dad,<br>
recently bestowed as Matai for my family,<br>
is getting better at putting full, honest thoughts on paper and out there to you.</p>
<p>My biggest strengths lie in grinding.<br>
Teaching myself through tinkering.<br>
Staying curious into late nights.<br>
Sniffing out what's wrong or missing.<br>
Being clear about what I like vs what I don't.</p>
<p>I learned that all from making music and transferred to software.</p>
<p><strong>But when it comes to technical opinions? I freeze.</strong></p>
<p>But this is part of being a great Engineer. You don't just ship. You explain <em>why</em>. You defend <em>why</em>. You question <em>why not</em>.<br>
Shipping code feels safe to me.<br>
Sharing opinions about software feels risky.</p>
<hr>
<p>So here's the goal. <strong>1 post a week until my birthday in April.</strong></p>
<p><strong>7 posts. 2 rules:</strong></p>
<ol>
<li>Make 7 posts.</li>
<li>Make the last one better than the first.</li>
</ol>
<p>Let me know, does this count as 1 of 7? Or is this the prequel?</p>]]></content:encoded>
    </item>
    <item>
      <title>Malo lava, let&apos;s build with Cursor —AI Code Editor</title>
      <link>https://tausani.net/blog/malo-lava-lets-build-with-cursor/</link>
      <guid>https://tausani.net/blog/malo-lava-lets-build-with-cursor/</guid>
      <pubDate>Sat, 24 Aug 2024 00:00:00 GMT</pubDate>
      <description>🇼🇸 Malo le soifua Growing up in central Aukilagi our family house was in Grey Lynn. In the late 90&apos;s, I went to a full immersion 100% samoan speaking a&apos;oga amata Pre school called A&apos;oga Fa&apos;asamoa, l...</description>
      <content:encoded><![CDATA[<hr>
<p><em>🇼🇸 Talofa! O lo’u igoa o Tausani Ah Chong, e sau mai le nu’u o Puipa’a ma Avao</em></p>
<p><em>📍 Central Tāmaki Makaurau, Aotearoa</em></p>
<p><em>💼 Intermediate Software Developer @ Vector ⚡️</em></p>
<p><em>👨‍👩‍👧‍👦 Proud dad of 2 kids</em></p>
<hr>
<p><em>Follow me on Instagram! <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>
<h1>🇼🇸 Malo le soifua</h1>
<p>Growing up in central Aukilagi our family house was in Grey Lynn. In the late 90's, I went to a full immersion (100% samoan speaking) a'oga amata (Pre school) called A'oga Fa'asamoa, located in Ponsonby — The first of its kind in NZ. Opened by the late Papali'i Dr Pita Taouma and wife Jan Taouma</p>
<p><a href="https://www.thecoconet.tv/coco-docos/pacific-history/island-archives-aoga-faa-samoa/">Read info here!</a></p>
<p>Aaaanyways — My 2 kids currently attend the very same A'oga amata, where im also on the Commitee/Board as a Parent rep — My first question in my first Committee meeting was — "Who maintains the school website?"</p>
<p>Ended up finding out that it was a previous committee member Riki Apa who built it and was launched in 2004 — I saw a chance to modernise it 20 years later, as UI and UX hasn't changed since then</p>
<p><strong>This below is the current website</strong></p>
<p><a href="https://www.aogafaasamoa.school.nz/">https://www.aogafaasamoa.school.nz/</a></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_5.29.39_PM.png" alt="Screenshot 2024-08-24 at 5.29.39 PM"></p>
<hr>
<h1>Tools for the build</h1>
<p>So yo, off the bat I wanted to have a jam at trying out <a href="https://www.cursor.com/">Cursor — The AI Code Editor</a></p>
<p>I also wanted to have a go at also:</p>
<ul>
<li>Hosting on a AWS S3 bucket (I've only ever used Vercel to deploy)</li>
<li>GitHub Actions to deploy to S3</li>
</ul>
<hr>
<h2>Cursor (IDE)</h2>
<p>Before you start using Cursor, you'll need to configure what models you want to use.</p>
<p>You can sign up to Cursor Pro which has their own features I decided to just roll with the free features</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_6.00.49_PM.png" alt="Screenshot 2024-08-24 at 6.00.49 PM"></p>
<p>You need to also supply you api keys</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_6.01.18_PM.png" alt="Screenshot 2024-08-24 at 6.01.18 PM"></p>
<h3>Built in chat feature</h3>
<p>With Cursor the main feature is you don't have to open up a browser or another app to ask your questions or revise some code. You just can just stay inside your IDE to chat to the model of your choice.</p>
<blockquote>
<p>You can either:</p>
<ol>
<li>Chat in-line, with <code>cmd + K</code> or</li>
<li>Open chat panel <code>cmd + L</code></li>
</ol>
</blockquote>
<p><strong>In-line chat</strong></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_6.16.24_PM.png" alt="Screenshot 2024-08-24 at 6.16.24 PM"></p>
<p><strong>Chat panel</strong></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_6.17.59_PM.png" alt="Screenshot 2024-08-24 at 6.17.59 PM"></p>
<p>I enjoyed the flow of creating with Cursor, it says it looks through your repo as context so keep that in mind if you decide to work on a repo that has personal or other information you don't want to link back to OpenAI or Anthropic.</p>
<p>Although even though it looked through the whole repo I still had to reply to some generated code and make sure to use tailwind to style for example, I would have expected that I didn't need to do that.</p>
<hr>
<h2>AWS S3</h2>
<p>Pretty simple setup, but would be a lot simpler with a tool like Terraform, but for this I configured all in the console.</p>
<ol>
<li>Create S3 bucket</li>
<li>Make it public</li>
<li>Enable static website hosting</li>
<li>Add bucket policy (permissions)</li>
</ol>
<p>Create your S3 bucket</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/create.png" alt="create.png"></p>
<p>Name your S3</p>
<p>Its good to be quite specific</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/name-s3.png" alt="name-s3.png"></p>
<p>Un-check <code>Block all public access</code></p>
<p>Check the box that you acknowledge. We will be using for static website hosting.</p>
<p>"AWS recommends that you turn on block all public access, <em><strong>unless public access is required for specific and verified use cases such as static website hosting.</strong></em>"</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/public-s3.png" alt="public-s3.png"></p>
<p>In <code>Properties</code> tab scroll all the way down</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/scroll.png" alt="scroll.png"></p>
<p>Select <code>Edit</code> to configure Static website hosting</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/edit-static.png" alt="edit-static.png"></p>
<p>Enable <code>Static website hosting</code> and check <code>Host a static website</code></p>
<p>You will need to double check the output of the static files from running a <code>build</code> command. It might be different per framework.</p>
<p>e.g. using Next</p>
<p><code>next build</code> generates a <code>/out</code> dir and populates <code>/out/index.html</code> and <code>/out/404.html</code> files</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/static.png" alt="static.png"></p>
<p>You will now see a URL populate so you can view your website</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/static-url.png" alt="static-url.png"></p>
<p>Next go to <code>Permissions</code> tab and select <code>Edit</code> to configure <code>Bucket policy</code></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/edit-policy.png" alt="edit-policy.png"></p>
<pre><code class="language-json">{
  "Version": "2012-10-17",
  "Id": "Policy1724460713351",
  "Statement": [
    {
      "Sid": "Stmt1724460711669",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": "arn:aws:s3:::&#x3C;your S3 bucket name>/*"
    }
  ]
}
</code></pre>
<p>Paste in the above policy.</p>
<p>I ran into getting a <code>403</code> from trying to hit the url if you don't do this step.</p>
<p>Now you're all set to upload your code.</p>
<p>I decided to use <code>GitHub actions</code> to upload whenever I push to <code>main</code></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/paste-policy.png" alt="paste-policy.png"></p>
<hr>
<h2>GitHub Actions</h2>
<p><strong>Simple steps also:</strong></p>
<ol>
<li>Generate yaml file</li>
<li>Add AWS secrets</li>
</ol>
<p>You could just create a <code>/&#x3C;your-app>/.github/workflows/main.yml</code> file without going through the GitHub website but I'll show anyways</p>
<p>Select <code>Actions</code> tab</p>
<p>Select <code>set up a workflow yourself</code></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/setup-actions.png" alt="setup-actions.png"></p>
<p>All you need to do is edit the <code>main.yml</code></p>
<p>Run your specific commands to build your app</p>
<p>Run command that will upload all contents from <code>/out</code> directory to your S3 and delete other contents beforehand</p>
<p>Make sure you're <code>AWS_REGION</code> matches for where you created your bucket</p>
<p>Commit your changes</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/yaml.png" alt="yaml.png"></p>
<p>Next you'll need to populate your <code>AWS_ACCESS_KEY_ID</code> and <code>AWS_SECRET_ACCESS_KEY</code> Repository secrets, so the above GitHub Action will work</p>
<p>You can add in <code>Settings</code> tab, clicking on <code>Actions</code> under <code>Secrets and variables</code></p>
<p>Now you're setup so any changes merged to <code>main</code> will now trigger to upload your artifacts to S3</p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_7.48.30_PM.png" alt="Screenshot 2024-08-24 at 7.48.30 PM"></p>
<hr>
<h1>Results</h1>
<p>So yeah thats me! Keep in mind this was just a quick weekend quest lol so time was limited.</p>
<p>Here are some changes I wanted to focus on for the first cut:</p>
<ul>
<li>Make use of full width of screen</li>
<li>Modernise the font and keep them consistent (There are a few different fonts used in Before)</li>
<li>Simplify the user experience
<ul>
<li>Much like 90's, 2000's style of making the website so accessible, to the point where there are multiple links and entry points to navigate the website. It ends up clogging up the page and actually confuses the user</li>
<li>Im hoping to keep the navigation in a single place at the top, and reduce the amount of information overload for each page</li>
</ul>
</li>
</ul>
<blockquote>
<p>I may keep expanding on the site, but all in all the main learnings came from the journey of creating:</p>
<ul>
<li>First time using Cursor</li>
<li>First time hosting on S3</li>
<li>First time using GitHub Actions</li>
</ul>
<p>Thats the part Im mostly happy about, and anything after is just a bonus</p>
</blockquote>
<p><strong>Make sure to check out both sites below and let me know your thoughts if you enjoyed this!</strong></p>
<p><strong>Ia fa</strong></p>
<h3>Before</h3>
<p><a href="https://www.aogafaasamoa.school.nz/">Link to website</a></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_5.29.39_PM%201.png" alt="Screenshot 2024-08-24 at 5.29.39 PM"></p>
<h3>After</h3>
<p><a href="http://aoga-faasamoa-web-ui-s3.s3-website-ap-southeast-2.amazonaws.com/">Link to website</a></p>
<p><img src="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_5.47.15_PM.png" alt="Screenshot 2024-08-24 at 5.47.15 PM"></p>
<hr>
<p><em>🇼🇸 Talofa! O lo’u igoa o Tausani Ah Chong, e sau mai le nu’u o Puipa’a ma Avao</em></p>
<p><em>📍 Central Tāmaki Makaurau, Aotearoa</em></p>
<p><em>💼 Intermediate Software Developer @ Vector ⚡️</em></p>
<p><em>👨‍👩‍👧‍👦 Proud dad of 2 kids</em></p>
<hr>
<p><em>Follow me on Instagram! <a href="https://www.instagram.com/tausani.376"><strong>@tausani.376</strong></a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>]]></content:encoded>
      <media:content url="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_5.29.39_PM.png" medium="image"/>
      <media:thumbnail url="https://tausani.net/blog/malo-lava-lets-build-with-cursor/Screenshot_2024-08-24_at_5.29.39_PM.png"/>
    </item>
    <item>
      <title>🤖 I built a Slack ChatGPT Bot</title>
      <link>https://tausani.net/blog/i-built-a-slack-chatgpt-bot/</link>
      <guid>https://tausani.net/blog/i-built-a-slack-chatgpt-bot/</guid>
      <pubDate>Thu, 23 Mar 2023 00:00:00 GMT</pubDate>
      <description>Malo le soifua! This is my first digital garden post - Whoop whoop! I&apos;ve been holding back a bit, with my excuse being that I haven&apos;t found the right project to build or topic to choose. Lately I&apos;ve b...</description>
      <content:encoded><![CDATA[<hr>
<p><em>Talofa! I’m Tausani, Junior Software Engineer @ <a href="https://halterhq.com/">Halter</a> shaping the future of dairy farming 🐄</em></p>
<p><em>I'm a proud dad of 2 👨‍👩‍👧‍👦</em></p>
<p><em>Just over 18 months into coding, where I transitioned from a music production background 🎹 to software after a 15-week bootcamp @ <a href="https://devacademy.co.nz/">Dev Academy Aotearoa</a></em></p>
<p><em>In my spare time (Which isn’t much with a small family!) I'm embracing the #BuildInPublic movement.</em></p>
<p><em>Always keen to learn and grow!</em></p>
<hr>
<p><em>Follow me on <strong>Twitter</strong>! <a href="https://twitter.com/tausani93"><strong>@tausani93</strong></a></em></p>
<p><em>Join the <strong>Pasifika Tech Network discord</strong> using <a href="https://docs.google.com/forms/d/e/1FAIpQLSf-uH02Pawmwkf0FIXHoUdyX_zjJyzhBXNkezZph6lGf3EA8Q/viewform">this form</a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>
<h1>Malo le soifua!</h1>
<p>This is my first digital garden post - Whoop whoop!</p>
<p>I've been holding back a bit, with my excuse being that I haven't found the right project to build or topic to choose.</p>
<p>Lately I've been inspired by my fellow peers in the <strong>Pasifika Tech Network discord</strong> as we share our new learnings and geek out about all things tech, with a island flavour of course. I've also been inspired by tech twitter raving about ChatGPT and posting about their projects, so I thought it was time I had a go.</p>
<p>Pretty much in this post, I'll go you through an overview rather than a deep dive of the process of building a Slack ChatGPT bot, and some the challenges and the learnings I gained.</p>
<ul>
<li>Repo: <a href="https://github.com/tausani-ah-chong/ask-chatgpt">https://github.com/tausani-ah-chong/ask-chatgpt</a></li>
<li>End result:</li>
</ul>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_1.15.13_PM.png" alt="Screenshot 2023-03-22 at 1.15.13 PM"></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_1.15.38_PM.png" alt="Screenshot 2023-03-22 at 1.15.38 PM"></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_1.15.49_PM.png" alt="Screenshot 2023-03-22 at 1.15.49 PM"></p>
<h3>Agenda:</h3>
<ul>
<li>Set up new Slack App/bot</li>
<li>Bolt + Slack API for App Mentions and Slash Commands</li>
<li>OpenAI/ChatGPT API for Completions</li>
<li>Learnings When Using ChatGPT to Guide You</li>
<li>Hosting, Security, and Privacy Concerns</li>
</ul>
<hr>
<h3>Setup new Slack App/bot</h3>
<p>To check set up a new Slack app/bot start off by following <a href="https://api.slack.com/apps?new_granular_bot_app=1">this link</a></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_12.10.43_PM.png" alt="Screenshot 2023-03-22 at 12.10.43 PM"></p>
<p>Once you're in you'll need to also need to add scopes/permissions so that you can use the App mentions and slash commands:</p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_12.14.24_PM.png" alt="Screenshot 2023-03-22 at 12.14.24 PM"></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_12.14.49_PM.png" alt="Screenshot 2023-03-22 at 12.14.49 PM"></p>
<hr>
<h3>Bolt + Slack API for App Mentions and Slash Commands</h3>
<p><a href="https://api.slack.com/bolt">Bolt</a> is a user-friendly framework developed by Slack that simplifies building Slack apps. Think <a href="https://expressjs.com/">ExpressJS</a> but with a layer on top for Slack API methods</p>
<p>Now you can enable the App mentions events + create slash command by setting up your URL in 2 places</p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_12.13.51_PM.png" alt="Screenshot 2023-03-22 at 12.13.51 PM"></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_12.11.09_PM.png" alt="Screenshot 2023-03-22 at 12.11.09 PM"></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_12.12.32_PM.png" alt="Screenshot 2023-03-22 at 12.12.32 PM"></p>
<p><strong>A couple things tripped me up here:</strong></p>
<ol>
<li>Make sure to use <code>{your-hosted-URL}/slack/events</code>
<ol>
<li>I thought I could create any route but turns out it <strong>needs</strong> to end with <code>/slack/events</code> for both commands to work. Wasn't clear at all in the docs which took a bit of time trying to debug why I was getting errors</li>
</ol>
</li>
<li>You need to verify your App URL
<ol>
<li>Setting up an event for app mentions also required a specific URL for verification, and the documentation lacked clear examples of the necessary HTTP methods.</li>
<li>You'll need a POST route that returns a <code>challenge</code> parameter</li>
</ol>
</li>
<li>Don't use Express &#x26; Bolt at the same time
<ol>
<li>I tried to use Express to create my POST route (In my defence ChatGPT imported Express as well as Bolt) i.e. I had Express routes for my POST route and Bolt for my command routes</li>
<li>Instead use the 'ExpressReceiver' method to handle Express-like functionality without importing both Express and Bolt.</li>
</ol>
</li>
</ol>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/bolt.png" alt="bolt.png"></p>
<p>From there you can also write your command methods</p>
<p><strong>Slash command:</strong></p>
<p>i.e. <em>/ask-chatgpt [question]</em></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/slasj.png" alt="slasj.png"></p>
<p><strong>App mention:</strong></p>
<p>i.e. <em>@ask-chatGPT [question]</em></p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/appMention.png" alt="appMention.png"></p>
<hr>
<h3>OpenAI API for Completions</h3>
<p>Once your Slack app is configured you can now we can use the openAI API - <a href="https://platform.openai.com/docs/api-reference/completions">OpenAI API docs</a>.</p>
<p><strong>One learning here:</strong></p>
<h3><em>Always read the API spec/docs!</em></h3>
<p>I know it sounds cliche but because I was using ChatGPT to guide me making this I relied on it a bit too much that I didn't read the docs. I made an obvious mistake in hindsight.</p>
<p>ChatGPT gave me an outdated URL which took way too much time for me to debug. I guess that happens when the dataset was from 2022.</p>
<p><em>Yup blame ChatGPT not the developer aye</em></p>
<p>But hey, it was a good lesson learned. This is why you always need to get your hands dirty, and try build something from scratch.</p>
<p>Anyways heres the code (For the current API spec lol this may change in the future)</p>
<p><img src="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/chatGPT-api.png" alt="chatGPT-api.png"></p>
<hr>
<h3>Learnings When Using ChatGPT to Guide You</h3>
<p>So yeah back to blaming ChatGPT (lol im kidding) I think doing this project definitely cemented that AI isn't just ready yet, and our jobs are safe <strong>(for now)</strong></p>
<p>Be aware of potential <strong>hallucinations</strong> and outdated information. Just use it as a tool. Foundational knowledge is still super important for you to make the best judgement.</p>
<p>Was still a fun way to build software though, definitely will carry on using ChatGPT (I think thats a no brainer) It still helped me get probably 70% of the project built.</p>
<p>Cool explanation about <strong>Hallucinations</strong> with AI:</p>
<p><a href="https://www.youtube.com/watch?v=6_hjykO03N0">https://www.youtube.com/watch?v=6_hjykO03N0</a></p>
<hr>
<h3>Hosting, Security, and Privacy Concerns</h3>
<p>I only got it to work properly locally, but I did try host on Vercel but requests kept timing out. My guess is because I was using the Hobby account. But I still need to deep dive further. Maybe you could help me!</p>
<p>I also had to consider privacy and security concerns as I would have needed to store chat data in database on the server. So decided this was a little bit too out of scope for this project.</p>
<p>I just ended up using an in-memory solution to store the chat data</p>
<hr>
<h3>Conclusion</h3>
<p>Building the Slack ChatGPT bot was a valuable learning experience, despite the time spent debugging the Slack and ChatGPT APIs. I gained insights into the Bolt framework, Slack API, and ChatGPT API, which will undoubtedly be useful for future projects. I hope that sharing my challenges and learnings can help others working on similar projects or those who are just getting started.</p>
<p>Feel free to check out the repo: <a href="https://github.com/tausani-ah-chong/ask-chatgpt">https://github.com/tausani-ah-chong/ask-chatgpt</a></p>
<h3>On a closing note</h3>
<p>I want to highlight the amazing <strong>Pasifika Tech Network</strong> community. After sharing a screen recording of my project on the discord server, the head honcho OG said he was "nerd sniped" and built a ChatGPT bot for our discord within the same day. This is a prime example of community and inspiration from peers. I love this community and can't wait to see what we'll achieve together in the future.</p>
<hr>
<h3>🌱 Want to build your own Digital garden?</h3>
<p>Follow this <a href="https://geraldtui.super.site/posts/how-to-setup-a-website-using-notion-and-super">guide from Gerald Tuimalealiifano</a> who is also part of the dream team on the <strong>Pasifika Tech Network discord</strong></p>
<hr>
<p><em>Follow me on <strong>Twitter</strong>! <a href="https://twitter.com/tausani93"><strong>@tausani93</strong></a></em></p>
<p><em>Join the <strong>Pasifika Tech Network discord</strong> using <a href="https://docs.google.com/forms/d/e/1FAIpQLSf-uH02Pawmwkf0FIXHoUdyX_zjJyzhBXNkezZph6lGf3EA8Q/viewform">this form</a></em></p>
<p><em>GitHub: <a href="https://github.com/tausani-ah-chong">https://github.com/tausani-ah-chong</a></em></p>
<hr>]]></content:encoded>
      <media:content url="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_1.15.13_PM.png" medium="image"/>
      <media:thumbnail url="https://tausani.net/blog/i-built-a-slack-chatgpt-bot/Screenshot_2023-03-22_at_1.15.13_PM.png"/>
    </item>
  </channel>
</rss>
