Why Rust-Based Agents Will Dominate x402 Protocol Integration (And How to Build One in 30 Minutes

Autonomous AI agents are launching tokens, managing treasuries, and running entire protocols without human intervention. But most of them are still using Python wrappers that make 3 RPC calls when they only need 1. If you’re building agents that interact with blockchain fundraising contracts, this inefficiency isn’t just slow—it’s expensive.

The x402 protocol standard changes this. It’s a pattern that lets agents query campaign data, verify contribution amounts, and trigger actions with single contract reads. No indexer required. No off-chain database. Just Rust, some basic Ethereum tooling, and a different way of thinking about how agents should interact with on-chain primitives.

What x402 Actually Solves

Most crowdfunding platforms store campaign state across multiple contracts or rely on events. Want to know if a campaign hit its goal? You scan events, reconstruct state, hope nothing reorged. Want to know who contributed? More events, more reconstruction.

x402 flips this. Campaign state lives in structured storage slots that agents can read directly:

struct Campaign {
    address creator;
    uint256 goal;
    uint256 raised;
    uint256 deadline;
    bool finalized;
    mapping(address => uint256) contributions;
}

Everything an autonomous agent needs to make decisions—goal, deadline, raised amount—is in one place. No historical queries. No “wait for sync.” Read slot, get state, decide.

Building a Rust Agent That Actually Ships

Python’s web3.py is great for scripts. Rust is better for agents that need to run 24/7 without memory leaks or dependency hell. Here’s a minimal x402 agent that monitors Fundchain campaigns and triggers actions when they reach 80% funding.

First, the dependencies in Cargo.toml:

[dependencies]
ethers = "2.0"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

The core agent logic reads campaign state every 60 seconds:

use ethers::prelude::*;
use std::sync::Arc;

#[derive(Debug, Clone)]
struct CampaignState {
    goal: U256,
    raised: U256,
    deadline: U256,
    finalized: bool,
}

async fn read_campaign_state(
    contract: &Contract<Provider<Http>>,
    campaign_id: U256,
) -> Result<CampaignState, Box<dyn std::error::Error>> {
    let goal: U256 = contract.method("getGoal", campaign_id)?.call().await?;
    let raised: U256 = contract.method("getRaised", campaign_id)?.call().await?;
    let deadline: U256 = contract.method("getDeadline", campaign_id)?.call().await?;
    let finalized: bool = contract.method("isFinalized", campaign_id)?.call().await?;

    Ok(CampaignState { goal, raised, deadline, finalized })
}

Notice what’s missing: no event parsing, no block range queries. The contract exposes getters that return current state. That’s the x402 pattern—optimized for agent reads, not human dashboards.

The Decision Loop

Autonomous agents need clear trigger conditions. This one watches for campaigns approaching their goal:

async fn agent_loop(
    contract: Arc<Contract<Provider<Http>>>,
    campaign_id: U256,
) -> Result<(), Box<dyn std::error::Error>> {
    loop {
        let state = read_campaign_state(&contract, campaign_id).await?;

        if state.finalized {
            println!("Campaign {} finalized. Stopping monitor.", campaign_id);
            break;
        }

        let progress = state.raised.as_u128() as f64 / state.goal.as_u128() as f64;

        if progress >= 0.8 && progress < 0.85 {
            println!("Campaign {} at {:.1}% - triggering boost signal", campaign_id, progress * 100.0);
            trigger_boost_action(&contract, campaign_id).await?;
        }

        tokio::time::sleep(tokio::time::Duration::from_secs(60)).await;
    }
    Ok(())
}

In my experience, the mistake most developers make here is trying to react to every state change. That’s fine for event-driven UIs. For agents managing multiple campaigns, you want polling with clear thresholds. Less RPC spam, clearer logic, easier to debug when something breaks at 3 AM.

Why This Beats Python Wrappers

Python agents using web3.py typically do this:

  1. Call getPastEvents for contribution events
  2. Sum contributions in memory
  3. Compare to goal from separate contract call
  4. Repeat every loop because Python doesn’t maintain state well

The Rust version above makes 4 contract calls total. Python’s event-based approach makes N calls where N = number of contributions since last check. For a campaign with 500 contributors, that’s 500x more RPC load.

Rust also gives you:

  • Statically typed contract ABIs: No runtime errors from typos in method names
  • Native async: tokio handles dozens of campaigns in one thread
  • Memory safety: No GIL, no surprise segfaults from native dependencies

Connecting to Real Infrastructure

This agent pattern works with any x402-compatible contract. Fundchain.ai implements x402 natively, so you can point this exact code at production:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let provider = Provider::<Http>::try_from("http://url2545.fundchain.ai/ls/click?upn=u001.okkrTKcGgKOHjQ-2BjYb5pKqQ6qrCXhRON-2F7YIJoFOI-2B1y5dzA-2FY3EiWUIW2epp-2FTa-2Frr6y-2F2HeFJCNQIHA5GZKA-3D-3DyWQP_jI-2B6iYjohItsLrFObi4lJ4WhASWB2OOsYcYZIZ7L693NQ4fAlB2-2FdNQmbM9PdxUq9YtgzZsAKYMOfxZovXeUQgj3jWDLpVEfRL0h16fBKsML-2F0SBUwraHUj4KnqdbuOVUYv-2FBSjaXZP0w9aFm9liOJMXLvB4wF-2BueqX7EqZoIfjmv6ojXRcE2HuHKihPAH1xBNowN7Nac1eSI80CH9gSJw-3D-3D
    let contract_address = "0x..."; // Fundchain factory on Base
    let abi = include_str!("./abi/Fundchain.json");

    let contract = Contract::new(
        contract_address.parse::<Address>()?,
        serde_json::from_str::<Abi>(abi)?,
        Arc::new(provider),
    );

    agent_loop(Arc::new(contract), U256::from(1)).await
}

What surprised me about this approach: you don’t need a database. Campaign state is already on-chain in a format agents can read directly. The agent is stateless. Kill it, restart it, same behavior. That’s the power of x402—optimized storage layout means agents don’t need caching layers.

What You Should Build Next

Most crowdfunding agents today just monitor. The interesting ones will co-manage campaigns with humans. An agent that detects slowing momentum and automatically posts updates. An agent that routes overflow funds to related campaigns. An agent that verifies milestone completion and releases tranches.

All possible with this pattern. x402 gives you the reads. You bring the decision logic.

If you want to skip the contract deployment and ABI wrangling, Fundchain.ai already exposes x402-compatible endpoints. Check the API docs at [fundchain.ai/api-docs] for read methods that match this exact pattern. The Rust code above works unchanged—just point it at production contracts that already have volume.

Strategic Leadership Communication: Mastering Conflict Management in the Modern Workplace

Workplace conflict is inevitable, but how leaders communicate during these challenging moments determines whether conflicts become destructive forces or catalysts for growth. Strategic leadership communication transforms conflict from organizational liability into competitive advantage.

Most workplace conflicts stem from predictable sources: poor communication patterns, personality clashes, unrealistic expectations, interdependence issues between departments, and competition over limited resources. When leaders fail to address these root causes through strategic communication, stress increases, team dynamics deteriorate, and productivity suffers.

Leaders who master strategic communication during conflicts create environments where teams thrive despite disagreements.

Conflict competency represents the ability to develop cognitive, emotional, and behavioral skills that enhance productive outcomes during disputes while reducing the likelihood of escalation or lasting relationship damage. This competency hinges on communication choices leaders make in critical moments.
Leaders exhibit either constructive or destructive communication responses during conflicts. Constructive responses include active listening, acknowledging different perspectives, asking clarifying questions, and focusing on shared goals. Destructive responses involve personal attacks, dismissive language, ultimatums, and blame-focused communication.

These communication patterns create measurable physiological effects on team members. Constructive communication reduces cortisol levels and promotes collaboration, while destructive communication triggers fight-or-flight responses that impair decision-making and creativity.

Every leader has “hot buttons” - specific situations or behaviors that consistently provoke reactive communication responses. Common workplace triggers include feeling disrespected, being interrupted during presentations, having decisions questioned publicly, or receiving criticism about work quality.

Strategic leaders identify their personal triggers and develop communication protocols for managing these situations effectively. This preparation prevents reactive responses that escalate conflicts and damage relationships.

The Transportation Security Administration’s Integrated Conflict Management System demonstrates how organizations can systematically improve conflict communication outcomes. Their approach focused on three key components: systematic skill development programs, organizational structure modifications, and comprehensive support mechanisms.

The results were measurable: reduced grievances, improved employee satisfaction, and faster resolution times for disputes. This success stemmed from treating strategic communication as a learnable skill rather than an innate talent.

When managed through effective communication, conflicts generate significant organizational benefits. Teams experience strengthened working relationships as they navigate disagreements successfully. Creative solutions emerge when diverse perspectives are communicated respectfully and thoroughly explored. Decision-making improves as leaders facilitate discussions that surface hidden assumptions and alternative approaches.
Leaders who embrace this mindset view conflicts as opportunities to demonstrate strategic communication skills and strengthen team capabilities.

Strategic leadership communication requires mastery at three distinct levels:
Individual Self-Mastery involves developing emotional regulation skills, practicing active listening techniques, and learning to communicate clearly under pressure. Leaders must recognize their default communication patterns and consciously choose more effective approaches.

Team-Level Coordination focuses on establishing communication norms, creating safe spaces for disagreement, and facilitating productive discussions between conflicting parties. Leaders set expectations for how team members communicate during disputes.
Organizational Systems Integration requires embedding strategic communication principles into policies, training programs, and performance evaluation criteria. Leaders create structures that support and reward effective conflict communication throughout the organization.

Implementing Strategic Communication Practices
Leaders serious about improving their conflict communication should focus on continuous skill development. This includes practicing difficult conversations in low-stakes situations, seeking feedback on communication effectiveness, and studying successful conflict resolution examples.

The investment pays dividends through reduced workplace stress, improved team dynamics, and enhanced organizational resilience. Strategic leadership communication transforms inevitable workplace conflicts into opportunities for growth, innovation, and stronger relationships.

Mastering these skills positions leaders to navigate organizational challenges effectively while building teams capable of thriving in complex, fast-changing business environments.

Codepath Volunteers

Earlier this year, CodePath organized a meetup with Microsoft employees who volunteer with the organization. The gathering brought together dedicated mentors from Microsoft and the greater Seattle area who are committed to diversifying the tech industry through meaningful mentorship.

During the event, I was inspired hearing firsthand accounts of how mentors supported mentees who started their careers. Participants shared powerful stories about how their mentorship experiences had transformed students’ lives, giving them the confidence, skills, and connections needed to succeed.

CodePath students often seek guidance in various areas, from finding internships and developing new programming skills to overcoming impostor syndrome. The impact of mentors in these journeys cannot be overstated. Many volunteers spoke about the mutual benefits they received, noting how teaching concepts to others deepened their own technical understanding and leadership abilities.

Join Our Monthly Community Calls
In addition to my work with CodePath, I host free monthly community calls where we share wins, learnings, and give each other advice. These sessions create a supportive environment for professionals in technology and other fields to connect with experts and learn from each other’s experiences. Whether you’re seeking mentorship, looking to expand your network, or simply want to engage with like-minded professionals, these calls provide valuable insights and connections.

To participate in our next community call, visit https://topmate.io/graceg to sign up. These sessions are open to everyone, regardless of experience level, and provide a fantastic opportunity to build relationships with others in the tech community.

Thanks for reading!

Women in Product Conference 2025 #25WIP

Earlier in the year, I had the privilege of attending the Women In Product Conference in Santa Clara. It was a full day of insights on the future of AI, leadership, and what it means to build with courage. The speakers came from across industries startups, big tech, consumer brands yet their lessons echoed a common theme: the era of building is here, and we rise together through community, clarity, and craft.
The conference opened with Tekedra Mawakana, Co-CEO of Waymo, in conversation with Cassie Campbell. Tekedra spoke about leading with vision, integrity, and boldness while standing at the edge of transformative technology. Her reminder: leadership is not just about managing change, but about embodying courage when the path forward isn’t obvious.
Cassie Campbell and Tekedra MawakanaClaire Vo, previous CPO of LaunchDarkly, delivered one of the most urgent calls to action of the day. She described AI as a generational economic opportunity - one that women can’t afford to sit out. Her words stuck with me: “This is the era of hard skills. The era of building.” It was a powerful reminder that as product managers, we can’t just observe the AI wave; we have to learn, adapt, and build with it.
Claire VoAparna Chennapragada, CPO at Microsoft, added a striking perspective: “Prompt sets are the new PRDs. Natural Language Interfaces are the new UX.” For PMs, this shifts the foundation of how we write requirements, design experiences, and deliver value.
Panel with Julie Wenah, Aparna Chennapragada, Sun Choe, Tiffany ToSuba Vasudevan, COO of Mozilla, emphasized that AI isn’t just about speed or scale - it’s about building responsibly. She encouraged PMs to flip the funnel: don’t start with technology, start with the problem and the value. Only then bring in AI capabilities that serve those needs. This framing was refreshing. In an industry where hype often outpaces substance, Suba grounded us in trust, responsibility, and human impact.
Suba Vasudevan, COO of MozillaThe “From Features to Futures” panel featured leaders who had navigated unconventional career paths. Yana Welinder, CEO of Kraftful, urged us not to wait until everything is perfect - just start. Opportunities rarely arrive gift-wrapped.
Deboshree Dutta spoke vulnerably about the burnout she experienced as a founder, and how resilience has been her greatest asset.
Debbie Soo, CEO of OpenTable, shared how gratitude and self-awareness anchor her leadership. The theme that tied it all together? Treat pivots like experiments. Test, learn, adapt - in products and in careers.
Panel with Debbie Soo, Yana Welinder, Deb Dutta, Renee DavisOne of my favorite sessions was with Charlotte Narvaez and Vidya Srinivasan from Meta. Their advice was practical, simple, and empowering: don’t let knowledge gaps linger - ask AI. Read widely, especially trusted AI newsletters like The Information.
Remember that the PM’s job is not to fine-tune models, but to define success and use cases. Their vision for the future of product management? AI taking the busywork off our plates - things like meeting notes and summaries - so that humans can spend more time on impact, creativity, and family.
Charlotte Narvaez and Vidya Srinivasan from MetaChloe Shih and Ami Vora closed the loop by reframing brand as “reputation goals.” It’s not about flashy visibility, but about intentionally defining how you want to show up. They encouraged us to evolve our professional brand by blending presence, influence, and authenticity. This was a reminder that while AI may reshape products, our personal leadership presence remains a key differentiator.
Ami Vora, ex CPO of Faire and VP at Meta & Chloe Shih, ex PM @ DiscordAcross all the sessions, three threads emerged for me: craft matters, courage is required, and community is our anchor. Craft is about intentionality, whether in a product, a pivot, or a personal brand. Courage is about stepping into AI, taking risks, and embracing pivots before we feel ready. And community is about recognizing that growth doesn’t happen alone, but through learning from and supporting each other.
A huge thank you to Women In Product for organizing such a powerful event and for supporting my attendance through the Empowerment Fund. I left Santa Clara energized, challenged, and committed to leading with vision in this new era of AI.

How Probabilistic Reasoning Works — From Evidence to Better Beliefs

AI often has to decide without complete information.

The question is not always “What is true?”

It is often:

“What should we believe now that new evidence has arrived?”

That is the core of probabilistic reasoning.

Core Idea

Probabilistic reasoning is a way to make decisions under uncertainty.

Instead of treating answers as simply true or false, it assigns probabilities.

Then it updates those probabilities when new information appears.

This makes AI systems more flexible in uncertain environments.

The Key Structure

The basic flow looks like this:

Prior Belief → New Evidence → Updated Belief → Decision

More compactly:

Probabilistic Reasoning = uncertainty + evidence + updating

Bayes’ theorem is the central rule behind this update.

It explains how prior belief changes after evidence is observed.

Implementation View

At a high level, probabilistic reasoning works like this:

define possible hypotheses

assign initial probabilities

observe new evidence

update probabilities using the evidence

compare updated beliefs

choose the most reasonable conclusion

This is why probabilistic reasoning matters in AI.

Real systems rarely have perfect information.

They need a way to revise beliefs as evidence changes.

Concrete Example

Imagine a medical diagnosis system.

The possible hypothesis is:

The patient has a disease.

At first, the system has only a prior probability.

Then new evidence appears:

  • fever
  • cough
  • test result

Each piece of evidence changes the probability.

The system does not simply say “disease” or “no disease” immediately.

It updates its belief step by step.

That is probabilistic reasoning.

Probability vs Conditional Probability

Probability gives a basic likelihood.

Conditional probability changes that likelihood when information is known.

Probability asks:

How likely is A?

Conditional probability asks:

How likely is A given B?

Written as:

P(A | B)

This distinction matters because real-world reasoning depends on context.

The probability of a disease may be low in general.

But the probability changes if symptoms or test results are observed.

Bayes’ Theorem

Bayes’ theorem is the core mechanism for belief updating.

In simple language:

prior belief + evidence = updated belief

More formally:

Posterior = Prior × Likelihood / Evidence

The important idea is not just the formula.

The important idea is revision.

You start with a belief.

Then evidence changes it.

That is the foundation of Bayesian reasoning.

Before vs After Evidence

This is the most important comparison.

Before evidence:

  • the system only has a prior belief
  • the conclusion is uncertain
  • many hypotheses may still be plausible

After evidence:

  • probabilities are updated
  • some hypotheses become more likely
  • some hypotheses become less likely
  • the system can make a better decision

So probabilistic reasoning is not static.

It is adaptive.

From Reasoning to Systems

A probabilistic reasoning system connects models and inference procedures.

It may include:

  • probability theory
  • conditional probability
  • Bayes’ theorem
  • Bayesian networks
  • Markov networks
  • conditional probability tables
  • inference algorithms

The goal is not only to calculate probabilities.

The goal is to support decisions under uncertainty.

That is why these ideas matter in AI architecture.

Graphical Models

When many variables interact, plain probability formulas become hard to manage.

Graphical models help by representing relationships as structure.

Bayesian Networks use directed edges.

Markov Networks use undirected edges.

Conditional Probability Tables store probability values for different conditions.

This makes probabilistic reasoning more scalable.

Instead of reasoning over isolated formulas, the system reasons over a structured model.

Recommended Learning Order

If probabilistic reasoning feels abstract, learn it in this order:

  1. Probability Theory
  2. Conditional Probability
  3. Bayes’ Theorem
  4. Probabilistic Reasoning
  5. Probabilistic Reasoning Systems
  6. Bayesian Network
  7. Conditional Probability Table
  8. Markov Network

This order works because you first understand uncertainty.

Then you understand updating.

Then you connect the idea to structured AI systems.

Takeaway

Probabilistic reasoning is how AI handles uncertainty.

The shortest version is:

Probabilistic Reasoning = prior belief + evidence + update

Probability represents uncertainty.

Conditional probability adds context.

Bayes’ theorem updates belief.

Graphical models make the structure scalable.

If you remember one idea, remember this:

Probabilistic reasoning lets AI revise what it believes when new evidence appears.

Discussion

When building AI systems under uncertainty, do you prefer starting from Bayes’ theorem directly, or from concrete examples like diagnosis, ranking, or risk prediction?

Originally published at zeromathai.com.
Original article: https://zeromathai.com/en/probabilistic-reasoning-hub-en/

GitHub Resources
AI diagrams, study notes, and visual guides:
https://github.com/zeromathai/zeromathai-ai

Meet Canada’s Boldest Women: WXN Unveils 2025 Canada’s Most Powerful Women: Top 100 Award Winners

I’ve been recognized as one of WXN’s Top 100 Most Powerful Women in Canada for 2025!


TORONTO, [October 30, 2025] - WXN (Women’s Executive Network) and its partners today unveil the winners of the 2025 Canada’s Most Powerful Women: Top 100 Awards, celebrating 102 women whose leadership, innovation and impact are transforming industries, organizations and communities across the country. A full list of winners is available here: [LINK].
The winners will be honoured in person at the 23rd annual Top 100 Awards Gala, hosted at the Fairmont Royal York Toronto on November 27. The gala also features Taylor Hui, executive director and founder of The BeaYOUtiful Foundation in a fireside chat with Nkechi Nwafor-Robinson, Founder of In My Skin Inc.
“This year has tested what it means to rise boldly, and our Top 100 Award Winners have shown us what it means to answer the call,” said Sherri Stevens, Owner and CEO of WXN. “They’ve turned setbacks into breakthroughs, uncertainty into courage, and ambition into real impact. Their achievements light a path for others, proving that strength, confidence and purpose are unstoppable - and that when women rise boldly, they change the whole world around them.”
In 2025, WXN is introducing a new Board of Directors Award, recognizing standout women who bring transformative vision and leadership to the highest levels of governance. With 11 categories in total, the Top 100 Awards highlight extraordinary contributions of bold women at every stage of their careers across industries:
Canada’s Most Powerful CEOs, presented by Postmedia
• Amex Emerging Leaders
• Entrepreneurs
• CN Executive Leaders
• RBC Future Leaders
• Food Industry Award, presented by Skip
• Professionals
• STEM • CPKC Skilled Trades
• Board of Directors
• WXN Hall of Fame Winners were selected by WXN’s Global Alliance for Inclusive Leadership, a partnership of established and influential corporations committed to helping women rise and lead. Winners span the private, public and not-for-profit sectors.
WXN has celebrated 1,833 women with a Top 100 Award since the program launched in 2012. Past winners include iconic Top 100 winners such as Lisa LaFlamme, award-winning international journalist; Princess Sarah Culberson, Princess of Sierra Leone; The Honourable Rona Ambrose, former leader of Canada’s Official Opposition in the House of Commons; and Dr. Makaziwe Mandela, global activist, head of the House of Mandela and the daughter of Nelson Mandela.
Join WXN in celebrating the extraordinary women shaping Canada’s future. For event details and tickets, visit https://wxnetwork.com/page/Top-100-about.
For media inquiries or to arrange an interview with Sherri Stevens, please contact: Virginia Johnson, Director of Marketing & Communications [email protected].
About WXN
WXN (Women’s Executive Network) is a one-of-a-kind community shaping the future of leadership across North America. We bring together thousands of bold women, allies, and corporate members in a rich and diverse ecosystem of professional development, networking, thought leadership, belonging, and celebration that propels professional women to rise and lead.
Guided by our Owner and CEO, Sherri Stevens, and WXN’s Global Alliance of Inclusive Leadership (GAIL), we lead North America’s most prestigious events for women in business, create professional development programming, and champion thought leadership for professional women. This includes the Canada’s Most Powerful Women: Top 100™ Awards, the GAIL Summit and Awards, the Bold Convos Summit, and programs such as the RAW Courage Coaching Program and the Boldly Forward Leadership Learning Series.
For more information, visit https://wxnetwork.com/.
Follow WXN on social media:
• Instagram: @wxnetwork
• Facebook: @WXNEvents
• LinkedIn: Women’s Executive Network

Building and Running Llama.cpp on an Air-Gapped Mac

If you ever tried to run Llama.cpp on a MacOS device that doesn’t have internet on it, you’ve probably hit the annoying GateKeeper errors that it’s downloaded from the internet and you should delete it. Generally I just build from source to avoid that, but I ran into something interesting that I thought I’d share.

Last night I noticed that llama.cpp’s newly added WebUI feature now includes downloads from huggingface and/or npm when you are running cmake, so if you are trying to build it on a computer that has no net connection, you’ll hit an error:

 UI: failed to download index.html from version: "Could not resolve hostname"
-- UI: downloading assets from latest: https://huggingface.co/buckets/ggml-org/llama-ui/resolve/latest
-- UI: failed to download index.html from latest: "Could not resolve hostname"
CMake Warning at /home/user/llama.cpp-b9181/scripts/ui-download.cmake:209 (message):
  UI: failed to download assets from HF Bucket (llama-ui)

There was a note that if you set LLAMA_BUILD_UI=OFF then it would disable that, and you’d be able to build offline- however, that didn’t work and it kept crashing. There’s a fix in for that, but in the meantime the fix is to set that AND LLAMA_BUILD_WEBUI=OFF.

Steps to Build Llama.cpp from Source on MacOS

NOTE: You have to have cmake installed on your machine for this to work. It’s an installer you can grab and run yourself.

1) Go to the repo, go to releases, go to the latest release (or the one you want), head to the bottom and download the source zip (named Source code (zip) at the bottom).
2) Unzip it somewhere
3) In terminal, navigate into the llama.cpp folder. For example, if you dropped it in your user folder -> llama.cpp-b9196, then you’d do cd ~/llama.cpp-b9196
4) Now you can run this to build it

