@cristobalbn/chaski 0.0.0-stage → 0.1.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cristobal Barrera
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.
package/README.md CHANGED
@@ -1,3 +1,589 @@
1
- # Temporary Holding Version
1
+ # chaski
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![test](https://github.com/cristobalbn/chaski/actions/workflows/test.yml/badge.svg)](https://github.com/cristobalbn/chaski/actions/workflows/test.yml)
4
+ [![Licencia: MIT](https://img.shields.io/badge/licencia-MIT-blue.svg)](LICENSE)
5
+ [![Node](https://img.shields.io/badge/node-%E2%89%A520-brightgreen.svg)](https://nodejs.org)
6
+ [![Dependencias](https://img.shields.io/badge/dependencias-0-brightgreen.svg)](package.json)
7
+
8
+ **Relevo de contexto entre agentes de código.** Cuando se agota la cuota de un
9
+ CLI, el siguiente arranca sabiendo qué se decidió, qué quedó a medias y cuál es
10
+ el siguiente paso — sin vigilar contadores ni copiar y pegar nada.
11
+
12
+ Los chaskis eran los mensajeros del imperio inca: cada uno corría un tramo y en
13
+ el **tambo** entregaba el mensaje al siguiente. Lo que llevaban era un registro
14
+ de nudos. Mismo problema, misma solución.
15
+
16
+ Compatible con **Claude Code**, **Codex CLI** y **Antigravity CLI (`agy`)**. Con
17
+ uno solo ya sirve: el relevo entre sesiones de la misma herramienta tiene valor
18
+ propio.
19
+
20
+ ---
21
+
22
+ ## El problema
23
+
24
+ Si pagas dos o tres suscripciones de $20 al mes y rotas entre ellas cuando se
25
+ agotan, cada rotación cuesta entre diez y treinta minutos de volver a explicar.
26
+ Y a veces llega con el código a mitad de un refactor, que es cuando entregarle
27
+ el teclado a un agente sin contexto rompe algo que funcionaba.
28
+
29
+ Los archivos de instrucciones (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`) describen
30
+ el *proyecto*, no la *sesión*: son estables y los escribes tú. La compactación
31
+ automática de cada CLI vive dentro de ese CLI y no cruza al de al lado. Y pedir
32
+ un resumen a mano funciona exactamente hasta el día en que te olvidas.
33
+
34
+ ---
35
+
36
+ ## Instalación
37
+
38
+ **Requisitos:** Node.js ≥ 20. Nada más — cero dependencias de runtime.
39
+
40
+ ### Si le pasaste este enlace a un agente
41
+
42
+ Si estás leyendo esto porque alguien te pidió instalar chaski en su proyecto,
43
+ sigue exactamente esto y no hace falta que leas el resto del README.
44
+
45
+ ```bash
46
+ node --version # debe ser >= 20; si no, detente y avisa
47
+ npm install -g @cristobalbn/chaski # o: npm install -g github:cristobalbn/chaski
48
+ cd <el proyecto del usuario>
49
+ chaski init
50
+ chaski doctor
51
+ ```
52
+
53
+ Después:
54
+
55
+ 1. **Muéstrale al usuario el resumen que imprime `chaski init`.** Explica qué
56
+ quedó instalado, qué tiene que hacer y qué comandos tiene. No lo
57
+ parafrasees ni lo resumas: ya está escrito para que lo lea una persona.
58
+ 2. **Pega también la salida de `chaski doctor`**, que dice qué CLIs quedaron
59
+ conectados y qué comando exacto se registró en cada configuración. El
60
+ usuario debería poder auditarlo.
61
+ 3. **Avísale de los dos pasos que solo él puede hacer**, o va a creer que la
62
+ herramienta está rota:
63
+ - **reiniciar las sesiones abiertas**, porque los hooks se cargan al abrir
64
+ la sesión;
65
+ - **y si tiene Codex, aceptar los hooks** cuando se lo pregunte («trust
66
+ all»). Sin eso Codex no ejecuta ninguno, y el permiso recién se aplica
67
+ en la sesión siguiente, así que tiene que abrirlo dos veces.
68
+ 4. **Dile las tres cosas que importan**, con tus palabras:
69
+ - no tiene que hacer nada más, chaski corre solo;
70
+ - cuando se le agote la cuota de un CLI, que abra otro **en la misma
71
+ carpeta**;
72
+ - escribir **«relevo»** en el chat agrega el «por qué», en cualquiera de los tres.
73
+
74
+ **Si algo falla**, no improvises una solución: pégale al usuario la salida de
75
+ `chaski doctor` y dile qué paso falló. Los modos de fallo conocidos están en
76
+ [Límites conocidos](#límites-conocidos).
77
+
78
+ **No instales con `npx`**: los hooks guardan una ruta absoluta y el caché de
79
+ `npx` es temporal. `init` aborta si detecta ese caso.
80
+
81
+ **No agregues configuración que no te pidieron.** chaski funciona sin
82
+ `chaski.json`; crearlo «por las dudas» solo agrega algo que mantener.
83
+
84
+ ### Opción 1 — npm (recomendada)
85
+
86
+ ```bash
87
+ npm install -g @cristobalbn/chaski
88
+ cd tu-proyecto
89
+ chaski init
90
+ ```
91
+
92
+ También se puede instalar directo desde GitHub:
93
+
94
+ ```bash
95
+ npm install -g github:cristobalbn/chaski
96
+ ```
97
+
98
+ > **No uses `npx chaski init`.** Los hooks guardan una ruta absoluta a los
99
+ > scripts, y el caché de `npx` es temporal: la ruta desaparece y los hooks
100
+ > fallan en silencio. `init` detecta ese caso y aborta con una explicación.
101
+
102
+ ### Opción 2 — desde el código fuente
103
+
104
+ Si prefieres leer lo que vas a ejecutar antes de instalarlo —algo razonable en
105
+ una herramienta que corre sola en cada turno— clona el repositorio. Son ~2.000
106
+ líneas de JavaScript sin dependencias:
107
+
108
+ ```bash
109
+ git clone https://github.com/cristobalbn/chaski.git
110
+ cd chaski
111
+ npm run check # verifica la sintaxis; no hay build
112
+ npm test # node:test, sin dependencias
113
+ cd ../tu-proyecto
114
+ node ../chaski/src/cli.mjs init
115
+ ```
116
+
117
+ ### Dónde escribe `init`, y dónde no
118
+
119
+ Los hooks van a **nivel de usuario** y sirven para todos tus proyectos. Los
120
+ archivos de proyecto —la skill, el bloque de `AGENTS.md`, la línea del
121
+ `.gitignore`— van **solo en el repositorio**, nunca en la carpeta desde la que
122
+ invocaste `init` si esa carpeta no es el repositorio.
123
+
124
+ Esto importa si tienes una carpeta contenedora con varios proyectos dentro:
125
+ instalar ahí la skill la aplicaría a todos, y el `AGENTS.md` le hablaría de
126
+ chaski a quien esté trabajando en otro proyecto. Todo lo de un proyecto vive en
127
+ su proyecto.
128
+
129
+ Si abres un agente en la carpeta contenedora, el relevo se inyecta igual
130
+ —los hooks son de usuario y chaski resuelve el repositorio hijo— y la petición
131
+ automática de la narrativa trae las instrucciones completas para escribirla sin
132
+ la skill. Lo que no tendrás ahí es el atajo `/relevo`.
133
+
134
+ ### Qué hace `init`
135
+
136
+ 1. Detecta cuáles de los tres CLIs tienes instalados y registra los hooks **a
137
+ nivel de usuario**, con rutas nativas del sistema operativo. Respalda cada
138
+ archivo de configuración antes de tocarlo.
139
+ 2. Agrega `.tambo/` y `chaski.local.json` a tu `.gitignore`.
140
+ 3. Instala la skill `relevo` dos veces: en `.claude/skills/relevo/`, que lee
141
+ Claude Code, y en `.agents/skills/relevo/`, que leen Codex y Antigravity.
142
+ Es el mismo archivo y reconoce las mismas peticiones: **«relevo»**,
143
+ **«guarda el relevo»** y **«actualiza el relevo»**.
144
+ 4. Agrega una sección de relevo a tu `AGENTS.md`. Si ya existe, añade o actualiza
145
+ un bloque delimitado con las peticiones comunes y conserva el resto del texto.
146
+
147
+ ### Dos pasos después de instalar
148
+
149
+ Hay dos cosas que `init` no puede hacer por ti, y sin ellas parece que la
150
+ herramienta no funciona.
151
+
152
+ **1. Reinicia tus sesiones.** Los CLIs cargan los hooks al abrir la sesión, así
153
+ que una que ya estaba abierta no los tiene y `.tambo/` va a seguir vacío.
154
+ Ciérrala y vuelve a abrirla.
155
+
156
+ **2. En Codex, acepta los hooks.** La primera vez que abras Codex te va a
157
+ preguntar si confías en ellos. **Tienes que aceptar** —aparece como «trust
158
+ all»— o no ejecuta ninguno. Y el permiso, aunque queda guardado, recién se
159
+ aplica en la sesión siguiente: cierra Codex y vuelve a abrirlo una vez más.
160
+
161
+ Si algo no captura, `chaski doctor` detecta exactamente este caso y te dice
162
+ qué falta:
163
+
164
+ ```
165
+ ⚠ codex: hooks registrados pero nunca ejecutados.
166
+ Codex pide confiar en los hooks la primera vez que lo abres.
167
+ Acepta ("trust all") y vuelve a abrirlo: el permiso se aplica
168
+ desde la sesión siguiente.
169
+ ```
170
+
171
+ ### Verificar la instalación
172
+
173
+ ```bash
174
+ chaski doctor
175
+ ```
176
+
177
+ Imprime el comando exacto que quedó registrado en cada configuración, el último
178
+ latido de cada CLI, el estado del relevo y **qué sale de tu máquina**. Revisa esa
179
+ salida antes de confiar en la herramienta: son unas diez líneas.
180
+
181
+ ### Capturar payloads (`chaski probe`)
182
+
183
+ Herramienta de diagnóstico: instala una sonda que vuelca a disco el payload
184
+ crudo que cada CLI le pasa a sus hooks. Sirve para ver por qué un hook no
185
+ captura, y para aportar fixtures si agregas soporte a otro CLI.
186
+
187
+ ```bash
188
+ chaski probe # instala la sonda en los CLIs que tengas
189
+ # abre cada CLI en modo INTERACTIVO, escribe algo, ciérralo
190
+ chaski probe --show # mira lo capturado
191
+ chaski probe --clean # quita la sonda
192
+ ```
193
+
194
+ Tiene que ser una sesión interactiva: ninguno de los tres dispara hooks en
195
+ modo headless.
196
+
197
+ ### Actualizar
198
+
199
+ ```bash
200
+ npm install -g @cristobalbn/chaski # o: npm install -g github:cristobalbn/chaski
201
+ cd tu-proyecto
202
+ chaski init # repítelo en cada proyecto que uses con Chaski
203
+ ```
204
+
205
+ **Ejecutar `chaski init` no es opcional.** Los hooks se registran con la ruta absoluta
206
+ de los scripts, así que una actualización que mueva la carpeta de instalación
207
+ —o que cambie un nombre de archivo— deja la configuración apuntando a algo que
208
+ ya no existe, y el CLI imprime un error de módulo no encontrado en cada turno.
209
+ `chaski init` reescribe las rutas y es idempotente: correrlo de nuevo sobre una
210
+ instalación sana no cambia nada.
211
+
212
+ También actualiza las copias de la skill y el bloque de peticiones de `AGENTS.md`
213
+ en ese proyecto. Las secciones antiguas sin delimitadores se conservan, porque
214
+ pueden contener instrucciones escritas por ti.
215
+
216
+ Si ya estás viendo ese error, corre `chaski init`. Pero **la sesión que ya lo
217
+ tiene abierto no lo va a ver desaparecer**: los CLIs leen su configuración de
218
+ hooks una sola vez, al arrancar, así que `init` corrige la ruta para la
219
+ próxima sesión, no para la que está corriendo. Cierra esa sesión y abre una
220
+ nueva. `chaski doctor` muestra el comando que quedó registrado, por si quieres
221
+ confirmarlo antes de reabrir.
222
+
223
+ Desde la versión actual los dos nombres de archivo anteriores a la
224
+ homologación al inglés —`capturar.mjs` y `leer.mjs`— siguen funcionando como
225
+ puentes, así que una configuración vieja ya no produce ese volcado de Node:
226
+ captura e inyecta igual, y el hook de inicio de sesión imprime una línea
227
+ recordando que conviene correr `init`. Los puentes existen para que
228
+ actualizar no rompa nada, no para quedarse: `init` sigue siendo el paso
229
+ correcto.
230
+
231
+ ### Desinstalar
232
+
233
+ ```bash
234
+ chaski uninstall
235
+ ```
236
+
237
+ Revierte cada configuración desde su respaldo. Tus relevos en `.tambo/` quedan
238
+ en disco porque son tuyos; bórralos a mano si quieres.
239
+
240
+ ---
241
+
242
+ ## Uso
243
+
244
+ 1. Abre Claude Code, Codex o agy **en la raíz del proyecto** y trabaja normalmente.
245
+ 2. Antes de cambiar de agente, escribe **«relevo»** en su chat y espera a que
246
+ confirme el guardado. Así queda anotada también la intención del trabajo.
247
+ 3. Abre otra terminal, **`cd` a esa misma carpeta**, e inicia el siguiente CLI.
248
+ 4. Escribe **«continúa desde el relevo»** para retomar el siguiente paso pendiente.
249
+
250
+ La captura de hechos y la lectura al arrancar son automáticas. Si se agota la
251
+ cuota antes de pedir el relevo, siguen disponibles los hechos guardados, aunque
252
+ puede faltar la narrativa reciente. No ejecutes `chaski init` en cada cambio:
253
+ basta al configurar el proyecto y al actualizar Chaski.
254
+
255
+ **El `cd` no es opcional:** el relevo vive dentro del proyecto, así que cada
256
+ proyecto tiene el suyo y no se mezclan. Tampoco se mezclan las ramas — volver a
257
+ una rama que dejaste hace una semana te devuelve su contexto.
258
+ No necesitas trabajar dentro del código de Chaski para usarlo en otro proyecto.
259
+
260
+ ### La narrativa se pide sola
261
+
262
+ El relevo tiene dos mitades. Los **hechos** —archivos, diff, commits, exit
263
+ codes— los saca chaski de git y del transcript sin costo ni intervención. La
264
+ **intención** —qué intentabas, qué quedó a medias y dónde, el siguiente paso—
265
+ solo la puede escribir el agent que estuvo en la conversación.
266
+
267
+ Pedirla a mano tiene un defecto que no es de disciplina: **la narrativa
268
+ consume cuota, porque la escribe el agent**. Quien espera a estar al límite
269
+ descubre que el momento en que más la necesita es el único en que ya no se
270
+ puede generar. Y el corte por cuota es abrupto: deja la tarea a medias, que es
271
+ exactamente cuando el siguiente agent necesita saber dónde quedó.
272
+
273
+ Por eso chaski la pide por su cuenta, **temprano y repartida**, mientras sobra
274
+ cuota. Al terminar un turno con trabajo detrás, el hook puede mantener al agent
275
+ un turno más con una instrucción: guarda la narrativa, con énfasis en lo que
276
+ quedó en vuelo. No se invoca ningún modelo por fuera —eso lo prohíben los
277
+ términos de los tres proveedores— sino que se le pide al agent que ya está en
278
+ sesión.
279
+
280
+ Cada petición cuesta un turno de tu conversación, así que los límites son
281
+ conservadores, y en este orden:
282
+
283
+ 1. **Una narrativa escrita hace menos de 20 minutos no se vuelve a pedir**,
284
+ pase lo que pase. Es el corte más fuerte: lo que vuelve insufrible a esta
285
+ función no es pedirla de más en una sesión larga, es pedirla dos veces
286
+ seguidas.
287
+ 2. **12 minutos** de debounce entre peticiones.
288
+ 3. Solo si hay trabajo real detrás: archivos sin commitear, commits nuevos o
289
+ comandos ejecutados.
290
+ 4. Y solo si la narrativa falta, quedó **8 turnos** atrás, o hay commits
291
+ nuevos.
292
+
293
+ | | |
294
+ |---|---|
295
+ | Apagarlo | `"askNarrative": false` en `chaski.json` o `chaski.local.json` |
296
+ | Cómo se ve | Cuatro líneas bajo el rótulo **«Stop hook feedback»**. Ese rótulo y el `Ran 1 stop hook` los pinta Claude Code al ejecutar cualquier hook y no se pueden suprimir; lo nuestro es el texto, y es corto a propósito porque ocupa pantalla del usuario. Se emite con `hookSpecificOutput.additionalContext`, que la documentación llama «non-error feedback»: mantiene el turno extra y las protecciones contra bucles sin rotularse como error. En una versión de Claude Code anterior a ese campo la petición no llega — no rompe nada |
297
+ | Dónde funciona | Los tres, con el contrato de cada uno: `decision: "block"` en Claude Code y Codex, `decision: "continue"` en Antigravity, que trata cualquier otro valor como permiso para parar |
298
+ | En Codex | su hook `Stop` se registra **síncrono**, porque un hook en segundo plano no puede bloquear. Esperas la captura (~340 ms) al cerrar cada turno |
299
+
300
+ ### La primera vez, verifica
301
+
302
+ Al abrir el segundo CLI, pregúntale *«¿qué sabes del estado de este trabajo?»*.
303
+ Si responde con los archivos tocados y qué quedó a medias, funcionó. Si no,
304
+ `chaski doctor` te dice qué hook no quedó registrado y dónde.
305
+
306
+ ### La misma petición en los tres agentes
307
+
308
+ Escribe en el **chat del agente**:
309
+
310
+ ```text
311
+ relevo
312
+ ```
313
+
314
+ También reconoce **«guarda el relevo»** y **«actualiza el relevo»**. Es una petición
315
+ en lenguaje natural que activa la skill instalada por `chaski init`; depende de
316
+ que el agente haya cargado las instrucciones del proyecto. Espera su confirmación.
317
+ Para retomar, escribe **«continúa desde el relevo»**: pide leer y continuar el
318
+ trabajo, sin sobrescribir la narrativa al llegar.
319
+
320
+ Los atajos nativos siguen disponibles si prefieres seleccionar la skill:
321
+
322
+ | Agente | Atajo para guardar |
323
+ |---|---|
324
+ | [Claude Code](https://code.claude.com/docs/en/skills) | `/relevo` |
325
+ | [Codex CLI](https://learn.chatgpt.com/docs/build-skills) | `$relevo` o `/skills` → `relevo` |
326
+ | [agy](https://antigravity.google/docs/skills/#slash-command-conversion) | `/relevo` |
327
+
328
+ Si la skill aún no aparece tras actualizar, abre una sesión nueva en ese proyecto
329
+ (en agy también puedes ejecutar `/skills reload`).
330
+
331
+ Los **hechos** —archivos, diff, exit codes, commits— se escriben solos en cada
332
+ turno, sin costo. La **narrativa** —qué estás intentando, qué decidiste, qué
333
+ descartaste y por qué— la escribe el agente cuando pides **«relevo»**.
334
+
335
+ No es obligatorio. Sin narrativa el relevo sigue siendo útil, porque los hechos
336
+ son lo que evita que el siguiente agente rompa algo. La narrativa es lo que
337
+ evita que reabra decisiones ya cerradas.
338
+
339
+ ### Otros comandos del día a día
340
+
341
+ ```bash
342
+ chaski next # muestra qué CLI está disponible y qué quedó pendiente
343
+ chaski cost # muestra el gasto externo ($0) y los turnos extra de chaski
344
+ chaski why [tema] # busca decisiones anteriores en .tambo/historia/ y decisiones/
345
+ chaski share [tema] # publica la decisión de la rama actual en decisiones/ (pide confirmación)
346
+ chaski share [tema] --yes # publica sin pedir confirmación interactiva
347
+ chaski version # muestra la versión instalada (también chaski --version)
348
+ ```
349
+
350
+ - **`chaski next`** lee `~/.chaski/quota.json` (alimentado cuando un hook detecta
351
+ un corte por `rate_limit`) y el `estado.json` de tu rama para decirte en un
352
+ segundo a qué CLI cambiarte y qué archivos o pasos quedaron en vuelo.
353
+ - **`chaski cost`** reporta el gasto externo (`0 tokens · $0.00`, porque chaski
354
+ nunca llama a APIs ni modelos externos) y contabiliza cuántos turnos extra
355
+ pidió chaski y cuántas narrativas escribió cada CLI en los últimos 7 días.
356
+ - **`chaski why [tema]`** busca en `.tambo/historia/entries.jsonl` —el archivo
357
+ append-only donde `capture.mjs` preserva cada narrativa antes de que la
358
+ siguiente la reemplace—, en las ramas activas y en `decisiones/`.
359
+ - **`chaski share [tema]`** toma la narrativa de la rama actual, vuelve a pasar
360
+ el filtro de secretos de `src/lib/secrets.mjs`, muestra en pantalla la ruta
361
+ `decisiones/YYYY-MM-DD-<tema>.md` y el contenido exacto, y pide confirmación
362
+ antes de escribir (o usa `--yes`). Nunca sobrescribe un archivo existente.
363
+
364
+ ---
365
+
366
+ ## Arquitectura
367
+
368
+ La idea central es **separar hechos de intención**:
369
+
370
+ - **Hechos** (determinísticos, gratis, instantáneos): se derivan de git y del
371
+ transcript. Cero tokens, cero red, y exactos por construcción.
372
+ - **Intención** (requiere un modelo): por qué se eligió un enfoque, qué falta.
373
+ Esto no está en el diff; está en la conversación.
374
+
375
+ El 70% del valor de un relevo está en la capa de hechos, y no cuesta nada. Por
376
+ eso el modelo es el último recurso y no el primero.
377
+
378
+ | Archivo | Cuándo corre | Qué hace |
379
+ |---|---|---|
380
+ | `src/capture.mjs` | hooks `Stop`, `SessionEnd`, `PreCompact`, `SubagentStop`, `StopFailure` | Lee el transcript desde una marca de agua y git; escribe `relevo.md`, `estado.json` y `.tambo/historia/` |
381
+ | `src/inject.mjs` | hook `SessionStart` | Imprime el relevo; lo que imprime entra al contexto del agente |
382
+ | `src/cli.mjs` | a mano | `init`, `doctor`, `next`, `cost`, `why`, `share`, `uninstall`, `probe` |
383
+ | `skill/SKILL.md` | al pedir «relevo» | Instrucciones para que el agente escriba la narrativa |
384
+
385
+ Archivos que genera en tu proyecto:
386
+
387
+ ```
388
+ .tambo/
389
+ branches/
390
+ main/relevo.md ← lo que se inyecta
391
+ main/estado.json ← hechos, marca de agua, firma
392
+ feat-pagos/relevo.md ← otra rama, otro contexto
393
+ historia/
394
+ entries.jsonl ← narrativas históricas (append-only, para chaski why)
395
+ ```
396
+
397
+ Y en `~/.chaski/`: la clave de firma, los latidos de cada CLI, el estado de
398
+ cuota (`quota.json`), la contabilidad de turnos (`cost.json`) y la config global.
399
+
400
+ El diseño completo, con los riesgos y la investigación de términos de uso, está
401
+ en [`docs/diseno.html`](docs/diseno.html). Describe el diseño entero, incluidas
402
+ piezas que todavía no existen: abre con una tabla que distingue lo construido
403
+ de lo pendiente.
404
+
405
+ La auditoría de noviembre de 2026 —qué se revisó, qué se encontró y qué se
406
+ decidió **no** arreglar, con el motivo— está en
407
+ [`docs/auditoria-2026-11.md`](docs/auditoria-2026-11.md). Si vas a cambiar algo
408
+ aquí, la sección de límites conocidos te ahorra descubrirlos de nuevo.
409
+
410
+ ---
411
+
412
+ ## Configuración
413
+
414
+ Todo tiene valores por defecto razonables. No hace falta configurar nada.
415
+
416
+ ### `chaski.json` — política del proyecto, **se versiona**
417
+
418
+ ```json
419
+ {
420
+ "redact": ["MI_PATRON_SECRETO_[A-Z0-9]+"],
421
+ "excludePaths": ["^infra/secretos/", "\\.tfstate$"]
422
+ }
423
+ ```
424
+
425
+ | Clave | Qué hace |
426
+ |---|---|
427
+ | `redact` | Expresiones regulares extra para redactar antes de escribir |
428
+ | `excludePaths` | Rutas que nunca aparecen en el relevo |
429
+ | `pruneAfterDays` | Días antes de borrar el relevo de una rama que ya no existe. Por defecto 30; `0` desactiva la limpieza |
430
+ | `pruneNarrativeAfterDays` | Lo mismo para los relevos que tienen narrativa. Por defecto 90 |
431
+
432
+ Los relevos con narrativa viven el triple a propósito: los hechos se
433
+ recalculan desde git en cualquier momento, pero la narrativa existe solo
434
+ porque alguien la escribió y no se recupera. Un relevo de rama viva no se
435
+ borra nunca, sin importar la antigüedad.
436
+
437
+ ### `chaski.local.json` — tu máquina, **en `.gitignore`**
438
+
439
+ Mismas claves. Se suma a la del proyecto en lugar de reemplazarla.
440
+
441
+ La partición es deliberada: tu equipo comparte la política del repositorio, pero
442
+ cada máquina declara lo suyo. Alguien clona y funciona, sin heredar la
443
+ configuración de nadie.
444
+
445
+ ---
446
+
447
+ ## Equipos y repositorios compartidos
448
+
449
+ Hay una regla que gobierna este escenario: **un archivo que se reescribe
450
+ automáticamente nunca va en git.** Versionar el relevo produciría conflictos de
451
+ merge permanentes sobre contenido que nadie quiere resolver.
452
+
453
+ Por eso `.tambo/` entra al `.gitignore` y `doctor` avisa si alguien lo trackea.
454
+ Cada persona tiene su propio relevo, local. Lo que el equipo sí comparte son las
455
+ convenciones estables, y esas van en `AGENTS.md`, que los tres CLIs ya leen de
456
+ forma nativa.
457
+
458
+ > Nota práctica: si `.tambo/` no está ignorado, `git stash -u` y los `checkout`
459
+ > se llevan tus relevos. Verificado a la mala durante el desarrollo.
460
+
461
+ ---
462
+
463
+ ## Seguridad
464
+
465
+ **El relevo es texto que se inyecta en el contexto de un agente con permisos de
466
+ escritura.** Eso lo convierte en un vector de inyección de prompt, así que:
467
+
468
+ - Se declara como datos y no como instrucciones, entre delimitadores explícitos.
469
+ - Se firma con HMAC contra una clave local en `~/.chaski/clave`, que nunca se
470
+ versiona. Si la firma no valida, el relevo se inyecta **rotulado como no
471
+ verificado** en lugar de descartarse en silencio.
472
+ - `.tambo/` va en `.gitignore`: no viaja entre máquinas por git.
473
+ - Tiene techo de tamaño, así que un relevo inflado no puede desplazar tu
474
+ contexto de trabajo.
475
+
476
+ **El filtro de secretos corre antes de escribir**, no solo antes de enviar: un
477
+ token en `.tambo/relevo.md` ya es una fuga aunque nunca salga de la máquina.
478
+ Cubre ~20 formatos de credencial, cadenas de alta entropía, asignaciones con
479
+ nombre sensible, URLs con credenciales y cabeceras `Authorization`. Las rutas
480
+ tipo `.env`, `*.pem` o `id_rsa` nunca aparecen en el relevo. Lo redactado deja
481
+ marca visible, para que nadie confunda una redacción con un dato ausente.
482
+
483
+ **Alcance de escritura:** `.tambo/` del proyecto, `~/.chaski/`, y los archivos
484
+ de configuración de los CLIs que habilitaste. En ningún otro lugar. No ejecuta
485
+ scripts del repositorio, no abre puertos y no hace commits.
486
+
487
+ Para reportar una vulnerabilidad, ver [SECURITY.md](SECURITY.md).
488
+
489
+ ---
490
+
491
+ ## Términos de uso de los proveedores
492
+
493
+ **chaski no invoca ningún CLI automáticamente.** Ni `claude -p`, ni
494
+ `codex exec`, ni `agy -p`.
495
+
496
+ Esto no es una limitación técnica, es una decisión informada. Los términos de
497
+ consumidor de Anthropic prohíben acceder a los servicios «por medios
498
+ automatizados o no humanos, mediante bot, script o de otro modo» salvo con una
499
+ API key. Google respondió oficialmente que los requests automáticos y
500
+ desatendidos no están soportados en planes de consumidor y pueden activar
501
+ bloqueos de cuenta — y hay suspensiones documentadas en sus foros. OpenAI apunta
502
+ a usar una API key para automatización.
503
+
504
+ La narrativa la escribe **el agente que ya tienes abierto**, que es uso
505
+ interactivo de una sesión que iniciaste tú. Si prefieres que la genere un
506
+ proceso aparte, configura tu propia API key: esa es la excepción que los
507
+ términos nombran explícitamente.
508
+
509
+ No existe una opción de configuración para invocar tu suscripción de forma
510
+ automática. No está implementada a propósito: una configuración que pone en
511
+ riesgo tu cuenta no debería estar a un flag de distancia.
512
+
513
+ ---
514
+
515
+ ## Lo que chaski no hace
516
+
517
+ - **No funciona en modo headless.** Verificado empíricamente en los tres:
518
+ `claude -p`, `codex exec` y `agy -p` no disparan los hooks `SessionStart` ni
519
+ `Stop`. chaski es para sesiones interactivas; si lo necesitas en CI, esta
520
+ herramienta no es la indicada.
521
+ - **No busca en el historial de meses atrás**, no comparte memoria con tu
522
+ equipo, no administra cuotas y no soporta veinte herramientas. Si necesitas
523
+ eso, [ai-memory](https://github.com/akitaonrails/ai-memory) es más completo y
524
+ está más maduro.
525
+ - **No hace commits** ni toca tu historial de git.
526
+
527
+ ---
528
+
529
+ ## Límites conocidos
530
+
531
+ | Límite | Valor | Por qué |
532
+ |---|---|---|
533
+ | Latencia del hook | ~340 ms, de los cuales unos 250 son subprocesos de git | El presupuesto de `Stop` en Claude Code es de 1,5 s **compartido** entre todos los hooks del evento. Hay margen de 5x, pero si tienes muchos hooks ahí, mide |
534
+ | Tamaño del relevo | 6.000 caracteres | Por encima de 10.000, Claude Code reemplaza el contenido por una ruta y el relevo no llega |
535
+ | Narrativa | puede atrasarse unos turnos | Los hechos están siempre al día; el porqué depende de cuándo pediste «relevo» |
536
+ | Hooks de Codex | requieren conceder confianza | La primera vez que abres Codex con hooks instalados pide confiar en ellos. Hasta que aceptes, no se ejecuta ninguno, y el permiso se aplica desde la sesión siguiente |
537
+ | Un turno con miles de archivos modificados | el relevo sale **incompleto, y lo dice** | El hook tiene un presupuesto de tiempo propio y sacrifica lo caro y poco informativo antes de agotarlo: primero el detalle de líneas `+/-` por archivo, después el log de commits. La rama, el `HEAD`, la lista de archivos y su total siempre sobreviven. Lo que se omitió aparece declarado en el relevo, porque un relevo incompleto que se presenta como completo es peor que uno recortado. Medido: 5.000 archivos modificados pasaban de 2.000 ms —y perdían el relevo entero— y ahora el hook completo tarda ~340 ms |
538
+ | Ruta del proyecto de más de ~240 caracteres | los subprocesos de git fallan | En Windows, una ruta así de larga hace que el subproceso de git falle. chaski lo interpreta como «esto no es un repositorio git» y lo reporta en silencio, perdiendo también la detección de la rama. No hay arreglo barato conocido: evita rutas tan largas para este proyecto |
539
+
540
+ Si un administrador fijó `allowManagedHooksOnly` o `disableAllHooks` en una
541
+ máquina corporativa, los hooks de usuario no corren. `doctor` lo detecta y lo
542
+ informa en vez de dejarte creyendo que funciona.
543
+
544
+ **`doctor` siempre termina con código de salida 0**, incluso cuando ningún CLI
545
+ tiene los hooks registrados. Es un comando de diagnóstico para que lo lea una
546
+ persona, no una verificación para encadenar en un script o en CI — si
547
+ necesitas eso, revisa su salida de texto, no su código de salida. (`init` sí
548
+ termina en 1 si algún CLI falló al configurarse.)
549
+
550
+ **Relevos de antes del renombre a `branches/`.** Versiones viejas de chaski
551
+ guardaban el relevo en `.tambo/ramas/<rama>/`. Ni `inject.mjs` ni `doctor`
552
+ migran ni mencionan esa carpeta: si tienes relevos ahí, quedaron huérfanos.
553
+ Para recuperarlos a mano, copia el contenido de
554
+ `.tambo/ramas/<rama>/estado.json` al campo `narrative` (y
555
+ `narrativeAuthor`/`narrativeWrittenAt`) del `estado.json` nuevo en
556
+ `.tambo/branches/<rama>/` — los hechos no se recuperan porque ya están
557
+ obsoletos, pero la narrativa escrita a mano sí vale la pena rescatarla.
558
+ Después puedes borrar `.tambo/ramas/`.
559
+
560
+ **Falsa alarma de firma con clientes de sincronización.** Si OneDrive, Dropbox
561
+ o similar bloquean `estado.json` justo cuando `capture.mjs` está escribiendo,
562
+ puede quedar un `relevo.md` nuevo firmado junto a un `estado.json` que todavía
563
+ tiene la firma anterior. La sesión siguiente ve la firma desajustada y avisa
564
+ de una posible manipulación aunque no haya pasado nada malintencionado — es un
565
+ falso positivo del mecanismo de integridad, no una vulnerabilidad.
566
+
567
+ ---
568
+
569
+ ## Contribuir
570
+
571
+ Las contribuciones son bienvenidas. Antes de abrir un PR, lee
572
+ [AGENTS.md](AGENTS.md): tiene los ocho invariantes del proyecto, los
573
+ presupuestos de latencia y tamaño, y las trampas conocidas de cada CLI.
574
+
575
+ El más importante: **cero dependencias de runtime**. La herramienta se ejecuta
576
+ sola en cada turno, así que un árbol de npm sería superficie de ataque.
577
+
578
+ Agregar soporte para otro CLI es un archivo en `src/lib/` más una entrada en el
579
+ mapa `CLIS` de `src/cli.mjs`.
580
+
581
+ ## Soporte
582
+
583
+ - **Bugs y propuestas:** abre un issue en el repositorio.
584
+ - **Diagnóstico:** incluye la salida de `chaski doctor` (no contiene secretos) y
585
+ las versiones de tus CLIs.
586
+
587
+ ## Licencia
588
+
589
+ MIT — ver [LICENSE](LICENSE).