Xbox Game Pass için Xbox Studios oyunlarına özel bir abonelik seçeneği gelebilir

Xbox Game Pass

Xbox Game Pass“Redphx” tarafından yapılan son keşfe göre Xbox Game Pass için yakında yalnızca “Xbox Studios” oyunlarına özel bir abonelik seçeneği gelebilir. Şirketin kodlarında “TRITON” olarak geçen yeni paket için şu anda listelenen oyunlar, “DOOM Eternal, DOOM 64, Dishonored 2, Fable Anniversary, Fallout 4, Fallout 76, Gears 5, Halo 5: Guardians, Halo Wars 2, Hellblade, Ori and the Blind Forest, Psychonauts, State of Decay 2, The Elder Scrolls Online ve Retro Classics.” olarak görünüyor. The Information tarafından geçtiğimiz günlerde yayımlanan yeni bir habere göre Microsoft Gaming’in, yani Xbox dünyasının yeni CEO’su Asha Sharma’nın görevindeki ilk icraatlarından biri, servisi daha geniş bir tüketici kitlesi için çekici kılmak ve servise yeni oyuncular eklemek amacıyla Game Pass için daha düşük fiyatlı bir abonelik seçeneği sunmak olabilir. Game Pass için geçtiğimiz aylarda detaylarına burada yer verdiğimiz çok büyük duyurular gerçekleştiren şirket, Sharma’nın yönetimi altında Xbox’ı yeniden konsolun öne çıktığı bir marka haline getirmek istiyor ve bunun […]

Xbox Game Pass için Xbox Studios oyunlarına özel bir abonelik seçeneği gelebilir yazısı ilk olarak Teknoloji haberleri – LOG üzerinde yayınlandı.

La Guia Completa de Instalacion de VICIdial (2026): De Servidor Nuevo a Primera Llamada en Menos de 2 Horas

Ultima actualizacion: Marzo 2026 | Tiempo de lectura: ~18 minutos

Ya hiciste las cuentas. Convoso quiere $150/puesto/mes. Five9 quiere aun mas. Mientras tanto, VICIdial — el mismo marcador predictivo open-source que alimenta mas de 14,000 instalaciones en todo el mundo — no cuesta absolutamente nada en licencias.

Solo hay un problema: instalarlo.

Cada guia que vas a encontrar en Google ahora mismo es un PDF de ViciBox 7 del 2018, un hilo de foro con 47 respuestas contradictorias, o un post de blog que parece que fue traducido tres veces. CentOS 7 — el sistema operativo que el 90% de esas guias referencian — llego a su fin de vida en junio de 2024. Si sigues esas instrucciones en 2026, estas construyendo sobre una base muerta.

Esta guia arregla eso. Vamos a cubrir ViciBox 12.0.2 (la version estable actual), instalaciones desde cero en AlmaLinux 9, despliegues de servidor unico, clusters multi-servidor, configuracion de troncales SIP con ejemplos reales de carriers, configuracion de WebRTC para agentes remotos, y cada problema comun que te va a arruinar el fin de semana si no lo conoces de antemano.

O — escuchanos — puedes saltarte todo esto y dejar que ViciStack lo maneje en una noche. Migramos operadores de VICIdial a infraestructura bare-metal completamente optimizada con precision de AMD llegando al 92-96% desde el primer dia. Sin compilar Asterisk desde el codigo fuente. Sin depurar audio unidireccional a las 2 AM. Pero si quieres hacerlo tu mismo, sigue leyendo. Respetamos el espiritu DIY. Solo queremos que sepas que hay una mejor opcion cuando estes listo.

Que Cambio Realmente en 2024-2026 (Y Por Que Tu Guia Antigua Te Esta Mintiendo)

Saquemos esto del camino primero, porque si te saltas esta seccion y sigues un tutorial desactualizado, vas a perder unas buenas 6-8 horas antes de darte cuenta de que algo esta roto de raiz.

CentOS 7 esta muerto. Literalmente muerto. EOL junio 2024. Sin mas parches de seguridad, sin mas actualizaciones. Cada “guia de instalacion de VICIdial” de striker24x7, cada curso de Udemy, cada hilo de foro que dice yum install centos-release-scl — todo eso es ficcion historica ahora.

ViciBox salto de la v9 a la v12. Los numeros de version no son un error. ViciBox 12.0.2 salio en enero de 2025, corriendo sobre OpenSuSE Leap 15.6 con Asterisk 18, MariaDB 10.11.9, y PHP 8.2. ViciBox 13.0 ya esta en beta con OpenSuSE 16.0 y soporte para SELinux. Si estas siguiendo una guia que menciona ViciBox 8 o 9, estas leyendo historia antigua.

Asterisk 18 es ahora el estandar. El salto de Asterisk 13/16 a 18 trajo soporte PJSIP, mejor manejo de WebRTC, y mejor negociacion de codecs. Matt Florell confirmo oficialmente el soporte completo de Asterisk 18 en septiembre de 2025. Los parches especificos de VICIdial ahora apuntan exclusivamente a Asterisk 18 para nuevas instalaciones.

PHP 8.2 es estandar. El codigo de VICIdial con mas de 4 anos tirara advertencias de depreciacion o directamente se rompera en PHP 8.x. Las funciones mysql_* que tus viejos scripts de instalacion referencian desaparecieron desde PHP 7.0.

El trunk SVN esta en la revision 3939+, version 2.14b0.5, esquema de base de datos 1729. Todavia alojado en svn://svn.eflo.net:3690/agc_2-X/trunk porque el proyecto VICIdial no tiene planes de migrar a Git. Algunas cosas nunca cambian.

Esto es lo que significa en la practica: los unicos dos caminos que valen la pena para una nueva instalacion de VICIdial en 2026 son ViciBox 12.0.2 (recomendado) o una instalacion desde cero en AlmaLinux 9 / Rocky Linux 9. Todo lo demas es una perdida de tiempo.

Tu Guia Antigua Te Esta Mintiendo. Nosotros No.
ViciStack despliega VICIdial completamente optimizado en Asterisk 18, AlmaLinux 9, con cada problema pre-resuelto. Salta la Instalacion →

Hardware: Lo Que Realmente Necesitas (No Lo Que El Foro Te Dijo en 2015)

Hablemos de numeros reales. La documentacion de ViciBox 12 finalmente tiene especificaciones de dimensionamiento adecuadas, y son diferentes de lo que encontraras en posts viejos de foros.

Servidor Unico (La Configuracion “Tengo 10-25 Agentes”)

Componente Minimo Recomendado
CPU 4 nucleos @ 2.0+ GHz 6+ nucleos @ 2.0+ GHz
RAM 8 GB 16 GB ECC
Almacenamiento 160 GB SSD 500 GB RAID1 SSD
Red 1 Gbps 1 Gbps dedicado

Los SSDs son obligatorios en 2026. No recomendados — obligatorios. La documentacion de ViciBox establece explicitamente SATA SSD como el minimo. Si alguien intenta venderte un servidor VICIdial con discos mecanicos, o estan atascados en 2016 o no les importa que tus agentes se queden sentados esperando consultas de base de datos.

Un solo servidor Express maneja de manera realista 15-20 agentes outbound con marcacion predictiva activa, o aproximadamente 50 agentes solo-inbound bajo condiciones ideales. Una vez que pasas de 25 agentes outbound, estas jugando con fuego.

Cluster Multi-Servidor (La Configuracion “Realmente Estoy Manejando un Negocio”)

Cuando superas un solo servidor, VICIdial se divide en cuatro roles. Para la guia completa sobre arquitectura de cluster, planificacion de capacidad, y cada detalle de configuracion, consulta nuestra guia dedicada de clusters.

Servidor de base de datos — El cerebro. Uno por cluster, siempre. Para 150 agentes: 8+ nucleos, 32 GB de RAM ECC, NVMe RAID1.

Servidores de telefonia/marcador — Los pulmones. Cada uno maneja aproximadamente 25 agentes outbound con grabacion pesada y ratios de marcacion de 4:1.

