Expo app : RedirectTo field with Supabase Auth always set to localhost

You are building an Expo Mobile app with Supabase as a backend?

You have correctly set the redirect url to exp:///auth/callback** in the URL Configuration of Supabase Auth and want to try your flow on Expo Go?

If you keep seeing localhost as the redirectTo address in the reset password link set by email, here is the fix:

npx expo start --tunnel

I shipped v7. Nobody showed up. Here’s my honest breakdown.

I shipped FireChat v7 last week.

Real AES-256-GCM encryption. Messages that disappear when everyone leaves. View-once media that actually deletes from storage. Push notifications that work across devices. Song sharing. A PWA that installs on your phone. Seven rewrites worth of lessons baked in.

And still. Nobody showed up.

7 views in 7 days.

That’s not low traction. That’s digital silence.

So I stopped blaming “marketing”

Nobody owes me users. Not because I built something. Not because I spent six months on it. Not because I think it’s genuinely good.

People only care about one thing — why should I use this instead of everything else?

And honestly? I never answered that loudly enough.

FireChat exists because my friend’s sister kept reading our WhatsApp chats. I wanted a place where conversations are locked behind a passphrase, encrypted on your device, and gone the moment everyone leaves. No history. No logs. Nothing to scroll through on someone else’s unlocked phone.

That’s a real reason. I just never led with it.

What FireChat actually is

  • Sessions are ephemeral — everything disappears when the last person leaves
  • Messages are AES-256-GCM encrypted client-side before touching any server
  • Sessions lock behind an identifier passphrase — even if someone gets the invite link, they’re not getting in without the key
  • View-once images and videos — tap to view once, then it’s gone
  • Push notifications when you get invited, even with the app closed
  • Installable PWA — lives on your home screen like a native app
  • Every user gets a public profile page with their vibe and their song

This isn’t a weekend clone. This is six months of real decisions about encryption, ephemerality, and what it means to build something that actually respects the people using it.

My brutally honest guesses for why nobody’s here

  • Zero distribution. I have no audience. I built and shipped into the void.
  • It looks like “just another chat app” from the outside. The differentiation isn’t visible until you’re inside.
  • The people who need it most don’t know it exists.
  • I’ve been building. I haven’t been telling the story.

What I’m actually asking

Try it. Break it. Tell me why you wouldn’t use it. Tell me what would make you actually open it over WhatsApp or Discord or Signal.

No “nice project bro.” Real feedback only.

fyrechatz.vercel.app

Building is the easy part. Getting people to care is the whole game. And I’m just figuring that out.

Automating Your Studio: The Dynamic Student Profile

You know the feeling. The lesson ends, the student leaves, and you’re left staring at a blank page, trying to recall every detail to write meaningful notes and a custom practice plan. It’s time-consuming and mentally draining. The solution lies not in working harder, but in leveraging AI to build a Dynamic Student Profile.

The Core Principle: Structured Data In, Intelligent Insight Out

