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.
- telar-0.1.0/LICENSE +21 -0
- telar-0.1.0/MANIFEST.in +10 -0
- telar-0.1.0/NOTICE +29 -0
- telar-0.1.0/PKG-INFO +158 -0
- telar-0.1.0/README.md +136 -0
- telar-0.1.0/docs/agentes.md +204 -0
- telar-0.1.0/docs/configuracion.md +133 -0
- telar-0.1.0/docs/contratos.md +493 -0
- telar-0.1.0/docs/estado.md +241 -0
- telar-0.1.0/docs/hallazgos.md +336 -0
- telar-0.1.0/docs/perfil.md +180 -0
- telar-0.1.0/docs/publicar.md +93 -0
- telar-0.1.0/ejemplo/README.md +22 -0
- telar-0.1.0/ejemplo/notas/madera.md +7 -0
- telar-0.1.0/ejemplo/proyectos/arboleda/README.md +10 -0
- telar-0.1.0/ejemplo/proyectos/faro/README.md +31 -0
- telar-0.1.0/ejemplo/proyectos/molino/README.md +11 -0
- telar-0.1.0/ejemplo/telar-perfil.yaml +65 -0
- telar-0.1.0/pruebas/comun.py +44 -0
- telar-0.1.0/pruebas/test_agente.py +584 -0
- telar-0.1.0/pruebas/test_calendario.py +344 -0
- telar-0.1.0/pruebas/test_cli.py +105 -0
- telar-0.1.0/pruebas/test_config.py +129 -0
- telar-0.1.0/pruebas/test_estado.py +429 -0
- telar-0.1.0/pruebas/test_estado_renombre.py +52 -0
- telar-0.1.0/pruebas/test_ficha_config.py +36 -0
- telar-0.1.0/pruebas/test_lectura.py +148 -0
- telar-0.1.0/pruebas/test_modelo.py +68 -0
- telar-0.1.0/pruebas/test_mux_tmux.py +974 -0
- telar-0.1.0/pruebas/test_mux_tmux_real.py +98 -0
- telar-0.1.0/pruebas/test_mux_zellij.py +287 -0
- telar-0.1.0/pruebas/test_mux_zellij_base.py +113 -0
- telar-0.1.0/pruebas/test_ordenes.py +434 -0
- telar-0.1.0/pruebas/test_perfil.py +137 -0
- telar-0.1.0/pruebas/test_proveedor_estado.py +473 -0
- telar-0.1.0/pruebas/test_salida.py +129 -0
- telar-0.1.0/pruebas/test_tareas.py +454 -0
- telar-0.1.0/pyproject.toml +44 -0
- telar-0.1.0/setup.cfg +4 -0
- telar-0.1.0/src/telar/__init__.py +24 -0
- telar-0.1.0/src/telar/agente/__init__.py +122 -0
- telar-0.1.0/src/telar/agente/base.py +558 -0
- telar-0.1.0/src/telar/agente/claude_code.py +425 -0
- telar-0.1.0/src/telar/cli.py +186 -0
- telar-0.1.0/src/telar/config.py +255 -0
- telar-0.1.0/src/telar/estado.py +888 -0
- telar-0.1.0/src/telar/lectura.py +355 -0
- telar-0.1.0/src/telar/modelo.py +155 -0
- telar-0.1.0/src/telar/mux/__init__.py +107 -0
- telar-0.1.0/src/telar/mux/base.py +382 -0
- telar-0.1.0/src/telar/mux/tmux.py +573 -0
- telar-0.1.0/src/telar/mux/zellij.py +687 -0
- telar-0.1.0/src/telar/ordenes/__init__.py +18 -0
- telar-0.1.0/src/telar/ordenes/_comun.py +618 -0
- telar-0.1.0/src/telar/ordenes/accion.py +109 -0
- telar-0.1.0/src/telar/ordenes/agente.py +457 -0
- telar-0.1.0/src/telar/ordenes/atencion.py +118 -0
- telar-0.1.0/src/telar/ordenes/config.py +95 -0
- telar-0.1.0/src/telar/ordenes/doctor.py +496 -0
- telar-0.1.0/src/telar/ordenes/ficha.py +162 -0
- telar-0.1.0/src/telar/ordenes/hilo.py +310 -0
- telar-0.1.0/src/telar/ordenes/hilos.py +110 -0
- telar-0.1.0/src/telar/ordenes/hoy.py +138 -0
- telar-0.1.0/src/telar/ordenes/init.py +301 -0
- telar-0.1.0/src/telar/ordenes/ir.py +52 -0
- telar-0.1.0/src/telar/ordenes/pendiente.py +172 -0
- telar-0.1.0/src/telar/ordenes/pendientes.py +170 -0
- telar-0.1.0/src/telar/ordenes/perfil.py +105 -0
- telar-0.1.0/src/telar/ordenes/tejer.py +159 -0
- telar-0.1.0/src/telar/ordenes/tiempo.py +143 -0
- telar-0.1.0/src/telar/ordenes/vincular.py +28 -0
- telar-0.1.0/src/telar/perfil.py +408 -0
- telar-0.1.0/src/telar/proveedores/__init__.py +87 -0
- telar-0.1.0/src/telar/proveedores/calendario.py +693 -0
- telar-0.1.0/src/telar/proveedores/estado.py +902 -0
- telar-0.1.0/src/telar/proveedores/tareas.py +702 -0
- telar-0.1.0/src/telar/salida.py +134 -0
- telar-0.1.0/src/telar.egg-info/PKG-INFO +158 -0
- telar-0.1.0/src/telar.egg-info/SOURCES.txt +99 -0
- telar-0.1.0/src/telar.egg-info/dependency_links.txt +1 -0
- telar-0.1.0/src/telar.egg-info/entry_points.txt +2 -0
- telar-0.1.0/src/telar.egg-info/requires.txt +1 -0
- telar-0.1.0/src/telar.egg-info/top_level.txt +1 -0
- telar-0.1.0/vscode/.vscode/launch.json +13 -0
- telar-0.1.0/vscode/.vscode/tasks.json +18 -0
- telar-0.1.0/vscode/README.md +126 -0
- telar-0.1.0/vscode/media/telar.svg +8 -0
- telar-0.1.0/vscode/package-lock.json +4304 -0
- telar-0.1.0/vscode/package.json +666 -0
- telar-0.1.0/vscode/src/acciones.ts +28 -0
- telar-0.1.0/vscode/src/cli.ts +227 -0
- telar-0.1.0/vscode/src/estilo.ts +99 -0
- telar-0.1.0/vscode/src/extension.ts +343 -0
- telar-0.1.0/vscode/src/modelo.ts +88 -0
- telar-0.1.0/vscode/src/vistas/carpeta.ts +75 -0
- telar-0.1.0/vscode/src/vistas/dia.ts +281 -0
- telar-0.1.0/vscode/src/vistas/ficha.ts +296 -0
- telar-0.1.0/vscode/src/vistas/hilos.ts +178 -0
- telar-0.1.0/vscode/src/vistas/hoy.ts +149 -0
- telar-0.1.0/vscode/src/vistas/tareas.ts +69 -0
- 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.
|
telar-0.1.0/MANIFEST.in
ADDED
|
@@ -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.
|