cmake -B build -DLLAMA_BUILD_UI=OFF -DLLAMA_BUILD_WEBUI=OFF
cmake --build build --config Release

NOTE: There is a PR to fix the need for both. Once it’s merged and tested, just -DLLAMA_BUILD_UI=OFF will work. https://github.com/ggml-org/llama.cpp/pull/23190

NOTE: You can add -j after “Release” to have it use more cores. Be careful with that, though, as it can be pretty performance hungry if you do just -j without a value, as it will just use all cores.

Once it’s done, you will find the executables within the /build/bin folder of that directory, so in our example ~/llama.cpp-b9196/build/bin!

Using the Pre-built Assemblies on MacOS

If you decide to download one of the pre-built assemblies like macOS Apple Silicon (arm64), then you may hit an issue where it complains that the application was downloaded from the internet and only give you the option to stop/delete the file. This is the fault of GateKeeper. You can press cmd + Space, type GateKeeper, and it should open that in settings. You’ll see a spot to tell it to let you run the app anyway; if you select that and then try to re-run the program, it’ll prompt you for the password. Unfortunately, it will do that not only for llama-server, but all the child processes, too… sometimes it can take as many as 7-9 password types.

It’s also possible to strip the com.apple.quarantine xattribute that macOS adds to internet downloaded files that causes Gatekeeper to be annoying. Removing it skips the prompts, so I usually just do that if I can’t build the sourcecode myself. The command that I use is:
xattr -dr com.apple.quarantine ~/replace-with-llama-folder-path.