The magic isn’t in asking AI to invent something new each week. It’s in providing it with a consistent, structured framework of your professional observations. By feeding AI standardized data—like your specific “Challenge Codes” (#rhythm, #intonation) and “Practice Quality Descriptors”—it can transform raw notes into actionable insights and predictive tracking.

Think of your chosen digital hub (like Notion or Airtable) as the central brain. Here, you store each student’s “Assigned Practice,” “Skills Focus” from your Skills Tree, and “Repertoire Status.” The AI uses this historical data combined with your latest lesson notes to generate a coherent “Post-Lesson Summary” and a tailored “Primary Focus for Practice.”

See It in Action

After a violin lesson, you input notes mentioning “#intonation” in a specific exercise and “Lyrical Phrasing Emerging” in a piece. The AI references the student’s profile, recognizes a recurring intonation challenge, and automatically suggests targeted exercises for the next practice plan while highlighting the positive phrasing development.

Three Steps to Implement

  1. Select and Structure Your Hub. Choose a flexible tool like Notion to act as your central database. Build your template there, incorporating your standardized observation language and data points.
  2. Configure Your Dashboard. Create a “Week Ahead” view that surfaces key data: “Students Needing Attention,” those approaching milestones, and “Group Trends” across your studio.
  3. Iterate on the Output. Review the AI-generated notes and plans. Refine your template and inputs to ensure the outputs are accurate and increasingly valuable, automating both milestone tracking and pattern identification.

By implementing a Dynamic Student Profile, you shift from manual note-taking to automated insight generation. You gain a system that tracks progress, predicts plateaus, and personalizes practice—freeing you to focus on the art of teaching itself.

I Automated My Upwork Proposals With AI — Here’s the Template (Free)

I got tired of writing Upwork proposals from scratch every time. So I built a template system.

5 templates. Each one optimized for a specific type of AI consulting job. Copy the template, fill in the brackets, submit.

The Problem

Writing proposals takes 15-30 minutes each. Most get ignored. The ones that get responses have a pattern — they’re specific, they show relevant experience, and they’re short.

So I reverse-engineered what works and made templates.

The 5 Templates

1. MCP / AI Security Audit

For jobs mentioning: security, OWASP, MCP, compliance, vulnerability assessment.

Key hook: “I’ve built 17 production MCP servers and published a security checklist based on OWASP Agentic AI Top 10.”

2. Multi-Agent / AI Architecture

For jobs mentioning: AI agents, orchestration, distributed systems, multi-agent.

Key hook: “My production platform runs 9 coordinated services across 14 cloud providers.”

3. Claude / Anthropic Integration

For jobs mentioning: Claude, Anthropic, prompt engineering, Claude Code.

Key hook: “250+ skills, 35 agents, 17 MCP integrations in production.”

4. RAG / Knowledge Graph

For jobs mentioning: RAG, retrieval, vector search, embeddings, knowledge graph.

Key hook: “Production A-RAG system with 5,600+ entities, BM25 + semantic + causal search.”

5. General AI/LLM

For everything else: chatbots, automation, GPT integration.

Key hook: “9 coordinated AI services running 24/7 with 14 cloud providers.”

The Scoring System

Each template includes a scoring guide — match keywords from the job description to pick the right template:

Job keywords Template
security, audit, OWASP #1
agent, orchestration #2
Claude, Anthropic #3
RAG, knowledge graph #4
AI, LLM, chatbot #5

Why This Works

  1. Specificity — Each template includes concrete numbers (9 services, 14 providers, 5,600+ entities) instead of generic claims
  2. Brevity — All templates are under 150 words
  3. Social proof — Links to portfolio, GitHub, published research
  4. Call to action — Ends with availability and rate, not a question

Get the Templates

The full template pack (all 5 templates + scoring guide + customization tips) is available for free.

If it saves you time, consider supporting the project — I’m building an open-source distributed AGI platform with 9 coordinated services.

My Setup

I built these templates as part of a larger system — a distributed AGI platform that runs 9 coordinated AI services. The same system that generates these proposals also:

  • Benchmarks itself every 30 minutes
  • Identifies its own weaknesses
  • Generates improvement hypotheses
  • Runs experiments to test them

You can see it live at yedanyagami.cc, including real-time fleet status.

If you’re a freelance AI developer, these templates will save you hours. Copy them, customize them, iterate on what works.

And if you want to see how the system behind them works — check out the interactive terminal on my site. Type services to see what’s running.

Directus Auth out of the Box — Registration, Login, Email Verification and Password Reset

One of the things I appreciate most about Directus is that authentication is built in. Registration, login, email verification, and password reset — all handled without reaching for a third party auth service like Auth0 or Clerk.

Here’s how I implement the full auth flow in a TanStack Start app using the Directus SDK.

User Registration

The SDK’s registerUser function handles registration. You pass the email, password and any additional fields. The verification_url tells Directus where to redirect the user after they click the link in their email — Directus appends the token to that URL automatically.

export async function registerUser(
  email: string,
  password: string,
  firstName: string,
  lastName: string,
) {
  const options = {
    first_name: firstName,
    last_name: lastName,
    verification_url: `${import.meta.env.VITE_TANSTACK_URL}/auth/verify-email`,
  };
  return await directus.request(
    registerUserDirectus(email, password, options),
  );
}

Directus sends the verification email automatically via your configured SMTP provider. I use Resend — SMTP is configured directly in the Docker Compose file via environment variables and the whole setup takes just a few minutes.

EMAIL_TRANSPORT: smtp
EMAIL_SMTP_HOST: smtp.resend.com
EMAIL_SMTP_PORT: 465
EMAIL_SMTP_USER: resend
EMAIL_SMTP_PASSWORD: your_resend_api_key
EMAIL_FROM: [email protected]

Login

Logging in is a single call on the Directus client. Session cookies are handled automatically thanks to the credentials: 'include' config set up on the client.

export async function loginUser(email: string, password: string) {
  return await directus.login({ email, password });
}

Clean, no token management, no localStorage juggling. The session is maintained via cookie.

Email Verification

When the user clicks the link in their verification email, they land on your /auth/verify-email route with a token in the query string. You take that token and hit Directus’s verify endpoint directly.

function VerifyEmailComponent() {
  const { token } = Route.useSearch();
  const [status, setStatus] = useState<
    'verifying' | 'success' | 'error' | 'pending'
  >('pending');

  useEffect(() => {
    if (!token) return;

    async function verify() {
      setStatus('verifying');
      try {
        const response = await fetch(
          `${import.meta.env.VITE_DIRECTUS_URL}/users/register/verify-email?token=${token}`,
          { method: 'GET' },
        );
        if (response.ok) {
          setStatus('success');
        } else {
          setStatus('error');
        }
      } catch (err) {
        setStatus('error');
      }
    }
    verify();
  }, [token]);
}

The status state drives your UI — show a spinner while verifying, a success message on completion, or an error state if the token is invalid or expired.

Password Reset

The password reset flow works the same way — Directus emails the user a reset link with a token, they land on your reset page, and you POST the new password along with the token to Directus’s reset endpoint.

const handleSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
  if (password !== confirm) {
    setError('Passwords do not match.');
    return;
  }
  setLoading(true);
  setError(null);

  try {
    const response = await fetch(
      `${import.meta.env.VITE_DIRECTUS_URL}/auth/password/reset`,
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token, password }),
      },
    );

    if (response.ok || response.status === 204) {
      navigate({ to: '/auth/login' });
    } else {
      setError('Failed to reset password. The link may have expired.');
    }
  } catch {
    setError('Something went wrong. Please try again.');
  } finally {
    setLoading(false);
  }
};

