The Most Important AI Skill Isn’t Technical

The Most Important AI Skill Isn’t Technical

Since the dawn of coding there have been 10X developers, who accomplish much more than their peers. There are also 10X AI collaborators…and coding skills are not the unlock. Here’s what’s needed for AI whispering at the highest levels.

You wouldn’t walk into your CEO’s office and say “fix the company.” You’d get a blank stare, a polite suggestion to come back with specifics, and a reputation for wasting executive time. There’s a reason “pls fix” is a dismissive punchline.

And yet: this is exactly how most people talk to AI.

“Write me a marketing plan.” “Design a dashboard.” “Help me with my strategy.” Then they’re surprised when they get back something generic, surface-level, and vaguely useless. They blame the tool. They say AI is overhyped. They move on.

Meanwhile, the person in the next office is using the same tool to produce work that used to take a team of three a full week. The difference isn’t a secret prompt template. It isn’t a computer science degree. It’s the same skill that’s been separating high performers from everyone else for decades: the ability to communicate clearly in writing.

The $1.2 Trillion Clue

Before we talk about AI, let’s talk about humans.

A Grammarly and Harris Poll study found that poor communication costs US businesses $1.2 trillion per year [1]. Not million. Not billion. Trillion. With a T. One hundred percent of knowledge workers surveyed experience miscommunication at least weekly. One in four report it multiple times a day. I have often said that every software development problem I’ve seen in a career that has yielded over 1,000 pieces of software stemmed from communications problems (bad elicitation of requirements, misunderstandings, miscommunications, mis-set expectations, vague feedback…). Every. Single. One.

This isn’t new information. Employers have listed “strong writing skills” near the top of their hiring criteria for as long as we’ve been tracking it: NACE Job Outlook surveys across multiple years have found that 73-82% of employers rank written communication as a must-have competency [2]. A Grammarly study of 100 LinkedIn profiles found that professionals with fewer language errors tend to reach higher positions 3. Writing quality serves as a career-long signal of competence.

The principle is simple: clear communicators get better outcomes from other humans. They waste less time. They create fewer misunderstandings. They compound advantage over years because every interaction is marginally more efficient.

This is the same principle that now governs AI productivity. And the mechanism behind it is almost embarrassingly obvious.

The Obvious Thing Nobody Talks About

Large language models generate human-like text because they were trained on human text. Billions of documents. Trillions of tokens. The entire written output of the internet, plus books, plus academic papers, plus technical documentation. Every pattern of clear, structured, purposeful writing that humans have ever produced: the model has seen it, absorbed it, and learned to continue it.

This means the conventions that make writing effective for humans are exactly the patterns these systems were trained to recognize and respond to. Specificity. Defined audience. Logical structure. Concrete examples. Clear scope. When you write a well-structured prompt, you’re speaking in a register the model has encountered millions of times and learned to match. When you write vaguely, you’re asking it to interpolate between low-information patterns. It does so unpredictably.

A PNAS study on how LLMs write found that instruction-tuned models default to a noun-heavy, informationally dense style [4]. They struggle to deviate from it even when asked. The model’s natural output reflects the dominant patterns in its training data: structured, clear communication. Users who prompt in kind get outputs that align. Users who don’t get outputs that drift.

When someone says “the AI doesn’t understand me,” the more precise diagnosis is often that their input didn’t match the communication patterns the model was trained to process effectively. The AI isn’t failing to understand. It’s accurately reflecting the ambiguity of what it received.

This is a mirror, not a mystery.

MIT Sloan Proved It With Data

In case the theory doesn’t convince you, here’s the empirical evidence.

MIT Sloan ran a large-scale experiment [5] and found something remarkable: only half the performance gains from switching to a more advanced AI model came from the model itself. The other half came from how users adapted their prompts. The researchers noted that the best prompters weren’t software engineers. They were people who knew how to express ideas clearly in everyday language.

Read that again. Non-engineers who could write clearly outperformed engineers who couldn’t. The tool was the same. The model was the same. The difference was communication skill.

Grammarly’s 2025 data tells a similar story from a different angle [6]: AI-literate workers (those who communicate effectively with AI tools) save 8.9 hours per week, compared to 6.3 hours for workers who are merely familiar with the technology. That’s a 41% productivity gap, and the primary variable is how well people articulate what they need.

HBR published a piece titled “Using Prompt Engineering to Better Communicate with People” [7], making the explicit argument that the skills flow in both directions. Get better at communicating with AI, and you get better at communicating with humans. Get better at communicating with humans, and you get better at communicating with AI. They’re the same muscle.

The Vagaries: When Communication Fails, AI Fails Worse

Unfortunately, AI doesn’t fail gracefully, so you can’t skip the fundamentals. When a human colleague receives vague instructions, they push back. They ask clarifying questions. They use organizational context and shared history to fill gaps. AI does none of this. It takes your ambiguity and runs with it, confidently, in whatever direction the statistical patterns suggest.

The failure modes are predictable and painful:

  • Vague instructions produce generic output. “Write a marketing strategy” gets you a Business 101 textbook summary. “Write a go-to-market strategy for a B2B SaaS analytics tool targeting mid-market CFOs, focusing on competitive displacement of spreadsheet-based forecasting” gets you something you can actually use.

  • Hidden assumptions produce mismatched tone and depth. You assumed the AI knew you wanted an executive summary. It assumed you wanted a comprehensive analysis. Neither of you said so. Now you have 3,000 words when you needed 300.

  • Missing context produces confident hallucinations. The model doesn’t know what it doesn’t know. Without sufficient context, it fills gaps with plausible-sounding fabrications. It’s not lying. It’s pattern-matching against insufficient data. (Every manager who’s delegated poorly to a new hire has seen the human version of this.)

  • Contradictory goals produce inconsistent output. “Make it shorter but more comprehensive.” “Be creative but stay on brand.” “Move fast but don’t break anything.” Humans learn to decode these contradictions through experience. AI takes them literally and produces work that oscillates between opposing objectives.

Nielsen Norman Group studied AI-generated UI design [8] and found the difference is stark. Vague prompts produce designs that look randomly assembled: generic layouts with no coherent information hierarchy. Detailed prompts that specify the user role, key metrics, and layout philosophy produce professional, usable work. Same tool. Same model. Different communication.

The old software engineering principle applies perfectly: garbage in, garbage out. The garbage just looks more polished now, which makes it harder to catch and more expensive when it slips through.

The Copywriter’s Playbook Was the Prompt Engineering Manual All Along

(Note the link at the end of this article to github project with a skill.md file that can apply these and a few other principles to your agent files and prompts, to help you get the best results possible!)

Ironically, researchers have spent the last three years discovering, one paper at a time, that virtually every principle in the copywriter’s playbook also improves AI output. The overlap is so complete it’s almost embarrassing.

Be specific, not abstract. Copywriters know “save $47 on your first order” beats “save money.” A 2023 study tested 26 prompting principles across LLaMA and GPT-4 and found an average 57.7% quality improvement on GPT-4 when applying them [9]. The copywriting version of this principle predates the internet. The AI research confirmed it with p-values.

Show, don’t tell. Copywriters use case studies because concrete examples beat abstract claims. Few-shot prompting (providing 2-3 examples of desired output) is the single most studied technique in all of prompt engineering, dating back to GPT-3’s original paper in 2020 [10]. Quality of examples consistently matters more than quantity. One compelling case study beats a list of twenty testimonials. One well-chosen example beats ten mediocre ones.

Break it into steps. Copywriters call it the “slippery slope”: each sentence leads naturally to the next, keeping cognitive load manageable. Researchers call it chain-of-thought prompting. When they added “let’s think step by step” to math problems, accuracy jumped from 18% to 79% [11]. The mechanism is different (the model uses intermediate tokens as working memory), but the prescription is identical: chunk complexity into digestible pieces.

Make the stakes real. Every copywriter knows emotion drives action more than logic. A Microsoft and Chinese Academy of Sciences team tested this directly on LLMs. Adding positive emotional framing (“this is very important to my career” or “take pride in your work and give it your best”) improved performance by up to 115% on BIG-Bench reasoning benchmarks [12]. A follow-up study tested negative emotional framing (“this seems beyond your skill level”) and found it boosted BIG-Bench performance by 46% [13]: less dramatic than positive framing on that benchmark, but the negative approach outperformed positive framing on instruction-following tasks (12.9% vs. 8%). Both of these flavors of emotional prompting increase performance. The models don’t feel urgency. But emotionally-framed requests in their training data were paired with higher-effort human responses. The statistical echo of human motivation is baked into the weights.