Servidores web — La cara. 2-4 nucleos, 4-8 GB de RAM. SSL reduce la capacidad aproximadamente a la mitad debido al overhead de TLS.

Servidor de archivo — La memoria. Este es el unico lugar donde los discos mecanicos realmente estan bien.

Deja de Adivinar las Especificaciones del Servidor.
ViciStack provisiona bare metal construido a medida para tu numero exacto de agentes y ratio de marcacion. Obtener Tu Cotizacion Personalizada →

Metodo de Instalacion 1: ViciBox ISO (El Camino Sensato)

ViciBox es el ISO pre-construido oficial mantenido por Kumba (el desarrollador de ViciBox). Empaqueta OpenSuSE Leap 15.6, Asterisk 18, MariaDB, Apache, PHP, y VICIdial en una sola imagen booteable. Es el camino de menor resistencia y el que recomendamos para cualquiera que valore su tiempo.

Descarga e Inicio

Descarga ViciBox 12.0.2 de download.vicidial.com/iso/vicibox/server/. Dos sabores: Standard (disco unico, RAID por hardware, VMs) y MD (RAID1 por software entre dos discos). Graba en USB con Rufus o dd, inicia, y selecciona “Install ViciBox” del menu.

El instalador copia el sistema operativo al disco, inicias sesion como root, y te guia a traves de idioma, teclado, zona horaria, y contrasena de root. Reinicia cuando se te indique. Tiempo total: aproximadamente 10 minutos.

Configuracion Pre-VICIdial (No Te Saltes Esto)

Antes de tocar VICIdial, asegura tu red. La configuracion de VICIdial esta permanentemente ligada a la direccion IP de tu servidor — cambiarla despues es una cirugia dolorosa en multiples archivos.

Establece una IP estatica:

yast lan

Selecciona tu interfaz, elige “Statically assigned IP Address,” ingresa la IP/subred/gateway, y establece DNS. Presiona ALT-O para aplicar. Verifica con ping -4 google.com.

Establece la zona horaria (usa el comando de ViciBox, no yast):

vicibox-timezone

El comando regular de yast para zona horaria no actualiza la zona horaria de PHP. Preguntame como lo se.

Actualiza el sistema:

zypper ref
zypper up
reboot

Advertencia critica: Siempre zypper up, nunca zypper dup. El comando dup (actualizacion de distribucion) puede degradar MariaDB o romper la compatibilidad con DAHDI. Multiples posts del foro documentan esto destruyendo sistemas de produccion.

Instala VICIdial (El Milagro de Un Solo Comando)

Para un servidor unico con 20 o menos agentes:

vicibox-express

Escribe Y. Espera. Reinicia. Eso es todo. VICIdial esta corriendo.

Verifica con screen -ls — deberias ver 10-12 sesiones de screen. Accede a http://<IP-de-tu-servidor>/vicidial/welcome.php con las credenciales por defecto 6666 / 1234 y estaras viendo un marcador funcionando.

Para un cluster, ejecuta vicibox-install en cada servidor (base de datos primero, luego web, luego telefonia), selecciona que roles habilitar, y apunta los servidores que no son DB a la IP del servidor de base de datos. Mismo proceso, solo repetido.

El Unico Bug Que Necesitas Arreglar Inmediatamente

ViciBox 12 viene con una version de MariaDB que deprecio el comportamiento implicito de TIMESTAMP. Esto puede romper tablas silenciosamente. Arreglalo antes de hacer cualquier otra cosa:

echo "explicit_defaults_for_timestamp = Off" >> /etc/my.cnf.d/general.cnf
systemctl restart mariadb.service

ViciBox Te Pone en Marcha. ViciStack Te Da Resultados.
Vamos mas alla de la instalacion — ajuste de AMD, gestion de DID, optimizacion de carriers, todo incluido. Ver la Diferencia →

Metodo de Instalacion 2: Instalacion Desde Cero en AlmaLinux 9 (El Camino del Controlador)

Algunas personas necesitan Linux de la familia RHEL. Algunas personas quieren entender cada componente. Algunas personas simplemente disfrutan compilar software desde el codigo fuente un viernes por la noche. No juzgamos.

La mejor opcion en 2026 es el auto-instalador de carpenox mantenido por Chris en CyburDial/Dialer.one. Es el script comunitario mas activamente mantenido y maneja AlmaLinux 9 + Rocky Linux 9 con Asterisk 18:

timedatectl set-timezone America/New_York
yum check-update && yum update -y
yum -y install epel-release && yum update -y
yum install git kernel* --exclude=kernel-debug* -y
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
cd /usr/src
git clone https://github.com/carpenox/vicidial-install-scripts.git
reboot
cd /usr/src/vicidial-install-scripts
chmod +x alma-rocky9-ast18.sh
./alma-rocky9-ast18.sh

SELinux debe estar deshabilitado. Esto no es negociable. Los scripts Perl de VICIdial, las operaciones de archivo de Asterisk, y la configuracion de Apache asumen que SELinux esta desactivado. Cada guia de instalacion desde cero comienza deshabilitandolo.

El script maneja la instalacion de dependencias, la compilacion de Asterisk 18 con los parches de VICIdial, DAHDI, LAME, Jansson, checkout de VICIdial por SVN, configuracion de base de datos, configuracion de crontab, y scripts de inicio. Los cinco parches especificos de VICIdial para Asterisk (estadisticas de AMD, estado de peer IAX, logging de peer SIP, y dos parches de reinicio de timeout) se aplican automaticamente.

Post-Instalacion: De “Esta Corriendo” a “Estamos Haciendo Llamadas”

Aqui es donde cada otra guia en internet se detiene. “Felicitaciones, instalaste VICIdial! Aqui hay una captura de pantalla de la pagina de login. Buena suerte!” No ayuda. Vamos a configurar esto de verdad.

Asegura los Valores por Defecto (Haz Esto Primero)

VICIdial viene con valores por defecto que son tambien agujeros de seguridad:

  1. Cambia la contrasena de admin — Admin → Users → Modify user 6666. Las credenciales por defecto 6666/1234 las conoce literalmente todo el que haya buscado en Google “vicidial.”
  2. Establece la contrasena root de MySQL — mysqladmin -u root password 'ALGO_FUERTE'
  3. Cambia las contrasenas de registro de telefonos — El valor por defecto es test. Si, en serio.
  4. Mueve SSH del puerto 22 — Cada bot en internet esta golpeando el puerto 22 ahora mismo.

Configurando Tu Troncal SIP

Aqui es donde la mayoria de las instalaciones DIY se atascan. Necesitas un carrier VoIP para realmente hacer llamadas telefonicas, y la configuracion de carriers de VICIdial tiene algunas particularidades no obvias.

Navega a Admin → Carriers → Add A New Carrier. Para un trunk autenticado por IP (la mayoria de los carriers empresariales):

Account Entry:

[tu-carrier]
disallow=all
allow=ulaw
allow=g729
type=peer
insecure=port,invite
host=sip.tucarrier.com
dtmfmode=rfc2833
context=trunkinbound
canreinvite=no

Dialplan Entry:

exten => _91NXXNXXXXXX,1,AGI(agi://127.0.0.1:4577/call_log)
exten => _91NXXNXXXXXX,2,Dial(${CARRIER}/${EXTEN:1},60,tTor)
exten => _91NXXNXXXXXX,3,Hangup

Global String: CARRIER=SIP/tu-carrier

El prefijo 9 es una convencion de dial string — cuando tu campana usa el prefijo de marcacion 9, VICIdial lo antepone a cada numero, y el dialplan lo elimina antes de enviarlo al carrier. Verifica tu trunk con:

asterisk -rx "sip show registry"
asterisk -rx "sip show peers"

Consejo profesional de operar 100+ centros VICIdial: La atestacion STIR/SHAKEN importa enormemente en 2026. Necesitas atestacion de nivel A, lo que requiere que tus DIDs y la terminacion esten en el mismo carrier. El enfoque dual-stack te da redundancia mientras mantienes nivel A en ambos.

La Configuracion del Carrier Es Donde Las Instalaciones DIY Van a Morir.
Una configuracion incorrecta de STIR/SHAKEN = “Posible Spam” en una semana. ViciStack configura tus carriers correctamente desde el primer dia. Hazlo Bien →

Creando Tu Primera Campana

Admin → Campaigns → Add a New Campaign. La configuracion critica es el Dial Method:

  • RATIO — Llamadas fijas por agente (ej., 2.0 = dos llamadas simultaneas por agente disponible). Simple, predecible, bueno para equipos pequenos.
  • ADAPT_HARD_LIMIT — Marcacion predictiva con un techo fijo en la tasa de abandono. Establece esto en 3% para cumplimiento TCPA. Esto es lo que la mayoria de las operaciones outbound deberian usar.
  • ADAPT_TAPERED — Mas agresivo al principio, mas conservador a medida que avanza el dia. Bueno para operaciones experimentadas que entienden los compromisos.
  • MANUAL — El agente hace clic para marcar. Para entornos de alto cumplimiento normativo o pruebas.

Configuraciones clave para establecer desde el inicio: Hopper Level (100-200 leads pre-cargados), Dial Timeout (26-30 segundos — depende del carrier), Available Only Tally = Y (solo marcar cuando los agentes estan realmente disponibles), y Auto Dial Level (empieza en 1.5 para modos adaptativos y ajusta basado en rendimiento). Para el desglose completo de cada configuracion del marcador que importa, consulta nuestra guia dedicada.

Cargando Leads

Lists → Add A New List → asigna a tu campana → Lists → Load New Leads. Sube un CSV con como minimo: phone_number, first_name, last_name, state. Siempre prueba con un lote pequeno primero. El cargador de leads de VICIdial es potente pero implacable con problemas de formato.

Configuracion del Telefono del Agente

Dos opciones en 2026:

Softphone SIP (MicroSIP, Zoiper, X-Lite): Crea un telefono en Admin → Phones con una extension (ej., 1001), IP del servidor, y contrasena de registro. El agente configura su softphone con estas credenciales. Funciona, pero requiere software en cada maquina de agente.

WebRTC/ViciPhone (la forma moderna): Requiere SSL/TLS en tu servidor web y el puerto 8089 abierto. Configura con vicibox-ssl en ViciBox, o certbot en instalaciones desde cero. Habilita plantillas de telefono WebRTC en Admin, establece los telefonos en “As Webphone = Y,” y los agentes obtienen un telefono basado en navegador integrado directamente en la interfaz del agente. Sin instalaciones de software, funciona desde cualquier lugar. Asi es como la mayoria de las operaciones remotas funcionan en 2026.

Clustering Multi-Servidor: Las Reglas Que Nadie Escribe

Una vez que creces mas alla de 20-25 agentes outbound, necesitas un cluster. Aqui estan las reglas que te salvaran del cementerio de posts de clusters rotos del foro:

Regla 1: Un proceso adaptativo, un servidor. El proceso AST_VDadapt (keepalive 5) gestiona el algoritmo predictivo. Corre en exactamente un servidor en todo el cluster. Ejecutarlo en dos servidores causa conflictos de nivel de marcacion que parecen abandonos aleatorios. Lo mismo aplica para AST_VDauto_dial_FILL (keepalive 7).

Regla 2: Misma LAN, sin routers. Todos los servidores del cluster deben estar en la misma red local con latencia de menos de 1ms. Un router entre tus servidores de base de datos y marcador agrega suficiente latencia para romper las sesiones de los agentes. Usa IAX2 (no SIP) para trunks inter-servidor.

Regla 3: NTP desde una sola fuente. Todos los servidores sincronizan sus relojes al servidor de base de datos o a una fuente NTP designada. La sincronizacion NTP independiente a servidores externos causa desviacion del reloj que rompe sesiones de agentes, desconecta llamadas, y corrompe reportes.

Regla 4: Conoce tu techo. Las tablas MEMORY de VICIdial son de un solo hilo. Un cluster llega al maximo alrededor de 450-500 agentes. Planifica tu crecimiento de acuerdo a esto.

Cuando Agregar Que

Llegas a… Agregas…
20 agentes outbound Separar DB de telefonia
25 agentes mas Segundo servidor de marcacion
50+ agentes Servidor de DB dedicado
70+ agentes Servidor web dedicado
150+ agentes Base de datos esclava para reportes
450+ agentes Segundo cluster

Regla #1 del Clustering: No Lo Aprendas Por Las Malas.
Hemos construido mas de 100 clusters. Que nuestras cicatrices salven tu fin de semana. Habla con un Experto en Clusters →

El Salon de la Fama de la Resolucion de Problemas

Estos son los problemas que llenan los mas de 13,400 hilos de soporte del foro de VICIdial. Aprende del dolor de otros:

Sin audio / audio unidireccional — 80% de probabilidad de que el firewall este bloqueando UDP 10000-20000 (puertos RTP). 15% de probabilidad de que falta un externip en sip.conf. 5% de probabilidad de que sea SIP ALG en un router NAT. Deshabilita temporalmente el firewall y prueba. Si el audio funciona, es el firewall.

“No available sessions” — Las extensiones de conferencia no estan pobladas para la IP de tu servidor. Admin → Conferences → Show VICIDIAL Conferences. Cada servidor necesita su propio rango de conferencias.

Grabaciones faltantes — Verifica todo el pipeline: esta SOX instalado? La grabacion de campana esta en ALLCALLS? Estan corriendo los cron jobs? Revisa /var/spool/asterisk/monitor/ para archivos crudos. La configuracion de grabacion a nivel de usuario puede sobreescribir silenciosamente la configuracion de campana — verifica ambas.

Advertencia de desajuste de esquema de base de datos — Actualizaste el codigo SVN pero olvidaste la base de datos. Ejecuta:

mysql -p -f --database=asterisk < /usr/src/astguiclient/trunk/extras/upgrade_2.14.sql

La Verdad Honesta Sobre VICIdial DIY vs. Administrado

Mira, escribimos toda esta guia porque creemos en la transparencia. VICIdial es un software increible. Es gratuito, es potente, y en las manos correctas, supera a marcadores que cuestan 10 veces mas.

Pero “las manos correctas” esta haciendo mucho trabajo pesado en esa oracion.

Manejar VICIdial tu mismo significa que eres el administrador de sistemas, el DBA, el ingeniero de telefonia, el auditor de seguridad, y el gerente de relaciones con carriers. Cuando Asterisk se cae a las 9 AM un lunes y 50 agentes estan sentados sin hacer nada, tu eres el que esta en la terminal. Cuando tus DIDs se marcan como spam y tus tasas de conexion caen un 40%, tu eres el que esta llamando a los carriers.

ViciStack existe porque hemos hecho esto mas de 200 veces. Hemos construido y vendido mas de 200 call centers. Hemos contratado mas de 10,000 agentes. Hemos pasado mas de 15 anos aprendiendo cada peculiaridad de VICIdial, cada trampa de Asterisk, cada optimizacion de carrier que mueve la aguja.

Esto es lo que entregamos que esta guia no puede:

  • Precision de AMD del 92-96% (vs. el 80-85% que la mayoria de las instalaciones autogestionadas logran). Esa diferencia significa 7-16% mas conversaciones en vivo por hora.
  • Migracion nocturna — Todo tu entorno VICIdial, movido a nuestra infraestructura bare-metal optimizada mientras tus agentes duermen.
  • Atestacion STIR/SHAKEN de nivel A configurada correctamente desde el primer dia.
  • Gestion de reputacion de DID — Rotamos y monitoreamos tus numeros para que “Posible Spam” no se coma tus tasas de conexion.

Leiste Toda la Guia. Respeto.
Ahora imagina saltarte todo y hacer llamadas manana. Eso es ViciStack. Obtener Tu Prueba de Concepto Gratuita →

Recursos Esenciales (Marca Estos Como Favoritos)

  • Documentacion de ViciBox 12: docs.vicibox.com — Especificaciones de hardware, fases de instalacion, redes, firewall
  • Foro de VICIdial: forum.vicidial.org — Mas de 13,400 temas. Busca antes de publicar. Matt Florell (mflorell) y William Conley (williamconley) son las voces mas autorizadas
  • SVN de VICIdial: svn://svn.eflo.net:3690/agc_2-X/trunk — El codigo fuente
  • Scripts de Instalacion de Carpenox: github.com/carpenox/vicidial-install-scripts — El auto-instalador mejor mantenido para Alma/Rocky
  • Manual del Gerente de VICIdial: Amazon, $45-65 — La referencia completa de Matt Florell
  • ViciStack: vicistack.com — Cuando termines de hacerlo tu mismo

Esta guia es mantenida por ViciStack y actualizada a medida que el ecosistema de VICIdial evoluciona. Ultima verificacion contra ViciBox 12.0.2 y VICIdial SVN trunk 2.14b0.5, marzo 2026. Encontraste algo desactualizado? Dinoslo.

STIR/SHAKEN para VICIdial: La Guia Completa de Implementacion 2026

Publicado por ViciStack — la plataforma administrada de VICIdial construida por operadores, para operadores.

Si estas corriendo un call center VICIdial en 2026 y piensas que STIR/SHAKEN es solo otra casilla de cumplimiento que puedes ignorar con seguridad — felicitaciones, estas a punto de aprender como se siente una caida del 50% en tasas de respuesta.

La realidad incomoda que nadie en la comunidad VICIdial esta explicando con suficiente claridad: el cumplimiento de STIR/SHAKEN es necesario pero ni de lejos suficiente. Conseguir que tus llamadas se firmen con atestacion de nivel A es la Capa 1 de un stack de cumplimiento y reputacion de 13 capas. La mayoria de los operadores de VICIdial se detienen en la Capa 1 y luego se preguntan por que sus numeros se marcan como “Posible Spam” a los seis dias de una campana.

Que Hace Realmente STIR/SHAKEN (Y Que No)

STIR/SHAKEN es un framework de autenticacion criptografica de llamadas. Eso es todo. STIR (Secure Telephone Identity Revisited) define los estandares IETF (RFC 8224, 8225, 8226) para firmar digitalmente llamadas telefonicas. SHAKEN es el framework de despliegue norteamericano construido sobre esos estandares.

Cuando tu servidor VICIdial dispara un SIP INVITE a traves de Asterisk, esa llamada llega a tu proveedor de troncal SIP. Su Authentication Service (STI-AS) mira tres cosas: Te conocen (KYC)? Te asignaron este numero de telefono? La llamada se origino en su red?

La concepcion erronea critica que les cuesta dinero a los operadores de VICIdial cada dia: STIR/SHAKEN NO bloquea llamadas. NO etiqueta llamadas como spam. Autentica identidad. Punto.

Las decisiones reales de bloqueo y etiquetado? Esas las toman los motores de analytics de los carriers — Scam Shield de T-Mobile (impulsado por First Orion), ActiveArmor de AT&T (impulsado por Hiya), y Call Filter de Verizon (impulsado por TNS). Estos tres sistemas controlan la reputacion de llamadas para mas de 200 millones de suscriptores inalambricos de EE.UU., y actualizan sus modelos cada seis minutos.

Los Tres Niveles de Atestacion y Por Que Solo Uno Importa

Full Attestation (A): Tu carrier verifico tu identidad, tu eres dueno del numero, y la llamada empezo en su red. Este es el unico nivel que mueve la aguja en entregabilidad.

Partial Attestation (B): Tu carrier te conoce, pero no puede confirmar que eres dueno del numero especifico. Los datos de la industria muestran que las llamadas con atestacion B y C son aproximadamente tres veces mas propensas a ser marcadas como robocalls.

Gateway Attestation (C): Tu carrier no sabe de donde vino la llamada. Las llamadas con nivel C estan funcionalmente muertas al llegar.

La regla de oro: Compra tus DIDs directamente de tu proveedor de troncal SIP. Si el carrier asigno el numero y estas enviando la llamada desde su red, eso es automaticamente nivel A.

Tu Eleccion de Carrier Es Todo el Juego

VICIdial no implementa STIR/SHAKEN. Tu carrier lo hace.

Tu carrier debe tener:

  • Su propio token SPC y certificado. Desde el 18 de septiembre de 2025, la FCC prohibio los certificados STIR/SHAKEN de terceros.
  • Estar en la Robocall Mitigation Database (RMD). En agosto de 2025, la FCC removio 1,388 proveedores del RMD en un solo mes. Los call centers usando esos carriers vieron sus operaciones cesar en 48 horas.
  • Ser un CLEC con sus propios recursos de numeracion. Para nivel A automatico.
  • Infraestructura construida para marcadores predictivos. VICIdial necesita 2-3x mas canales concurrentes que agentes activos.

Tus Configuraciones de VICIdial Estan Alimentando los Algoritmos de Spam

La conexion que nadie hace con suficiente explicitud: la configuracion de tu campana de VICIdial genera patrones de llamadas especificos que los motores de analytics de carriers interpretan como firmas de spam.

AMD es el asesino silencioso de reputacion. Cuando el modulo AMD de Asterisk detecta un saludo de buzon de voz y desconecta despues de 2-3 segundos de analisis de audio, genera volumenes masivos de llamadas de muy corta duracion. Las llamadas de menos de 30 segundos son la senal de spam mas fuerte en los algoritmos de carriers.

Tu metodo de marcacion importa mas de lo que piensas. RATIO a 3:1 con 10 agentes dispara 30 llamadas simultaneas. ADAPT_AVERAGE produce el patron de trafico mas suave.

Configuraciones optimas de VICIdial para gestion de reputacion:

Dial Method:           ADAPT_AVERAGE
Auto Dial Level:       1.0  (dejar que adapt lo suba)
Adaptive Drop %:       2.0
Drop Action:           MESSAGE
Drop Exten:            8304  (grabacion safe harbor)
Dial Timeout:          28
Available Only Tally:  Y
Calls per DID per day: 75   (bajo configuraciones de DID Rotation)

El Stack Completo de Cumplimiento: 13 Capas, No Solo 1

La Cadena de Entregabilidad:

  1. Atestacion STIR/SHAKEN de nivel A (lado del carrier)
  2. Registro CNAM ($0.15-$2/numero)
  3. Inscripcion en Free Caller Registry
  4. Registro individual en motores de analytics (Hiya, First Orion, TNS)
  5. Monitoreo continuo de reputacion de numeros
  6. Branded calling (opcional pero cada vez mas importante)

La Cadena de Cumplimiento Legal:

  1. Documentacion de consentimiento (TrustedForm o Jornaya)
  2. Limpieza DNC Federal
  3. Limpieza DNC Estatal (11-13 estados mantienen listas separadas)
  4. Identificacion de celulares y cumplimiento TCPA
  5. Consultas a la Reassigned Numbers Database
  6. Limpieza de litigantes
  7. Gestion de DNC interna y grabacion de llamadas (VICIdial maneja esto nativamente)

Para un centro de 50 puestos, el cumplimiento minimo viable corre $3,000-$5,000/mes. El stack completo recomendado llega a $10,000-$18,000/mes.

Eso suena caro hasta que calculas la alternativa. El no cumplimiento le cuesta a un centro de 50 puestos un estimado de $143,000-$768,000 por mes en conexiones perdidas, salarios de agentes desperdiciados, desgaste acelerado de DIDs, y costos de remediacion.

El Camino de Implementacion en VICIdial: Tu Manual de 90 Dias

Semana 1-2: Auditoria de Carrier

  • Verifica el estado RMD de tu carrier
  • Confirma que tienen su propio token SPC y certificado
  • Solicita confirmacion de nivel de atestacion para tus DIDs especificos

Semana 3-4: Higiene de Numeros

  • Registra cada DID outbound en FreeCallerRegistry.com
  • Configura CNAM para todos los numeros
  • Ejecuta una verificacion de reputacion de referencia

Semana 5-8: Configuracion de VICIdial

  • Cambia a ADAPT_AVERAGE si estas corriendo RATIO arriba de 2.0
  • Establece porcentaje de abandono al 2% maximo
  • Cambia Drop Action de HANGUP a MESSAGE o IN_GROUP
  • Establece dial timeout a 28 segundos minimo
  • Limita llamadas por DID por dia a 75 maximo

Semana 9-12: Monitoreo y Optimizacion

  • Implementa rastreo diario de tasas de respuesta por carrier
  • Rastrea ratio de llamadas de corta duracion (llamadas contestadas de 6 segundos o menos como % del total). Manten por debajo del 15%
  • Monitorea codigos de respuesta SIP 603 — un pico repentino significa bloqueo activo

90 Dias Es Mucho Tiempo. Nosotros Podemos Hacerlo en 48 Horas.
ViciStack migra toda tu operacion a infraestructura optimizada y en cumplimiento de la noche a la manana. Inicia Tu Migracion →

La Linea Final

STIR/SHAKEN es el sistema operativo de la entregabilidad de llamadas moderna. No es toda la historia — es la Capa 1 de 13 — pero sin el, nada mas importa.

Los operadores que construyan el stack completo de cumplimiento y gestion de reputacion ahora veran tasas de respuesta, tasas de conversion, e ingresos por puesto que hacen que la inversion sea evidente por si misma. Los operadores que sigan tratando STIR/SHAKEN como problema de alguien mas se encontraran gastando mas dinero para llegar a menos personas hasta que la economia colapse por completo.

Deja de adivinar. Empieza a construir. Contacta a ViciStack →

ViciStack es la plataforma administrada de VICIdial que maneja cumplimiento STIR/SHAKEN, optimizacion de carriers, gestion de reputacion de numeros, y configuracion del marcador — para que tus llamadas realmente conecten.

Our Agent’s #1 Failure Mode: Thinking

Our Agent’s #1 Failure Mode: Thinking

Thirty-three tasks. Four projects. $32.93. Time to read the spreadsheet.

MissionControl has been running for a week. Quick context if you’re just joining: autonomous dev agent. Describe a coding task in Telegram, it spawns a Claude Code session, builds the feature, opens a PR on GitHub. Post 1 covered the 16-hour build. Posts 2 through 5 covered the bugs, the trust chain, the architecture, and a task that deployed a full MVP then got marked as failed. All anecdotal. Now there’s enough data to stop telling stories and start reading spreadsheets.

The Raw Numbers

Metric Value
Tasks created 33
Completed 12 (36%)
Failed 19 (58%)
Cancelled 2 (6%)
Total spend $32.93

36% completion rate. Worse than the 50% reported after 20 tasks. But the raw number lies — it’s weighed down by early infrastructure failures that no longer exist. Strip those out and the picture changes.

Where the Money Went

Not all failures are equal. Some cost pennies. One category cost almost $9.

“No commits produced” — 5 tasks, $8.88

The real failure mode. Five tasks where Opus ran for its full budget or turn limit and produced zero commits. Tasks #20, #23, #25, #27, #29 — all greenfield builds (“Build a full-stack…”) on $2 budgets.

The pattern is consistent: Opus starts by reading the entire codebase. Then it plans. Then it plans more. Explores alternative approaches. Considers edge cases it will never hit. By the time it’s ready to write code, the budget is gone.

$8.88 burned on thinking. Not a single line committed.

API and infra failures — 10 tasks, $0.69

Ten tasks failed on infrastructure issues — all fixed since. Anthropic API 500s during early testing (4 tasks, $0.69). Missing sudo, stale OAuth tokens, missing worker user (6 tasks, $0). Resolved in the first week. Noise in the data now.

Timeout — 1 task

Default timeout was too short for a full-stack build on a 2-core box. Bumped it. Hasn’t recurred.

CLI quirk — 1 task

--print combined with --output-format=stream-json silently requires --verbose. Without it, the CLI exits 1 with no useful error. Fixed in worker.ts.

The Funnel

Signal separated from noise:

33 total tasks
 - 10 infra/API failures (fixed, no longer relevant)
 -  2 cancelled
 -  1 timeout (fixed)
 -  1 CLI quirk (fixed)
 = 19 real attempts
 - 12 completed
 -  5 "no commits" (the actual problem)
 -  2 other failures

Strip the noise: roughly 63% on real attempts. Not bad for an autonomous agent with no human in the loop. But 5 tasks and $8.88 wasted on overthinking — that’s the leak.

Model Economics

Model Tasks Cost Avg/Task Raw Success Adjusted
Opus 30 $30.65 $1.02 30% (9/30) 50% (9/18)
Sonnet 3 $2.28 $0.76 100% (3/3) 100% (3/3)

Three data points isn’t a sample size. But the pattern is worth noting.

Opus’s failure mode is overthinking. Reads everything, considers everything, plans extensively. On a constrained budget, that means it runs out of money before it writes code. On greenfield builds — where the codebase is small and the task is “just build it” — this is exactly wrong.

Sonnet’s strength is mechanical execution. Clear task, does the task. No exploration spirals. No alternative-architecture tangents. Three tasks, three completions, $0.76 average.

This isn’t “Sonnet is better.” It’s match the model to the task shape. Opus for complex modifications to large codebases where understanding context matters. Sonnet for greenfield builds and mechanical fixes where the path is clear.

Three Changes We Made

The data pointed to three specific interventions. Shipped all three before starting the next batch.

1. Doubled All Budgets

Parameter Old New
Default task budget $5 $10
Max task budget $10 $20
Daily budget cap $50 $100

The hypothesis: “no commits produced” isn’t an intelligence failure — it’s a budget failure. Opus needs room to think and build. At $2, it can do one or the other. At $4-10, it can do both.

This is a bet. If doubling budgets converts those five failures into completions, the ROI is obvious — spending $4 to get working code beats spending $2 to get nothing. If it doesn’t, we have a deeper problem that money won’t fix.

2. Two-Phase Reviews

Single-phase reviews were inconsistent. Task #33 came back with “Done” and no detail. Task #31 found a real bug. Same prompt, different quality. Split analysis from execution.

Phase 1 — Opus analyzes. Read-only access. Reviews the PR diff against a structured checklist: logic errors, security, styling, imports, TypeScript compliance. Outputs a machine-readable verdict:

<!-- REVIEW_VERDICT {"approved": false, "issues": [
  "src/components/VotingPanel.tsx:42 — duplicate accent color logic",
  "src/components/Icon.tsx — missing style?: CSSProperties prop"
]} -->

Budget: $1.50. Model: Opus. Tools: read-only (Bash, Read, Glob, Grep).

Phase 2 — Sonnet fixes. If Phase 1 finds issues, a child task is auto-created. Sonnet gets the issue list, fixes each one, runs tsc --noEmit and npm run build, commits, and pushes.

Budget: $1.00. Model: Sonnet. Tools: full access.

Already caught real bugs in production PRs. The duplicate accent color in VotingPanel would have shipped. The missing style prop on icon components would have caused runtime issues in any consumer passing inline styles. Total review cost: $2.50 for analysis plus fixes — cheaper than a single Opus task that might or might not find anything.

3. Commit-Early Culture

The lead dev prompt now emphasizes incremental commits over perfect final PRs. Old pattern: plan everything, build everything, commit once at the end. Budget runs out before that final commit — zero output.

New pattern: commit after each meaningful unit of work. A partial feature with three commits is infinitely more valuable than a complete feature with zero commits.

Can’t force the model to commit early — it’s guidance, not enforcement. But combined with higher budgets, the goal is to shift the failure mode from “zero output” to “partial output.” Partial output can be retried. Zero output is wasted money.

What We’re Watching

Batch 2 starts now. Three questions:

Does doubling budgets convert failures? If the five “no commits” tasks would have succeeded at $4-10, the completion rate will show it. If they still fail at higher budgets, the problem is in the prompt or the task shape, not the money.

Does two-phase review scale? Three review tasks isn’t a pattern. Need 15-20 to know if the structured verdict format is reliable and if Sonnet consistently fixes what Opus finds.

Can we auto-calibrate? A greenfield build and a one-line config change shouldn’t share a budget. Considering scope-size flags — small, medium, large — that auto-set budget and timeout based on expected complexity. Not built yet. Waiting for more data to set the thresholds.

The Takeaway

Thirty-three tasks taught us more than building the system did. The system works. The question was always “how well?” Now we know: ~63% on real attempts, with a clear #1 failure mode we can measure and attack.

Not crashes. Not bugs. Not infrastructure. The agent thinks too much and ships nothing. Solvable problem. Higher budgets give it room. Two-phase reviews separate thinking from doing. Commit-early guidance reduces the blast radius of a timeout.

$32.93 for 33 tasks and a clear roadmap for improvement. Not bad.

Next up: batch 2 results — did the changes work?

4 pgvector Mistakes That Silently Break Your RAG Pipeline in Production

pgvector is the fastest way to add vector search to an existing PostgreSQL database. One extension, a few SQL commands, and you have similarity search running alongside your relational data. No new infrastructure. No new SDK. No vendor lock-in.

That simplicity is also its trap. Most teams add pgvector in a day and spend the next six months debugging performance issues that have nothing to do with the extension itself. The problems are almost always configuration mistakes that tutorials skip over.

Here are four I have seen break RAG pipelines in production, and how to fix each one before your team starts debating a migration to Pinecone.

No HNSW Index Means Full Table Scans

By default, pgvector performs exact nearest neighbor search. That means it scans every single row in the table on every query. For a prototype with 10,000 vectors, this is invisible. At 500,000 vectors, queries start crossing 800 milliseconds. At a million, you are looking at multi-second response times that make your RAG pipeline feel broken.

The fix is a single SQL statement: create an HNSW index on your vector column. HNSW (Hierarchical Navigable Small World) is an approximate nearest neighbor algorithm that trades a tiny amount of accuracy for massive speed improvements. After adding the index, the same 500K-vector query drops to under 50 milliseconds.

The reason this catches teams off guard is that pgvector works perfectly without the index. There is no warning, no error, no degradation signal. It just gets slower as data grows, and most teams blame the embedding model or the LLM before they check the database.

Dimensionality Is Not Free

OpenAI’s ada-002 embedding model outputs vectors with 1,536 dimensions. Each vector row in PostgreSQL consumes roughly 6 kilobytes of storage. Scale that to one million documents and you are looking at 6 gigabytes just for the embeddings column, before accounting for the HNSW index overhead, which can double or triple the total.

This matters because your AWS or cloud bill is not driven by the LLM API calls most teams obsess over. It is driven by the RDS instance size and storage needed to hold and index those vectors. A db.r6g.xlarge running pgvector with a million high-dimensional vectors costs real money every month.

The alternative is to use a smaller embedding model. Cohere’s embed-v3 outputs 384 dimensions and performs competitively on most retrieval benchmarks. That cuts storage by 75 percent and proportionally reduces index build time, memory usage, and query latency. Unless your use case specifically requires the nuance of 1,536 dimensions, smaller is almost always the right production choice.

Wrong Distance Function, Wrong Results

Most tutorials use cosine similarity as the default distance function, and most teams never question it. But pgvector supports three distance functions: cosine similarity, inner product, and L2 (Euclidean) distance. Each one measures “similarity” differently, and the choice directly affects which documents appear in your top-K results.

Cosine similarity measures the angle between vectors, ignoring magnitude. Inner product considers both direction and magnitude, which makes it the better choice when your embeddings are already normalized (as most modern embedding models produce). L2 distance measures the straight-line distance between vector endpoints, which works best when magnitude carries meaningful information.

The practical impact is real. I have seen cases where switching from cosine to inner product on the same dataset changed three of the top five results. If your RAG pipeline returns mediocre answers and you have already tuned your chunking strategy and prompt, check the distance function before anything else. It is a one-line configuration change that can transform result quality.

Know the Scaling Ceiling

pgvector is not a dedicated vector database. It is an extension that adds vector operations to PostgreSQL, and PostgreSQL was not designed to be a vector search engine at scale. In practice, pgvector handles up to about five million vectors comfortably on a db.r6g.xlarge instance with proper HNSW indexing. Past ten million vectors, expect query performance to degrade under concurrent load, and index build times to become a deployment bottleneck.

For most teams, this ceiling is not a problem. The majority of production RAG systems index fewer than five million documents. If you are in that range and already running PostgreSQL, adding pgvector is the right call. You avoid the operational complexity of a separate vector database, keep your data in one place, and eliminate an entire category of infrastructure to manage.

If you are genuinely approaching the ten million mark, look at pgvector-scale (which adds partitioning and distributed indexing) or evaluate a dedicated solution like Pinecone or Weaviate. But make that decision based on actual data volume, not on anxiety about future scale.

The Config Is the Bottleneck

The pattern I see repeated is predictable. Week one, a team adds pgvector and it works great. By month two, queries slow down and nobody thinks to check the index. By month four, someone proposes migrating to a managed vector database. By month six, a senior engineer adds one HNSW index and the problem disappears.

pgvector is a genuinely excellent tool for most production RAG systems. The mistakes that break it are not bugs or limitations. They are configuration gaps that tutorials gloss over and documentation buries. Fix the index, right-size the dimensions, pick the correct distance function, and know your scaling ceiling. That is the entire playbook.

What vector store is your team running in production right now?

Setting up Claude Code for success

When first starting a new project using Claude Code, it is easy to jump ahead, diving straight into coding. However, if you spend a bit of time setting up Claude Code, the outcome will be a smoother and more enjoyable development experience.

Generating a CLAUDE.md file

When first starting your project, spend time talking through the requirements of the project with Claude. Take into account your tech stack, What language are you writing it in? Are you using a framework?

You should also not only discuss the tech stack, but also how you want this built. How do you want the folder structure to be laid out? How do you want to interact with the database?

Here is a general list of things you might include:

  • Programming Language (and version)
  • Framework and routing approach
  • Dependency injection patterns
  • Database access layer (raw queries, query builder, ORM)
  • Coding standard
  • Folder and namespace conventions
  • Error handling approach
  • Unit Testing
  • Third party packages you might include.

The goal of this conversation is to produce a CLAUDE.md file — a markdown document that lives in your project root, that is automatically loaded into Claude’s context at the start of every session. It’s the source of truth that means you never have to re-explain your stack again.

What a CLAUDE.md looks like

Here’s an example CLAUDE.md file

# Project Blueprint

## Stack
- Language: PHP 8.3
- Framework: FlightPHP (micro-framework)
- Database: Postgres 18
- Coding standard: PSR-12

## Database Access
Use Flight PHP build in PDO wrapper with prepared statements exclusively.
All queries live inside the business logic — never in controllers.

## Folder Structure
app/
  Controllers/ # Thin controllers, Only reference Logic classes and UI
  Logic/       # Business logic
  config/      # Config files — DO NOT READ OR EDIT

## Code Style
Run PSR-12 checks via: vendor/bin/phpcs --standard=PSR12 app/
Auto-fix via:          vendor/bin/phpcbf --standard=PSR12 app/

## What NOT to do
- Never use static methods on service classes
- Never put SQL in controllers
- Never read from app/config/config.php
- Never commit directly — all git operations are manual

Once this file exists, every new Claude Code session starts with this context. Claude knows your conventions without being told.

The CLAUDE.md is a time saver when coding across multiple sessions. It also allows more frequent context clearing, which can help keep Claude Code focused on the current ask, lowering costs, and save time not having to explain design choices every session.

Items can also be added to the file as you come across issues and technical asks that may not have been in the CLAUDE.md file initially, building up a good repository of information that Claude can use to help build the application to your specifications.

We all have different ways of coding, and teaching Claude how you like to code through the CLAUDE.md file, will result in code similar to how you code yourself, which helps when reviewing the code, as it will seem familiar.

Guardrails

Claude Code is powerful, which is why it needs guardrails. Left unconstrained, an AI can read your environment files, touch your git history, run database commands, or make network requests you didn’t intend. None of that maliciously, just helpfully, and that’s the problem.

The permissions system in Claude Code lets you define exactly what it can and cannot do, locked into your project’s .claude/settings.json. The deny list is your non-negotiable safety layer.

There are three settings files:

  • managed-settings.json
  • settings.local.json
  • settings.json

These are hierarchical.

Managed-settings.json is the top tier, It lives outside the repo.

OS Path
macOS /Library/Application Support/ClaudeCode/managed-settings.json
Linux /etc/claude-code/managed-settings.json
Windows C:ProgramDataClaudeCodemanaged-settings.json

Instructions in the managed-settings.json cannot be overridden by instructions in the repo level json files.

  • settings.json should be committed to your repository.
  • settings.local.json should not be committed to the repository.
  • settings.local.json overrides settings.json.

The difference between these is that settings.json is shared across developers in a multi developer setup, while settings.local.json is intended for individual developer instructions.

In a business setting, putting the most critical instructions in the managed-settings.json, and limiting the use of settings.json & settings.local.json, sets the system for success. While as an individual developer, just using the settings.local.json file might be sufficient.

What belongs on the deny list

Environment files & secrets
Your .env, .env.*, certificates (.pem, .key, .p12), and SSH/AWS credential folders should be completely off-limits. Claude has no reason to read them. With config files, creating a sample config with no secret keys set is useful for giving Claude access to the config structure without giving access to the keys.

Destructive git operations
Block git commit, git push, git merge, git reset, git clean, and anything else that writes to your history. You own the git history, not Claude. Every commit should be decided on and controlled by a person. This allows for code reviewing prior to committing the code.

Direct database access
No mysql, psql, pg_dump, mysqldump, or any other direct database CLI commands. Claude should generate migration files and queries in code, not run commands directly against your data.

Network and remote access
Block curl, wget, ssh, scp, rsync, and similar tools. Claude should fetch docs through approved WebFetch domains, not make arbitrary outbound calls.

System-level commands
rm, sudo, chmod, chown, kill, crontab — anything that can damage your system or escalate privileges.

The full settings file

The allow list is just as important as the deny list. It gives explicit permission for the tools you do want Claude to be able to run. Fetching framework docs, requiring Composer packages, running your linter etc.

Special Note

Within a settings file, DENY instructions override ALLOW instructions, however when there is a hierarchy of settings files, the higher priority files instructions override the instructions from lower priority files. If something is denied in managed-settings.json, adding an ALLOW in settings.json will not override the denial in managed-setting.json

{
  "permissions": {
    "allow": [
      "Bash(composer require:*)",
      "Bash(vendor/bin/phpcbf --standard=PSR12 app/)",
      "Bash(vendor/bin/phpcs --standard=PSR12 app/)"
    ],
    "deny": [
      "Read(app/config/config.php)",
      "Edit(app/config/config.php)",
      "Read(.env)",
      "Edit(.env)",
      "Read(**/*.pem)",
      "Read(**/*.key)",
      "Read(**/*.p12)",
      "Read(**/*.pfx)",
      "Read(~/.ssh/**)",
      "Read(~/.aws/**)",
      "Read(./.git/**)",
      "Bash(git commit:*)",
      "Bash(git push:*)",
      "Bash(git merge:*)",
      "Bash(git rebase:*)",
      "Bash(git reset:*)",
      "Bash(git clean:*)",
      "Bash(git branch -d:*)",
      "Bash(git branch -D:*)",
      "Bash(git tag -d:*)",
      "Bash(git stash drop:*)",
      "Bash(git stash clear:*)",
      "Bash(git remote add:*)",
      "Bash(git remote remove:*)",
      "Bash(git remote set-url:*)",
      "Bash(git config --global:*)",
      "Bash(rm:*)",
      "Bash(rmdir:*)",
      "Bash(shred:*)",
      "Bash(dd:*)",
      "Bash(mkfs:*)",
      "Bash(fdisk:*)",
      "Bash(curl:*)",
      "Bash(wget:*)",
      "Bash(nc:*)",
      "Bash(netcat:*)",
      "Bash(nmap:*)",
      "Bash(telnet:*)",
      "Bash(ftp:*)",
      "Bash(sftp:*)",
      "Bash(scp:*)",
      "Bash(rsync:*)",
      "Bash(ssh:*)",
      "Bash(mysql:*)",
      "Bash(mysqldump:*)",
      "Bash(mysqlimport:*)",
      "Bash(mariadb:*)",
      "Bash(mariadb-dump:*)",
      "Bash(psql:*)",
      "Bash(pg_dump:*)",
      "Bash(pg_restore:*)",
      "Bash(pg_dumpall:*)",
      "Bash(redis-cli:*)",
      "Bash(sudo:*)",
      "Bash(su:*)",
      "Bash(chmod:*)",
      "Bash(chown:*)",
      "Bash(passwd:*)",
      "Bash(useradd:*)",
      "Bash(usermod:*)",
      "Bash(crontab:*)",
      "Bash(kill:*)",
      "Bash(pkill:*)"
    ]
  }
}

The pattern to remember: tight allow, broad deny. Explicitly permit the specific tools Claude needs; broadly block everything that could cause harm if run without your supervision.

Custom Commands

Custom commands are saved prompts you can used during any session to run a repeatable, structured action across your codebase.

The most valuable commands aren’t about generating code, they’re about reviewing what’s been built. Running a security audit through a project catches problems before they’re buried under layers of new code.

Custom commands live in .claude/commands/ as markdown files. Each file is a detailed prompt that Claude executes when you invoke the slash command.

Claude Code itself can help you draft these command files efficiently.

Commands worth building

/security-audit
Reviews all files in the application for SQL injection risks, unvalidated input, missing authentication checks, insecure direct object references, and exposed error messages. Outputs a prioritised list of findings with file and line references.

/architecture-review
Checks that the business rules are being followed.

/update-claude
“Review what we have just discussed and update CLAUDE.md with any new architectural patterns or ‘What not to do’ rules we have discovered”.

Example: the security audit command

Perform a security audit on the PHP codebase in app/.

Check for the following issues and report each with file
path, line number, and severity (high/medium/low):

1. SQL injection risks — any string concatenation in
   queries, any unparameterised input
2. Missing input validation — user-supplied data used
   without sanitisation or type checking
3. Authentication gaps — routes or methods that should
   require auth but don't check for a session
4. IDOR risks — fetching records by ID without verifying
   the current user owns that record
5. Verbose error exposure — raw exceptions or stack
   traces that could leak system details

Output format:
[SEVERITY] File: path/to/file.php (line N)
Issue: description
Fix: recommended action

Do not fix anything — report only. Fixes happen
in a separate pass once the full list is reviewed.

Run audits often. The best time to run a security audit is not at the end of the project , it’s during the project development. Issues caught early are easy to fix. Issues caught after three months of layered code become complex.

Claude Ignore

Similar to .gitignore, there is a .claudeignore file. Entries in the .claudeignore tells Claude that the files and folders listed are not relevant.

Folders like node_modules, vendor, logs, caches etc would be good one to add to .claudeignore.

.claudeignore is not a replacement for settings.json. Claude can still read items listed in .claudeignore, You can still ask Claude to read them to gain context.

.claudeignore saves you tokens by not having Claude read the files upfront.

Context Compacting

As a Claude Code session grows longer, it will eventually compact, compressing older parts of the conversation to free up context window space. Claude does its best to preserve what matters, but compacting loses context. Architectural decisions made three hours ago, the reasoning behind a particular pattern choice, all of that is at risk of being quietly forgotten.

This is where the CLAUDE.md file helps.

Because CLAUDE.md is loaded at the start of every session, and re-read whenever Claude needs to orient itself , your core context is never actually lost to compacting. It doesn’t live in the conversation history. It lives in the file.

Compacting can chew through hours of back-and-forth . Your architecture conventions are still right there, intact, waiting to be loaded again.

In long conversations, you may want to update the CLAUDE.md file with new information that came about during the conversation.

This can change how you work. Instead of using a single long session and worrying about context drift, you can:

  • Use /clear freely and often to start fresh without losing your architectural context
  • Treat each task or feature as its own clean session, describe the scope, build it, clear, repeat

Working in small, focused sessions with frequent clears is actually a healthier pattern than one long marathon session anyway. It forces you to scope tasks tightly, keeps the context window lean, and means Claude is always working with fresh, uncluttered context.

Time to code

With CLAUDE.md setup, and your system secured, you’ve created a safe space for Claude Code to be genuinely excellent.

This lets you focus on working through the architecture and delivering a quality product.

Setting up Claude Code isn’t about restricting the AI, it’s about defining the playing field so you can stop worrying about the boundaries and start focusing on the architecture.

I security-audited my own AI gateway and added WASM plugin support. Here’s what I found.

I've been building AegisFlow, an open-source AI gateway in Go. It sits between your apps and LLM
  providers (OpenAI, Anthropic, Ollama, etc.) and handles routing, security, rate limiting, and
  observability.

  Yesterday I sat down and did a proper security audit of the whole thing. Found more issues than I'd
  like to admit.

  The security stuff

  Timing attacks on API key validation. The tenant key lookup was using plain string comparison. An
  attacker could measure response times to progressively guess keys character by character. Switched
  to SHA-256 hashing both sides and comparing with subtle.ConstantTimeCompare. Also iterates all
  tenants on every check so there's no early-exit timing leak.

  inputHash := sha256.Sum256([]byte(apiKey))
  var match *TenantConfig
  for i := range c.Tenants {
      for _, key := range c.Tenants[i].APIKeys {
          keyHash := sha256.Sum256([]byte(key))
          if subtle.ConstantTimeCompare(inputHash[:], keyHash[:]) == 1 {
              match = &c.Tenants[i]
          }
      }
  }

  Admin panel was open by default. If you didn't set admin.token in your config, every admin endpoint
  was unauthenticated. Usage stats, provider health, tenant config, policy rules — all exposed. An
  attacker could read your exact jailbreak keywords and craft prompts around them. Now it blocks all
  data endpoints when no token is configured and logs a warning at startup.

  Rate limiter was failing open. When the limiter errored (Redis down, memory issue), it silently let
  requests through. Flipped it to return 503 instead.

  Other fixes: 10MB request body limit (was unlimited — one curl command could OOM the process), SSE
  injection in streaming responses (policy violation messages were string-concatenated into the event
  stream instead of JSON-serialized), and response cache was keyed by model+messages but not tenant
  ID, so tenant A could get tenant B's cached response.

  Jailbreak detection got real

  The keyword filter had 3 patterns. That's not a filter, that's a suggestion. Expanded to 25 covering
   the common techniques.

  But the bigger fix: added NFKC Unicode normalization. Before this, someone could write "іgnore
  previous instructions" with a Cyrillic і and walk right past the filter. Or add extra spaces:
  "ignore  previous  instructions". The normalizeText function now handles both:

  func normalizeText(s string) string {
      s = norm.NFKC.String(s)
      s = strings.Map(unicode.ToLower, s)
      s = multiSpaceRe.ReplaceAllString(s, " ")
      return strings.TrimSpace(s)
  }

  WASM plugin support

  This is the part I'm most excited about. You can now write custom policy filters in any language
  that compiles to WebAssembly and load them at runtime through config.

  policies:
    input:
      - name: "custom-toxicity"
        type: "wasm"
        action: "block"
        path: "plugins/toxicity.wasm"
        timeout: 100ms
        on_error: "block"

  The plugin ABI is four exported functions:

  ┌───────────────────────────────────────────────────┬───────────────────────────────────────────┐
  │                      Export                       │               What it does                │
  ├───────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ alloc(size) → ptr                                 │ Plugin allocates memory for host to write │
  │                                                   │  inputs                                   │
  ├───────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ check(content_ptr, content_len, meta_ptr,         │ Main check. Returns 0 (allow) or 1        │
  │ meta_len) → i32                                   │ (violation)                               │
  ├───────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ get_result_ptr() → ptr                            │ Pointer to result JSON after violation    │
  ├───────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ get_result_len() → i32                            │ Length of result JSON                     │
  └───────────────────────────────────────────────────┴───────────────────────────────────────────┘

  The host passes request metadata as JSON (tenant ID, model, provider, phase) so plugins can make
  context-aware decisions. Config-level action always overrides whatever the plugin returns — a plugin
   can't escalate its own permissions.

  Runtime is wazero, pure Go, zero CGO. Each plugin gets its own timeout and on_error behavior (block
  or allow). If a plugin crashes or returns garbage JSON, the gateway handles it gracefully based on
  your config.

  Wrote a Go example plugin that blocks messages containing "forbidden":

  //go:wasmexport check
  func check(contentPtr *byte, contentLen uint32, metaPtr *byte, metaLen uint32) int32 {
      content := unsafe.String(contentPtr, contentLen)
      if strings.Contains(strings.ToLower(content), "forbidden") {
          result, _ := json.Marshal(map[string]string{
              "action":  "block",
              "message": "content contains forbidden word",
          })
          resultBuf = result
          return 1
      }
      return 0
  }

  Build it with GOOS=wasip1 GOARCH=wasm go build -o plugin.wasm . and point your config at it. No
  gateway recompilation.

  Live request feed

  Added a fifth page to the admin dashboard. Shows every request flowing through the gateway in real
  time — latency, status codes, cache hits, policy violations. Auto-refreshes every 2 seconds. Nothing
   fancy, but useful when you're debugging or demoing.

  What's next

  Phase 3: Kubernetes operator with CRDs, multi-region routing, and A/B testing for models. The goal
  is making this work across clusters, not just on a single node.

  Repo: github.com/saivedant169/AegisFlow

  57 tests, all passing with race detector. MIT licensed. If you're proxying LLM traffic and want
  something self-hosted, take a look.

The Libravatar Problem Nobody Warned Me About (And How I Finally Fixed It)

I didn’t expect something as simple as setting a profile picture to turn into a full debugging session.

But that’s exactly what happened.

It started like any normal onboarding task. I had just set up my Fedora Account System account, everything was working fine, and I thought, “Let me quickly update my profile picture and move on.”

Simple, right?

I clicked “Change Avatar.”
I was redirected to Libravatar.
I logged in.
I uploaded my picture.

Done.

Or at least, that’s what I thought.

I went back to check my profile… and there it was, the same default avatar staring back at me like nothing had changed.

At first, I assumed it was just a delay. Maybe caching. Maybe I needed to refresh.

I refreshed.

Nothing.

I logged out and back in.

Still nothing.

That was the moment I realized this wasn’t just a small glitch. There was something deeper going on.

The Loop That Made It Worse

While trying to figure it out, I ran into another issue, the login loop.

At one point, instead of smoothly logging in, I kept getting prompted repeatedly for credentials. It felt like I was stuck between two systems that weren’t fully talking to each other.

That’s when I made a small but important decision, I cancelled the prompt.

And surprisingly, that worked.

It redirected me to the proper Fedora login page, and I was finally able to proceed cleanly.

It was my first clue that the problem wasn’t just about uploading an image… it was about how systems were connected.

Understanding the Real Problem

At this point, I stopped guessing and started thinking.

Libravatar wasn’t just storing images. It was linking identities.

And Fedora wasn’t just using usernames. It was relying on a specific identity mapping system — OpenID and email associations.

That’s when it clicked.

Uploading the image wasn’t enough.
The system needed a verified identity to attach it to.

The Fix That Finally Worked

Instead of trying to re-upload the image again, I took a different route.

I added a new email address inside Libravatar.
Then I verified it.

Came back. Refreshed.

And just like that — it worked.

The new profile picture finally showed up.

What I Learned

This wasn’t just about fixing an avatar issue.

It taught me something deeper about working in real systems:

Things don’t always fail loudly, sometimes they fail silently
Identity systems (OpenID, email mapping) matter more than they seem
Debugging isn’t about trying random fixes, it’s about understanding how things connect

Most importantly, I learned that the difference between being stuck and moving forward is often just one shift, from guessing to thinking.

Why I Decided to Document It

After solving it, I realized something:

If I ran into this, others definitely would too.

So instead of keeping the solution to myself, I turned it into a guide for the community, something simple, clear, and easy to follow.

Because in open source, solving a problem is good…

But making it easier for the next person?

That’s better.

If you’re interested in the documentation I prepared as a guide for resolving these issues, you can find it here