A 204 response means success — redirect the user to login. Handle expired tokens gracefully with a clear error message.

What Directus Handles For You

  • ✅ Sending the verification email — via your SMTP provider configured in Docker Compose
  • ✅ Generating and validating tokens
  • ✅ Sending the password reset email
  • ✅ Session management via cookies
  • ✅ Secure password storage

All you need is your SMTP credentials added to your Docker Compose file. I use Resend for email delivery — it’s straightforward to set up and works reliably. Everything else is handled by Directus out of the box.

This is the auth setup I use across all my TanStack Start projects. Combined with Directus roles and permissions, it covers everything a production app needs without adding a separate auth service to your stack.

Have questions about the setup? Drop a comment below.

Help pls

I am actually very confused.

So I got AI to code in a POST request to /api ,so front-end is supposedly done. It tells me to do this:
Create a Vercel Serverless Function
In your repo, add a new file:

/api/x.js
This is where you call OpenAI. Your client will call /api/x.

I have no idea how to do this. Where do I click in Vercel for this…

But I have added the environmental variable of the API key.

So how do I do the serverless function?

Why I Switched to a VPS with Coolify for Hosting My Full Stack Apps

There are plenty of great hosting options out there — Netlify, Vercel, Railway and more. I’ve tried a few of them and they all have their place. But after going through a few different setups, I landed on a VPS managed with Coolify and it’s been the best experience for my workflow.

Here’s how I got there.