One ask per piece. Copywriting’s “Rule of One” (one idea, one audience, one call to action) has a direct analog: multi-task prompts tend to degrade LLM performance compared to single-task prompts, particularly in smaller models [14]. Ask for three things at once and the model weights them unevenly, just like a reader who skims a multi-CTA email and does none of them.

Name your audience. “Written for CFOs at Series B startups” produces entirely different copy than “written for general audiences.” Same for LLMs: specifying the audience measurably shifts vocabulary, depth, and readability. The model isn’t imagining a reader. It’s shifting toward token distributions that co-occurred with that audience type in training data. Different mechanism, same result.

Say what to do, not what to avoid. Copywriters learned long ago that “don’t think about a pink elephant” makes you think about a pink elephant. LLMs have the same problem. Negative instructions (“don’t be verbose,” “avoid jargon”) consistently underperform positive ones (“write concisely,” “use plain language”). Anthropic has formalized this into their official documentation. The suppression instruction activates the very concept you’re trying to suppress.

End with the ask. Direct mail copywriters know the P.S. is the most-read section of a letter because eyes jump to the end. LLMs have a structural equivalent: research shows models perform best when key information appears at the beginning or end of a prompt, with significant degradation for anything buried in the middle [15]. Because LLMs process tokens left to right, the request at the end has full visibility of all the context that came before it. Lead with your background and constraints, close with what you actually want. Burying your actual request in the middle of a long prompt is the AI equivalent of burying the lede.

The pattern is relentless. Every principle that makes human communication more effective also makes AI communication more effective. Not because LLMs think like people, but because people wrote the data that LLMs learned from. Good copywriting created the training signal. The model absorbed its statistical fingerprint. When you write the way a skilled communicator writes, you’re hitting the exact frequency the model was tuned to receive.

It’s Not “Prompt Engineering.” It’s Writing.

The tech industry loves to rebrand familiar skills as novel disciplines. “Prompt engineering” sounds like something you’d need a certification for. In reality, strip away the jargon and you’re looking at a skill set that every good business writing course has taught for decades:

  • Chain-of-thought prompting is asking someone to show their work and think step by step. (Research shows this alone can boost accuracy by 20%.)
  • Few-shot prompting is providing examples of what good output looks like. An editorial brief.
  • Role prompting is specifying the audience and voice. Basic communication context-setting.
  • Structured prompting is organizing your request with clear sections and constraints. An assignment description.

These techniques work because they’re not tricks. They’re the fundamentals of effective written communication, dressed up in new vocabulary.

And the parallels go deeper than metaphor. A December 2025 Google Research paper found that simply repeating a prompt twice (literally copying and pasting it) improved LLM accuracy by up to 76% on non-reasoning tasks [16]. The reason is mechanical: as noted above, LLMs process tokens left to right. A token at position 5 can only “see” tokens 1 through 4. When you repeat the prompt, every token in the first copy gets to attend to every token in the second copy. The model finally has full visibility of the complete request when generating its answer.

Separate research confirmed the corollary [17]: prompt component order matters enormously. Models perform measurably better when context and background appear before the question rather than after. Why? Same mechanism. If the question comes first and context comes second, the question tokens are processed before the model has “seen” the context. They’re informationally blind to it.

THE EXCEPTION THAT PROVES THE RULE: The “End with the ask” principle inverts a classic business writing principle. Journalism and the military teach BLUF: Bottom Line Up Front. State the key point first, then provide supporting context. That works for humans because busy executives scan from the top, likely have necessary context already, and may not finish reading. But LLMs aren’t scanning. They’re fully processing, from left to right, building context as they go. An ask that appears before the context is an ask that was processed blind. For prompts, the optimal structure is context first, ask last: give the model everything it needs to know, then tell it what to do with that knowledge. The ask at the end has full visibility of every token that came before it.

The fact that effective prompt structure diverges from effective executive communication on this one point makes the broader convergence even more striking. Writing structure isn’t just a preference. Inside an LLM, it’s physics.

The people who already practice clear, structured writing don’t need a prompt engineering course. They just need to talk to the AI the way they’d write a good brief, a clear email, or a well-structured requirements document.

The people who never learned to write clearly? They need to learn that first. No prompt template will substitute for the ability to articulate what you actually want.

The Compounding Gap

In an era when AI helps people write better, the people who already write well extract far more value from the tools. They iterate faster. They recognize when output drifts. They course-correct with precision instead of frustration. They build on good outputs instead of starting over from bad ones.

This creates a compounding loop. Good communicators get better AI results. Better AI results accelerate their work. Accelerated work gives them more reps. More reps sharpen their communication further. The gap between clear communicators and vague ones isn’t closing with AI. It’s widening. The best communicators are the 10X AI Collaborators.

The World Economic Forum’s 2025 Future of Jobs Report confirms this trajectory [18]: while basic literacy skills (reading, writing, and mathematics) show a small net decline in projected demand, skills like analytical thinking, creative thinking, and leadership are increasing in importance. The premium on clear, structured communication as a meta-skill that enables all of these is going up, not down.

If you’re a leader: invest in your team’s writing skills. Not their prompt engineering skills, their writing skills. The ability to define a problem precisely, specify an outcome clearly, provide relevant context, and structure a request logically. These pay dividends in every human interaction–and in every AI interaction.

If you’re an individual contributor: the single highest-leverage skill you can develop right now isn’t learning a new framework or memorizing prompt patterns. It’s learning to write with clarity and precision. It will make you better at your job, better at managing people, and better at working with every AI tool that exists or will exist. Communication skills are the key.

The Bottom Line (Not Up Front)

Communication has always been the key to everything. AI didn’t change that. It amplified it. The same skills that make you effective with a boardroom full of executives make you effective with the most powerful AI tools on the planet, because those AI tools learned everything they know from our written communication.

You wouldn’t walk into your CEO’s office and say “fix the company.” Don’t do it to your AI either.

If you’re interested in the free “plsfix” skill (couldn’t help myself), which applies these and other LLM communication principles to your AI prompts, spec files, or administrative files, you can find it at https://github.com/keithmackay/plsfix.

References

  1. Grammarly and Harris Poll: The State of Business Communication (2022)
  2. NACE Job Outlook Surveys: Employer-Desired Competencies
  3. Grammarly: Good Grammar, Good Career (LinkedIn Profile Analysis)
  4. Do LLMs Write Like Humans? Variation in Grammatical and Rhetorical Styles, PNAS (2025)
  5. MIT Sloan: Study Finds Generative AI Results Depend on User Prompts as Much as Models
  6. Grammarly 2025: The Critical Role of AI Literacy Across the Enterprise
  7. Using Prompt Engineering to Better Communicate with People, Harvard Business Review
  8. Nielsen Norman Group: Good from Afar, But Far from Good: AI Prototyping in Real Design Contexts
  9. Principled Instructions Are All You Need for Questioning LLaMA-1/2, GPT-3.5/4
  10. Language Models are Few-Shot Learners (GPT-3)
  11. Large Language Models are Zero-Shot Reasoners (Kojima et al., 2022)
  12. Large Language Models Understand and Can be Enhanced by Emotional Stimuli (EmotionPrompt)
  13. NegativePrompt: Leveraging Psychology for Large Language Models Enhancement via Negative Emotional Stimuli
  14. Degradation of Multi-Task Prompting Across Six NLP Tasks and LLM Families
  15. Lost in the Middle: How Language Models Use Long Contexts (Liu et al., 2023)
  16. Google Research: Repeat Prompting Improves Non-Reasoning LLMs (2025)
  17. Order Matters: Rethinking Prompt Construction in In-Context Learning
  18. World Economic Forum Future of Jobs Report 2025

Optimización Heurística – Funciones de Prueba y TSP de México

Rosenbrock 2D - Descenso por Gradiente

Optimización Heurística — Trabajo 01

Autores: Manuel Alejandro Sánchez Daza · Mario Alberto Cañas Baquero

Curso: Redes Neuronales y Algoritmos Bio-inspirados

Repositorio: github.com/LeMannuelo/RNAB-Trabajo-01

Este trabajo tiene dos partes. En la primera comparamos métodos de optimización numérica sobre funciones matemáticas clásicas. En la segunda resolvemos el Problema del Vendedor Viajero sobre las 32 capitales de México. En ambos casos usamos métodos heurísticos y los contrastamos con enfoques más tradicionales.

Parte 1 — Optimización Numérica

1.1 Introducción

La optimización numérica aparece en casi todo lo que hacemos en machine learning e ingeniería: entrenar una red neuronal, ajustar parámetros de un modelo, minimizar el error de un sistema. El problema siempre es el mismo en esencia: encontrar el punto donde una función alcanza su valor mínimo.

