@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/AGENTS.md +376 -0
- package/CHANGELOG.md +289 -0
- package/LICENSE +21 -0
- package/README.md +588 -2
- package/SECURITY.md +75 -0
- package/package.json +48 -4
- package/skill/SKILL.md +80 -0
- package/src/capturar.mjs +24 -0
- package/src/capture.mjs +545 -0
- package/src/cli.mjs +1053 -0
- package/src/inject.mjs +199 -0
- package/src/leer.mjs +19 -0
- package/src/lib/ask.mjs +194 -0
- package/src/lib/budget.mjs +64 -0
- package/src/lib/facts.mjs +566 -0
- package/src/lib/paths.mjs +323 -0
- package/src/lib/relay.mjs +303 -0
- package/src/lib/secrets.mjs +148 -0
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
|
-
#
|
|
1
|
+
# chaski
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/cristobalbn/chaski/actions/workflows/test.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
[](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).
|