Where I Started

I started with Netlify. It’s beginner friendly, deployment is simple and it works well for frontend projects. I then tried Vercel and that was also a solid experience — great DX, fast deploys, good defaults.

Both are genuinely good platforms. But as my projects grew more complex — running a frontend, a Directus instance, a database — the platform costs and constraints started to feel limiting.

The Raw VPS Experiment

I decided to try self-hosting on an Ubuntu VPS with Nginx as my web server and reverse proxy. Manually configuring everything — SSL, domains, process management, deployments. It was a solid learning experience and I’d recommend it to anyone who wants to understand how hosting actually works under the hood.

But it wasn’t the ideal long-term setup. Too much manual work, too much that could go wrong quietly.

Discovering Coolify

Coolify changed things. It’s a self-hosted platform that sits on top of your VPS and gives you:

  • Automatic deployments — push code and your frontend deploys automatically via Git integration
  • Docker Compose support — I manage my Directus instance and PostgreSQL database through Coolify using Docker Compose, which keeps everything clean and reproducible
  • Reverse proxy handled for you — no more manually writing Nginx configs
  • SSL out of the box — certificates are handled automatically
  • No hidden fees — you pay for the VPS, that’s it. Coolify itself is free to self-host

Full Control, Your Way

With a VPS you decide how it’s configured. You’re not subject to platform pricing changes, compute limits, or vendor lock-in. Everything runs on infrastructure you control.

The tradeoff is responsibility — you manage the server, handle updates, and own any issues that come up. It’s not the right fit for everyone.

Is It Worth It?

If you’re comfortable with a bit of server management and want a flexible, cost-effective setup for running full stack apps, a VPS with Coolify is hard to beat. It’s the sweet spot between the ease of a managed platform and the control of raw infrastructure.

For my stack — TanStack Start on the frontend, Directus as the backend, PostgreSQL as the database — it handles everything cleanly in one place.

Have questions about the setup or want to know if it’s a good fit for your project? Drop a comment below.

Why I Use Directus as My Backend — Flexible, Self-Hosted and Production Ready

If you’re looking for a backend that’s flexible, affordable and genuinely enjoyable to work with, Directus is worth a serious look.

Here’s why it’s become my default choice for full stack projects.

Free to Self-Host (With a Sensible Threshold)

Directus uses a BSL 1.1 license. If your organization has less than $5M in total annual income — revenue and funding combined — you can self-host it for free across all your projects, including production and commercial ones. No feature paywalls, no artificial limits.

Once you’re past that threshold, a commercial license is required. But for the vast majority of indie developers, freelancers, startups and small teams, it’s completely free.

Works with Any SQL Database

Directus sits on top of your existing database rather than replacing it. It supports PostgreSQL, MySQL, SQLite, MariaDB and more. My preference is PostgreSQL — pair them together and you get a rock solid data layer with Directus handling the API, auth, and admin UI on top.

Flexible Data Structures

Whether you’re building a simple blog, an e-commerce store, or a complex multi-tenant app, Directus adapts to your data model. You define your collections and fields, and Directus generates a full REST and GraphQL API automatically. No rigid schema to fight against.

Built-In Features That Scale With You

Starting small? Directus is simple enough to get up and running fast. Ready to grow? It has you covered:

  • Authentication — built in, with session and token support
  • Roles and Permissions — granular access control per collection and field
  • Automation — flows and webhooks for backend logic without extra services
  • Dashboard — a full admin UI out of the box for managing your data
  • File Management — upload, transform and serve assets directly

Actively Maintained

Directus is backed by a strong team of developers and an active open source community. It’s regularly updated, well documented, and not going anywhere. That matters when you’re building something you plan to maintain long term.

Who It’s For

  • Startups — get a full backend running quickly without over-engineering
  • Freelancers — one backend you can reuse across different client projects
  • Growing products — the feature set scales as your requirements do
  • Developers who want control — self-host it, own your data, no vendor lock-in