En esta parte comparamos dos enfoques muy distintos. Por un lado el descenso por gradiente, que usa la información matemática de la función para moverse siempre en la dirección que más reduce el valor. Por otro lado los métodos heurísticos — PSO, Evolución Diferencial y Algoritmos Evolutivos — que no necesitan conocer el gradiente y en cambio exploran el espacio de búsqueda con una población de soluciones que evoluciona iterativamente.

Las dos funciones de prueba que escogimos son:

Función de Rosenbrock — famosa por su “valle de banana”: el mínimo global es fácil de encontrar en papel, pero en la práctica los algoritmos tienen que atravesar un valle largo, estrecho y curvado para llegar ahí.

f(x) = Σ [ 100·(xᵢ – xᵢ₋₁²)² + (1 – xᵢ₋₁)² ]

Mínimo global en x* = (1, 1, …, 1), f(x*) = 0.

Función de Griewank — multimodal, con muchos mínimos locales distribuidos por toda la superficie. Cualquier algoritmo sin mecanismos de exploración queda atrapado antes de llegar al mínimo global.

f(x) = (1/4000)·Σᵢxᵢ² – Πᵢ cos(xᵢ/√i) + 1

Mínimo global en x* = (0, 0, …, 0), f(x*) = 0

Ambas se optimizaron en 2D y 3D.

1.2 Metodología

Descenso por gradiente

Parte de una posición inicial aleatoria en $[-5, 5]^d$ y en cada iteración da un paso en dirección opuesta al gradiente:

x_(k+1) = x_k – α · ∇f(x_k)

donde α es la tasa de aprendizaje (learning rate)

Implementamos los gradientes analíticos de ambas funciones. Los parámetros usados:

Función Dimensión Learning rate Máx. iteraciones
Rosenbrock 2D 0.001 50 000
Rosenbrock 3D 0.001 30 000
Griewank 2D 0.01 1 400
Griewank 3D 0.01 1 400

El learning rate de Rosenbrock es más bajo porque su valle estrecho hace que pasos grandes generen oscilaciones. Para Griewank se puede usar un paso mayor porque la superficie es más suave localmente.

PSO — Optimización por Enjambre de Partículas

Inspirado en el comportamiento de bandadas de aves. Cada partícula tiene posición y velocidad; la velocidad combina inercia, atracción hacia el mejor punto personal y atracción hacia el mejor punto global de la población (Eberhart & Kennedy, 1995).

v_(k+1) = w·v_k + c1·r1·(p_i – x_k) + c2·r2·(g – x_k)

donde:
w = inercia
c1 = coeficiente cognitivo (atracción al mejor personal)
c2 = coeficiente social (atracción al mejor global)
r1, r2 = números aleatorios en [0, 1]

Parámetro Rosenbrock Griewank
Partículas 40–50 40–50
Iteraciones 300–500 200
Inercia $w$ 0.7 0.5
$c_1$, $c_2$ 1.5, 1.5 1.5, 1.5

DE — Evolución Diferencial

Cada candidato genera un vector mutante combinando tres individuos aleatorios distintos, y decide si adopta ese vector según quién tenga menor costo (Storn & Price, 1997).

v = x_r1 + F · (x_r2 – x_r3)

donde F es el factor de escala y r1, r2, r3 son índices distintos aleatorios

Parámetro Valor
Población 40
Iteraciones 200–300
Factor de escala $F$ 0.8
Tasa de cruce $cr$ 0.9

EA — Algoritmo Evolutivo

Selección por torneo, cruce intermedio y mutación gaussiana. Los mejores individuos producen descendencia con pequeñas perturbaciones.

Parámetro Valor
Población 60
Iteraciones 200–350
$sigma$ mutación 0.001–0.05 según función
Tamaño torneo 3

Para la comparación estadística se realizaron 10 corridas independientes por algoritmo con semillas distintas.

1.3 Resultados

Descenso por gradiente

Función Dim. $f(mathbf{x})$ final Evaluaciones
Rosenbrock 2D $1.38 times 10^{-18}$ 50 002
Rosenbrock 3D $4.99 times 10^{-14}$ 30 002
Griewank 2D $7.40 times 10^{-3}$ 1 402
Griewank 3D $1.15 times 10^{-2}$ 1 402

En Rosenbrock el gradiente funcionó espectacularmente: precisión de $10^{-18}$ en 2D. En Griewank converge rápido pero a un mínimo local — el valor final es mayor que cero.

Las animaciones lo muestran claramente:

Rosenbrock 2D - Descenso por Gradiente
Figura 1. Descenso por gradiente sobre Rosenbrock 2D. El punto recorre lentamente el valle hasta llegar al mínimo global en (1, 1).

Rosenbrock 3D - Descenso por Gradiente
Figura 2. Trayectoria del gradiente sobre Rosenbrock 3D.

Griewank 2D - Descenso por Gradiente
Figura 3. Descenso por gradiente sobre Griewank 2D. El algoritmo cae al primer mínimo local que encuentra.

Griewank 3D - Descenso por Gradiente
Figura 4. Trayectoria del gradiente sobre Griewank 3D.

Métodos heurísticos

Función Gradiente PSO DE EA
Rosenbrock 2D $1.4 times 10^{-18}$ ✅ ~$10^{-4}$ ~$10^{-6}$ ~$10^{-3}$
Rosenbrock 3D $5.0 times 10^{-14}$ ✅ ~$10^{-2}$ ~$10^{-4}$ ~$10^{-2}$
Griewank 2D $7.4 times 10^{-3}$ ❌ ~$0$ ✅ ~$0$ ✅ ~$10^{-3}$
Griewank 3D $1.2 times 10^{-2}$ ❌ ~$0$ ✅ ~$0$ ✅ ~$10^{-3}$

PSO Rosenbrock 2D
Figura 5. PSO sobre Rosenbrock 2D. Las partículas convergen al valle desde distintas posiciones iniciales.

DE Rosenbrock 2D
Figura 6. Evolución Diferencial sobre Rosenbrock 2D.

EA Rosenbrock 2D
Figura 7. Algoritmo Evolutivo sobre Rosenbrock 2D.

PSO Griewank 2D
Figura 8. PSO sobre Griewank 2D. La población logra escapar de los mínimos locales y converge al origen.

DE Griewank 2D
Figura 9. Evolución Diferencial sobre Griewank 2D.

EA Griewank 2D
Figura 10. Algoritmo Evolutivo sobre Griewank 2D.

1.4 Discusión

El resultado más interesante no es que un método sea “mejor” sino que cada uno tiene fortalezas claras dependiendo del tipo de función.

El gradiente en Rosenbrock logró una precisión de $10^{-18}$, algo que ningún heurístico alcanzó. Cuando la función tiene un solo mínimo y se puede calcular el gradiente exacto, no hay forma más eficiente de llegar al óptimo que seguir directamente esa información matemática. En Griewank ese mismo gradiente se convirtió en su peor enemigo: la primera pendiente descendente lo llevó a un mínimo local y no salió.

Los heurísticos mostraron exactamente lo contrario: en Griewank, PSO y DE encontraron el mínimo global de manera consistente en casi todas las corridas. La razón es que al trabajar con una población distribuida en todo el espacio tienen una visión más amplia del paisaje y pueden escapar de mínimos locales. En Rosenbrock sin embargo ninguno alcanzó la precisión del gradiente, porque el valle estrecho dificulta la exploración poblacional — los saltos no aprovechan la curvatura del valle.

En evaluaciones, el gradiente fue el más costoso en Rosenbrock (hasta 50 000) pero el más barato en Griewank (1 400). Los heurísticos se mantuvieron estables entre 8 000 y 12 000 evaluaciones sin importar la función, lo que los hace más predecibles en costo computacional.

Conclusión práctica: si la función es unimodal y diferenciable, el gradiente es imbatible en precisión. Si es multimodal o no se puede calcular el gradiente, los heurísticos son la opción correcta.

Parte 2 — TSP: 32 Capitales de México

2.1 Introducción

El Problema del Vendedor Viajero (Traveling Salesman Problem, TSP) es uno de los problemas de optimización combinatoria más estudiados en la literatura. Su formulación es simple: dado un conjunto de $n$ ciudades y los costos de desplazamiento entre cada par, se busca la ruta que permita visitar todas exactamente una vez y regresar al punto de partida minimizando el costo total (Applegate et al., 2006).

Este trabajo aplica dos metaheurísticas al TSP sobre las 32 capitales de los estados de México, modelando el costo de desplazamiento con datos reales de carretera obtenidos mediante OSRM. El objetivo es encontrar la ruta de menor costo económico considerando combustible, peajes y el costo del tiempo del vendedor.

2.2 Formulación del problema

