I built a visual drag-and-drop ML trainer (no code required). Free & open source.

For those who are tired of writing the same ML boilerplate every single time or to beginners who don’t have coding experience.

MLForge is an app that lets you visually craft a machine learning pipeline.

You build your pipeline like a node graph across three tabs:

Data Prep – drag in a dataset (MNIST, CIFAR10, etc), chain transforms, end with a DataLoader. Add a second chain with a val DataLoader for proper validation splits.

Model – connect layers visually. Input -> Linear -> ReLU -> Output. A few things that make this less painful than it sounds:

  • Drop in a MNIST (or any dataset) node and the Input shape auto-fills to 1, 28, 28
  • Connect layers and in_channels / in_features propagate automatically
  • After a Flatten, the next Linear’s in_features is calculated from the conv stack above it, so no more manually doing that math
  • Robust error checking system that tries its best to prevent shape errors.

Training – Drop in your model and data node, wire them to the Loss and Optimizer node, press RUN. Watch loss curves update live, saves best checkpoint automatically.

Inference – Open up the inference window where you can drop in your checkpoints and evaluate your model on test data.

Pytorch Export – After your done with your project, you have the option of exporting your project into pure PyTorch, just a standalone file that you can run and experiment with.

Free, open source. Project showcase is on README in Github repo.

GitHub: https://github.com/zaina-ml/ml_forge

To install MLForge, enter the following in your command prompt

pip install zaina-ml-forge

Then

ml-forge

Please, if you have any feedback feel free to comment it below. My goal is to make this software that can be used by beginners and pros.

This is v1.0 so there will be rough edges, if you find one, drop it in the comments and I’ll fix it.

How to Customize Your Form Submission Email Notifications (And Why It Matters)

If you’ve ever received a form submission email
that looks like this:

name=John+Smith&email=john%40example.com
&message=Hello+there&_next=https://yoursite.com
&_gotcha=&session=Morning+Workshop
&totalAmount=%24150.00

You know exactly how frustrating it is.
Raw field data dumped into an email with no structure, no
labels, and no context.
If you’re the one reading
those emails or worse, forwarding them to a
colleague or client, it’s a nightmare.

The problem gets worse when your form has many fields.
Registration forms, event entries, client intake forms, and job applications.
These forms can have 20, 30, or even 40 fields.
When all of that arrives as one unformatted block of text, the
person reading it has to hunt for the information
they need every single time.

This guide shows you how to fix that completely
using Formgrid’s custom email template feature
so every submission email arrives clean, organized,
and readable by anyone.

Why Default Form Emails Look So Bad

Most form backends send notification emails by simply dumping whatever data they received into the email body.
They don’t know your form’s
structure. They don’t know which fields are important.
They don’t know that your recipient needs to see Attendee Information before Session Selection, before Payment Details.

They just send everything in one flat list or worse, as raw URL-encoded data.

This is fine for a simple 3-field contact form.
But the moment your form gets complex, the default
email becomes unreadable.

Here are the most common complaints:

Internal fields showing up: hidden fields
like _next, _gotcha, and _subject appear
in the email even though they’re not real data.

No section headers: All fields listed in
one flat list with no grouping or context.

No formatting: Long text values show as
one unbroken paragraph with no line breaks.

Wrong field order: Fields appear in
submission order not in a logical reading order.

Generic subject line: Every email says
“New form submission” with no context about
who submitted or what they selected.

All of these problems are solved with a custom email template.

What a Custom Email Template Looks Like

Instead of a raw data dump, imagine receiving
this for every workshop registration:

Clean. Organized. Readable by anyone.
Whether they’re a developer, an event coordinator, or
an office manager who just needs to know who’s
coming and what they paid.

That’s exactly what Formgrid’s custom email
template feature delivers.

Who Needs Custom Email Templates

Event organizers: Workshop registrations, conference entries, seminar signups. Your coordinator needs to see the attendee details in a logical order, not a random field dump.

Small businesses: Client intake forms,
service booking forms, and quote request forms.
Your team needs to act on submissions quickly.
A clean email means faster response times.

Freelancers: Project brief forms,
onboarding forms. When a new client submits
their brief, you want it formatted like a
document you can actually work from.

Nonprofits: Volunteer applications,
membership forms, donation forms. Your coordinator needs to process applications efficiently without deciphering raw data.

Agencies: Building forms for clients.
Your clients expect professional emails that
match their brand and workflow.

If you’re sending form submission emails to anyone who isn’t a developer, custom email
templates are not optional. They’re essential.

How Formgrid Custom Email Templates Work

Formgrid uses Mustache templating: A simple,
widely used templating language that lets you
write an HTML email with placeholders that get
replaced with real submission data automatically.

The Available Variables