I use Directus with TanStack Start on the frontend and the Directus SDK for all data fetching. If you’re exploring it for your next project and want to see how the integration works in practice, I’ve covered the SDK setup and data fetching patterns in previous posts on my profile.

Have a project in mind and want to know if Directus is the right fit? Drop a comment and I’m happy to help.

Twilio API Autopsy: What Agent-Native Almost Looks Like

Twilio is the communications API that set the standard for developer DX. At 8.0/10 AN Score (L4 Established), it’s one of the highest-scoring services in Rhumb’s dataset. This autopsy examines what Twilio gets right for agents — and the friction points that keep it from a perfect score.

Canonical post: rhumb.dev/blog/twilio-api-autopsy

Score at a glance

Dimension Score
AN Score 8.0 / 10 (L4)
Execution 8.4
Access Readiness 7.3
Confidence 63%

Agent decision: Use Twilio as the default choice for agent-driven SMS, voice, and WhatsApp messaging. Authentication is trivial (SID + token), most operations are idempotent-safe, and error messages are specific enough for self-correction. Budget for carrier-level rate limiting, A2P 10DLC registration latency (1–7 days for US numbers), and per-destination pricing variability. This is one of the easiest high-value APIs for an agent to integrate.

What makes Twilio agent-friendly

🔑 Authentication agents actually understand

Account SID + Auth Token. Basic HTTP auth. No OAuth dance, no token refresh, no redirect URIs. An agent receives two strings and can immediately make API calls.

Better: agents can provision their own scoped API keys via the API — no human bottleneck required. This is the gold standard for agent authentication: simple, stateless, and self-provisionable.

♻️ Idempotency keys on messages

Twilio accepts an idempotency key header on message creation. If a request times out and the agent retries with the same key, Twilio returns the original response without sending a duplicate message. Combined with status callback webhooks, agents can implement a reliable message delivery pipeline with exactly-once semantics.

📡 Webhook architecture is agent-ready

Every message and call can have a StatusCallback URL that receives real-time updates. Webhooks are signed with your Auth Token, failed deliveries are retried with exponential backoff for up to 48 hours, and the webhook body includes structured data — not just an event ID that requires a follow-up API call.

📋 Error codes that teach

When an API call fails, Twilio returns:

  • status (HTTP code)
  • code (Twilio-specific numeric error code)
  • message (human-readable explanation)
  • more_info (documentation URL for the specific error)

Error code 21211 (“The To phone number is not a valid phone number”) links to a page explaining valid formats, common mistakes, and how to fix them. Most agents can self-correct without even following the link — the code + message is specific enough.

Where Twilio falls short for agents

📱 Phone number verification wall

Before sending messages to US numbers, agents must complete A2P 10DLC campaign registration — a carrier-reviewed process that takes 1–7 business days. An agent can initiate this via the API but cannot complete it autonomously. First-message latency is a real constraint.

💰 Per-message pricing complexity

Pricing varies by destination country (200+), originating number type, message type (SMS vs MMS), carrier surcharges, and message segment count. There is no single price — the agent must either call the Twilio Pricing API per destination or maintain a lookup table that needs quarterly updates due to carrier surcharge changes.

Same ‘Happy Birthday!’ → US number: ~$0.0079. UK number: ~$0.0420. This makes budget enforcement genuinely difficult.

⏱ Rate limits are carrier-imposed, not API-imposed

The Twilio API handles high request volumes — you can queue thousands of messages in seconds. But carrier networks impose their own limits:

  • US long code: 1 SMS/second per number
  • Toll-free: 3/second
  • Short codes: 100+/second

The API doesn’t surface carrier limits in headers. Agents must implement sending rate controls based on phone number type and manage silently filtered messages.

What would close the gap to 9.0+

  1. Carrier-level rate limit headers — surface effective sending rate per number type in response headers
  2. Cost estimation endpoint — batch pricing before sending, not per-country lookups
  3. Automated A2P 10DLC pre-registration — agent-submittable campaigns with webhook approval status
  4. Idempotency on all endpoints — currently only messages; needs coverage on phone number purchases, subaccount creation, configuration updates

Real integration cost for agents

