telar 0.1.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.
Files changed (101) hide show
  1. telar-0.1.0/LICENSE +21 -0
  2. telar-0.1.0/MANIFEST.in +10 -0
  3. telar-0.1.0/NOTICE +29 -0
  4. telar-0.1.0/PKG-INFO +158 -0
  5. telar-0.1.0/README.md +136 -0
  6. telar-0.1.0/docs/agentes.md +204 -0
  7. telar-0.1.0/docs/configuracion.md +133 -0
  8. telar-0.1.0/docs/contratos.md +493 -0
  9. telar-0.1.0/docs/estado.md +241 -0
  10. telar-0.1.0/docs/hallazgos.md +336 -0
  11. telar-0.1.0/docs/perfil.md +180 -0
  12. telar-0.1.0/docs/publicar.md +93 -0
  13. telar-0.1.0/ejemplo/README.md +22 -0
  14. telar-0.1.0/ejemplo/notas/madera.md +7 -0
  15. telar-0.1.0/ejemplo/proyectos/arboleda/README.md +10 -0
  16. telar-0.1.0/ejemplo/proyectos/faro/README.md +31 -0
  17. telar-0.1.0/ejemplo/proyectos/molino/README.md +11 -0
  18. telar-0.1.0/ejemplo/telar-perfil.yaml +65 -0
  19. telar-0.1.0/pruebas/comun.py +44 -0
  20. telar-0.1.0/pruebas/test_agente.py +584 -0
  21. telar-0.1.0/pruebas/test_calendario.py +344 -0
  22. telar-0.1.0/pruebas/test_cli.py +105 -0
  23. telar-0.1.0/pruebas/test_config.py +129 -0
  24. telar-0.1.0/pruebas/test_estado.py +429 -0
  25. telar-0.1.0/pruebas/test_estado_renombre.py +52 -0
  26. telar-0.1.0/pruebas/test_ficha_config.py +36 -0
  27. telar-0.1.0/pruebas/test_lectura.py +148 -0
  28. telar-0.1.0/pruebas/test_modelo.py +68 -0
  29. telar-0.1.0/pruebas/test_mux_tmux.py +974 -0
  30. telar-0.1.0/pruebas/test_mux_tmux_real.py +98 -0
  31. telar-0.1.0/pruebas/test_mux_zellij.py +287 -0
  32. telar-0.1.0/pruebas/test_mux_zellij_base.py +113 -0
  33. telar-0.1.0/pruebas/test_ordenes.py +434 -0
  34. telar-0.1.0/pruebas/test_perfil.py +137 -0
  35. telar-0.1.0/pruebas/test_proveedor_estado.py +473 -0
  36. telar-0.1.0/pruebas/test_salida.py +129 -0
  37. telar-0.1.0/pruebas/test_tareas.py +454 -0
  38. telar-0.1.0/pyproject.toml +44 -0
  39. telar-0.1.0/setup.cfg +4 -0
  40. telar-0.1.0/src/telar/__init__.py +24 -0
  41. telar-0.1.0/src/telar/agente/__init__.py +122 -0
  42. telar-0.1.0/src/telar/agente/base.py +558 -0
  43. telar-0.1.0/src/telar/agente/claude_code.py +425 -0
  44. telar-0.1.0/src/telar/cli.py +186 -0
  45. telar-0.1.0/src/telar/config.py +255 -0
  46. telar-0.1.0/src/telar/estado.py +888 -0
  47. telar-0.1.0/src/telar/lectura.py +355 -0
  48. telar-0.1.0/src/telar/modelo.py +155 -0
  49. telar-0.1.0/src/telar/mux/__init__.py +107 -0
  50. telar-0.1.0/src/telar/mux/base.py +382 -0
  51. telar-0.1.0/src/telar/mux/tmux.py +573 -0
  52. telar-0.1.0/src/telar/mux/zellij.py +687 -0
  53. telar-0.1.0/src/telar/ordenes/__init__.py +18 -0
  54. telar-0.1.0/src/telar/ordenes/_comun.py +618 -0
  55. telar-0.1.0/src/telar/ordenes/accion.py +109 -0
  56. telar-0.1.0/src/telar/ordenes/agente.py +457 -0
  57. telar-0.1.0/src/telar/ordenes/atencion.py +118 -0
  58. telar-0.1.0/src/telar/ordenes/config.py +95 -0
  59. telar-0.1.0/src/telar/ordenes/doctor.py +496 -0
  60. telar-0.1.0/src/telar/ordenes/ficha.py +162 -0
  61. telar-0.1.0/src/telar/ordenes/hilo.py +310 -0
  62. telar-0.1.0/src/telar/ordenes/hilos.py +110 -0
  63. telar-0.1.0/src/telar/ordenes/hoy.py +138 -0
  64. telar-0.1.0/src/telar/ordenes/init.py +301 -0
  65. telar-0.1.0/src/telar/ordenes/ir.py +52 -0
  66. telar-0.1.0/src/telar/ordenes/pendiente.py +172 -0
  67. telar-0.1.0/src/telar/ordenes/pendientes.py +170 -0
  68. telar-0.1.0/src/telar/ordenes/perfil.py +105 -0
  69. telar-0.1.0/src/telar/ordenes/tejer.py +159 -0
  70. telar-0.1.0/src/telar/ordenes/tiempo.py +143 -0
  71. telar-0.1.0/src/telar/ordenes/vincular.py +28 -0
  72. telar-0.1.0/src/telar/perfil.py +408 -0
  73. telar-0.1.0/src/telar/proveedores/__init__.py +87 -0
  74. telar-0.1.0/src/telar/proveedores/calendario.py +693 -0
  75. telar-0.1.0/src/telar/proveedores/estado.py +902 -0
  76. telar-0.1.0/src/telar/proveedores/tareas.py +702 -0
  77. telar-0.1.0/src/telar/salida.py +134 -0
  78. telar-0.1.0/src/telar.egg-info/PKG-INFO +158 -0
  79. telar-0.1.0/src/telar.egg-info/SOURCES.txt +99 -0
  80. telar-0.1.0/src/telar.egg-info/dependency_links.txt +1 -0
  81. telar-0.1.0/src/telar.egg-info/entry_points.txt +2 -0
  82. telar-0.1.0/src/telar.egg-info/requires.txt +1 -0
  83. telar-0.1.0/src/telar.egg-info/top_level.txt +1 -0
  84. telar-0.1.0/vscode/.vscode/launch.json +13 -0
  85. telar-0.1.0/vscode/.vscode/tasks.json +18 -0
  86. telar-0.1.0/vscode/README.md +126 -0
  87. telar-0.1.0/vscode/media/telar.svg +8 -0
  88. telar-0.1.0/vscode/package-lock.json +4304 -0
  89. telar-0.1.0/vscode/package.json +666 -0
  90. telar-0.1.0/vscode/src/acciones.ts +28 -0
  91. telar-0.1.0/vscode/src/cli.ts +227 -0
  92. telar-0.1.0/vscode/src/estilo.ts +99 -0
  93. telar-0.1.0/vscode/src/extension.ts +343 -0
  94. telar-0.1.0/vscode/src/modelo.ts +88 -0
  95. telar-0.1.0/vscode/src/vistas/carpeta.ts +75 -0
  96. telar-0.1.0/vscode/src/vistas/dia.ts +281 -0
  97. telar-0.1.0/vscode/src/vistas/ficha.ts +296 -0
  98. telar-0.1.0/vscode/src/vistas/hilos.ts +178 -0
  99. telar-0.1.0/vscode/src/vistas/hoy.ts +149 -0
  100. telar-0.1.0/vscode/src/vistas/tareas.ts +69 -0
  101. telar-0.1.0/vscode/tsconfig.json +13 -0