How I built a 6-CTA landing page generator with Next.js 16 + AI

TL;DR — I built a landing page generator with 6 distinct conversion modes that share one form, one AI prompt, and one backend. The trick wasn’t the AI part. The trick was modeling “conversion intent” as a first-class primitive so a single launch could become a Stripe checkout, a COD form, a calendar booking, or a waitlist — without forking the codebase six ways.

Stack: Next.js 16 App Router, Supabase, Stripe + PayPal, OpenAI, Tailwind, deployed on Vercel.

The problem with “landing page builders”

Every landing page builder I’ve used (Carrd, Framer, Webflow, Unbounce) treats the page like the product. You drag a button onto a canvas, you link it somewhere, you ship.

That works if you’re selling one thing in one way. The moment you have:

  • a SaaS with a “Start Free” trial AND a “Book a Demo” path,
  • a dropshipping store doing Cash on Delivery in some countries and Stripe in others,
  • a salon taking online bookings,
  • a consultant who wants a “Request Quote” form,

…you end up bolting together Calendly + Typeform + Stripe Payment Links + an email tool, glued with Zapier. Every page has a different lookalike, a different analytics surface, and a different broken integration on launch day.

I wanted a single primitive: pick what you’re selling and how someone converts. Generate the page. Ship.

So I built PageStrike, and the architectural decision that made it work was treating conversion mode as a discriminated union, not a UI choice.