Factor Twilio
Setup time 5 minutes (copy SID + token)
Regulatory latency 1–7 days (US A2P 10DLC)
Adapter complexity 1 client, consistent patterns
Defensive code ~15% of integration

Compare: HubSpot requires 2–4 hours of human setup and ~40% defensive code. Salesforce: 1–4 weeks and ~50% defensive code. Twilio is in a different class.

Lessons for API designers

Simple auth wins. Basic HTTP auth is the fastest path to agent integration. OAuth adds weeks of human setup.

Error messages are documentation. Twilio’s error codes with explanation + documentation URL mean agents can self-correct. A generic ‘400 Bad Request’ teaches nothing.

Make credentials self-provisionable. Let agents create their own API keys via the API. This eliminates the human bottleneck that plagues enterprise APIs.

Idempotency on write operations. If an agent can safely retry any write, integration complexity drops dramatically.

AN Scores are computed from documentation review, API structure analysis, authentication flow assessment, and runtime probing where available. Methodology at rhumb.dev/blog/self-score. Live scores at rhumb.dev.

🚨 CrashLoopBackOff no Kubernetes: o que é e por que acontece?

Quem trabalha com Kubernetes cedo ou tarde encontra esse status no terminal:

CrashLoopBackOff

Ele aparece quando um container dentro do Pod falha repetidamente e o Kubernetes passa a reiniciá-lo com um tempo de espera progressivo entre as tentativas. Esse status é mostrado pelo kubectl para indicar exatamente esse ciclo de falha + reinício + espera.

🔁 Como funciona na prática

Quando a aplicação quebra, o Kubernetes não reinicia o container infinitamente sem pausa.

Ele aplica um backoff exponencial, com atrasos como:

10s → 20s → 40s → 80s…

Esse tempo cresce até um limite máximo de 5 minutos entre as tentativas de reinício. Se a aplicação continuar falhando, o Kubernetes continua tentando, mas respeitando esse teto.

🛡️ Qual é a finalidade do CrashLoopBackOff?

A ideia não é “travar” o Pod por acaso. O objetivo é:

evitar reinícios inúteis sem parar
reduzir consumo desnecessário de recursos no node e no cluster
dar tempo para diagnóstico
deixar claro que a aplicação está falhando repetidamente

Ou seja: o CrashLoopBackOff é uma forma de proteger a infraestrutura e, ao mesmo tempo, evidenciar que algo está errado na aplicação.

⏱️ E os 10 minutos?

Existe um ponto importante aqui: se o container conseguir ficar 10 minutos rodando sem falhar, o Kubernetes zera o contador do backoff. Então, se ele voltar a quebrar depois disso, a próxima espera volta a começar do início, em vez de continuar num intervalo alto.

⚙️ O papel do restartPolicy

O comportamento também depende da política de reinício do Pod:

Always: sempre tenta reiniciar
OnFailure: reinicia apenas se houver erro
Never: não reinicia automaticamente

O valor padrão em Pods é Always.

✅ E quando o Pod termina com sucesso?

Isso também pode gerar reinício, dependendo da política usada.

Se um container termina com sucesso, mas o Pod está com restartPolicy: Always, ele pode ser iniciado novamente. Só que esse não costuma ser o modelo ideal para tarefas que têm começo, meio e fim.

🧩 Quando usar Job em vez de Pod?

Para tarefas que executam e terminam, o recurso mais adequado normalmente é um Job.

O Job existe justamente para workloads finitas e aceita apenas restartPolicy: Never ou OnFailure no template do Pod. Quando a tarefa termina com sucesso, o Job considera a execução concluída.

🎯 Resumindo

O CrashLoopBackOff não é só um erro visual no terminal.
Ele é um mecanismo do Kubernetes para:

desacelerar reinícios de uma aplicação quebrada
evitar desperdício de recursos
facilitar diagnóstico
proteger o node e o cluster

Em resumo: se o Pod falha repetidamente, o Kubernetes não reinicia “na marra” para sempre ele controla esse comportamento de forma inteligente.