ratifact 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ratifact-1.0.0/.gitignore +16 -0
- ratifact-1.0.0/LEEME.md +455 -0
- ratifact-1.0.0/LICENSE +21 -0
- ratifact-1.0.0/PKG-INFO +284 -0
- ratifact-1.0.0/README.md +254 -0
- ratifact-1.0.0/pyproject.toml +54 -0
- ratifact-1.0.0/ratifact/__init__.py +7 -0
- ratifact-1.0.0/ratifact/app.py +202 -0
- ratifact-1.0.0/ratifact/archivos.py +98 -0
- ratifact-1.0.0/ratifact/build.py +227 -0
- ratifact-1.0.0/ratifact/busqueda.py +134 -0
- ratifact-1.0.0/ratifact/catalogo.py +138 -0
- ratifact-1.0.0/ratifact/cli.py +67 -0
- ratifact-1.0.0/ratifact/clientes.py +206 -0
- ratifact-1.0.0/ratifact/clientes_toml.py +210 -0
- ratifact-1.0.0/ratifact/config.py +264 -0
- ratifact-1.0.0/ratifact/delegacion.py +175 -0
- ratifact-1.0.0/ratifact/doctor.py +299 -0
- ratifact-1.0.0/ratifact/esquema.py +204 -0
- ratifact-1.0.0/ratifact/herramientas/__init__.py +3 -0
- ratifact-1.0.0/ratifact/herramientas/contexto_documentos.py +280 -0
- ratifact-1.0.0/ratifact/herramientas/decisiones.py +261 -0
- ratifact-1.0.0/ratifact/herramientas/pendientes_sesiones.py +78 -0
- ratifact-1.0.0/ratifact/herramientas/proyectos.py +300 -0
- ratifact-1.0.0/ratifact/herramientas/tareas.py +286 -0
- ratifact-1.0.0/ratifact/herramientas/tareas_brief.py +184 -0
- ratifact-1.0.0/ratifact/informe.py +182 -0
- ratifact-1.0.0/ratifact/informe_memoria.py +279 -0
- ratifact-1.0.0/ratifact/instalacion.py +247 -0
- ratifact-1.0.0/ratifact/instalar.py +262 -0
- ratifact-1.0.0/ratifact/instalar_extras.py +193 -0
- ratifact-1.0.0/ratifact/integraciones/__init__.py +3 -0
- ratifact-1.0.0/ratifact/integraciones/base.py +24 -0
- ratifact-1.0.0/ratifact/integraciones/codegraph.py +19 -0
- ratifact-1.0.0/ratifact/integraciones/engram.py +14 -0
- ratifact-1.0.0/ratifact/integraciones/gentle_ai.py +23 -0
- ratifact-1.0.0/ratifact/integraciones/registro.py +108 -0
- ratifact-1.0.0/ratifact/listado.py +85 -0
- ratifact-1.0.0/ratifact/migracion_v2.py +206 -0
- ratifact-1.0.0/ratifact/modelos.py +131 -0
- ratifact-1.0.0/ratifact/plantillas.py +51 -0
- ratifact-1.0.0/ratifact/procesos.py +168 -0
- ratifact-1.0.0/ratifact/prompts.py +29 -0
- ratifact-1.0.0/ratifact/registros.py +258 -0
- ratifact-1.0.0/ratifact/retirado.py +88 -0
- ratifact-1.0.0/ratifact/rutas.py +73 -0
- ratifact-1.0.0/ratifact/skills/run-task/SKILL.md +56 -0
- ratifact-1.0.0/ratifact/upgrade.py +195 -0
- ratifact-1.0.0/ratifact/upgrade_aplicar.py +185 -0
- ratifact-1.0.0/ratifact/vocabulario.py +82 -0
- ratifact-1.0.0/ratifact/workers.py +197 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Configuración personal (rutas absolutas de cada usuario): ver projects.example.json
|
|
2
|
+
projects.json
|
|
3
|
+
# Respaldos de configuración (contienen rutas personales)
|
|
4
|
+
projects.json.bak-*
|
|
5
|
+
*.bak-ratifact-*
|
|
6
|
+
# Telemetría local
|
|
7
|
+
logs/
|
|
8
|
+
# Python
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.pyc
|
|
11
|
+
*.tmp
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
# Estado local del agente
|
|
14
|
+
.atl/
|
|
15
|
+
# Paquete (uv build)
|
|
16
|
+
dist/
|
ratifact-1.0.0/LEEME.md
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
# ratifact (antes memoria-proyectos) — instalación
|
|
2
|
+
|
|
3
|
+
English: [README.md](README.md) (qué es, instalación, primer proyecto, /run-task, comandos, integraciones, upgrade).
|
|
4
|
+
|
|
5
|
+
Servidor MCP local: comando `ratifact serve` (paquete instalable, sección 0; `servidor.py` es su envoltorio hasta 1.1). Proyectos registrados: `projects.json`.
|
|
6
|
+
Desde la v1 el contrato está en inglés: herramientas, parámetros, descripciones y respuestas
|
|
7
|
+
(`docs/v1-english-naming.md`). Pasos para usuarios existentes después de actualizar: `docs/upgrade-v1.md`.
|
|
8
|
+
|
|
9
|
+
Variables de entorno: `RATIFACT_CONFIG` (projects.json), `RATIFACT_LOG` (telemetría) y `RATIFACT_BASE` (carpeta de
|
|
10
|
+
proyectos). Las anteriores `MEMORIA_PROYECTOS_*` siguen funcionando como respaldo hasta 1.1 (gana la nueva; el log del
|
|
11
|
+
servidor avisa una vez por variable). Sin variable, la configuración es `~/.config/ratifact/projects.json` si existe, si
|
|
12
|
+
no `~/.config/memoria-proyectos/projects.json` (no se mueve ni reescribe nada).
|
|
13
|
+
|
|
14
|
+
## 0. Comando `ratifact` (instalación fija)
|
|
15
|
+
El repositorio es un paquete instalable (`pyproject.toml`, MIT). `uv tool install ratifact` (desde PyPI) o
|
|
16
|
+
`uv tool install ~/Projects/.memoria-proyectos` (desde la copia local) instala una copia fija (no editable) y deja el
|
|
17
|
+
ejecutable `~/.local/bin/ratifact`; después de cada integración en main: `uv tool install --reinstall
|
|
18
|
+
~/Projects/.memoria-proyectos`, reiniciar los clientes y verificar con `ratifact doctor` (procedimiento completo en
|
|
19
|
+
"Desfase de versiones", más abajo). Los clientes se configuran con `ratifact install --apply`
|
|
20
|
+
(sección 1); las configuraciones viejas con `servidor.py` siguen funcionando hasta 1.1.
|
|
21
|
+
|
|
22
|
+
| Subcomando | Qué hace |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `ratifact serve` | Servidor MCP por stdio (lo que lanzan los clientes). `servidor.py` es un envoltorio de esto hasta 1.1. |
|
|
25
|
+
| `ratifact install [--apply] [--client NOMBRE]` | Configura los clientes MCP que encuentra (Claude Desktop, Claude Code, Pi, Codex (experimental)) y enlaza `/run-task` (sección 1). Sin `--apply` solo muestra el plan. |
|
|
26
|
+
| `ratifact report [--days N] [--project P] [--log RUTA]` | Resumen del uso (sección 7). `analizar_uso.py` es un envoltorio hasta 1.1 (acepta `--dias`/`--proyecto`). |
|
|
27
|
+
| `ratifact doctor` | Solo lectura: versión y de dónde corre (instalación fija o copia de trabajo, con aviso), configuración usada y grafía de sus claves, por proyecto código, memoria (ruta, esquema, `.memorias/` viejo o `.ratifact/` nuevo, estado git) e integraciones detectadas, log, variables `MEMORIA_PROYECTOS_*` y acciones pendientes, el estado de cada cliente (configurado con ratifact / configuración vieja / sin configurar / no encontrado), el build, si la fuente local es más nueva que la instalación y los procesos `ratifact serve` vivos, marcando los anteriores a la instalación. Sale con 0 si no hay nada pendiente, 1 si hay acciones. Si no existe la configuración por defecto pero hay servidores corriendo con `RATIFACT_CONFIG`/`MEMORIA_PROYECTOS_CONFIG` o un `projects.json` junto al repositorio de origen, sugiere el comando exacto (`RATIFACT_CONFIG=<ruta> ratifact upgrade`). |
|
|
28
|
+
| `ratifact upgrade` | Paso explícito, con todos los clientes cerrados. Sin opciones solo muestra el plan; `--apply` lo ejecuta: migra a v2 las memorias v1, mueve `<base>/.memorias/<p>` a `<base>/.ratifact/<p>` (las rutas propias nunca se mueven), escribe `~/.config/ratifact/projects.json` con claves en inglés y renombra el viejo a `projects.json.bak-v1`, regenera las vistas y copia el log viejo. Aborta si hay un servidor corriendo con esa configuración, un `.lock` tomado o una memoria con cambios sin commit (cabecera "Aborted — nothing was changed:", el plan y los motivos; código de salida 1); idempotente; si un paso falla, lo revierte. |
|
|
29
|
+
| `ratifact --version` | Versión instalada. |
|
|
30
|
+
|
|
31
|
+
## 1. Clientes MCP: `ratifact install`
|
|
32
|
+
Una vez por equipo, con el comando instalado (sección 0):
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
ratifact install # plan: qué clientes encontró y qué cambiaría; no toca nada
|
|
36
|
+
ratifact install --apply # lo hace, con respaldo de cada archivo
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Configura los clientes que encuentra: Claude Desktop (`~/.config/Claude/claude_desktop_config.json`; en macOS
|
|
40
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`), Claude Code (`claude mcp add --scope user` si existe
|
|
41
|
+
el comando `claude`; si no, `~/.claude.json`), Pi (`~/.pi/agent/mcp.json`) y Codex, experimental (`~/.codex/config.toml`). Cada uno
|
|
42
|
+
queda con el servidor `ratifact`, comando = ruta absoluta del ejecutable instalado, `args ["serve"]` y sin variables de
|
|
43
|
+
entorno; el resto del archivo (otros MCP, preferencias) queda idéntico. Antes de escribir guarda
|
|
44
|
+
`<archivo>.bak-ratifact-<fecha>` junto al archivo (los archivos dentro de un proyecto —`CLAUDE.md`, `AGENTS.md`,
|
|
45
|
+
`.claude/settings.json`— se respaldan en `~/.local/state/ratifact/backups/<fecha>/<ruta absoluta>`, nunca dentro del
|
|
46
|
+
repositorio; un archivo que no se reescribe no tiene respaldo), valida el resultado volviéndolo a parsear y reemplaza el original de forma atómica; un
|
|
47
|
+
archivo inválido (p. ej. una coma de más en el JSON) se informa y no se toca. Un cliente no instalado se informa y se
|
|
48
|
+
salta; `--client claude-desktop|claude-code|pi|codex` limita a uno. Un segundo `--apply` no cambia nada y lo dice.
|
|
49
|
+
Codex es experimental: `ratifact install` lo configura y las herramientas MCP responden, pero aún no se ha
|
|
50
|
+
validado una ejecución completa de `/run-task` (`$run-task` en Codex).
|
|
51
|
+
|
|
52
|
+
Además: reemplaza la entrada vieja `memoria-proyectos` (nunca quedan las dos), renombra los permisos de Claude Code
|
|
53
|
+
`mcp__memoria-proyectos__<herramienta>` → `mcp__ratifact__<herramienta>` (en `~/.claude/settings.json` y en el
|
|
54
|
+
`.claude/settings.json` de cada proyecto registrado; los nombres en español de v0 se traducen), mueve las tablas de
|
|
55
|
+
aprobación por herramienta de Codex a la clave nueva, reescribe el bloque generado de `CLAUDE.md`/`AGENTS.md` de los
|
|
56
|
+
proyectos registrados (solo ese texto exacto, con respaldo fuera del repositorio), enlaza `/run-task` (sección 12), crea
|
|
57
|
+
`~/.config/ratifact/projects.json` vacío si no hay ninguna configuración, informa las integraciones detectadas por
|
|
58
|
+
proyecto y cómo apagarlas (las integraciones se detectan en disco y, por defecto, quedan en automático: nunca se pregunta) y lista lo que no puede hacer solo (las aprobaciones de Claude
|
|
59
|
+
Desktop, sección 10). Reinicie los clientes después.
|
|
60
|
+
|
|
61
|
+
## Nota de versión
|
|
62
|
+
El servidor fija `mcp>=1.2,<2`. La serie 2.x de la librería `mcp` cambió la API y el servidor se desconecta al
|
|
63
|
+
arrancar. No quite ese límite sin probar antes con `./diagnostico.sh`.
|
|
64
|
+
|
|
65
|
+
## 2. Claude Code
|
|
66
|
+
Lo configura `ratifact install --apply` (sección 1): equivale a
|
|
67
|
+
`claude mcp add --scope user ratifact -- <home>/.local/bin/ratifact serve`.
|
|
68
|
+
|
|
69
|
+
## 3. Instrucciones del proyecto en claude.ai
|
|
70
|
+
El texto exacto (en inglés, con los nombres de herramientas v1) lo devuelve `project_instructions("<proyecto>")`:
|
|
71
|
+
péguelo tal cual en *Project instructions*. Empieza así:
|
|
72
|
+
|
|
73
|
+
> project: game
|
|
74
|
+
> At the start of every chat, call `get_context("game")` before answering; assume nothing that is not there.
|
|
75
|
+
> When we reach a decision, record it with `propose_decision` (it stays proposed). Only if I accept it explicitly, call `accept_decision` with my literal words in `user_quote`; the app will ask me to approve it.
|
|
76
|
+
> …
|
|
77
|
+
|
|
78
|
+
## 4. Agregar otro proyecto
|
|
79
|
+
En cualquier chat con el MCP conectado, pida: "registra el proyecto <nombre> con el código en <ruta>".
|
|
80
|
+
`register_project` lo agrega a `projects.json`, crea su memoria (por defecto en `~/Projects/.ratifact/<nombre>`,
|
|
81
|
+
con repo git propio) y devuelve las instrucciones exactas para pegar en el proyecto de Claude y en CLAUDE.md/AGENTS.md.
|
|
82
|
+
Para recuperar esas instrucciones de un proyecto existente: `project_instructions("<nombre>")`.
|
|
83
|
+
Recomendado: marcar `register_project` como "requiere aprobación" igual que `accept_decision`.
|
|
84
|
+
|
|
85
|
+
### Actualizar un proyecto ya registrado
|
|
86
|
+
|
|
87
|
+
`update_project(name, path="", tests="", repo="", redetect=False, integrations="", models="", delegation="")` corrige projects.json sin
|
|
88
|
+
editarlo a mano; reemplaza a la antigua `configurar_pruebas` (eliminada). Indique al menos uno de estos campos
|
|
89
|
+
(sin ninguno, la herramienta falla y no toca el archivo):
|
|
90
|
+
- `path`: nueva carpeta del código, cuando el proyecto se movió. Mismas validaciones que `register_project`
|
|
91
|
+
(debe quedar dentro de la carpeta de proyectos, ser una carpeta existente, y no contener la memoria del
|
|
92
|
+
proyecto, porque se commitearía y publicaría con el código; el mensaje de rechazo es distinto al del alta, porque aquí mover la memoria de un
|
|
93
|
+
proyecto existente no está soportado). La respuesta indica la ruta vieja y la nueva. Si el proyecto es de
|
|
94
|
+
varios repositorios y el comando de pruebas guardado queda con claves que ya no son repos bajo la ruta nueva, el
|
|
95
|
+
cambio se aplica igual (no bloquea) pero la respuesta avisa cuáles quedaron huérfanas ("orphan tests") y sugiere
|
|
96
|
+
`redetect=True`.
|
|
97
|
+
- `tests`: comando con que `/run-task` verifica el trabajo. En proyectos de varios repositorios, `repo`
|
|
98
|
+
indica a cuál se aplica.
|
|
99
|
+
- `redetect=True`: vuelve a detectar el comando a partir de los archivos del proyecto, en vez de darlo con
|
|
100
|
+
`tests` (ambos a la vez son incompatibles). En un proyecto de un solo repositorio redetecta el comando
|
|
101
|
+
completo; en uno de varios repositorios redetecta todos, o solo `repo` si se indica. Es la forma de
|
|
102
|
+
recuperar el comportamiento que antes tenía `configurar_pruebas()` llamada sin argumentos.
|
|
103
|
+
- `integrations`: activa o apaga integraciones opcionales, p. ej. `"codegraph=off,gentle-ai=auto"` (valores
|
|
104
|
+
`auto`|`off`; por defecto `auto`). Se guarda en `projects.json` bajo `"integraciones"` (solo las `off`). Un
|
|
105
|
+
nombre o valor desconocido se rechaza listando los válidos. codegraph (`.codegraph/`) y gentle-ai (`.atl/`) se
|
|
106
|
+
detectan en la carpeta del proyecto o en cualquiera de sus repos; engram no se detecta (solo guía condicional).
|
|
107
|
+
Las activas aparecen en `get_context` (una línea + guía para planificar), en `create_task` (la línea) y
|
|
108
|
+
en `update_task(..., "in_progress")` (guía para execute, verify y close); una apagada no aparece nunca.
|
|
109
|
+
- `models`: excepciones del proyecto a los modelos por rol, p. ej. `"explore=haiku,write=sonnet"` (roles
|
|
110
|
+
`explore`, `write`, `verify`; el valor es el nombre de modelo del cliente, texto libre). `inherit` en un rol quita
|
|
111
|
+
la excepción de ese rol, que vuelve a usar el global. Un rol desconocido o un valor vacío se rechazan listando los
|
|
112
|
+
roles válidos. Se guarda en la entrada del proyecto en `projects.json` bajo `"models"`.
|
|
113
|
+
|
|
114
|
+
### Modelos por rol (`settings.json`)
|
|
115
|
+
|
|
116
|
+
El valor global de los modelos por rol vive en `settings.json`, en la misma carpeta que el `projects.json` activo
|
|
117
|
+
(p. ej. `~/.config/ratifact/settings.json`). Lo crea el usuario a mano (`ratifact install` no lo escribe):
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{"models": {"explore": "haiku", "write": "sonnet", "verify": "sonnet"}}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Se lee en cada llamada. Las excepciones de un proyecto (`update_project(..., models=...)`) ganan rol por rol; los
|
|
124
|
+
roles que el proyecto no define se heredan del global. Si hay al menos un rol configurado,
|
|
125
|
+
`update_task(..., "in_progress")` agrega un bloque "Model routing" con cada rol, su modelo y su origen
|
|
126
|
+
(global/project): es la petición explícita del usuario de fijar ese modelo al delegar el rol a un sub-agente; un
|
|
127
|
+
cliente que no permite elegir el modelo de sub-agentes lo ignora, y los roles sin modelo usan el de la sesión. Sin
|
|
128
|
+
configuración la respuesta no cambia. Un `settings.json` inválido no rompe ninguna herramienta (se ignora con un
|
|
129
|
+
aviso en ese bloque) y `ratifact doctor` lo reporta sin modificarlo; doctor muestra además los modelos efectivos de
|
|
130
|
+
cada proyecto (o `models: session default`).
|
|
131
|
+
No cubre renombrar un proyecto ni mover la ubicación de su memoria (`.ratifact/<nombre>` o la clave `"memoria"`):
|
|
132
|
+
para eso edite `projects.json` a mano y mueva la carpeta con `git mv`/`mv` según corresponda.
|
|
133
|
+
|
|
134
|
+
### Política de delegación
|
|
135
|
+
|
|
136
|
+
Si una tarea se delega lo decide ratifact al planificar, no el agente que la ejecuta. `"delegation": "required" |
|
|
137
|
+
"suggested" | "off"` va en `settings.json` junto a `"models"` (global; por defecto `required`). Excepción por proyecto:
|
|
138
|
+
`update_project(name, delegation="off")` (`inherit` la quita; un valor desconocido se rechaza con la lista de válidos).
|
|
139
|
+
Excepción por tarea, fijada en la planificación: `create_task(..., delegation="off")` o
|
|
140
|
+
`amend_task(..., delegation="required")` (solo en todo o changes_requested), guardada como `delegation:` en el
|
|
141
|
+
frontmatter. Precedencia: tarea > proyecto > global > `required`. Criterio para `off`: la tarea toca seguridad, es
|
|
142
|
+
transversal o depende de diagnosticar una causa que la especificación aún no conoce.
|
|
143
|
+
|
|
144
|
+
- `required`: `update_task(..., "in_progress")` devuelve un bloque "Delegation" imperativo: la sesión principal
|
|
145
|
+
orquesta y no escribe el código; exploración en un trabajador explore, implementación en trabajadores write,
|
|
146
|
+
verificación en un trabajador verify que no vio la implementación, cada uno con el modelo de su rol (o el de la
|
|
147
|
+
sesión); los encargos llevan la especificación completa; el orquestador revisa el diff completo antes de
|
|
148
|
+
in_review; si un escritor falla la verificación dos veces, el orquestador toma la implementación y lo declara como
|
|
149
|
+
`escalated: write`.
|
|
150
|
+
- `suggested`: el bloque es una sugerencia. `off`: no hay bloque de delegación.
|
|
151
|
+
- El resultado lleva una línea propia, separada de `Integrations used:` (que solo nombra integraciones, nunca roles):
|
|
152
|
+
`Workers: explore/haiku×1, write/sonnet×2, verify/sonnet×1` (más `escalated: write` si corresponde) o
|
|
153
|
+
`Workers: none — reason: <motivo>`. Con `required`, `update_task(..., "in_review")` sin una línea Workers válida
|
|
154
|
+
cambia el estado igual pero responde con un aviso.
|
|
155
|
+
- Formato ampliado: `Workers: <rol>/<modelo>×<n>, …[, rework: <rol>×<n>, …][, escalated: <rol>][ — note: <texto libre>]`.
|
|
156
|
+
`<rol>/<modelo>×<n>` cuenta solo los encargos iniciales, incluso con varios trabajadores del mismo rol en paralelo (dos
|
|
157
|
+
escritores en paralelo son `Workers: write/sonnet×2`); `rework: <rol>×<n>` cuenta los reenvíos de ese rol causados por
|
|
158
|
+
un defecto que encontró el verificador o la revisión del diff del orquestador (el rol debe figurar entre los
|
|
159
|
+
trabajadores, n ≥ 1). La nota empieza en ` — note:` (canónico) o en ` - note:` / ` -- note:`, y se aceptan
|
|
160
|
+
`none - reason:` / `none -- reason:` (`Workers: write/sonnet×1 - note: x`); un guion ASCII en cualquier otro lugar
|
|
161
|
+
(`Workers: write/sonnet×1 - resumed once`) no separa nada y es un token inválido. El parser ignora el texto de la nota. Sin paréntesis: el retrabajo va en
|
|
162
|
+
`rework:`, los comentarios en `— note:`. Ejemplo:
|
|
163
|
+
`Workers: explore/haiku×1, write/sonnet×1, verify/sonnet×1, rework: write×1 — note: diff review found a missing test`.
|
|
164
|
+
Las líneas del formato anterior (sin `rework:` ni nota) siguen siendo válidas.
|
|
165
|
+
- Corrección sin duplicar: si el aviso dice que la línea es inválida, propone una corregida cuando puede derivarla;
|
|
166
|
+
enviar solo esa línea con `update_task(..., "in_review")` reemplaza la línea `Workers:` del último bloque de
|
|
167
|
+
resultado (o la agrega ahí) en lugar de crear un bloque nuevo.
|
|
168
|
+
- Auditoría: al pasar a in_progress se graba en el frontmatter `routing: explore=<m>,write=<m>,verify=<m> ·
|
|
169
|
+
delegation=<política> · build=<build> · at=<hora ISO 8601, a minutos>` (`session` si el rol no tiene modelo; se
|
|
170
|
+
sobrescribe en cada reejecución; `build=` y `at=` solo en las tareas nuevas: las tareas anteriores conservan la forma corta
|
|
171
|
+
y se siguen leyendo). `ratifact report` toma el período de `at=` cuando existe (si no, de `updated`). `ratifact report`
|
|
172
|
+
mide el cumplimiento por proyecto (tareas required con trabajadores reales, escalamientos) y compara tareas
|
|
173
|
+
delegadas y no delegadas en revisiones y en duración in_progress → in_review; las tareas sin `routing:` se cuentan
|
|
174
|
+
aparte. El routing también termina con `· client=<nombre>/<versión>`, tomado del `clientInfo` MCP de la
|
|
175
|
+
inicialización (saneado: sin espacios, sin `·`, sin saltos de línea, máximo 64 caracteres; `client=unknown` si no
|
|
176
|
+
hay dato) y cada registro nuevo de `uso.jsonl` lleva el campo `client`; se graba el valor recibido, sin normalizar.
|
|
177
|
+
`ratifact report` mide además, entre las tareas delegadas (última línea `Workers:` válida de cada una),
|
|
178
|
+
cuántas tuvieron rework, los reenvíos totales por rol, los escalamientos y la tasa de retrabajo (con rework /
|
|
179
|
+
delegadas), y desglosa por cliente (`client=` del routing, `unknown` si falta) tareas, cumplimiento de la delegación
|
|
180
|
+
y tasa de retrabajo. `ratifact doctor` muestra la política efectiva de cada proyecto (p. ej. `delegation=required (global)`).
|
|
181
|
+
|
|
182
|
+
### Desfase de versiones
|
|
183
|
+
Hay tres copias de ratifact: la fuente (este repositorio), la instalación (directorio de uv tool, al que enlazan las
|
|
184
|
+
skills /run-task) y el servidor en ejecución (un `ratifact serve` por cliente, que conserva el código con el que
|
|
185
|
+
arrancó). Se desfasan al integrar sin reinstalar o al reinstalar sin reiniciar un cliente. Procedimiento tras cada
|
|
186
|
+
cambio: integrar en main → `uv tool install --reinstall ~/Projects/.memoria-proyectos` → reiniciar todos los clientes
|
|
187
|
+
(Claude Desktop, Claude Code, Codex, Pi) → `ratifact doctor`.
|
|
188
|
+
|
|
189
|
+
- **Build:** cada servidor calcula al arrancar `<versión>+<7 hex>` (hash del contenido de su paquete, skills incluidas,
|
|
190
|
+
sin bytecode). `get_context` lo muestra en su primera línea (`ratifact <build>`) y `routing:` lo graba por tarea.
|
|
191
|
+
- **Servidor obsoleto:** el servidor vuelve a mirar sus propios archivos (solo stat, caché de 5 s). Si cambiaron o
|
|
192
|
+
faltan desde que arrancó, `get_context` muestra debajo del build un aviso ⚠ para reiniciar ese cliente, las demás
|
|
193
|
+
herramientas anteponen el mismo aviso y `update_task(..., "in_progress")` se rechaza sin modificar nada: reiniciar
|
|
194
|
+
el cliente y repetir el paso.
|
|
195
|
+
- **Fuente más nueva que la instalación:** si uv instaló ratifact desde una carpeta local (su recibo de instalación),
|
|
196
|
+
`doctor` y `get_context` comparan el paquete de esa carpeta con el instalado y piden reinstalar, con el comando. Las
|
|
197
|
+
instalaciones desde PyPI no muestran este aviso.
|
|
198
|
+
- **`ratifact doctor`** lista además los procesos `ratifact serve` vivos (PID, hora de inicio y proceso padre). Como la
|
|
199
|
+
reinstalación reescribe todos los archivos aunque no cambien, un proceso anterior a la instalación se marca solo si
|
|
200
|
+
su contenido difiere: cada servidor deja su build de arranque en `~/.local/state/ratifact/servers/<pid>.json`
|
|
201
|
+
(se borra al salir y los PID muertos se limpian al arrancar). Mismo contenido → "nada que hacer"; sin
|
|
202
|
+
registro (servidor anterior a esto) → "el contenido puede ser idéntico" y `get_context` en ese cliente da la
|
|
203
|
+
respuesta definitiva. doctor solo lee: no escribe, no envía señales ni termina procesos (Linux y macOS; en otros
|
|
204
|
+
sistemas informa que el listado no está disponible).
|
|
205
|
+
Solo cuenta como servidor el proceso con ese registro: el envoltorio con el que Claude Desktop en Linux lanza el
|
|
206
|
+
MCP (su padre, que también muestra `ratifact serve` en la línea de comando, sin registro) se muestra dentro de la
|
|
207
|
+
entrada de su servidor ("wrapper <pid>, <cliente>"), y cualquier otro proceso sin registro se lista aparte como
|
|
208
|
+
"Unregistered processes" y no cuenta. doctor también avisa si corre en Windows nativo (no soportado:
|
|
209
|
+
instalar ratifact dentro de WSL2, con los repositorios en el sistema de archivos de WSL, no en `/mnt/c`), indica
|
|
210
|
+
cuando corre dentro de WSL y advierte de un repositorio registrado bajo `/mnt/` (lento y con diferencias de git).
|
|
211
|
+
- El autodiagnóstico del servidor funciona igual: una huella distinta se confirma una vez con el hash de contenido,
|
|
212
|
+
así que reinstalar con el mismo código no dispara el aviso ni el rechazo de `in_progress`.
|
|
213
|
+
|
|
214
|
+
`ratifact install --apply` y `ratifact upgrade --apply` terminan recordando reiniciar los clientes y verificar con
|
|
215
|
+
`ratifact doctor`. Un servidor anterior al registro de build/PID no se autodiagnostica; `doctor` sí lo muestra.
|
|
216
|
+
|
|
217
|
+
## 5. Tareas de código (Claude Desktop → Claude Code)
|
|
218
|
+
Flujo: en Claude Desktop se acuerda un cambio y se registra con `create_task` → queda `.project/tasks/T-NNN.md` →
|
|
219
|
+
en Claude Code, dentro del repositorio, se ejecuta `/run-task T-NNN` (que empieza con `read_task`) → Claude Code crea la rama, implementa, corre las pruebas
|
|
220
|
+
del proyecto ("How to verify") y deja la tarea `in_review` (o `failed`) con el resultado → usted revisa la rama e integra.
|
|
221
|
+
|
|
222
|
+
Instalación del comando: una sola vez por equipo, con los enlaces globales de la sección 12 (no se copia por repositorio).
|
|
223
|
+
Claude Code debe tener el MCP registrado (sección 2) para leer y actualizar la tarea.
|
|
224
|
+
|
|
225
|
+
Las instrucciones del proyecto en claude.ai (`project_instructions`) ya incluyen el flujo: `create_task` con goal,
|
|
226
|
+
criterios verificables, ADR aplicables, archivos y fuera de alcance; el comando `/run-task T-NNN`; `amend_task` para
|
|
227
|
+
ampliar una tarea que todavía no corrió; `list_tasks` y `read_task` para revisar; `request_changes` con findings y
|
|
228
|
+
criterios adicionales para pedir correcciones; `merged`/`discarded` solo con confirmación del usuario.
|
|
229
|
+
|
|
230
|
+
`amend_task(project, id, additional_criteria="", notes="")`: solo para tareas `todo` o `changes_requested`
|
|
231
|
+
(otro estado → error que lo nombra). Agrega un bloque fechado "### Amendment N" (sub-etiquetas **Additional criteria** y
|
|
232
|
+
**Notes**) en la sección "## Amendments" de la spec, antes de "How to verify"; los criterios originales no se tocan. Un
|
|
233
|
+
commit por enmienda; al menos uno de los dos campos; una enmienda idéntica dentro de la ventana de idempotencia
|
|
234
|
+
no se escribe de nuevo.
|
|
235
|
+
|
|
236
|
+
`read_task(project, id)`: brief de trabajo de una tarea en lugar del archivo completo: frontmatter, spec
|
|
237
|
+
completa (con las enmiendas), el bloque relevante según el estado (`changes_requested` → la última Review;
|
|
238
|
+
`in_review`/`failed` → el último resultado; `in_progress` → la última Review si es el último bloque) y un índice de una
|
|
239
|
+
línea (título · rango de líneas · tamaño) de los demás bloques Result/Review, legibles con `read_document` y ese rango.
|
|
240
|
+
|
|
241
|
+
Ciclo de revisión: `todo` → `in_progress` → `in_review` → (`changes_requested` → `in_progress` → `in_review`)* →
|
|
242
|
+
`merged`. Una tarea devuelta se corrige en la misma rama con commits nuevos; cada devolución queda como "Review N" en la
|
|
243
|
+
tarea (con **Findings** y **Additional criteria**). `update_task` rechaza pasar de `in_review` a `todo`: devolver es
|
|
244
|
+
siempre `request_changes`. El parámetro `status` acepta también (hasta 1.1) los nombres en español de antes del esquema v2
|
|
245
|
+
(`pendiente`, `en_curso`, `en_revision`, `fallida`, `integrada`, `descartada`); se guarda y se responde en inglés.
|
|
246
|
+
|
|
247
|
+
Pendientes que resuelve una tarea: `create_task(..., resolves="P-001 (partial)")` — ids separados por
|
|
248
|
+
coma, cada uno opcionalmente con `(parcial)` o `(partial)` (sin distinguir mayúsculas ni espacios; `p-1` vale como `P-001`). Cada id
|
|
249
|
+
debe existir y estar abierto; si alguno no, la herramienta lo rechaza nombrando los inválidos y no escribe nada. Se guarda
|
|
250
|
+
en el frontmatter (`resolves: P-001 (partial)`) y como sección "## Resolves" de la tarea; sin `resolves`, ni
|
|
251
|
+
campo ni sección. Al marcar la tarea `merged`, la respuesta recuerda cada pendiente declarado que siga abierto: los completos
|
|
252
|
+
con la llamada a `close_pending` y los parciales con cómo registrar lo que falta: una nota anexada al archivo del
|
|
253
|
+
pendiente con `update_document(..., mode="append")`, o cerrarlo con `close_pending` y abrir el resto con `add_pending`. Nunca se cierra ni se modifica un
|
|
254
|
+
pendiente automáticamente.
|
|
255
|
+
|
|
256
|
+
## 6. Ubicación de la memoria
|
|
257
|
+
Con la clave `"memoria"` en `projects.json`, la memoria vive fuera del repositorio del código (repo git propio) y no depende
|
|
258
|
+
de la rama activa. Recomendado para todos los proyectos. Las herramientas siguen usando rutas `.project/...`.
|
|
259
|
+
Sin esa clave, la memoria es `<carpeta de proyectos>/.ratifact/<nombre>`; una que todavía vive en la
|
|
260
|
+
ruta por defecto vieja `.memorias/<nombre>` se sigue encontrando ahí hasta que `ratifact upgrade --apply` la mueve.
|
|
261
|
+
Las claves de cada proyecto en `projects.json` se leen en español (`ruta`, `memoria`, `escritura`, `pruebas`,
|
|
262
|
+
`integraciones`) o en inglés (`path`, `memory`, `writable`, `tests`, `integrations`); si están las dos, gana la inglesa.
|
|
263
|
+
Al escribir se conserva la grafía que ya tiene la entrada. Renombrar las claves y mover las memorias de `.memorias/` a
|
|
264
|
+
`.ratifact/` es `ratifact upgrade --apply` (sección 0), nunca la migración automática.
|
|
265
|
+
|
|
266
|
+
## 7. Telemetría
|
|
267
|
+
Cada llamada a una herramienta agrega una línea a `~/.local/state/ratifact/uso.jsonl` (`$XDG_STATE_HOME/ratifact/`; hasta
|
|
268
|
+
antes de instalarse como paquete era `<repo>/logs/uso.jsonl`, y `ratifact upgrade` lo copia si el nuevo no existe) con herramienta, proyecto,
|
|
269
|
+
tamaños, duración y error; nunca el contenido. Resumen: `ratifact report --days 7` (opcional `--project game`; también
|
|
270
|
+
`python3 ~/Projects/.memoria-proyectos/analizar_uso.py --dias 7` hasta 1.1).
|
|
271
|
+
El informe lee el mismo log que escribe el servidor: `--log <ruta>` si se indica, si no `RATIFACT_LOG` (o
|
|
272
|
+
`MEMORIA_PROYECTOS_LOG`), y si no `~/.local/state/ratifact/uso.jsonl`. Las filas guardan el nombre inglés de la herramienta; las anteriores
|
|
273
|
+
a la v1 (nombre en español) se traducen al agregar, así el historial suma por herramienta. Si el archivo no existe, lo informa con su ruta y termina con error.
|
|
274
|
+
`get_context` avisa cuando INDEX.md acumula 5 o más cambios sin regenerarse.
|
|
275
|
+
Arranque compacto: `get_context` ya no incluye `OPEN.md`. Después de INDEX.md muestra
|
|
276
|
+
"# Open items (N)" con una línea por pendiente abierto (`- P-NNN · <tema> (<fecha>)`, en orden numérico, tema
|
|
277
|
+
cortado a 100 caracteres, sin extracto ni dueño) y cierra con `Detail: read_document("<proyecto>", "P-NNN")`; sin
|
|
278
|
+
pendientes abiertos, solo "# Open items (0)". "Recently closed" no sale en el arranque. `OPEN.md`
|
|
279
|
+
sigue generándose en disco. Al final, la línea "Content language: <content_language> — …" pide escribir el contenido de
|
|
280
|
+
los registros en ese idioma; las respuestas de las herramientas son siempre en inglés.
|
|
281
|
+
El resumen de `analizar_uso.py` agrega el tamaño de `get_context` por proyecto (p50/máx en caracteres y ~tokens,
|
|
282
|
+
con aviso si el p50 supera la referencia de 2.000 tokens = 8.000 caracteres) y la sección "Pendientes abiertos
|
|
283
|
+
referenciados por tareas integradas": por proyecto, los declarados en `resolves` y los mencionados en el texto de la
|
|
284
|
+
tarea (spec —objetivo, criterios, revisiones— y Result; no cuentan Out of scope, Notes, How to verify ni Resolves),
|
|
285
|
+
con la tarea y su fecha de integración. Lee memorias v1 y v2. También cuenta, por proyecto, las rutas v1 traducidas
|
|
286
|
+
(`alias_ruta` en el log; ver sección 13).
|
|
287
|
+
|
|
288
|
+
## 8. Confirmación de decisiones
|
|
289
|
+
Toda decisión nace como propuesta. La única vía a "acordada" es `accept_decision`, que exige la frase literal del
|
|
290
|
+
usuario (`user_quote`, guardada en el ADR) y debe requerir aprobación en cada cliente:
|
|
291
|
+
- Claude Desktop: Configuración → conectores/MCP → ratifact → `accept_decision` → requiere aprobación.
|
|
292
|
+
- Claude Code: `"mcp__ratifact__accept_decision"` y `"mcp__ratifact__accept_decisions"` en `permissions.ask` de `.claude/settings.json` (`ratifact install` renombra los `mcp__memoria-proyectos__…` existentes).
|
|
293
|
+
- Pi: sin permisos configurables; la evidencia queda en la sección "Confirmación" del ADR.
|
|
294
|
+
|
|
295
|
+
## 9. Revisar propuestas
|
|
296
|
+
Desde el chat: "revisa las propuestas pendientes" → `review_proposals` muestra todas con su detalle. Por cada una:
|
|
297
|
+
confirmar (`accept_decision`, con aprobación), ajustar (nueva decisión + `supersede_decision`) o descartar
|
|
298
|
+
(`reject_decision`, con motivo; queda en el historial como descartada).
|
|
299
|
+
Con formularios: "decidamos las propuestas" → `decide_proposals` abre un formulario por propuesta en la aplicación
|
|
300
|
+
(accept / reject / adjust / postpone + comment). La respuesta viene directo del usuario, sin pasar por el
|
|
301
|
+
modelo. Si la aplicación no soporta formularios (MCP elicitation), la herramienta lo indica y se usa el flujo por chat.
|
|
302
|
+
|
|
303
|
+
## 10. Aprobaciones en Claude Desktop
|
|
304
|
+
Crear registros en la memoria debe pasar por usted; modificar o leer, no. Marque como "requiere aprobación":
|
|
305
|
+
`propose_decision`, `add_pending`, `create_task`, `create_document`, `register_project`, `accept_decision` y
|
|
306
|
+
`accept_decisions`. Las aprobaciones se guardan por nombre de servidor y de herramienta: tras pasar a la clave
|
|
307
|
+
`ratifact` hay que marcarlas de nuevo; `ratifact install` lo recuerda en sus pasos manuales.
|
|
308
|
+
Deje en "permitir siempre" el resto (lecturas, `read_task`, `amend_task`, `update_document` sobre archivos existentes, `update_task`,
|
|
309
|
+
`update_index`, `log_session`, `reject_decision`, `supersede_decision`). El servidor no tiene herramientas
|
|
310
|
+
para borrar archivos: nada se elimina, solo cambia de estado. En Claude Code no se usan aprobaciones para el código.
|
|
311
|
+
|
|
312
|
+
## 11. Pruebas
|
|
313
|
+
Desde esta carpeta: `uv run --with pytest --with "mcp>=1.2,<2" pytest -q` (o `python3 -m pytest -q` con pytest y mcp instalados).
|
|
314
|
+
Corren contra una carpeta temporal: no tocan `projects.json`, la telemetría ni los proyectos reales.
|
|
315
|
+
`test_cobertura.py` falla si se agrega una herramienta sin pruebas (el criterio 1 de estabilización: suite pytest en verde que cubra todas las herramientas).
|
|
316
|
+
|
|
317
|
+
## 12. /run-task global (una vez por equipo)
|
|
318
|
+
`/run-task` es genérico: la fuente es `ratifact/skills/run-task/SKILL.md`, que viaja dentro del paquete instalado
|
|
319
|
+
(`skills/` y `run-task.md` en la raíz del repositorio son enlaces a ella). `ratifact install --apply` lo enlaza desde la
|
|
320
|
+
copia instalada (nunca desde la copia de trabajo), así existe en todos los proyectos:
|
|
321
|
+
|
|
322
|
+
- Claude Code: `~/.claude/skills/run-task` (el enlace antiguo `~/.claude/commands/run-task.md` se borra si es nuestro)
|
|
323
|
+
- Pi: `~/.pi/agent/prompts/run-task.md` (y `~/.pi/agent/skills/run-task` si existe esa carpeta)
|
|
324
|
+
- Codex: `~/.codex/skills/run-task` y `~/.agents/skills/run-task` (según la versión lee una u otra; se enlaza la carpeta
|
|
325
|
+
entera porque Codex no sigue un `SKILL.md` enlazado como archivo)
|
|
326
|
+
|
|
327
|
+
Un destino que ya existe como archivo o carpeta real (no enlace) nunca se reemplaza: el plan pide borrarlo a mano.
|
|
328
|
+
Si usa gentle-shell independiente, enlace también `~/.gentle-shell/agent/prompts/run-task.md` a la misma fuente.
|
|
329
|
+
|
|
330
|
+
## 13. Versión de esquema de la memoria
|
|
331
|
+
|
|
332
|
+
Cada memoria declara en `schema.json` el formato con que fue escrita y el idioma de su contenido:
|
|
333
|
+
`{"version": 2, "content_language": "es"}`. Hoy es v2: carpetas `decisions/`, `pending/`, `sessions/`, `tasks/`;
|
|
334
|
+
vistas `DECISIONS.md` y `OPEN.md`; claves, estados y títulos de sección en inglés (`docs/v1-english-naming.md` §5–§6).
|
|
335
|
+
Las memorias nuevas nacen en v2 con `content_language` `"en"`; las migradas, con `"es"`.
|
|
336
|
+
|
|
337
|
+
Migración automática (v1 → v2), en el **primer acceso** a cada memoria (cualquier herramienta con
|
|
338
|
+
`project`, también las de solo lectura), bajo el bloqueo:
|
|
339
|
+
|
|
340
|
+
- Precondiciones: la memoria es un repo git con al menos un commit y `git status` limpio (salvo `.lock`). Si no, la
|
|
341
|
+
herramienta responde un error que explica por qué y no se toca nada.
|
|
342
|
+
- Antes de cambiar nada crea el tag `pre-v2` (si existe, `pre-v2-2`, `-3`, …).
|
|
343
|
+
- Un solo commit `memory: migrate schema v1 → v2`: renombra las carpetas con `git mv` (historia preservada), cambia
|
|
344
|
+
las claves y los estados del frontmatter, los títulos de sección conocidos y, dentro de los bloques "Revisión N",
|
|
345
|
+
las etiquetas `**Observaciones**`/`**Criterios adicionales**`; regenera `DECISIONS.md`/`OPEN.md` y borra
|
|
346
|
+
`acuerdos.md`/`abiertas.md`. El resto del cuerpo, las citas del usuario, `INDEX.md` y `docs/` no cambian. El cuerpo del
|
|
347
|
+
commit lista lo que quedó como estaba: claves desconocidas y títulos de texto libre.
|
|
348
|
+
- Si algo falla (un paso o el commit), la memoria vuelve exactamente al tag (y se borra el tag); la herramienta da el
|
|
349
|
+
error y la próxima llamada lo reintenta.
|
|
350
|
+
- Vuelta atrás manual: `git -C <memoria> checkout pre-v2` (o `reset --hard pre-v2`) devuelve el árbol anterior.
|
|
351
|
+
- Se mantiene `esquema.json` con `{"version": 2}` como centinela: un servidor anterior a v2 lee "v2" y se niega
|
|
352
|
+
("usa el esquema v2 y este servidor solo conoce hasta v1"), sin tocar nada. Se quita en 1.1.
|
|
353
|
+
- Despliegue: reinicie todos los clientes (Claude Desktop, Claude Code, Pi, Codex) antes de la primera llamada.
|
|
354
|
+
- Rutas v1 (`.project/tareas/T-001.md`, `.project/acuerdos.md`…, que siguen apareciendo en INDEX.md, docs/ y chats
|
|
355
|
+
viejos): se traduce solo el primer tramo después de `.project/` y la respuesta empieza con
|
|
356
|
+
"(→ .project/<ruta nueva>)". Las vistas no se escriben a mano (ni con el nombre viejo ni con el nuevo). Si una memoria
|
|
357
|
+
tiene a la vez la carpeta v1 y la v2, la llamada falla. Cada uso queda en la telemetría (`alias_ruta`); el alias se
|
|
358
|
+
quita en 1.1 cuando `analizar_uso.py` muestre que no se usa.
|
|
359
|
+
|
|
360
|
+
Una memoria más nueva que el servidor (p. ej. otro equipo con una versión posterior) no se modifica: el servidor pide
|
|
361
|
+
actualizar ratifact. `list_projects` muestra la versión de cada memoria.
|
|
362
|
+
|
|
363
|
+
Para desarrolladores: un cambio de formato sube `VERSION_ESQUEMA` y agrega la función de migración en `MIGRACIONES`
|
|
364
|
+
(con los mismos resguardos: repo limpio, tag `pre-vN`, un commit y vuelta atrás), con su prueba en
|
|
365
|
+
`tests/test_esquema.py`; la de v2 está en `ratifact/migracion_v2.py` y `tests/test_migracion_v2.py`.
|
|
366
|
+
|
|
367
|
+
## 14. Codex, experimental (CLI, extensión de IDE y app de escritorio)
|
|
368
|
+
|
|
369
|
+
Las tres comparten `~/.codex/config.toml`; lo configura `ratifact install --apply` (sección 1) con una edición acotada:
|
|
370
|
+
solo reescribe las tablas `[mcp_servers.memoria-proyectos]`/`[mcp_servers.ratifact]` y sus subtablas (borra la `.env`,
|
|
371
|
+
renombra las `.tools.<herramienta>` con su `approval_mode`) y deja el resto del archivo byte por byte. Queda:
|
|
372
|
+
|
|
373
|
+
```toml
|
|
374
|
+
[mcp_servers.ratifact]
|
|
375
|
+
command = "<home>/.local/bin/ratifact"
|
|
376
|
+
args = ["serve"]
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Si el servidor está definido de otra forma (tabla en línea, claves con puntos), no toca el archivo y da las
|
|
380
|
+
instrucciones para hacerlo a mano.
|
|
381
|
+
|
|
382
|
+
Codex eliminó los comandos personalizados (`~/.codex/prompts`) en marzo de 2026; `/run-task` se instala como skill
|
|
383
|
+
(enlaces de carpeta de la sección 12; Codex no sigue un `SKILL.md` enlazado como archivo) y se invoca con `$run-task T-NNN`. Codex lee `AGENTS.md`
|
|
384
|
+
de forma nativa, pero solo desde la raíz del repo git hacia abajo: en proyectos de varios repos ponga el bloque en la
|
|
385
|
+
carpeta raíz (si abre Codex ahí) y en el `AGENTS.md` de cada repo. Si hay otra memoria de agente instalada (engram),
|
|
386
|
+
el servidor declara en sus instrucciones MCP que ratifact es la fuente de verdad del proyecto.
|
|
387
|
+
|
|
388
|
+
## 15. Idempotencia de creación
|
|
389
|
+
|
|
390
|
+
`propose_decision`, `add_pending` y `create_task` son idempotentes: si ya existe un registro del
|
|
391
|
+
mismo tipo (un ADR no compite con una tarea ni con un pendiente, aunque el texto del título coincida) con el
|
|
392
|
+
mismo título normalizado (sin distinguir mayúsculas, recortando los extremos y colapsando espacios internos),
|
|
393
|
+
**creado en los últimos `VENTANA_IDEMPOTENCIA_MINUTOS` minutos** (10 por defecto) en el mismo proyecto, Y QUE
|
|
394
|
+
TODAVÍA ESTÁ EN SU ESTADO INICIAL ("proposed" para ADR, "open" para pendientes, "todo" para tareas),
|
|
395
|
+
la llamada no crea ningún archivo nuevo, no hace commit, y devuelve el id del registro existente avisando que
|
|
396
|
+
ya estaba registrado (en el caso de una tarea, con el comando `/run-task T-NNN` para repetírselo al usuario).
|
|
397
|
+
`amend_task` aplica la misma ventana a una enmienda idéntica de la misma tarea.
|
|
398
|
+
|
|
399
|
+
La condición de estado inicial es deliberada: un registro que ya cambió de estado (rejected, superseded,
|
|
400
|
+
closed, in_progress, in_review, changes_requested, merged, failed, etc.) significa que un humano ya intervino sobre
|
|
401
|
+
él, así que nunca cuenta como duplicado aunque sea reciente. Esto cubre el flujo normal de "proponer → el
|
|
402
|
+
usuario pide un cambio → descartar/cerrar y volver a registrar corregido", que no debe confundirse con un
|
|
403
|
+
reintento perdido (un reintento genuino de un cliente que perdió la respuesta siempre encuentra el registro
|
|
404
|
+
todavía en su estado inicial, porque nadie tuvo tiempo de tocarlo).
|
|
405
|
+
|
|
406
|
+
Esto existe porque la llamada a una tool puede perderse en la capa del cliente (p. ej. Claude Desktop con un
|
|
407
|
+
timeout de 120 s) sin que el modelo sepa si el servidor llegó a ejecutarla; con esto, reintentar a ciegas es
|
|
408
|
+
seguro. No hay idempotency key del cliente (fuera de alcance v1): la detección es solo por título + estado +
|
|
409
|
+
antigüedad. La telemetría registra estas llamadas como exitosas (`error: false`) con un flag `duplicado: true`,
|
|
410
|
+
y `analizar_uso.py` reporta cuántas creaciones fueron duplicados detectados.
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
## 16. Code layout
|
|
414
|
+
|
|
415
|
+
`servidor.py` es solo un envoltorio de `ratifact serve` hasta 1.1 (cabecera PEP 723, agrega su carpeta a `sys.path`,
|
|
416
|
+
importa el paquete `ratifact/` y llama a `ratifact.cli`); el punto de entrada es el comando `ratifact` (sección 0). El código
|
|
417
|
+
vive en `ratifact/`; ningún módulo supera 300 líneas y no hay importaciones circulares:
|
|
418
|
+
|
|
419
|
+
| Módulo | Responsabilidad |
|
|
420
|
+
|---|---|
|
|
421
|
+
| `ratifact/cli.py` | Comando `ratifact` (`serve`, `install`, `report`, `doctor`, `upgrade`, `--version`); `servidor()` carga herramientas y prompts. |
|
|
422
|
+
| `ratifact/instalar.py`, `ratifact/instalar_extras.py` | `ratifact install`: plan y ejecución; permisos de Claude Code, bloque de CLAUDE.md/AGENTS.md y enlaces de `/run-task`. |
|
|
423
|
+
| `ratifact/clientes.py`, `ratifact/clientes_toml.py` | Clientes MCP (Claude Desktop, Claude Code, Pi, Codex experimental): detección, estado (también para doctor) y edición de su configuración; la de Codex es una edición acotada del TOML. |
|
|
424
|
+
| `ratifact/archivos.py` | Escritura segura de archivos de otros programas: validación, respaldo `.bak-ratifact-<fecha>` y reemplazo atómico. |
|
|
425
|
+
| `ratifact/skills/` | Skill `run-task`, incluida en el paquete. |
|
|
426
|
+
| `ratifact/rutas.py` | Rutas sin projects.json: configuración nueva/vieja, log por defecto (XDG), copia de trabajo o instalación fija y repositorio de origen. |
|
|
427
|
+
| `ratifact/informe.py`, `ratifact/informe_memoria.py` | `ratifact report` (antes `analizar_uso.py`): agregados del log y los indicadores que salen de las memorias. |
|
|
428
|
+
| `ratifact/instalacion.py` | Inventario de solo lectura para doctor/upgrade: projects.json y sus claves, memorias (ubicación, esquema, git), integraciones, servidores en marcha y `.lock` tomados. |
|
|
429
|
+
| `ratifact/doctor.py` | `ratifact doctor`. |
|
|
430
|
+
| `ratifact/upgrade.py`, `ratifact/upgrade_aplicar.py` | `ratifact upgrade`: plan (sin cambios) y ejecución por pasos con vuelta atrás. |
|
|
431
|
+
| `ratifact/app.py` | Instancia FastMCP `mcp`, decoradores `herramienta`/`herramienta_async`, telemetría (`LOG_USO`, `_registrar_uso`) y `_ejecutar`. |
|
|
432
|
+
| `ratifact/config.py` | Rutas y configuración: `CONFIG` (projects.json, claves en español o inglés: `_valor`, `_clave_escritura`), `BASE_PROYECTOS`, `ErrorMemoria`, `_proyectos`, `_raiz`, `_mem`, ayudantes de repositorios, `_ruta_segura`, `_zonas_escritura` y el alias de rutas v1 (`_traducir_alias`). |
|
|
433
|
+
| `ratifact/vocabulario.py` | Vocabulario del esquema v2 y su equivalente v1: carpetas, vistas, claves, estados por tipo y `_normalizar_estado` (parámetros en español o inglés); mapas del contrato v0 → v1 (`HERRAMIENTAS_V0`, `PARAMETROS_V0`, `PROMPTS_V0`, `MODOS_V0`). |
|
|
434
|
+
| `ratifact/esquema.py` | `VERSION_ESQUEMA`, `MIGRACIONES`, versión (`schema.json` / centinela `esquema.json`), resguardos de la migración (repo limpio, tag, commit, vuelta atrás), `_asegurar_esquema` (primer acceso) y `_bloqueo`. |
|
|
435
|
+
| `ratifact/migracion_v2.py` | Migración v1 → v2: carpetas, frontmatter, títulos, etiquetas de revisión y el informe del commit. |
|
|
436
|
+
| `ratifact/registros.py` | Frontmatter (lectura/escritura), `_escribir_atomico`, `_commit`, ids y slugs, idempotencia, `_regenerar_vistas`, `_resumen_tareas`, `_hoy`/`_ahora`. |
|
|
437
|
+
| `ratifact/catalogo.py` | Catálogo de la memoria derivado en cada llamada: `_catalogo`, resolución de ids de `read_document` (`_resolver_id`), registros de `list_documents` y coincidencias por id/título de `search` (id exacto y hasta 5 títulos al inicio de palabra) y el bloque de pendientes abiertos de `get_context` (`_bloque_pendientes`). Sin índice, caché ni watcher. |
|
|
438
|
+
| `ratifact/busqueda.py` | Respuesta de `search` con cuotas por sección: catálogo, luego memoria y código a partes iguales (lo que un lado no usa pasa al otro), y la línea final con lo omitido por sección. |
|
|
439
|
+
| `ratifact/listado.py` | Listado con profundidad adaptativa de `list_documents`: `_listado` (presupuesto `LIMITE_LISTADO_ENTRADAS`/`LIMITE_LISTADO_CARACTERES` en config). |
|
|
440
|
+
| `ratifact/plantillas.py` | `PLANTILLA_INSTRUCCIONES`, `PLANTILLA_AGENTES` y `TEXTO_CIERRE`. |
|
|
441
|
+
| `ratifact/prompts.py` | Prompts `start` y `close` (antes `inicio` y `cierre`). |
|
|
442
|
+
| `ratifact/integraciones/` | Integraciones opcionales: `base.py` (descriptor `Integracion`, `FASES`), un módulo por integración (`codegraph.py`, `gentle_ai.py`, `engram.py`) y `registro.py` (`INTEGRACIONES`, detección en disco en cada llamada, guía para `get_context`/`create_task`/`update_task` y el parseo de `integraciones`). Agregar una = un módulo + registrarlo. Nunca llama a otros MCP. |
|
|
443
|
+
| `ratifact/herramientas/contexto_documentos.py` | `list_projects`, `get_context`, `search`, `list_documents`, `read_document`, `create_document`, `update_document`, `update_index`. |
|
|
444
|
+
| `ratifact/herramientas/decisiones.py` | `propose_decision`, `accept_decision`, `accept_decisions`, `review_proposals`, `decide_proposals`, `reject_decision`, `supersede_decision`. |
|
|
445
|
+
| `ratifact/herramientas/pendientes_sesiones.py` | `add_pending`, `close_pending`, `log_session`. |
|
|
446
|
+
| `ratifact/herramientas/tareas.py` | `create_task`, `update_task`, `request_changes`, `list_tasks` (y `_comando_pruebas`). |
|
|
447
|
+
| `ratifact/herramientas/tareas_brief.py` | `amend_task` y `read_task`. |
|
|
448
|
+
| `ratifact/herramientas/proyectos.py` | `init_memory`, `project_instructions`, `register_project`, `update_project` y la detección del comando de pruebas. |
|
|
449
|
+
|
|
450
|
+
`tests/contrato_herramientas.json` es la instantánea del contrato MCP (nombre, descripción y esquema de cada
|
|
451
|
+
herramienta y prompt); `tests/test_contrato.py` falla si cambia. Para regenerarla a propósito (descripciones normalizadas con `inspect.cleandoc` y formato fijo, así que
|
|
452
|
+
regenerar dos veces da los mismos bytes): `uv run --with pytest --with "mcp>=1.2,<2" python tests/test_contrato.py`.
|
|
453
|
+
`tests/contrato_herramientas_v0.json` es la
|
|
454
|
+
instantánea anterior al renombrado (v0, en español): la prueba comprueba que cada herramienta vieja tiene exactamente
|
|
455
|
+
una nueva y que `amend_task`/`read_task` son las únicas agregadas.
|
ratifact-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Emanuel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|