Sea $G = (V, E)$ un grafo completo donde $V = {v_0, ldots, v_{31}}$ representa las 32 capitales. Se busca la permutación $pi$ que minimice:

min Σₖ c(π(k), π(k+1 mod n))

sujeto a que cada ciudad se visite exactamente una vez

El costo entre cada par de ciudades integra tres componentes:

c_ij = C_combustible(d_ij) + C_peaje(d_ij) + C_vendedor(t_ij)

  • Combustible: vehículo Renault Twingo Access 2012, rendimiento 55 km/galón, precio gasolina Magna $92.5 MXN/galón → ~$1.68 MXN/km
  • Peajes: modelo proporcional de $1.5 MXN/km basado en tarifa media de autopistas de cuota (~$1.0–$2.0 MXN/km según SCT, 2023)
  • Tiempo del vendedor: $150 MXN/hora

2.3 Obtención de datos

Las distancias y tiempos reales entre las 32 capitales se obtuvieron mediante OSRM (Open Source Routing Machine), que calcula rutas siguiendo la red vial real de OpenStreetMap incluyendo autopistas y restricciones de tráfico (Luxen & Vetter, 2011). Se realizaron 496 consultas para los $binom{32}{2}$ pares únicos de ciudades.

Métrica Distancia (km) Tiempo (h) Costo (MXN)
Mínimo 38.1 0.60 $204
Máximo 5 212.6 65.92 $25 483
Media 1 216.2 15.11 $5 906

El par de menor distancia es Tlaxcala–Puebla (38.1 km) y el de mayor distancia es Mexicali–Chetumal (5 212.6 km), los dos extremos geográficos del país — lo que valida la coherencia de los datos.

Las 32 entidades y sus capitales:

# Estado Capital # Estado Capital
0 Aguascalientes Aguascalientes 16 Morelos Cuernavaca
1 Baja California Mexicali 17 Nayarit Tepic
2 Baja California Sur La Paz 18 Nuevo León Monterrey
3 Campeche Campeche 19 Oaxaca Oaxaca de Juárez
4 Chiapas Tuxtla Gutiérrez 20 Puebla Puebla
5 Chihuahua Chihuahua 21 Querétaro Santiago de Querétaro
6 CDMX Ciudad de México 22 Quintana Roo Chetumal
7 Coahuila Saltillo 23 San Luis Potosí San Luis Potosí
8 Colima Colima 24 Sinaloa Culiacán
9 Durango Durango 25 Sonora Hermosillo
10 Guanajuato Guanajuato 26 Tabasco Villahermosa
11 Guerrero Chilpancingo 27 Tamaulipas Ciudad Victoria
12 Hidalgo Pachuca 28 Tlaxcala Tlaxcala
13 Jalisco Guadalajara 29 Veracruz Xalapa
14 Estado de México Toluca 30 Yucatán Mérida
15 Michoacán Morelia 31 Zacatecas Zacatecas

2.4 Metodología

Colonia de Hormigas (ACO)

Propuesto por Dorigo et al. (1996), se inspira en el comportamiento de las hormigas reales al buscar rutas entre el nido y fuentes de alimento. Las hormigas depositan feromonas en los caminos recorridos; los más cortos acumulan más feromona y atraen a más hormigas, reforzando esa ruta (Dorigo & Stützle, 2004).

La probabilidad de que una hormiga en la ciudad $i$ elija la ciudad $j$ es:

p_ij = (τᵢⱼᵅ · ηᵢⱼᵝ) / Σₖ (τᵢₖᵅ · ηᵢₖᵝ)

donde:
τᵢⱼ = feromona en el arco (i, j)
ηᵢⱼ = 1/c_ij (visibilidad — preferencia por rutas baratas)
α = peso de la feromona
β = peso de la heurística

donde $eta_{ij} = 1/c_{ij}$ es la visibilidad (preferencia por rutas baratas) y tras cada iteración la feromona se actualiza:

τᵢⱼ ← ρ · τᵢⱼ + Δτᵢⱼ

donde ρ = tasa de evaporación (0.95) y Δτᵢⱼ = 1/costo_ruta

Parámetro Valor Justificación
n_ants 150 Cobertura amplia del espacio
n_best 150 Todas las hormigas depositan feromona
n_iterations 500 Convergencia estable antes de iter. 400
decay ($rho$) 0.95 Evaporación lenta, favorece explotación
alpha 1 Peso igual feromona–heurística
beta 2 Leve énfasis en costo

Algoritmo Genético (GA)

Metaheurística evolutiva inspirada en los principios de selección natural (Holland, 1975). Cada cromosoma es una permutación de las 32 ciudades. Los operadores:

  • Cruce Order Crossover (OX): preserva el orden relativo de los genes del segundo padre, evitando ciudades duplicadas (Davis, 1985).
  • Mutación Swap: intercambia dos ciudades aleatorias con probabilidad $p_m$.
  • Selección: elitismo (20 mejores pasan directo) + torneo binario.
Parámetro Valor Justificación
n_population 200 Balance diversidad–costo computacional
n_generations 500 Convergencia verificada antes de gen. 400
mutation_rate 0.02 Mutación baja para preservar buenas soluciones
elite_size 20 10% de la población pasa sin modificación

2.5 Resultados

Comparación ACO vs. GA

Algoritmo Costo óptimo (MXN) Tiempo de cómputo
ACO $69 747.57 100.6 s
GA $76 651.69 6.4 s

El ACO encontró una solución 9% mejor que el GA ($6 904 MXN de diferencia), a costa de un tiempo de cómputo ~15 veces mayor.

Desglose del costo — Ruta óptima ACO

Concepto Valor % del total
Distancia total 13 987.1 km —
Tiempo de viaje 186.0 h (7.7 días) —
Combustible $20 867.88 MXN 29.9%
Peajes (est.) $20 980.68 MXN 30.1%
Costo vendedor $27 899.00 MXN 40.0%
Total $69 747.57 MXN 100%

Ruta óptima (ACO)

Aguascalientes → Zacatecas → San Luis Potosí → Guanajuato → Santiago de Querétaro → Pachuca → Tlaxcala → Puebla → Xalapa → Oaxaca de Juárez → Tuxtla Gutiérrez → Villahermosa → Campeche → Mérida → Chetumal → Chilpancingo → Cuernavaca → Ciudad de México → Toluca → Morelia → Guadalajara → Colima → Tepic → Durango → Culiacán → Hermosillo → Mexicali → La Paz → Chihuahua → Saltillo → Monterrey → Ciudad Victoria → Aguascalientes

La ruta recorre el Bajío y el centro, desciende hacia el sureste por el Golfo, cruza la Península de Yucatán, asciende por el Pacífico y cierra por el norte — geográficamente consistente con un recorrido de mínima distancia.

Rutas óptimas ACO vs GA
Figura 11. Comparación visual de las rutas óptimas encontradas por ACO (azul) y GA (rojo) sobre el mapa de México.

Animación del recorrido

Animación recorrido ACO
Figura 12. Construcción progresiva de la ruta óptima (ACO) sobre las 32 capitales de México.

Convergencia

Ambos algoritmos convergieron antes de completar las 500 iteraciones. El ACO mostró una caída pronunciada del costo en las primeras 150 iteraciones seguida de refinamientos graduales. El GA convergió más rápido en tiempo real pero se estabilizó en un costo subóptimo.

Análisis de sensibilidad — tarifa del vendedor

El costo del vendedor representa el 40% del total, más que combustible y peajes. Para entender su impacto se recalculó el costo de ambas rutas con distintas tarifas horarias:

Tarifa (MXN/h) Costo ACO (MXN) Costo GA (MXN)
50 ~$55 000 ~$60 000
100 ~$62 000 ~$68 000
150 ~$69 748 ~$76 652
200 ~$77 000 ~$85 000
300 ~$91 000 ~$101 000
500 ~$119 000 ~$132 000

A medida que sube la tarifa, el costo del tiempo domina sobre el combustible y los peajes, lo que en escenarios extremos podría cambiar la ruta óptima hacia trayectos más rápidos aunque sean más largos en distancia.

2.6 Conclusiones

En calidad de solución el ACO fue claramente superior: encontró una ruta 9% más barata que el GA. Esto es consistente con la literatura para problemas de permutación — el mecanismo de memoria colectiva mediante feromona permite explotar eficientemente rutas prometedoras a lo largo de las iteraciones (Dorigo & Stützle, 2004). El GA sin embargo convergió en menos de 7 segundos frente a los 100 del ACO, lo que lo hace preferible cuando el tiempo de cómputo es una restricción o se necesitan múltiples ejecuciones.