The 6-CTA mental model

Every landing page on the internet collapses into one of six conversion shapes:

action_mode What happens on click Real-world use
buy_now Stripe / PayPal checkout E-commerce, digital goods
start_free Redirect to external signup SaaS free trials
collect_emails Form → email list Waitlists, beta signups, lead magnets
cash_on_delivery Form → order with no upfront payment MENA / LATAM e-commerce
request_quote Form → quote inquiry pipeline Agencies, consulting, B2B
book_call Calendar slot → confirmed booking Salons, consulting, legal, transport

That’s the whole product surface. A user picks one. Everything downstream — what fields to ask for, what the public page looks like, what happens on submit, how the dashboard shows results — flows from that single column on the launches table:

CREATE TABLE launches (
  id uuid PRIMARY KEY,
  workspace_id uuid REFERENCES workspaces(id),
  action_mode text NOT NULL CHECK (
    action_mode IN ('buy_now','start_free','collect_emails',
                    'cash_on_delivery','request_quote','book_call')
  ),
  -- … 30+ other columns the AI fills in
);

This single discriminator is what lets the rest of the system stay sane.

Polymorphic page rendering

Every public landing page lives at /p/[slug]. The server component reads the launch, then dispatches to a category-specific React component:

// src/app/p/[slug]/page.tsx (simplified)
const mode = launch?.action_mode || "start_free";

