Delphi AI Skills 0.3.0: el lenguaje y la auditoría del código
🇮🇹 Italiano • 🇬🇧 English • 🇩🇪 Deutsch • 🇧🇷 Português
La 0.3.0 de delphi-ai-skills trae las skills Delphi genéricas que se anunciaron en el lanzamiento: diez skills open source que enseñan a Claude Code, Codex, Cursor y Gemini el lenguaje y la RTL, y cómo auditar una unit que nadie mira desde hace ocho años.
En el último párrafo del primer anuncio, en julio, estaba escrito que las siete skills de entonces eran deliberadamente verticales sobre DelphiMVCFramework, que ese era el punto de partida y no la meta, y que las siguientes tratarían de Delphi como plataforma. La 0.3.0 es la primera parte de esa pieza que faltaba.
Ahora las skills son diez. Dos de las tres nuevas no tienen relación con DMVCFramework: valen para cualquier código Delphi: un formulario VCL, un servicio Windows, una librería, una unit que nadie toca desde 2004.
En resumen
delphi: el lenguaje y la RTL, sin presuponer framework ni layout de proyecto: version gating, memoria y lifetime, cadenas, excepciones, generics, threading.delphi-code-smells: la pasada de auditoría sobre el código que ya tenéis. Warnings del compilador, memory leaks, access violation, dobles liberaciones, y para cada defecto la manera de encontrarlo.dmvcframework-jsonrpc: JSON-RPC 2.0, desde la publicación de la clase hasta el clienteIMVCJSONRPCExecutor.- Sigue siendo Apache-2.0, sigue siendo Markdown puro, sigue funcionando en Claude Code, Codex, Cursor, Gemini CLI y cualquier agente que sepa leer un archivo.
- Repositorio: github.com/danieleteti/delphi-ai-skills
La skill delphi: la que no presupone nada
Un agente IA ha leído mucho más C# y TypeScript que Object Pascal. El resultado no es código equivocado de forma evidente: es código que parece Delphi. Tiene los begin en su sitio, las mayúsculas correctas, pero por dentro lleva s[0] para leer el primer carácter, un try ... except ... finally ... end en un solo bloque, una cadena multilínea que en Delphi 11 no existe, y más ruido llegado de otros lenguajes.
La skill delphi cubre exactamente esa capa, y la parte que primero se paga sola es el version gating. El modelo no sabe con qué versión compiláis, y en la misma unit mezcla épocas distintas sin darse cuenta: una sintaxis que llegó con Florence al lado de un idioma que se escribía en 2004.
// Delphi 12 Athens y posteriores. En 11 Alexandria no compila.
var lSql := '''
select * from customers
''';
// Delphi 13 Florence y posteriores: if-then-else como expresión.
X := if Left < 100 then 22 else 45;
La skill trae la tabla de las CompilerVersion release por release, y antes que eso la regla que la hace útil: la versión de destino se determina, no se supone. El agente se lo pregunta al compilador, porque dcc32.exe --version imprime exactamente la CompilerVersion que hace falta; si no llega por ahí, mira qué Studio hay instalados; y si encuentra más de uno, o ninguno, hace una sola pregunta: ¿11 Alexandria, 12 Athens o 13 Florence? El .dproj no vale como respuesta, porque <ProjectVersion> es la versión del formato del archivo de proyecto, no la del producto, y un proyecto guardado por última vez desde un IDE viejo se abre igual de bien en uno nuevo.
De ahí en adelante se adapta. En un 13 Florence confirmado el if como expresión se usa y punto, y envolverlo en un {$IF} es ruido. En 11 no debe aparecer. Y cuando la respuesta no llega, la skill escribe para 11 Alexandria (el mínimo que asume), pone la guarda explícita y os lo declara, en vez de dejar que descubráis la decisión al compilar.
{$IF CompilerVersion >= 36} // Delphi 12 Athens y posteriores
...
{$ENDIF}
Después está el catálogo de los errores que un LLM comete en Delphi con una regularidad casi conmovedora, cada uno con la forma correcta al lado y el motivo. Unas cuantas líneas, para dar una idea:
| Mal | Bien | Por qué |
|---|---|---|
s[0] para el primer carácter |
s[1], o bien s.Chars[0] |
string es base 1, pero TStringHelper (Chars, IndexOf, Substring) está compilado en base 0. Dos bases de indexación en el mismo tipo. |
return X; |
Result := X;, o Exit(X) |
Result es una variable implícita, no una instrucción. Leída antes de asignarla, devuelve basura. |
try ... except ... finally ... end |
anidarlos | Un solo bloque no puede tener los dos. Es un error de sintaxis, no una preferencia. |
with lObj do ... |
una variable local | with enmascara los identificadores: un campo añadido a lObj seis meses después se apropia de un nombre del contexto exterior, en silencio, y compila. |
procedure Foo(AText: string) |
procedure Foo(const AText: string) |
En un tipo gestionado, const evita el refcount y la copia. |
TStringList.Create esperando que libere los Objects[] |
TStringList.Create(True) |
Los dos contenedores tienen defaults opuestos: TObjectList<T> posee, TStringList no. |
El grueso del material está en seis archivos reference/ que el agente abre solo cuando la tarea lo pide: memoria y lifetime, cadenas y encodings, excepciones, generics y RTTI, concurrencia, estilo. La ventana de contexto se mantiene libre hasta que hace falta de verdad, que es el motivo por el que una skill es un archivo en disco y no un bloque pegado al principio del chat.
Todo se ha copiado de los fuentes RTL/VCL instalados en disco, o confirmado en la docwiki. La skill sabe además que puede estar incompleta, y cuando necesita una firma que no tiene, lleva el orden de las operaciones escrito dentro: primero lee el fuente, después la docwiki, y si aun así no está segura lo dice. No estoy seguro de que TFoo.Bar exista, compruébalo en System.Classes.pas es una respuesta útil. Una respuesta segura y equivocada no lo es.
Y lee el árbol correcto: si compiláis con 12 Athens, la comprobación hay que hacerla en Studio\23.0\source\rtl, no en la copia del mismo archivo que está bajo 37.0. La RTL crece release tras release, y un tipo o una sobrecarga que existe en Florence puede sencillamente no existir en Athens. Vale también para lo que las skills traen consigo: el contenedor de DUnitX con el que se hace fallar una build por un memory leak se llama TDUnitXServiceLocator en la versión distribuida con 13 Florence y TDUnitXIoC en la distribuida con 12 Athens, con exactamente la misma llamada debajo. Un detalle así no se recuerda: se va a leer.
Una declaración, sin embargo, es solo la mitad de la respuesta. Dice cuántos parámetros hacen falta y de qué tipo, y calla sobre todo lo demás: quién libera qué, en qué orden hay que llamar a las cosas, cuál es la forma idiomática. Para eso hace falta un punto de llamada real, y las skills lo buscan en este orden: primero vuestro código, que arrastra consigo también las convenciones de la casa que hay que respetar, después los propios fuentes (la RTL usa constantemente sus propias API, así que un grep devuelve ejemplos que funcionan y no prosa de documentación), después los samples del framework o la docwiki.
Y si el agente no sabe dónde están esos fuentes, la regla es preguntar en vez de adivinar. La respuesta, eso sí, no se pierde al terminar la sesión: después de comprobar que la ruta existe, el agente os propone escribirla en el archivo de instrucciones que ya lee, el CLAUDE.md del proyecto o el AGENTS.md, en un bloque propio:
<!-- delphi-local-sources -->
Delphi RTL/VCL source: C:\Program Files (x86)\Embarcadero\Studio\23.0\source (12 Athens, CompilerVersion 36.0)
DelphiMVCFramework checkout: C:\DEV\dmvcframework (sources/ + samples/)
<!-- /delphi-local-sources -->
Ese bloque es lo primero que el agente mira cuando arranca la sesión, y la pregunta se hace una vez por proyecto en lugar de una vez al día. Si una ruta ya no existe, o cambiáis de versión de Delphi, os lo dice y vuelve a preguntar: prefiere admitir que no sabe antes que rescatar algo de la memoria.
La skill delphi-code-smells: primero la máquina, después la opinión
La otra mitad del oficio no es escribir código, es mirar el que ya está. Aquí es donde los agentes se comportan peor, y no porque se equivoquen: porque son educados. Pedís una review y os llega una página de observaciones sobre los nombres de las variables, el orden de las uses y la longitud de los métodos. Cero leaks. Una review que devuelve quince notas de estilo y ningún problema de lifetime no es una review, es una opinión.
delphi-code-smells impone un orden de ataque, y los dos primeros puntos no admiten juicio humano alguno:
- Compilar con warnings y hints activos, y leer cada línea de la salida. Gratis, objetivo, y con más rendimiento que cualquier otra cosa.
- Ejecutar con
ReportMemoryLeaksOnShutdown := True, y si existe una suite de tests, ejecutarla. - Ownership a mano: cada
Createde la unit, quién lo libera, por qué caminos, incluido el que lanza. - Gestión de las excepciones: cada
exceptsinon, cada handler vacío, cadatry/exceptque quería ser untry/finally. - Concurrencia: todo lo que se puede alcanzar desde un
TThread.Executeo desde el cuerpo de unTTask.Run. - El resto. Naming,
with, métodos largos, números mágicos.
La regla que mantiene la lista en pie está escrita en la skill de forma poco diplomática: un leak que el compilador no ve gana a una convención de naming, siempre. Y cada defecto hay que reportarlo con lo que cuesta en runtime, no con lo feo que es de leer.
El defecto número uno de la clasificación es este, y lo sigo viendo todas las semanas en mis consultorías:
// MAL: el constructor está DENTRO del try
try
lList := TStringList.Create;
...
finally
lList.Free; // si Create lanza, aquí se llama a Destroy sobre memoria sin inicializar
end;
// BIEN
lList := TStringList.Create;
try
...
finally
lList.Free; // .Free es nil-safe: "if x <> nil then x.Free" es ruido
end;
Dos líneas cambiadas de sitio. La primera versión produce un access violation solo cuando el constructor falla, o sea casi nunca, o sea el martes por la mañana en casa del cliente que no reinicia el servidor desde hace ocho meses.
La skill trae también la pasada de cinco minutos: un puñado de greps ordenados por rendimiento, del constructor dentro del try a la excepción tragada por un except end, del FreeAndNil sobre una variable local al FreeOnTerminate. Son los golpes que un humano no tiene ganas de dar y que una máquina da en tres segundos.
rg -n -U 'try\b[^;]*?\n\s*\w+\s*:=\s*T\w+\.Create' # constructor DENTRO del try
rg -n -P '(?s)except\s*(//[^\n]*\n\s*)*end' # excepción tragada
rg -n 'FreeOnTerminate' # lifetime de los threads
Luego está la parte que hace la auditoría repetible en vez de episódica: cómo se lee de verdad el informe del memory manager, cuándo hace falta RegisterExpectedMemoryLeak, y cómo se configura DUnitX para que un leak haga fallar la build. Un leak encontrado una vez es una jornada de trabajo. Un leak que a partir de mañana rompe la pipeline es una clase de bug cerrada.
Una última regla, que es mi favorita porque vale también para las personas: no reportes nunca un smell del que no sepas decir cómo se encuentra. Si no hay un código de warning, una herramienta o un grep que lo demuestre, es una preferencia, y nadie la había pedido.
Y además, JSON-RPC
La tercera skill nueva, dmvcframework-jsonrpc, vuelve al perímetro del framework: un endpoint JSON-RPC 2.0 en DelphiMVCFramework es una clase Delphi normal publicada sobre un segmento de URL, sin atributos de routing por método. La skill cubre qué es invocable y qué no, la distinción entre function (request) y procedure (notification), los parámetros nominales y posicionales, las tres reglas de ownership sobre quién libera qué, los códigos de error, los hooks, y el cliente IMVCJSONRPCExecutor para llamar a ese endpoint desde Delphi.
Las diez skills, en una tabla
| Skill | Qué cubre |
|---|---|
delphi |
El lenguaje y la RTL: version gating, inline var, memoria y lifetime, cadenas y encodings, excepciones, System.Generics.Collections, RTTI, threading, convenciones. |
delphi-code-smells |
La review: warnings y hints que indican un bug real, warnings-as-errors, búsqueda de leaks, cómo hacer fallar una build por un leak, análisis estático, catálogo de smells con la manera de encontrarlos. |
dmvcframework |
El núcleo del framework: bootstrap y engine, controladores y functional action, routing, IMVCResponse, ownership, ORM ActiveRecord, Repository, contenedor DI, validación, middleware, JWT, SSE, dotEnv. |
dmvcframework-minimal-api |
Rutas como métodos anónimos: grupos de rutas (Prefix, MapGet, MapPost), binding guiado por los tipos, subida de archivos, endpoint filter y HTTP filter, .AsWeb. |
dmvcframework-webapp |
Aplicaciones web server-side: TemplatePro, herencia de plantillas, fragmentos, ViewData, login con cookie/JWT, archivos estáticos, helpers HTMX del lado Delphi. |
dmvcframework-ui |
La capa de presentación del wizard: Bootstrap 5.3, baselayout.html, los tokens de style.css, modo oscuro, toasts. |
dmvcframework-security |
Secure coding en el servidor: control de acceso e IDOR, mass assignment, inyección SQL, XSS en TemplatePro, CSRF, path traversal, subida de archivos, SSRF, cabeceras, hardening del JWT, secretos. |
dmvcframework-jsonrpc |
JSON-RPC 2.0: publicación, request y notification, parámetros, ownership, errores, hooks, cliente. |
dmvcframework-testing |
DUnitX, IMVCServer in-process, IMVCRESTClient, tests CRUD, de autenticación y de autorización, fixtures de base de datos. |
htmx-skill |
El índice de cada página de la documentación oficial de htmx.org, para que el agente lea la página correcta en vez de recordar htmx a su manera. |
Las dos skills Delphi no tienen requisitos: ningún layout de proyecto, ningún framework. Las siete de DMVCFramework parten de un proyecto creado con el wizard del IDE, y dmvcframework-security la arrastra de oficio cualquier endpoint que reciba entrada de un cliente.
Cómo se instalan y cómo se usan
git clone https://github.com/danieleteti/delphi-ai-skills.git
cd delphi-ai-skills
install_in_claude.bat
Para Claude Code se acaba aquí: las skills se descubren solas. Para los demás agentes están install_in_codex.bat, install_in_cursor.bat e install_in_gemini.bat, que copian las skills y escriben el puntero en el archivo de instrucciones correcto (AGENTS.md, .cursor/rules/*.mdc, GEMINI.md), porque esos agentes no las descubren por su cuenta. Cada script acepta una ruta de proyecto, si preferís versionar las skills en el repositorio y dárselas a todo el equipo:
install_in_claude.bat C:\DEV\mi-proyecto
A las skills no se las “llama”: se describe la tarea y el agente elige. El disparador más fuerte es nombrar la tecnología. “Encuentra el leak” es ambiguo, “encuentra el leak en esta unit Delphi” no.
¿Esta unit compila en Delphi 11, o estoy usando sintaxis que existe solo a partir de Athens? Este servicio pierde memoria en unos pocos días: encuentra el punto. Haz una review de esta unit y dime qué está mal de verdad, no el estilo. ¿Qué warnings del compilador estoy ignorando que esconden un bug real? Haz que la build falle cuando hay un memory leak. Este código corre en un thread y toca una label VCL: ¿qué tiene de malo? ¿
TObjectList<T>conOwnsObjectso unTList<T>simple?
Cuando queréis la garantía, basta con nombrar la skill: en Claude Code con /delphi o /delphi-code-smells, en los demás citando la ruta (“lee skills/delphi-code-smells/SKILL.md, después revisa esta unit”). Funciona en todas partes, porque es un archivo de texto, no una función.
Un consejo que vale los diez segundos que cuesta: si tenéis los fuentes de DelphiMVCFramework en disco, decídselo al agente al principio de la sesión (“los fuentes de DMVCFramework están en C:\DEV\dmvcframework”). Las skills están instruidas para verificar en vez de adivinar, y con los fuentes al alcance verifican mucho mejor.
Por qué las skills no pueden contener un nombre inventado
Hay un problema de fondo en un proyecto cuyo único propósito es impedir que un agente se invente nombres de API: si quien se inventa uno es la skill, el daño es más grave que antes, porque ahora el error tiene el aire autorizado de la documentación.
Por eso las skills no salen si no pasan por una pipeline que las compara con el código de verdad: los fuentes de DelphiMVCFramework y la RTL de todas las versiones de Delphi soportadas. Cada nombre citado tiene que ser un nombre que exista ahí dentro. Si falta uno solo, la release se detiene, y no es una opinión que se pueda discutir en review: o el nombre está en los fuentes o no está en las skills.
Es el control que hizo aflorar el defecto del DUnitX de 12 Athens contado más arriba, y lo hizo aflorar aquí en vez de en vuestra casa, que es exactamente el objetivo.
Lo que una verificación así no puede deciros es si esa API está usada bien: para eso hace falta un compilador, y para un error de ownership hace falta ejecutar el programa. Es el primero de los tres niveles con los que se controlan las skills, y es el que cuesta tan poco que puede quedarse encendido siempre.
Materiales y vídeos en Patreon
Las skills le dicen al agente qué es verdad. Queda fuera el cómo: cómo es una sesión de trabajo real, dónde conviene pararse, qué pedir y en qué orden, cuándo el agente está tomando un camino que os va a costar dos horas.
En las próximas semanas publicaré bastante material, escrito y en vídeo, en la página de Patreon de DelphiMVCFramework: sesiones enteras sobre Delphi y sobre DMVCFramework con las skills trabajando, dejando dentro los puntos en los que algo sale torcido, porque son la parte que enseña.
El repositorio sigue siendo Apache-2.0 y completo: nada de lo que hace falta para usar las skills está detrás de una suscripción. Patreon es el sitio donde encontráis el material explicativo, y es también la manera con la que quien quiere sostiene el trabajo sobre DMVCFramework y sobre todo lo que gira a su alrededor. Si os resulta útil, el canal es ese. Y si preferís coger las skills e ir por vuestro camino, está igual de bien: precisamente para eso están en GitHub.
Preguntas frecuentes sobre delphi-ai-skills 0.3.0
¿Qué hay de nuevo en la 0.3.0 de delphi-ai-skills?
Tres skills más respecto a la primera release, diez en total: delphi (el lenguaje y la RTL, sin ningún framework), delphi-code-smells (la review del código existente) y dmvcframework-jsonrpc (JSON-RPC 2.0). La 0.3.0 corrige además dos afirmaciones equivocadas en la reference sobre la memoria de la skill delphi.
¿Tengo que usar DelphiMVCFramework para usar estas skills?
No, y estaba previsto desde el primer anuncio. delphi y delphi-code-smells no presuponen ningún framework ni ningún layout de proyecto: valen para un formulario VCL, un servicio Windows, una librería, una unit heredada. Las otras siete siguen siendo específicas de DelphiMVCFramework.
¿Qué hace la skill de auditoría sobre el código Delphi?
delphi-code-smells pone la review en el orden correcto: primero el compilador con warnings y hints activos, después la ejecución con ReportMemoryLeaksOnShutdown := True, después el ownership a mano, las excepciones, la concurrencia y solo al final el estilo. Cubre los warnings que indican un bug real (con su código, por ejemplo W1035), $WARN y los warnings-as-errors, cómo se lee un informe de leaks, cómo se hace fallar una build por un leak con DUnitX, los analizadores estáticos de terceros, y un catálogo de defectos en el que cada entrada dice lo que cuesta en runtime y cómo se encuentra.
¿Las skills se ocupan de la seguridad?
En el lado servidor sí, y es dmvcframework-security: una dependencia obligatoria de todas las skills DMVCFramework, aplicada a cualquier endpoint que reciba entrada de un cliente. Cubre control de acceso e IDOR, mass assignment, inyección SQL, XSS en TemplatePro, CSRF, path traversal, subida de archivos, SSRF y open redirect, cabeceras de seguridad, hardening del JWT y gestión de los secretos. delphi-code-smells, en cambio, es una auditoría de defectos, no una auditoría OWASP: se ocupa de leaks, access violation, dobles liberaciones y resultados silenciosamente equivocados.
¿Sobre qué versión de Delphi funcionan?
Sobre 11 Alexandria, 12 Athens y 13 Florence. La skill determina cuál tenéis: interroga al compilador con dcc32.exe --version, en su defecto mira qué Studio hay instalados, y si sigue habiendo ambigüedad os pregunta cuál usáis, en vez de adivinar. Con la versión conocida, se adapta. Cuando la respuesta no llega, el objetivo es Delphi 11 Alexandria, con una guarda {$IF CompilerVersion >= ...} alrededor de todo lo que dependa de la versión. El contenido de la skill está verificado sobre los fuentes RTL/VCL de Delphi 13 Florence. Las skills DMVCFramework apuntan a la 3.5.0 (silicon).
¿Con qué agentes IA funcionan? Claude Code, Codex, Cursor, Gemini CLI, Windsurf, Continue y cualquier agente capaz de leer instrucciones en Markdown. El repositorio incluye el script de instalación para los cuatro primeros. En los agentes distintos de Claude Code la carga depende de cuánto respete ese agente su propio archivo de instrucciones, así que conviene nombrar la tecnología en el prompt, o bien la propia skill.
¿Cómo sé que las skills no contienen nombres de API inventados? Porque no pueden. Antes de cada release, una pipeline compara cada nombre citado en las skills con el código de verdad: los fuentes de DelphiMVCFramework y la RTL de las versiones de Delphi soportadas. Si un solo identificador no existe ahí dentro, esa release no sale. No es una relectura atenta hecha por alguien competente, es una barrera: la misma disciplina que las skills imponen al agente, aplicada a las skills. En la práctica, cuando una skill afirma algo sobre una API, esa afirmación ya se ha contrastado con el código en vez de con la memoria de alguien. Lo que el control no prueba es que la API esté usada bien: para eso hacen falta el compilador y la ejecución, que son los dos niveles de encima.
El camino por delante
Seguimos en 0.x, y la forma del conjunto hay que considerarla inestable: las skills podrán dividirse, unirse, renombrarse o eliminarse a medida que el uso real muestre qué hace falta de verdad. La 1.0.0 llegará cuando el conjunto se haya demostrado en suficientes proyectos reales. Mientras tanto, los avisos valen más que cualquier roadmap: si una skill os ha hecho escribir código equivocado, ese es el defecto que quiero ver primero.
El criterio para contribuir sigue siendo uno solo: cada afirmación debe ser verificable en los fuentes, citando el archivo. Ningún nombre de API escrito de memoria. Es la disciplina que pedimos a los agentes, y sería curioso no aplicárnosla a nosotros.
El proyecto está aquí: github.com/danieleteti/delphi-ai-skills. Las issues y las pull request son bienvenidas.
Un agente que escribe Delphi sin saber Delphi produce código que compila mal y envejece peor. Un agente instruido produce código que podéis leer dentro de dos años sin preguntaros quién lo escribió. La diferencia, por ahora, son diez archivos Markdown.
Comments
comments powered by Disqus