El hallazgo más relevante del modelo de costos es que el tiempo del vendedor representa el 40% del costo total, superando tanto al combustible como a los peajes. Esto implica que la tarifa horaria es el parámetro más sensible del modelo: un incremento en el salario puede alterar la ruta óptima de forma no trivial, favoreciendo trayectos más rápidos sobre los más cortos en distancia.

El uso de distancias reales por carretera (OSRM) fue una mejora metodológica importante respecto a distancias euclidianas, ya que México presenta rodeos significativos especialmente hacia Baja California y la Península de Yucatán.

Uso de inteligencia artificial

Durante el desarrollo de este trabajo se utilizó Claude (Anthropic) como herramienta de apoyo. Los principales usos fueron:

  • Revisión y depuración del código de los algoritmos heurísticos (PSO, DE, EA, ACO, GA).
  • Consultas sobre la configuración y justificación de parámetros.
  • Ajustes de presentación y visualización en los notebooks.
  • Apoyo en la redacción y estructura de este reporte.

El impacto fue positivo en velocidad de desarrollo: debugging que podría tomar horas se resolvió en minutos con consultas puntuales. Todos los resultados numéricos, las decisiones de diseño del experimento y las conclusiones fueron verificados y validados manualmente. La IA funcionó como asistente de código y escritura, no como autor del trabajo.

Referencias

  • Applegate, D. L., Bixby, R. E., Chvátal, V., & Cook, W. J. (2006). The Traveling Salesman Problem: A Computational Study. Princeton University Press.

  • Davis, L. (1985). Applying adaptive algorithms to epistatic domains. Proceedings of the International Joint Conference on Artificial Intelligence, 162–164.

  • Dorigo, M., Maniezzo, V., & Colorni, A. (1996). Ant system: optimization by a colony of cooperating agents. IEEE Transactions on Systems, Man, and Cybernetics — Part B, 26(1), 29–41. https://doi.org/10.1109/3477.484436

  • Dorigo, M., & Stützle, T. (2004). Ant Colony Optimization. MIT Press. https://doi.org/10.7551/mitpress/1290.001.0001

  • Eberhart, R., & Kennedy, J. (1995). A new optimizer using particle swarm theory. Proceedings of the Sixth International Symposium on Micro Machine and Human Science, 39–43. https://doi.org/10.1109/MHS.1995.494215

  • Griewank, A. O. (1981). Generalized descent for global optimization. Journal of Optimization Theory and Applications, 34(1), 11–39. https://doi.org/10.1007/BF00933356

  • Holland, J. H. (1975). Adaptation in Natural and Artificial Systems. University of Michigan Press.

  • Luxen, D., & Vetter, C. (2011). Real-time routing with OpenStreetMap data. Proceedings of the 19th ACM SIGSPATIAL International Conference on Advances in Geographic Information Systems, 513–516. https://doi.org/10.1145/2093973.2094062

  • OpenStreetMap contributors. (2024). OpenStreetMap. https://www.openstreetmap.org

  • OSRM Project. (2024). Open Source Routing Machine. http://project-osrm.org

  • Rosenbrock, H. H. (1960). An automatic method for finding the greatest or least value of a function. The Computer Journal, 3(3), 175–184. https://doi.org/10.1093/comjnl/3.3.175

  • Secretaría de Comunicaciones y Transportes (SCT). (2023). Tarifas de autopistas de cuota en México. Gobierno de México.

  • Storn, R., & Price, K. (1997). Differential evolution — a simple and efficient heuristic for global optimization over continuous spaces. Journal of Global Optimization, 11(4), 341–359. https://doi.org/10.1023/A:1008202821328

kovax-react 0.6: Pagination, breakpoint hooks, and one source of truth for responsive layout

kovax-react 0.6 is on npm. If you already use kovax-react 0.5 with ThemeProvider and CSS-variable theming, this release is the “admin panel polish” follow-up: a pagination component you can drop next to tables and search results, plus responsive hooks that read the same breakpoint.* tokens as themeToken and your stylesheets — no duplicate 768px constants in JS.

TL;DR

Area What shipped
Pagination Semantic nav, prev/next, numbered pages, ellipsis windows, aria-current="page", motion from duration.* / easing.*, honors prefers-reduced-motion
Tree-shaking Optional kovax-react/pagination entry exports Pagination + getPaginationItems
Responsive useMediaQuery, useBreakpointUp, breakpointMinMediaQuery, breakpointMinWidth, breakpointMinMediaQueryFromToken — all aligned with breakpoints (sm … 2xl in em)
Docs Pagination.md, playground Components → Pagination, Documentation topic with EN/RU UI copy

No new runtime peer dependencies beyond what you already use for kovax-react.

Install

npm install [email protected]

Wrap your app in ThemeProvider as before — Pagination and the media-query hooks pick up the same CSS variables and token scale as the rest of the library.

Why another minor release?

After 0.5, two gaps showed up in real apps:

  1. Lists and tables need a pager — not just “page 3 of 40” text, but keyboard-friendly controls, clear current-page state, and ellipsis when there are dozens of pages.
  2. Breakpoints were defined twice — once in design tokens / CSS, again as magic numbers in React. That drifts the moment someone tweaks breakpoint.md.

0.6 closes both without pulling in a routing or data-fetching layer: you keep page / pageCount controlled in parent state (or your router) and wire onPageChange.

Pagination

Basics

import { Pagination } from "kovax-react";
import { useState } from "react";

export function SearchResultsPager() {
  const [page, setPage] = useState(1);

  return (
    <Pagination
      page={page}
      pageCount={40}
      onPageChange={setPage}
      variant="outline"
      size="sm"
      aria-label="Search results"
    />
  );
}

Props worth knowing:

  • variant: soft (default) or outline
  • size: sm | md
  • siblingCount: how many page numbers sit beside the current page (default 1); increase for wider “windows” on dense UIs
  • disabled: freeze controls while a request is in flight
  • i18n: previousAriaLabel, nextAriaLabel, getPageAriaLabel, optional visible previousLabel / nextLabel
<Pagination
  page={page}
  pageCount={12}
  onPageChange={setPage}
  siblingCount={2}
  previousAriaLabel="Previous"
  nextAriaLabel="Next"
  getPageAriaLabel={(p) => `Page ${p}`}
/>

The component renders nothing when pageCount < 1, so you can skip conditional JSX around empty result sets.

Accessibility and motion

  • Root is a nav with your aria-label (required for a meaningful landmark).
  • Active page uses aria-current="page".
  • Ellipsis markers are aria-hidden; navigation stays on real buttons.
  • Hover/active feedback uses theme motion tokens; when the user prefers reduced motion, scale animations are skipped.

Custom layout, same gap logic

Need your own button components or a mobile-specific strip? Export the algorithm:

import { getPaginationItems } from "kovax-react/pagination";

const items = getPaginationItems(page, pageCount, 1);
// → (number | "ellipsis")[]

return (
  <nav aria-label="Results">
    {items.map((item, i) =>
      item === "ellipsis" ? (
        <span key={`e-${i}`} aria-hidden>…</span>
      ) : (
        <button
          key={item}
          type="button"
          aria-current={item === page ? "page" : undefined}
          onClick={() => setPage(item)}
        >
          {item}
        </button>
      ),
    )}
  </nav>
);

Smaller bundles

Full barrel:

import { Pagination, getPaginationItems } from "kovax-react";

Pagination-only entry (same API, less to parse if you only ship a pager):

import { Pagination, getPaginationItems } from "kovax-react/pagination";

Full prop reference: Pagination.md.

Breakpoints in JavaScript

Design tokens already expose em breakpoints (sm 30em, md 48em, lg 62em, …). They respect root font size — a nicer default than hard-coded pixels for accessibility.

Hooks and helpers:

API Role
useBreakpointUp("md") true when viewport ≥ token md
useMediaQuery(query, options?) Generic matchMedia subscription
breakpointMinMediaQuery("md") "(min-width: 48em)" string for CSS-in-JS or tests
breakpointMinWidth("md") Raw token value (48em)
breakpointMinMediaQueryFromToken("breakpoint.md") Same as above via themeToken path
import {
  useBreakpointUp,
  useMediaQuery,
  breakpointMinMediaQuery,
  themeToken,
} from "kovax-react";

const isMdUp = useBreakpointUp("md");
const isWide = useMediaQuery(`(min-width: ${themeToken("breakpoint.lg")})`);
const mqForCss = breakpointMinMediaQuery("md"); // "(min-width: 48em)"

SSR and hydration

useMediaQuery is built on useSyncExternalStore, so server and first client paint can agree via defaultMatches:

// Desktop-first layout: fewer “flash from mobile to desktop” warnings
const isLgUp = useBreakpointUp("lg", { defaultMatches: true });

On the server, getServerSnapshot returns defaultMatches (default false). After hydration, the real matchMedia result takes over and listeners update on resize.