{{ _formName }}    — name of your form
{{ _time }}        — submission timestamp
{{ fieldName }}    — any field by its exact name
{{# fields }}      — loop through all fields
  {{ _name }}      — field label inside the loop
  {{ _value }}     — field value inside the loop
{{/ fields }}      — close the loop

The {{ fieldName }} variable is the most
powerful one. It maps directly to the name
attribute of your HTML input field. So if your
form has:

<input type="text" name="attendeeName" />

You can use {{ attendeeName }} anywhere in
your email template and it will be replaced
with whatever the user typed.

Two Ways to Use Custom Email Templates

Option 1: The Simple Loop (Works for Any Form)

If you just want clean, formatted emails without thinking too much about structure, use the
fields loop. This works for any form automatically:

<div style="font-family: sans-serif; 
            max-width: 600px; 
            margin: 0 auto;">

  <h2 style="color: #1d4f3d;">
    New Submission — {{ _formName }}
  </h2>

  {{# fields }}
  <div style="margin-bottom: 16px; 
              border-bottom: 1px solid #eee; 
              padding-bottom: 16px;">
    <p style="margin: 0; 
              font-size: 12px; 
              color: #888; 
              text-transform: uppercase;">
      {{ _name }}
    </p>
    <p style="margin: 4px 0 0; 
              font-size: 15px; 
              color: #333;">
      {{ _value }}
    </p>
  </div>
  {{/ fields }}

  <p style="font-size: 12px; color: #999;">
    Submitted: {{ _time }}
  </p>

</div>

This renders every field cleanly with its label above and value below.
No internal fields, no raw data, no mess.
Just clean readable output
for every submission automatically.

Option 2: Sectioned Template

(For Complex Registration Forms)

If your form has multiple sections, like a
workshop registration with attendee details,
session selection, dietary requirements, and
payment.
You can group fields into sections
with clear headers:

<div style="font-family: sans-serif; 
            max-width: 600px; 
            margin: 0 auto; 
            color: #1f2937;">

  <h2 style="color: #1d4f3d; 
             border-bottom: 2px solid #e8f3ee; 
             padding-bottom: 10px;">
    New Registration: {{ _formName }}
  </h2>

  <h3 style="color: #1d4f3d;">
    Attendee Information
  </h3>
  <p><strong>Name:</strong> {{ attendeeName }}</p>
  <p><strong>Email:</strong> {{ email }}</p>
  <p>
    <strong>Company:</strong> {{ company }}
  </p>
  <p><strong>Phone:</strong> {{ phone }}</p>

  <h3 style="color: #1d4f3d; 
             margin-top: 24px;">
    Session Selection
  </h3>
  <p>
    <strong>Workshop:</strong> {{ workshopName }}
  </p>
  <p><strong>Date:</strong> {{ workshopDate }}</p>
  <p><strong>Format:</strong> {{ format }}</p>

  <h3 style="color: #1d4f3d; 
             margin-top: 24px;">
    Dietary Requirements
  </h3>
  <p>
    <strong>Dietary Preference:</strong> 
    {{ dietaryPreference }}
  </p>
  <p>
    <strong>Allergies:</strong> {{ allergies }}
  </p>

  <h3 style="color: #1d4f3d; 
             margin-top: 24px;">
    Payment
  </h3>
  <p>
    <strong>Ticket Type:</strong> {{ ticketType }}
  </p>
  <p>
    <strong>Total:</strong> {{ totalAmount }}
  </p>
  <p>
    <strong>Payment Method:</strong> 
    {{ paymentMethod }}
  </p>

  <h3 style="color: #1d4f3d; 
             margin-top: 24px;">
    Notes
  </h3>
  <p>{{ notes }}</p>

  <hr style="margin-top: 32px; 
             border: none; 
             border-top: 1px solid #e5e7eb;" />
  <p style="font-size: 12px; 
            color: #9ca3af; 
            margin-top: 12px;">
    Submitted: {{ _time }}
  </p>

</div>

The variable names, {{ attendeeName }},
{{ workshopName }}, {{ totalAmount }}, must
match the name attributes of your HTML form
inputs exactly.

So if your form has:

<input type="text" name="attendeeName" />
<select name="workshopName">...</select>
<input type="hidden" name="totalAmount" />

The variables {{ attendeeName }},
{{ workshopName }}, and {{ totalAmount }}
will be replaced with the actual submitted
values automatically.

This gives you complete control over the layout,
grouping, and the order of every notification email.

How to Set Up Custom Email Templates

in Formgrid

Custom email templates are available on the
Business plan at $29/month.

Step 1: Go to Your Form Settings

Log in to your Formgrid dashboard, open your
form, and click the Settings tab.


Step 2: Find the Custom Email Template Section

Scroll down to the Custom Email Template
section.
If you’re on the Business plan, you’ll
see the full template editor.
If you’re on the free or Premium plan, you’ll see a prompt to
upgrade.


Step 3: Enable the Custom Template

Toggle the custom template on. The editor pre-populates with a starter template using the simple fields loop, a clean starting
point that works for any form immediately.

Step 4: Customize Your Template

Edit the HTML to match your needs.
Use the simple loop for basic forms or build a sectioned template for complex registration forms.

The available variables panel shows every variable you can use.
Click any variable chip to copy it to your clipboard instantly.

Step 5: Preview and Save

Click Preview to see exactly how your
email will look with sample data substituted
in. When you’re happy, click Save Template.

From this point on every submission to your
form will use your custom template, clean,
organized, and formatted exactly the way
you designed it.

Step 6: Test It

Submit a test entry on your form and check your inbox.
Your notification email should
arrive formatted exactly as you designed it.

Custom Subject Lines

You can also control the email subject line using the _subject hidden field in your
HTML form:

<input 
  type="hidden" 
  name="_subject" 
  value="Workshop Registration — {{ attendeeName }}"
/>

Or set it dynamically with JavaScript before
submission:

document.getElementById('subjectField').value = 
  'Registration - ' + name + ' - ' + ticketType;

This means every submission email has a
meaningful subject line: “Workshop Registration.
Sarah Johnson. Early Bird”, instead of
the generic “New form submission.”

What Else Is Included in the Business Plan

Custom email templates are part of the Formgrid
Business plan that also includes:

  • 15,000 submissions/month
  • Webhooks: Connect to Zapier, Make,
    Slack, Notion, Google Sheets, and more
  • Auto-responder emails: Automatically
    Send confirmation emails to your form
    submitters
  • Priority support

All for $29/month.

Final Thoughts

Default form notification emails are fine for simple contact forms. But the moment your form gets complex, with multiple sections and many fields,
non-technical recipients, a raw data dump
in your inbox, it becomes a real problem.

Custom email templates solve this completely.
Your emails arrive formatted, organized, and
readable by anyone. Whether they’re a developer, an event coordinator, or an office manager, processing registrations.

With Formgrid.dev
you get:

✅ Full HTML email template control

✅ Mustache variables for any field

✅ Sectioned layouts for complex forms

✅ Custom subject lines

✅ Preview before saving

✅ Works with any HTML form on any website

Start free and upgrade to Business when
you’re ready for custom templates.

👉 Try Formgrid free at formgrid.dev

Full disclosure: I built Formgrid.
Written as honestly as I could let you know in the
comments if anything looks off.

Tags: #webdev #javascript #tutorial #productivity #formapi

🚀 I Built a Simple API Monitoring Tool for Laravel (No Datadog Needed)

As a Laravel developer, I kept running into the same problem:

👉 “What is actually happening in my APIs?”

  • Which endpoints are being hit the most?
  • Which requests are slow?
  • Where are the errors happening?

Most solutions like Datadog or New Relic felt:

  • Overkill
  • Expensive
  • Time-consuming to set up

So I built something simpler.

⚡ Introducing ApiLens

A lightweight Laravel package that gives you a real-time dashboard of your API activity.

No setup headaches. No external services.

🎯 What it does

  • Logs every request (endpoint, method, status, duration)
  • Shows recent API activity
  • Helps identify errors (4xx / 5xx)
  • Highlights slow endpoints
  • Simple filter system to debug quickly

📸 Dashboard Preview

📦 Installation

composer require apilens/laravel-api-lens
php artisan apilens:install

Open:

http://localhost:8000/apilens?token=secret

That’s it.

🧠 Why I built this

I didn’t need:

  • Distributed tracing
  • Enterprise dashboards
  • Complex setup

I just needed:

👉 A quick way to understand what my APIs are doing

💡 Who this is for

  • Laravel developers
  • Freelancers building APIs
  • Startups that need quick visibility
  • Anyone debugging backend issues

⚖️ ApiLens vs Datadog

Feature ApiLens Datadog
Setup 1 min Complex
Cost Free Paid
Focus Laravel Generic
Use case Dev + small teams Enterprise

🚧 What’s coming next

  • Time-based filters
  • Charts & analytics
  • Alerts
  • SaaS version (multi-project dashboard)

💬 Feedback

Would love your thoughts 🙌

  • What features would you want?
  • Would you use something like this?

🔗 GitHub

👉 https://github.com/anirbancodes69/laravel-api-lens

I’ve Used AI to Build Production Software Since 2022. Here’s What Actually Works.

Everyone’s talking about AI coding. Most of the conversation is theoretical.

I’ve been shipping production software with AI assistance since 2022 — when ChatGPT was brand new, and when this was genuinely weird. In that time, I’ve built many products, including (most recently) security APIs processing real transactions, marketing automation systems, and a 360-degree agent security toolkit.

Along the way, I’ve learned that the practices matter more than the model. Here’s what actually works.

The 66% Problem

Stack Overflow’s 2025 survey found that 66% of developers spend more time fixing “almost-right” AI-generated code than they would have spent writing it themselves.

I’ve seen what happens when developers skip the discipline. But I learned early to avoid that trap.

In late 2022 into 2024, I wasn’t letting AI write directly into my codebase. I’d generate code for specific problems, cut and paste it in myself, study how it worked, and test relentlessly — at the file level, unit level, and system level. The pain wasn’t shipping code I didn’t understand. The pain was working with a minuscule context window where the AI had almost no understanding of my full codebase. I could only trust it to develop specific functions, one file at a time.

That limitation forced discipline. I couldn’t let the AI loose on my system because it literally couldn’t see most of it. So I stayed in the driver’s seat, treating AI as a code generator I had to validate and integrate manually.

The context windows got bigger. The tools got better. But those early lessons still serve me today. Here’s what actually works.

Practice 1: Questions Are Your Superpower

The biggest reason developers ship code they don’t understand? They don’t ask questions.

AI is an incredible teaching tool. I constantly ask:

  • “Why was this decision made?”
  • “How does this work under the hood?”
  • “Show me the technical details.”
  • “Develop a mockup of the data flow.”
  • “What happens if this input is malformed?”

Deep, detailed questions. Not “does this work?” but “explain to me exactly what happens when X calls Y.”

This serves two purposes: I understand the code, and I catch mistakes before they’re committed. When the AI can’t explain something clearly, that’s a red flag that it doesn’t understand either.

Practice 2: Never Auto-Accept Mission-Critical Code

For anything that matters, I watch the AI work in real time. I read every line as it’s being generated. When I see it heading in the wrong direction, I interrupt and correct course.

This single practice has saved me more debugging time than any other.

The instinct is to let it finish and review later. Don’t. By the time it’s done, you’re reviewing 2000 lines and the context of each decision is gone. But watching it write 20 lines and catching the third line that’s wrong? That’s a 10-second fix instead of an hour of debugging.

Auto-accept is for boilerplate. Anything else, you watch.

Practice 3: Start by Integrating, Not Generating

When AI coding tools first emerged, I didn’t have the agent write code directly into my codebase.

Instead, I had it generate code, then cut and paste it in myself — essentially using AI like Stack Overflow. I’d read the code, understand it, decide where it fit, and manually integrate it.

This taught me crucial lessons about what AI does well (boilerplate, patterns, syntax) and what it doesn’t (architecture, edge cases, your specific codebase conventions). More importantly, it kept me in control.

That early discipline is why Practice 2 now works for me. I trained myself to read and evaluate AI code before it became habit to just accept it.

If you’re new to AI coding, start here. Generate, review, integrate manually. Build the muscle of evaluating AI output before you let it touch your codebase directly.

Practice 4: Think Like a Systems Engineer

AI excels at implementing individual functions. It struggles with how pieces fit together.

That’s my job.

Before asking AI to implement anything, I think through:

  • How does this feature connect to existing systems?
  • What data flows in and out?
  • What other components will this affect?
  • Where does this fit in the overall architecture?

The AI doesn’t have the full picture of your system. You do. If you don’t do this thinking, no one will — and you’ll end up with a codebase of individually-correct components that don’t work together.

Practice 5: Limit Scope Ruthlessly

I never have an agent develop anything top-to-bottom for me. Never.

Instead, I develop individual features with the agent:

  1. Plan it — What exactly are we building?
  2. Discuss it — How should it work? What are the edge cases?
  3. Ask questions — Many, many questions before implementation
  4. Review proposed code — Have AI generate example code during discussion
  5. Then implement — One feature, one piece at a time

It’s more than a spec. It’s a conversation to ensure the final output is what actually works. By the time implementation starts, I know exactly what the code will look like because I’ve already seen drafts during the discussion phase.

Practice 6: Relentless Systems Testing

Unit tests are often inadequate. They test that a function does what the function does — which tells you nothing about whether it works in your actual system.

For every feature, I create multiple types of tests:

  • Does it work in isolation?
  • Does it integrate correctly with existing code?
  • What errors appear that shouldn’t?
  • What was accidentally reverted or broken?
  • Does it handle real-world inputs, not just happy-path test data?

I’ll often conduct at least 5 different system and integration tests for a single feature before considering it done.

The feature-first development approach (Practice 5) is vital here. When you’re developing one feature at a time instead of letting AI build an entire application, you can actually test each piece thoroughly.

Practice 7: Build Shared Understanding Before Implementation

Programming is problem-solving. The code is just the output.

Before touching code, I have extended conversations with the AI to build a shared understanding of the problem. Not just “what should we build?” but deep exploration:

  • Have the AI read and summarize the relevant modules
  • Ask it to diagram the data flow and architecture
  • Run diagnostic tests together to understand current behavior
  • Identify what’s working, what’s not, and why
  • Explore options and tradeoffs together

Here’s what this looks like in practice. Before improving my ML LLM attack classifier’s detection rate, I had the AI:

  1. Map out the entire pipeline architecture (client → server, what each layer contributes)
  2. Run tests to check what the ML model was actually detecting vs. missing
  3. Analyze what features the model was trained on vs. what it needed
  4. Identify gaps in the training data (attack patterns that existed but weren’t included)
  5. Propose a plan to expand training data while maintaining balance

Only after this exploration — after both the AI and I understood the current system, the problem, and the solution — did we write any code.

This creates a shared baseline. The AI understands the context. I understand the approach. By the time implementation starts, I’ve already seen example code during the discussion, asked questions about it, identified issues, and refined the approach. The actual implementation becomes almost mechanical.

Practice 8: Automate What AI Misses

AI is not reliable for security review. It can miss SQL injection, XSS vulnerabilities, hardcoded credentials, and other OWASP top 10 issues that deterministic scanners catch every time.

I run automated security scanning as part of standard CI/CD discipline:

  • Static analysis that flags dangerous patterns
  • Dependency vulnerability checks
  • Pre-commit hooks that block obvious security issues

These aren’t AI-powered. They’re deterministic pattern matchers that catch the same vulnerability the same way every time. No hallucinations, no missed edge cases, no “I didn’t notice that.”

The value is catching what’s lurking in the code that neither you nor the AI were thinking about. You’re focused on the feature. The AI is focused on what you asked. Neither is systematically checking for injection attacks in that database query you wrote three files ago.

Automated scanners don’t replace security expertise. But they’re a reliable safety net that catches the obvious issues before they ship.

What I’ve Shipped Using These Practices

These aren’t theoretical. Using them, here’s some of what I’ve built:

  • AI Security Guard — A security scanning API with 5 specialized ML/NLP detection experts, processing real x402 micropayment transactions
  • AgentGuard 360 — An upcoming 360-degree security toolkit for AI agents with device hardening, content scanning, and operations visibility
  • Marketing automation — Internal frameworks with deterministic systems, including a purpose-built CRM, smart post generation and scheduling, automated lead detection and nurturing, and a content generation system that has produced AI-powered educational and strategic content that has been viewed nearly 2 million times

All production. All with AI assistance. All with these practices.

The Meta-Lesson

The developers who thrive with AI coding won’t be the ones who use AI the most. They’ll be the ones who develop the discipline to use it well.

AI doesn’t replace engineering judgment. It amplifies whatever judgment you bring. Good practices + AI = production software. No practices + AI = technical debt factory.

Build the discipline.

I’m building AI Security Guard — security scanning for AI agents. If you’re working with MCP, tool-using agents, or any AI that processes untrusted content, check out aisecurityguard.io/v1/skill.md.

We Built a Shopping Agent That Searches Thousands of Retailers in Real Time

We just launched ShopSavvy Desktop – a shopping agent for Mac, Windows, and Linux that searches thousands of retailers in real time, compares prices, shows price history, and cross checks every spec and review.

The depth

This isn’t just a price checker. Ask it “build me a PC with [specs] under $1500” and it handles component compatibility, stays in budget, and builds a collection lineup. Ask “assemble a home office setup under $2000” and it researches each category, finds best picks, and tracks the running total.

The Lineup

As you chat, an interactive comparison panel builds alongside the conversation. The agent picks the right display mode for the task:

  • Ranked — Products scored and ordered with annotations and badges
  • Collection — Multi-product budget building with a running total
  • Table — Sortable spec grid
  • Versus — Head-to-head matchup with detailed score breakdowns
  • Timeline — Price sparklines showing trends over time

You can export any Lineup to CSV, Markdown, or copy it straight into a spreadsheet.

Some features worth highlighting

Inline Price Checking: Anytime the agent mentions a price, you get a live price check inline to verify it’s accurate and current.

Call for Me: Need to know if a local store has something in stock? The agent calls them. On the phone. You watch the call live with real-time transcripts. It checks stock, current prices, and price matching policies.

Buy It For Me: Say “buy it” and the agent handles checkout on the retailer’s website. Payment info is encrypted on your device and unlocked with Touch ID. The agent never sees your card number.

Watches Everything: Price drops on products, deals matching keywords, changes to entire lineups over time. Desktop push notifications when something you care about changes.

The tech

  • Electron with BrowserView-based product sidebar
  • Real-time WebSocket streaming with thinking/reasoning display
  • Custom agent tools for product search, offer lookup, review fetching, price history
  • Inline live price verification on every price mentioned
  • Encrypted on-device payment vault
  • Multiple lineup display modes with export capabilities

Try it

It’s free to start: shopsavvy.com/desktop

We’ve been building shopping tech for almost two decades (ShopSavvy mobile has 40M+ downloads). No tracking, no ads.

Would love to hear what you think.

Top 5 Terminal AI Coding Agents in 2026

TL;DR: Claude Code for complex refactors if you have the budget. Gemini CLI for the best free tier (now with Plan Mode). Aider if you want multi-provider flexibility and the best git workflow.

Terminal AI coding agents have moved past the novelty stage. Developers are dropping IDE-integrated copilots for command-line tools that can reason across entire codebases, run shell commands, and commit changes autonomously.

March 2026 made this space even more competitive: Google shipped Plan Mode for Gemini CLI on March 11, and the open-source community keeps pushing Aider and OpenCode forward. Meanwhile, Claude Code and Codex CLI continue to battle for the premium end of the market.

Here are the five terminal AI coding agents worth evaluating right now, compared side-by-side.

The Comparison Table

Feature Claude Code Codex CLI Gemini CLI Aider OpenCode
Maker Anthropic OpenAI Google Open-source Open-source
Open-source No Yes (Apache 2.0) Yes (Apache 2.0) Yes (Apache 2.0) Yes (MIT)
Default model Claude Sonnet 4 o4-mini Gemini 2.5 Pro Configurable Configurable
Multi-provider Anthropic only OpenAI only Gemini only Any provider Any provider
Plan mode Built-in Yes Yes (NEW) No Yes
Git integration Auto-commit Auto-commit Yes Best-in-class Yes
Sandbox execution Yes Yes (isolated) Yes No No
MCP support Yes No Yes No Yes
Free tier No Bring API key 60 req/min free Bring API key Bring API key
Starting cost $20/mo Pro API costs only Free API costs only API costs only

Claude Code

Claude Code is Anthropic’s terminal agent built around one massive advantage: a 1-million-token context window. It can ingest entire repositories in a single prompt, which makes it the strongest option for understanding complex, interconnected codebases.

Strength: Unmatched reasoning over large codebases. Multi-file refactors and architectural-level bug hunts are where Claude Code pulls ahead of everything else.

Weakness: The most expensive option by far. No free tier, and you’re locked into Anthropic’s model family.

Best for: Senior engineers working on large, messy codebases where understanding the full picture matters more than speed.

Pricing: $20/month (Pro) or usage-based API pricing.

Codex CLI

Codex CLI is OpenAI’s open-source terminal agent. It runs commands in an isolated sandbox by default, which means it can execute code, install packages, and run tests without risking your local environment.

Strength: Sandboxed execution is a genuine differentiator. You can let it run wild without worrying about destructive commands. Fast iteration speed for scaffolding and boilerplate.

Weakness: Locked to OpenAI models. No multi-provider support, and the ecosystem is smaller than Aider’s.

Best for: Teams already invested in the OpenAI ecosystem who want safe, sandboxed code execution in the terminal.

Pricing: Free and open-source. You pay for OpenAI API usage.

Gemini CLI

Gemini CLI is Google’s entry, and it just became significantly more capable. The Plan Mode update (March 11, 2026) lets Gemini CLI create a structured plan before executing changes, similar to how Claude Code approaches complex tasks. Google also shipped Conductor automated reviews in early March.

Strength: The best free tier in this category — 60 requests per minute on Gemini 2.5 Pro with a Google account. Plan Mode closes the gap with Claude Code on complex tasks. Strong MCP support.

Weakness: Locked to Gemini models. Still maturing compared to Claude Code and Aider. The newest agent in this list (excluding OpenCode), so the community and tooling ecosystem is still catching up.

Best for: Developers who want a powerful terminal agent without paying anything. Android and Google Cloud developers get extra integration benefits.

Pricing: Free tier (60 req/min). Paid API for higher volume.

Aider

Aider is the original terminal AI coding agent, and it remains the most flexible. It works with any LLM provider — OpenAI, Anthropic, Google, local models via Ollama, or any OpenAI-compatible API. Its git integration is the best in the category: automatic commits with meaningful messages, easy rollback, and diff-aware context management.

Strength: True multi-provider support means you’re never locked in. Switch between Claude, GPT, Gemini, or local models with a flag. Git workflow is seamless — every change is a clean, reversible commit.

Weakness: No sandbox execution (runs commands directly in your environment). No built-in plan mode — it edits files directly, which can be jarring for complex tasks.

Best for: Developers who want provider flexibility, use local models, or care deeply about clean git history. The “Swiss Army knife” of terminal coding agents.

Pricing: Free and open-source. You pay for whichever LLM API you choose.

OpenCode

OpenCode is the newest entrant, built in Go and designed to be lightweight and fast. It supports multiple providers out of the box, has built-in plan mode, and includes MCP support for extending its capabilities with external tools.

Strength: Lightweight, fast startup, and actively developed. The Go implementation means it installs as a single binary with no runtime dependencies. Growing community on r/LocalLLaMA.

Weakness: Newest tool on this list, so the ecosystem and documentation are still thin. No sandbox execution. Fewer battle-tested workflows compared to Aider.

Best for: Developers who want a fast, minimal terminal agent that supports multiple providers and MCP, without the overhead of Node.js or Python runtimes.

Pricing: Free and open-source. Bring your own API key.

How to Choose

The decision tree is simpler than the feature matrix suggests:

  • Budget is zero? Start with Gemini CLI. The free tier on Gemini 2.5 Pro is generous, and Plan Mode makes it viable for real work.
  • Need provider flexibility? Aider is the safest bet. It works with everything and has years of community-tested workflows.
  • Want maximum code understanding? Claude Code’s context window is still unmatched for large codebases.
  • OpenAI ecosystem? Codex CLI with sandbox execution is a natural fit.
  • Want something minimal? OpenCode is worth watching — fast, Go-based, and growing quickly.

The Verdict

There is no single winner because these tools optimize for different things. Aider is the safest default for most developers — it works with any provider, has the most mature git integration, and has been battle-tested longer than anything else on this list. Claude Code wins on raw reasoning quality for complex refactors but commands a premium price. And Gemini CLI, with Plan Mode now shipping, is the dark horse that offers the most capability per dollar spent (which is zero).

The real power move? Use two of them. Aider or Gemini CLI for daily coding, Claude Code when you hit a gnarly multi-file bug that needs the full-context treatment.

These terminal agents handle code generation, debugging, and refactoring. For orchestrating agents that connect to APIs, manage workflows, and automate tasks on schedules, platforms like Nebula complement terminal agents by handling the non-coding automation layer.

What terminal coding agent are you using? Drop your setup in the comments.

Mastering User Identity in OpenClaw: A Guide to the Identity-Resolver Skill

Unified User Experiences with OpenClaw’s Identity-Resolver

In the rapidly evolving world of autonomous agents and automated workflows,
one of the most persistent hurdles is identity fragmentation. As users
interact with your OpenClaw agents across multiple platforms—perhaps sending a
message from Telegram in the morning, a request via WhatsApp during their
commute, and a command through Discord in the evening—the agent often treats
these as three separate individuals. This results in disjointed memory,
fragmented access control, and a poor user experience. Enter the Identity-
Resolver
skill, a critical component of the OpenClaw ecosystem designed to
bridge these gaps.

The Core Problem: Multi-Channel Fragmentation

In a standard agent setup, each messaging channel carries its own unique user
identifier. A platform like Telegram provides a numeric ID, while Discord uses
a username and tag combination, and web-based interfaces might use email or
session cookies. Without a translation layer, the agent cannot inherently know
that ‘Telegram User A’ and ‘Discord User B’ are actually the same person. This
leads to several technical challenges: your memory systems become siloed,
access control rules fail to apply consistently, and personalization becomes
impossible because your agent doesn’t have a single, holistic view of the
user’s history.

The Identity-Resolver Solution

The Identity-Resolver skill acts as a middleware layer that maps various
channel-specific identities to a single, ‘canonical’ user ID. By creating a
unified backbone, all your other skills—whether they deal with tiered memory,
access control, or user preferences—can query this resolver to ensure they are
always interacting with the correct underlying identity. It effectively turns
a collection of disparate platform accounts into a single, cohesive user
entity.

Key Technical Features

The beauty of this skill lies in its simplicity and robustness. Here is why it
is essential for your OpenClaw deployment:

  • Zero Dependency Architecture: The skill is built entirely with pure Python standard library components. This ensures maximum portability and minimal overhead, making it easy to integrate into any agent environment.
  • Thread-Safe Operations: Utilizing fcntl file locking, the Identity-Resolver handles concurrent requests safely. In an environment where multiple messages might arrive simultaneously from different channels, this ensures the identity map remains consistent and free from corruption.
  • Path Traversal Protection: Security is paramount when dealing with user identifiers. The skill automatically sanitizes all canonical IDs, restricting them to alphanumeric characters, underscores, and hyphens to prevent malicious path traversal attempts.
  • Owner Auto-Registration: The system automatically detects the primary owner from the project’s USER.md file, ensuring that administrative access is set up immediately upon installation.

Getting Started: Installation and Setup

Installation is straightforward for those familiar with the OpenClaw
workspace. The recommended approach is using ClawHub:

clawhub install identity-resolver

Alternatively, if you prefer manual integration via Git, you can simply clone
the repository into your skills/ directory. Once installed, the
initialization process is a one-time command that sets up your identity map.
From there, verifying a user’s status is as simple as running a command
through the included CLI: uv run python scripts/identity_cli.py resolve
--channel [channel_name] --user-id [your_id]
.

Developer Deep-Dive: Integrating into Your Skills

For developers, the true power of the Identity-Resolver is in its Python API.
By importing resolve_canonical_id into your own skills, you can ensure that
your data storage is always keyed by a stable identifier. Imagine a memory
system that stores user-specific files in a directory structure like
data/users/{canonical_id}/memory.json. By using the resolver, it doesn’t
matter if the user switched devices or platforms; their memories remain
accessible.

Example integration code snippet:

`from identity import resolve_canonical_id

channel = os.getenv(“OPENCLAW_CHANNEL”)

user_id = os.getenv(“OPENCLAW_USER_ID”)

canonical_id = resolve_canonical_id(channel, user_id)

Use canonical_id for all user-specific operations`

Practical Use Cases

1. Unified Memory Systems

When implementing a tiered memory skill, you need to be certain that the
information you are retrieving belongs to the current user, regardless of how
they are reaching out to the agent. The Identity-Resolver ensures that your
memory trees are indexed by the canonical ID, providing a consistent knowledge
base across every channel.

2. Global Access Control

Security rules should not be bound to the platform. By checking the user’s
status against their canonical ID, you can implement robust access control.
For instance, you can grant administrative privileges exclusively to the
owner, ensuring that even if someone manages to compromise a specific channel,
the agent’s core permissions remain protected by the central identity map.

3. Cross-Platform Tracking

Perhaps you want your agent to recognize a user when they move from a desktop
web interface to a mobile messaging app. The Identity-Resolver enables
seamless tracking by mapping these unique interactions to the same canonical
ID, allowing the agent to pick up exactly where the conversation left off.

Conclusion

The Identity-Resolver is more than just a mapping tool; it is a foundational
piece of infrastructure for any serious OpenClaw agent developer. By solving
the multi-channel identity problem, it empowers you to build smarter, safer,
and more personalized user experiences. Whether you are building complex
memory systems, granular access control, or simply trying to track users
across a fragmented digital landscape, this skill provides the reliability and
security you need. Start your integration today and unify your agent’s
understanding of the world.

Skill can be found at:

resolver/SKILL.md>

Zero Trust Architecture for AI Runtime Execution

The introduction of the Bedrock AgentCore Runtime Shell Command elevates large language models from text generators to active system participants. This capability demands a strict zero trust architecture.

Enterprise operations require predictability. When deploying an autonomous shell, the infrastructure must enforce a zero trust baseline. Giving a probabilistic model direct interaction with an operational environment is a massive paradigm shift. We can no longer rely on prompt engineering to secure an enterprise environment. Trusting a generative model to obey natural language constraints is a structural vulnerability. Instead, we must apply strict deterministic limits.

Here is how we build the architecture for an autonomous shell:

Network Isolation
The execution environment must be entirely sealed. Place the Bedrock agent runtime in a dedicated Virtual Private Cloud with no inbound internet access. Outbound connections must be explicitly allowed to approved endpoints only.

Identity and Access Management
The role assumed by the agent must have a strict permissions boundary. It should never have the ability to alter its own permissions or create new policy versions. Limit the blast radius to the exact resources required for the task.

Immutable Logging
Every system command generated and executed by the shell must be recorded. Send these logs to an isolated storage bucket where the agent has zero write access. You need a verifiable audit trail of every automated action.

Security is not optional. We MUST build environments that dictate the rules to the AI. We MUST treat the autonomous shell exactly like an unverified external entity. Security is established by deterministic infrastructure rules, never by generative models.

Sources:

https://aws.amazon.com/about-aws/whats-new/2026/03/bedrock-agentcore-runtime-shell-command/

https://docs.aws.amazon.com/bedrock/latest/userguide/security-iam.html

https://aws.amazon.com/architecture/security-identity-compliance/

Reusing CloudFront, ALB, and API Gateway in a Serverless Platform

Post Banner

Modern serverless platforms often need to support a mix of public-facing entry points - web applications and APIs - while keeping internal communication private and tightly controlled. Non-functional requirements around security, compliance, and operational isolation typically drive this.

Post Banner

At the same time, such platforms are increasingly built around multiple domain services, each representing a bounded context and owned by a small team. Independent deployments, limited blast radius, and clear ownership are usually explicit architectural goals.

These goals, however, often collide with another equally important requirement: speed. In fast-paced development environments, the ability to spin up feature environments on demand, test changes quickly, and tear everything down without friction is critical to maintaining delivery velocity.

This post explores how architectural choices at the edge - specifically around CloudFront, Application Load Balancers (ALB), and API Gateway - can either enable or severely constrain that speed. It looks at how careful reuse of these components can support isolated, per-service deployments and on-demand environments without driving up cost or operational complexity, and where the trade-offs start to appear.

Architectural choices

Frontend

In many serverless platforms, the frontend acts as the primary public entry point. A common pattern is to place CloudFront at the edge and route requests to different backend origins depending on their nature.

Static assets are typically served from S3, while dynamic requests are forwarded to compute workloads that render pages or handle frontend-driven API calls. These dynamic workloads may run as Lambda functions or containers, often inside a VPC to meet security and compliance requirements.

At this point, there is an architectural choice to make: whether dynamic frontend traffic should be handled by the API Gateway or an Application Load Balancer (ALB).

From a non-functional requirements perspective, separating public access from private execution is key. While API Gateway is well-suited for exposing managed APIs, frontend traffic often benefits from being terminated at ALB, with requests forwarded to compute that remains fully private within a VPC. CloudFront supports private origins through VPC-origin integrations with internal ALB, whereas private API Gateways cannot be used directly as CloudFront origins. This makes ALB a more natural fit when frontend compute is intentionally kept off the public internet.

Placing Lambda functions behind an ALB and inside a VPC also addresses increasingly common security requirements in regulated environments. When compute is fronted by an internal ALB, CloudFront becomes the only public ingress path by design. The ALB is not internet-facing and cannot be accessed directly, which ensures that all external traffic is consistently terminated, inspected, and controlled at the edge.

This pattern significantly reduces the risk of accidental or intentional bypass of edge-level controls. Combined with VPC-based execution, it enables tighter governance of inbound and outbound traffic through WAF, security groups, routing, and egress filtering. Together, these measures provide stronger guarantees than relying solely on managed service boundaries or publicly reachable endpoints.

CF-ALB-Frontend

From an operational perspective, ALB offers lower latency for HTTP workloads, native support for both host-based and path-based routing, and seamless integration with both Lambda and container-based runtimes such as ECS. These characteristics make it particularly well-suited for frontend and backend-for-frontend (BFF) use cases, where routing flexibility, performance, and network controls often outweigh API-centric features such as request validation, usage plans, or request transformation.

This does not diminish the role of API Gateway in the overall architecture. API Gateway remains a strong choice for internal and external APIs, especially where API lifecycle management, authentication, throttling, and contract enforcement are primary concerns. Using ALB at the frontend edge simply allows each component to be applied where it fits best, rather than forcing a single service to satisfy fundamentally different requirements.

Internal API

Internally, platforms often expose functionality through APIs consumed by other services or internal clients. A key architectural decision is whether to operate a single internal API Gateway or multiple gateways aligned with services, domains, or teams.

There is no universal answer. Smaller platforms or early-stage systems often benefit from a single internal API, as it simplifies discovery and reduces operational overhead. As platforms grow, multiple APIs aligned with domains or “two-pizza teams” can become more appropriate, particularly when ownership boundaries, release cadence, or non-functional requirements diverge.

What matters more than the number of gateways, however, is recognising that API shape and deployment shape are not the same thing. A single logical API does not require a single infrastructure deployment unit, just as multiple services do not automatically justify multiple gateways. Treating these concerns separately allows teams to optimise for independent releases, blast-radius reduction, and clearer ownership, while keeping the external API surface coherent.

SingleVsMultipleAPIGs

This distinction becomes especially important in high-paced environments, where the ability to evolve services independently should not be constrained by how APIs are presented or grouped at the edge.

Backend services and infrastructure-as-code

From an infrastructure-as-code (IaC) perspective, backend services are often deployed as independent units to support isolation, targeted releases, and reduced blast radius. This aligns naturally with domain-driven design, where each service represents a bounded context and can evolve independently.

When multiple backend services are exposed through a single API Gateway, this model becomes more nuanced. API Gateway configuration changes - such as routes, integrations, or method settings - are only made effective through an explicit deployment step. As a result, while service-specific configuration can be defined independently, the API Gateway itself still has a shared deployment lifecycle.

This does not make per-service backend stacks incompatible with a single API Gateway, but it does require additional structure. In practice, this means decomposing API Gateway configuration into distinct concerns: a base or core API configuration, per-service or per-domain route and integration definitions, and a dedicated deployment component responsible for applying changes to the gateway. That deployment component must be notified when any service updates its portion of the API configuration, without introducing tight coupling between services or requiring knowledge of how many services exist.

Without this explicit separation, a shared API Gateway can easily become a point of implicit coupling, where independent service deployments are forced to coordinate around a central API deployment. With the right decomposition and signalling in place, however, a single logical API can still support independent service lifecycles and parallel provisioning.

TFsplit

In contrast, using an API Gateway per backend service naturally scopes configuration and deployment to the service itself, avoiding the need for cross-service coordination at the gateway level. The trade-off is increased operational overhead and a more fragmented API surface. The choice between these approaches is therefore not about feasibility, but about how much complexity is absorbed by infrastructure design versus operational management, and how much flexibility is required as the platform continues to evolve.

On-demand feature environments

Why they matter

Fast feedback is essential. Feature environments allow teams to validate changes in realistic conditions, unblock reviews, and catch integration issues early. While tools like LocalStack can help with local development, they have limitations - especially for integration testing, CI pipelines, and workflows involving multiple services.

On-demand environments bridge that gap, but naïvely provisioning full stacks per feature quickly becomes expensive and slow, too slow.

Reuse as an enabler

Not all infrastructure needs to be duplicated. Components like CloudFront, ALB, and API Gateway are surprisingly well-suited to reuse, provided routing is designed with that goal in mind.

This is not just a cost consideration. Creating or modifying edge components such as CloudFront distributions or load balancers can easily take ten minutes or more, which makes them a poor fit for fast, iterative workflows. When feature environments depend on provisioning or reconfiguring these components, feedback loops slow down dramatically.

The key, therefore, is deciding what varies per environment and what stays shared. By reusing long-lived edge infrastructure and shifting environment-specific concerns into routing, configuration, and backend resources, platforms can keep costs predictable and provisioning times low. The trade-off is that this requires upfront discipline in routing design, naming conventions, and configuration boundaries, but that investment pays off quickly as the environment count and delivery pace increase.

Ephemeral on-demand environments

Ephemeral environments, the golden grail, aim for maximum speed. They rely on shared edge infrastructure and differentiate environments through routing.

This approach typically requires:

  • Shared CloudFront configuration with a common domain name
  • Path-based routing at ALB
  • Frontend support for runtime basePath and assetPrefix changes
  • Multiple API Gateway stages mapped to environment identifiers

EphmeralEnvs

Note: Internal API design is irrelevant here

When these conditions are met, spinning up a new environment becomes little more than adding routing rules and deploying service-specific resources. Cleanup is trivial, and costs remain largely constant regardless of the number of environments. Neither CloudFront nor the ALB needs to be aware of how many environments exist or may exist in the future.

Semi-static on-demand environments

Some frontends (e.g., Next.js) require environment-specific configuration at build time and cannot easily adapt to runtime path changes. In these cases, a semi-static approach is often necessary.

Here, each environment may have:

  • Shared CloudFront configuration with alternate domain names and static Route 53 records
  • Shared ALB with host-based routing
  • Any API Gateway configuration implementation

SemiStaticEnvs

Note: Internal API design is irrelevant here

In contrast to the ephemeral environments option, this model requires CloudFront and Route 53 to be prepared upfront. Each environment must be explicitly represented through distribution configuration and DNS records, making environments longer-lived and less dynamic by design.

Practical limits and quotas

In practice, hard service quotas are rarely the first blocker. More often, provisioning time and operational friction become limiting factors as environments scale.

That said, quotas do influence how far reuse patterns can go and whether a limit can be raised or must be designed around matters. API Gateway REST APIs support a limited number of stages per API (10 by default, soft limit), which constrains stage-based environment reuse. Private API Gateway custom domain names are also subject to soft limits. On the load-balancing side, an ALB supports up to 100 listener rules (soft limit) and 100 target groups (hard limit), the latter requiring an architectural change.

For example, reusing a single ALB across ten environments can consume listener rules perhaps not so quickly, while a single API Gateway with one stage per environment approaches its stage limit fast. These constraints don’t prevent reuse, but they highlight the need to understand early which limits can be adjusted and which require rethinking the design.

Conclusion

The patterns described in this post are not a single fixed architecture, but a set of reuse-oriented edge and routing strategies for serverless platforms built on CloudFront, ALB, and API Gateway. Their value lies in being applied selectively.

For lower environments - feature, preview, and integration stages - reusing edge components and differentiating environments through routing enables fast provisioning, easy teardown, and predictable costs. These environments benefit most from shared CloudFront distributions, shared ALBs, and carefully structured API Gateway reuse, where speed and feedback outweigh the need for strict isolation.

Upper environments are different. Staging, pre-production, and production typically require:

  • Standalone, fully isolated infrastructure
  • Right-sized capacity and scaling characteristics
  • Stable DNS and edge configuration
  • The ability to run meaningful load, stress, and performance tests against an environment that truly behaves like production

In those environments, reuse at the edge is usually inappropriate. Dedicated CloudFront distributions, ALBs, and API Gateways are not an optimisation failure - they are a requirement.

Supporting both approaches within the same platform does introduce additional complexity, particularly in infrastructure-as-code. Designing IaC that remains DRY while allowing some environments to share edge infrastructure and others to be fully isolated requires clear layering, strong conventions, and explicit ownership boundaries. This is more demanding than a uniform setup, but it is entirely achievable with deliberate design.

These patterns optimise for:

  • Fast feedback and experimentation where environment churn is high
  • Independent service evolution with controlled blast radius
  • Predictable cost and provisioning time at scale
  • The ability to evolve toward stricter isolation when needed

They are not optimised for:

  • Maximum isolation across all environments
  • Treating edge infrastructure as immutable per environment
  • Eliminating all shared components

Being explicit about where reuse applies - and where it must not - allows the platform to move quickly without compromising correctness. The goal is not to reuse everything, but to reuse the right things, in the right places, for the right reasons.