Saltar al contenido
Curso Claude Code en equipo: una sola forma de trabajar
17/29 Bloque opcional · El paquete Composer de convenciones Compartir el CLAUDE.md del equipo entre proyectos con un paquete Composer y @import
Tu lectura Quedan 38 min
Lección 17 de 29 · Bloque opcional · El paquete Composer de convenciones

Compartir el CLAUDE.md del equipo entre proyectos con un paquete Composer y @import

38 min de lectura Claude Code 2.1

Hola, bienvenido. Con esta lección empieza el bloque opcional del paquete Composer de convenciones. Vamos a crear el paquete cursosdesarrolloweb/conventions con la guideline del equipo y sus 3 primeros documentos de convención, a instalarlo en helpdesk desde Sail y a importarlo en la primera línea de CLAUDE.md. Así, lo que dice cómo es el código del equipo se escribe en un solo sitio y llega igual a todos los repos.

Si tu equipo no comparte convenciones de código entre proyectos, porque solo tiene uno o porque cada proyecto sigue las suyas, puedes saltarte este bloque entero. Los bloques que vienen después funcionan igual con el paquete y sin él. Y si te saltaste el bloque de QA, guardia y subagentes, puedes seguir aquí sin problema. Cuando una lección de este bloque modifique un archivo del plugin que cambió el bloque que no hiciste, copia el archivo completo en vez de aplicar el diff. Del CHANGELOG.md, copia solo la entrada nueva.

En la primera lección repartimos la configuración del equipo en 3 sitios, y dijimos que el paquete Composer contiene cómo es el código. Hasta ahora no lo hemos necesitado, porque el plugin team solo lleva cómo se trabaja. Pero las convenciones de código también se copiaron de repo en repo. Cuando Marta compara los .ai/docs/ de sus repos, 9 de los 15 documentos son distintos en al menos un repo. Y en uno de ellos alguien cambió la guideline del proyecto, .ai/guidelines/project.md, y no volvió a compilar CLAUDE.md con Boost, así que Claude siguió leyendo la versión anterior.

El paquete resuelve las 2 cosas. Los documentos viven en el paquete y llegan a cada repo con composer update, con su versión apuntada en composer.lock. Y la guideline que resume las convenciones no se compila: CLAUDE.md la importa desde vendor/ con una sola línea, así que lo que lee Claude es siempre lo que trae la versión instalada del paquete.

Qué lleva el paquete y por qué se instala en require

El paquete es un repo más en team/, junto a claude-plugins y helpdesk. Al terminar esta lección va a tener esto:

Estructura
team/
├── claude-plugins/
├── conventions/
│ ├── composer.json
│ ├── resources/
│ │ ├── docs/architecture/
│ │ │ ├── actions.md
│ │ │ ├── models.md
│ │ │ └── viewmodels.md
│ │ ├── guidelines/
│ │ │ └── conventions.md
│ │ └── rules/
│ │ ├── actions.md
│ │ ├── models.md
│ │ └── viewmodels.md
│ └── src/
│ └── ConventionsServiceProvider.php
└── helpdesk/

resources/guidelines/conventions.md es lo que va a importar CLAUDE.md. resources/docs/ guarda los documentos de convención, que Claude lee cuando va a crear una pieza. Y resources/rules/ guarda las rules que remiten a esos documentos, listas para copiarlas a cada repo.

El paquete se instala en require y no en require-dev. En esta lección solo lleva texto, pero en la siguiente llevará código que el proyecto necesita para funcionar, y lo que está en require-dev no se instala en producción con composer install --no-dev. Las herramientas de QA (Pint, Larastan, Rector y Pest) siguen en el require-dev de cada proyecto, como hasta ahora.

Es un repo nuevo, así que le vamos a abrir su pestaña. Como la carpeta conventions todavía no existe, la abrimos en ~/code/team. Desde cualquier pestaña de la sesión:

Terminal
zellij action new-tab --name conventions --cwd ~/code/team