Token docs (including breakpoint table): Tokens.md.

Example: responsive columns without duplicating constants

import { Grid, useBreakpointUp } from "kovax-react";

export function ProductGrid({ children }: { children: React.ReactNode }) {
  const threeCols = useBreakpointUp("lg");

  return (
    <Grid columns={threeCols ? 3 : 1} gap={16}>
      {children}
    </Grid>
  );
}

Try it in the playground

The live site is still statically prerendered (SEO-friendly routes, sitemap). For 0.6, open:

  • Components → Pagination — variants, sizes, ellipsis, disabled state, code tabs
  • Components → Design tokens — breakpoint scale next to spacing, motion, z-index
  • Documentation → Pagination — the same Markdown as the repo, with EN/RU chrome

No local install required to click through examples.

Changelog and what’s next

Full release notes (including a Russian summary block): CHANGELOG.md.

From the 0.5 roadmap, items still on the radar include Breadcrumb, richer Toast patterns, and more overlay polish. Menu already exists on the Popover primitives in the current tree — feedback on API shape is welcome.

If something’s missing, open an issue or PR — or leave a comment here; I read them.

Thanks for reading — happy paging.

I Built a Free, Modern Alternative to Paid Universal Sign-In for Expo

If you’ve tried adding Google sign-in to a React Native app recently, you’ve probably ended up at @react-native-google-signin/google-signin.

It is the de-facto standard. It works. It also has a paid Universal Sign-In tier that uses Google’s modern Credential Manager APIs on Android, while the free tier still wraps the older legacy Sign-In SDK.

That paywall is fair. The maintainers have built and maintained a serious package. But for many teams — indie developers, side projects, MVPs, and Android-first Expo apps — the gap still hurts.

So I built expo-google-credential-auth: an MIT-licensed, Android-first package built on the modern Credential Manager + Google Identity Services stack.

This is the comparison I wish existed when I was choosing between the available options.

Who this is for

TL;DR

  • Use paid Universal Sign-In if you need iOS today, SLA support, passkeys, or broader federated identity support.
  • Use expo-google-credential-auth if you’re Android-first, want the modern Google auth stack for free, and prefer a smaller dependency you can audit end-to-end.

Use the paid Universal Sign-In product if you need iOS today, enterprise support, or passkey / federated sign-in flows beyond Google. It is a mature commercial product and a sensible choice for production apps that need full coverage immediately.

Use expo-google-credential-auth if you’re shipping Android first, want the modern Credential Manager stack without a license fee, want a small dependency you can read end-to-end, and can wait for iOS and web support.

Both options rely on modern Google APIs on Android. The real question is not which one is universally better. It is which one fits your product right now.

Comparison table

Feature google-signin free google-signin paid expo-google-credential-auth
Android SDK Legacy Google Sign-In SDK Modern Credential Manager Modern Credential Manager
iOS support ✅ Yes ✅ Yes 🟡 Coming soon
Web support Separate flow ✅ Yes 🟡 Coming soon
License MIT Commercial MIT
Auth and authorization separation Conflated into one call Conflated into one call Explicit separate flows
Cancellation handling Throws exception Throws exception Returns discriminated union
Revoke clears Play Services caches Partial Yes Yes
Native code auditability Large codebase Large codebase + closed paid bits Small focused Kotlin module
Bundle impact Larger Larger Smaller focused module
Support model Community / paid tier Commercial SLA GitHub issues, best effort

A table alone does not explain the trade-offs. These are the four differences that matter most in practice.

1. Authentication and authorization should be separate flows

This is the design decision I care about most.

Many Google sign-in integrations blur two different OAuth concepts into one signIn() call. That call often returns an idToken and sometimes an accessToken, which encourages developers to treat them as interchangeable.

They are not interchangeable.

Concept Authentication Authorization
Question answered Who is this user? What can my app do on their behalf?
Token type ID token Access token
Typical use Verify user identity on your backend Call Google APIs
Revocable? No, it expires naturally Yes
User interface Account picker Consent screen

Common bug: the /userinfo 401 usually happens when an app sends an ID token to an endpoint that expects an access token.

In expo-google-credential-auth, authentication and authorization are separate calls:

// Authentication — for your backend
const { idToken, user } = await GoogleAuth.signIn();
// Authorization — for Google APIs
const { accessToken } = await GoogleAuth.requestAuthorization({
  scopes: ['https://www.googleapis.com/auth/drive.readonly'],
});

This means you can:

  • sign in without requesting API permissions,
  • request additional scopes later,
  • revoke API access without signing the user out,
  • model your app flow closer to the OAuth protocol underneath.

2. Cancellation is not an error

In many existing integrations, dismissing the sign-in sheet throws an exception:

try {
  await GoogleSignin.signIn();
} catch (e) {
  if (e.code === statusCodes.SIGN_IN_CANCELLED) {
    // Not actually an error
  } else if (e.code === statusCodes.NO_SAVED_CREDENTIAL_FOUND) {
    // Also not really an error
  } else {
    // Actual failure
  }
}

A user closing a sheet is not exceptional. It is a normal branch in the user flow.

expo-google-credential-auth models this as a discriminated union:

const result = await GoogleAuth.signIn();

switch (result.type) {
  case 'success':
    return handleUser(result.idToken, result.user);

  case 'cancelled':
    return;

  case 'noSavedCredentialFound':
    return promptCreateAccount();
}

Actual failures, such as network errors or configuration problems, can still throw. But normal user behavior stays in the return type, where TypeScript can narrow it properly.

3. Android revoke behavior needs more than one cleanup step

Most teams do not notice this until production: revoking access on the server is not always enough to clear local Android auth state.

A complete Android revoke flow needs to handle multiple layers:

  1. Server-side revocation

    Call Google’s revoke endpoint to invalidate the grant.

  2. Credential Manager state

    Clear Credential Manager’s local credential state.

  3. Play Services OAuth cache

    Clear sign-in and revoke state through Google Play Services APIs.

  4. Android AccountManager token cache

    Invalidate the underlying Android OAuth token cache.

Each cleanup step should be best-effort and isolated. If one layer fails, the others should still run.

The implementation in expo-google-credential-auth is intentionally small and auditable. The point is not that the code is clever. The point is that the auth behavior is visible instead of hidden.

4. Small dependencies are easier to trust

This is more subjective, but it matters for auth libraries.

When authentication breaks, you want to understand the dependency. You want to trace what native code does. You want to audit the token flow. You want to know whether the package is doing something surprising.

expo-google-credential-auth is intentionally focused: a small Kotlin implementation with thin TypeScript bindings.

Small is a feature when the package sits on your login path.

When you should still pay

The paid Universal Sign-In tier is still the right choice if:

  • You need iOS in production today. expo-google-credential-auth is Android-first right now.
  • You need passkeys or non-Google federated identity. This package focuses only on Google auth.
  • You need commercial support or an SLA. GitHub issues are not a substitute for vendor support.
  • Your current setup already works. Migration risk is real. Do not rewrite working auth code for a marginal improvement.

This is not a “never pay” argument. It is a “choose the right trade-off” argument.

For many Android-first Expo apps, free + focused + modern is enough.

Try it

Install the package:

npm install expo-google-credential-auth

You will need an Android development build because Credential Manager requires native code. It will not work inside Expo Go.

The setup guide and Android configuration notes are available in the npm README.

Final thoughts

Google sign-in in React Native has historically been harder than it should be, especially in Expo projects that want to use modern Android APIs without paying for a commercial tier.

expo-google-credential-auth is my attempt to make that path smaller, clearer, and free.

If you’re building an Android-first Expo app and want modern Google auth without a license fee, try it and see whether it fits your project.

📦 Package: expo-google-credential-auth
💻 Source & issues: https://github.com/sagnik2001/expo-google-credential-auth

About me: I build mobile and developer tools. Find me on GitHub · LinkedIn.

If this post saved you time, a ⭐ on the repo or a follow here on Dev.to means a lot.

The Log Management Cost Trap: Part II — Storage

File system aggregation architecture

Authored by Benoit Gaudin

In Part I of this series, I explored the challenges of designing, running, and managing a centralised log management solution, with a focus on data ingestion. In Part II, I focus on data storage. Part III covers search.

I’ll discuss different storage types and how their characteristics can fulfil the requirements of log management solutions, how data is organised within these systems, and the role of file formats in enabling efficient ingestion, storage, and retrieval.

Storage Types

When evaluating storage options, the type of storage medium is the first decision to make. File systems and blob storage each come with distinct characteristics.

Disks and File Systems

File systems operate at a lower level of abstraction and often require explicit management of storage capacity, throughput, and IOPS. Managed services like AWS EFS and FSx simplify some of this — EFS, for example, supports automatic scaling of storage and throughput capacity.