telar-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nicolás Rivas
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.
@@ -0,0 +1,10 @@
1
+ # El sdist lleva el proyecto entero: el ejemplo y las pruebas son parte de lo que se
2
+ # revisa antes de instalar algo que va a hablar con tu terminal.
3
+ include LICENSE NOTICE README.md
4
+ recursive-include docs *.md
5
+ recursive-include ejemplo *
6
+ recursive-include pruebas *.py
7
+ recursive-include vscode *.json *.md *.ts *.svg
8
+ prune vscode/node_modules
9
+ prune vscode/out
10
+ global-exclude __pycache__/* *.pyc
telar-0.1.0/NOTICE ADDED
@@ -0,0 +1,29 @@
1
+ telar
2
+ Copyright (c) 2026 Nicolás Rivas
3
+ Licensed under the MIT License (see LICENSE).
4
+
5
+ ────────────────────────────────────────────────────────────────────────────
6
+
7
+ Acknowledgements
8
+
9
+ telar grew out of a private system where the project bar was a zellij plugin —
10
+ a fork of cfal/zellij-vertical-tabs:
11
+
12
+ zellij-vertical-tabs
13
+ https://github.com/cfal/zellij-vertical-tabs
14
+ Copyright (c) cfal
15
+ MIT License
16
+
17
+ No code from that project ships in telar: the bar was rewritten as a separate
18
+ view, and telar itself is the engine underneath. The debt is real anyway — the
19
+ idea of tabs as a vertical list of projects, and the first working version of
20
+ it, came from there.
21
+
22
+ ────────────────────────────────────────────────────────────────────────────
23
+
24
+ Dependencies
25
+
26
+ PyYAML — MIT License. https://pyyaml.org/
27
+ Used to read the work repository's telar-perfil.yaml.
28
+
29
+ Everything else telar uses is in the Python standard library.
telar-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: telar
3
+ Version: 0.1.0
4
+ Summary: Un telar para hilos de trabajo: multiplexor de terminal, perfiles de repositorio y agentes.
5
+ Author: Nicolás Rivas
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/nicorivas/telar
8
+ Project-URL: Source, https://github.com/nicorivas/telar
9
+ Keywords: tmux,zellij,terminal,workspace,agents
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: PyYAML>=6.0
21
+ Dynamic: license-file
22
+
23
+ # telar
24
+
25
+ A loom for threads of work.
26
+
27
+ You keep twenty terminal tabs open. Each one is a different piece of work, each has
28
+ an agent running in it, and after a reboot you cannot tell which is which. `telar`
29
+ turns those tabs into **threads**: a tab, a folder, and whatever that folder says
30
+ about itself, held together across restarts.
31
+
32
+ **telar does not decide what a project is.** That is the point. Your work
33
+ repository declares it, in a `telar-perfil.yaml` that ships with the repo — which
34
+ folders are units of work, which file is their face, which sections of that file
35
+ can be read, and which actions the repo offers. Any telar that opens the repo
36
+ weaves the same thing.
37
+
38
+ ## Status
39
+
40
+ Early, but it runs. Configuration, profile, model and state are in place, the
41
+ commands are written, and every `--json` output is a documented contract
42
+ ([docs/contratos.md](docs/contratos.md)). `telar --help` lists what there is, and
43
+ says so plainly when you ask for something that isn't written yet.
44
+
45
+ ## Install
46
+
47
+ ```sh
48
+ pip install telar # once it's published
49
+ pip install -e . # from a clone
50
+ telar --version
51
+ ```
52
+
53
+ Python 3.11+. Standard library only, except PyYAML for reading the profile. A
54
+ terminal multiplexer (tmux 3.0+ or zellij 0.45+) does the actual work of holding tabs.
55
+
56
+ ## Try it
57
+
58
+ Two ways in. **From a clone**, an invented workspace ships with the repo, so you can
59
+ look at a real profile without using anyone's data:
60
+
61
+ ```sh
62
+ git clone https://github.com/nicorivas/telar && cd telar
63
+ telar --raiz ejemplo perfil # what the example workspace declares
64
+ telar --raiz ejemplo pendientes --repo # what those invented projects still owe
65
+ ```
66
+
67
+ **From an install**, start in your own repository — `init` writes a profile you can edit
68
+ and a config file, and touches nothing else:
69
+
70
+ ```sh
71
+ cd ~/work/your-repo
72
+ telar init # profile + config, both yours to edit
73
+ telar doctor # what is missing on this machine, and how to fix it
74
+ telar --help
75
+ ```
76
+
77
+ (`pip install telar` ships the package, not the example; the example travels with the
78
+ source distribution and the clone.)
79
+
80
+ ## A day of it
81
+
82
+ ```sh
83
+ telar init # write the config, find the multiplexer, prepare the state
84
+ telar tejer # raise the session
85
+ telar vincular proyectos/faro # this thread is that folder
86
+ telar hilos # everything open, with the state each folder reports
87
+ telar ficha faro # what that folder says about itself
88
+ telar pendientes # what is left to do, across threads
89
+ telar pendiente faro:2 # take that one to the thread where the work lives
90
+ telar hoy # the day in one screen
91
+ ```
92
+
93
+ Two of them are meant to be called by other programs, not by you:
94
+ `telar tiempo marcar` from the multiplexer whenever the focused tab changes, and
95
+ `telar atencion set espera` from the agent when it needs you. `telar doctor` checks
96
+ whether either is wired.
97
+
98
+ ## Wiring the agent
99
+
100
+ The agent working inside a tab can report what it is doing, and telar writes those
101
+ hooks into the agent's own configuration — for Claude Code, `~/.claude/settings.json`.
102
+ That file belongs to another program, so the command prints the path and the diff and
103
+ waits for a yes:
104
+
105
+ ```sh
106
+ telar agente instalar # show the path and the diff, then ask
107
+ telar agente instalar --seco # what it would write, writing nothing
108
+ telar agente instalar --ajustes FILE # into that file instead of the user's
109
+ telar agente instalar --ejecutable PATH # how the hook should call telar back
110
+ telar agente instalar --si # write without asking (--json skips it too)
111
+ telar agente desinstalar # take telar's hooks out, leave the rest
112
+ ```
113
+
114
+ It merges with the hooks that were already there, keeps a backup beside the file, and
115
+ refuses to write a hook that points at a telar which will not outlive it — one running
116
+ from a temporary virtualenv, say. The six events are in
117
+ [`docs/agentes.md`](docs/agentes.md).
118
+
119
+ ## How it fits together
120
+
121
+ | Piece | Whose | Where |
122
+ |---|---|---|
123
+ | Configuration — multiplexer, session, working root, providers | yours, per machine | `~/.config/telar/config.toml` ([docs](docs/configuracion.md)) |
124
+ | Profile — what a unit of work is, and what can be read from it | the work repository's, versioned with it | `telar-perfil.yaml` ([docs](docs/perfil.md)) |
125
+ | Threads, fichas, attention | derived, disposable | `~/.local/state/telar` |
126
+
127
+ ## What it will not do
128
+
129
+ - **No telemetry.** No usage reports, no phone-home, no auto-update.
130
+ - **No network** beyond what a provider declares — and no provider exists until
131
+ your configuration names it.
132
+ - **No writing to your work repository** unless you ask. Derived state lives
133
+ elsewhere and can be deleted without losing anything.
134
+ - **No silent writes anywhere else, either.** One command edits another program's
135
+ configuration — `telar agente instalar` — and it shows the path and the diff and
136
+ waits for a yes. `--si` is how you say it in a script.
137
+ - **No guessed commands.** It runs the actions the profile declares, as argument
138
+ lists, without a shell in between.
139
+
140
+ ## Documentation
141
+
142
+ Docs are in Spanish, the language this is written in.
143
+
144
+ - [`docs/configuracion.md`](docs/configuracion.md) — the config file, key by key.
145
+ - [`docs/perfil.md`](docs/perfil.md) — the profile schema, and the minimal
146
+ convention that applies when there is no profile.
147
+ - [`docs/contratos.md`](docs/contratos.md) — the shapes telar passes around, written
148
+ so an outside program can produce them. Today: a thread's state.
149
+ - [`docs/agentes.md`](docs/agentes.md) — the six events an agent reports, and what
150
+ another agent would have to do to integrate.
151
+ - [`docs/publicar.md`](docs/publicar.md) — how a version gets out: what to set up
152
+ once, and the runbook per release.
153
+ - [`ejemplo/`](ejemplo/) — a small invented workspace.
154
+ - [`CHANGELOG.md`](CHANGELOG.md) — what changed, version by version.
155
+
156
+ ## License
157
+
158
+ MIT — see [LICENSE](LICENSE) and [NOTICE](NOTICE).
telar-0.1.0/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # telar
2
+
3
+ A loom for threads of work.
4
+
5
+ You keep twenty terminal tabs open. Each one is a different piece of work, each has
6
+ an agent running in it, and after a reboot you cannot tell which is which. `telar`
7
+ turns those tabs into **threads**: a tab, a folder, and whatever that folder says
8
+ about itself, held together across restarts.
9
+
10
+ **telar does not decide what a project is.** That is the point. Your work
11
+ repository declares it, in a `telar-perfil.yaml` that ships with the repo — which
12
+ folders are units of work, which file is their face, which sections of that file
13
+ can be read, and which actions the repo offers. Any telar that opens the repo
14
+ weaves the same thing.
15
+
16
+ ## Status
17
+
18
+ Early, but it runs. Configuration, profile, model and state are in place, the
19
+ commands are written, and every `--json` output is a documented contract
20
+ ([docs/contratos.md](docs/contratos.md)). `telar --help` lists what there is, and
21
+ says so plainly when you ask for something that isn't written yet.
22
+
23
+ ## Install
24
+
25
+ ```sh
26
+ pip install telar # once it's published
27
+ pip install -e . # from a clone
28
+ telar --version
29
+ ```
30
+
31
+ Python 3.11+. Standard library only, except PyYAML for reading the profile. A
32
+ terminal multiplexer (tmux 3.0+ or zellij 0.45+) does the actual work of holding tabs.
33
+
34
+ ## Try it
35
+
36
+ Two ways in. **From a clone**, an invented workspace ships with the repo, so you can
37
+ look at a real profile without using anyone's data:
38
+
39
+ ```sh
40
+ git clone https://github.com/nicorivas/telar && cd telar
41
+ telar --raiz ejemplo perfil # what the example workspace declares
42
+ telar --raiz ejemplo pendientes --repo # what those invented projects still owe
43
+ ```
44
+
45
+ **From an install**, start in your own repository — `init` writes a profile you can edit
46
+ and a config file, and touches nothing else:
47
+
48
+ ```sh
49
+ cd ~/work/your-repo
50
+ telar init # profile + config, both yours to edit
51
+ telar doctor # what is missing on this machine, and how to fix it
52
+ telar --help
53
+ ```
54
+
55
+ (`pip install telar` ships the package, not the example; the example travels with the
56
+ source distribution and the clone.)
57
+
58
+ ## A day of it
59
+
60
+ ```sh
61
+ telar init # write the config, find the multiplexer, prepare the state
62
+ telar tejer # raise the session
63
+ telar vincular proyectos/faro # this thread is that folder
64
+ telar hilos # everything open, with the state each folder reports
65
+ telar ficha faro # what that folder says about itself
66
+ telar pendientes # what is left to do, across threads
67
+ telar pendiente faro:2 # take that one to the thread where the work lives
68
+ telar hoy # the day in one screen
69
+ ```
70
+
71
+ Two of them are meant to be called by other programs, not by you:
72
+ `telar tiempo marcar` from the multiplexer whenever the focused tab changes, and
73
+ `telar atencion set espera` from the agent when it needs you. `telar doctor` checks
74
+ whether either is wired.
75
+
76
+ ## Wiring the agent
77
+
78
+ The agent working inside a tab can report what it is doing, and telar writes those
79
+ hooks into the agent's own configuration — for Claude Code, `~/.claude/settings.json`.
80
+ That file belongs to another program, so the command prints the path and the diff and
81
+ waits for a yes:
82
+
83
+ ```sh
84
+ telar agente instalar # show the path and the diff, then ask
85
+ telar agente instalar --seco # what it would write, writing nothing
86
+ telar agente instalar --ajustes FILE # into that file instead of the user's
87
+ telar agente instalar --ejecutable PATH # how the hook should call telar back
88
+ telar agente instalar --si # write without asking (--json skips it too)
89
+ telar agente desinstalar # take telar's hooks out, leave the rest
90
+ ```
91
+
92
+ It merges with the hooks that were already there, keeps a backup beside the file, and
93
+ refuses to write a hook that points at a telar which will not outlive it — one running
94
+ from a temporary virtualenv, say. The six events are in
95
+ [`docs/agentes.md`](docs/agentes.md).
96
+
97
+ ## How it fits together
98
+
99
+ | Piece | Whose | Where |
100
+ |---|---|---|
101
+ | Configuration — multiplexer, session, working root, providers | yours, per machine | `~/.config/telar/config.toml` ([docs](docs/configuracion.md)) |
102
+ | Profile — what a unit of work is, and what can be read from it | the work repository's, versioned with it | `telar-perfil.yaml` ([docs](docs/perfil.md)) |
103
+ | Threads, fichas, attention | derived, disposable | `~/.local/state/telar` |
104
+
105
+ ## What it will not do
106
+
107
+ - **No telemetry.** No usage reports, no phone-home, no auto-update.
108
+ - **No network** beyond what a provider declares — and no provider exists until
109
+ your configuration names it.
110
+ - **No writing to your work repository** unless you ask. Derived state lives
111
+ elsewhere and can be deleted without losing anything.
112
+ - **No silent writes anywhere else, either.** One command edits another program's
113
+ configuration — `telar agente instalar` — and it shows the path and the diff and
114
+ waits for a yes. `--si` is how you say it in a script.
115
+ - **No guessed commands.** It runs the actions the profile declares, as argument
116
+ lists, without a shell in between.
117
+
118
+ ## Documentation
119
+
120
+ Docs are in Spanish, the language this is written in.
121
+
122
+ - [`docs/configuracion.md`](docs/configuracion.md) — the config file, key by key.
123
+ - [`docs/perfil.md`](docs/perfil.md) — the profile schema, and the minimal
124
+ convention that applies when there is no profile.
125
+ - [`docs/contratos.md`](docs/contratos.md) — the shapes telar passes around, written
126
+ so an outside program can produce them. Today: a thread's state.
127
+ - [`docs/agentes.md`](docs/agentes.md) — the six events an agent reports, and what
128
+ another agent would have to do to integrate.
129
+ - [`docs/publicar.md`](docs/publicar.md) — how a version gets out: what to set up
130
+ once, and the runbook per release.
131
+ - [`ejemplo/`](ejemplo/) — a small invented workspace.
132
+ - [`CHANGELOG.md`](CHANGELOG.md) — what changed, version by version.
133
+
134
+ ## License
135
+
136
+ MIT — see [LICENSE](LICENSE) and [NOTICE](NOTICE).
@@ -0,0 +1,204 @@
1
+ # Los agentes
2
+
3
+ Adentro de un hilo casi siempre hay un agente de línea de comandos trabajando. telar
4
+ **no lo lanza ni lo pilota**: lo reconoce, se entera de en qué anda, y recuerda qué
5
+ conversación vive en qué tab para poder volver a abrirla mañana.
6
+
7
+ Este documento dice qué tiene que hacer un agente —cualquiera— para integrarse.
8
+
9
+ ## Los seis eventos
10
+
11
+ Todo el contrato cabe en seis palabras. Un agente avisa; telar anota.
12
+
13
+ | Evento | Cuándo lo manda | Qué deja escrito |
14
+ |---|---|---|
15
+ | `abre` | arrancó una conversación | este hilo tiene esta conversación, en este panel |
16
+ | `empieza` | se puso a trabajar | atención: `trabajando` |
17
+ | `espera` | necesita a la persona | atención: `espera` |
18
+ | `sigue` | dio señales de vida (corrió una herramienta) | desmiente un `espera` anterior; nada más |
19
+ | `termina` | acabó la respuesta | atención: `termino` |
20
+ | `cierra` | la sesión se acabó | atención: `ninguna` |
21
+
22
+ Los cuatro del medio son exactamente lo que escribe `telar atencion set`: el evento es
23
+ la forma automática de lo mismo que se puede decir a mano. `abre` y `cierra` no hablan
24
+ de atención sino del **registro de conversación por panel**.
25
+
26
+ Tres reglas que están en el código y no se negocian:
27
+
28
+ * **`sigue` no afirma, desmiente.** Una herramienta ejecutada no significa «empecé»;
29
+ significa «si te dije que te esperaba, ya no». Cualquier otra lectura pisa un
30
+ `espera` legítimo que todavía nadie resolvió.
31
+ * **Lo que no cambia no se escribe.** Del otro lado hay una barra vigilando el
32
+ archivo: reescribir `trabajando` sobre `trabajando` la despierta para nada.
33
+ * **Al `cierra` no se borra la conversación.** Se apaga el semáforo y se deja anotada:
34
+ es exactamente la que se va a querer retomar mañana. Quien quiera olvidarla del todo
35
+ lo pide (`telar agente aviso --olvidar`).
36
+
37
+ ## El camino corto: un comando por evento
38
+
39
+ Un agente que sepa correr un comando ya puede integrarse, sin escribir una línea de
40
+ Python y en cualquier lenguaje:
41
+
42
+ ```sh
43
+ telar agente aviso --evento abre --sesion "$ID_DE_LA_CONVERSACION"
44
+ telar agente aviso --evento empieza
45
+ telar agente aviso --evento espera
46
+ telar agente aviso --evento sigue
47
+ telar agente aviso --evento termina
48
+ telar agente aviso --evento cierra --sesion "$ID_DE_LA_CONVERSACION"
49
+ ```
50
+
51
+ Para los cuatro del medio, `telar atencion set trabajando|espera|termino|ninguna` hace
52
+ lo mismo y se lee mejor. `abre` es el que de verdad conviene mandar: es lo que después
53
+ permite `telar agente retomar`.
54
+
55
+ ### Cómo sabe telar en qué hilo pasó
56
+
57
+ En este orden, y **nunca por el foco**:
58
+
59
+ 1. `--hilo`, si se dijo;
60
+ 2. `$TELAR_HILO`, que el multiplexor exportó al abrir el tab y el agente heredó;
61
+ 3. al **abrir**, el panel donde corre el agente (`$TELAR_PANEL`, o `$ZELLIJ_PANE_ID` /
62
+ `$TMUX_PANE`): una conversación que se retoma en otro tab tiene que mudarse con él,
63
+ y el panel es lo único que lo dice;
64
+ 4. la conversación ya anotada, que para todo lo demás es exacta y no cuesta nada;
65
+ 5. el panel otra vez, como último recurso.
66
+
67
+ El foco no está en la lista a propósito. La persona se va a otro tab mientras el agente
68
+ trabaja, y ese es justamente el momento en que se dispara un evento: anotar «el que
69
+ tiene el foco» le pone la atención —o peor, la conversación— al hilo equivocado.
70
+
71
+ Lo barato es que el multiplexor exporte `TELAR_HILO` al crear el tab. Con eso, ningún
72
+ evento necesita preguntarle nada a nadie.
73
+
74
+ ### Las reglas del gancho
75
+
76
+ Quien enganche `telar agente aviso` en su agente hereda tres cuidados que ya están
77
+ resueltos de este lado, pero conviene saber por qué:
78
+
79
+ * **callado**: no imprime nada salvo que se le pida `--json`. Hay agentes que meten la
80
+ salida de sus ganchos en su propio contexto, y un gancho charlatán le habla al agente;
81
+ * **siempre sale con 0**: un gancho que falla no puede frenar a quien lo llamó. Una
82
+ carga rota, un disco lleno o un hilo que no se puede resolver terminan todos en el
83
+ mismo lugar: no hacer nada;
84
+ * **no levanta el multiplexor si no hace falta**: preguntarle cuesta subprocesos y hay
85
+ eventos que se disparan a cada herramienta.
86
+
87
+ ## El camino completo: un adaptador
88
+
89
+ Vale la pena cuando el agente ya manda una carga con todo adentro (como los *hooks* de
90
+ Claude Code) o cuando además se quiere `retomar`, `nuevo` e instalador.
91
+
92
+ Un adaptador es un módulo que hereda de `telar.agente.base.AgenteBase` y se registra:
93
+
94
+ ```python
95
+ from telar.agente import registrar
96
+ from telar.agente.base import AgenteBase, Aviso, Evento
97
+
98
+ class MiAgente(AgenteBase):
99
+ nombre = "mi-agente"
100
+ comandos = ("mi-agente",) # lo que delata al proceso en el panel
101
+
102
+ def leer_aviso(self, crudo, *, evento=None):
103
+ return Aviso(
104
+ evento=evento or MOMENTOS[crudo["tipo"]],
105
+ agente=self.nombre,
106
+ sesion=str(crudo.get("id", "")),
107
+ )
108
+
109
+ def retomar(self, conversacion): # devuelve el comando, NO lo corre
110
+ return ["mi-agente", "--continuar", conversacion.id]
111
+
112
+ def nuevo(self, ruta=None):
113
+ return ["mi-agente"]
114
+
115
+ registrar("mi-agente", lambda config: MiAgente(config))
116
+ ```
117
+
118
+ Eso es todo lo obligatorio. De `AgenteBase` vienen hechos `corriendo`,
119
+ `conversaciones`, `anotar` y `atencion`, y de `telar.agente.base` la traducción entera
120
+ (`atencion_de`, `resolver_hilo`, `aplicar`), que es la misma para todos.
121
+
122
+ Opcional, y recomendado en este orden:
123
+
124
+ | Método | Para qué |
125
+ |---|---|
126
+ | `archivo_de(conversacion)` | dónde quedó el registro de esa conversación en disco |
127
+ | `ganchos()` | qué eventos nativos hay que enganchar (`Gancho`) |
128
+ | `ruta_ajustes()` | dónde vive la configuración del agente en esta máquina |
129
+ | `instalar()` / `desinstalar()` | escribir y sacar los ganchos por el usuario |
130
+
131
+ Si el adaptador viene con telar, se agrega a `telar.agente.INCLUIDOS` (nombre → módulo)
132
+ y se importa solo al pedirlo. Uno de afuera no necesita estar ahí: le basta con que
133
+ algo lo importe para que su `registrar` corra.
134
+
135
+ ### Cuatro cosas que conviene no improvisar
136
+
137
+ * **Reconocer al agente se hace por el proceso, nunca por el título del panel.** Un
138
+ título miente en cuanto alguien lo renombra. `AgenteBase.corriendo` mira el comando
139
+ palabra por palabra, porque muchos agentes se distribuyen como un script que arranca
140
+ otra cosa (`node …/claude`).
141
+ * **`retomar` y `nuevo` devuelven el comando y no lo corren.** Quién lo corre y en qué
142
+ panel es de quien tenga el foco puesto ahí.
143
+ * **El vínculo se anota cuando el agente arranca, no cuando se necesita.** Al resucitar
144
+ una sesión el multiplexor relanza el comando y el agente abre una conversación
145
+ *nueva*; si nadie anotó nada al arrancar, veinte hilos en la misma carpeta son
146
+ indistinguibles.
147
+ * **Un panel corre una conversación a la vez.** Por eso `abre` manda el panel: es lo
148
+ único que permite darse cuenta de que la anterior murió (un `/clear`, o salir y
149
+ volver a entrar) y sacarla del hilo. Sin eso, un hilo acumula conversaciones muertas
150
+ y `retomar` abre la equivocada.
151
+
152
+ ## El adaptador incluido: Claude Code
153
+
154
+ Es el único que viene de fábrica. Traduce así:
155
+
156
+ | Momento de Claude Code | Evento |
157
+ |---|---|
158
+ | `SessionStart` | `abre` |
159
+ | `UserPromptSubmit` | `empieza` |
160
+ | `Notification` | `espera` |
161
+ | `PostToolUse` | `sigue` |
162
+ | `SubagentStop` | `sigue` |
163
+ | `Stop` | `termina` |
164
+ | `SessionEnd` | `cierra` |
165
+
166
+ Son siete momentos y **seis** ganchos: `SubagentStop` se entiende si llega, pero no se
167
+ engancha —un subagente que termina no cambia en qué está la conversación—, así que en tu
168
+ `settings.json` vas a contar seis. Los seis apuntan al **mismo** comando —`telar agente aviso
169
+ claude-code`— y cuál fue viene en el JSON que Claude Code le manda por la entrada
170
+ estándar (`hook_event_name`). Una sola línea que mantener.
171
+
172
+ ```sh
173
+ telar agente instalar # los escribe en ~/.claude/settings.json
174
+ telar agente instalar --seco # muestra cómo quedaría el archivo, sin tocarlo
175
+ telar agente instalar --ajustes ./settings.json
176
+ telar agente desinstalar # saca los de telar, deja los ajenos
177
+ telar agente ver # qué hay puesto, y qué sabe telar de este hilo
178
+ ```
179
+
180
+ El instalador **se mete en casa ajena y se porta como tal**: mezcla con los ganchos que
181
+ ya estaban y solo reemplaza los suyos (se reconocen por su comando), deja un respaldo
182
+ `settings.json.telar.bak` antes de tocar nada, escribe a un temporal que después
183
+ renombra, y ante un JSON que no entiende se niega a escribir en vez de pisarlo. Los
184
+ ganchos recién puestos los lee Claude Code al arrancar de nuevo.
185
+
186
+ Ese respaldo **no se pisa nunca**: si el nombre ya está ocupado —un segundo `instalar`, o
187
+ el `desinstalar` que viene después—, el nuevo sale fechado
188
+ (`settings.json.telar.20260919-142530.bak`). Así el retrato del archivo *antes* de telar
189
+ sobrevive justo a la orden que deshace telar. Y la copia hereda los permisos del
190
+ original: una configuración que era privada sigue siéndolo.
191
+
192
+ Dos detalles de Claude Code que se pagan si no se saben: la carpeta de configuración es
193
+ `~/.claude` salvo que `$CLAUDE_CONFIG_DIR` diga otra, y las conversaciones se guardan en
194
+ `projects/<carpeta con la ruta aplanada>/<id>.jsonl`. Cómo se aplana esa ruta es cosa
195
+ suya y cambia sin avisar, así que telar no la reconstruye: busca el archivo por su
196
+ nombre, que es el id.
197
+
198
+ ## Qué NO hace telar con el agente
199
+
200
+ * no lo lanza ni lo mata: abrir un panel y correr algo ahí es del multiplexor;
201
+ * no lee sus conversaciones —sabe dónde están, y nada más—;
202
+ * no le manda nada por la red, ni le cuenta a nadie qué se hizo;
203
+ * no le escribe en la entrada sin que se lo pidan: `escribir` deja el texto puesto y la
204
+ última palabra es siempre de la persona.