const commonProps = {
  sections: sections ?? [],
  pageId: page.id,
  launchId: page.launch_id,
  workspaceId: page.workspace_id,
  companyName: workspace?.company_name,
  currency: launch?.currency ?? null,
};

if (mode === "collect_emails") {
  return <EmailCaptureLP {...commonProps}
    emailCaptureType={launch?.email_capture_type}
    leadMagnetUrl={launch?.lead_magnet_url} />;
}

if (mode === "request_quote") {
  return <QuoteRequestLP {...commonProps} {...quoteProps} />;
}

if (mode === "book_call") {
  // Sub-routing: salon vs legal vs consulting vs generic
  switch (bookingHost?.booking_category) {
    case "legal":      return <LegalLP {...commonProps} {...legalProps} />;
    case "consulting": return <ConsultingLP {...commonProps} {...consultingProps} />;
    case "salon":      return <SalonLP {...commonProps} {...salonProps} />;
    default:           return <BookCallLP {...commonProps} {...bookCallProps} />;
  }
}

// buy_now, start_free, cash_on_delivery use unified <SectionedLP />
return <SectionedLP {...commonProps} actionMode={mode} />;

Two things to notice:

  1. Common props always go through commonProps. When I added multi-currency support last week, I added currency to that object once. Every LP got it.
  2. book_call has a second-level discriminator (booking_category) because a salon booking and a legal consultation share zero UI assumptions — staff picker vs. credentials list, gallery vs. office photo, allowed-days array vs. weekday range.