En la pestaña nueva, reescribimos el layout con todas las pestañas, la de conventions ya con la carpeta del repo, que vamos a crear enseguida y en la que se va a quedar:

Terminal
cat > ~/.config/zellij/layouts/team.kdl <<'EOF'
layout {
default_tab_template {
pane size=1 borderless=true {
plugin location="zellij:tab-bar"
}
children
pane size=1 borderless=true {
plugin location="zellij:status-bar"
}
}
tab name="helpdesk" cwd="~/code/team/helpdesk" focus=true {
pane
}
tab name="claude-plugins" cwd="~/code/team/claude-plugins" {
pane
}
tab name="helpdesk-lucia" cwd="~/code/team/helpdesk-lucia" {
pane
}
tab name="helpdesk-aitor" cwd="~/code/team/helpdesk-aitor" {
pane
}
tab name="conventions" cwd="~/code/team/conventions" {
pane
}
}
EOF
Representación de Zellij con el layout del curso: arriba las pestañas helpdesk, claude-plugins, helpdesk-lucia, helpdesk-aitor y conventions, con conventions activa; en el centro el prompt en ~/code/team; y abajo la barra de atajos con Ctrl y Alt

Y en la misma pestaña, vamos a crear las carpetas:

Terminal
mkdir -p conventions/src conventions/resources/guidelines conventions/resources/docs/architecture conventions/resources/rules

Vamos a empezar por el manifiesto del paquete, conventions/composer.json:

conventions/composer.json Nuevo +23
1{
2 "name": "cursosdesarrolloweb/conventions",
3 "description": "Cómo es el código en los proyectos Laravel del equipo",
4 "type": "library",
5 "version": "1.0.0",
6 "license": "proprietary",
7 "require": {
8 "php": "^8.4",
9 "illuminate/support": "^13.0"
10 },
11 "autoload": {
12 "psr-4": {
13 "Cursosdesarrolloweb\\Conventions\\": "src/"
14 }
15 },
16 "extra": {
17 "laravel": {
18 "providers": [
19 "Cursosdesarrolloweb\\Conventions\\ConventionsServiceProvider"
20 ]
21 }
22 }
23}

El nombre, cursosdesarrolloweb/conventions, es el que pondrá cada repo en su require, y debes cambiar cursosdesarrolloweb por tu usuario o tu organización, igual que en el namespace. license es proprietary, que es lo que la documentación de Composer indica para el código que no es de código abierto.

Con version nos apartamos de lo habitual. La documentación de Composer recomienda no escribirla cuando se puede deducir de los tags del repo, y en un paquete público es lo normal. Nosotros la vamos a escribir siempre, por 2 motivos. El primero es que el repositorio path que vamos a usar enseguida la necesita: sin ella, Composer ve la rama como dev-main y composer require no encuentra ninguna versión que cumpla ^1.0. El segundo es que el tag de cada versión lo vamos a crear a partir de este campo, así que siempre coinciden.

extra.laravel.providers registra el service provider con el package discovery de Laravel, así que ningún repo tiene que añadirlo a mano. Vamos a crear el provider vacío, en conventions/src/ConventionsServiceProvider.php:

conventions/src/ConventionsServiceProvider.php Nuevo +9
1<?php
2
3declare(strict_types=1);
4
5namespace Cursosdesarrolloweb\Conventions;
6
7use Illuminate\Support\ServiceProvider;
8
9final class ConventionsServiceProvider extends ServiceProvider {}

De momento no hace nada. Más adelante registrará el comando que instala el paquete en un repo, y lo creamos ya para que Laravel lo descubra desde la primera versión.

Lo que queda de esta lección
  1. 02La guideline, los docs y las rules del paquete
  2. 03El primer commit y el tag v1.0.0
  3. 04Composer desde Sail: un repositorio path con un volumen
  4. 05La línea del import en CLAUDE.md
  5. 06Mover los docs y apuntar las rules a vendor/
  6. 07Medir lo que se ha quedado en el repo
Sigue leyendo con tu suscripción El curso completo, con su proyecto final, el certificado y el foro, está incluido en la suscripción. Ver los planes