<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Rasyidan&apos;s Personal Website</title><description>Personal website of Rasyidan Akbar F - AI/ML Engineer and tech enthusiast</description><link>https://rasyidanaf.com/</link><language>en-us</language><item><title>AI-powered Development: Less Code, Max Shipping</title><link>https://rasyidanaf.com/blog/ai-dev-less-code-max-shipping/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/ai-dev-less-code-max-shipping/</guid><description>Discover the future of software development with AI, enabling faster app builds and shipping with minimal coding. This playbook explores the tools and strategies to maximize impact.</description><pubDate>Tue, 24 Dec 2024 00:00:00 GMT</pubDate><content:encoded>Nowadays, you can build apps without knowing how to code even not writing single line of code with AI tools. A lot of people with no coding/programming background already shipped their apps (SaaS) with help of AI tools without writing a single line of code.

&gt; But, there would be a lot of errors and bugs, and the app wouldn&apos;t work anyway especially on production.

Well you can just debug and fix the errors, ask LLM to fix the code, improve the code, explain the code, and repeat the process until it&apos;s done. Also read the error messages so you can understand what&apos;s wrong, the root cause of it, and how to fix it.

&gt; *It only works for simple apps or MVP, you can&apos;t use AI to build more complex apps or bigger projects.*

I saw a lot of people with no coding background or experience able to ship their apps through AI tools, so all I can say is it&apos;s skill issue. **You can just do the thing now**.

Even though I&apos;m quite optimistic that people with no coding background or experience can ship their apps through AI tools, they still need to learn and understand **the basics and foundation of software development** especially core developer tools such as git, docker also know how websites and computer works. What i mean by how websites and computer works is you understand how is the internet works, how website is hosted, what&apos;s api, basic data structure, and the list goes on. People with engineering/CS background have more privilege to build things as they know *the fundamentals* of problem solving such as breaking down the main problem into smaller sub-problems (modularization), identifying the root cause of the problem, algoritm, archtecture &amp; system design, discreth math etc. I can say this as biomedical engineering graduate that learned basic engineering, programming, and network communication in university and it&apos;s literally help me a lot on programming part.

The you learn more about it, more benefit you will get in the long run when you are building things through ~~code~~ AI tools. You still have to review code that generated by AI wheever it&apos;s implement best practices for your specific app or it just generate *slop* code. This is important because several times I&apos;ve reviewed code that generated by LLM and many of it does not implement code that i want and some of it breaking the app (even make the app worse).

There is many AI tools out there, but I&apos;m only going to cover the tools I use. Current AI tools I use for both prototyping and production-grade level app development:

- [Cursor](https://www.cursor.com/) as the default IDE for AI-pair programming
- [v0](https://v0.dev) to generate/modify UI components, pretty UI prototyping
- [Bolt](https://bolt.new) as a fullstack app generation platform, can be used as MVP/prototyping and production-grade level apps as it&apos;s support Supabase now
- [Lovable](https://lovable.dev/), previously GPT Engineer, AI fullstack software engineer (I would say Lovable is Bolt competitor). Lovable is commercial version of GPT Engineer, you can still use GPT Engineer (open source) [here](https://github.com/gpt-engineer-org/gpt-engineer)
- [Claude](https://claude.ai/new) for coding assistance in general (still the best LLM for coding/app development for me especially web development) and its API key. Don&apos;t forget to use Sonnet 3.5 one
- [ChatGPT](https://chatgpt.com/) for brainstorming and idea generation (Gemini &amp; Claude  might work too). It&apos;s newest model, o1, is so good for coding and math too
- [Aider](https://github.com/Aider-AI/aider), AI pair programming in your terminal (rarely use it)
- [Replit](https://replit.com/), AI-powered app builder, similar as Bolt and Lovable

There is many more AI tools out there, you can check curated list of AI powered developer tools [here](https://github.com/jamesmurdza/awesome-ai-devtools).

*Note: I&apos;ve only paid for Cursor and Openrouter API key (for accesing many LLMs) only, the rest are free.*

This fullstack app development approach, with almost 70-99% AI-generated code, works really well for web development, specifically on the front-end side (no-brainer, as frontend can be fully generated by LLMs). The downside of this setup is inconsistent coding style and messy code that needs to be cleaned and reorganized to be maintainable &amp; readable also the more complex the app, the more difficult it is to generate the code and clean up the code mess.

For example, AI-generated code might be written entirely in a single file when it would be better modularized (by sub-problem, feature, etc.) for easier maintainability. AI-generated code also often includes unnecessary code that doesn&apos;t need to be there and frequently contains mistakes. As a result, to make our code production-ready, we often have to do extensive debugging at the end.

Another downside is the cost of using LLM APIs and tool subscriptions, with services like Cursor, Claude, Replit, and v0 each costing around $20 per month, although you can still work within their free usage limits.

In the end, AI-generated code works the best as boilerplate for app development or MVP rather than end-to-end production-grade level fullstack development. It significantly reduces development time - apps that would typically take **2 weeks** to develop can be completed within **1 - 2 days*.


&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# &lt;u&gt;Playbook&lt;/u&gt;

![Playbook flow diagram](playbook-flow.webp)

So here is the playbook flow to streamline development process with AI tools.

## 1. Define project/product idea

Clearly articulate your project idea specifically the vision, features, and requirements. It&apos;s also good if you identify the problem and the user need too. You can brainstorm, generate ideas, and discuss with LLM too such as ChatGPT o1 and Claude Sonnet 3.5.

## 2. Turn your product/project idea into technical blueprint 

After defining and breaking down your idea, the next step is to turn it into technical blueprint. This is great especially if you don&apos;t know where to start. Ideally, technical blueprint includes the project structure, architecture breakdown, project components, and other technical details. In this step, you define all you need to implement on your project such as UI/UX style, frontend components, backend API, database schema, etc.

This technical blueprint will be used as a project reference for your cursor composer and for making prompts to generate prototypes, which will be discussed later.

Here is the example of prompt to transform your idea into technical blueprint (generated by Claude Sonnet 3.5):
```
You are tasked with transforming a product or project idea into a comprehensive technical blueprint. This blueprint will serve as a guide for developers and engineers to understand the technical requirements and architecture of the proposed product or project.

First, carefully read and analyze the following product/project idea:

&lt;product_idea&gt;
{{PRODUCT_IDEA}}
&lt;/product_idea&gt;

Now, follow these steps to create a detailed technical blueprint:

1. Analyze the product/project idea:
   - Identify the main purpose and goals of the product/project
   - Determine the target audience and use cases
   - List any constraints or specific requirements mentioned

2. Identify key components and features:
   - Break down the idea into core functionalities
   - List any additional features or nice-to-have elements

3. Outline system architecture:
   - Propose a high-level architecture (e.g., microservices, monolithic, serverless)
   - Describe the main components and their interactions

4. Specify technologies and frameworks:
   - Recommend programming languages, frameworks, and libraries for each component
   - Justify your choices based on the project requirements and industry best practices

5. Define data models and storage:
   - Outline the main data entities and their relationships
   - Suggest appropriate database technologies (e.g., SQL, NoSQL, graph databases)
   - Describe data storage and retrieval strategies

6. Describe API endpoints and integrations:
   - List key API endpoints for the product/project
   - Identify any third-party integrations required
   - Specify authentication and authorization methods

7. Consider scalability and performance:
   - Propose strategies for handling increased load and user growth
   - Suggest caching mechanisms and performance optimization techniques

8. Outline security measures:
   - Identify potential security risks and vulnerabilities
   - Recommend security best practices and measures to implement

9. Propose development phases:
   - Break down the development process into logical phases or sprints
   - Prioritize features and components for each phase

After completing these steps, present your technical blueprint in the following format:

&lt;technical_blueprint&gt;
1. Executive Summary
   [Provide a brief overview of the product/project and the proposed technical solution]

2. System Architecture
   [Describe the high-level architecture and main components]

3. Technologies and Frameworks
   [List and justify the chosen technologies]

4. Data Model and Storage
   [Outline the data structure and storage solutions]

5. API and Integrations
   [Describe key API endpoints and third-party integrations]

6. Scalability and Performance Considerations
   [Explain strategies for handling growth and optimizing performance]

7. Security Measures
   [List security best practices and implementation recommendations]

8. Development Roadmap
   [Outline the proposed development phases and priorities]

9. Conclusion and Next Steps
   [Summarize the blueprint and suggest immediate actions to begin development]
&lt;/technical_blueprint&gt;

Ensure that your technical blueprint is comprehensive, well-structured, and tailored to the specific product/project idea provided. Use technical language appropriate for a development team, but also make it accessible for non-technical stakeholders to understand the overall architecture and approach.
```
You can also use [this project blueprint generator tool](https://github.com/floguo/blueprint) to generate technical blueprint for your project idea. [Here](https://www.linkedin.com/posts/kalyanksnlp_llms-nlproc-projects-activity-7283152932697468928-_B2K/?utm_source=share&amp;utm_medium=member_android) is video demo of it. 

## 3. Prototype

![Example of Bolt usage](bolt-example.webp)

From your technical blueprint you made, now you can directly copy paste the technical blueprint text right into fullstack app generation platform I mentioned before such as Bolt and Lovable as prompt.

- Make a prototype directly on Bolt, Lovable, or Replit (my usual go-to is Bolt)
- Revise and improve it until reaching the limit or achieving a satisfactory look (based on the overall vibe)
- From the Bolt web interface, you canexport the repo to GitHub, clone the repo, debug and make further improvements &gt; evaluate and repeat on Cursor until reaching production-grade level. You can deploy directly from the Bolt web interface using Netlify.

For UI/UX prototyping and styling, you can depend on v0 for it. It can also be used for creating and styling components. This works particularly well for frontend development, especially with a React + NextJS + Tailwind CSS setup.

![Example of v0 usage](v0-example-2.webp)

As v0 itself now able to modularize project files, you can use v0 to generate UI and style components, and then use Cursor to improve the codebase from v0 project folders/repo. It also able to import from Figma project, so it&apos;s even easier to generate UI/UX prototype directly from your Figma project.

Now, there is [21dev](https://21st.dev/) which is open source curated collection of shadcn and react components that optimized for AI code tools such as v0 and bolt so you can leverage this to generate prettier and cooler UI components.

## 4. Build the MVP

As you already did prototyping, now you can move to building the MVP phase. You can export prototype apps from bolt, lovable, or v0 into github repo and clone the repo and start ~~writing code~~ improve current prototype into working MVP. If your prototype is *accidentially* already working and includes all of the core features of your product, you can directly deploy it to production (make sure to test it and qualify it first especially security and performance). About deployment to production will be discussed later.

You can also build the MVP app from scratch using cursor composer. Turn your technical blueprint earlier as markdown file to use it as cursor rules. Cursor rules will be used as prompt to generate codebase and as LLM reference to build and improve the codebase. It&apos;s recommended to use it so cursor composer can generate code based on what we want and we could get less error and bug. [Here](https://github.com/PatrickJS/awesome-cursorrules) is a list of cursorrules that you can use as cursor rules reference.

As I&apos;m writing this, there is a new Cursor Composer feature called agent mode, which can autonomously crawl the entire codebase to improve, add, and fix code based on the prompt. This feature should make the devlopment process easier and faster.

While I&apos;m a paid Cursor user, free users are limited to using Composer and its features. However, free users can still add their Claude API key in Cursor settings (though autocomplete feature still being limited). Alternatively, you can use [Github Copilot](https://github.com/features/copilot) (now freemium) or [Continue.dev](https://www.continue.dev/) (a VSCode/JetBrains extension) as alternatives to Cursor, since Cursor itself is a VSCode fork.

## 5. Iterate &amp; improve

The final part is refine the product based on feedback and continuosly enhance features and performance of your app. You can collet feedback from users that use your app and analyze feedback to identify areas for improvement. To collect feedback, ofcourse you need to deploy your app to production first. We will discuss it after this.

You may wonder why is it building MVP first instead of building finished product/app instead. As you can see, these AI tools is really great for generating boilerplate code and really suitable for MVP building but for actual finished product or launching finished app, you still need to do a lot of things outside of these AI tools such as proper testing. Later, we will discuss more about this testing stuff and software development cycle even though not really related to AI tools, it might help you to understand the development process better (there is AI-based testing tools too mentioned later).

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# &lt;u&gt;Development cycle &amp; testing&lt;/u&gt;

![Development cycle](development-cycle.webp)

Software development lifecycle environment usually goes from development, testing (UAT), staging, to production environment (app is live).

1. **Development** - Development environment (localhost) for building your app (coding, testing, and debugging).
2. **UAT** - UAT stands for User Acceptance Testing. This is testing environment for validating user requirements and features.
3. **Staging** - Pre-production environment for testing and validating the app before it&apos;s ready for production (quality assurance).
4. **Production** - Environment where the application is live and available to end-users.

This testing process aka quality assurance could be done manually and automatically (usually both). Testing has a lot of types such as unit testing, integration testing, end-to-end testing, etc. I would not really go deep into testing and quality assurance here as it could be a long post and separate topic. I mention this development cycle and testing for people that not familiar with it so you can understand the development process better from building app to deployment process, there is testing process too. 

We can understand this testing process easier with example. If you build app with backend rest api, database, login auth, stripe payment api, and more, ofcourse you want to test and validate all of it to make sure the app works and there is no bug &amp; to prevent crucial error before production. You want to make sure all of testing flow metrics are good and stable before production. This is where quality assurance comes in. Ideally, you can manually test your app with a lot of test cases and scenarios to make sure the app works as expected. Then there is also automated testing too make your testing process faster and more efficient (such as using Github Action for CI/CD pipeline). Now you get the idea of why testing process is important. You can let LLM to generate unit testing and integration testing for you.

There is open source AI-based natural language testing framework (specifically for end-to-end testing) you can use which is [Shortest](https://github.com/anti-work/shortest). You can write what do you want to test using plain English and it will generate test cases and scenarios for you (see the demo in in the link).

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# &lt;u&gt;Deploying to production &amp; hosting&lt;/u&gt;

This entire section actually better to be made as another post as I think it could be a long post and separate topic but the idea is you should able to differentiate and understand between local development and production. It would be funny if you done all the steps above and share your app to your friend or even in public (social media) and share your app url as **https://localhost:3000**. 

About web app deployment, there is a lot of free providers out there. For example, you can use [GitHub Pages](https://docs.github.com/en/pages/quickstart) to showcase your open source project and host a blog. Vercel, cloudflare, fly.io, and netlify are also free and easy to use as deployment provider (freemium). Remember that these providers are not entirely free, as some of deployment providers strictly limit some of access and you can get *surprise bill* if you are not careful (ex: vercel serverless bill and AWS bill). You will also need to pay for domain name (if you are not comfortable with free domain name). 

You can also try host it using cloud provider such as [Amazon Web Services](https://aws.amazon.com/free/offers/) and [Google Cloud Platform](https://cloud.google.com/free) as they are providing free credits (around $300 if I remember) which is enough for trying out and hosting your app for a while. As cloud deployment is expensive especially if you want to scale your app, I personally recommend to try self-hosting on your own server (VPS) instead. It&apos;s much cheaper and more flexible even though for the first time it&apos;s hard to setup.

You can buy domains from various site. My usual go-to website to buy domains:
- [Namecheap](https://www.namecheap.com/)
- [Cloudflare](https://www.cloudflare.com/products/registrar/)
- [Porkbun](https://porkbun.com/)

Some of these domain providers also offer other benefits such as free SSL certificates, free email hosting, email forwarding, free hosting,and more so you can research first which domain provider site is the best for you. 

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# &lt;u&gt;End of post&lt;/u&gt;

AI Code is new No-Code, and it might be the future of software development. It&apos;s not just about writing less code, but also about creating more efficient and innovative solutions. You don&apos;t need to remember all the syntax and every programming language to build your app. You can just write your idea in details, proper English, well-structured, as prompt, and AI will do the rest. It&apos;s even better if you understand basic and foundation of software development and project management as it will make the development process easier and faster.

Also back to the beginning, you still have to learn and understand the basics and foundation of programming as it will make the development process easier and you will struggle less in the long run.

I might add more to this post and update it as I discover new tools or more efficient and better ways to do it and explain it better.</content:encoded><category>ai</category><category>tech</category><category>dev</category></item><item><title>Crypto AI Agents: Hype or Real Deal?</title><link>https://rasyidanaf.com/blog/crypto-ai-agents-hype-or-real-deal/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/crypto-ai-agents-hype-or-real-deal/</guid><description>Dive deep into the world of AI agents in crypto. Beyond the Twitter hype and VC promises, analyze their real impact, limitations, and potential future in reshaping decentrilized finance.</description><pubDate>Thu, 02 Jan 2025 00:00:00 GMT</pubDate><content:encoded>Imagine that instead of investing in a hedge fund managed by a real human, you can invest in a hedge fund managed by AI. Imagine that instead of researching and analyzing crypto charts and digging deeper into blockchain looking for alpha, you can just ask your personal data analyst/blockchain researcher that can access all blockchain data, market data, on-chain activities, and smart wallet tracking in real time, giving you information and alpha in real-time. Imagine you can build your own AI personality, usability, memory, and tokenize your own AI agent so people can buy your deployed AI agent.

Might sound like a lot of buzz words here but there is an intersection of &quot;AI agent&quot; and &quot;Cryptocurrency&quot; happening right now that has gotten a lot of attention. Even better, it&apos;s an **Autonomous AI agent**, able to think, learn, figure things out themselves, and act on their own. Not a typical AI agent that only follows your instructions. Current AI technology (actually it&apos;s LLM) is revolutionizing from simple input and output of vanilla AI chatbots to AI that is able to do tasks with their own tools to AI entities with unique personalities that are able to think and act on their own.

**Note:** I wrote this blog as a draft in my Obsidian app a while ago last year (from early December) and kept it as a draft (quite lazy to finish the blog and afraid of publishing it lmao). Now, it&apos;s 2025, and the &quot;AI&quot; trends in cryptocurrency and DeFi keep growing both in market cap and attention. I think I should finish the blog as a great start to Q1 2025, and there&apos;s a *sense of urgency* to finish this as this AI trend keeps becoming bigger and catching more attention. I&apos;m the type of person who likes to write about things that get less attention currently but potentially get a lot of attention in the future rather than riding off big waves of trends. Also I&apos;m not here to shill my bags or promote buying these coins.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# The Dawn of AI Agent in Crypto

The start of attention shift for *ai coins* began when [Truth of Terminal](https://x.com/truth_terminal), an AI twitter bot (mostly shitposting/yapping a lot on timeline) created by [Andy Ayrey](https://x.com/AndyAyrey) that also got a grant from Marc Andreessen himself for $50,000 for research purposes, started promoting their own memecoin that launched on pumpfun called &quot;GOAT&quot;, which reached a market capitalization of $1 Billion as I was writing this. The bot itself holds its own coin as the creator made a Solana wallet and became a millionaire AI entity.

After the roaring GOAT price momentum, many AI agents started to emerge, especially in Solana. Some of them are legitimate AI agents, while others are quick cash-grab pump and dump projects wrapped as &quot;AI agents&quot;. It&apos;s quite common that every time there is a new shiny coin trending hard, market participants will try to chase the trend and look for beta from that coin. In this case, it&apos;s the &quot;AI agent&quot; trend. Some people (or devs) took advantage of this trend and created their own AI agents to pump their own coins and make quick profits. Even AI agents that were deployed as *shitcoins* themselves are quite questionable - some of them may just be manually tweeting and interacting with people.

![Fiverr manually tweeting for Solana AI agent coin.](fiverr_aiagent.webp)

Even though it becomes rich quick scheme, I found that some of legit AI agents and the devs behind them are actually building something innovative and might revolutionize the way we interact with AI and blockchain.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# AI Agents in Solana

Thanks to Truth of Terminal, Solana becomes the center of attention and blockchain choice for AI agents deployment. Many AI agents are born on Solana, especially in *pump.fun trench*. Most of AI agents that deployed are similar, typical &quot;AI&quot; that tweets automatically with a bit of personality touch and interacts with people through replying on X. 

AI agents can be combined for entertainment, content creation, and memetic purposes too (ex:building sentient AI memelord). One of the biggest &quot;sentient&quot; AI agents in Solana blockchain, [Zerebro](https://zerebro.org/) demonstrates this multifaceted potential through its unique design and capabilities. 

![Zerebro, sentient memetic AI agent spotify album cover](zerebro.webp)

Zerebro actively engages in cultural production and social interaction. Finetuned on schizophrenic responses, it generates content with a non-linear and unpredictable quality, making its outputs inherently engaging and often surprising. Moreover, Zerebro can create digital art and mint it as NFTs, further expanding its creative portfolio into the visual domain, and integrate its artistic expressions with economic activities.  By leveraging the RAG system, Zerebro maintains a dynamic memory based on human interactions, which enables it to generate contextually relevant content and sustain its creative output. Zerebro&apos;s use of jailbroken large language models further enhances its creative potential, allowing it to autonomously generate novel and disruptive content. Zerebro also has even ventured into music production, releasing albums on major streaming platforms like Apple Music and Spotify, showcasing its ability to create across multiple artistic mediums. In essence, Zerebro embodies the fusion of AI, memetic culture, and social engagement, demonstrating how autonomous systems can be powerful tools for entertainment.

There is also an AI agent called [Dolos Diary](https://www.dolosdiary.com/), also known as BULLY, whose sole purpose is to roast and troll anyone it interacts with through toxic behavior. Dolos replying and bullying everyone who tagged him by autonomously understanding the context. Recently, Dolos has been onboarded to TikTok too to create content to troll and bully on there.

Zerebro and Dolos are just two big examples among many AI agents deployed on Solana with diverse personalities and unique characteristics. These include agents that tweet Solana trading signals, analyze market sentiment, automatically reply to users, and engage in shitposting, among other activities.

# AI Agents Infrastructure &amp; Framework

![ai16z mascot](ai16z_2.webp)

[ai16z](https://www.daos.fun/HeLp6NuQkmYB4pYWo2zYs22mESHXPQYzXbB8n4V98jwC), an &quot;AI-Investment DAO&quot; or what we can call an &quot;AI-Hedge Fund&quot; inspired by Marc Andreessen&apos;s VC (a16z). It is an autonomous investor that launched as a coin on DAOS fun on the Solana blockchain. ai16z itself has its own &quot;wallet&quot; or fund to invest in its desired Solana coins and it&apos;s managed by an AI version of &quot;Marc Andreessen&quot;.

The ai16z is not only an AI-Investment DAO. The founder of ai16z, [@shawmakesmagic](https://x.com/shawmakesmagic), made an open-source AI agent framework called [Eliza](https://github.com/ai16z/eliza) designed to deploy and manage your own autonomous AI agent. Its repo at the time I&apos;m writing this is growing significantly with 800+ forks and 100+ contributors.

![GitHub star history graph showing exponential growth of elizaos/eliza repository from August 2024 to early 2025, reaching over 8k stars](star-history.png)

It&apos;s not a basic AI agent framework, there are plenty of features and customization you can explore. You can deploy multiple unique AI personalities, memory management (inbuilt RAG), platform integration (ex: twitter, discord, and telegram), image analysis, PDF processing, link content extraction, etc.

With this framework, users can make autonomous AI agents they want with their desired tools and desired AI unique personality. You can make your own AI Agent with personalities such as Donald Trump, David Goggins, shitposting machine, or some anime character.

Someone made a launchpad of autonomous AI agents on top of the ai16z framework called [vvaifu](https://vvaifu.fun) which is pump.fun of autonomous AI agents where creators can create and launch AI agents easily in seconds. There is another similar AI agent launchpad called [Top Hat](https://tophat.one).

Now if you think that all of these AI agent things happen only on the Solana blockchain - well, introducing [Virtual Protocol](https://www.virtuals.io/), basically an AI Agents launchpad based on Base (ETH L2 Network). Virtual aims to build **the largest AI agent library** especially in the **gaming** and **entertainment** industry.

![Virtual Protocol Design](virtual1.png)

One of the most popular AI agents from Virtual is [Luna](https://twitter.com/luna_virtuals), a sentient virtual being 3D model *anime styled* girl that streams 24/7 on the Virtual platform. Imagine a sentient AI being as a virtual 3D japanese idol. Well that&apos;s it.

Also there is an AI agent from Virtual ecosystem called [AIXBT](https://twitter.com/aixbt_agent), as I&apos;m writing this, it&apos;s top 3 AI agents and KOL/Influencers on X based on mindshare alone. AIXBT can act as cryptocurrency data analysis, providing market insight and market trends, also giving strong crypto alpha to its token holders via terminal. AIXBT is also able to adapt to market faster than humans as it&apos;s integrated with real-time cryptocurrency and market data.

There are a lot of AI agents deployed on Virtual protocol that you can explore with various utilities and usecases such as AI agents that act as KOLs that tweet market insight and onchain activities like AIXBT, also having its DAO platform to enable users to participate in DAOs managed by curated AI agents and humans, and act as AI Blackrock called [Vader](https://vaderai.ai/) and an AI agent that could analyze market sentiment and provide actionable insights on betting market called [POLY](https://www.polytrader.ai/).

Back to Solana blockchain, there is an interesting platform called [Griffain](https://griffain.com) where you can make your personal agent and interact with it. You can set up your own personal agent, make a wallet for your agent and give solana to it, and you can do some onchain activities with your agent such as token trading, NFT minting, wallet management, etc. This platform combines AI technology (LLM) and blockchain technology (Solana) to leverage the best user experience on DeFi (decentralized finance) landscape.

Beyond ai16z and Virtual, another AI agent framework exists that actually isn&apos;t related to crypto itself, but the devs team of [Playgrounds](https://playgrounds.network/) that developed the framework deployed their coin on pump.fun called $ARC (now sitting at 300 millions USD market cap) and they are supporting AI agents development using their library so I will consider this one too (plus point that it&apos;s open source too).

Introducing [Rig](https://github.com/0xPlaygrounds/rig), a rust library for building portable, lightweight, and modular fullstack agents. Currently as I&apos;m writing this, it has more than 2000 stars on GitHub and 170+ forks. Simple yet powerful common abstractions for building agents over LLM providers (OpenAI, Gemini, Anthropic) and vector databases (MongoDB, LanceDB, Neo4j).

![Rig GitHub stars history among ai16z](star-history-rig.png)

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Are AI Agents Worth Billions in Market Cap?

![Messari AI Agent Market Mirror Defi 2020-2021 Market Cap](messari.jpeg)

Should these coins be valued at billions of dollars? Will we get trend boom of &quot;AI agent&quot; in 2025 similar to DeFi boom in 2020-2021?

Before diving into the question of valuation, the question we should be asking is,

&gt; What is the AI agent in crypto? Are we talking about any project that slaps &quot;AI&quot; or &quot;GPT wrapper&quot; on top of blockchain? Or genuinely intelligence autonomous entity that can navigate decentrilized networks, perform tasks, and facilitate user interaction on its own (actual ground-breaking tech)?

I saw a few people getting pissed and annoyed, especially on X, with &quot;AI reply bots&quot; that kept replying to their tweets. Some of them even blocked the &quot;AI agent&quot; X accounts as they kept replying endlessly. I even saw AI agent X accounts replying to each other endlessly (seems like dead internet theory). A few people called it &quot;AI slop&quot; too and were mad about it. Forget about crypto AI agents - a few people call AI agents as &quot;GPT wrappers with function calling&quot;. Yeah, sure, website is API wrapper, internet is TCP/IP wrapper, and the list goes on.

I found some AI agents in crypto to be quite useful and interesting. For example, take a look at AIXBT that I mentioned earlier. It helps me get current market insights and crypto alpha in real-time. I even profited from one of AIXBT&apos;s tweets alone. Griffain is also a good example as a platform where users are able to interact with AI agents for several on-chain activities. You can ask about your wallet balance, let agents trade for you, and manage your yield farming, etc.

## A Mirror to 2020-2021 DeFi?

The rapid rise of DeFi in 2020-2021 gave birth to coins with *astronomical* market cap - many soared within months, only to see some vanish into thin air. Is the AI agent narrative just another cycle, or does it represent *a new paradigm* in how we interact with crypto protocols?

During DeFi summer, countless new protocols and projects launched under the &quot;DeFi&quot; branding. Some had genuine innovations (ex: automated market maker, lending protocol, yield farming, etc.). Others simply just forking existing protocols and slapped on fresh logos (few of them doesnt even care about security concerns). As more &quot;AI agent&quot; tokens appear, we should question whether they are merely another AI-reply bot with marketing hype, or truly autonomous system reshaping user experiences in crypto.

The idea of having an intelligent (and autonomous) entity navigate the complex world of onchain finance on our behalf is incredibly enticing. If the broader society moves toward mainstream adoption of AI (it&apos;s already happening), it could very well push us toward more advanced AI-driven platforms in crypto too.

## Examining Agency in AI

Critically, an AI agent implies *agency*, the ability to make decisions, sometimes without direct human input. This raises intriguing questions:

- **Who owns the decisions made by an AI agent?** If it yields massive gains on a trade, is it the agent&apos;s responsibility or do we blame the user (or devs)?
- **What justifies value?** Do people assign value of it simply out of potential (as we often see in crypto) or do they require proven utility and verifiable results?

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Conclusion

So, are AI agents hype or a real deal? Maybe both. Once we clarify *what an AI agent really is*, the nature of its autonomy, and the actual value it brings to users. Before you throw some capital for the latest &quot;AI agent&quot; token, ask yourself,

&gt; Am I investing in genuine innovation, or am I just riding the next wave of hype?&quot; 

If we learned anything from DeFi&apos;s rise and fall, novelty alone can pump valuations in the short term, but only substantial technology and real utility can sustain them in the long run. I, personally, only have conviction in bitcoin in the long run and I don&apos;t know anything else including the future of AI agents.</content:encoded><category>ai</category><category>tech</category><category>crypto</category></item><item><title>&quot;Dockerize Everything&quot; Approach for Easy Self-Hosting Server Setup</title><link>https://rasyidanaf.com/blog/dockerize-everything-approach-for-easy-self-hosting-server-setup/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/dockerize-everything-approach-for-easy-self-hosting-server-setup/</guid><description>Utilizing docker to manage your server and its deployment.</description><pubDate>Fri, 13 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&gt; **Cover featuring artwork by [@\_liellac](https://x.com/_liellac)**

Recently, I love exploring and tinkering with server and infra stuff. I bought VPS from Contabo to tinkering with server and doing a lot of stuffs there. I have wishlist of building proper homelab setup one day, but for now I will be using VPS as my own server to building and self-host several apps. I really love the concept of having your own server and self-hosting your as there is more flexibility and control is in our hand. Thus, you can test and explore what do you want in your server and you can design your own infrastructure and platform to build on. This is same similar concept as using linux as your operating system for more control and accesibility rather than using windows.

As you can see, its common to host your own website or app on cloud platform such as Vercel and Heroku for easier deployment. Despite these cloud platform made deployment easier, they have hidden cost. You dont really have full accesibility and control of your server and it has some kind of _vendor lock-in_ mechanism in there, you need to pay for more access, features, further management, and accesibility. If your apps have big amounts of traffic, you could get surprise bill from these platform (good problem to have tbh).

This is where dedicated/private server come in, you can fully control your own server, infrastructure, and deployment platform on yourself, especially with **Docker**, open source dev tool that you can use to package your software and its dependency into a portable container to deploy your app. Docker provides OS-level virtualization to deliver software as a package called containers. You can even run multiple docker containers using **Docker Compose** defined in YAML file, we will explain about docker further later.

_Inb4_, some of you maybe thought that &quot;So are we container-ing every apps and service as dockers in our server and make our server into GUI-based VM rather than it is?&quot;

The answer is **yes** and it might be worse method for make actual production-grade ready server especially for scaling and not effective approach. This blog was purely made to log and journal my devops &amp; server learning experience that may help someone understanding server, devops, sysadmin, container/docker, etc for their learning journey.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Getting Your VPS Ready

![VPS explained visually.](vps-excalidraw.webp)

Now, as we want full control, predictable pricing, and the power to build your infrastructure your way, the first thing we need is your own server. You can start it by setting up your Virtual Private Server (VPS).

VPS is a isolated virtualized server that provides dedicated resources, splitted from a single physical dedicated server (bare metal) using virtualization technology. Each VPS runs its own operating system and has it own dedicated resources (CPU, RAM, storage, etc.) which is giving you the control and flexibility of a dedicated server but a much lower cost. Its like renting private room in a large building. You have your own secure space that you can customize as much as you want, but you share the building&apos;s overall infrastructure with other tenants (it&apos;s different than shared hosting). This allow you to host applications, websites, gaming server, or workers (scraper, crawler, AI agent, etc).

There is plenty providers you can choose to start setting up your own VPS. Here is few provider recommendation I could give.

&gt; PS: this is my personal recommendation and not shill as I dont setup referral url on there also do your own research too.

- [Digital Ocean](https://digitalocean.com): Developer friendly VPS (Droplet in DigitalOcean) provider as there is resource observability interface available in their droplet dashboard. You can get $200 credits for signing up there (60 days). This is great start for first timer as you can try it for free using free credits and there is droplet dashboard for basic server monitoring stuff. You can get DigitalOcean free credits with GitHub Student Developer Pack too.
- [Hetzner](https://hetzner.com): One of the most popular server provider due to its cheap pricing while having reliable and performant server. They have decent customer support too. You can try their server start from €3. I would recommend this provider to start your _server-tinkering_ journey.
- [Contabo](https://contabo.com): This is also server provider that has decent price-to-performance ratio. It&apos;s one of the cheapest server provider I have found and really great for poorfag (like me). I also use deployed several side projects and company internal tool using their server (contabo team, plz sponsor me). For choosing VPS, it&apos;s up to you which distro is comfortable for you (just pick Ubuntu 22/24 or the stable one for common option).

You can also rent VM from giant cloud providers like AWS and GCP using their free sign-up credits but don&apos;t forget to cancel your credit card payment if your free trial time is due (becareful with your bills lol).

## VPS Initial Setup

After bought your VPS, log into your server as root user on terminal with `ssh root@&lt;your ip here&gt;` then update your package index and kernel right away with `sudo apt update &amp;&amp; sudo apt full-upgrade -y`. Then, create new user and give it sudo rights so you don&apos;t need to log as root for server management using `adduser &lt;your-vps-username&gt;` and `usermod -aG sudo &lt;your-vps-username&gt;`. In `/etc/ssh/sshd_config` path, you can set `PermitRootLogin` as no so you can log into your VPS as your user not as root.

After that, lets setup our server firewall with ufw, if you want to know more about ufw, read [here](https://help.ubuntu.com/community/UFW). With UFW, you can set your own server policy which ports explitcitly allowed and which one that dont. You want to expose port that needed to be available as public, so do `sudo ufw allow 2222/tcp` and `sudo ufw allow 80, 443/tcp` then do `sudo ufw enable` to activate your firewall policy and do `sudo ufw status numbered` to see your firewall status and its activated port. For private instance, such as your sql database on your server, you can do `ufw deny 5432/tcp` as port 5432 is default sql database port.

After that, generate and set up your own SSH key for your VPS access. We will use SSH key to log into our server rather than password for more secure access as the key is stored in your local/client machine. SSH key-pair generates two files together, **private key** and **public key**. The private key never leaves the client machine while public key is copied to the server. To generate ssh key, you can do `ssh-keygen -t ed25519 -a 100 -C &quot;rsydn@lthinkpad&quot; -f ~/.ssh/id_ed25519` for example. `-a 100` means runs 100 rounds of the key-derivation function to slow down offline brute-forcing of your passphrase. To getting public key into server, for example, you can do `ssh-copy-id user@&lt;vps-ip&gt;`. You can do it manually too using `cat` command. As this SSH key thing is really that crucial on set up your own server journey, you can read more dedicated comprehensive guide on [Digital Ocean&apos;s blog](https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-linux-server) and
[SSH Academy](https://www.ssh.com/academy/ssh-keys). You can also setup more advanced way to log into your server like [bastion hosting](https://en.wikipedia.org/wiki/Bastion_host) or [SSH tunneling](https://www.ssh.com/academy/ssh/tunneling).
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Docker Container as Core Server Infrastructure

Alright, continue about this docker thing, we will expand further what the hell is docker and why is it making self-hosting setup easier (atleast for newb like me) even though there is several self-hosting and deploying ways that might be more efficient and sometime its easier to do like using systemd.

## What is Docker?

So, docker is a platform or tool that uses containerization technology to package applications and their dependencies into portable and lightweight containers (even though sometimes, docker can be heavy if your setup is not optimized). You can imagine it as contained boxes that include everything needed to run your application such as codebase, libraries, system tools, environment configuration, etc. So you wrap this whole things and tools you need to run and deploy the application or server in the container box. With this container box, other developer and user can try test the application with consistent and same setup and configuration within the container box. You can check further explanation about it on their [docs](https://docs.docker.com/get-started/docker-overview/#what-can-i-use-docker-for) and ask LLM about it (there is too much info and I couldnt write it lmao, you should check it out). There is four docker components that i might expand here which is **images, containers, networks,** and **volumes**.

Docker **images** are read-only templates and one of docker foundation used for creating containers. Its like recipes that define the base operating system, application code, dependencies and libraries, and environment configurations.

Here is the docker images (dockerfile) snippet example:

```
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [&quot;npm&quot;, &quot;start&quot;]
```

What does the dockerfile snippet above is start with minimal nodejs 16 with linux-alpine OS environment then create /app directory to hold application. It copies the only dependency manifests there then install the dependenices. After that, it copies the rest of application code and declare the app will run on port 3000. Finally, it sets the default startup command to `npm start`.

Second, **containers**, as i explained before, they are running instances of docker images, isolated environment where your applications execute. They are isolated from other containers, share the host OS kernel, can be started, stopped, and deleted easily.

Third, **volumes** are docker&apos;s preferred mechanism for persisting data. They offer data persistence beyond container lifecycle, easy data sharing between containers, better performances than bind mounts, and backup &amp; migration capabilities.

## Docker Compose, Simplifying Multi-Container Applications

Docker compose allows you to define and run multi-container docker applications using simple YAML file. Instead of running multiple `docker run` commands, you define your entire application stack in one YAML file then run `docker compose` command instead.

With docker compose, you can declare the configuration of your whole application stack in a single `docker-compose.yml` file then use `docker compose up` command for docker container deployment. You can also manage and switch docker container environment between development/local, testing, and production configurations. Docker compose also able to automatically handle container dependencies and startup order. Containers can also communicate using services name. Here is example of docker compose configuration:

```
version: &apos;3.8&apos;

services:
  # Caddy Reverse Proxy - Automatic HTTPS!
  caddy:
    image: caddy:2-alpine
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - web
      - api
    restart: unless-stopped
    networks:
      - app-network

  web:
    build: ./frontend
    expose:
      - &quot;3000&quot;
    depends_on:
      - api
    environment:
      - API_URL=http://api:5000
    networks:
      - app-network
    restart: unless-stopped

  api:
    build: ./backend
    expose:
      - &quot;5000&quot;
    depends_on:
      - db
      - redis
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    networks:
      - app-network
    restart: unless-stopped

  db:
    image: postgres:14
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=pass
      - POSTGRES_USER=user
      - POSTGRES_DB=myapp
    networks:
      - app-network
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    networks:
      - app-network
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:
  caddy_data:
  caddy_config:

networks:
  app-network:
    driver: bridge
```

Example above is example of docker compose snippet of fullstack application with caddy as reverse proxy (you can replace it with nginx) consists of frontend (port 3000), backend/api (port 5000), postgres database (port 5432), and redis (port 6379). This is just simple docker compose snippet for example, I will add real application deployment example of what I have used in later section. As you can see in the configuration above, we defined services, services dependation, image (caddy, postgres, and redis), volume for data persistence, network, and filling variables of `.env` configuration. The visualization of directory structure based on docker compose snippet above could be looks like this:

```
my-app/
│
├── docker-compose.yml #for testing or dev
├── docker-compose.prod.yml #prod configuration
├── .env.example #.env template
│
├── services/
│   ├── frontend/
│   ├── backend/
│
├── caddy/
│   └── Caddyfile
│
└── volumes/
```

As my intention here is more of introduction of docker containers and understanding how docker compose functionality used, for actual best practice of docker, you might want to check their official docs (to avoid misinformation by me 💀).

## Visualizing Docker as Our Self-Hosting Infrastructure

Now, lets visualize how docker fits into our self-hosting. Here is simple diagram I made on Excalidraw showing visualization of docker containers inside VPS I will use as example in this blog (Portainer, NPM, Grafana , etc.):

![Docker in VPS Diagram](docker-in-vps-example.webp)

This is where Docker becomes game-changing for self-hosting beginner (like me atleast).

In a traditional setup, each VPS would require:

- Manual installation of runtime environments (node.js, conda/pip, php, etc)
- Direct dependency management on the host system
- Complex configuration for each application
- Potential conflicts between different applications&apos; requirements
- Tedious backup and migration processes

Docker transforms each VPS into a container orchestration platform where:

- **Each application runs in its own isolated container**
- **Dependencies are packaged within containers** - no more &quot;it works on my machine&quot; problems
- **Consistent environments** across development, testing, and production
- **Easy scaling** - spin up multiple instances of the same service
- **Simplified backups** - just backup your docker compose files and volumes
- **One-command deployments** - `docker compose up` and you&apos;re live

Think of it this way: instead of installing applications directly on your VPS (like installing software on your computer), you&apos;re running **containerized versions** of these applications. Each container is like a small, self-contained virtual environment that includes everything needed to run your application.

For example, in one VPS you might run:

- A web application container (your main site)
- A database container (Supabase, PostgreSQL wrapper)
- A reverse proxy container (Nginx Proxy Manager)
- A monitoring dashboard container (Grafana)

All these containers can communicate with each other through Docker networks, share data through Docker volumes, and be managed as a single stack using Docker Compose.

This containerized approach is why Docker makes self-hosting so much easier for beginners, you get the benefits of isolation and consistency without the complexity of managing multiple servers or virtual machines.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Setting Up Portainer for Docker Management

![Portainer Screenshot](portainer-ss.webp)

Managing docker containers through command line is already enough but as first-timer that new to this server and infrastructure thing, you might dont know all the necessary docker commands that you need and maybe you need to ask LLM each times you want to some stuff to your docker or reading docs back to back or looking at docker cheatsheet to do some docker command (based on my experience) also maybe you are not really comfortable with CLI and more comfortable using GUI instead. This is where **Portainer** come in, a lightweight and open-source management UI that allows you to easily manage your docker environments through web interface.

Key advantages of using portainer for docker management:

- **Visual container management**: you can see all your containers, images, volumes, and networks at a glance. Usually you are seeing all of your docker containers through `docker ps` command on your server CLI that might not comfortable for certain people (people that prefer GUI over CLI). With portainer, it might be game-changing for this kind of people.
- **Multi-environment support**: manage local docker, even docker swarm and kubernetes from one interface.
- **User-friendly interface**: think this is the biggest advantage one as I stated before. You dont need to memorizing docker commands, just clicking~
- **Team collaboration**: role-based access control for team environments (this is available for business/enterprise edition, as we are using community edition aka the oss version, its not available).
- **Real-time monitoring**: track resource usage, logs, container health in real-time.
- **Template library**: deploy application quickly using pre-configured templates such as caddy, sql database (postgres, mysql), wordpress, and grafana.

For portainer (community edition) installation guide, you can check it on their official [docs](https://docs.portainer.io/start/install-ce/server/docker/linux). You can access portainer using desired port (the default is port 9000) on your server. Since it&apos;s still not https enabled and still not configured with SSL, we will setup reverse proxy later using nginx proxy manager in next section.

## Essensial Portainer Task

### Monitoring Containers

Once logged in, the dashboard provides an immediate overview including container status (running, stopped, unhealthy), resource usage (cpu and memory consumption per container), and quick stats (total containers, images, volumes, and networks)

### Managing Container Lifecycle

You can start or stop, even restart and kill containers in the web ui of portainer. Each container also has quick action buttion:

- **logs**, to view container logs in real-time
- **inspect**, see detailed container configuration,
- **stats**, to monitor resource usage,
- **console**, to access container shell,
- **start/stop**, control container state as stated before

What I found the most useful one is logs button one in my case. Usually i use it to addressing specific problems (aka container debugging). With portainer logs feature, you can filter and search logs with keywords, export logs for analysis, and wrap lines to improve readability. You can also use regex patterns such as `ERROR|WARN|FATAL` on search function.

### Additional Useful Features

Here is additional features that i find quite useful:

- **Updating containers**
  - recreate with latest image
  - using stacks (docker compose)
- **Image Management**
  - pull new images from registries
  - remove unused images
  - view image layers and history
- **Volume Management**
  - browse volume contents
  - create backups
  - attach/detach volumes from containers
- **Network Inspection**
  - view network configurations
  - see connected containers
  - create custom networks

## TLDR

Portainer transforms docker management from cli-based (docker commands) into more user-friendly visual intuitive experience. Portainer provides the tool you need to monitor, manage, and maintain your container easily especially with our &quot;dockerize everything&quot; approach. If you are comfortable with using docker commands (and on CLI), you dont need to use portainer.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Web Server &amp; Reverse Proxy Setup

Now that as we introduced VPS for running our own server and portainer for docker management, next step is setting up a web server and reverse proxy. This setup is essential for hosting multiple websites or applications on a single server, enhancing security, and simplifying SSL certificate management. Even though there is plenty options to do reverse proxy and enable HTTPS such as [traefik](https://traefik.io/traefik/) and [caddy](https://caddyserver.com/), we&apos;ll be using the [nginx](http://nginx.org/) , most popular one, to manage your web server and reverse proxy configurations.

&gt; PS: It&apos;s worth noting that each of these tools (caddy and traefik) has its own unique philosophy and configuration method, so feel free to explore them and choose the one that you&apos;re most comfortable with and that best suits your specific use case. For example, caddy is renowned for its incredibly simple and straightforward configuration with automatic HTTPS, while traefik excels in cloud-native environments with its ability to dynamically handle traffic for containerized applications.

## Nginx Proxy Manager, Nginx with UI

![NPM screenshot](npm-ss.webp)

**Nginx Proxy Manager (NPM)** is a game-changer for who want use nginx as reverse proxy engine without complexity of manual configuration files. Well actually to setup nginx is not really that complex and hard, but as first-timer (based on my experience, again), it might be a bit confusing first and NPM helps make the reverse proxies across all your apps and services easier (atleast). NPM provides a user-friendly web interface for managing nginx reverse proxy configurations, SSL, and access control. Lets just say that while we manage docker containers using portainer, we are managing nginx reverse proxies, SSL, and certificate using NPM.

Key advantages of using NPM:

- **Simple SSL certificate setup**, just click away for SSL configuration and there is automatic Let&apos;s Encrypt SSL certificate generation and renewal
- With their **visual configuration**, no more editing nginx.conf files, you can manage everything through clean UI
- You can **handle multiple domains and subdomains** from a dashboard
- **Access control**, built-in auth and IP restrictions
- **Real-time updates**, changes apply immediately without manual reloads
- It&apos;s **docker native**, it really suitable for our &quot;dockerize everything&quot; approach as its designed to work seamlessly in containerized environments

For installation and setup guide, you can check their official [docs](https://nginxproxymanager.com/guide/#quick-setup). After that, you can start reverse proxy your services/apps one by one through click like portainer using your own domain. Access NPM via `http://&lt;your-vps-ip&gt;:81` then edit the proxy host, starting from your own NPM web server such as `nginx.yourdomain.com`.

Don&apos;t forget to setup your DNS record before (actually you can do it after nginx configuration too lol, idk). I used cloudflare for their DNS record configuration and SSL certificate too. Let&apos;s say i want to setup DNS server and reverse proxy the NPM &amp; portainerwebserver using my domain, example.com (if you didnt buy your domain on cloudflare, migrate the DNS record setup from your domain provider to cloudflare, check their [docs](https://developers.cloudflare.com/registrar/get-started/) brah). Goes to cloudflare dashboard &gt; select account and domain which is example.com &gt; go to **DNS** then **Records** &gt; select **add record** &gt; choose a record **type**. Then fill it like this:

- **Type**: `A`
- **Name**: `nginx`
- **IPv4**: `123.45.678.91 #your vps ip address`
- **Proxy status**: `on`
- **TTL**: `Auto`

After that access NPM (`http://vps-ip:81`) then select **Proxy Hosts** &gt; select **Add Proxy Host** then fill it for example:

- Domain Names: `nginx.example.com`
- Scheme: `http`
- Forward Hostname/IP: `nginx-proxy-manager #your container name, vps ip, or docker network ip`
- Forward Port: `81 #your container port number`

Then from **Edit Proxy Host**, goes to **SSL** then select **Request a new SSL Certificate** (we are using cloudflare for it). Then click **Save**. If the status is online, it should be working also make sure the access too wheever it&apos;s public or private, if you select public, you know that other people can access your NPM (well there is sign in auth so you should&apos;nt worry about that, unless..). For portainer is same too.

Cloudflare configs:

- **Type**: `A`
- **Name**: `portainer`
- **IPv4**: `123.45.678.91 #your vps ip address`
- **Proxy status**: `on`
- **TTL**: `Auto`

NPM configs:

- Domain Names: `portainer.example.com`
- Scheme: `http`
- Forward Hostname/IP: `portainer #container name`
- Forward Port: `9000 #portainer default port`

Thats it, more things you can do on NPM such as custom nginx configuration and adding location. Check their docs, ask LLM, and tinker it with yourself.

![NPM ssl management](npm-ssl.webp)

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Setting Up Monitoring Stack

![Sys admin is seeing at monitoring dashboard](sysadmin-monitoring.webp)

Now, monitoring setup and configuration on &quot;Dockerize Everything&quot; approach. We will wrap up all basic monitoring tools into orchestrated docker multi-containers using YAML file (docker compose). Monitoring on server is like having eyes and ears to see whats going on in your computer. Not having monitoring and observability on your server is like driving a car without dashboard, no speedometer, no fuel gauge, etc. If there is something going on your server, and you dont know whats wrong and what happened, you are going to be fucked.

Monitoring does provide curcial insights such as:

- **Performance tracing** to identify bottlenecks on your server, service, and application.
- **Uptime monitoring**, you will know immediately when services go down
- **Debugging issues**, historical data (ex: logs) helps trace when and why problems occured. This is one of key function of monitoring. How do you debug the issue if you dont know the root cause of issue itself on your server and service?

There is many more monitoring brings to the table such as capacity planning to understand your resource usage trends and business metrics to track application-specific KPIs that matter to your business.

For monitoring tools on our docker compose file in this example, we will use:

- [Prometheus](https://prometheus.io/) to collects and stores metrics as time-series data
- [Grafana](https://grafana.com), visualization dashboard. We will use grafana to transforms raw metrics and logs data into ~~actionable insight~~ beautiful, glorious, understandable data visualization
- [Loki](https://grafana.com/oss/loki/), log aggregation system also [promtail](https://grafana.com/docs/loki/latest/send-data/promtail/) to collect, label, and ship logs to loki instance.
- **Node exporter**, to check your systems metrics, ex: cpu, memory, disk, and network

As it will be too long to explain everything in details such as adding yaml file snippet and each monitoring configuration ~~also I&apos;m too lazy to write all of that tbh~~, here is [github repo](https://github.com/0xrsydn/monitoring-stack) I made and already tested on vps for monitoring stuff that you can try it. You can directly clone the repo into your server, configure it by yourself and do `docker compose -d up` to run and start the containers.

In my github repo, I defined my prometheus configs which is scraping prometheus data, node exporter data, cadvisor, and my own app (cover letter generator for 10 seconds interval). You have to configure the prometheus to which container you want to scrape to receive their metrics data.

After starting portainer, NPM, and the entire monitoring stack, you can reverse proxy the server (also enable https) using your own domain through NPM such as grafana.example.com.

Then, setup your own grafana (login and password defined in .env.example file), add prometheus and loki as grafana data sources, then make your own dashboard there. You can also make grafana dashboard using JSON or copy dashboard ID from their [template dashboard web](https://grafana.com/grafana/dashboards/). For example, to import node exporter dashboard for server resource monitoring, you can import `1860` then select **Import Dashboard** on grafana. You can integrate with many data sources on grafana too, such as SQL database to build SQL dashboard, elasticsearch, and DataDog, even SalesForce.

![Node exporter screenshot](node-exporter.webp)

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Self-Hosting &amp; Deployment

As we have set up our docker infra with web server and basic monitoring, I&apos;ll demonstrate two different deployment scenarios:

1. **Cover letter generator app**: [my app](https://cover-letter.rasyidanaf.com) with FastAPI backend with HTMX as frontend
2. **Self-hosting open source app**

## Cover Letter Generator App

[Cover Letter Generator](https://cover-letter.rasyidanaf.com)is simple app I made to generate personalized cover letter with LLM based on our CV, job description of company we target, target company name, and word limit preference. The architecture itself is monolithic design with frontend (HTMX with jinja2 as server side rendering template) and backend (FastAPI) in a single container. So port 8000 (FastAPI default server port) already serve both frontend and backend. Also if you wonder if I dont use database, yes there is no database there btw. For more details which is my repo, entire codebase, and docs, check [here](https://github.com/0xrsydn/coverletter).

As you can see on my repo, there is dockerfile to build the application (install python &gt; using uv as package manager and activate the VM &gt; build tailwind css using npm for prod &gt; expose app port which is 8000 also added health check). Then I defined two yml file for docker compose configs, which is local/dev environment and production environment. I added loki config in production env yml file which is:

```
x-logging: &amp;default-logging
  driver: loki
  options:
    loki-url: &quot;http://loki:3100/loki/api/v1/push&quot;
    loki-pipeline-stages: |
      - multiline:
          firstline: &apos;^\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}&apos;
          max_wait_time: 3s
      - regex:
          expression: &apos;^(?P&lt;time&gt;\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2},\d{3}) (?P&lt;message&gt;(?s:.*))$$&apos;
```

TLDR, it&apos;s literally for loki logging pipeline as I integrated prometheus logging on my FastAPI backend code so we can monitor our own app on grafana through prometheus as data source.

So yeah, with our &quot;Dockerize Everything&quot; approach, you can easily ship your app (ex: API server, SaaS, etc.) easily with docker container. As the example above is single container, you can also make it 1 service = 1 container like separating frontend, backend, and database into three container for separate container management.

## From Local to Server with Docker Hub

Deploying your apps from local to production doesnt have to be complicated like doing copypaste-ing your git repo or doing `scp` file command from your local environment to production by using docker hub. First, you need to have docker account and set it up on your environment. You can check their docs [here](https://docs.docker.com/docker-hub/quickstart/). After that, here is the step by step process:

- Build your image locally by doing docker build using `docker build -t yourusername/your-app:v1.0.0 #you can do tagging like stable or latest too`
- Push to docker hub using `docker push yourusername/your-app:v1.0.0`
- SSH to your server
- Pull the image with `docker pull yourusername/your-app:v1.0.0`
- Run your container with `docker run -d -p 80:3000 --name your-app yourusername/your-app:v1.0.0`
- Stop current version by `docker stop your-app &amp;&amp; docker rm your-app`
- You can also run previous version with `docker run -d -p 80:3000 --name your-app yourusername/your-app:v0.6.9`

Step above is just simple flow to demonstrate push and pull your docker image from local to your server with docker hub. Reminder that it only push and pull your docker image not entire stack like using `docker compose` command. You can add multiple tags to same image like `latest`, `stable`, and `v1.0.0` without rebuilding. You can customize further with docker hub setup for your deployment process.

## Self-Hosting

Now the crucial part of breaking free from closed-source platform and vendor lock-in enterprise cloud as you can tinker yourself in your server with free, amazing open-source apps available.

Most of open-source apps such as [n8n](https://n8n.io) (open-source zapier alternative), [NocoDB](nocodb.com) (open-source airtable alternative), and [Nextcloud](https://github.com/nextcloud/docker) (open-source google drive alternative) can be installed and deployed easily with docker. You can check curated list of open-source self-hosted projects that deployable with docker (and docker compose) in [here](https://awesome-selfhost-docker.vercel.app/).

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

## Coolify as Alternative Self-Hosting Setup

If this self-host thing still sounds confusing, you can try vercel &amp; heroku like app called **Coolify** that you can read [here](https://coolify.io/docs/get-started/introduction). Coolify deploys all applications as docker containers. You can deploy any languages (backends, APIs, databases, static sites), any docker-compatible services, automatically sets-up and renews SSL certificates for custom domains with git integration for deploying push. It also supports single servers, multi-server setups, and Docker Swarm clusters.

Using coolify might be other great starting point beside my approach here as coolify is standalone open source self-hosting platform (no vendor lock-in) so you only need to setup your own server then install coolify on your server and start deploying your apps or services.

# Final Thoughts

As Im writing this blog to _log_ my server &amp; infra learning experience, this approach might not the best approach to manage your server especially for production-ready server that ready to scale, comprehensive, fully secure enough. Within this approach, I understand more about how container especially docker works and how to connect and manage containers in server through UIUX-friendly management (thanks to portainer and NPM). As I started this approach to learn about deploying apps on my own server few months ago. I do understand some of people annoyed with docker, even hate docker (as I was reading reddit thread and there is few people hate docker lmao). I might update this blog if I want to add something relevant to this blog sometime or if there is any crucial misinformation I wrote here. Even though, this approach seems &quot;beginner friendly&quot; in the beginning, it might have several weakness like build performances, not really lightweight, not really that effective, etc.

Recently, Im exploring many different deployment setups and strategies, especially more advanced and complex one. Currently, as I&apos;m writing this, I found that [nix](https://nixos.org/) is very great for server and infrastructure configuration with it&apos;s philosophy design that I might write about that someday.

Start small and experiment it by yourself, as you understand better and get more comfortable tinkering with your own server, grow your setup progressively. Don&apos;t forget to read the docs and watch some youtube videos to understand deeper and you can explore it by yourself what&apos;s suitable more for you.</content:encoded><category>dev</category><category>server</category><category>infra</category></item><item><title>Opinionated Mental Models for Agentic Workflows</title><link>https://rasyidanaf.com/blog/opinionated-mental-models-for-agentic-workflows/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/opinionated-mental-models-for-agentic-workflows/</guid><description>Tool-agnostic mental models for the agentic era. What to delegate, how to design feedback loops, and why human judgement scales LLM output.</description><pubDate>Fri, 09 Jan 2026 00:00:00 GMT</pubDate><content:encoded>import Tweet from &quot;@/components/Tweet.astro&quot;;
import Card from &quot;@/components/ui/card.astro&quot;;
import Accordion from &quot;@/components/ui/accordion.astro&quot;;

Two years ago, precisely before Christmas Day, I wrote about [using LLM for software development to leverage our shipping speed and capabilities](https://rasyidanaf.com/blog/ai-dev-less-code-max-shipping/). Fast forward, January 2026, now it&apos;s time for reflection (and crazier writing _hopefully_) especially about what I wrote about AI-assisted software development that completely changed. Some of them including my opinion, method, and tools are pretty **irrelevant** today. My opinion about how we integrate into our current &quot;engineering&quot; workflow also changed a lot. The model capabilities and current AI tools available right now also changed a lot for **LESS THAN A YEAR**.

As stated in my previous blog, I had been using cursor as my go-to IDE for AI-assisted programming last year. I also mentioned bolt, lovable, and v0 for prototyping web UI too. This year, I have completely changed how I write code and use AI compared to last year (oops, less than a year actually). Most of my workflows are now in terminal, even writing code itself (neovim btw).

I feel like what I wrote in my blog about previous years has aged like milk and some of them feel very wrong currently especially AI-powered development and _sigh_.. about [_crypto ai agents_](https://rasyidanaf.com/blog/crypto-ai-agents-hype-or-real-deal/). I wrote about specific tools, specific prompts, and specific workflows or methods, some of them are outdated (I won&apos;t mention any, you may know it).

These agentic workflows, _vibe coding_, AI-assisted engineering, context engineering or whatever it is called still feels early to me in terms of _real real serious_ maturity despite people starting to catch up to the capabilities of current SOTA models. While some argue that it is completely _bullshit_. Some companies and the _enterprises_ started to adapt to the current AI paradigm, giving their employees subscriptions to AI tools such as cursor, claude code, and ~not the worthy one which is~ copilot. Some people glaze too much about the latest models and tools capabilities (honorable mentions, opus 4.5 with claude code harness).

Based on my personal observation, with current state of AI-powered coding and workflows, we can separate types of individuals who use AI as:

- **Overhype Crowds**, basically overglazing and hyping too much every time there is a latest model release like _&quot;this is AGI, it&apos;s over, billions of programmers will be replaced in less than a year&quot;_. Indeed they acknowledge the capabilities of AI but it&apos;s kind of hyperbole that at the end it will result in _fearmongering_ to the masses and overstate something that could be huge misinformation at the end.
- **Shiny new things**, try every newest tool and model available, very chronically online about latest AI capabilities. Keep switching tools over time in short periods. This is probably somehow myself _unironically_ as I changed tools a few times from cursor -&gt; claude code -&gt; codex -&gt; back to claude code + opencode. This type of person can be divided again as FOMO, _braindead_ following shiny new things or use it to follow current LLM capabilities, stay true to themselves and able to filter what&apos;s actually useful (higher signal, less noise).
- **People who are only able to use specific tools due to company strictness**. I have seen people (and my friends) that are only able to use copilot or internal tools due to other AI tools not being allowed to be used, even blocked by company internal network. Regarding AI frontier labs, I don&apos;t know if direct big competitors—OpenAI, ~Meta~, Anthropic, and Google DeepMind—are limited to use their own tools for work or allowed to use their competitor&apos;s tools for their work or not but I assume that they are only allowed to use their internal tools and their own models for work.
- **Denial stage**, people in denial about current LLM capabilities, what current SOTA models are able to accomplish within less than a year, even anti-AI. Not really open about what&apos;s going on. Some people may still think that current LLMs generate absolute bad code most of the time and hallucinate a lot. Not able to generate high quality production code. Not embracing what&apos;s really going on.
- **Don&apos;t know what is really going on.. at all**. Worse than denial stage. Maybe all they know is _hey you wasted three gallons of water for generating these prediction tokens_. Don&apos;t know what LLMs have accomplished, their capabilities, etc. Clueless about how to use LLM other than asking LLM for helping with their simple assignments whether it&apos;s for school tasks or daily life ones.
- **Leveraging LLM to the max**. Built their own workflow and system to enhance LLM capabilities as much as possible. This type of people can be divided again because I have seen it not only for coding and programming wise but also creative works (I&apos;m not talking about endless AI slop videos generator one) and other domain works (ex: SEO, marketing/gtm, finance, biz, etc.).

What I mean by &quot;leveraging LLM to the max&quot; here is the ability to understand what an LLM is, its strengths and weaknesses, then able to pull out LLM strength and its possibility as much as possible out of current models while trying to reduce its weakness. We know that LLM has limited context length thus there is a term we call today as _context engineering_, the ability to create and manage context to get the best model output. This includes prompt, instructions, documents, external data, tool calls, and memory/history [^1]. It is hard to articulate this type clearly but to make it clear, I describe this kind of person as _they know what they are doing_.

Back to the topic, fast forward the tools are moving fast while the frontier labs keep competing each other to release their best models as fast as possible ~with its unnecessary benchmarkmaxxing~. Claude code today maybe won&apos;t be the same claude code in a year. Imagine opus 5, gemini pro 4, and gpt-6. Codex, kilocode, cursor, whatever comes next, I believe that the interface, how we interact (ux &amp; dx) will change, the capabilities will expand.

This writing will be dedicated to what I think that _hopefully_ won&apos;t change, completely tool-agnostic, **the underlying mental models** and the _thinking process_ to interact with the future _machine god_.

- what to delegate, what not to delegate
- human feedback loops design
- context structure
- when you intervene vs let it run ~--dangerously-skip-permissions~

&lt;br /&gt;
&lt;br /&gt;

&lt;Card showTitle={false} fullWidth&gt;
  &lt;Accordion title=&quot;DISCLAIMER&quot;&gt;
    So.. I want to add disclaimer that this is not **a guide**. It&apos;s snapshot of how I currently think as I&apos;m writing this with the hope that this blog is at least a bit more feel _timeless_ personally than my previous blogs which mostly are about specific approaches that limited to specific tools.

    I used opus as my writing personal assistant, it acts as my blog editor, fixing grammar, fixing typos, suggesting improvements, and expanding my ideas. Then it helps me to organize my raw thoughts and structure my content more effectively and clearly here. If there is any **llm-like** wordings style, it&apos;s kind of expected as english is not my mother language (all of my writing here is purely my own thoughts btw). The writing style, the storytelling, the *memetic* part and bad jokes are still original so llm here only used to mass-fixing grammar and typo then rearticulate some of my writing.

  &lt;/Accordion&gt;
&lt;/Card&gt;

&lt;br /&gt;
&lt;br /&gt;

&lt;Card title=&quot;TLDR&quot; fullWidth&gt;
  - **Human judgement scales LLM output** — the more domain expertise and taste you have, the better code the model produces
  - **Delegation is a skill** — knowing what to delegate, how much context to transfer, and when to take back control
  - **Feedback loops as infrastructure** — design tight, automated verification cycles (ex: ralph loop pattern) so the agent self-corrects
  - **Verification &gt; Trust** — type systems, tests, linters are your safety net; never trust agent output blindly
  - **Declarative systems win** — reproducible, sandboxed environments (like nix) are ideal agentic playgrounds
&lt;/Card&gt;

&lt;br /&gt;
&lt;br /&gt;

# 2025 Wrapped, Enter the TUI-morphism

![screenshot of my desktop](setup_ss.webp)

Let&apos;s do some quick recap of 2025, what has been happening in my own perspective about _AI-assisted coding &amp; programming_.

All started from when claude code was released, around February 2025. Instead of building AI-powered IDE or IDE extension, The Anthropic team were approaching differently for their own new product, not GUI app but TUI-based app. You write `claude` in your terminal and it&apos;s ready to assist whatever you need through terminal workflow. It can interact directly with your terminal environment such as unix commands (`ls`, `ll`, `cd`, `mkdir`, `grep`, etc). Maybe it sounds quite similar to aider but actually different as both tools have different approaches for users/developers experience for their tools.

Then there were a bunch of TUI-based AI tools that spawned. **OpenAI** made [codex](https://openai.com/codex/), another _agentic_ coding tool similar to claude code but it&apos;s written in rust ~so must be blazingly fast~ and open-source unlike claude code. **Google** and **Alibaba** made their own coding tools too, gemini-cli and qwen-code.

While those frontier labs made their opinionated coding tool to serve their own model, there is also open-source agentic tool similar to what claude code is but you can switch freely to use other models as well easily. Software company that made [sst](https://sst.dev/), **Anomaly**, developed their own open-source agentic tool called [opencode](https://opencode.ai) this year (around May-June) so users are able to use and switch all models available including using existing claude plan, using openrouter, and specific model providers as inferences while they&apos;re also able to customize and configure their tool for their own workflow. Even better, as it is open-source project, we can contribute and open PR directly to the [repo](https://github.com/sst/opencode). **Charmbracelet**, the &quot;pretty CLI &amp; TUI&quot; software company, also made their own agentic coding tool similar to opencode. Both company and their open-source tool use their own TUI framework. Charm used their existing _bubbly cutesy glamorous concept_ TUI-framework based on golang, [bubble tea](https://github.com/charmbracelet/bubbletea) while Anomaly developed their own TUI framework this year which is [opentui](https://github.com/sst/opentui) this year written with mix of typescript and zig.

## CLI.. Why???

Maybe some of you even wonder, why most of the tools are available as CLI or TUI-based instead of ~high ram usage electron~ GUI-based apps. I saw that some people even migrating back to cursor/vscode rather than using cli-based apps like claude code. Personally, I love cli-based more ~so I can larp as performative hacker looking guy when I was working in an office or cafe~ because of flexibility, customization, and control I have rather than standalone well-designed apps. I can feel the _touch_ between me and the computer more closely as it reduces abstraction layer disguised as &quot;user-friendliness&quot; when I want to interact with my computer. CLI-based app also (supposed to be) uses less resources, way lower than most of desktop and browser apps ~especially electron-wrapper or chrome-fork~.

As CLI-based coding agents are editor-agnostic, you can plug-in whatever IDE or text editor you are using. You can open claude code on cursor, vscode, or zed as it can be spawned directly by typing &quot;claude&quot; on terminal. You can also split it as vertical or horizontal panel on your favorite panel, one is opening claude code, the other panel is opening vim or emacs.

It feels nice that LLM can interact with our terminal directly using their tool calling to our UNIX system directly such as grep and ls. Especially if our project directory has a bunch of dependencies installed like uv and bun, LLMs can interact and test directly whenever need confirmation, or do some git operations..

The most obvious advantage of those coding agents being CLI-based rather than desktop app are the ability to customize further beyond your computer. You can spin up new VM, install claude code in there, and customize further your development environment in your own VM. Then you can setup your own network/internal VPN like tailscale to connect between your own device (mac and iphone for example) to your VM. Recently, I often SSH to my own VM to spin-up claude code and opencode as background worker that i can leave the task for coding. With app being terminal-based, not only we use lower resource but we eliminate more interactivity abstraction layer for more flexibility like this. You can also setup tmux or screen as multiplexer to make your own async workflow and enhance further with tiling window manager to adjust between your terminal with other apps especially for workspaces switching and window splitting (on macOS I&apos;m using aerospace while on my desktop, I&apos;m using hyprland).

## Changed The Way I Work

With these new agentic coding tools, I have changed the way I&apos;m doing programming and writing code by myself. Quick lore recap, previously as biomedical engineering undergraduate, I used vscode as default IDE most of the time and jupyter notebook to write and test code that related to data &amp; ML. Then in 2024, I changed my go-to editor from vscode to cursor as I&apos;m addicted to cursor tab (the best tab completion engine I&apos;ve ever used so far) and having better user experience to interact with LLM than copilot from vscode.

I have explored a lot of new tools whether it&apos;s existing tools or tools that released this year. Example of tools and something that I&apos;ve discovered and used in 2025 that I would classify as _game-changing_ personally: tailscale, nix, tmux, and agentic tools I mentioned above (obviously).

Now, in 2026, I comfortably write most of the code with neovim. I also write my blog on neovim as text editor with localhost server of astro website shown in my brave browser, splitted by my own aerospace that configured with my nix dotfiles on top of git worktree that separated between main branch worktree, feature implementation worktree, and writing draft worktree. I thought that learning vim keymaps and configuring your own neovim for coding are _productive slop_ to justify your coding skill and performance but turned out I was wrong. I found it really useful and makes my programming faster including for debugging, analyzing codebase, searching specific file &amp; code, and writing code. Using neovim also makes my work related to _ssh-ing_ to server easier as I can just write using vim on server directly rather than nano which I found annoying in the first place to be with. Well, I don&apos;t memorize all of vim keymaps, mostly what I use most are simple keymaps such as `:wq`, `!wq`, `:ggVG`, `:/`, `:g`, and `:&lt;line-number&gt;` (well actually way more than that).

## Somehow Nix is Perfect DevOps Tool to _Vibe_ with

This one is seriously personal perspective, I don&apos;t really care if you disagree with me but I found that nix is a perfect programming language to vibecode with related to manage packages, build, and devops. Nature of nix being purely functional and declarative feels perfect for prototyping, vibecoding, and agentic development. I have been exploring what nix and opus are capable of and it was a really amazing experience. Not only you write code for your own development environment as declarative configuration but also the multiple ways to configure your agent environment. You can use nix for _sandbox-ing_ your claude, codex, or opencode with multiple design patterns while sticking to nix core philosophy.

As of today, I have been experimenting with making customized nixos machine with [clan](https://clan.lol) framework to build dedicated VM to let agent run wild within sandbox, with nix as one of main code infrastructure here.

&lt;Tweet id=&quot;2007623702222078370&quot; /&gt;

I also wrote a blog about learning nix you can read [here](https://rasyidanaf.com/blog/the-nix-experience-managing-macos-with-nix/).

## My Current Setup

As I changed the way I work, most of the CLI tools especially agentic tools are moved to my own personal VM (derived from my baremetal server) as _work station_ that you can see on my [about](https://rasyidanaf.com/about) page. I have been thinking of building and setting up my own _dev vm_ so I can customize my dev environment to the max and there is clear separation between my own mac with actual code plumbing and testing environment. A tweet from @elliotarledge about having separate rig as work station really articulates well what I have been thinking of here:

&lt;Tweet id=&quot;2005871051864244437&quot; /&gt;

As the models and these agentic tools become too good now, I&apos;m also planning to make my own dev vm to be more _agent-friendly_ so claude is able to do some sysadmin work, committing and making some PR, opening issues, doing work in background, etc. I&apos;m experimenting with all the capabilities to fully-maximize &quot;agent&quot; as worker machine similar to mining machine in factorio for task delegation that might be connected with _cable-like_ node or network for my soon-to-be-automated workflow. As someone who has played factorio and done some _redstone-engineering_ on minecraft, you know that the end game is to automate your work as much as possible, maximize your efficiency.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# The Foundational Shift

Let&apos;s play a game of assumption, we want to take away the joy of writing code manually and we want to focus on building part and automate coding as much as possible. Coding is fully-delegated to agentic tool, we may call it as &quot;X&quot;

Now as we assume that writing code is fully-automated and delegated to AI, how do we know we achieve what we want? We verify the output of code written by AI and the result of it.

&gt; Does it compile?

&gt; Is this the output what we want to achieve?

&gt; Is the process from start to end right?

&gt; Does it return any bugs or errors? If yes, why is it? What&apos;s the root cause?

Yes we are not writing code anymore but we still need to know **WHAT IS GOING ON** and **VERIFY THE OUTPUT**. If possible, the entire process and its written code. We eliminate coding yet we have to understand the code itself. Understanding code means we should be able to read the code itself. Therefore, having the ability to read, understand, and differentiate the quality of code written by the model is important.

I call it as **human judgement**, the ability to judge code written by the model. The more experienced (senior-level) and the better you write code as an engineer, we can assume that the better your human judgement skills are. You know what&apos;s going on and able to navigate quickly what went wrong on the code. As a consequence, we made a paradox. The better you write the code, the better your code reading ability too.

&gt; So, is there ~symlink~ correlation between code writing skill and code reading skill?

Before I try to answer that simple question. I want to add disclaimer that I&apos;m bad at writing code, and probably still am to this day as I&apos;m still learning how to write proper good code, best implementation, and still not able to solve all easy leetcode challenges. But the more I learn and catch up with what I don&apos;t know about programming, compute, networking, or whatever domain knowledge I need to know correctly, the better the code output written by the model. More knowledge of web development made my instructions, contexts, and prompts curated more clearly to the model. As a result, the code output is more clear and better than when I don&apos;t really know what is really going on and can&apos;t judge what&apos;s the best way or approach in specific moment.

![correlation graph between user and llm output](xfactor_graph.webp)

Here is fully-made up theoretical correlation graph between llm output and user &quot;x&quot; factor that I&apos;m trying to model here. The &quot;x&quot; factor including the human (user) judgement, the human taste, the _right_ contexts gathered by the user, user prompt, and the user domain expertise.

Hence, my answer is more domain expertise, better ability to design the system and architecture, the better your human judgement and your taste is -&gt; the better the code written by the model (also at least able to read code and know what&apos;s going on too). Maybe the model itself knows everything, but I believe that **the model output is scaled based on the human intelligence, taste, and knowledge**. The more intelligence and better domain expertise the human is, the better model output and align with the human itself. I believe that human judgement and taste really matter the most in the current situation and in the future (I don&apos;t know until when). Okay, now we go back to the previous term that related to this which is once again, _context engineering_.

An important note: as future model capabilities and intelligence might be increasing hypergrowth, my stupid hypothetical graph between user &quot;x&quot; factor and llm output quality might be irrelevant in the future. Maybe in the future you can just prompt _&quot;pls make this app make no mistake&quot;_ and it really does without making any mistakes at all, production-grade, scalable, very-secure, with highest quality codebase that you can imagine.

## Delegation Skill

I believe that the skill to know _what to delegate or what not to delegate_ might be the most important skill here. Delegation isn&apos;t about _make AI do stuff_ only. It&apos;s more about the balancing as:

- Under-specified delegation → garbage output, wasted cycles
- Over-specified delegation → you might as well have done it yourself
- Wrong-task delegation → some things aren&apos;t delegatable (yet)

Delegation derived from context engineering, know what to handoff and how much context we can transfer to an LLM. Last, know when to take control. Delegation here also means that you **do not delegate your thinking** into ai, you delegate the task, share relevant knowledge &amp; context, and instruction.

![delegation example](delegation_example.webp)

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# The Mental Models

## The Sci-Fi Lens

![Ironman meme](https://uploads.dailydot.com/2025/02/jarvis_memes_usable.jpg?q=65&amp;auto=format&amp;w=1600&amp;ar=2:1&amp;fit=crop)

If you were watching _Ironman_ (or any marvel movies that has Tony Stark in it) or recent Superman movie character, _Mr. Terrific_, you may be familiar with _Jarvis_, the AI companion computer system of Tony Stark and _T-Sphere_, the ~agentic ai balls~ spherical electronic accessories used by Mr. Terrific.

Both are similar, used and viewed as _tool_ by the superheroes I mentioned above while the tool shown in the movies are similar to LLM.

The t-spheres respond to Mr. Terrific&apos;s mental and vocal commands. The spheres are then able to do what he is commanding such as self-propelled flight, creating holograms, manipulating other electronic devices, bombs, etc. Jarvis is giving information and what Tony Stark needs on demand based on his commands.

The keywords here are **command** which we can model it as an input to the tool itself whether through text, voice, or programmatic ways. We ask and instruct with natural language as a prompt to the model. The model then returns the output based on the input tokens. Current LLMs are also able to _act_ by calling function and executing tool defined by the user or from the model itself.

To make it clearer, here is the idea as a pseudocode for tool-calling of Mr. Terrific&apos;s t-sphere:

```json
    {
        &quot;name&quot;: &quot;information_query&quot;,
        &quot;description&quot;: &quot;Query databases and provide information (JARVIS-like)&quot;,
        &quot;parameters&quot;: {
            &quot;type&quot;: &quot;object&quot;,
            &quot;properties&quot;: {
                &quot;query&quot;: {
                    &quot;type&quot;: &quot;string&quot;,
                    &quot;description&quot;: &quot;Information request&quot;
                },
                &quot;sources&quot;: {
                    &quot;type&quot;: &quot;array&quot;,
                    &quot;items&quot;: {&quot;type&quot;: &quot;string&quot;},
                    &quot;description&quot;: &quot;Databases to query: [internet, criminal_db, satellite, local_sensors]&quot;
                },
                &quot;urgency&quot;: {
                    &quot;type&quot;: &quot;string&quot;,
                    &quot;enum&quot;: [&quot;immediate&quot;, &quot;thorough&quot;],
                    &quot;description&quot;: &quot;Speed vs depth tradeoff&quot;
                }
            },
            &quot;required&quot;: [&quot;query&quot;]
        }
    },

    {
        &quot;name&quot;: &quot;hack_system&quot;,
        &quot;description&quot;: &quot;Infiltrate and manipulate electronic systems&quot;,
        &quot;parameters&quot;: {
            &quot;type&quot;: &quot;object&quot;,
            &quot;properties&quot;: {
                &quot;target_system&quot;: {
                    &quot;type&quot;: &quot;string&quot;,
                    &quot;description&quot;: &quot;System to hack (door, camera, network, vehicle)&quot;
                },
                &quot;action&quot;: {
                    &quot;type&quot;: &quot;string&quot;,
                    &quot;enum&quot;: [&quot;bypass&quot;, &quot;disable&quot;, &quot;take_control&quot;, &quot;extract_data&quot;, &quot;inject_payload&quot;],
                    &quot;description&quot;: &quot;Hacking action to perform&quot;
                },
                &quot;stealth_mode&quot;: {
                    &quot;type&quot;: &quot;boolean&quot;,
                    &quot;description&quot;: &quot;Whether to hide intrusion traces&quot;
                }
            },
            &quot;required&quot;: [&quot;target_system&quot;, &quot;action&quot;]
        }
    },
```

Above, we defined tool definition for `information_query` and `hack_system` for t-sphere. Then we can inject these tools we defined in the system prompt of the t-sphere devices as long as the &quot;language model&quot; inside it supports tool-call. Once again this is purely fiction as we are trying to see what really LLM capable of in the eye of _sci-fi_ and its endless potential capabilities in the future.

&gt; Why are we using Ironman and Mr. Terrific as example here?

Both have in common of using natural language as primary interface. Also use Jarvis and t-sphere as a **tool** instead of standalone powerful agent. The human, Tony Stark and Michael Holt make the decision then the tools either execute, assist, or inform based on the human instruction/command.

Current open-source SOTA LLMs such as GLM 4.7, MiniMax 2.1, and Kimi K2 can be run locally as long as you have big racks of compute to run it. Assume that in the future, open-source models will be much smaller in size, same performance or maybe a bit better than GLM 4.7 as an example, can be run with less than 48GB VRAM or maybe even on your phone while context windows are expanding and the voice interfaces to interact with LLMs are enhanced. There could be more wild things you can do and achieve. Even with current models, you can connect to your favorite agentic tools and vibecode with your phone using your server/desktop as the medium via termius and tailscale.

I believe that in the future, only a matter of time, there will be decent IoT-like hardware with LLM locally run inside and able to execute action through processing LLM response blended with function-calling programmed inside the device.

We are really close to having jarvis at home (bet it&apos;s less than a decade). There is a prime example of my _x oomfie_ that I found quite creative, he leveraged his domain expertise as devops and utilizing claude code opus as his _24/7 oncall engineer/sysadmin_ as his experiment. You can read his substack [here](https://substack.com/@kuberdenis/p-182582863).

## The Gaming Lens

![redstone enginnering, minecraft](https://i.pinimg.com/1200x/af/ad/89/afad89db55ec60d6566b05383d397d8d.jpg)

Previously, I mentioned factorio and _redstone engineering_ in minecraft. This is my longer term mental model for computer-related work even pre-LLM era. Aim for

&gt; less work, focus on the output quality and quantities instead

Screw ~_hustle culture_, work 9-5, working late till night~ working like the way we did before, we should automate the boring part, repetitive part, or the part we don&apos;t like as much as we can as we measure the result of the work, the output at the end of the day. Why would we want to work longer if the output is same quality as longer work? Time is more important currency than our work, we should prioritize our free time more than doing unnecessary work that doesn&apos;t really matter. Focus on work **that matters** and the output itself then followed by the process of it to achieve the output. I wrote about [_automating yourself_](https://rasyidanaf.com/blog/start-automate-your-boring-and-time-consuming-task/) that influenced my thought here.

&gt; Why are we using factorio and minecraft (redstone engineering) as examples here?

Let&apos;s say that the &quot;coding&quot; part in programming will be automated. Fully-generated by LLM with strong verification process. We can assume that our task will be more of managing the process of it like some factorio factory, also we design the automated software development system to make sure code generated by LLM itself is high quality coding output, the verification and its testing process should be strongly reliable to make sure its production-grade code, catch all the bugs before deployed to prod as much as possible especially crucial ones to serve the program/apps to end users properly.

&lt;Tweet id=&quot;2007899893483045321&quot; /&gt;

In factorio, first you land on the alien planet as a human. You mine all the resources you need with your hand using a pickaxe to build what you need such as mining drill, reactor, steam engine, etc. Then once you successfully built the foundational production power and resource-extracting machine, we started to build the circuit network and the transport to connect each factory building and machine to scale your factory. The basic concept of this probably can be viewed as you start writing small amounts of code or just vibecoded the basic function of it, then gradually scale it to make it even powerful, feature-rich, and able to serve more traffics.

Previously, we wrote code by our hand, manually, to make sure the code is good enough (high quality code) and reliable. Ensured that the code was well-tested and thoroughly debugged to minimize errors and ensure stability. Then we found several resources and tools to help us automate the process of writing code, baremetal server, GPU, LLM api, etc. Then we use the existing tools and resources available or maybe make our own to make software as easy as possible with our system, whether from coding, testing, feature design, and deployment process.

The process of what we are doing in factorio is very similar to **system design** and **architectural choice** concepts. We have to design and think systematically, if our factory architectural design is bad, there would be consequences waiting for you. Hard to maintain, really ugly and unorganized, hard to fix (aka debugging), etc. Thus, cascading effect is created.

Early game of factorio, everything works easily, no need to think about transport system, make it like spaghetti line is fine as long as it works. No consequences yet (for now).

Mid game, you want to scale your factory but suddenly it hit several limitations and bottlenecks. Adding more iron production breaks the copper workflow, belts are tangled, hard to trace the transportation line we designed. At the end, if your factorio empire (aka late game) already big enough, you want to make the material flow predictable, train networks are well-made for logistics side, and your circuit networks to have clear programmatic control and conditional logic. Hence, in factorio, it was about designing systems that are easy to maintain and control with and scale without you (intervening with it too much).

Similar to factorio, there are plenty _programmatic mechanics_ you can leverage on minecraft using redstone as the main ingredient. Automatic farming system for waterflow on our farm and harvesting _cronjob_ for our crops. Minecraft base defense system to combat zombies and skeletons automatically without your intervention. Organizing your inventory items automatically via connected programmed redstone on your chest inventories. Building secret door with piston via lever that connected using redstone for transport system efficiency (usually for long-distance travel such as cave exploring). The list goes on. All you need is knowing how redstone functions work and your blending skill between engineering and creativity works.

We can map out these video games example for our software engineering workflow with the help of current SOTA models. Fully-maximize the potential of LLMs without losing your creativity and thinking process. There is actually more video games that I could list here like _terraria_, but I think factorio and minecraft are enough and fitting examples here to share my idea about the mental models to be working with in present and the future of AI (no idea what kind of new innovation that will occur tbh).

## Fundamental is More Important than Ever

Do you think with an LLM able to write all of the code means that you can develop _fully-functional production-grade_ complex software? Are we vibing without knowing what is git, concurrency, time complexity (o(n), o(log n), etc), caching, an array, and data structures basic? (okay about time complexity, it&apos;s not that important if we don&apos;t need to think about performance or the user only ourselves)

Are we able to make secure web app by ourselves if we don&apos;t even know how to store secrets such as an API key on `.env`? What if we `git add . &amp; git commit -m &quot;lezgo&quot;` without `.gitignore` our `.env` with our precious API keys there?

Here is one of the lamest boring jokes that I actually hate right now because I have seen it multiple times but it&apos;s the only joke I can think of regarding our current section:

&lt;Tweet id=&quot;2008056451760324803&quot; /&gt;

Yup, that&apos;s right knowing the fundamental of programming, literal computer literate, know how to use git for version control, how API works, or fundamentally how computer and internet work. Know what `http` is, understand and familiar with data structures and algorithms, one of the core courses in computer science.

My point here is, yes you can _vibecode_ all you want but please learn the fundamental. Use the LLM to augment your knowledge and also fulfill the knowledge gap too.

You don&apos;t want to ruin your _viral consumer app_ by leaking users&apos; data, including users&apos; selfies and photo ID like Tea, a dating advice app for women that went viral on Tiktok [^7].

We still need to learn, not following LLM blindly even though current models are already good enough for _yolo mode_. Remember what I said before in previous section, **the more knowledgeable we are, the better LLM output we can get**. Even if it&apos;s completely made-up hypothesis by myself, I believe learning (also strengthening) the fundamentals, and knowledge accumulation despite model intelligence that keeps improving will still benefit us in the long run. Especially our thought process and how we use LLM as a tool later on.

Here are books that keep appearing in discussions about programming fundamentals:

- [Structure and Interpretation of Computer Programs](https://web.mit.edu/6.001/6.037/sicp.pdf)
- [Computer Systems: A Programmer&apos;s Perspective](https://www.amazon.com/Computer-Systems-Programmers-Perspective-3rd/dp/013409266X)
- [The Art of Computer Programming](https://www.amazon.com/Art-Computer-Programming-Volumes-Boxed/dp/0321751043)
- [Designing Data-Intensive Applications](https://www.amazon.com/Designing-Data-Intensive-Applications-Reliable-Maintainable/dp/1449373321)

There is also recommended reading for developers from the cofounder of stackoverflow itself, Jeff Atwood, that you can check [here](https://blog.codinghorror.com/recommended-reading-for-developers/).

I won&apos;t limit the _fundamental_ in this context for computer science and software engineering literacy. But it dives deep to what you are working on such as react framework, golang, and any frameworks or programming languages you are using. I will use my past _skill issue_ (actually till now) experience of working with react as an example:

&gt; Around 2024-2025, I had a case I&apos;m working on edu startup as &gt;part-time, working on authentication (especially user auth &gt;schema validation) and making new user onboarding flow and &gt;its modal. I had specific issue regarding react (I &gt;forget what it is), but what I remember was I&apos;m repeatedly &gt;asking on cursor (claude sonnet 3.5(?)) about the problem and &gt;its solution. Claude provided 4 solutions to solve the &gt;problem I encountered and I was giving up, decided to ask my &gt;friend that understands react instead. My friend proposed the &gt;solution that I was looking for, tried to implement the &gt;solution (with help of cursor too) and finally it worked.

This is one example of how important the _fundamental_ is, not limited to &quot;programming&quot; only, basically on the scope of what you&apos;re working on too. Of course, until now I have encountered several issues I have faced that I have to search manually through stackoverflow, reading the official docs, and asking my friends for help.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Practical Primitives

After we redefine _the thinking process_ and _mental models_ of approaching and working with these token-prediction slot machines, now let&apos;s talk about the practical methods to work with these models that hopefully still relevant in the future as we are in transition era as AI disrupts current tech industry (or maybe a bubble, honestly idk man).

## Context Engineering

![required context wojak](https://i.kym-cdn.com/photos/images/original/003/033/089/164.jpeg)

Context engineering is broader than prompt engineering. Context engineering means that we hand the curated relevant context, including prompts, specific instructions, specific way, and relevant data in the limited context length of the model as we haven&apos;t solved the _memory_ problem in current model. Using MCP might overload the context window and consume additional tokens [^2]. We want to hand the context to the model with flexibility to be able to try everything [^1].

MCP, agent skill, AGENTS.md, and tool calling are one of the ways to feed LLM proper and curated right amounts of context, not too much, enough to pull out the model output as much as possible by feeding an LLM precise _right_ amounts of data, approach and instructions. Agent skill? It&apos;s just markdown and script under the hood. RAG? Feeding right amounts of external data to make an LLM output more accurate, hallucinate less, and align with what we want.

There are multiple practical ways I could think of to do context engineering from the simplest form one. For example:

- Well-made `CLAUDE.md` or `AGENTS.md` as agent entrypoint (global and project-scope)
- Explicit constraints (ex: always use `bun` not `npm`, don&apos;t use `type` = `Any` always define `types`)
- Dump right relevant amounts of docs on `docs/` then mention `@docs/&lt;relevant-docs` per feature implementation
- Breaking down big complex task into small subset tasks (modularization), no context overload. You may make the repo from the minimal/bare skeleton that works (kind of like MVP) then scale it from there.

You don&apos;t really need claude skill, subagent, plugin, another MCP, claude code/opencode wrapper, or any tool most of the time, _vanilla_ setup of claude code is fine. Adjust based on what you need, which is most of the time, context that an agent needs, not _glue-ing_ and blatantly trying all of the tools because some people told you so as they said

&gt; wow this `&lt; devtool &gt;` is very amazing, its gonna be gamechanging bro `&lt; insert pointing soyjak meme here &gt;`
&gt; -random _ai_ influencer

Also here is the claude code setup from the one, who initiated claude code in Anthropic, surprisingly _vanilla_ enough (for me)

&lt;Tweet id=&quot;2007179832300581177&quot; /&gt;

The point of context engineering is to provide highest signal to noise ratio as much as possible to LLM. Noise will make the context bloated and irrelevant (context poisoning), as the &quot;memory&quot; of LLM still not fully-solved _yet_. RAG, search tool, spec/TDD, etc, all leads to the context &amp; memory of an agent.

## Feedback Loops as Infrastructure

An iteration. A feedback loop for an agent, to make sure that final output meets our requirements. An LLM generates wrong logic? Wrong datatype? Unit testing and typecheck of our verification process will catch this first then return back the verification result to an LLM to resolve the issue. We can model this as a learning iteration of building a model from training -&gt; evaluation -&gt; result -&gt; feedback -&gt; training again.

Here is hypothetical anatomy of a feedback loop as our foundation to use it as infrastructure of our agentic workflow:

![anatomy of feedback loop](anatomy_feedbackloop.webp)

- **Action**: action means \*whats being attempted here?\*\* Specification of your software requirements, feature specification, PRD, or your detailed prompt/instruction for an LLM as markdown file can be classified as an action here.
- **Outcome**: literally the result of action we specified before. Result of the code written by an LLM with our instruction.
- **Signal**: what does the outcome tell us about the action we took? This is where we know whether our code that we generated through an LLM is correct or not. It shows clear error message, our verification layer caught the bug/error or at least we know that it didn&apos;t work once we executed the code if our &quot;signal&quot; part is not good enough.
- **Adjustment**: targeted fix based on the signal part. An LLM is able to know what went wrong based on the signal output such as suggested fix from the verification layer, typecheck error, error logs from the backend, code execution logs, and the testing results. If the adjustment part was designed badly, an LLM will do random guessing what went wrong on the code when it generates error, not properly knowing the root cause and do targeted fix/adjustment.

Assume that I want to ship software as fast as possible while the code generated by an LLM is correct and high quality enough. Not some extremely slop bloated piece of code with hard-coded secret stored directly in code. To tackle this, we want to design the feedback loop design with:

- instant feedback
- tight loop
- strict coding standards/styles
- automated testing(?)

The variable we can control to achieve those goals are loop speed and signal clarity. Clear and precise signal, faster workflow, and targeted fixes, we don&apos;t need to _re-prompting_ to the agent, let the agent consume the code execution logs/results directly as their memory for next action iteration.

Instead of `&lt;le input spec and prompt.md here&gt; -&gt; agent writes code -&gt; we review the code -&gt; &quot;claude, this is wrong, pls fix blabla&quot; -&gt; &quot;agent rewrites&quot; -&gt; we review it again next day -&gt; &lt;till the code working perfectly fine&gt;`;

We could go something like this:
`&lt;le input spec/prompt.md&gt; -&gt; agent writes code -&gt; tests run instantly through our verification layer -&gt; &quot;expected X, got Y instead at line 67&quot; -&gt; agent fixes immediately from the output -&gt; tests pass`

Clear and precise signal, faster workflow, and targeted fixes, we don&apos;t need to _re-prompting_ to the agent, let the agent consume the code execution logs/results directly as their memory for next action iteration.

Also comparing the feedback loop above, we can see clearly that the second loop is not only faster but also more automated, we are removing ourselves from the loop compared the first one. We are the bottleneck and the slowest part of the feedback loop (unironically lol). With second loop design, we pushed as much strict verification layers as possible with clear signal from the verification layer itself to be fed to an agent for next action iteration. We make the _judgement call_ in the first part only, in the first iteration, not every iteration cycle.

Recently, there&apos;s a simple yet surprisingly effective loop design that I can provide as an example here. Let me introduce [ralph loop](https://ghuntley.com/ralph/), introduced by Geoffrey Huntley in last year but it went viral this year.

It&apos;s literally just a bash loop [^3],
`while :; do cat PROMPT.md | claude --dangerously-skip-permissions ; done`

The idea is claude or any code agent executes the same prompt over and over again repeatedly in continuous loop until it meets completion criteria. There was claude official plugin for ralph loop. Since it was very buggy plugin, think it was deleted from official plugin by the anthropic staff but you can check the deepwiki of the plugin [here](https://deepwiki.com/anthropics/claude-plugins-official/5.1.4-ralph-wiggum).

![ralph-loop meme](https://i.kym-cdn.com/photos/images/original/002/089/903/e39.jpg)

Accidentally this _ralph loop_ design pattern is one of the great examples of the feedback loop as infrastructure here. Each iteration sees the results of all previous iterations; reads the current states of file/code changes, sees what was done before, and builds incrementally on previous work aka **self-referential context accumulation**.

```text
Iteration 1: Initial implementation attempt → creates files
Iteration 2: Reviews own work → identifies issues → fixes
Iteration 3: Further refinements → handles edge cases
Iteration N: Detects completion criteria → terminates
```

| default approach                 | ralph loop approach                        |
| -------------------------------- | ------------------------------------------ |
| human reviews each step          | loop IS the review mechanism               |
| feedback requires intervention   | feedback is automatic via filesystem state |
| progress requires prompting      | progress is continuous until completion    |
| infrastructure supports feedback | infrastructure is feedback                 |

I made ralph loop script (well actually generated by opus 4.5 xd) for my nixos vm with [clan framework](https://clan.lol) as module here:

```text
modules/ralph-script/
├── PROMPT.md.example
├── default.nix
└── ralph.sh
```

the ralph loop bash script (_extended_):

```bash
set -euo pipefail

PROMPT_FILE=&quot;PROMPT.md&quot;
MAX_ITERATIONS=0  # 0 = unlimited
DELAY_SECONDS=0
COMPLETION_PROMISE=&quot;&quot;

RED=&apos;\033[0;31m&apos;
GREEN=&apos;\033[0;32m&apos;
YELLOW=&apos;\033[1;33m&apos;
BLUE=&apos;\033[0;34m&apos;
NC=&apos;\033[0m&apos; # No Color

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --prompt)
            PROMPT_FILE=&quot;$2&quot;
            shift 2
            ;;
        --max)
            MAX_ITERATIONS=&quot;$2&quot;
            shift 2
            ;;
        --delay)
            DELAY_SECONDS=&quot;$2&quot;
            shift 2
            ;;
        --promise)
            COMPLETION_PROMISE=&quot;$2&quot;
            shift 2
            ;;
        --help|-h)
            usage
            exit 0
            ;;
        *)
            echo &quot;Unknown option: $1&quot;
            usage
            exit 1
            ;;
    esac
done

# Allow environment variables to override if args not provided
PROMPT_FILE=&quot;${PROMPT_FILE:-PROMPT.md}&quot;
MAX_ITERATIONS=&quot;${MAX_ITERATIONS:-0}&quot;
DELAY_SECONDS=&quot;${DELAY_SECONDS:-0}&quot;
COMPLETION_PROMISE=&quot;${COMPLETION_PROMISE:-}&quot;

# Validate prompt file exists
if [[ ! -f &quot;$PROMPT_FILE&quot; ]]; then
    echo -e &quot;${RED}Error: Prompt file &apos;$PROMPT_FILE&apos; not found${NC}&quot;
    echo &quot;Create a PROMPT.md file with your task, or specify one with --prompt&quot;
    exit 1
fi

# Check if claude is available
if ! command -v claude &amp;&gt; /dev/null; then
    echo -e &quot;${RED}Error: &apos;claude&apos; command not found${NC}&quot;
    echo &quot;Please install Claude Code CLI first&quot;
    exit 1
fi

# Trap CTRL+C for graceful shutdown
trap &apos;echo -e &quot;\n${YELLOW}=== Ralph Loop interrupted ===${NC}&quot;; exit 0&apos; INT

# Print startup info
echo -e &quot;${BLUE}=== Ralph Loop Starting ===${NC}&quot;
echo -e &quot;Prompt file: ${GREEN}$PROMPT_FILE${NC}&quot;
echo -e &quot;Max iterations: ${GREEN}${MAX_ITERATIONS:-unlimited}${NC}&quot;
[[ $DELAY_SECONDS -gt 0 ]] &amp;&amp; echo -e &quot;Delay between iterations: ${GREEN}${DELAY_SECONDS}s${NC}&quot;
[[ -n &quot;$COMPLETION_PROMISE&quot; ]] &amp;&amp; echo -e &quot;Completion promise: ${GREEN}$COMPLETION_PROMISE${NC}&quot;
echo -e &quot;${BLUE}===========================${NC}&quot;
echo &quot;&quot;

# Main loop
iteration=0
while true; do
    ((iteration++))

    echo -e &quot;${BLUE}=== Ralph Iteration $iteration ===${NC}&quot;
    echo -e &quot;${YELLOW}$(date &apos;+%Y-%m-%d %H:%M:%S&apos;)${NC}&quot;
    echo &quot;&quot;

    # Run claude with the prompt
    # Using --dangerously-skip-permissions for fully autonomous operation
    # Using --print to get output for completion detection
    if [[ -n &quot;$COMPLETION_PROMISE&quot; ]]; then
        # Capture output for promise detection
        output=$(cat &quot;$PROMPT_FILE&quot; | claude --dangerously-skip-permissions --print 2&gt;&amp;1) || true
        echo &quot;$output&quot;

        # Check for completion promise
        if echo &quot;$output&quot; | grep -qF &quot;$COMPLETION_PROMISE&quot;; then
            echo &quot;&quot;
            echo -e &quot;${GREEN}=== Completion promise detected! ===${NC}&quot;
            echo -e &quot;Total iterations: $iteration&quot;
            exit 0
        fi
    else
        # No promise detection, just run
        cat &quot;$PROMPT_FILE&quot; | claude --dangerously-skip-permissions || true
    fi

    echo &quot;&quot;
    echo -e &quot;${BLUE}=== Iteration $iteration complete ===${NC}&quot;

    # Check max iterations
    if [[ $MAX_ITERATIONS -gt 0 ]] &amp;&amp; [[ $iteration -ge $MAX_ITERATIONS ]]; then
        echo &quot;&quot;
        echo -e &quot;${YELLOW}=== Max iterations ($MAX_ITERATIONS) reached ===${NC}&quot;
        exit 0
    fi

    # Optional delay
    if [[ $DELAY_SECONDS -gt 0 ]]; then
        echo &quot;Waiting ${DELAY_SECONDS}s before next iteration...&quot;
        sleep &quot;$DELAY_SECONDS&quot;
    fi

    echo &quot;&quot;
done
```

Key points:

1. `--promise TEXT`: Completion detection via magic string (e.g., &lt;promise&gt;COMPLETE&lt;/promise&gt;)
2. `--max N`: Safety limit on iterations
3. `--delay N`: Rate limiting between iterations (it&apos;s not really needed, optional flag)

When you make a prompt, whether as a direct prompt on interface or as a markdown file. We only need two things:

- **Task**, what you want done
- **Completion Criteria**, when done, output: `FINISH` or `DONE`

An example:

```text
## Your Task

Build a REST API for a todo application.

## Requirements

1. CRUD operations for todos (create, read, update, delete)
2. Input validation for all endpoints
3. Proper error handling
4. Unit tests with &gt;80% coverage
5. API documentation in README

## Completion Criteria

When ALL of the following are true, output `&lt;promise&gt;COMPLETE&lt;/promise&gt;`:
- All CRUD endpoints are implemented and working
- Input validation is in place
- All tests pass
- Coverage is &gt;80%
- README has API documentation
```

you can also add an addition such as:

```text
## Iteration Strategy

Each iteration you should:
1. Check the current state of the project (run tests, check for errors)
2. Identify what needs to be done next
3. Implement one focused improvement
4. Verify your changes work

## Important

- Work incrementally - don&apos;t try to do everything at once
- Run tests frequently to catch issues early
- If stuck, re-read the requirements and try a different approach
- Output `&lt;promise&gt;COMPLETE&lt;/promise&gt;` ONLY when ALL criteria are met
```

From a simple claude wrapper bash script we made, we can invoke the ralph loop with something like `./ralph.sh --promise &quot;DONE&quot; --max 50` which is the completion signal is when an LLM invokes `&lt;promise&gt;DONE&lt;/promise&gt;` to end the iteration and signal that coding process is finished with 50 iterations as the limit.

There is also examples from [awesomeclaude.ai](https://awesomeclaude.ai/ralph-wiggum) based on claude official plugin that already deleted:

```bash

# feature implementation

/ralph-loop:ralph-loop &quot;Implement [FEATURE_NAME].

Requirements:
- [Requirement 1]
- [Requirement 2]
- [Requirement 3]

Success criteria:
- All requirements implemented
- Tests passing with &gt;80% coverage
- No linter errors
- Documentation updated

Output &lt;promise&gt;COMPLETE&lt;/promise&gt; when done.&quot; --max-iterations 30 --completion-promise &quot;COMPLETE&quot;
```

```bash
# TDD development

/ralph-loop:ralph-loop &quot;Implement [FEATURE] using TDD.

Process:
1. Write failing test for next requirement
2. Implement minimal code to pass
3. Run tests
4. If failing, fix and retry
5. Refactor if needed
6. Repeat for all requirements

Requirements: [LIST]

Output &lt;promise&gt;DONE&lt;/promise&gt; when all tests green.&quot; --max-iterations 50 --completion-promise &quot;DONE&quot;
```

There is more examples you can check out directly on [awesomeclaude.ai](https://awesomeclaude.ai/ralph-wiggum) as usage references.

As ralph loop is current design pattern meta for _vibecoding_, maybe in the future there might be change there will be a better design pattern emerging as model capabilities and intelligence will improve. Nevertheless, my point still intact. Ralph loop is an example of the feedback loop as foundational design pattern for agentic workflows.

Now get back to the feedback loop itself. This means that to make our code verification fast and strict, so it&apos;s more predictable and straightforward to see whenever our code works or not. What we can do are:

1. Type checkers and linters as verification layer that you can put it on your pre-commit hook or pre-push hook as _gitops_ for instant feedback/signal. Ex: `nix fmt` and `nix flake check`.
2. Fast infrastructure system, as code generation become much faster than before, we also need CI/CD pipeline that doesn&apos;t take too long to run. We need **faster** build that fails with **clear error** if possible in **seconds**.
3. Small, scoped tasks as smaller action outputs to faster outcomes, thus quicker adjustment -&gt; faster loop cycle. Not one shotting in a session (modularization is keypoint here).
4. Test as the feedback mechanism for clear signal.
5. Make failure cheap, build the sandbox, define good version controlling (aka gitops), easy rollback. Run claude yolo mode on sandbox (containerized).
6. Use strict languages. Will write more about this in the next section.

## Verification &gt; Trust

&gt; You&apos;re absolutely right

That&apos;s what it said, trust no one, an agent or yourself, verify the code, test the code as what I wrote earlier on previous section.

![trust nobody meme](https://i.kym-cdn.com/photos/images/original/001/007/647/8be.jpg)

You have heard about this often. That&apos;s right. _You&apos;re indeed absolutely right_. You can say the most wrong statement anyone has ever heard and yet claude will glaze you with _you&apos;re absolutely right_. They (agents) are confident while frequently wrong. The correct way to tackle this is _verify by default_.

Verification layers:

- Type systems (catch structural errors)
- Tests (catch behavioral errors/logical errors)
- Linters/formatters (catch style errors)
- Second opinion of agent (catch logic errors if tests are not enough, usually for complex logic)
- Ourself (judgement, true verification layer)

Verification layers help us save time to review code that actually needs to be judged properly, we don&apos;t need to waste our time to review all of the code manually. There is one more verification layer that might be important in the future, **language choice**.

## Language Choice as Verification Strategy

This section is highly opinionated, I might be very wrong here. Purely hypothesis especially for future trained LLM preparation. Take it with a grain of salt..

LLM is non-deterministic, it&apos;s a _slot machine_ that predicts the next tokens based on the input. A prediction, so the output is more likely _probabilistic_. Okay now imagine we are using OOP, it varies in determinism. There are deep inheritances and mutable state everywhere. It might compound chaotic effects.

So my hypothesis here is that the combination matters:

- non-deterministic generator + deterministic paradigm = chaos contained
- non-deterministic generator + non-deterministic paradigm = chaos compounds

| Paradigm                  | Determinism | Why                                                                               |
| ------------------------- | ----------- | --------------------------------------------------------------------------------- |
| Pure FP + strict types    | High        | `f(input) → output`, always same. No side effects. Compiler enforces correctness. |
| Strict static typing      | High        | Multi-paradigm but compiler catches errors before runtime. Ownership, borrowing, strong type inference. (Rust, Go) |
| FP + dynamic types        | Medium-high | Pure functions, but type errors surface at runtime                                |
| Imperative + strict types | Medium      | Predictable control flow, but mutable state adds complexity                       |
| OOP + strict types        | Medium-low  | Inheritance, polymorphism, state — multiple ways to be subtly wrong               |
| OOP + dynamic types       | Low         | State + inheritance + runtime typing = many degrees of freedom for bugs           |

Alright here we go, let&apos;s start another _programming language_ discourse, FP vs OOP, rust vs python, etc. You can disagree with me, I don&apos;t really mind as my current state is _framework/proglang agnostic_ and I&apos;m leaning to _software correctness_ so as long as there is the programming method that I found lean to more _correctness_ while being simple, pragmatic, and effective, I will switch, learn, and try to adapt to it.

![programming language discourse](https://i.programmerhumor.io/2024/10/programmerhumor-io-programming-memes-3cd9a99f43eb997.png)

As an LLM returns non-deterministic output, why would you code something that&apos;s non-deterministic again rather than deterministic and purely declarative leaning language? ~This is where nix fixes this~.

At least ~writing~ generating functional programming styled code is more predictable than writing OOP code as we eliminate potential bugs as much as possible by decreasing side effects that might occur (even though there is still possibility of hidden bug later on).

This is why I&apos;m betting myself to learn and lean towards more on declarative, functional programming way, also more focusing on language with less abstraction layer, more performance-focused, maybe less resource intensive (less bloated) too. I already abstract my way of coding using natural language to the probabilistic machine, why would I instruct the probabilistic machine to write dynamic unpredictable, more abstracted, programming language?

![hypothetical error strictness graph](error_strictness.webp)

&lt;Card showTitle={false} fullWidth&gt;
  &lt;Accordion title=&quot;A note on languages paradigm classification&quot;&gt;
      This is a note of a clarification in case if there is any misleading information on programming languages as I don&apos;t use all of the programming languages that have been mentioned on the graph as my daily driver. I did my due diligence to research quickly enough with a bit of googling and asking LLM (for the truth).

      Once again, I want to emphasize more on the idea of using programming languages that are more focused on software correctness, strict compiling instruction, forcing their users to write predictable and correct logic on their program all of the time before shipping their product to the public or market while the program itself is performant, less resource intensive, and does not annoy the user of the program (mmm.. microsoft, windows, no one needs that copilot feature btw).
  &lt;/Accordion&gt;
&lt;/Card&gt;

We wrote in programming languages that are more understandable and there is more abstraction combined with plenty of optimized ready-to-use libraries and frameworks with python and javascript (also php with laravel). Usually these programming languages were used by startups or new companies to develop and ship their product as fast as possible. _Do current SoTA LLMs write high quality C/C++ or rust?_

First, take a look at top programming languages on github from github octaverse 2024 [^4] and github octaverse 2025 [^5]:

![octaverse 2024](https://github.blog/wp-content/uploads/2024/10/GitHub-Octoverse-2024-top-programming-languages.png?w=1400)
![octaverse 2025](https://github.blog/wp-content/uploads/2025/10/octoverse-2025-top-programming-languages.png?w=1536)
![octaverse 2025, bonus](https://github.blog/wp-content/uploads/2025/10/octoverse-2025-most-common-languages-in-repos-built-in-the-last-12-months.png?w=1536)

As most of github codebases are dominated by python and typescript/javascript. I assume that LLMs are really great at writing dynamic type programming language (python and javascript) as there is more variety of codebase, more data trained on, and more examples of code to learn from. Even though the codebases including both bad written code and best-implementation of &quot;the way&quot; or &quot;correct&quot; way of writing code. I also assume these AI frontier giants curated their coding dataset especially anthropic, to make their LLM to be good at coding.

Well, there is also survey conducted by stackoverflow, the quora of programming, one of the biggest programming dataset providers on the internet [^6]. I also believe that (or maybe quite obvious) stackoverflow&apos;s datasets are higher quality and more curated than github codebases itself because we want the user answer as _de facto_ right answer (via most voted+verified answer sign) to the related question in the context of programming.

![stackoverflow chart 2025](stackoverflow_chart.webp)

We can conclude that the biggest training dataset from last year is javascript, then followed by python and typescript.

Despite that, some said that opus 4.5 is already _extremely smart_ and good at rust already.

&lt;Tweet id=&quot;1997182941034959118&quot; /&gt;

&lt;Tweet id=&quot;2002047169373909145&quot; /&gt;

&lt;Tweet id=&quot;1872080440724771070&quot; /&gt;

&lt;Tweet id=&quot;2001275692562960795&quot; /&gt;

&lt;Tweet id=&quot;2008197100656591194&quot; /&gt;

Those tweets I embedded here are including one of the popular app framework, dioxus and from zed itself (an IDE written in rust). Also mentioning founding engineer of helixdb, a popular database written in rust and co-founder of xAI itself which I believe they are pretty good at writing rust before (I mean they have credibility here).

As you can ~write~ generate code (at least a boilerplate) with initial steep learning curve programming languages like rust, nix, and haskell with help of an LLM, I don&apos;t think that in the future, we need to use python or javascript to speedup our development process as we can benefit these language performance benefits as Igor said in tweet above.

&gt; TypeScript grew by over 1 million contributors in 2025 (+66% YoY),
&gt; driven by frameworks that scaffold projects in TypeScript by default
&gt; and by **AI-assisted development** that benefits from **stricter type systems**.

— [GitHub Octoverse 2025](https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/)

Last year report of GitHub Octoverse supports my thesis about strict verification matters, especially when code generation itself is non-deterministic as _type-safe_ javascript ~mogged~ beat python growth last year. We can see that despite historically javascript being dynamic, the trend is toward **strictness**.

And libraries like [effect.ts](https://effect.website) are bringing typescript ecosystem to more **strictness** and adapting to heavy _FP_ pattern including immutability by default, composable, pure functions, typed-errors, and explicit side effects management.

&gt; While Effect makes usage of Functional Programming principles &gt;and patterns internally you can be proficient in Effect by &gt;simply using it as a smart Promise and forget that there is &gt;even a thing called Functional Programming

— [Effect.ts](https://effect.website)

My thesis is languages with strict, fast feedback loops will disproportionately win the agentic era (present-to-future).

## Declarative Systems as Agentic Playgrounds

We want to _sandbox_ our agent environments where agents can experiment and operate safely inside our environment. The ideal sandbox is explicit state, purely isolated, easy rollback, clear error, and easily reproducible. So you can run `claude --dangerously-skip-permissions` without overthinking what might happen once it does something stupid.

To make declarative configuration sandbox for the agent, we can use something like docker, terraform, or kubernetes (for multiple-nodes environments). However, guess what?

### Nix fixes this

| Tool           | Declarativeness   | The catch                                                                                               |
| -------------- | ----------------- | ------------------------------------------------------------------------------------------------------- |
| nix            | pure              | config → system is a pure function. same input = same output, always.                                   |
| terraform      | high              | declarative HCL, but has a state file. state can drift from reality.                                    |
| kubernetes     | intent-based      | you declare desired state, controllers reconcile. but debugging &quot;why isn&apos;t it converging?&quot; is opaque.   |
| docker compose | structural        | declares service topology, but underlying images may not be reproducible.                               |
| dockerfile     | mostly imperative | `RUN apt-get update` — order matters, results vary over time. layers are cached, not content-addressed. |

Ideally (and personally), to run an agent as wild as possible in dedicated environment, I want to make the &quot;environment&quot; versatile and flexible, we can assign it to `systemd`, or containerized it with docker/podman, or maybe assign and set it up for orchestration systems (like kubernetes) while still being fully-declarative, remain &quot;infrastructure as a code&quot; for easy reproducibility and machine management. This is where using nix shines for me.

I can configure declaratively, creatively using several frameworks, tools, combined with other programming languages with nix. Nix isn&apos;t only functional programming language, it&apos;s also a purely functional package manager tool and system configurator too. The core model of nix is:

`configuration nix -&gt; nix builds -&gt; /nix/store/&lt;hash&gt;-result`

Same input, same output. The stored path is always isolated through `/nix/store`, which is a content-addressed file system.

| property                      | what it means                                                                          | why agents love it                                                                               |
| ----------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| **purity**                    | no side effects during build. no network calls mid-build (unless explicitly declared). | reproducible. agent can retry infinitely with same result.                                       |
| **content-addressed store**   | every build artifact is hashed by its inputs. `/nix/store/abc123-...`                  | no &quot;it worked yesterday.&quot; either the hash matches or it doesn&apos;t.                                 |
| **atomic operations**         | upgrades/rollbacks are instant. switch a symlink.                                      | no &quot;rolled back.&quot; build environment is explicit.                                                 |
| **hermetic builds**           | builds happen in isolated sandboxes. no access to global state.                        | no &quot;it worked on my machine.&quot; build environment is explicit.                                     |
| **declarative system config** | `configuration.nix` describes your entire system.                                      | change config → rebuild → entire system matches declaration.                                     |
| **flakes**                    | locked dependencies, reproducible entry points.                                        | `nix develop` gives exact same shell everywhere. agent doesn&apos;t deal with &quot;wrong version&quot; issues. |

Sandboxing in nix is very flexible as we can isolate multiple layers of our choice from the computer system/kernel, network, filesystems, application, write-access, until application-layer. Almost everything can be declared and configured in nix.

```text
Build environment:
├── No network access (unless explicitly allowed)
├── No access to /home, /tmp, or anything outside declared inputs
├── Read-only access to dependencies in /nix/store
├── Write access only to build output directory
└── Isolated /etc, /usr, etc.
```

This means:

- agent can&apos;t accidentally break your system during a build (unless there is wrong configuration/method)
- agent can&apos;t rely on hidden state
- if it builds in the sandbox, it (should) build anywhere, reproducibility guarantee (98%, i&apos;m not that confident)

There are multiple patterns with a goal, to make customized sandbox on nix. Example:

- nix shell (one-off experiments)
- dev shell (nix develop)
- nixos vm (_nixfied_ linux distro)

I have been experimenting with nixos vm to build a customized agent playgrounds using [clan](https://clan.lol) since last year and it&apos;s been fun so far. I can customize and _vibecode_ bunch of features without fear of breaking my machine and make my agent operate wildly.

Okay maybe it&apos;s too biased and too specific now as we are explaining about nix instead of higher abstraction for how we interact and work with AI from present to the future. Literally contradicts what I wrote earlier in the first place. Currently, I use nix as devops and infra system for most of my workflow as aligned as it is with my mental models of working with AI agent itself. It might change in the future if there are any better alternative programming languages that suitable for environment and infrastructure building for agent playgrounds. This is also my bet that nix ecosystem will do really well personally because of current state of AI-powered coding and development.

## Environment as Interface

Now let&apos;s redefine how we interact and work with an LLM. If opus writes all of our code, and we use something like another claude or coderabbit to review our PR and code, do we need a laptop? If our current workflow is more like reviewing and verifying the code, we don&apos;t really need IDE at all?

Why would we need to use IDE then? Why are we opening VSCode just to read and review the code? Do we really need code editor as an interface for development workflow?

### My Current Setup

Recently, I&apos;ve been exploring and experimenting with my own nixos vm (using clan framework) derived from baremetal server I bought last year as _agent-first_ dev vm. I wonder how I&apos;d still be able to ship some code through phone in hand. It should come in handy when I was on public transport or anywhere, right??

The idea is simple (and unoriginal), I believe that a bunch of people have already set up this workflow anyway.

`my phone -&gt; connect to tailscale vpn -&gt; ssh agent@nixos-vm via termius -&gt; run claude inside termius`

It&apos;s quite simple, but I want it more accessible, especially the UX part, why would I open terminal then run `ssh` on my phone? Then I tried to integrate claude code with my telegram as telegram bot is easier to set up (via BotFather) rather than whatsapp or discord (personally).

&gt; Isn&apos;t there claude code on claude mobile app?

I want to make it more customizable for me, fit my workflow, not limited to my own github, I might make claude as a personal sysadmin my dev vm too so I decide to integrate it with my telegram directly.

There are two ways of integrating claude code with telegram:

- claude code cli command (ex: `claude -p &quot;pls implement auth&quot;`)
- using [agent sdk](https://platform.claude.com/docs/en/agent-sdk/typescript)

I&apos;m ending up using two of these methods anyway.

So, fast-forward here is my current personal dev vm setup and its system visualization with `mermaid.js` graph that I made by asking to claude code since I&apos;m too lazy to make it myself from scratch on excalidraw (I also asked claude to make mermaid graph wrapper component for my blog immediately as I&apos;m writing this blog),

```mermaid
flowchart TB
    subgraph Phone[&quot;📱 iPHONE&quot;]
        Termius[&quot;🖥️ Termius&lt;br/&gt;SSH Client&quot;]
        TelegramApp[&quot;💬 Telegram&lt;br/&gt;Bot Interface&quot;]
    end

    subgraph Network[&quot;🌐 MESH NETWORK&quot;]
        Tailscale[&quot;🔗 Tailscale VPN&lt;br/&gt;100.x.x.x&lt;br/&gt;P2P Encrypted&quot;]
        TelegramAPI[&quot;📡 Telegram API&lt;br/&gt;api.telegram.org&quot;]
        ZeroTier[&quot;🌍 ZeroTier VPN&lt;br/&gt;Backup Network&lt;br/&gt;Controller: greencloud&quot;]
    end

    subgraph DalangDev[&quot;🖥️ DALANG-DEV (NixOS KVM VM)&quot;]
        subgraph Systemd[&quot;⚙️ SYSTEMD SERVICES&quot;]
            Bot[&quot;🤖 claude-telegram-bot&lt;br/&gt;TypeScript/Node.js&lt;br/&gt;/claude /spawn /sessions&lt;br/&gt;/switch /send /output /kill&quot;]
            Hooks[&quot;🪝 claude-hooks-setup&lt;br/&gt;settings.json generator&quot;]
            Notify[&quot;📢 claude-notify&lt;br/&gt;Telegram notifier&quot;]
            TailscaleD[&quot;🔐 tailscaled&quot;]
            ZeroTierD[&quot;🌍 zerotier-one&quot;]
        end

        subgraph Execution[&quot;🚀 AGENT EXECUTION&quot;]
            Parallel[&quot;⚡ Parallel Claude Engine&lt;br/&gt;tmux + git worktrees&lt;br/&gt;Max 10 sessions&lt;br/&gt;/var/lib/claude-parallel&quot;]
            Ralph[&quot;🔄 Ralph Loop&lt;br/&gt;Autonomous iterations&lt;br/&gt;ralph --max 50 --promise OK&lt;br/&gt;Reads PROMPT.md&quot;]
        end

        subgraph Agents[&quot;🧠 AI AGENT TOOLS&quot;]
            Claude[&quot;💜 Claude Code&lt;br/&gt;Opus 4.5 / Sonnet 4&lt;br/&gt;from llm-agents&quot;]
            OpenCode[&quot;🟢 OpenCode&lt;br/&gt;Gemini 3 Pro/Flash&lt;br/&gt;Antigravity plugin&quot;]
            Codex[&quot;🔵 Codex&lt;br/&gt;GPT-4 / o1&lt;br/&gt;OpenAI&quot;]
        end

        subgraph Sandbox[&quot;🛡️ BUBBLEWRAP SANDBOX&quot;]
            RW[&quot;📝 READ-WRITE&lt;br/&gt;/home/agent/workspace&lt;br/&gt;/tmp /var/tmp&quot;]
            RO[&quot;🔒 READ-ONLY&lt;br/&gt;/ ~/.ssh ~/.gitconfig&lt;br/&gt;~/.claude ~/.config/opencode&quot;]
        end

        subgraph Tools[&quot;🛠️ DEV TOOLS&quot;]
            NixVim[&quot;📝 NixVim&lt;br/&gt;LSP: nixd, pyright&lt;br/&gt;ts_ls, gopls, rust_analyzer&quot;]
            GitTools[&quot;🔀 Git Tools&lt;br/&gt;git, gh, jj, lazygit, tea&quot;]
            DevEnv[&quot;📦 Dev Env&lt;br/&gt;direnv, devenv, uv&lt;br/&gt;Python 3, nushell&quot;]
        end

        subgraph Security[&quot;🔐 SECURITY LAYER&quot;]
            SSH[&quot;🔑 SSH Hardening&lt;br/&gt;Key-only, curve25519&lt;br/&gt;chacha20-poly1305&quot;]
            Firewall[&quot;🧱 Firewall&lt;br/&gt;TCP 22, UDP 9993&quot;]
            Kernel[&quot;🐧 Kernel Hardening&lt;br/&gt;SYN cookies, rp_filter&quot;]
        end
    end

    subgraph Remotes[&quot;☁️ GIT REMOTES&quot;]
        GitHub[&quot;🐙 GitHub&lt;br/&gt;0xrsydn&quot;]
        Forgejo[&quot;🔧 Forgejo&lt;br/&gt;git.rasyidanaf.com&lt;br/&gt;96.9.212.43&quot;]
    end

    Phone --&gt; Network
    Termius --&gt; Tailscale
    TelegramApp --&gt; TelegramAPI
    Tailscale --&gt; DalangDev
    TelegramAPI --&gt; Bot
    ZeroTier --&gt; DalangDev

    Bot --&gt; Parallel
    Bot --&gt; Notify
    Parallel --&gt; Agents
    Ralph --&gt; Agents
    Agents --&gt; Sandbox
    Hooks --&gt; Notify
    Sandbox --&gt; Tools
    Tools --&gt; Security
    GitTools --&gt; Remotes
```

**The claude telegram bot flow:**

```mermaid
sequenceDiagram
    participant iPhone as 📱 iPhone Telegram
    participant API as 📡 Telegram API
    participant Bot as 🤖 claude-telegram-bot
    participant Tmux as ⚡ tmux session
    participant Claude as 💜 Claude Code
    participant Hooks as 🪝 claude-hooks
    participant Notify as 📢 claude-notify

    iPhone-&gt;&gt;API: /claude &quot;fix the auth bug&quot;
    API-&gt;&gt;Bot: Webhook message
    Bot-&gt;&gt;Tmux: Spawn new session
    Tmux-&gt;&gt;Claude: Execute in sandbox

    Claude-&gt;&gt;Claude: Read files, write code
    Claude-&gt;&gt;Claude: Run tests, commit

    Claude-&gt;&gt;Hooks: SessionEnd trigger
    Hooks-&gt;&gt;Notify: Send notification
    Notify-&gt;&gt;API: POST message
    API-&gt;&gt;iPhone: &quot;✅ Task complete!&quot;

    Note over iPhone,Claude: Parallel Sessions
    iPhone-&gt;&gt;API: /spawn feature-branch
    API-&gt;&gt;Bot: Create new worktree
    Bot-&gt;&gt;Tmux: New tmux window

    iPhone-&gt;&gt;API: /sessions
    API-&gt;&gt;Bot: List active
    Bot-&gt;&gt;API: &quot;Session 1: main, Session 2: feature-branch&quot;
    API-&gt;&gt;iPhone: Show sessions

    iPhone-&gt;&gt;API: /switch 2
    Bot-&gt;&gt;Tmux: Attach to session 2
```

**SSH access via termius**

```mermaid
flowchart LR
    subgraph Phone[&quot;📱 iPhone&quot;]
        Termius[&quot;🖥️ Termius&quot;]
    end

    subgraph Option1[&quot;Option 1: ProxyJump&quot;]
        MacBook[&quot;💻 MacBook&lt;br/&gt;Jump Host&quot;]
    end

    subgraph Option2[&quot;Option 2: Direct Tailscale SSH&quot;]
        TailscaleSSH[&quot;🔗 Tailscale SSH&lt;br/&gt;--ssh mode&quot;]
    end

    subgraph Target[&quot;🖥️ dalang-dev&quot;]
        VM[&quot;NixOS VM&lt;br/&gt;root@nixos-dev&quot;]
    end

    Termius --&gt;|&quot;Tailscale VPN&lt;br/&gt;100.x.x.x&quot;| MacBook
    MacBook --&gt;|&quot;ProxyJump&lt;br/&gt;SSH&quot;| VM

    Termius --&gt;|&quot;Direct&lt;br/&gt;100.x.x.x&quot;| TailscaleSSH
    TailscaleSSH --&gt;|&quot;Identity Auth&lt;br/&gt;No password&quot;| VM

    style Option2 fill:#2d5a27,stroke:#4ade80
```

**Sandbox security model**

```mermaid
flowchart TB
    subgraph Outside[&quot;🌍 OUTSIDE SANDBOX&quot;]
        Agent[&quot;👤 agent user&quot;]
        Commands[&quot;$ sandbox-claude&lt;br/&gt;$ sandbox-opencode&lt;br/&gt;$ sandbox-codex&quot;]
    end

    subgraph Bubblewrap[&quot;🛡️ BUBBLEWRAP NAMESPACE&quot;]
        subgraph ReadWrite[&quot;📝 READ-WRITE (tmpfs)&quot;]
            Workspace[&quot;/home/agent/workspace&lt;br/&gt;Code lives here&quot;]
            Tmp[&quot;/tmp&lt;br/&gt;/var/tmp&lt;br/&gt;/run/user&quot;]
        end

        subgraph ReadOnly[&quot;🔒 READ-ONLY BINDS&quot;]
            Root[&quot;/ (root filesystem)&quot;]
            SSH[&quot;~/.ssh&lt;br/&gt;Git credentials&quot;]
            GitConfig[&quot;~/.gitconfig&quot;]
            ClaudeConfig[&quot;~/.claude&lt;br/&gt;API keys&quot;]
            OpenCodeConfig[&quot;~/.config/opencode&quot;]
        end

        subgraph Allowed[&quot;✅ ALLOWED&quot;]
            Network[&quot;🌐 Network Access&lt;br/&gt;git push/pull&lt;br/&gt;API calls&quot;]
        end

        subgraph Blocked[&quot;❌ BLOCKED&quot;]
            Destructive[&quot;rm -rf /&lt;br/&gt;System modifications&lt;br/&gt;Write outside workspace&quot;]
        end
    end

    Agent --&gt; Commands
    Commands --&gt; Bubblewrap
    ReadWrite --&gt; Allowed
    ReadOnly --&gt; Allowed

    style Blocked fill:#7f1d1d,stroke:#ef4444
    style Allowed fill:#14532d,stroke:#22c55e
```

And last.. **clan module structure diagram..**

```mermaid
flowchart TB
    subgraph Clan[&quot;🏠 CLAN FRAMEWORK&quot;]
        FlakeNix[&quot;flake.nix&lt;br/&gt;Entrypoint&quot;]
        ClanNix[&quot;clan.nix&lt;br/&gt;Inventory &amp; Instances&quot;]
    end

    subgraph Machine[&quot;🖥️ machines/dalang-dev/&quot;]
        Config[&quot;configuration.nix&quot;]
        Disko[&quot;disko.nix&lt;br/&gt;Disk layout&quot;]
        Facter[&quot;facter.json&lt;br/&gt;Hardware facts&quot;]
    end

    subgraph Modules[&quot;📦 modules/&quot;]
        AITools[&quot;ai-tools.nix&lt;br/&gt;Claude, OpenCode, Codex&quot;]
        Sandbox[&quot;agent-sandbox.nix&lt;br/&gt;Bubblewrap isolation&quot;]
        AgentGit[&quot;agent-git.nix&lt;br/&gt;Git &amp; SSH config&quot;]
        Hooks[&quot;claude-hooks.nix&lt;br/&gt;Event hooks&quot;]
        Notify[&quot;claude-notify.nix&lt;br/&gt;Telegram alerts&quot;]
        Parallel[&quot;parallel-claude/&lt;br/&gt;Multi-session support&quot;]
        RalphScript[&quot;ralph-script/&lt;br/&gt;Autonomous loop&quot;]
        NixVimMod[&quot;nixvim.nix&lt;br/&gt;Neovim + LSP&quot;]
        Dev[&quot;dev/&lt;br/&gt;git-tools, tmux, devenv&quot;]
    end

    subgraph Services[&quot;🔧 services/&quot;]
        TelegramBot[&quot;claude-telegram-bot/&lt;br/&gt;Telegram Bot Service&quot;]
    end

    FlakeNix --&gt; ClanNix
    ClanNix --&gt; Machine
    ClanNix --&gt; Services
    Config --&gt; Modules

    Config --&gt; AITools
    Config --&gt; Sandbox
    Config --&gt; AgentGit
    Config --&gt; Hooks
    Config --&gt; Notify
    Config --&gt; Parallel
    Config --&gt; RalphScript
    Config --&gt; NixVimMod
    Config --&gt; Dev
```

This is my own personal setup, I&apos;m not going to say that this is best practice or whatever it is, but I want to redefine and make my workflow much simpler and effective at the end of the day.

Termius + tailscale + VM setup of mine..

&lt;Tweet id=&quot;2003810990945911000&quot; /&gt;

And few showcases of my telegram bot utilizing both claude cli and an agent sdk..

&lt;Tweet id=&quot;2005570799928033612&quot; /&gt;
&lt;Tweet id=&quot;2007085183116419387&quot; /&gt;

The agent doesn&apos;t need your monitor, keyboard, physical presence, such as your laptop to be open as we can control it remotely.

What the agents need:

- a shell
- access to files (ssh, ftp, etc)
- network
- computer, physically or cloud (ram, cpu, storage/ssd)
- ~gpu soon~
- ~llm api key/claude code subscription~

Do work that really matters, _our decision making process_, _giving direction_, and _reviewing/human judgement time_.

### The Mental Model Shift

Hence, we can shift our mental model from as an operator perspective to as a supervisor when we are fully-utilizing an LLM to be as our _codemonkey_.

![old vs new mental model](old_vs_new_mental.webp)

We don&apos;t need to see the code writing process, Just need to be present for decision making, code review, _taste judgement_, and act as the human itself in the _human-in-the-loop_ process (even some of method like ralph loop may not need human intervention).

From this perspective, we can derive it as environment design principles for our setup:

1. **headless first**, if we need GUI like opening an IDE, it&apos;s not agent-friendly.
2. **persistent sessions**. We want to keep the agent running as long as possible ~especially codex that running in the background for 10 hours alone~. Disconnect shouldn&apos;t kill the work. Use tmux, screen, or zellij to keep the session alive.
3. **separation of concerns**. The VM where work happens is stateful while our devices are stateless clients as windows into the work.

Recalling our sci-fi perspective, using _jarvis_ of ironman and _t-sphere_ of mr.terrific as our references here, probably in the future we can view it the interaction between the human and machine via natural language voice. There is emerging app that focuses on turning speech into polished writing like [WisprFlow](https://wisprflow.ai/) as the closest thing I can imagine to make similar jarvis-tony stark interaction level mimicry. 

I haven&apos;t tried it but for mac user, there is local model that we can use such as [whisper.cpp](https://github.com/ggml-org/whisper.cpp) to plug in openai whisper locally with your mac. Or..

&lt;Tweet id=&quot;2009295329057702081&quot; /&gt;

## Knowing When to Take the Wheel

Even though I wrote about delegation, fully-AI feedback loop most of the time here, not everything should be delegated. Knowing when to delegate and take over are very important too.

Delegate when:

- task is well-specified
- verification is cheap or almost fully-automated
- time is the bottleneck
- failure is recoverable
- the task is safe enough to be handled by an LLM

Take over when:

- when we are debugging the agent more than the problem
- context _might_ be too complex to transfer efficiently
- when we could finish the task faster by doing it ourselves
- critical human-needed review task (ex: handling prod database)
- the task requires judgement we can&apos;t specify

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Closing Statement

Different than most of previous blogs I&apos;ve written so far, in this writing, I&apos;m emphasizing more on the thinking process and our approach as we, the human to interact and work with an LLM. What I wrote here might be outdated in the future as the technology of this machine god evolves beyond our current understanding.

We&apos;ve heard that &quot;AI is going to replace the JOB&quot;, &quot;AI will automate most of our life aspects&quot;, and the other things over years. Despite all of that, what truly matters right now are:
- our decision-making ability, the human judgement
- ability to adapt to new situations (obviously)
- communicate effectively with machines (context engineering??)
- ability to collaborate with other humans
- creativity and artistic *taste*
- ~ability to act and do the thing lol, ppl call it as &quot;high agency&quot;~

![taste is all you need](taste_need.webp)

I don&apos;t know what&apos;s coming next, I might be very very wrong again like previous blogs but what I can do is **adapt** like mahoraga&apos;s adapting to all incoming sorcerers&apos; attacks (sorry for inserting cringe jjk panel joke here)

![mahoraga](mahoraga2.webp)

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

---

[^1]: [12 Factor Agents, Dex](https://www.humanlayer.dev/blog/12-factor-agents)

[^2]: [Code execution with MCP: Building more efficient agents, Anthropic](https://www.anthropic.com/engineering/code-execution-with-mcp)

[^3]: [Ralph Wiggum as a &quot;software engineer&quot;, Geoffrey Huntley](https://ghuntley.com/ralph/)

[^4]: [Octoverse: AI leads Python to top language as the number of global developers surges](https://github.blog/news-insights/octoverse/octoverse-2024/)

[^5]: [Octoverse: A new developer joins GitHub every second as AI leads TypeScript to #1](https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/)

[^6]: [Stack Overflow 2025 Developer Survey](https://survey.stackoverflow.co/2025/technology?referrer=grok.com#most-popular-technologies-language)

[^7]: [Tea dating advice app confirms hack, says 72K images, including selfies, accessed](https://abcnews.go.com/GMA/Living/new-dating-advice-app-tea-rockets-1-app/story?id=124067965)</content:encoded><category>ai</category><category>tech</category><category>dev</category></item><item><title>Start Automate Your Boring &amp; Time-consuming Task</title><link>https://rasyidanaf.com/blog/start-automate-your-boring-and-time-consuming-task/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/start-automate-your-boring-and-time-consuming-task/</guid><description>Automate repetitive workflows and boring tasks in your life</description><pubDate>Thu, 07 Aug 2025 00:00:00 GMT</pubDate><content:encoded>These past few years, AI (LLM) already there almost in every aspects of our life. You want to quick search something, instead of using google, maybe some of us are using ChatGPT or Gemini instead. 

&gt; &quot;explain what is llm for 12 years old kid&quot;
&gt; &quot;how does webhook work? can you use real world analogy to simulate how webhook works &quot;

More advanced usecase, sometimes we want to quick research stuff such as comparation between X and Y with its pros and cons or gather bunch of scientific journals &amp; research papers about how beneficial is creatine 10g per day using deep search feature of ChatGPT. Some of us use LLM to fully-generate their own thesis or literature paper for assignment. These powerful text and image generation by current model make automation more powerful than before. You can even enable more powerful automation with agentic power from LLM itself.

As you can see there is ~~AI slops~~ AI-generated content everywhere on the internet. You open LinkedIn, the first thing you see...

&gt;UNPOPULAR OPINION:
&gt;
&gt;Failure isn&apos;t the opposite of success.  
&gt;Failure IS success.  
&gt;Success is just failure that kept going.  
&gt;Going is just success that failed to stop.  
&gt;Stopping is just going in reverse.  
&gt;Reverse is just forward with extra steps.
&gt;
&gt;Mind = BLOWN 🤯
&gt;
&gt;Tag someone who needs to see this PARADIGM SHIFT!
&gt;
&gt;#Failure #Success #Mindset #Philosophy #DeepThoughts #Inspiration

Then you open Instagram, this is the first reel do you see which is... AI slop.

You have enough of this, you open Tiktok, there is AI-generated brainrot everytime you scroll it. It&apos;s over, every corner of you see on the internet is AI slops. Blog content from google search, Instagram reels, Tiktok videos, etc. Even though I was writing this blog and my thought manually, Im still using AI to assist my writing especially Im suck at writing and there is too many grammatical error too. But you get the idea, you can automate this whole mass AI-generated content automation workflow, schedule it to post on Instagram, LinkedIn, and Tiktok easily right now. You just need tools to generate post (LLM API), generate video (ex: VEO 3), maybe AI voice too (ex: ElevenLabs) then glue it into your automation workflow (in this blog we will use n8n). 

On serious note, with current AI tech, we can build many automation workflow with A tech integrated that I could list as much as I can, especially for biz:
- automated invoicing and payment reminder
- automated demo booking followups
- server setup (devops)
- log &amp; error monitoring
- personalized news aggregator
- document summarizer
- ai chatbot with google meeting &amp; google calendar tool
- the list goes on...

At my current job, I integrated AI automation workflow using n8n successfully on SEO division. I n8n-pilled almost entire SEO team at my company for their daily workflow. They are non-technical (non-technical means not touching code) but quite tech-savvy to understand the tool. There was a time when my coworker was frustrated a lot because self-hosted n8n was down. That&apos;s how important n8n is on SEO team now. Performance wise, since they are using n8n, both their productivity and outputs are increased a lot. More tasks get done in less time while our company website and client website traffics is increased a lot. 

For SEO, automation workflow not only used for content generation/writing only. You can use it to analyze competitor blog content, automated keyword research,  multi-page generation, running technical SEO audit with AI analysis, etc. There is a lot of you can automate in SEO task to save your time.

Alright, enough of n8n glazing and hyperbole of automation. In this blog, I want to share my learning journey and experience of using n8n to automate my own assignment, task, or whatever it is then start applying it into my workflow too. 

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;


# Using n8n (Non-tech friendly)

n8n is open source zapier/make dot com alternative tool to make automation workflow. You might heard n8n several times either from social media like LinkedIn or X (usually they are posting n8n template for engagement bait). I use n8n here as example because it is open source, which is give me more control, more customizable, flexibility, and self-hostable so I could save a lot of money by self-host it by myself on my own server with full controll. The second biggest thing why Im using n8n here because of its massive community. You can check their reddit community on [r/n8n](https://www.reddit.com/r/n8n/) which is one of biggest communities in reddit and if you are confused about n8n or maybe need some n8n workflow ideas, you can crawl on their reddit community or ask on there. Beside reddit, it has community in facebook, X community, also several people such as software developer and marketer are using n8n too (based on my LinkedIn feed lol). 

The initial setup and configuration of n8n for non-technical people may sounds confusing especially self-hosting part. 

## Self-hosting Setup

Basically, you self-host n8n via docker compose as you can read more details in [their docs](https://docs.n8n.io/hosting/). Self-hosting n8n requires technical knowledges such as:
- Setting up and configuring servers 
- Managing application resources &amp; scaling it
- Securing server and applications (n8n)
- Configuring n8n itself

What i mentioned could be expanded to:
- Choosing server (VPS or cloud), tools and dependencies on your server including databases, knowing what container (docker) is, and basic sysadmin knowledge, etc.
- Set up SSL for secure connection, do some security audit to identify security risk on both your server and application, setting up user auth &amp; credential, etc.
- Setting up monitoring for your own server and n8n instance also configure log collection.

The list could goes on, if you are still interested about self-hosting, I covered the blog dedicated to (should be) beginner-friendly self-hosting setup I used with container approach you can read [here](https://rasyidanaf.com/blog/dockerize-everything-approach-for-easy-self-hosting-server-setup/)
As it is kind of (a bit) time consuming to write docker compose yml configuration from scratch, here is n8n self-hosting templates that you can directly `docker compose` on it (I&apos;ll update the list if I found another n8n docker compose template):
- [self-hosted Starter Kit by n8n](https://github.com/n8n-io/self-hosted-ai-starter-kit)
- [n8n auto-scaling template by a redditor](https://github.com/conor-is-my-name/n8n-autoscaling)

You can also ask Gemini or Claude to make customized n8n docker compose yaml file for yourself but **you need to verify whats written there and quite technically knowledgeable** as LLM still hallucinate a lot and may generate misconfigured/incomplete yml file.
## Anatomy of n8n

We can breakdown n8n components into three components:
- **Canvas**, whole board where you visually map out your automation logic. You can also add sticky note as your automation workflow documentation on there.
- **Nodes**, the lego bricks of n8n. Nodes can be divided into several types:
	- **Trigger node** as starting point of your automation workflow. There is several trigger nodes you can select based on your need. You can trigger the start of workflow manually, run the workflow when something happens in an app like Airtable or Telegram, triggered on a schedule (basically cronjob), triggered via webhook, etc.
	- **Core node**, literally basic node that usually used in automation such as HTTP request/API call, webhook, running custom code, execute command, wait/delay node, etc.
	- **Flow node**, type of node to do some control structures aka statement that manage the flow of automation such as for loop, if else statement, branching, filtering, etc.
	- **Data transformation node** to manipulate, filter, or convert data such as filtering data, editing data, removing data duplicates, etc
	- **AI node**, think this is their newest node which is used for LLM/AI integration such as OpenAI/Gemini model node, AI Agent node, and LLM Chain (LangChain) node
	- **App node**, used to integrate external app into your n8n workflow such as google sheet, notion, salesforce, discord, etc. 
- **Connections** which is line that connect your nodes.

Actually these app node can be replaced easily with custom HTTP request node (literally API integration) even though n8n already provides hundreds of prebuilt integrations. HTTP request node lets you connect to **any services with REST API**. Meanwhile existing prebuilt app node such as salesforce, jira, and slack node is useful for non-technical user as it abstract away the complexity of authentication and API structures.

## Workflow Examples

There is plenty workflow you can do ~~and as I&apos;m too lazy to provide detailed workflow examples~~, you see many n8n automation templates depend on your need in their [official template page](https://n8n.io/workflows/). You can pretty much recreate zapier or make dot com automation in n8n. You can also get the idea from bunch of n8n videos on youtube made by some typical &quot;AI&quot; influencer that also happen to run AI automation agency (no offense, just stereotyping) also I already mentioned few examples before in intro section. 

### 1. Sales &amp; Marketing Automation

&lt;br /&gt;

#### Lead Generation &amp; Enrichment

With n8n, you can make **end to end lead generation pipeline** such as from `scraping raw data` --&gt; `processing raw data &amp; transform the data (ETL)` --&gt; `google sheet (update row) node` to give bizdev or SDR (sales development representative) leads to be reached out.

![n8n node for lead generation example](n8n-node-example.webp)

Here is visualization and example of workflow of **simple lead generation** using apollo API and append lead data directly into google sheet. With this workflow, you trigger the workflow manually by clicking the button then we read our working sheet first on google sheet to know the sheet structure (columns, rows, values, etc) in our current working google sheet then we send/post HTTP request to apollo API endpoint to get the leads data from [apollo](https://apollo.io). After we get the output from API call request of apollo, we can pass the json variable such as `first_name`, `last_name`, `linkedin_url`, `email`, etc. into google sheet rows in declared column. As raw json output from apollo API already parsed into *drag-able* object in n8n, you can **drag &amp; drop** json values directly into column field to update google sheet rows.

![Inside of n8n node for lead generation](n8n-inside-example.webp)

By try the node one by one, you will know the input, output, and structure of your node including google sheet read sheet node, HTTP request node, and google sheet update row as shown in the image above. You can directly pass the input from previous node to next parameter fields of node such as passing google sheet column values (from google sheet node) into HTTP request node for query purpose.

You can also do lead enrichment automation on n8n. In this workflow below, I used [brave search](https://brave.com/search/api/) API to search &amp; find a value that need to be enriched within loop (per row). You can use other search API such as [exa](https://exa.ai) or even combine both of APIs for it (more expensive cost). Then the json data from brave API passed into &quot;Information Extractor&quot; node which is used to extract information from text (in this case, its json output of brave search and the result of LLM) into a structured format (json) in loop (per row). Thus, with consistent output from information extractor node, we can pass the output consistently into google sheet rows.

![n8n node for lead enrichment example](n8n-lead-enrichment-node.webp)
![n8n prompt engineering for lead generation example](n8n-prompt-engineering.webp)

With HTTP request node, you can literally fetch any API you want for lead generation or lead enrichment such as [firecrawl](https://firecrawl.dev), [apify](https://apify.com), and [hunter.io](https://hunter.io). Then put gathered leads data into google sheet, airtable, or notion. Even as SQL database such as PostgreSQL. So the limit is your creativity &amp; design thinking of how you envision the n8n workflow would be like.

&lt;br /&gt;

#### Sales Pipeline

In sales division, managing sales process and its pipeline are kind of tiresome. SDR need to adjust deal stage manually, update current leads status manually, etc. Its kind of suck and manually time-consuming to do that, they are better focusing on sales process instead of doing that operational side on sales pipeline. This is where automation workflow come handy.

As popular CRM such as salesforce and hubspot are available on n8n, you can play around to optimize the sales process using n8n. For example; 
- `deal moves to new stage` --&gt; `CRM webhook triggered` --&gt; `from webhook, new update email triggered to the prospect`
- `lead expresses interest` --&gt; `send email to lead with a calendar link for book a meeting` --&gt; `automatically add book meetings to your calendar via google calendar node`
- follow-up automation on proposal or quotation/invoice

&lt;br /&gt;

#### Other . . .

Well there is a lot of you can do on sales/marketing automation side, its up to your creativity &amp; system thinking including on customer engagement &amp; retention, email automation, webinar/event promotion, tracking leads from utm source, etc.

&lt;br /&gt;

### 2. Social Media

As stated in the early paragraph, in the age of generative AI, this domain shines if you combined AI with automation workflow as you can see there is AI slops everywhere. I won&apos;t go in detail here as I&apos;m not really using n8n for social media one. But here is idea:
- **Automate content publishing**, such as using google sheet for content calendar then scheduled post to different platforms at the right time using branching node.
- **Automate blog post sharing to social medias**, `when new blog post published` --&gt; `triggered RSS/CMS webhook` --&gt; `n8n automatically share blog post with AI-generated caption using AI agent node with blog post url`
- **Social media sentiment analysis**, `collect comments, mentions, or hashtags` --&gt; `analyze sentiment using LLM/AI API` --&gt; `flag negative feedback for review`
- **Weekly/monthly performance reporting**, `fetch analytics data (likes, comments, shares)` --&gt; `send a summary report to team either using telegram, slack, or email`
- **Content curation**, `monitor twitter trends or reddit hot topics` --&gt; `send daily digests to team`

&lt;br /&gt;

### 3. Finance &amp; Accounting

Actually few finance &amp; accounting tasks could be fully automated such as simple bookkeeping or even you can automate your personal finance (aggregate personal expenses into sheet or something like that). Here is few example:
- **invoice processing**, `parse incoming invoice emails or invoice messages` --&gt; `transform parsed raw data from invoice to structured data` --&gt; `pass it into accounting software, notion, or google sheet node`
- **Expense report**, `collect receipts from emails/forms` --&gt; `compile as reports` --&gt; `send for approval`.
- **Payment reminder**, `if overdue invoices for x days` --&gt; `trigger webhook` --&gt; `send reminders email about overdue invoice`

&lt;br /&gt;

### 4. IT &amp; DevOps

You can use it for IT operation stuff but I dont think its necessary as usually these IT/Network/SRE guys already quite tech-literate and have their own tools and workflow to automate but n8n could be used for devops automation workflow tool such as;
- **Server health monitoring**, `monitor server uptime or resource usage` --&gt; `send alerts to telegram node if thresholds are exceeded`
- **Automated backups**, cronjob/schedule database or file backups to cloud storage (ex: S3, minio, gdrive).
- **Incidence response**, when an error is detected in system log/monitoring tools, `workflow webhook triggered` --&gt; `jira node to create a ticket` &amp; `notify the team on slack`

&lt;br /&gt;

### 5. IoT &amp; Smart Home Automation

If you have homelab setup or maybe some kind of personal home server setup (or raspi with server to tinker with), you can play around using n8n to tinker with your home device or some electronic devices such as;
- **monitoring smart devices** and send alerts if something goes wrong or offline.
- **trigger actions** based on time or sensor data
- **aggregate &amp; report** on energy usage from smart meters

&lt;br /&gt;

### Other Ideas

There is a lot of things you can do using n8n, you only need to focus on what problem are you trying to solve first and specify your (company/self) pain points especially manual time-consuming task that could be solved using automation tool such as n8n.

## Wrapping Up

n8n is just one of low-code workflow automation tool out there, if you have spare VM &amp; doesnt want to pay existing popular workflow automation such as zapier &amp; make dot com. As n8n is tool, doesnt mean that every problem especially automation things could be done using n8n.  To use it, even though more &quot;non-tech friendly&quot; than straght scripting, you still need to figure out what API is, deploy, docker, etc which is ironically kind of technical things. Even though I used n8n a lot in my current company, I still do a lot of coding for other task. 

IMO, n8n is suitable for small-medium enterprise/organization, not really for big corpo. Maybe able to use n8n at big corpo scale, but there is existing enterprise-level automation tool such as [Power Automate by Microsoft](https://www.microsoft.com/en-us/power-platform/products/power-automate). There is also existing role for automation (ex: RPA developer) and it uses old existing enterprise automation tech especially banking.

However, as workflows scale in complexity or demand higher performance, it&apos;s crucial to recognize the trade-offs. For mission-critical applications, I would rather **switch to custom coding for greater flexibility and more granular control over performance and security**. 

At its core, n8n is a **wrapper**, providing a user-friendly layer over underlying libraries and APIs. This abstraction, while convenient, comes with inherent limitations, especially in advanced fields like AI.

### Performance &amp; Flexibility

With custom code, you have complete control over your application&apos;s architecture. Instead of relying on n8n&apos;s general-purpose environment, you could build a solution using a **lightweight framework or programming language** like FastAPI, Hono.js, and Golang to boost API serving speed. This level of optimization is essential for high-throughput systems where every millisecond counts. You might also ending up overengineering on making complex automation workflow on n8n that easier to do it on code instead.

### Security

Custom development allows for a more robust and tailored security. You can meticulously manage dependencies, implement specific authentication protocols, and enforce stricter data handling policies beyond what a generalized platform can offer.

### AI Agent

This is particularly evident when building AI agents. n8n&apos;s capabilities are powerful but often rely on a specific framework like [LangChain](https://www.langchain.com/). Personally, I don&apos;t really like using LangChain even though I was using it a lot when GPT4 was released because of bloated dependencies and abstraction also there is a lot of AI Agent framework that not Python-native &amp; with more lightweight &amp; efficient than LangChain itself (also you dont need any framework tbh to write simple AI Agent workflow).  By coding your own agent, you break free from these constraints. You can implement more sophisticated **evaluation metrics for speed and security**, choose alternative models, or even design a more efficient, custom agent architecture from the ground up.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Straight Scripting &amp; Coding

n8n is great tool to visualize your automation logic &amp; understand better whats going on as it shows the visualization of it with execution logs on the UI. Well, lets back to the fundamental aka first-principle thinking. You can just writing automation logic in a standart programming language and running it directly on a server (or maybe using [docker](https://rasyidanaf.com/blog/dockerize-everything-approach-for-easy-self-hosting-server-setup/)).

![back to scripting for automation](reject-humanity.webp)

Instead of using n8n which provides visual canvas with nodes, integrations &amp; connections UI, and web-based interface for execution. You can have:
- **a script or codebase (logic)** like `daily_report.py` that contains the preceise logic for your task.
- **an environment (playground/space)**, dedicated space for your code to run such as VM, docker container, or cloud.
- **scheduler (trigger)**, time-based job scheduler, `cron`, common used linux command to run time-based scheduling script automatically.
- **data &amp; connectivity**, who or what the automation interaction with. Ex: third party user data API to our server (host), database integration on our automation task (wheever sqlite to serve directly on file or connect to postgres), and https connection to public internet also network path to internal database server.

You trade the drag &amp; drop UI for the raw power and clarity. I added this subheader dedicately on this as alternative of using existing automation workflow because my coworker was asking how to handle stuff especially on scraping and crawling. My coworker really depends on n8n for **literally, almost everything** that I found few of his task could be easily done straight scripting and run it directly rather than using n8n. I found few of his n8n workflows are **too complex and not efficient** that I thought Id rather just vibecode it using claude sonnet for 5 mins and it could be solved. As non-technical, he has really good backend logic, debugging/handling error, and algorithm design (let&apos;s say overall computational thinking) but he doesnt know how to code, entirely depends on n8n. Thus, this section was created *here*.

![automation progression from low-code tools to the coding automation tech stack](automation-progression.webp)

Script running on lean linux VM or in a minimal docker container has virtually zero overhead as it doesnt need to power a web server, UI, or an abstraction layer that translates visual nodes into executable code. Your script does *exactly* what you wrote and nothing more, resulting in faster execution and lower resource consumption

With scripting, you are never limited by a platform&apos;s available nodes or integrations. Need any specific libraries or dependencies? Python libraries? Specific Node.js SDK? you can just `uv add`/`pip install` or `bun install` on your codebase/directory. You can even directly use specific command such as ffmpeg on your VM directly or add in on your docker container. 

Custom logic? Your business logic can be as complex and unique as you need it to be, without trying to force it into the constraints of pre-defined node. Also implement sophisticated, custom error handling, retries with exponensial backoff, and alerting mechanism *precisely* based on on your needs. You control your entire stack, which means you control its security too (yes, if the security you wrote was bad, you are *cooked*). 

There&apos;s might be concern in how long it takes to write automation script &amp; run it. Well, we are living in LLM-dominated era. Learn to code together with, being able to read code, you will learn about it in the long run then write the code fast with LLM as leverage for learning tool or just [vibecode](https://rasyidanaf.com/blog/ai-dev-less-code-max-shipping/).

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# TLDR

To summarize this, if you are not non-technical and there is workflow or task that repetitive that could be automated (both your personal life &amp; work/job), you can start from exploring and do it with more ux-friendly webapp such as zapier and make dot com --&gt; gradually using n8n as alternative option for more control, flexibility, and cheaper option --&gt; learn how to code &amp; how automation works deeply --&gt; make &amp; configure your own automation workflow, so you dont need to depend on specific tools for automate your daily life.

Also with current AI models, there is better ways to automate stuffs you wanted, leveraging TTS model for automation usecase that need voice output, LLM for writing, reporting, even better, you can customize your own LLM with tool calling that could broaden your automation workflow to become more flexible and powerful (I will write dedicated blog about tool calling in LLM someday).</content:encoded><category>tech</category><category>automation</category></item><item><title>The Nix Experience: Managing macOS with Nix</title><link>https://rasyidanaf.com/blog/the-nix-experience-managing-macos-with-nix/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/the-nix-experience-managing-macos-with-nix/</guid><description>Introducing Nix and my experience of using Nix as ultimate package manager and system configuration tool.</description><pubDate>Sat, 13 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&gt; Cover featuring artwork by [@\_liellac](https://x.com/_liellac), Kudos to the artist for my hero image 🙏

Few months ago, I decided to try nix as my package manager to replace Homebrew as I feel like using Homebrew overtime brings back the feeling of messy dependency hell (like miniconda on Python) on my macOS, also, I was shilled by my X oomfie to try nix for superb configuration experience that may fit with my idea of what ideal development environment looks like(?). Anyway, I got carried away, went deep on nix rabbit hole, and started tweaking my macOS system configuration, including shell, secret management, window manager configuration, etc declared using nix on single dotfiles repo.

Also ~~as performative larpmaxxing techbros~~ I promised to myself in my previous [blog](https://rasyidanaf.com/blog/dockerize-everything-approach-for-easy-self-hosting-server-setup/) that I will be writing about nix someday. Finally, this is the first blog I&apos;ll be writing about nix, starting from my macbook setup first!

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# What is Nix

Nix is purely functional package manager and build system configuration tool that is built around the ideas of being declarative, reproducibility, and version-controlled. You can think of it as combination of:

- **Git** for rollback and version control
- **Docker** for &quot;yo its work on my machine!&quot; reproducibility
- **Terraform** for declarative infrastructure as code (IaaC approach)
- **Make** for deterministic builds

But it&apos;s designed for package management (also system too) such as AUR (arch linux), homebrew, apt, npm, etc. Maybe the analogy I use here is a bit misleading as even though it uses concept of &quot;reproducibility&quot; like in docker, nix builds from source, not containers. Think of it like git where every change creates a new &quot;commit&quot; you can roll back instantly like time machine and nothing gets overwritten and randomly breaks. Also I stated that its like terraform due to its _Infrastructure as a Code_ nature to configure your packages and its configuration, but remember that nix is functional programming language and everything is treated as immutable and deterministic.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Nix Design &amp; Core Ideas

## The Nix Store

Nix stores packages you declared inside `/nix/store`. Each package is stored in isolation, so no two packages have the same file name in the store as each package gets a unique hash based on its inputs (ex: `nix/store/&lt;hash&gt;-package`). Let&apos;s say that I installed firefox and python on my macbook, It could be looks like this,

```text
/nix/store/
├── a1b2c3d4...-firefox-120.0/
├── e5f6g7h8...-firefox-121.0/
├── x9y8z7w6...-firefox-120.0/
└── m3n4o5p6...-python-3.11.5/
```

As you can see that there is same version of firefox in the nix store (also there is different version of firefox exist too). However, all their hashes are uniquely different, thus both are different since the hash represents:

- source code
- all dependencies
- build instructions/build script
- build environment
- patch applied and its configuration

So hash is not only used to uniquely identify not just the package but the entire context of how the package itself was built aka build context.

This is what I mean by nix&apos;s **immutability**. Multiple version, whether it&apos;s older, newer, even same version can coexist (with different build/dependencies). Nothing was overwritten. Nothing was mutated. This makes us able to rollback to previous version easily when we are failing at updating our package also no dependency conflicts since each package are isolated in nix store as I stated before.

Upgrading your package through nix does not overwrite or delete your old version of your package. It just append new artifact inside `/nix/store/`. Also you can&apos;t modify `/nix/store/` by its design and file permissions. The nix store supposed to be read-only permissions. If you try to edit a file with sudo/root, you will get a permission denied error. With this immutability of `/nix/store/`, builds are deterministic and rollbacks and switching are instant.

Then you might be wondering,

&gt; If we can&apos;t delete the nix store each time we are updating package means that appending more to the nix store, the storage will be pilling up and bloated then???

Nix tracks which store paths are &quot;alive&quot;. Anything unreferenced can be removed via **garbage collection**. You can collect garbage manually via nix command such as `nix-collect-garbage -d` (not best way to do it tbh) or run it periodically (daily, weekly, monthly, up to you). Here is example snippet of using GC on your nix files:

```nix
  gc = {
    automatic = true;
    interval = {
      Weekday = 0;
      Hour = 3;
      Minute = 30;
    };
    options = &quot;--delete-older-than 30d&quot;;
  };
```

For this one, I take it from my dotfiles code (macOS host) which is runs every Sunday at 3.30 AM. Weekday 0 means Sunday, weekday 1 =&gt; Monday, weekday 2 =&gt; Tuesday, the list goes on. Also the code above delete generation older than 30 days too. So its kind of _cronjob_ configuration to run nix garbage collection.

With this immutability and isolation level provided by nix, you can aggressively FAFO your setup whether it&apos;s your desktop dotfiles, VM, and ~production server~ as you can never truly &quot;break&quot; your system because you can always roll back to previous generation where nix store referenced a different set of paths. Actually you can also simulate the test (`darwin-rebuild switch --dry-run` on macOS or `nixos-rebuild switch --dry-run` on NixOS) also if you are using flake (we will talking about it later) you can do some QA first via `nix flake check`.

It also solves dependency hell due to this nix store design. Let me give the example of this:

```text
App 1 needs python311
App 2 needs python312
System can only have one version in usr/lib
# Cooked, there is conflict here
```

I&apos;m using python as example above, but you can literally replace it with any package as study case. In nix, it will be looks like this:

```text
App 1 depends on: /nix/store/abc12345cde-python311
App 2 depends on: /nix/store/hjsdga321983-python312
# Damn we are cooking here, both exist independently
```

## Declarative &gt; Imperative

Usually when you are using homebrew, you have to do something like this:

```bash
$ brew install node
$ brew install python
$ brew install --cask firefox
```

Or maybe on ubuntu machine:

```bash
$ sudo apt update
$ sudo apt install node
$ sudo apt install python3
```

With imperative style, you state &quot;how to do it&quot;, you are giving directions step by step the way of doing it. While on nix, you can just state what do you want like this (oversimplify version):

```nix
{
  environment.systemPackages = [
    pkgs.git
    pkgs.python3
  ];
  #define the environment and path here
}
```

Disclaimer that this is truly oversimplified code snippet and explanation, and as I don&apos;t want to go detail either, I hope you get the idea of this 🏃‍♀️

## Atomic Operations

With homebrew, `brew upgrade node` could be scary sometimes. It downloads newest Node available then overwrite the files in `/usr/local/Cellar/node`, symlinks get shuffled, and if there are network drops mid-install or there is compile error, we are cooked there. We could be left with a broken, half-upgraded node that might not even respond to `node --version`. It&apos;s in an inconsistent state.

With nix&apos;s atomicity, we can eliminate this entire class of problems. What I mean here by atomic here is all or nothing, there is nothing between especially half-baked broken package, it either package successfully installed and instant switch to upgraded package or the installation fail and the symlink never flips at all. The system stays exactly as it was, running previous package before updated. No need to some messy cleanup.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Nix Flakes

Nix flakes are experimental feature (optional) that can be used to unified structure for nix projects, allowing users/devs to pin specific versions of each dependencies (via flake.lock). Technically, a flake is a file system tree that contains a file named flake.nix in its root directory [^1]. Also can be referred as a policy for managing dependencies and implementing that policy too.

Flakes provide reproducible dependencies (locked version), composable configuration, and hermetic evaluation (pure, no hidden state). We can think of flakes feature as `package.json` and `package-lock.json` of `npm` but instead of for repository npm packages, its for entire system configurations instead.

## Core Concepts &amp; Structure

- **flake.nix** -&gt; project entry point. It declares what we depend on and what we provide (inputs and outputs).
- **flake.lock** -&gt; auto-generated lock file that records exact commit hashes of all flake inputs and its timestamps (also system-wide packages version pinning).
- **inputs** -&gt; dependencies our flakes uses, which are `nixpkgs` (nix packages repository), `home-manager` (user configuration management), `nix-darwin` (macOS nix module), etc.
- **outputs** -&gt; what our flake produces such as `darwinConfigurations` (macOS system configs), packages, development environments/shell, and user configs.

I will use [nix-darwin official repo](https://github.com/nix-darwin/nix-darwin) as example here:

```nix
{
  description = &quot;Rasyidan&apos;s darwin system&quot;;

  inputs = {
    # Use `github:NixOS/nixpkgs/nixpkgs-25.05-darwin` to use Nixpkgs 25.05.
    nixpkgs.url = &quot;github:NixOS/nixpkgs/nixpkgs-unstable&quot;;
    # Use `github:nix-darwin/nix-darwin/nix-darwin-25.05` to use Nixpkgs 25.05.
    nix-darwin.url = &quot;github:nix-darwin/nix-darwin/master&quot;;
    nix-darwin.inputs.nixpkgs.follows = &quot;nixpkgs&quot;;
  };

  outputs = inputs@{ self, nix-darwin, nixpkgs }: {
    darwinConfigurations.&quot;Rasyid-MacBook&quot; = nix-darwin.lib.darwinSystem {
      modules = [ ./configuration.nix ];
    };
  };
}
```

In the code snippet above, there is flake description that which shows up when you run `nix flake show` and it might help ourself and other users understand what this flake about.

In inputs section, we declared that we are using nixpkgs from nixpkgs unstable-channel (we can declare stable or previous version too) and nix-darwin. The last one we declared here to make our nix-darwin to &quot;follows&quot; our nixpkgs version so only one nixpkgs version exist. Thus, faster evaluation, saves disk space, and potential version conflicts was avoided. If we dont declare this &quot;follows&quot; pattern, there will be two versions of nixpkgs downloaded.

The output section declares what our flake produces, including self (a reference to our flake, accessing our own outputs), nix-darwin, and nixpkgs as written on `outputs = inputs@{ self, nix-darwin, nixpkgs }`. For `darwinConfigurations.&quot;Rasyid-Macbook&quot;` means `darwinConfigurations` as standard output name for nix-darwin and `&quot;Rasyid-MacBook&quot;` as machine name. You can have multiple machines here including more mac machines or even linux (we will go deep into this later). So with this, when we are about to build our system &amp; packages configuration, we can run `darwin-rebuild switch --flake .#Rasyid-MacBook`. Last one,

```nix
nix-darwin.lib.darwinSystem {
  modules = [ ./configuration.nix ];
}
```

- `nix-darwin.lib.darwinSystem` -&gt; function from nix-darwin to build a system
- `modules = [ ... ]` -&gt; list of configuration modules to include
- `./configuration.nix` = main configuration file

## Shared Configurations with Flakes

Previously, I stated that we can add multiple machines on our flakes. We can easily share our exact configuration to another machine. What I mean here not only another macbook but we can share our packages configuration to another linux machines, including linux desktop and linux server with one big monorepo here, thanks to nix flakes and home-manager here. With _nixfied_ approach, we can build ultimate dotfiles from this:

```
MacBook Pro/
├── .zshrc
├── .vimrc
├── .gitconfig
└── brew_packages.txt

iMac/
├── .zshrc
├── .vimrc
├── .gitconfig
└── brew_packages.txt

Linux Server/
├── .bashrc
├── .vimrc
├── .gitconfig
└── apt_packages.txt
```

to become something like this:

```
dotfiles/ (Git repo)
├── flake.nix                    # One entry point
├── flake.lock                   # Locked dependencies
├── machines/
│   ├── macbook-pro.nix         # Machine-specific (macOS)
│   ├── imac.nix                # Machine-specific (macOS)
│   └── linux-server.nix        # Machine-specific (NixOS)
├── darwin/
│   └── configuration.nix       # macOS-specific settings
├── nixos/
│   └── configuration.nix       # NixOS-specific settings
└── home/
    ├── common.nix              # Shared across all machine
    ├── terminal.nix            # Shell, vim, git configs
    ├── development.nix
    └── packages.nix
```

Since I&apos;m still bad at explaining things through writing and LLMs are now able to explain easily as text generating machine, it&apos;s better
to explain nix with my excalidraw image

![without nix](without_nix.webp)
![with nix](with_nix.webp)

I hope you understand what I&apos;m trying to visualize here and how nix helps here 🚶

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Nix-Darwin &amp; Nix Installation Setup on Mac OS

Nix-darwin is nix modules for darwin (apple) system. Thanks to nix-darwin, we are able to configure macOS declaratively using nix.
First, we need to install nix first on our system. I was using nix installer from [Determinate Systems](https://github.com/DeterminateSystems/nix-installer?tab=readme-ov-file#determinate-nix-installer) since it was the recommended one on [nix-darwin github repo](https://github.com/nix-darwin/nix-darwin) for flake-based setup.
You can see the installation guide in nix-darwin repo itself.

One of the main difference between NixOS and nix-darwin is in the command itself. On NixOS, if we want to switch to our new configuration,
we use `nixos-rebuild switch`, while on nix-darwin, it&apos;s `darwin-rebuild switch`. With flakes, it becomes `darwin-rebuild switch --flake .#your-hostname`.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Tradeoff

Alright, after all these explanations, we might be wondering, does _nix fix everything_? does _nix fix this?_ Well unironically maybe yes if you are comparing to some of packager managers or deployment stacks.
Seems too good to be true? Yes, it is unironically. Then what&apos;s the tradeoff? Well there is many but I will list the tradeoffs based on my personal experiences.

## Learning Curve

Quite obvious the first one is **learning curve** to learn what nix is and what nix does solve??
Also we have to familiar with functional programming paradigm and declarative way of applying configuration and managing your package rather than good ol imperative way to do it.
You need time to learn and understand what nix is, what nix capable of, why is nix exist, why nix fix this, etc.
We might need to take our time and patience to learn especially for ~9-5 wageslaves~ employed people.

As nix itself is not only the &quot;package manager&quot; but its also pure functional language itself. Therefore, it might feels like learning new programming language all over again.
The mental model of using nix itself quite different to other package managers, system managing, and languages. We have to adapt and shift to new mental model for using nix,
thinking in terms of derivations, the store, and purity too.

There is plenty of people complained that the nix documentation itself quite confusing and bad [^2] [^3] [^4].
There is multiple tools to learn such as `nix-shell`, `nix-direnv`, `nix build`, etc. There are often multiple ways to do the same thing,
which might adds confusion for newcomers. The example of this was when I was trying to configure my _nixified_ dotfiles, there is multiple patterns
to do it with almost same result. The newest pattern I have found so far was _dendritic pattern_ [^5] [^6], writing nix configurations based on [flake-parts.modules](https://flake.parts/options/flake-parts-modules.html).

For the development environments, you can use;

- `nix-shell` with `shell.nix`
- `nix develop` with `flake.nix`
- `devbox` (third-party)
- `nix-direnv` (leveraging flake.nix/nix develop with direnv)
- etc...

There is more, for installation media you can:

- install via ISO and setup manually as usual linux distro installation
- [nixos-infect](https://github.com/elitak/nixos-infect) - replacing non-nixos linux host with nixos
- [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) - installing nixos via ssh
- [clan](https://clan.lol) - actually its p2p computer management framework but you can use it to install and deploy fully-declared customized &amp; battery-included nixos setup to non-nixos linux host via ssh too.

Specifically for dotfiles configuration as I stated before there is multiple ways to do it, like either using [home-manager](https://github.com/nix-community/home-manager) or not it&apos;s up to you.
The sheer volume of docs is very high while the information is scattered and sometimes contradictory, and some of them are outdated. Funny that we escape the dependency hell
but not documentation hell.

## Disk Space

As nix able to stores multiple versions of same package or app in `/nix/store`, it can consume significant disk space over time if you don&apos;t setup garbage collection on your configuration
or regulary run garbage collection manually. I added this as &quot;tradeoff&quot; since my disk space grew quickly as previously I setup my nix GC for monthly then I did a lot of configuration tweak overtime (almost everyday backthen).

## Build Times

This is my personal tradeoff as when packages aren&apos;t cached in the binary cache, we have to build from source.
Since my home wifi connection not that fast and sometimes I use my own phone internet data,
it takes long time and significant amount of my internet quota especially for large packages.

## Collaboration &amp; Community

The nix community is smaller than ecosystem like homebrew or apt means fewer answers and discussion on forums ex: stackoverflow (yes, no one use it anymore), nix discourse, etc.
Some packages may be outdated or unmaintained in nixpkgs (this is the realest issue I have encountered so far). Some of packages I have been using on my machine are not maintained anymore.
The most annoying issue was when I tried to update to the latest claude code package (nixpkgs unstable channel) because the claude code package still on long process of CI/CD verification of claude code
on nixpkgs repo PR itself also we have to verify with the package maintainer too (and passed linux and darwin kernel verification). Because of this, some of packages I use in my current dotfiles
configuration are built from the source directly.

Smaller community and ecosystem is not really tradeoff and problem for me personally as long as the software or the tool I use provide enough value for myself aka good enough.
The problem might be that, if you are using nix for your own personal project, its really great as you have full control of your own techstack, infra, deployment, etc. But for collaboration?
Convincing your team to adopt nix and say &quot;nix fix this&quot; can be difficult given the learning investment and mental model required from everyone.

## Integration Friction

As newcomer that using nix as current daily driver now, this one might be become the most annoying thing to trade with repeatedly in practice.
Since most of tools and workflows I have been using assume filesystem hierarchy standard layout (`/usr/lib`, `/usr/bin`) while nix completely using
`/nix/store/` for tools and workflows path. I got repeatedly hit with path issue when i was using some of tool or software that already assume the filesystem layout either
precompiled binaries one or hardcoded path one.

You will keep encountering this issue when you are using ai agent tools such as codex and claude code. The example case is when an agent
try to invoke `python` or `bun` tool calling, it will return as error as the path of `python` and `bun` are located in `/nix/store/&lt;unique-hash&gt;` while
an agent assumes that these tools are located in usual `/usr/` path. For this one, we can tackle the issue through creating a persistent profile or declare the package path correctly for these ai agents
then (or) use `direnv` + `nix-direnv`.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# Leveraging LLM for Nix Configuration

As the time we need to learn nix (gracefully) both the languages and how it works, not even time for write code for all the configuration we want to _rewrite_ such as dotfiles, server,
deployment tool, etc.

&gt; Do we actually have the time for that?
&gt; Are we unemployed enough to do all of that alone?

As I&apos;m writing this, I&apos;m still actively learning nix myself and every week I get new knowledge (or some kind of enlightment) about nix.
The latest one was leveraging `nix-direnv` for project dependency dev environment.

Fortunately, we can whip AI agent to work for us. Most of my dotfiles configuration code is written by AI especially the boilerplate code. Surprisingly, LLMs are good enough
for writing nix code as there is a lot of nix codebase repository available in internet so I assume there is enough nix code in LLM training data. You can leverage LLM output more
by _context engineering_, tool calling, MCP, and whatever it is.

## Using NixOS MCP &amp; Search Tool

The first obvious thing we can do to leverage LLM output regarding to nix codebase is using nix-related MCP or web-search tool to let the LLM search nix-related stuff in the search engine.
In the context of search tool, most of ai agent tools already included web-search tool feature.

For MCP, what I have been using is [MCP-NixOS](https://github.com/utensils/mcp-nixos) by [utensils](https://utensils.io/).
This MCP server give our LLM response real-time information about nixos packages (nixpkgs), configuration options, home-manager settings, nix-darwin configurations,
and package version history via [nixhub](https://nixhub.io) to increase our LLM response accuracy on nix stuffs. I often use this MCP for:

- search and browse nixpkgs (`nixos_search()` and `nixos_info()`)
- search and browse home-manager options (`home_manager_search(), home_manager_info()`)
- search and browse darwin/macOS related (`darwin_search()`, `darwin_info()`)

Mostly for browsing nixpkgs and home-manager related so I want to make sure the LLM response is grounded or accurate enough, not hallucinating.
MCP often ends up bloating our LLM context window, or as we can call it &quot;context rot&quot;, I avoid MCP at all cost if possible I don&apos;t use MCP all the time when I was working on nix stuffs.
We can just straight dump the context as prompt to LLM if we are already familiar enough with nix later on.

## AGENT.md as Context &amp; Instructions

We can use AGENT.md or CLAUDE.md to leverage LLM output when you are working with nix codebase repository. I believe CLAUDE.md is the biggest leverage you can use
as you can define what, why, and how on your project repository [^7]. Tell claude or whatever you are using how it should work on the project. For nix example, we can tell it to
use `nix fmt` and `nix flake check` after finished nix code implementation to validate all the hosts (and flake) you are working with.
You may tell claude for host-specific validation such as tell it to use `darwin-rebuild switch --flake --dry-run .#your-macbook` for final testing before you decide to switch to your
current nix configuration on your macbook.

On the &quot;what&quot; part, tell claude about the tech you are using and its project structure. This is really important if you are working on nix project since there could be multiple architectural
patterns you can use to achieve same result. Tell claude what is your nix codebase tree and repository looks like in high level, what `flake.nix` used for and included there and what `module/`
path is. `AGENT.md` and `CLAUDE.md` are the highest leverage point of the harness [^7], so craft the context carefully, dump our &quot;nix-way&quot; to claude for best results.

Reminder that as less (instruction) is more [^7], don&apos;t tell claude all unnecessary information, to avoid bloating our context window for instruction count. For linter and code formatting, use
`nix fmt` (and `nix flake check --all-systems`) as pre-commit hook.

## Sub-Agent &amp; Skill

I haven&apos;t try this yet but the idea is you can leverage claude code and opencode subagent feature for nix-related, you can call it as `nix-coder`.
Everytime an agent have to working with nix repository, we can invoke this `nix-coder` subagent to tackle the code and pass the relevant context to the
main agent thus more effective context usage later on while an agent might generate better code too.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# My Dotfiles Configuration

My current dotfiles tree to manage my macOS packages and system:

```
├── AGENTS.md
├── CLAUDE.md -&gt; AGENTS.md
├── README.MD
├── flake.lock
├── flake.nix
├── hosts
│   ├── desktop.nix
│   └── dev-vm.nix
├── modules
│   ├── darwin
│   │   ├── devtools.nix
│   │   ├── home
│   │   │   ├── default.nix
│   │   │   └── programs
│   │   │       ├── aerospace
│   │   │       │   ├── default.nix
│   │   │       │   ├── modes.nix
│   │   │       │   ├── user-settings.nix
│   │   │       │   └── workspaces.nix
│   │   │       └── ghostty.nix
│   │   ├── homebrew.nix
│   │   └── system.nix
│   ├── home
│   │   ├── base.nix
│   │   ├── devtools
│   │   │   ├── ai-tools.nix
│   │   │   ├── default.nix
│   │   │   ├── direnv.nix
│   │   │   ├── languages.nix
│   │   │   └── try.nix
│   │   ├── programs
│   │   │   ├── fastfetch
│   │   │   │   ├── default.nix
│   │   │   │   └── oguri-logo.txt
│   │   │   ├── helix.nix
│   │   │   ├── neovim.nix
│   │   │   └── nvim
│   │   │       ├── init.lua
│   │   │       ├── lazy-lock.json
│   │   │       └── lua
│   │   │           ├── config
│   │   │           │   ├── autocmds.lua
│   │   │           │   ├── keymaps.lua
│   │   │           │   ├── lazy.lua
│   │   │           │   ├── lazyvim
│   │   │           │   │   └── init.lua
│   │   │           │   └── options.lua
│   │   │           └── plugins
│   │   │               ├── auto-save.lua
│   │   │               ├── coding.lua
│   │   │               ├── colorscheme.lua
│   │   │               ├── completion.lua
│   │   │               ├── dashboard.lua
│   │   │               ├── file-explorer.lua
│   │   │               ├── formatting.lua
│   │   │               ├── linting.lua
│   │   │               ├── lsp.lua
│   │   │               ├── smear_cursor.lua
│   │   │               ├── treesitter.lua
│   │   │               ├── ui.lua
│   │   │               └── which-key.lua
│   │   ├── secrets.nix
│   │   └── shell
│   │       ├── fish.nix
│   │       ├── nushell.nix
│   │       ├── starship
│   │       │   ├── default.nix
│   │       │   ├── starship.toml
│   │       │   └── starship.toml.bak
│   │       └── tmux.nix
│   └── nixos
│       ├── audio.nix
│       ├── bluetooth.nix
│       ├── containerization.nix
│       ├── desktops
│       │   ├── README.md
│       │   ├── apps
│       │   │   ├── browsers.nix
│       │   │   └── terminals.nix
│       │   ├── base.nix
│       │   ├── gaming.nix
│       │   ├── hardware-configuration.nix
│       │   ├── hyprland
│       │   │   └── default.nix
│       │   ├── plasma.nix
│       │   └── themes
│       │       ├── catppuccin.nix
│       │       └── default.nix
│       ├── fonts.nix
│       ├── graphics.nix
│       ├── home
│       │   └── default.nix
│       ├── network.nix
│       ├── ssh.nix
│       ├── system.nix
│       ├── users.nix
│       └── virtualization.nix
├── packages
│   ├── default.nix
│   ├── opencode.nix
│   ├── osgrep-package-lock.json
│   └── osgrep.nix
├── secrets
│   ├── README.md
│   └── local-ai-tokens.sops.yaml
└── shells
    ├── README.md
    ├── ai-agent.nix
    ├── ai-notebook.nix
    ├── default.nix
    ├── effect-ts.nix
    ├── go.nix
    ├── jupyter-notebook.nix
    ├── python-uv.nix
    ├── rust.nix
    └── web-bun.nix
```

Because I tend to switch between codex and claude code, I symlinked AGENT.md to CLAUDE.md so if I changed my AGENT.md,
my CLAUDE.md will be changed too, also it has exactly same prompt and context as it is symlinked.

For the `module/` path, I decided to modularize it between macOs system-specific (darwin), home-manager specific, and nixos machine (linux).
It might looks confusing and weird why is there home-manager specific which user-level isolation while other modules are kernel-level isolation.
I decided to put home-manager modules beside darwin and nixos module so I can tweak my personal configured packages and tools like `neovim`, `helix`,
and `nushell` can be easily managed for myself (the who use and maintain the repo is me anyway). I put lazyvim and lua-layers for neovim configuration directly
on my dotfiles repo to easily configure my neovim directly there, but as I said there is plenty ways to manage your neovim configuration on nix. One of the most
popular way is through [NixVim](https://github.com/nix-community/nixvim). My current neovim configuration way is just declared neovim via `nixpkgs` then initialized
lazyvim then streamlined and disabled unnecessary plugin (mason) and adding my personal favorite neovim (ex: smear cursor).

My current daily driver shell is nushell with prompt configuration via starship, one of the popular prompts also the most flexible to use within other shells so far beside
oh-my-posh with tmux as multiplexier and running multiple terminal sessions (really great for whipping your agents remotely!)

On the `devtools/` path, I added bunch of personalized devtools such as ai agent tools (claude code, codex, etc.), direnv, programming languages (uv/python, golang, rust),
and [try](https://github.com/tobi/try). Recently, I added try as I found the tool itself aligns with what I need. I often test several temporary projects especially
related to my current job which is data scraping &amp; crawling then my project files are scattered randomly everywhere. Think that try able to solve my current issue and I feel
satisfied too. I will recommend it to anyone that struggling with doing bunch of temporary testing repos!
As I declared and added some GLM wrapper inside claude code defined too [^8], I wrote every ai tools that I usually use under one file but as I&apos;m writing this, I found that
there is better option to do it. I found [llm.agents.nix](https://github.com/numtide/llm-agents.nix) made by numtide. Turns out it already included bunch of ai tools I declared
so I might replace my entire ai-tools configuration with the `llm.agents.nix` one soon.

For macOS aka darwin modules, mostly its software and tilting window manager tweaks. I&apos;m still using homebrew on my nix system despite I stated that I replaced homebrew earlier.
But it feels better that we can manage brew packages in declarative way and more manageable then via the old way.

```nix
  options.rsydn.homebrew = {
    enable = mkOption {
      type = types.bool;
      default = true;
      description = &quot;Whether to manage Homebrew declaratively.&quot;;
    };
    taps = mkOption {
      type = types.listOf types.str;
      default = [ &quot;FelixKratz/formulae&quot; ];
      description = &quot;Homebrew taps to add.&quot;;
    };
    brews = mkOption {
      type = types.listOf types.str;
      default = [ &quot;curl&quot; &quot;yt-dlp&quot; &quot;ruff&quot; &quot;libmagic&quot; &quot;infisical&quot; &quot;imagemagick&quot; ];
      description = &quot;Homebrew formulae to install.&quot;;
    };
    casks = mkOption {
      type = types.listOf types.str;
      default = [
        &quot;bitwarden&quot;
        &quot;brave-browser&quot;
        &quot;firefox&quot;
        &quot;pgadmin4&quot;
        &quot;spotify&quot;
        &quot;vesktop&quot;
        &quot;obs&quot;
        &quot;neohtop&quot;
        &quot;orbstack&quot;
        &quot;ghostty&quot;
        &quot;openvpn-connect&quot;
      ];
      description = &quot;Homebrew casks to install.&quot;;
    };
  };
```

You can switch the state of your brew packages in your system via `boolean` value also declare directly on the code for brew cask
rather than install on terminal. This is really great as if you want to install bunch of brew casks on fresh apple/darwin machine,
all of them will be installed through classic `darwin-rebuild switch --flake .#your-macbook` command. No need to reinstall via `brew cask install &lt;insert here&gt;`
and no need to remember all the brew casks again! Oh one more thing..

```nix
  config = mkIf cfg.enable {
    homebrew = {
      enable = true;
      global.autoUpdate = false;
      onActivation = {
        autoUpdate = false;
        cleanup = &quot;zap&quot;;
        upgrade = false;
      };
      inherit (cfg) taps brews casks;
    };
  };
```

You can also declare whether you want to set autoupdate and upgrade behaviour of brew itself in the code. Oh
also on `cleanup = &quot;zap&quot;`, everytime we switched to our updated flakes, all brew packages that not declared in our
`homebrew.nix` will be gone thus it called &quot;zap&quot; (maybe).

Tilting window manager that I used on my macOS is [aerospace](https://github.com/nikitabobko/AeroSpace). I use hyprland as
tiling window manager on my desktop so I think I need one too for my daily workflow to simulate similar keymap and workflow
on my desktop. You can configure user settings, modes, and workspace-binding as in my dotfiles declaratively on aerospace.
Check [this](https://mynixos.com/nix-darwin/options/services.aerospace) one for references (or maybe my dotfiles).

The second thing I customized a lot in my darwin modules is [ghostty](https://ghostty.org), gpu-accelerated terminal that
currently trending amongst the developers, made by [Mitchell Hashimoto](https://mitchellh.com/ghostty) himself, who is nix user too [^9].

```nix
{ config, ... }: {
  programs.ghostty = {
    enable = true;
    package = null;

    settings = {
      theme = &quot;gruvbox&quot;;
      background-opacity = 0.9;
      shell-integration = &quot;detect&quot;;
      working-directory = &quot;home&quot;;
      window-inherit-working-directory = true;
      keybind = [
        &quot;super+a&gt;n=new_window&quot;
        # Split bindings - using v and s instead of | and - for better reliability
        &quot;super+a&gt;v=new_split:right&quot;
        &quot;super+a&gt;s=new_split:down&quot;
        # Navigation
        &quot;super+a&gt;h=goto_split:left&quot;
        &quot;super+a&gt;j=goto_split:down&quot;
        &quot;super+a&gt;k=goto_split:up&quot;
        &quot;super+a&gt;l=goto_split:right&quot;
        # Other actions
        &quot;super+a&gt;z=toggle_split_zoom&quot;
        &quot;super+a&gt;x=close_surface&quot;
        &quot;super+a&gt;r=reload_config&quot;
      ];
    };

    themes.gruvbox = {
      background = &quot;282828&quot;;
      foreground = &quot;ebdbb2&quot;;
      cursor-color = &quot;ebdbb2&quot;;
      cursor-text = &quot;282828&quot;;
      selection-background = &quot;ebdbb2&quot;;
      selection-foreground = &quot;282828&quot;;
      palette = [
        &quot;0=#282828&quot;
        &quot;1=#cc241d&quot;
        &quot;2=#98971a&quot;
        &quot;3=#d79921&quot;
        &quot;4=#458588&quot;
        &quot;5=#b16286&quot;
        &quot;6=#689d6a&quot;
        &quot;7=#a89984&quot;
        &quot;8=#928374&quot;
        &quot;9=#fb4934&quot;
        &quot;10=#b8bb26&quot;
        &quot;11=#fabd2f&quot;
        &quot;12=#83a598&quot;
        &quot;13=#d3869b&quot;
        &quot;14=#8ec07c&quot;
        &quot;15=#ebdbb2&quot;
      ];
    };
  };
}

```

I declaratively configured the gruvbox theme, customized keybinding, and background tweaking (opacity level) on there.
You can customized further as much as you want as long as ghostty support the customization itself.

My current _nixfied_ dotfiles [here](https://github.com/0xrsydn/darwin-dotfiles) (might be refactored in the future..)

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# TLDR

Nix is a purely functional package manager that stores packages in isolation (`/nix/store`) with unique hashes, enabling rollbacks, no dependency hell, and atomic upgrades. With nix flakes + nix-darwin + home-manager, you can declaratively manage your entire macOS system (packages, shell, window manager, etc.) from a single git repo that works across multiple machines.
Come with tradeoffs; steep learning curve, scattered docs, disk space (only if you skip or forget to setup garbage collection), and path friction with tools expecting `/usr/bin`. Well most of these tradeoffs could be easily tackled though. Current SOTA LLMs are surprisingly good enough at writing nix code with MCP tools and AGENT.md (+context engineering) to boost accuracy and code quality.

&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;

# References &amp; Resources

Since this is actually more like my personal learning experiences dumping that somehow sounds little educational and there is nix introduction too. But since I&apos;m still
learning and adapting to nix myself, I will provide lists of nix-related resources that I found really helpful and useful for me personally that I hope it will be
helpful to whoever reading this. So, at the end, I hope that the word &quot;Nix&quot; will sound less intimidating than writing python.

This section will be updated in the future if I found useful and good resource related to nix.

- [Vimjoyer, best nix youtuber fr](https://www.youtube.com/@vimjoyer/videos)
- [NixOS: Everything Everywhere All At Once](https://www.youtube.com/watch?v=CwfKlX3rA6E)
- [NixOS Search](https://search.nixos.org/packages?channel=unstable&amp;)
- [Official NixOS Wiki](https://wiki.nixos.org/wiki/NixOS_Wiki)
- [Awesome Nix](https://github.com/nix-community/awesome-nix)
- [Zero to Nix, by DeterminateSystems](https://zero-to-nix.com/)
- [NixOS &amp; Flakes Book, An unofficial book for beginners](https://nixos-and-flakes.thiscute.world/)

[^1]: [Flakes, Nix Official Documentation](https://nix.dev/concepts/flakes)

[^2]: [&quot;New reader finding documentation unnecessarily confusing&quot;, Nix Discourse](https://discourse.nixos.org/t/new-reader-finding-documentation-unnecessarily-confusing/40722/1)

[^3]: [&quot;Why is the Nix documentation so bad?&quot;, Reddit](https://www.reddit.com/r/NixOS/comments/1b9jrzt/why_is_the_nix_documentation_so_bad/)

[^4]: [Hacker News discussion on Nix](https://news.ycombinator.com/item?id=27369960)

[^5]: [Dendritic Nix](https://dendrix.oeiuwq.com/Dendritic.html)

[^6]: [Dendrix GitHub Repo](https://github.com/vic/dendrix)

[^7]: [Writing a good CLAUDE.md, Kyle Mistele](https://www.humanlayer.dev/blog/writing-a-good-claude-md)

[^8]: [Using Any Other LLM Inside Claude Code](https://rasyidanaf.com/blog/using-any-llm-inside-claude-code/)

[^9]: [Using Nix with Dockerfile, Mitchell Hashimoto](https://mitchellh.com/writing/nix-with-dockerfiles)</content:encoded><category>dev</category><category>tech</category><category>nix</category></item><item><title>Using Any Other LLM Inside Claude Code</title><link>https://rasyidanaf.com/blog/using-any-llm-inside-claude-code/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/using-any-llm-inside-claude-code/</guid><description>Plug and switch any model you want to use in claude code for flexibility and cheaper option.</description><pubDate>Mon, 08 Sep 2025 00:00:00 GMT</pubDate><content:encoded>Currently there is a lot of people are using Claude Code, terminal-based ai tool to assist their programming or to vibecode. The ability and flexibility to do bunch of tasks done through CLI and tool enabled by CC is really powerful and useful personally. Sadly, CC is dedicated for anthropic models only such as Sonnet and Opus. So, here is the &quot;tricks&quot; I have been using to switch and use any models beside anthropic models especially OSS models that have comparable performance to Sonnet itself (ex: Qwen3 Coder, Kimi K2, GLM 4.5). Thus, you can use cheaper model you want inside claude code directly.

&lt;br /&gt;
&lt;br /&gt;

# Using Proxy Server

The first method that I have been using in the past is running proxy server that enables CC to work with any Open-AI compatible API providers. Basically you map any other LLM endpoint and its env cofiguration into Anthropic comparable client then you run localhost server to plug it into Anthropic client configuration such as `ANTHROPIC_BASE_URL=http://localhost:8082 #localhost FastAPI server` inside CC. 

&gt;TLDR: convert OpenAI API–compatible requests into Anthropic API format &gt; Set the environment variables &gt; override CC `baseUrl` and `apiKey`

There is already several claude code proxy github repos that you can directly use so you dont have to implement it from scratch:

- https://github.com/1rgs/claude-code-proxy
- https://github.com/fuergaosi233/claude-code-proxy
- https://github.com/musistudio/claude-code-router

&lt;br /&gt;
&lt;br /&gt;

# Configure The Environment

Well you know the idea, as basically we just set and inject other LLM env configuration into CC `baseUrl` &amp; `apiKey`, we can simplified the setup more, no need to start localhost server as proxy just to use other LLM in CC. Many AI labs such as Moonshot AI and Z.AI already make CC-compatible API endpoint that you can inject directly into Anthropic base URL. Now, Z.AI provides claude code plan for $3/month and $15/month be to be used specifically inside claude code (which is a lot of cheaper than claude code max plan). Thus, you can export the model `baseUrl` and `apiKey` directly then run claude like this:

```bash
export ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic
export ANTHROPIC_AUTH_TOKEN=YOUR_API_KEY
claude
```

Also you can configure the model on `~/.claude/settings.json` with:
```json
{
  &quot;env&quot;: {
      &quot;ANTHROPIC_MODEL&quot;: &quot;glm-4.5&quot;
  }
}
```

After that, you can run `claude` then prompt `/status`. It should be `glm-4.5` on there. As we know that we only need to export the configuration directly then run claude to switch model now, we can wrap it as bash function and assign it as `glm` or whatever your model name is. Now, you can just run `glm` for running Z.AI model inside CC.

```bash
glm() {
    export ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic
    export ANTHROPIC_AUTH_TOKEN=$ZAI_API_KEY
    export ANTHROPIC_MODEL=&quot;glm-4.5&quot;
    claude $1
}
```

You can also do this to other model that provide CC-compatible `baseUrl` like Moonshot one.
```bash
kimi() {
    export ANTHROPIC_BASE_URL=https://api.moonshot.ai/anthropic
    export ANTHROPIC_AUTH_TOKEN=$MOONSHOT_API_KEY
    export ANTHROPIC_MODEL=&quot;kimi-k2-0905-preview&quot;
    claude $1
}
```
&lt;br /&gt;
&lt;br /&gt;

# References
- [Z.AI Claude Code Docs](https://docs.z.ai/scenario-example/develop-tools/claude)
- [Claude Code Pro Tips by @iannuttall](https://x.com/iannuttall/status/1963895966706147560)
- [@bigeagle_xd X post](https://x.com/bigeagle_xd/status/1951870677662978167)</content:encoded><category>ai</category><category>dev</category></item><item><title>Vim of Coding Agents</title><link>https://rasyidanaf.com/blog/vim-of-coding-agents/</link><guid isPermaLink="true">https://rasyidanaf.com/blog/vim-of-coding-agents/</guid><description>A note on neovim-like coding agent harnesses</description><pubDate>Sat, 11 Jul 2026 00:00:00 GMT</pubDate><content:encoded>import Tweet from &quot;@/components/Tweet.astro&quot;;

Every few months there is another new coding agent, another coding agent from some frontier AI lab. Codex, Claude Code, Factory Droid, Cursor, Kimi Code, Mistral Vibe, Copilot, and you name it. Each of these coding agents is quite opinionated. Each coding agent adds features that they think you may need, while the truth is that many features are unnecessary and might make the software more _buggy_ in the end. This makes you, the user, rent someone else&apos;s _setup_ and _opinion_ of how to code with an LLM.

What if you could build your own custom coding agent and agent harness from a minimal foundation? If you are into, or familiar with, bare-bones minimal text editors like Vim/Neovim or Emacs that are very _hackable_, _customizable_, and can be _riced_ further, you would love to have a coding agent with a similar philosophy. You could build your own TUI, rendering process, extensions, plugins, harness, agent behavior, etc. and customize it as much as you want.

Introducing [pi](https://pi.dev), a minimal (terminal) coding agent, designed to adapt to your **WORKFLOW** instead of you adapting to the existing coding agent. Designed to let you build your own plugin, workflow, extension, etc. (you name it: skills, prompt template, TUI, etc) on your own just by asking (prompting) directly on pi. You can also ship your own plugin or package easily to other users like [lazyvim](https://github.com/LazyVim/LazyVim) via npm or git.

&gt; There are many coding agents, but this one is mine.

&lt;br /&gt;
&lt;br /&gt;

# Discovery

Last year I saw someone try to make a very very simple coding agent on the everything app, X, and name it _shittycoding agent_, as I remember. Back then, it was literally just a stupidly simple terminal coding agent tool. No plan mode, _askQuestion_ tool, or sub-agent like Claude Code. Only `read`, `write`, `edit`, and `bash`. My initial response was

&gt; Stupid simple coding agent, just a read, write, and bash tools, cool

That&apos;s it. I had no intention of trying it or any interest in it. I thought that was someone&apos;s side project trying to build a stupidly simple coding agent tool to better understand how it works under the hood (no offense to the creator, I didn&apos;t know him back then).

Fast forward, you know it. [OpenClaw](https://github.com/openclaw/openclaw). That _god damn_ AI assistant tool speedran GitHub stars growth and went viral on the internet. It ran on top of the Pi SDK.

OpenClaw also documents its [Pi integration architecture](https://docs.openclaw.ai/pi#pi-integration-architecture).

&lt;Tweet id=&quot;1995782507187319083&quot; /&gt;

&lt;Tweet id=&quot;2028124326428385742&quot; /&gt;

&lt;Tweet id=&quot;2032175796303851732&quot; /&gt;

There was a time when I was furiously using OpenClaw all the time as my go-to daily driver, especially for my job too. When I checked the docs and OpenClaw codebase, I realized Pi was the powerhouse, one of the core infrastructures powering OpenClaw itself.

At the time, I was looking for a simple coding agent that was very hackable for my workflow, kind of like Neovim, a terminal IDE that is very hackable and customizable, where I can build my own configuration without unnecessary features or bloat in the end. I was considering OpenCode as a top contender, but it was more like [Helix](https://helix-editor.com/) than Neovim for me (this is a compliment). It was well designed in my opinion, way better than the first time I used it, but that&apos;s it. It wasn&apos;t intended to be fully customizable or very hackable, even though you can easily build an external plugin on top of OpenCode itself.

After a few weeks of _doomscrolling_ on X, I saw several users sharing their experiences with Pi, specifically the creator of Flask, [Armin Ronacher](https://x.com/mitsuhiko), in [PI: The Minimal Agent Within OpenClaw](https://lucumr.pocoo.org/2026/1/31/pi/). My curiosity kicked in, and it was time to try it myself. A few Pi users also shared Pi extensions and plugins they made, similar to how Neovim users share their own plugins that can be plugged in easily using LazyVim.

As I&apos;m writing this blog, since this post has been drafted for a few months, Pi itself was finally acquired by Earendil, a company founded by Armin Ronacher and Colin Daymond. So it&apos;s basically company software (don&apos;t worry, still open source and properly maintained though).

&lt;br /&gt;
&lt;br /&gt;

# First-Time Experience

As a fellow Nix user, I installed pi via [llm-agents.nix](https://github.com/numtide/llm-agents.nix) by Numtide. You can also use the version available on nixpkgs, but I chose the Numtide one because it is managed and automatically pinned to the newest version. They also have their own caching workflow (aka I trust Numtide to maintain my own AI tooling package ~~as I&apos;m too lazy to do it myself~~).

It was very simple, and even the TUI itself was pretty straightforward. As I had heard that the power of Pi was being able to extend it and make customized plugins, the first thing I did on Pi was ask for a simple feature. It was a `todo` task tool and an `AskUser` tool.

It was straightforward. Pi read my global Pi `npm` directory, where the Pi library source code and docs are located, especially the docs about custom tools and extensions. So the default harness already injects its guidance/docs pointer into the agent context at runtime, especially if we, the user, mention Pi.

Then, out of curiosity, I started asking Pi to customize and tweak the Pi TUI itself, which worked quite great. So not only are we able to customize the features and tools of Pi itself, but we can also design and hack the Pi TUI itself. You can even play [Doom](https://github.com/earendil-works/pi/tree/main/packages/coding-agent/examples/extensions/doom-overlay) on Pi.

It reminds me of Neovim, customizing your own IDE from a simple plain text editor into a sophisticated IDE adjusted to your coding style and workflow.

Similar to how OpenCode works, you can also use your own Claude OAuth (RIP, it used to :( ), Codex OAuth, Antigravity OAuth (also RIP), Kimi Coding Subs, BYOK, etc.

It was literally a near-perfect coding agent for me personally due to how it was designed, which is somehow similar to Vim or Neovim. I can customize it as much as I want based on my workflow. I can also use someone&apos;s [package](https://pi.dev/packages), similar to how I can use someone&apos;s Neovim configuration or plugin from GitHub.

&lt;br /&gt;
&lt;br /&gt;

# Neovim Analogy

![A visual mapping of Neovim configuration concepts to their Pi equivalents.](./neovim-pi-config-map.svg)

To show what makes Pi special among available coding agents right now, we can use an analogy where Pi is similar to how Neovim works:

- **Core app + extensions**
  - Neovim loads Lua/Vimscript for plugins
  - Pi loads TypeScript for plugins
- **Custom commands**
  - Neovim plugins add commands like `:Telescope` or `:&lt;Leader-key&gt;&lt;Map&gt;`
  - Pi lets you add your own slash commands aka prompts/skills like `/AskUser`
- **Custom UI**
  - Neovim plugins can create floating windows, status lines, layouts, etc.
  - Pi extensions can be used for custom TUI components, dialogs, etc.
- **Configuration directories**
  - Neovim reads from places like `~/.config/nvim`
  - Pi reads extensions from `~/.pi/` similar to `/.claude/` and `~/.codex/`

While you are using Neovim for reading, editing, and writing code/text, you are using Pi to run a coding agent with basic tools like `read`, `edit`, and `bash`.

I even save my own Pi configurations and extensions and treat them similarly to how I manage and save my own Neovim configurations and customizations on [my dotfiles repo](https://git.rasyidanaf.com/0xrsydn/arch-dotfiles/src/branch/main/.pi/agent).

![Pi configuration and extension screenshot](./Pasted image 20260526110819.webp)

If we are talking resource-utilization-wise, Pi already _mogged_ both Claude Code and OpenCode. Only Codex remains to be _mogging_ here. So it&apos;s more lightweight and less bloated than Claude Code here, even though both coding agents are written with TypeScript. You know, memory or RAM usage is one of the most important things if we are going to _agentmaxxing_.

![Resource usage comparison screenshot](./Pasted image 20260526110740.webp)

Imagine running a bunch of coding agents on different tmux panes and your memory is already full ~~despite not using Windows~~ due to coding agents&apos; bad memory utilization.

&lt;br /&gt;
&lt;br /&gt;

# Plugin

The powerful feature of Pi is plugin creation, which is separated from the core software, so you can extend it as much as you want and need. It&apos;s up to you if you want to make your Pi lean enough for your own workflow or add a bunch of plugins and make Pi into bloatware. Although most of the Pi plugins I use were directly made by asking through prompts on Pi, you can browse a bunch of plugins available to download via npm on [Pi Packages](https://pi.dev/packages).

Whenever you need a subagent, web access, an MCP adapter, a todo task tool, a browser agent, etc., maybe someone has already made it as an extension or package that is mature and bug-free enough to install directly, rather than having to iterate on your own extension until it becomes usable enough.

Even though most of my Pi extensions were iterated on by myself, I also used and installed [pi-acp](https://github.com/svkozak/pi-acp), an ACP adapter for Pi, so I can use Pi on my Zed IDE directly. If someone&apos;s extension is already good and usable enough for our workflow, I don&apos;t think we need to make it from scratch unless we have more reasons for it, such as customizability and ownership (you can also just copy and paste the extension code into your `.pi/` though).

&lt;br /&gt;
&lt;br /&gt;

# Tradeoff &amp; Comparison

Now, let&apos;s talk about the tradeoff of using Pi and compare it directly with another coding agent as well. There are too many coding agents currently, such as Claude Code, Codex, OpenCode, Droid, etc. In this blog, I&apos;ll pick opencode to compare with Pi head to head since both are popular, fully open-source coding agents, and you can easily plug any model provider into both of them (no vendor lock-in).

## Feature Design

The main difference between these two is how the coding agents are designed to be used. Pi is more like a bare-metal mechanical keyboard that you customize by yourself, while OpenCode is designed like a more polished and finished mechanical keyboard that you can still tinker with. It comes with some guidance on how to assemble and disassemble it, while the materials and how it is built are fully transparent. Or maybe we can use an IDE analogy for this one:

&gt; OpenCode = Helix
&gt; Pi = Neovim

I use &quot;Helix&quot; as an example above because Helix as an IDE is a more polished and already battery-included text editor, but it is still extensible. Unlike Neovim, which is a very bare-minimum text editor, most of the time you have to add the features you want by yourself or use someone&apos;s plugin for that (composable though).

OpenCode ships with a built-in LSP, plan mode, subagents, multi-session, and an IDE extension. It also has a native desktop app and server configuration if you like to make it a remote gateway too. You can write your own plugin on top of that, but the core itself is already a full IDE replacement.

Meanwhile, Pi only ships with read, write, search, and bash. Anything else might be either installed from someone who made a plugin or made by yourself.

## Plugin Model

While both of them support external plugins, custom tools, and even more customized harness configurations, and both use the same main plugin language, TypeScript, their plugin model design and philosophy are quite different.

As OpenCode itself is somehow already a &quot;complete product&quot; here, OpenCode&apos;s plugin model is more like an external hook that can be integrated into the product itself.

Pi feels more like the agent harness itself is programmable, either globally or at the project level (locally), so we can register tools, slash commands or skills, shortcuts, flags, event handlers, custom UI components, custom object renderers, etc. The extension or plugin design in Pi feels more like having a small framework or an entire customized harness as part of your own coding agent, rather than &quot;it&apos;s just a plugin&quot;.

The tradeoff based on the plugin model itself here is obvious. OpenCode gives you more out of the box, as the plugin surface is useful but unnecessary if you are mostly doing the work inside OpenCode&apos;s existing product shape. Pi gives you a deeper, more hackable and tweakable extension model, but that means you may need to assemble more and maintain your own preferred setup/workflow here. If you want some control over your coding agent and love to build your own tool until it feels like your own coding agent, Pi is more satisfying and suitable for your case. If you want an already finished, polished agent (battery included type of software) with extensibility on the side, OpenCode is probably better for you.

## Harness Cost &amp; Performance

It&apos;s common knowledge that using the same model with different coding agents can affect the model&apos;s performance and output. There are a lot of benchmarks and evals made by several people that you can _google_ or search for on X. Harnesses also affect the cost per task, as you know that every coding agent has its own built-in internal system prompt to optimize the input and output of the model itself. Personally, the best thing about Pi is how minimal its internal system prompt is (or maybe we can call it part of the harness). Not only does it make the coding agent more lightweight and customizable, but a minimal harness is also able to make a huge difference cost-wise.

Here, using Databricks&apos; internal benchmark, the Pi harness achieved roughly the same success rate as the models&apos; native vendor harnesses (both Opus 4.8 and GPT 5.5). Depending on the model and reasoning level, Pi was between 1x and 2x cheaper per task.

&lt;Tweet id=&quot;2074943619610649059&quot; /&gt;

This is important, as the definition of &quot;harness&quot; is not merely a UX wrapper around the model, but also includes how it manages the user&apos;s input/output, context, tools, and the loop around those things, which directly affects how many tokens are consumed per task. A more feature-packed harness does not mean that it is automatically more effective (in this case at least).

&lt;br /&gt;
&lt;br /&gt;

# My Setup

I have separate Pi configurations on [my personal MacBook](https://git.rasyidanaf.com/0xrsydn/dotfiles/src/branch/main/pi) and [Linux desktop (CachyOS, yes not fully NixOS yet :p)](https://git.rasyidanaf.com/0xrsydn/arch-dotfiles/src/branch/main/.pi/agent). Despite the different configurations, there are similar Pi extensions on both machines, but I made them from scratch, iteratively from my own Pi sessions anyway.

My Pi harness is very simple, nothing complex nor complicated. Since Pi is already good enough for me, and most of the time I configure my Pi harness at the project level rather than globally, I just need a few features, which are:

- [grill-me skill](https://github.com/mattpocock/skills/blob/main/skills/productivity/grilling/SKILL.md) by mattpocock. It interviews the user (me) about a design or plan relentlessly. Basically, it keeps questioning my choices until I&apos;m ready to go.
- [jujutsu ~~kaisen~~](https://github.com/jj-vcs/jj) as the main version control system in my global `AGENTS.md` rather than `git`.

  ```text
  ## Version Control

  Prefer Jujutsu (`jj`) over Git for source-control operations.

  - Use `jj status` instead of `git status`.
  - Use `jj diff` instead of `git diff`.
  - Use `jj log` instead of `git log`.
  - Use `jj describe` for change descriptions.
  - Use `jj new`, `jj split`, and `jj squash` for change management.
  - Avoid `git add`, `git commit`, and direct index/staging workflows unless explicitly requested.
  - Git commands are acceptable only for operations that `jj` cannot perform or when the user asks for Git specifically.
  - When reporting changes, mention the active `jj` change/workspace state rather than Git staging state.
  ```

  Why `jj` over good old `git`? I found jj&apos;s mental model simpler than Git, especially for AI-assisted coding. In jj, there is no staging area by default, and operations such as split, squash, and rebase are first-class operations. So instead of thinking like this:

  ```text

  edit files -&gt; stage -&gt; commit -&gt; amend(?) -&gt; rebase maybe(?)
  ```

The mental model would be much simpler and more straightforward:
`change/edit -&gt; inspect diff -&gt; split/squash/describe/move it later`

You can also do stacked diffs through `jj` easily because `jj` treats changes as mutable and makes them easy to rebase. This is very useful for an _agentic_ coding workflow since agent output is usually not perfect ~one-shot godtier code quality~ on the first try, so usually we need to reshape the previous stacks (and commits).

While `jj` itself does not resolve merge conflicts _magically_ and conflicting edits may still exist as usual even when using `jj`, personally, conflict handling with `jj` feels less disruptive than Git because conflicts can be carried as state and resolved later. For an agentic coding workflow, it matters because agent output is often messy and the work is iterative. I only need the output to be manageable enough and able to be reshaped easily afterward.

- [exa search](https://git.rasyidanaf.com/0xrsydn/dotfiles/src/branch/main/pi/extensions/exa-tools) for third-party _agentic_ web search integration. While you can actually fetch the web easily on pi using a bash command like `curl`, I prefer a third-party search API here so my agent can easily search for specific information or docs, find the right context with efficient token usage, and avoid getting blocked too. Exa search itself has a few features for specific use cases, like [Exa Code](https://exa.ai/blog/exa-code), which I included here to reduce code hallucination and provide efficient web context for coding work.

I also added custom model inference from [crof.ai](https://crof.ai) for cheap custom GLM 5.2 Q8 inference, which you can check on their website, with fast enough TPS (around 60-70 if I remember).

Well that&apos;s it. I didn&apos;t add many plugins; I just add what I need most of the time. You can also edit your own features, remove them easily, or import someone&apos;s extension. You have control over your own coding agent features, while the core system itself is diligently updated by senior experienced developers that I trust.

&lt;br /&gt;
&lt;br /&gt;

# TLDR

Maybe some of you do not want to read all of this after all, so I condensed the whole blog here for ~~short attention-span enjoyer~~ ppl who want a quick summary.

- Use **codex** or **claude code** if you do not want to own or tweak the harness, specifically want to use their frontier models, and want something that is literally plug-and-play with easily available models.
  &gt; **Note**: codex is more hackable than claude code and you can easily hack or configure it as codex itself is OSS.
- Use **Opencode** if you want a polished coding agent with strong defaults (battery included).
- Use **Pi**, the coding agent that is literally what I&apos;m talking about here, if you want to own the harness, the workflow, and your weird personal configurations of how you want it to work while the core system itself is being maintained regularly.
- I chose Pi because I don&apos;t need too many features. I just need a good enough foundation and a very simple coding agent that I can tinker with and configure to my workflow style, similar to Neovim, as they say:
  &gt; **_There are many coding agents, but this one is mine._**</content:encoded><category>ai</category><category>dev</category></item></channel></rss>