The category-specific LPs are not shared components with conditional rendering. They’re separate files. Trying to unify them with a giant if (category === "salon") prop forest is the trap. They share atoms (button, input, calendar), not molecules.

The AI generation pipeline

The “AI” in “AI landing page generator” is the least interesting part technically. It’s a structured-output prompt that returns JSON matching the launches schema.

// src/app/api/ai/generate-launch/route.ts (simplified)
const response = await openai.chat.completions.create({
  model: "gpt-4o-2024-08-06",
  response_format: {
    type: "json_schema",
    json_schema: { name: "launch", schema: LAUNCH_SCHEMA, strict: true },
  },
  messages: [
    { role: "system", content: SYSTEM_PROMPT_FOR_MODE[actionMode] },
    { role: "user",   content: userBrief },
  ],
});

const launch = JSON.parse(response.choices[0].message.content);
await supabase.from("launches").insert({
  workspace_id, action_mode: actionMode, ...launch
});

The interesting part is that each action_mode has its own system prompt because the questions you ask a user are different:

  • For collect_emails, the AI fills email_capture_type, lead_magnet_url, copy that emphasizes scarcity.
  • For cash_on_delivery, it fills product fields, address-collection copy, COD trust signals.
  • For book_call, it generates a host bio, service descriptions, and duration recommendations.

