8f6958f856
Registra los nuevos issues pendientes en el indice y excluye la carpeta worktrees/ del control de versiones. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7.8 KiB
7.8 KiB
0031 — Expandir tools/file/ con write, list, append, delete
Objetivo
Ampliar el paquete tools/file/ con operaciones de escritura, listado, append y borrado. Mantener el patron deny-by-default, validacion de symlinks, y respetar el flag read_only del config.
Contexto
tools/file/file.goactualmente solo tieneread_file(107 lineas)- Seguridad existente: deny-by-default, symlink resolution via
EvalSymlinks, output truncation a 64KB - Helpers existentes:
validatePath()yresolveReal()ya estan listos para reutilizarse - Config
FileOpsCfgtiene camposAllowedPaths []stringyReadOnly bool— ReadOnly ya existe pero no se usa porque no hay operaciones de escritura - Los agentes necesitan interactuar con carpetas de trabajo (workspaces, proyectos, outputs)
Arquitectura
tools/file/file.go → mantener read_file + validatePath (existente)
tools/file/write.go NEW → write_file tool
tools/file/list.go NEW → list_directory tool
tools/file/append.go NEW → append_file tool
tools/file/delete.go NEW → delete_file tool
tools/file/file_test.go → ampliar tests existentes
tools/file/write_test.go NEW → tests de escritura
tools/file/list_test.go NEW → tests de listado
tools/file/delete_test.go NEW → tests de borrado
agents/runtime.go → registrar nuevas tools en buildToolRegistry()
Patron pure core / impure shell
pkg/— sin cambiostools/file/— cada tool sigue el patron Def (puro) + Exec (impuro)agents/— solo cambio en registro de tools
Tareas
Fase 1: Refactor de validacion compartida
- 1.1 Extraer
validatePath()yresolveReal()atools/file/validate.go(ya son funciones internas, solo moverlas para reutilizarlas) - 1.2 Crear helper
validateWritePath(absPath, cfg)que ademas verificaReadOnly == false
Fase 2: write_file
- 2.1 Crear
tools/file/write.goconNewWriteFile(cfg) tools.Tool - 2.2 Parametros:
path(string, required),content(string, required) - 2.3 Validaciones:
- Rechazar si
cfg.ReadOnly == true validatePath()contra AllowedPaths- Crear directorios padre si no existen (
os.MkdirAll) - Limite de contenido: max 1MB de input
- Rechazar si
- 2.4 Devolver confirmacion con bytes escritos y path
Fase 3: list_directory
- 3.1 Crear
tools/file/list.goconNewListDirectory(cfg) tools.Tool - 3.2 Parametros:
path(string, required),recursive(boolean, optional, default false) - 3.3 Validaciones:
validatePath()contra AllowedPaths- Limite de entries: max 500 archivos en el output
- No seguir symlinks fuera de AllowedPaths
- 3.4 Output: lista con nombre, tamaño, tipo (file/dir), fecha modificacion
Fase 4: append_file
- 4.1 Crear
tools/file/append.goconNewAppendFile(cfg) tools.Tool - 4.2 Parametros:
path(string, required),content(string, required) - 4.3 Validaciones:
- Rechazar si
cfg.ReadOnly == true validatePath()contra AllowedPaths- Si el archivo no existe, crearlo (igual que write)
- Limite de tamaño: verificar que archivo existente + contenido nuevo < 10MB
- Rechazar si
- 4.4 Devolver confirmacion con bytes añadidos y tamaño total
Fase 5: delete_file
- 5.1 Crear
tools/file/delete.goconNewDeleteFile(cfg) tools.Tool - 5.2 Parametros:
path(string, required) - 5.3 Validaciones:
- Rechazar si
cfg.ReadOnly == true validatePath()contra AllowedPaths- Solo archivos: no permitir borrar directorios (prevencion de
rm -rfaccidental) - Resolver symlinks antes de borrar (no borrar el symlink si apunta fuera de AllowedPaths)
- Rechazar si
- 5.4 Devolver confirmacion con path eliminado
Fase 6: Registro en runtime
- 6.1 En
agents/runtime.go→buildToolRegistry(), registrar las 4 tools nuevas condicionalmente:if cfg.Tools.FileOps.Enabled { reg.Register(file.NewReadFile(cfg.Tools.FileOps)) if !cfg.Tools.FileOps.ReadOnly { reg.Register(file.NewWriteFile(cfg.Tools.FileOps)) reg.Register(file.NewAppendFile(cfg.Tools.FileOps)) reg.Register(file.NewDeleteFile(cfg.Tools.FileOps)) } reg.Register(file.NewListDirectory(cfg.Tools.FileOps)) } - 6.2
list_directoryse registra siempre (no requiere escritura)
Fase 7: Tests
- 7.1 Test:
write_filecrea archivo nuevo en AllowedPaths - 7.2 Test:
write_filerechaza si ReadOnly es true - 7.3 Test:
write_filerechaza paths fuera de AllowedPaths - 7.4 Test:
write_filerechaza contenido > 1MB - 7.5 Test:
list_directorylista correctamente archivos y subdirectorios - 7.6 Test:
list_directoryrespeta limite de 500 entries - 7.7 Test:
list_directoryno sigue symlinks fuera de AllowedPaths - 7.8 Test:
append_fileañade contenido al final - 7.9 Test:
append_filecrea archivo si no existe - 7.10 Test:
delete_fileborra archivo existente - 7.11 Test:
delete_filerechaza borrar directorios - 7.12 Test:
delete_filerechaza si ReadOnly es true - 7.13 Test: symlink que apunta fuera de AllowedPaths es rechazado en todas las tools
- 7.14 Test: path traversal (
../) es rechazado en todas las tools
Fase 8: Cleanup
- 8.1 Actualizar
CLAUDE.mdseccion de tools con las nuevas herramientas - 8.2 Actualizar
.claude/rules/create_tool.mdsi hay nuevos patrones - 8.3
go build -tags goolm ./...ygo test -tags goolm ./...
Ejemplo de uso
Config del agente:
tools:
file:
enabled: true
allowed_paths:
- "/home/ubuntu/workspace/proyecto-x"
read_only: false
Interaccion en Element:
Usuario: Lista los archivos en /home/ubuntu/workspace/proyecto-x/src
Bot: [usa list_directory] Encontre 12 archivos:
- main.go (2.3 KB, 2026-04-01)
- handler.go (1.1 KB, 2026-04-02)
- ...
Usuario: Escribe un archivo test.txt con "hola mundo"
Bot: [usa write_file] Archivo creado: /home/ubuntu/workspace/proyecto-x/test.txt (10 bytes)
Usuario: Añade una linea mas al test.txt
Bot: [usa append_file] Contenido añadido: 15 bytes (total: 25 bytes)
Usuario: Borra el test.txt
Bot: [usa delete_file] Archivo eliminado: /home/ubuntu/workspace/proyecto-x/test.txt
Intento fuera de AllowedPaths:
Usuario: Lee /etc/passwd
Bot: Error: path "/etc/passwd" not under any allowed path
Decisiones de diseno
- ReadOnly como gate:
write_file,append_file,delete_filesolo se registran siReadOnly == false.read_fileylist_directorysiempre se registran si file tools esta habilitado - Solo archivos en delete: borrar directorios es demasiado peligroso para un agente autonomo. Si necesita borrar un directorio, puede borrar archivos uno por uno
- Limites de tamaño: 1MB para write (evita saturar disco), 64KB para read output (evita saturar contexto LLM), 500 entries para list (evita listados enormes)
- Crear padres automaticamente:
write_filehaceMkdirAllpara crear la estructura de directorios. Simplifica el uso sin riesgo de seguridad (los paths padre tambien estan bajo AllowedPaths) - Reutilizar validatePath(): misma logica de seguridad para todas las operaciones. Un solo punto de validacion
Prerequisitos
- Ninguno
Riesgos
- Escritura accidental: un agente con LLM podria decidir escribir archivos incorrectos. Mitigacion: AllowedPaths restringe donde puede escribir, y el system prompt debe instruir al agente sobre cuando escribir
- Race conditions: dos agentes escribiendo el mismo archivo. Mitigacion: file locking no es necesario en la primera version; los agentes tipicamente tienen workspaces separados
- Disk exhaustion: un agente escribiendo en loop. Mitigacion: rate limiting del tool registry + limite de 1MB por write