One major advantage of file systems is the ability to append data to existing files. This is especially relevant in log management, where data is immutable and continuously streamed.

At Bronto, we leverage file systems for data aggregation — specifically their ability to append to files. Aggregation runs over a few hours before data is transferred to blob storage, so the storage footprint stays modest and cost-effective. This aggregation phase prevents small files from landing on blob storage, which is known to cause performance issues at query time.

File system aggregation architecture

Blob Storage

Blob storage is the popular choice for data analytics workloads due to scalability and cost-effectiveness. Unlike file systems, blob storage doesn’t support appending — files must be rewritten entirely when modified.

The pricing model differs significantly: costs include both storage and per-transaction API operations (writes, reads). Overall, blob storage is more cost-efficient than remote disks for large, infrequently-modified datasets.

Blob storage also supports extremely high throughput. AWS S3, for instance, enables massive parallel processing — making it ideal for data-intensive workloads like AWS EMR and AWS Athena.

The tradeoff: blob storage isn’t well-suited for frequent appends or aggregations. Solutions like Datadog Husky and ClickHouse use compaction to address this — writing many small objects over time, then consolidating them into larger ones.

Bronto combines both: blob storage for long-term, large immutable files; file storage for short-term data aggregation. This balance optimises both performance and cost at scale.

File Formats and Data Organisation

File format alone doesn’t determine query performance — how data is physically organised in storage matters just as much. Here are the key techniques.

Compression

Compression is essential at scale. The primary benefit is reduced storage footprint, translating directly into lower costs. At large volumes, the savings are substantial.

That said, maximum compression isn’t always ideal. Higher compression ratios demand more CPU, memory, and time — increasing compute cost. The right point on the curve depends on your access patterns.

Compression trade-off diagram

Row-based vs. Column-based Formats

In row-oriented storage, all fields for each record are stored together sequentially. In column-oriented storage, all values for each field are stored together.

Row-oriented formats suit unstructured data with write-intensive workloads. But with the rise of structured logging and agents that annotate data with attributes, columnar formats have become increasingly relevant for log data — enabling much more efficient scans when you only need specific fields.

Partitioning

Partitioning diagram

Partitioning divides large datasets into smaller segments so queries can skip irrelevant data entirely. The key is choosing a logical criterion for segmentation.

For log data, time-based partitioning is the natural choice — queries almost always specify a time range, so only the relevant time partition needs to be scanned. This dramatically reduces both the volume of data read and the cost of doing so, especially when data is retained over months or years.

Indexing

Indexes work like a book index: rather than reading the entire dataset to find a value, you consult the index to jump directly to where it lives.

Inverted indexes are especially effective for searching uncommon values across large datasets. The tradeoff is size — inverted indexes can grow as large as the original dataset in some cases, significantly increasing storage cost.

Indexing diagram

Predicate Pushdown

Predicate pushdown evaluates filter conditions using file metadata or summary statistics — without downloading or inspecting full file contents. File formats like Parquet support this by storing column statistics (min/max values) in each data block.

If the statistics for a file guarantee that a filter condition can’t match any record in it, the entire file can be skipped. At scale, across datasets distributed across many files, this can dramatically reduce both data transfer and compute cost.

Bloom Filters

A Bloom filter is a probabilistic data structure that answers one question: is a value definitely not present, or possibly present, in a dataset?

When a file’s Bloom filter returns “definitely not,” the system skips that file entirely — no scan needed. Compared to inverted indexes, Bloom filters are smaller and more lightweight. They don’t pinpoint exact data locations, but they’re highly effective at eliminating irrelevant files before any data is transferred.

Dictionary Encoding

Dictionary encoding optimises storage and search for key-value pairs where values have low cardinality — country names, log levels, environment tags, and so on. Instead of storing the full value in every row, a compact reference (dictionary entry) is stored, and the actual values live in a separate dictionary.

This reduces storage size and enables a query optimisation: if filtering by a key whose values don’t appear in a file’s dictionary at all, that file’s entire column can be skipped.

Conclusion

Developing a storage strategy for a large-scale log management system demands deep expertise and a clear understanding of data ingestion and access patterns. The choices made at the storage layer directly shape what’s possible — and what it costs — at the ingestion and search layers.

Bronto combines file storage for aggregation and blob storage for long-term retention, and borrows techniques from databases and analytics engines — partitioning, Bloom filtering, predicate pushdown, and dictionary encoding — to achieve high search performance at low cost.

In Part III, I’ll focus on the approaches and economics of search, and detail how Bronto uses AWS Lambda to provide a fast, cost-effective way to process large volumes of data stored in S3.

See How Bronto Handles This