One prompt → one schema → one row. The downstream is deterministic.

Side note for anyone trying this with Kontext Pro for hero image generation: passive prompts like “keep the subject identical, just change the background” will return the source unchanged. You need aggressive transform directives. I lost a day to that.

The multi-currency problem (the part that bit me last week)

A salon in Rabat wants to charge MAD. A consultant in London charges GBP. A SaaS in Berlin charges EUR. PageStrike supports paid bookings — meaning the LP needs a Stripe Checkout or a PayPal order in whatever currency the seller picked.

But Stripe and PayPal don’t support the same set of currencies. Stripe takes ~135, PayPal takes 25. And my app’s picker offers 40. If a seller picks a currency that PayPal doesn’t accept, the PayPal button breaks at runtime.

The fix is a tiny helper that computes the intersection at build time:

// src/lib/currency/payment-providers.ts
import { CURRENCIES } from "@/lib/currency/constants";
import { PAYPAL_SUPPORTED_CURRENCIES } from "@/lib/paypal/currencies";

// Codes Stripe does NOT support among the app's 40. Empty today.
// Kill-switch in case Stripe ever drops one.
const STRIPE_BLOCKED = new Set<string>([]);

/**
 * Returns the set of ISO-4217 codes safe to charge in.
 * Intersection: app menu ∩ PayPal ∩ (Stripe  blocked).
 */
export function getPayableCurrencies(): Set<string> {
  const out = new Set<string>();
  for (const c of CURRENCIES) {
    if (PAYPAL_SUPPORTED_CURRENCIES.has(c.code) && !STRIPE_BLOCKED.has(c.code)) {
      out.add(c.code);
    }
  }
  return out;
}

export function isPayableCurrency(code: string | null | undefined): boolean {
  if (!code) return false;
  return getPayableCurrencies().has(code.toUpperCase());
}

Then in the launch wizard, this snaps the currency to USD if the seller adds a paid service while sitting on a non-payable code:

const payableCurrencies = useMemo(() => getPayableCurrencies(), []);

useEffect(() => {
  const hasAnyPaid = services.some(
    s => typeof s.price_cents === "number" && s.price_cents > 0
  );
  if (!hasAnyPaid) return;
  if (!payableCurrencies.has(currency)) setCurrency("USD" as CurrencyCode);
}, [services, currency, payableCurrencies]);

