agents-city 0.3.0 → 0.5.1

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 (107) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.es.md +294 -16
  3. package/README.md +291 -16
  4. package/benchmarks/latency/fake-claude-cli.mjs +2 -1
  5. package/benchmarks/reception/README.md +16 -0
  6. package/benchmarks/reception/run.mjs +84 -0
  7. package/bin/agents-city.js +5 -0
  8. package/bin/connect +5 -0
  9. package/bin/hall.html +208 -22
  10. package/bin/navegador.mjs +203 -13
  11. package/bin/serve.py +176 -111
  12. package/bin/test +18 -4
  13. package/bin/test-arnes.py +192 -0
  14. package/bin/test-cage.py +9 -0
  15. package/bin/test-channel.py +178 -12
  16. package/bin/test-claude-runtime.py +132 -4
  17. package/bin/test-connect-client.mjs +609 -0
  18. package/bin/test-connect.py +52 -0
  19. package/bin/test-contracts.py +214 -0
  20. package/bin/test-demo.py +67 -0
  21. package/bin/test-desinstala.py +170 -0
  22. package/bin/test-doctor.py +31 -0
  23. package/bin/test-i18n.py +189 -0
  24. package/bin/test-navegador.py +54 -0
  25. package/bin/test-seat.py +78 -20
  26. package/bin/test-security.py +2 -0
  27. package/bin/test-serve.py +414 -2
  28. package/bin/uninstall +5 -0
  29. package/city/web/dist/city.js +65 -65
  30. package/city/web/dist/index.html +18 -5
  31. package/city/web/dist-hall/hall.js +1566 -486
  32. package/city/web/index.html +17 -4
  33. package/city/web/src/bienvenida.ts +48 -341
  34. package/city/web/src/casa.ts +324 -0
  35. package/city/web/src/demo.ts +277 -0
  36. package/city/web/src/dialogo.ts +178 -0
  37. package/city/web/src/es.ts +281 -25
  38. package/city/web/src/explorador.ts +216 -0
  39. package/city/web/src/hall.ts +612 -139
  40. package/city/web/src/idioma.ts +21 -1
  41. package/city/web/src/main.ts +28 -5
  42. package/city/web/src/motores.ts +48 -1
  43. package/city/web/src/vista.ts +58 -0
  44. package/demo/graba.py +127 -0
  45. package/demo/grabaciones/legal.jsonl +22 -0
  46. package/demo/grabaciones/medicina.jsonl +22 -0
  47. package/demo/grabaciones/software.jsonl +22 -0
  48. package/docs/managed-connect.md +237 -0
  49. package/docs/security.md +41 -2
  50. package/package.json +8 -4
  51. package/plugin/.claude-plugin/plugin.json +1 -1
  52. package/plugin/channel/adapter-prompts.ts +10 -0
  53. package/plugin/channel/adapter.js +78 -31
  54. package/plugin/channel/agents_city_hybrid_crypto_bg.wasm +0 -0
  55. package/plugin/channel/bus.js +109 -65
  56. package/plugin/channel/bus.ts +11 -1
  57. package/plugin/channel/client.js +67 -30
  58. package/plugin/channel/delivery-queue.ts +160 -21
  59. package/plugin/channel/hub/remote-roads.ts +32 -1
  60. package/plugin/channel/hub/road-controller.ts +116 -16
  61. package/plugin/channel/kinsh_vodozemac_wasm_bg.wasm +0 -0
  62. package/plugin/channel/licenses/CONNECT_CLIENT_THIRD_PARTY_NOTICES.md +21 -0
  63. package/plugin/channel/licenses/HYBRID_CRYPTO_THIRD_PARTY_NOTICES.md +12 -0
  64. package/plugin/channel/licenses/hybrid-crypto-Apache-2.0.txt +201 -0
  65. package/plugin/channel/licenses/keyring-MIT.txt +21 -0
  66. package/plugin/channel/licenses/vodozemac-Apache-2.0.txt +201 -0
  67. package/plugin/channel/local-hub.js +2080 -97
  68. package/plugin/channel/local-hub.ts +5 -4
  69. package/plugin/channel/managed-connect/bridge.ts +208 -0
  70. package/plugin/channel/managed-connect/cli.ts +416 -0
  71. package/plugin/channel/managed-connect/device.ts +15 -0
  72. package/plugin/channel/managed-connect/local-cities.ts +94 -0
  73. package/plugin/channel/managed-connect/person-message.ts +74 -0
  74. package/plugin/channel/managed-connect/reception-bridge.ts +341 -0
  75. package/plugin/channel/managed-connect/relay-session.ts +7 -0
  76. package/plugin/channel/managed-connect/storage.ts +653 -0
  77. package/plugin/channel/managed-connect/transport.ts +87 -0
  78. package/plugin/channel/managed-connect-cli.js +4777 -0
  79. package/plugin/channel/managed-connect-cli.ts +7 -0
  80. package/plugin/channel/managed-connect-client.d.ts +261 -0
  81. package/plugin/channel/managed-connect-client.js +6572 -0
  82. package/plugin/channel/managed-connect-client.manifest.json +38 -0
  83. package/plugin/channel/package-lock.json +123 -105
  84. package/plugin/channel/package.json +4 -4
  85. package/plugin/channel/protocol.ts +4 -0
  86. package/plugin/channel/reception.ts +896 -0
  87. package/plugin/channel/road-cli.ts +1 -1
  88. package/plugin/channel/runtime/arnes.json +189 -0
  89. package/plugin/channel/runtime/arnes.ts +47 -0
  90. package/plugin/channel/runtime/claude.ts +18 -0
  91. package/plugin/channel/runtime/codex-config.ts +51 -1
  92. package/plugin/channel/runtime/codex.ts +31 -11
  93. package/plugin/channel/runtime/kimi.ts +6 -4
  94. package/plugin/channel/runtime-files.ts +39 -5
  95. package/plugin/channel/runtime-gateway.js +426 -100
  96. package/plugin/channel/runtime-gateway.ts +12 -0
  97. package/plugin/channel/trust/agents-city-sandbox-roots.json +66 -0
  98. package/plugin/scripts/arnes.py +271 -0
  99. package/plugin/scripts/busca.py +46 -10
  100. package/plugin/scripts/cage.py +5 -0
  101. package/plugin/scripts/city-session.sh +144 -28
  102. package/plugin/scripts/crecimiento.py +4 -1
  103. package/plugin/scripts/demos.py +122 -0
  104. package/plugin/scripts/desinstala.py +237 -0
  105. package/plugin/scripts/doctor.py +37 -15
  106. package/plugin/scripts/read-card.py +48 -8
  107. package/plugin/scripts/reception.py +665 -0
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "city",
11
11
  "source": "./plugin",