Orchestrated Multi-Agent Safety & Test Oversight – AKA “`O MAS TO”

I am building a small experiment inspired by Stripe Minions. Not related to OrKa. This is a different playground. But apparently I have a recurring problem: I do not trust agents enough to let them freely touch a codebase, and I do not trust humans enough to believe they will always review AI output properly when they are tired, rushed, or already late for another meeting.

So the question became simple. Can we automate small development tasks without pretending the coding agent is the adult in the room?

Because yes, AI can write code! We know that. Sometimes it writes useful code. Sometimes it writes code that looks clean, passes the first glance, and then you realize it quietly moved business logic into the wrong layer because it had “a better idea.” Classic junior developer energy, but with infinite confidence and no coffee breaks.

The interesting part of Stripe Minions, at least for me, is not that agents can open pull requests. The interesting part is the machinery around them. The task definition, the constraints, the review process, the checks, the fact that the agent is not just sitting there with a keyboard and divine permission to refactor your production system.

That is the part I want to explore!

In my experiment, GitHub access starts as read-only. The system can inspect the codebase, understand structure, look at existing patterns, and generate a candidate issue. But it cannot immediately modify anything. Before planning even starts, the task needs to pass a semantic gate: is it scoped, is it testable, is it clear enough, and is it safe enough to continue? Only after that does the workflow move into planning, architecture, execution, PR creation, review, and final merge validation.

I am calling this orchestration ’O MASTO.

In Neapolitan, ’o masto is the master craftsman. The person who looks at the work and decides if it is actually good enough. Not if it looks good in a demo. Not if the agent says it is done. Actually good enough.

In this experiment, it also stands for Orchestrated Multi-Agent Safety & Test Oversight. Yes, the acronym is a bit forced. No, I do not care. It makes me laugh, and naming things is half of software engineering anyway.

The idea is that ’O MASTO is the layer that does not trust the agent. It checks the task, the plan, the implementation, the PR, the tests, the regression risk, and the final merge conditions. It is not there to be impressed. It is there to say “no, this is not good enough, go back.”

That is the core idea I keep coming back to. The executor is not the boss. The reviewer is not the boss. The LLM is definitely not the boss. The gate is the boss!

I think this is where AI coding workflows need to go. Not toward bigger chat windows where we ask the model to “please be careful.” Toward systems that assume the model will be wrong sometimes and are designed to catch that before the damage reaches main.

AI will not remove engineering discipline. It will expose who actually had it.

If a project has no tests, no review culture, no stable patterns, no definition of done, and no clear ownership, an AI coding agent will not magically fix it. It will just produce chaos faster, with better formatting.

My bet is that the next serious layer of AI development tooling will be trust infrastructure. Not just generation. Validation. Rejection. Retry. Traceability. Merge control. Basically “old school” software engineering.

GitHub’s New Billing Model Changes Everything About Agentic Development

Delegated agent architecture diagram showing a main router agent dispatching to four specialized sub-agents — Research (Flash 0.25x), Code (Sonnet 1x), Review (Opus 10x), and Docs (GPT-4.1 0x) — each with minimal focused context

The Bill Is Coming Due

On April 27, GitHub announced that all Copilot plans will transition to usage-based billing on June 1, 2026. Premium Request Units (PRUs) are being replaced by GitHub AI Credits, charged based on actual token consumption — input, output, and cached tokens — at each model’s published API rate.

Here’s the line that should make every engineering leader sit up:

“Today, a quick chat question and a multi-hour autonomous coding session can cost the user the same amount.”

That’s the old model. Under the new one, that multi-hour agentic session will cost exactly what it consumes. And if your team has been running unoptimized agents with bloated contexts and premium models for everything? The invoice is about to get specific.

What Actually Changed

The transition happened in two phases. First, in June 2025, GitHub introduced premium request limits with model multipliers — Claude Opus 4 at 10x, GPT-4.5 at 50x, Gemini 2.0 Flash at 0.25x. Sonnet 4 at 1x (or 0.9x with auto model selection). Pro users got 300 monthly premium requests, Business 300 per user, and Enterprise 1,000 per user — with overages at $0.04 per request.

Now, starting June 1, 2026, the system moves to pure token-based billing. Your plan price becomes your credit pool:

Plan Price Monthly AI Credits
Copilot Pro $10/month $10
Copilot Pro+ $39/month $39
Copilot Business $19/user/month $19
Copilot Enterprise $39/user/month $39

Credits are consumed based on token usage at published API rates. Once you’re out, you either buy more or stop. The fallback to a lower-cost model is going away. Admin budget controls can cap spend at the enterprise, cost center, or user level. To ease the transition, existing Business customers get $30 in promotional credits and Enterprise gets $70 for June through August 2026.

This is a natural evolution. As InfoWorld noted, it’s the second pricing recalibration in under a year — and it aligns with the broader industry shift toward consumption-based AI pricing.

The Impact Spectrum: Who Gets Hit Hardest

Not every team will feel this equally. The impact correlates directly with how you’ve been using agentic development.

High-impact teams (expect significant cost increases):

  • Running long, multi-turn agent sessions with full conversation history accumulating
  • Using Claude Opus or GPT-4.5 for everything, regardless of task complexity
  • Relying on “god prompt” architectures where a single agent carries all context
  • No governance over which models get invoked or how long sessions run

Low-impact teams (may actually spend less):

  • Delegating work to focused sub-agents with minimal context per turn
  • Routing model selection based on task complexity
  • Using deterministic guardrails (hooks, hookflows) that prevent wasted cycles
  • Keeping agent sessions short and focused

The math is simple. Every quality LLM call sends the entire conversation history as input tokens. A 50-turn session with a growing context window doesn’t just cost 50x — it grows superlinearly as each turn carries all previous turns as input. Under token-based billing, that compounding cost becomes visible on your invoice for the first time.

Harness Engineering: The Cost Control Layer

This is where agent harnesses become a financial strategy, not just an architectural pattern.

A harness is the infrastructure that governs agent behavior deterministically — hooks that fire on every tool call, hookflows that chain validations, and guardrails that prevent entire categories of waste. The key insight: deterministic enablement via hooks gives you more cost efficiency per dollar than pure context engineering, because:

  1. You can use less expensive models while sustaining quality. When a hook validates file paths before write operations, checks test results before commits, or enforces style rules on output — the model doesn’t need to be “smart enough” to remember all those rules. The harness handles enforcement. That means Sonnet (1x multiplier) or even GPT-4.1 (included, 0x) delivers the same quality that previously required Opus (10x).

  2. You eliminate token waste from retries and mistakes. Without hooks, an agent might write to the wrong directory, fail CI, retry with the full error in context, and try again — each attempt burning tokens at scale. A preToolUse hook that validates the operation before it executes? Zero wasted tokens.

  3. You don’t need the entire conversation history. When governance is embedded in the harness rather than the prompt, you can aggressively trim context. The agent doesn’t need to “remember” rules it can’t violate anyway.

I run 50+ agents in my own platform with hooks governing everything from git operations to data file access. A single dev-guard hook prevents all raw git commands and forces governed tools — that’s one deterministic rule replacing paragraphs of prompt instructions that every model invocation would carry as input tokens.

Delegated Agents: Small Context, Big Savings

Delegated agent architecture diagram showing a main router agent dispatching to four specialized sub-agents — Research (Flash 0.25x), Code (Sonnet 1x), Review (Opus 10x), and Docs (GPT-4.1 0x) — each with minimal focused context
Each sub-agent starts fresh with only the context it needs — no accumulated conversation history, no carrying 50 prior tool calls.

The monolithic agent pattern — one god-agent that handles everything — was always an architectural antipattern. Under usage-based billing, it becomes a financial one.

Every time a model responds, it processes the full conversation. A 20-turn session where each turn has a 10K-token context means your 20th response is processing ~200K input tokens. Delegate that same work to four 5-turn sub-agents, each with 3K-token focused context, and your total input token cost drops dramatically.

The pattern:

Main Agent (routing layer)
  ├── Research Agent (Gemini 2.0 Flash — simple lookup, 0.25x)
  ├── Code Agent (Sonnet 4 — implementation, 1x)
  ├── Review Agent (Opus — only for final quality check, 10x)
  └── Docs Agent (GPT-4.1 — formatting, included)

Each sub-agent starts fresh with only the context it needs. No accumulated conversation history. No carrying 50 prior tool calls in the input buffer. Just the task description, relevant files, and completion criteria.

This maps directly to the maturity curve I wrote about — expert-level agentic development looks like simplicity. Small, focused agents with clear contracts, not sprawling sessions trying to do everything.

MCP Tool Isolation: Context Is Budget

Here’s one that surprises people: MCP (Model Context Protocol) tools consume context space. When a model has 30 tools registered, every request includes the schema definitions for all 30 tools in the system prompt. That’s potentially thousands of tokens per request that deliver zero value if the agent only uses two of them.

The fix is architectural. Isolate tools at the agent level:

  • Your code-writing agent gets dev_add, dev_commit, dev_push — not telegram_send, gcal_create_event, or gmail_search
  • Your research agent gets web search and API tools — not file editing tools
  • Your notification agent gets communication tools — not code tools

Under flat-rate billing, this was a nice-to-have for reliability. Under token billing, it’s a direct cost reduction on every single request.

Model Selection Strategy: The Right Model for the Job

GitHub Copilot model cost multipliers showing the hierarchy from GPT-4.5 at 50x down to included models at 0x, with color-coded tiers indicating cost severity
The multiplier hierarchy makes the economic argument clear — one GPT-4.5 interaction costs as much as 200 Flash interactions.

The multiplier table makes the economic argument clear. Here’s what different models cost you relative to a standard premium request:

Model Multiplier Best For
GPT-5 mini / GPT-4.1 / GPT-4o Included (0x) Chat, simple code completion, quick questions
Gemini 2.0 Flash 0.25x Fast research, summarization, simple transforms
Sonnet 4 1x Most coding tasks, implementation, reviews
Claude Opus 4 10x Complex architecture, nuanced reasoning
GPT-4.5 50x Extremely rare — only highest-complexity tasks

The mistake I see teams making: defaulting to Opus or equivalent for everything because “we want the best quality.” Under the original premium request system (before multipliers were introduced in June 2025), every model cost one request regardless of complexity. Once multipliers landed — and especially now with token-based billing — that Opus call costs 10x what Sonnet costs.

The harness engineering approach to model selection is explicit routing:

  • Linting, formatting, simple refactors → Use included models (GPT-4.1). Zero premium cost.
  • Standard implementation work → Sonnet 4 (1x). Capable, cost-effective.
  • Architecture decisions, complex debugging → Opus (10x). Worth it when it matters.
  • Never GPT-4.5 unless you have a very specific, verified reason. At 50x, a single interaction costs more than 50 standard Sonnet calls.

With delegated agents, each agent can specify its own model. Your harness routes the right model to the right task without human intervention — and without every task paying the Opus tax.

The Three Layers That Save You Money

Looking at this through the lens of the three architectural layers that production agents need:

  1. Skills (reusable procedures) — reduce token waste by keeping instructions in the harness, not the prompt. The model doesn’t need to carry a 2000-token skill definition in every turn when the skill fires deterministically via hooks.

  2. Extensions (governed tools) — replace raw operations with validated, focused tools. Each extension call is a single tool invocation rather than a chain of unguarded attempts that might fail and retry.

  3. Hooks (deterministic guardrails) — prevent bad operations before they execute. No wasted tokens on failed attempts, no retries, no error messages inflating context.

Together, these layers move governance out of the token stream and into the infrastructure. That’s the fundamental cost optimization: everything that can be enforced deterministically should be — because instructions in your prompt cost tokens on every single request.

The Bottom Line

Before and after comparison showing monolithic Opus session costing ~$8.40 versus delegated agents with mixed models costing ~$1.20 — an 85% cost reduction through harness engineering
Same task, same quality — dramatically different cost. Harness engineering turns architectural best practices into direct financial savings.

GitHub’s shift to usage-based billing isn’t a punishment — it’s transparency. For the first time, teams will see exactly what their agentic workflows cost. The teams that invested in harness engineering — deterministic hooks, delegated agents, model routing, tool isolation — will find their bills modest and predictable. The teams running sprawling, ungoverned agent sessions with premium models on every turn will finally see the true cost of that architecture.

The fix isn’t to stop using agentic development. It’s to architect it properly. Start with your highest-volume workflows: what model are they using? How much context are they carrying? Can you delegate to sub-agents? Can a hook replace a prompt instruction?

Every deterministic rule you add to your harness is tokens you’ll never pay for again.

Resources