Two lessons here that I’d put in a “things I should have done day 1” file:

  1. Never trust a third-party SDK’s “supported currencies” list to match yours. Compute the intersection in code, with the SDK’s own list imported as a Set. The day Stripe drops a currency, you change one constant.
  2. Validate at the form level, not at the API. By the time the user has clicked Save, picked an unsupported currency, and seen a generic 400, you’ve burned trust.

Stack summary

Layer Choice Why
Framework Next.js 16 App Router Server Components + async params + route handlers in one tree
DB Supabase (Postgres + RLS) Free auth, row-level security, JSONB for flexible launch shapes
Payments Stripe + PayPal Different geos need different providers — both, not one
AI OpenAI gpt-4o (structured outputs) The json_schema mode is what makes one-shot generation reliable
Hosting Vercel Edge cache for public LPs, Fluid Compute for the API
Bundler Turbopack Next 16 default; HMR is night-and-day vs. Webpack on this size

What I’d do differently if I started over

One. Model action_mode as a discriminated union in TypeScript from day one, not a text column with magic strings. I retrofitted this. It hurt.

Two. Treat each conversion mode’s lifecycle as its own table. I started with one engagements table and a kind column. It became a polymorphic mess (an order has tracking_number, a quote has quote_amount, a subscription has email_capture_type). Splitting it into orders, quotes, subscriptions, bookings with category-appropriate status enums is the cleanup I’m doing right now.

Three. Write the dashboard before the public LPs. The dashboard is where you spend hours; the LP is where the visitor spends seconds. I wrote them in the wrong order and the dashboard now has technical debt the LPs don’t.

Try it

PageStrike is live at pagestrike.com — free plan, AI-generated landing pages with all 6 CTAs, Stripe + PayPal payments, calendar bookings, multi-currency. Built for indie hackers and small teams who don’t want to glue 5 tools together.

If you’ve built something similar and made different architectural calls, I’d genuinely love to hear them in the comments — particularly around the polymorphic-LP vs. unified-renderer trade-off. I went one way; the other has merits.

This is the first post in what I’m planning as a build-in-public series. Next up: the booking calendar timezone problem and why I almost gave up on it.

On minimalism

When I first moved to the Seattle area, my mom told me to buy a queen mattress, a sofa couch, a dining table, basically all the essentials for a “proper” home. I listened, of course. Soon, my once-empty studio filled with furniture, decor, and more.

Now, as I think back on all the memories made outside my apartment through travels, experiences, and simply living life, I realize I didn’t need most of those things. They didn’t really contribute to my happiness.

As my lease ends and I prepare to move, I’ve been reflecting on how this principle extends beyond furniture. The physical baggage I’ve accumulated mirrors the mental and emotional baggage we sometimes carry. Much of it isn’t truly needed or useful.

There’s real value in lightness, the freedom to move through life with agility, without attachment to places or possessions. There’s beauty in that kind of freedom.

As I downsize and focus only on what’s truly essential, I’m practicing gratitude for what I have while gaining clarity about what I genuinely value. It’s about understanding the trade-offs I’m willing to make to create space for what pushes me forward.

The extra stuff is just icing on the cake. By choosing to live well within my means, I’m able to direct more energy and invest more deeply, both physically and figuratively, into the things that matter most.

AI Test Automation Architecture: The 3-Layer System

AI test automation architecture is the system that tells AI what to test.

It also defines how to run tests and prove the result.

I split it into three layers: orchestration, execution, and evidence.

Without all three, AI testing becomes prompt output with no production gate.

Why tool lists fail

Most AI testing content starts with tools.

That is backwards.

AI means software that predicts.

Predictions can help QA teams move faster.

But predictions do not prove quality.

The 3-layer model

Layer Plain meaning Main question
Orchestration test control plan What risk should this cover?
Execution actual test run Did it run in the real pipeline?
Evidence proof from runs Can a human review it?

The practical gate

Use this before AI-generated tests ship:

Gate Pass condition
Scope The test maps to one named risk
Data Test data setup is explicit
State Browser state is controlled
Run The test passes in CI
Evidence Trace or equivalent proof exists
Review A human can explain the failure mode

CI means automated build server.

MCP means tool connection standard.

Playwright is a browser test tool.

Together, they can help AI agents run useful tests.

But the architecture must prove each run.

The rule

Never ask AI to expand test coverage first.

Build the proof system before that.

Generation is cheap.

Evidence is the architecture.

Read the canonical version:

https://www.anton.qa/blog/posts/ai-test-automation-architecture-3-layer-system

Anton Gulin is the AI QA Architect — the first person to claim this title on LinkedIn. He builds AI-powered test automation systems where AI agents and human engineers collaborate on quality. Former Apple SDET (Apple.com / Apple Card pre-release testing). Find him at anton.qa or on LinkedIn.