12
- "version": "0.3.0",
12
+ "version": "0.5.1",
13
13
  "description": "Operate one autonomous city seat, its domain, role, repo support agents, goal, recognised skills and explicit roads to other cities."
14
14
  }
15
15
  ]
package/README.es.md CHANGED
@@ -106,7 +106,7 @@ Esto es `0.x` a propósito: los comandos ya se usan hoy, pero los formatos de
106
106
  fichero y las APIs todavía pueden cambiar entre versiones menores. Aquí nada
107
107
  pretende estar congelado.
108
108
 
109
- Necesitas Node.js 22 o superior, Python 3 y tmux; los detalles están en la
109
+ Necesitas Node.js 22.13 o superior, Python 3 y tmux; los detalles están en la
110
110
  [tabla de requisitos](#requisitos-base), y `agents-city seat` se ofrece a
111
111
  instalar tmux si falta. No se instala nada en el sistema más allá de la carpeta
112
112
  global de npm de tu Node activo.
@@ -162,7 +162,7 @@ agents-city --version
162
162
 
163
163
  | Requisito | Para qué se usa |
164
164
  |---|---|
165
- | Node.js 22 o posterior | paquete npm, bus WebSocket y frontends |
165
+ | Node.js 22.13 o posterior | paquete npm, bus WebSocket, recepción local y frontends |
166
166
  | npm | instalación y empaquetado |
167
167
  | Python 3 | Hall, onboarding, ciudades, mapas y utilidades |
168
168
  | bash | sesiones y launchers |
@@ -491,6 +491,7 @@ agents-city setup
491
491
  agents-city seat
492
492
  agents-city cities
493
493
  agents-city road
494
+ agents-city connect
494
495
  agents-city bus
495
496
  agents-city committee
496
497
  agents-city agents
@@ -556,12 +557,46 @@ se escriben en el registro de actividad. El token de observador rota con el hub,
556
557
  sólo acepta un origen de este ordenador y es de sólo lectura: el navegador no
557
558
  puede dirigir el comité. `Ctrl-c` detiene el Hall.
558
559
 
560
+ **Demos**, en el rail, reproduce un comité entero sin montar nada: una historia
561
+ por dominio de trabajo — un estudio, una clínica, un despacho — con play, pausa,
562
+ repetir y velocidad. Lo que reproduce son *grabaciones*: `demo/graba.py` ejecuta
563
+ cada historia sobre el bus local real, a través de la máquina de estados real del
564
+ comité, y guarda el flujo exacto de eventos que vio un espectador; el Hall los
565
+ reproduce con el mismo renderizador que usa el rail en vivo. Lo dice en pantalla,
566
+ porque una demo que finge estar en vivo es justo la que este producto no debe
567
+ publicar. Para lanzar una en vivo desde terminal: `agents-city demo --domain
568
+ software`.
569
+
570
+ Regenera las grabaciones tras editar `demo/stories.py`:
571
+
572
+ ```bash
573
+ demo/graba.py # todas las historias
574
+ demo/graba.py medicina # sólo una
575
+ ```
576
+
577
+ La suite de demo falla cuando una grabación deja de corresponderse con la
578
+ historia que dice ser, así que una obsoleta es un build en rojo y no un navegador
579
+ reproduciendo en silencio el comité del mes pasado.
580
+
559
581
  Bajo la marca hay dos botones: **día/noche** e **ES/EN**. El Hall habla español e
560
582
  inglés, arranca en el idioma del navegador y recuerda la elección explícita. Las
561
583
  traducciones se indexan por la frase en inglés, así que lo que aún no esté
562
584
  traducido cae en un inglés legible y no en un identificador — un texto nuevo
563
585
  nunca se queda bloqueado esperando a la traducción.
564
586
 
587
+ La cobertura es una prueba, no una costumbre. `bin/test-i18n.py` lee las rutas de
588
+ renderizado, saca cada frase en inglés que una persona va a ver, y falla cuando
589
+ alguna no tiene español — así una vista nueva no puede colarse sin traducir, que
590
+ es como la cobertura había caído al 40% sin que nadie se diera cuenta.
591
+
592
+ El mecanismo evidente — barrer el DOM renderizado y traducir lo que coincida con
593
+ una clave — es a propósito lo que **no** se hace. En el DOM no hay forma de
594
+ distinguir una frase que escribió este producto de un nombre de ciudad o de
595
+ agente que escribió alguien, así que a quien tenga una ciudad llamada `Overview`
596
+ se le renombraría sola. Esa distinción sólo existe en el fuente, entre un literal
597
+ y una interpolación, y ahí es donde se comprueba: lo que lleve un `${}` se
598
+ salta.
599
+
565
600
  ### `agents-city setup`
566
601
 
567
602
  Crea o selecciona una ciudad y abre el Hall; con `--tui` entrega el flujo a
@@ -668,6 +703,59 @@ agents-city road disconnect producto <city-id-remoto>
668
703
  No se puede conectar una ciudad consigo misma. Una invitación remota debe
669
704
  aceptarse de forma independiente en cada máquina.
670
705
 
706
+ ### `agents-city connect`
707
+
708
+ Empareja este ordenador con un servicio de Roads gestionadas. No crea una
709
+ conexión unilateral: las dos personas la aprueban en el servicio y quien la
710
+ recibe ve a la otra persona en su recepción humana privada, sin exponer un
711
+ catálogo de ciudades. El cliente público implementa el protocolo v4; el servicio
712
+ alojado queda fuera de este repositorio y todavía no está habilitado en
713
+ producción ni auditado de forma independiente.
714
+
715
+ ```bash
716
+ agents-city connect --service https://connect.example.com --trust-file roots.json
717
+ agents-city connect --city producto
718
+ agents-city connect --all
719
+ agents-city connect status
720
+ agents-city connect roads
721
+ ```
722
+
723
+ El comando genera material Ed25519/X25519, Olm y ML-KEM-768 firmado en este
724
+ ordenador, muestra un PASCO de un solo uso y abre el navegador para autorizarlo.
725
+ Sólo sube material público. Las claves privadas, el estado del ratchet, las
726
+ semillas ML-KEM y los reintentos quedan cifrados en
727
+ `~/.agents-city/.runtime/connect/vault/`; la clave de envoltura permanece en el
728
+ Llavero de macOS, Credential Manager de Windows o Secret Service de Linux. El
729
+ cliente falla de forma cerrada si el keyring no está disponible. La jaula sella
730
+ el vault para las ventanas de agentes de repositorio en macOS y Linux.
731
+
732
+ La cadena de raíces firmada indicada con `--trust-file` es obligatoria en el
733
+ primer emparejamiento con un servicio que no sea de desarrollo. El cliente
734
+ conserva la última versión aceptada. Una raíz posterior debe continuar desde
735
+ esa raíz local exacta y llevar suficientes firmas de las autoridades offline
736
+ anteriores y nuevas; se rechazan saltos, rollback, caducidad y cambios
737
+ silenciosos de operador o testigo. El protocolo v4 verifica después al peer
738
+ mediante transparencia de claves, protege el primer mensaje Olm con X25519 +
739
+ ML-KEM-768 híbrido y usa el Double Ratchet de Olm. Los envíos sellados normales
740
+ omiten remitente, dispositivo, ciudad y Road de la petición exterior. Esto no
741
+ oculta a Cloudflare la IP, el momento o el tamaño rellenado; los pasos
742
+ posteriores del ratchet son clásicos.
743
+
744
+ El paquete incluye una raíz pública únicamente para el origen exacto del
745
+ sandbox gestionado. Los servicios autoalojados siguen necesitando su
746
+ `--trust-file` revisado. Una raíz devuelta por el propio servicio nunca se
747
+ acepta como primer anclaje.
748
+
749
+ `--city` elige un hub local que mantiene viva la recepción del propietario; no
750
+ elige un destinatario ni se revela a la otra persona. Un solo hub por ordenador
751
+ mantiene el lease y una conexión cifrada saliente; no se abre ningún puerto
752
+ público. Usa `--service URL` o `AGENTS_CITY_CONNECT_URL` para un endpoint piloto.
753
+ El servidor alojado no forma parte de este repositorio Apache; el cliente y el
754
+ protocolo auditables sí.
755
+
756
+ [docs/managed-connect.md](docs/managed-connect.md) detalla el contrato de claves,
757
+ sobres, cifrado, ACK, revocación y modelo de amenazas.
758
+
671
759
  ### `agents-city bus`
672
760
 
673
761
  Opera mensajes entre asientos sobre carreteras ya declaradas.
@@ -682,7 +770,7 @@ agents-city bus send '*' "Aviso para todas mis carreteras"
682
770
  | Subcomando | Efecto |
683
771
  |---|---|
684
772
  | `roster` | devuelve carreteras y presencia online conocida |
685
- | `inbox` | devuelve y consume el inbox pendiente; el historial append-only permanece |
773
+ | `inbox` | devuelve y consume el siguiente lote aprobado de hasta 20; el texto gestionado no aparece hasta que el propietario lo envía desde el ayuntamiento |
686
774
  | `send owner/city TEXTO` | envía a un destino permitido |
687
775
  | `send '*' TEXTO` | envía a todas las carreteras; exige al menos una |
688
776
 
@@ -1551,9 +1639,28 @@ AGENTS_CITY_DATA="$HOME/.agents-city/$CITY_OWNER/producto" \
1551
1639
  En una sesión normal no hace falta establecer `AGENTS_CITY_DATA`: ya está
1552
1640
  inyectado en cada ventana. El ejemplo lo hace explícito para una terminal externa.
1553
1641
 
1554
- ### Caso 10: conectar ciudades de dos máquinas o personas
1642
+ ### Caso 10: conectar dos personas desde ordenadores distintos
1643
+
1644
+ Con un operador de Roads gestionadas, cada persona empareja su ordenador.
1645
+ `--city` elige el hub local que inicia la recepción del propietario; no revela
1646
+ esa ciudad ni da acceso directo a ella:
1647
+
1648
+ ```bash
1649
+ agents-city connect --city producto --service https://connect.example.com --trust-file roots.json
1650
+ agents-city connect --city research --service https://connect.example.com --trust-file roots.json
1651
+ ```
1652
+
1653
+ Una persona solicita la conexión en el servicio y la otra la acepta. Los
1654
+ clientes reciben la Road bilateral mediante sus sesiones autenticadas; ninguna
1655
+ parte intercambia un token compartido, abre un puerto local ni recibe el catálogo
1656
+ de ciudades de la otra. El texto entrante se detiene primero en la recepción
1657
+ humana. Quien lo recibe decide qué ciudad o ciudades locales pueden leerlo, o
1658
+ activa el router opcional que falla de forma cerrada y sólo actúa cuando una
1659
+ regla coincide sin ambigüedad. El contrato del cliente público está en
1660
+ [docs/managed-connect.md](docs/managed-connect.md).
1555
1661
 
1556
- En la máquina A:
1662
+ Para autoalojar el transporte remoto existente basado en token, intercambia en
1663
+ cambio las invitaciones públicas de ciudad. En la máquina A:
1557
1664
 
1558
1665
  ```bash
1559
1666
  agents-city road invite producto > producto.invitation.json
@@ -1782,12 +1889,32 @@ El hub local no mezcla datos efímeros con la configuración legible:
1782
1889
  ├── road-queue/*.json
1783
1890
  ├── road-inbox/*.json
1784
1891
  └── road-history.jsonl
1892
+
1893
+ ~/.agents-city/.runtime/reception/
1894
+ └── reception.sqlite3 # cuarentena del propietario compartida por sus ciudades
1785
1895
  ```
1786
1896
 
1787
1897
  Las credenciales y ficheros de runtime se crean con permisos privados. Los
1788
1898
  outboxes permiten que un actor se reconecte sin perder tareas ya aceptadas; el
1789
- ACK elimina el pendiente. El límite actual es 200 pendientes por cola y 72 horas
1790
- de vida por mensaje. `bus inbox` consume `road-inbox`, no el historial append-only.
1899
+ ACK elimina el pendiente. Los outboxes de actores y la cola local de reintentos
1900
+ admiten 200 pendientes; el inbox de Roads admite 500 por defecto y devuelve como
1901
+ máximo los 20 más antiguos en cada lectura. El texto E2EE gestionado entra
1902
+ primero en la recepción separada del propietario: ninguna ciudad ni modelo puede
1903
+ consumirlo hasta que una persona lo rechaza o lo envía a una o varias ciudades
1904
+ desde el ayuntamiento. Una ráfaga ya enrutada crea una sola activación agrupada
1905
+ del asiento, no un turno del modelo por mensaje, y cada runtime nativo ejecuta
1906
+ como máximo un turno a la vez. Una cola llena aplica backpressure en vez de
1907
+ borrar silenciosamente un elemento anterior. La vida de cada mensaje es de 72
1908
+ horas. `bus inbox` consume el `road-inbox` aprobado, no la cuarentena ni el
1909
+ historial append-only.
1910
+
1911
+ El rendimiento del relay no es el rendimiento de respuestas. Para una ciudad,
1912
+ la capacidad semántica segura es aproximadamente las peticiones agrupadas por
1913
+ turno divididas por la duración del turno. La regresión local vacía 100 mensajes
1914
+ de Road en cinco lotes exactos de 20 tras una sola activación sin contenido; una
1915
+ prueba separada con 20 peticiones y runtime lento demuestra que la concurrencia
1916
+ del modelo permanece en uno y que el backlog durable se vacía sin pérdidas. El
1917
+ resultado `queued` del remitente nunca significa leído ni respondido.
1791
1918
 
1792
1919
  ### Variables configurables
1793
1920
 
@@ -1809,6 +1936,12 @@ de vida por mensaje. `bus inbox` consume `road-inbox`, no el historial append-on
1809
1936
  | `CITY_HOOKS` | `city` | `everywhere` ejecuta los hooks de conciencia en todas las sesiones de Claude, no solo en runtimes de ciudad |
1810
1937
  | `CITY_DESKTOP` | `~/Desktop`, o el escritorio de Windows bajo WSL | dónde escribe `agents-city shortcut` |
1811
1938
  | `CITY_CAGE` | `1` | `0` arranca todas las ventanas sin jaula |
1939
+ | `CITY_ROAD_INBOX_MAX_PENDING` | `500` | capacidad local del inbox de Roads, entre 20 y 10.000; al llenarse aplica backpressure |
1940
+ | `CITY_ROAD_INBOX_WAKE_INTERVAL_MS` | `300000` | intervalo mínimo entre activaciones agrupadas del backlog, de 30 segundos a 1 hora |
1941
+ | `CITY_RECEPTION_MAX_PENDING` | `10000` | mensajes remotos pendientes del propietario antes de aplicar contrapresión al relay, de 100 a 100.000 |
1942
+ | `CITY_RECEPTION_MAX_BYTES` | `67108864` | bytes totales pendientes en la recepción local privada, de 1 MiB a 512 MiB |
1943
+ | `CITY_RECEPTION_PENDING_DAYS` | `30` | retención local de mensajes sin decidir, de 1 a 90 días |
1944
+ | `CITY_RECEPTION_DELIVERY_INTERVAL_MS` | `1000` | frecuencia con la que un bus reclama rutas aprobadas por la persona, de 250 ms a 30 segundos |
1812
1945
  | `CITY_CAGE_DENY` | vacío | rutas extra que sellar, separadas por `:` |
1813
1946
  | `CITY_CAGE_ALLOW_WRITE` | vacío | rutas extra que mantener escribibles, separadas por `:` |
1814
1947
  | `CITY_UPDATE_CHECK` | `1` | `0` no pregunta nunca a npm si hay versión más nueva |
@@ -1843,9 +1976,17 @@ CITY_SETTLE=0 CITY_STAGGER=0 agents-city seat --city producto
1843
1976
  Lee `.git/config` y `HEAD` directamente en vez de lanzar `git` una vez por
1844
1977
  repositorio, así que un escaneo completo termina mientras alguien mira la
1845
1978
  pantalla, y funciona allí donde funcione Python: macOS, Linux y Windows por
1846
- igual. La guía y el Hall buscan sobre este índice; `plugin/scripts/find-repos.sh`
1847
- es un envoltorio fino para quien lo llama desde shell, y sólo imprime la mitad
1848
- git.
1979
+ igual. Este índice es el que usa la **terminal**: `seat --repos`, y el lanzador
1980
+ resolviendo el `repo@rama` de una ficha a una ruta de esta máquina.
1981
+ `plugin/scripts/find-repos.sh` es un envoltorio fino para quien lo llama desde
1982
+ shell, y sólo imprime la mitad git.
1983
+
1984
+ El **Hall** no lo usa, y a propósito: allí, elegir sobre qué trabaja un agente es
1985
+ un explorador de carpetas. Recorres tu disco y coges lo que quieras — un
1986
+ repositorio, un worktree, una carpeta de documentos, un fichero exacto — y no se
1987
+ te adelanta nada ni se filtra nada. Una lista adivinada sólo puede ofrecerte lo
1988
+ que sabía buscar, y es una lista más que leer antes de hacer aquello a lo que
1989
+ venías.
1849
1990
 
1850
1991
  El índice se cachea un día en `$XDG_CACHE_HOME/agents-city/lugares.tsv` o
1851
1992
  `~/.cache/agents-city/lugares.tsv`. Tanto el formulario de casas del Hall como el
@@ -1937,10 +2078,18 @@ tus repos, adjuntarse a tu tmux o leer ficheros privados de tu home. Para códig
1937
2078
  no confiable usa cuentas/VMs/contenedores separados y aplica también los permisos
1938
2079
  del CLI de cada proveedor.
1939
2080
 
1940
- El bus remoto amplía la superficie de confianza. Despliega HTTPS/WSS, rota
1941
- tokens, limita los scopes y revisa [docs/self-host.md](docs/self-host.md). Una
1942
- carretera autoriza intercambio de mensajes entre asientos; no implica confianza
1943
- para ejecutar comandos recibidos ni acceso al filesystem remoto.
2081
+ Un bus remoto amplía la superficie de confianza. Para el transporte autoalojado
2082
+ con token, despliega HTTPS/WSS, rota tokens, limita los scopes y revisa
2083
+ [docs/self-host.md](docs/self-host.md). Managed Connect usa firmas de
2084
+ dispositivo, transparencia de claves con testigos, establecimiento de sesión
2085
+ híbrido X25519 + ML-KEM-768, Double Ratchet de Olm y entrega sellada. Su material
2086
+ privado queda cifrado bajo una clave del keyring del sistema operativo en el
2087
+ directorio sellado por la jaula `~/.agents-city/.runtime/connect/vault/`; consulta
2088
+ [docs/managed-connect.md](docs/managed-connect.md). Una Road gestionada autoriza
2089
+ alcance cifrado hasta la recepción humana del propietario, no entrada directa a
2090
+ un modelo. Solo la ruta posterior del propietario deja el texto disponible para
2091
+ las ciudades elegidas. Ninguna Road autoriza ejecutar comandos recibidos ni
2092
+ acceder al filesystem remoto.
1944
2093
 
1945
2094
  ## Resolución de problemas
1946
2095
 
@@ -2099,10 +2248,139 @@ agents-city seat --repos
2099
2248
  ```
2100
2249
 
2101
2250
  La detección exige `.git` (directorio o fichero de worktree) y un remote `origin`.
2102
- Si acabas de cambiar las raíces, usa **Buscar otra vez** en el formulario de
2103
- casas, o ejecuta `plugin/scripts/busca.py --refresh`. `AGENTS_CITY_ORG` puede estar filtrando el repo;
2251
+ Si acabas de cambiar las raíces, ejecuta `plugin/scripts/busca.py --refresh`. `AGENTS_CITY_ORG` puede estar filtrando el repo;
2104
2252
  déjala vacía para indexar todos los remotes.
2105
2253
 
2254
+ ### Tus CLIs, tal y como las tienes
2255
+
2256
+ Esto no compite con la CLI que ya usas. Las orquesta, y eso sólo funciona si
2257
+ respeta lo que configuraste en ellas — tus plugins, tus skills, tus servidores
2258
+ MCP, tu modelo, tus permisos.
2259
+
2260
+ Eso es una afirmación sobre tu máquina, así que va como comando y no como
2261
+ promesa:
2262
+
2263
+ ```bash
2264
+ agents-city doctor --config # qué añadimos, qué heredamos, qué no tocamos
2265
+ agents-city doctor --config --json # lo mismo, como datos
2266
+ ```
2267
+
2268
+ Imprime tres columnas por CLI, y la diferencia entre ellas es lo importante:
2269
+
2270
+ * **el trato** — lo que añadimos o pisamos. Es corto, cada línea dice *por qué*,
2271
+ y es lo que hace que el bus sea la única ruta entre agentes y que la jaula
2272
+ aguante. Sin eso no hay producto.
2273
+ * **heredamos** — lo que a propósito *no* mandamos, para que tu propia CLI lea
2274
+ tu propia configuración. Tu modelo, tu esfuerzo, tu política de aprobación.
2275
+ * **no tocamos** — lo que carga exactamente igual que siempre.
2276
+
2277
+ El informe y el runtime leen **el mismo fichero** —
2278
+ `plugin/channel/runtime/arnes.json` — así que la afirmación no puede separarse
2279
+ del comportamiento. Los conectores sacan sus valores de esa declaración en vez de
2280
+ escribirlos a mano, y la suite falla si un runtime impone algo que la declaración
2281
+ no menciona. Escribir esa comprobación encontró dos: un system prompt inyectado
2282
+ en Kimi que no declaraba nadie, y un valor de sandbox escrito en dos sitios.
2283
+
2284
+ Donde tu ajuste y el nuestro se cruzan, gana el tuyo cuando puede: el
2285
+ `approval_policy` de Codex se respeta si lo has puesto, y `on-request` es sólo el
2286
+ recurso cuando no. El informe dice la consecuencia en voz alta — `never`
2287
+ desactiva las herramientas de app y MCP — en vez de decidir en silencio que no
2288
+ querías decir eso.
2289
+
2290
+ ### Tu silla conserva tu propio Claude Code
2291
+
2292
+ La ventana del asiento abre **Claude Code de verdad** — tus plugins, tus skills,
2293
+ tus servidores MCP, tu statusline, el autocompletado de slash commands, el
2294
+ selector de modelo. Es el arnés que ya usas, en el panel, y es a propósito: la
2295
+ silla es donde una persona trabaja a mano.
2296
+
2297
+ Sigue estando en el bus. Los hooks del plugin (`SessionStart`,
2298
+ `UserPromptSubmit`, `Stop`, `SessionEnd`) reportan los prompts y las respuestas
2299
+ de esa sesión como los mismos eventos `conversation.*` que reporta el gateway,
2300
+ así que el ayuntamiento ve la conversación igual. Y lleva los dos flags que
2301
+ hacen del bus la única ruta entre agentes — `crossSessionInbound: refuse` y
2302
+ `--disallowed-tools SendMessage,ListAgents`. Un producto más silencioso con un
2303
+ agujero dentro no sería un producto mejor.
2304
+
2305
+ **Las casas de los agentes conservan el gateway** y su prompt `city>`, porque lo
2306
+ que compra el gateway es que el bus pueda *meter* trabajo en una ventana — que
2307
+ es el oficio entero de una casa y nada del oficio de la silla.
2308
+
2309
+ Una clave de la ficha devuelve la silla a lo de antes:
2310
+
2311
+ ```yaml
2312
+ ui.seat: gateway # el prompt de la ciudad en la silla, como antes
2313
+ ```
2314
+
2315
+ `CITY_UI=gateway` lo fuerza para un arranque. A las casas no se les pregunta:
2316
+ una casa existe para recibir encargos, y el gateway es lo que lo hace posible.
2317
+
2318
+ ### El motor con el que corre una casa
2319
+
2320
+ `model.<ventana>` y `effort.<ventana>` en la ficha dicen con qué corre una casa,
2321
+ una sola vez, la mueva la CLI que la mueva. Claude los toma como flags; los
2322
+ gateways nativos leen esa misma grafía del texto del comando y la mandan con el
2323
+ turno — por eso una clave significa lo mismo para las cuatro:
2324
+
2325
+ | proveedor | modelo | esfuerzo |
2326
+ | --- | --- | --- |
2327
+ | `claude` | sí, un alias que resuelve la CLI (`opus`, `sonnet`…) | sí |
2328
+ | `codex` | sí, el nombre que use tu Codex (`~/.codex/config.toml`) | sí |
2329
+ | `opencode` | sí, `proveedor/modelo` | no existe ese ajuste |
2330
+ | `kimi` | sí | no existe ese ajuste |
2331
+
2332
+ Un comando que ya lleva el flag se lo queda: `runs.dbt: codex --model o3` es
2333
+ alguien diciendo lo que quería, y una clave genérica no debe pisar una frase
2334
+ concreta. El esfuerzo sólo se escribe donde se lee, porque un flag que nadie lee
2335
+ es justo como un control acaba pareciendo que funciona.
2336
+
2337
+ ### Publicar una versión
2338
+
2339
+ Una release es una etiqueta. Empujar `v0.5.2` ejecuta la suite entera en Linux,
2340
+ macOS y Windows, comprueba que la etiqueta y los tres manifiestos dicen la misma
2341
+ versión, y publica con **procedencia**: una declaración firmada de qué commit y
2342
+ qué workflow produjeron ese tarball exacto. Cualquiera puede comprobarlo:
2343
+
2344
+ ```bash
2345
+ npm audit signatures
2346
+ ```
2347
+
2348
+ No hay ningún token guardado. Publica por *trusted publishing* de npm, que
2349
+ cambia una identidad OIDC de corta vida emitida por el workflow por el derecho a
2350
+ publicar este paquete: un secreto que no existe no se puede filtrar.
2351
+
2352
+ ```bash
2353
+ npm version patch --no-git-tag-version # y luego un PR con la subida
2354
+ git tag v0.5.2 && git push origin v0.5.2 # la etiqueta es la release
2355
+ ```
2356
+
2357
+ Esto existe porque publicar a mano no funcionaba. Cuatro versiones se quedaron
2358
+ sin publicar en un solo día, no por descuido sino porque el paso vivía en la
2359
+ cabeza de una persona y necesitaba su passkey — y lo que llegaba al registro era
2360
+ lo que hubiera en un directorio de trabajo, sin conexión con ningún commit que
2361
+ nadie pudiera nombrar.
2362
+
2363
+ ### Desinstalarlo del todo
2364
+
2365
+ ```bash
2366
+ agents-city uninstall # dice exactamente qué se iría; no borra nada
2367
+ agents-city uninstall --yes # lo hace
2368
+ agents-city uninstall --keep-cities --yes # desconecta la máquina, conserva las ciudades
2369
+ agents-city uninstall --npm --yes # y quita también el paquete global
2370
+ ```
2371
+
2372
+ Cierra todas las sesiones, halls y mapas que el producto arrancó, quita los
2373
+ accesos directos del escritorio y el registro del plugin de Claude, y borra
2374
+ `~/.agents-city` (tus ciudades, su estado y sus copias), `~/.config/agents-city`,
2375
+ `~/.cache/agents-city` y `~/.claude/channels/city-bus` — más el token del bus en
2376
+ el Keychain de macOS.
2377
+
2378
+ Nunca toca tus repositorios, tus worktrees ni tus carpetas de documentos. La casa
2379
+ de un agente guarda *enlaces* a eso, y lo único que se va es el enlace.
2380
+
2381
+ `reset` responde a la otra pregunta: vacía una ciudad, deja una copia y conserva
2382
+ la instalación, para cuando piensas seguir usándolo.
2383
+
2106
2384
  ### GitHub no muestra repos privados u organizaciones
2107
2385
 
2108
2386
  ```bash