agents-city 0.4.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.es.md +240 -11
- package/README.md +238 -11
- package/benchmarks/latency/fake-claude-cli.mjs +2 -1
- package/benchmarks/reception/README.md +16 -0
- package/benchmarks/reception/run.mjs +84 -0
- package/bin/agents-city.js +1 -0
- package/bin/connect +5 -0
- package/bin/hall.html +117 -18
- package/bin/navegador.mjs +170 -1
- package/bin/serve.py +201 -101
- package/bin/test +15 -3
- package/bin/test-arnes.py +192 -0
- package/bin/test-cage.py +9 -0
- package/bin/test-channel.py +178 -12
- package/bin/test-claude-runtime.py +132 -4
- package/bin/test-connect-client.mjs +609 -0
- package/bin/test-connect.py +52 -0
- package/bin/test-contracts.py +214 -0
- package/bin/test-diario.py +185 -0
- package/bin/test-doctor.py +31 -0
- package/bin/test-i18n.py +189 -0
- package/bin/test-navegador.py +61 -0
- package/bin/test-seat.py +78 -20
- package/bin/test-security.py +2 -0
- package/bin/test-serve.py +366 -0
- package/city/web/dist-hall/hall.js +789 -214
- package/city/web/src/bienvenida.ts +14 -13
- package/city/web/src/casa.ts +143 -56
- package/city/web/src/demo.ts +61 -31
- package/city/web/src/es.ts +187 -27
- package/city/web/src/explorador.ts +70 -43
- package/city/web/src/hall.ts +520 -103
- package/city/web/src/idioma.ts +21 -1
- package/city/web/src/motores.ts +48 -1
- package/city/web/src/vista.ts +58 -0
- package/demo/graba.py +5 -10
- package/docs/managed-connect.md +237 -0
- package/docs/security.md +41 -2
- package/package.json +8 -4
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/channel/adapter-prompts.ts +10 -0
- package/plugin/channel/adapter.js +78 -31
- package/plugin/channel/agents_city_hybrid_crypto_bg.wasm +0 -0
- package/plugin/channel/bus.js +109 -65
- package/plugin/channel/bus.ts +11 -1
- package/plugin/channel/client.js +67 -30
- package/plugin/channel/delivery-queue.ts +160 -21
- package/plugin/channel/hub/remote-roads.ts +32 -1
- package/plugin/channel/hub/road-controller.ts +116 -16
- package/plugin/channel/kinsh_vodozemac_wasm_bg.wasm +0 -0
- package/plugin/channel/licenses/CONNECT_CLIENT_THIRD_PARTY_NOTICES.md +21 -0
- package/plugin/channel/licenses/HYBRID_CRYPTO_THIRD_PARTY_NOTICES.md +12 -0
- package/plugin/channel/licenses/hybrid-crypto-Apache-2.0.txt +201 -0
- package/plugin/channel/licenses/keyring-MIT.txt +21 -0
- package/plugin/channel/licenses/vodozemac-Apache-2.0.txt +201 -0
- package/plugin/channel/local-hub.js +2080 -97
- package/plugin/channel/local-hub.ts +5 -4
- package/plugin/channel/managed-connect/bridge.ts +208 -0
- package/plugin/channel/managed-connect/cli.ts +416 -0
- package/plugin/channel/managed-connect/device.ts +15 -0
- package/plugin/channel/managed-connect/local-cities.ts +94 -0
- package/plugin/channel/managed-connect/person-message.ts +74 -0
- package/plugin/channel/managed-connect/reception-bridge.ts +341 -0
- package/plugin/channel/managed-connect/relay-session.ts +7 -0
- package/plugin/channel/managed-connect/storage.ts +653 -0
- package/plugin/channel/managed-connect/transport.ts +87 -0
- package/plugin/channel/managed-connect-cli.js +4777 -0
- package/plugin/channel/managed-connect-cli.ts +7 -0
- package/plugin/channel/managed-connect-client.d.ts +261 -0
- package/plugin/channel/managed-connect-client.js +6572 -0
- package/plugin/channel/managed-connect-client.manifest.json +38 -0
- package/plugin/channel/package-lock.json +123 -105
- package/plugin/channel/package.json +4 -4
- package/plugin/channel/protocol.ts +4 -0
- package/plugin/channel/reception.ts +896 -0
- package/plugin/channel/road-cli.ts +1 -1
- package/plugin/channel/runtime/arnes.json +189 -0
- package/plugin/channel/runtime/arnes.ts +47 -0
- package/plugin/channel/runtime/claude.ts +18 -0
- package/plugin/channel/runtime/codex-config.ts +51 -1
- package/plugin/channel/runtime/codex.ts +31 -11
- package/plugin/channel/runtime/kimi.ts +6 -4
- package/plugin/channel/runtime-files.ts +39 -5
- package/plugin/channel/runtime-gateway.js +426 -100
- package/plugin/channel/runtime-gateway.ts +12 -0
- package/plugin/channel/trust/agents-city-sandbox-roots.json +66 -0
- package/plugin/scripts/arnes.py +271 -0
- package/plugin/scripts/busca.py +46 -10
- package/plugin/scripts/cage.py +5 -0
- package/plugin/scripts/city-session.sh +144 -28
- package/plugin/scripts/crecimiento.py +4 -1
- package/plugin/scripts/demos.py +58 -43
- package/plugin/scripts/desinstala.py +36 -21
- package/plugin/scripts/diario.py +119 -0
- package/plugin/scripts/doctor.py +90 -15
- package/plugin/scripts/read-card.py +48 -8
- package/plugin/scripts/reception.py +665 -0
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
|
|
@@ -583,6 +584,19 @@ traducciones se indexan por la frase en inglés, así que lo que aún no esté
|
|
|
583
584
|
traducido cae en un inglés legible y no en un identificador — un texto nuevo
|
|
584
585
|
nunca se queda bloqueado esperando a la traducción.
|
|
585
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
|
+
|
|
586
600
|
### `agents-city setup`
|
|
587
601
|
|
|
588
602
|
Crea o selecciona una ciudad y abre el Hall; con `--tui` entrega el flujo a
|
|
@@ -689,6 +703,59 @@ agents-city road disconnect producto <city-id-remoto>
|
|
|
689
703
|
No se puede conectar una ciudad consigo misma. Una invitación remota debe
|
|
690
704
|
aceptarse de forma independiente en cada máquina.
|
|
691
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
|
+
|
|
692
759
|
### `agents-city bus`
|
|
693
760
|
|
|
694
761
|
Opera mensajes entre asientos sobre carreteras ya declaradas.
|
|
@@ -703,7 +770,7 @@ agents-city bus send '*' "Aviso para todas mis carreteras"
|
|
|
703
770
|
| Subcomando | Efecto |
|
|
704
771
|
|---|---|
|
|
705
772
|
| `roster` | devuelve carreteras y presencia online conocida |
|
|
706
|
-
| `inbox` | devuelve y consume el
|
|
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 |
|
|
707
774
|
| `send owner/city TEXTO` | envía a un destino permitido |
|
|
708
775
|
| `send '*' TEXTO` | envía a todas las carreteras; exige al menos una |
|
|
709
776
|
|
|
@@ -1572,9 +1639,28 @@ AGENTS_CITY_DATA="$HOME/.agents-city/$CITY_OWNER/producto" \
|
|
|
1572
1639
|
En una sesión normal no hace falta establecer `AGENTS_CITY_DATA`: ya está
|
|
1573
1640
|
inyectado en cada ventana. El ejemplo lo hace explícito para una terminal externa.
|
|
1574
1641
|
|
|
1575
|
-
### Caso 10: conectar
|
|
1642
|
+
### Caso 10: conectar dos personas desde ordenadores distintos
|
|
1576
1643
|
|
|
1577
|
-
|
|
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).
|
|
1661
|
+
|
|
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:
|
|
1578
1664
|
|
|
1579
1665
|
```bash
|
|
1580
1666
|
agents-city road invite producto > producto.invitation.json
|
|
@@ -1803,12 +1889,32 @@ El hub local no mezcla datos efímeros con la configuración legible:
|
|
|
1803
1889
|
├── road-queue/*.json
|
|
1804
1890
|
├── road-inbox/*.json
|
|
1805
1891
|
└── road-history.jsonl
|
|
1892
|
+
|
|
1893
|
+
~/.agents-city/.runtime/reception/
|
|
1894
|
+
└── reception.sqlite3 # cuarentena del propietario compartida por sus ciudades
|
|
1806
1895
|
```
|
|
1807
1896
|
|
|
1808
1897
|
Las credenciales y ficheros de runtime se crean con permisos privados. Los
|
|
1809
1898
|
outboxes permiten que un actor se reconecte sin perder tareas ya aceptadas; el
|
|
1810
|
-
ACK elimina el pendiente.
|
|
1811
|
-
|
|
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.
|
|
1812
1918
|
|
|
1813
1919
|
### Variables configurables
|
|
1814
1920
|
|
|
@@ -1830,6 +1936,12 @@ de vida por mensaje. `bus inbox` consume `road-inbox`, no el historial append-on
|
|
|
1830
1936
|
| `CITY_HOOKS` | `city` | `everywhere` ejecuta los hooks de conciencia en todas las sesiones de Claude, no solo en runtimes de ciudad |
|
|
1831
1937
|
| `CITY_DESKTOP` | `~/Desktop`, o el escritorio de Windows bajo WSL | dónde escribe `agents-city shortcut` |
|
|
1832
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 |
|
|
1833
1945
|
| `CITY_CAGE_DENY` | vacío | rutas extra que sellar, separadas por `:` |
|
|
1834
1946
|
| `CITY_CAGE_ALLOW_WRITE` | vacío | rutas extra que mantener escribibles, separadas por `:` |
|
|
1835
1947
|
| `CITY_UPDATE_CHECK` | `1` | `0` no pregunta nunca a npm si hay versión más nueva |
|
|
@@ -1966,10 +2078,18 @@ tus repos, adjuntarse a tu tmux o leer ficheros privados de tu home. Para códig
|
|
|
1966
2078
|
no confiable usa cuentas/VMs/contenedores separados y aplica también los permisos
|
|
1967
2079
|
del CLI de cada proveedor.
|
|
1968
2080
|
|
|
1969
|
-
|
|
1970
|
-
tokens, limita los scopes y revisa
|
|
1971
|
-
|
|
1972
|
-
|
|
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.
|
|
1973
2093
|
|
|
1974
2094
|
## Resolución de problemas
|
|
1975
2095
|
|
|
@@ -2131,6 +2251,115 @@ La detección exige `.git` (directorio o fichero de worktree) y un remote `origi
|
|
|
2131
2251
|
Si acabas de cambiar las raíces, ejecuta `plugin/scripts/busca.py --refresh`. `AGENTS_CITY_ORG` puede estar filtrando el repo;
|
|
2132
2252
|
déjala vacía para indexar todos los remotes.
|
|
2133
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
|
+
|
|
2134
2363
|
### Desinstalarlo del todo
|
|
2135
2364
|
|
|
2136
2365
|
```bash
|
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ This is `0.x` on purpose: the commands are usable today, and the file formats
|
|
|
104
104
|
and APIs can still change between minor versions. Nothing here pretends to be
|
|
105
105
|
frozen yet.
|
|
106
106
|
|
|
107
|
-
You need Node.js 22+, Python 3 and tmux; the
|
|
107
|
+
You need Node.js 22.13+, Python 3 and tmux; the
|
|
108
108
|
[requirements table](#base-requirements) has the details, and `agents-city seat`
|
|
109
109
|
offers to install tmux when it is missing. Nothing is installed system-wide
|
|
110
110
|
beyond the npm global folder of your active Node installation.
|
|
@@ -160,7 +160,7 @@ agents-city --version
|
|
|
160
160
|
|
|
161
161
|
| Requirement | Used for |
|
|
162
162
|
|---|---|
|
|
163
|
-
| Node.js 22 or later | npm package, WebSocket bus, and frontends |
|
|
163
|
+
| Node.js 22.13 or later | npm package, WebSocket bus, local reception, and frontends |
|
|
164
164
|
| npm | installation and packaging |
|
|
165
165
|
| Python 3 | Hall, onboarding, cities, maps, and utilities |
|
|
166
166
|
| bash | sessions and launchers |
|
|
@@ -486,6 +486,7 @@ agents-city setup
|
|
|
486
486
|
agents-city seat
|
|
487
487
|
agents-city cities
|
|
488
488
|
agents-city road
|
|
489
|
+
agents-city connect
|
|
489
490
|
agents-city bus
|
|
490
491
|
agents-city committee
|
|
491
492
|
agents-city agents
|
|
@@ -576,6 +577,18 @@ explicit choice. Translations are keyed by the English sentence, so anything not
|
|
|
576
577
|
yet translated falls back to readable English rather than to an identifier — new
|
|
577
578
|
strings are never blocked on a translation pass.
|
|
578
579
|
|
|
580
|
+
Coverage is a test, not a habit. `bin/test-i18n.py` reads the render paths, pulls
|
|
581
|
+
out every English sentence a person will see, and fails when one has no Spanish —
|
|
582
|
+
so a new view cannot quietly ship untranslated, which is how coverage had drifted
|
|
583
|
+
to about 40% before anybody noticed.
|
|
584
|
+
|
|
585
|
+
The obvious mechanism, sweeping the rendered DOM and translating what matches a
|
|
586
|
+
key, is deliberately **not** what this does. At DOM time there is no way to tell
|
|
587
|
+
a sentence this product wrote from a city or agent name somebody typed, so a
|
|
588
|
+
person whose city is called `Overview` would watch it rename itself. The
|
|
589
|
+
distinction only exists in the source, between a literal and an interpolation,
|
|
590
|
+
and that is where the check is made: anything holding a `${}` is skipped.
|
|
591
|
+
|
|
579
592
|
### `agents-city setup`
|
|
580
593
|
|
|
581
594
|
Creates or selects a city and opens the Hall; `--tui` hands the flow to `seat`.
|
|
@@ -681,6 +694,62 @@ agents-city road disconnect product <remote-city-id>
|
|
|
681
694
|
A city cannot connect to itself. Each machine must independently accept the
|
|
682
695
|
other remote invitation.
|
|
683
696
|
|
|
697
|
+
### `agents-city connect`
|
|
698
|
+
|
|
699
|
+
Pairs this computer with a managed Road service. It does not create a
|
|
700
|
+
connection unilaterally: both people approve it in the service, and the
|
|
701
|
+
recipient sees the sender in their private human reception without exposing a
|
|
702
|
+
city catalogue. The public client implements protocol v4; the hosted service is
|
|
703
|
+
outside this repository and is not production-enabled or independently audited.
|
|
704
|
+
|
|
705
|
+
```bash
|
|
706
|
+
agents-city connect --service https://connect.example.com --trust-file roots.json
|
|
707
|
+
agents-city connect --city product
|
|
708
|
+
agents-city connect --all
|
|
709
|
+
agents-city connect status
|
|
710
|
+
agents-city connect roads
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
The command generates Ed25519/X25519, Olm and signed ML-KEM-768 material on this
|
|
714
|
+
computer, prints a one-use PASCO and opens the browser for approval. Only public
|
|
715
|
+
material is uploaded. Private keys, ratchet state, ML-KEM seeds and retry data
|
|
716
|
+
are encrypted in `~/.agents-city/.runtime/connect/vault/`; the wrapping key
|
|
717
|
+
stays in macOS Keychain, Windows Credential Manager or Linux Secret Service.
|
|
718
|
+
The client fails closed if that keyring is unavailable. The vault is sealed from
|
|
719
|
+
repo-agent windows on macOS and Linux.
|
|
720
|
+
|
|
721
|
+
The signed root chain supplied through `--trust-file` is mandatory for first
|
|
722
|
+
pairing with a non-development service. The client persists its last accepted
|
|
723
|
+
version. A later root must continue from that exact local root and carry enough
|
|
724
|
+
signatures from both the old and new offline authorities; skipped versions,
|
|
725
|
+
rollback, expiry and silent operator/witness replacement are rejected. Protocol
|
|
726
|
+
v4 then verifies the peer through key transparency, protects the first Olm
|
|
727
|
+
message with hybrid X25519 + ML-KEM-768, and uses the Olm Double Ratchet. Normal
|
|
728
|
+
sealed submissions omit sender, device, city and Road identity from the outer
|
|
729
|
+
request. This does not hide IP address, timing or padded size from Cloudflare,
|
|
730
|
+
and later ratchet steps are classical.
|
|
731
|
+
|
|
732
|
+
The package includes a public root only for the exact managed sandbox origin;
|
|
733
|
+
self-hosted services still require their reviewed `--trust-file`. A root
|
|
734
|
+
returned by the service is never accepted as a first pin.
|
|
735
|
+
|
|
736
|
+
`--city` chooses a local hub that can keep the computer's reception bridge
|
|
737
|
+
alive; it is not a recipient selector and is never disclosed to the other
|
|
738
|
+
person. Exactly one hub per computer holds the lease and one outbound encrypted
|
|
739
|
+
session; no public port is opened. Use `--service URL` or
|
|
740
|
+
`AGENTS_CITY_CONNECT_URL` for a pilot endpoint. The hosted server is not part of
|
|
741
|
+
this Apache repository; the auditable client and wire protocol are.
|
|
742
|
+
|
|
743
|
+
`agents-city connect roads` prints a connected person's name for a person Road,
|
|
744
|
+
not the opaque `rx-*` transport endpoints. In the Hall, every incoming message
|
|
745
|
+
waits for manual review by default. The owner may route it to one or more local
|
|
746
|
+
cities, reject it with a reason, or explicitly enable the deterministic Auto
|
|
747
|
+
router. Auto routes only one unique low-risk rule match; ambiguous, unmatched,
|
|
748
|
+
prompt-like, secret-seeking, or command-like text remains in the human queue.
|
|
749
|
+
|
|
750
|
+
See [docs/managed-connect.md](docs/managed-connect.md) for the exact key,
|
|
751
|
+
envelope, encryption, ACK, revocation and threat-model contract.
|
|
752
|
+
|
|
684
753
|
### `agents-city bus`
|
|
685
754
|
|
|
686
755
|
Operates messages between seats over declared roads.
|
|
@@ -695,7 +764,7 @@ agents-city bus send '*' "Notice for every connected city"
|
|
|
695
764
|
| Subcommand | Effect |
|
|
696
765
|
|---|---|
|
|
697
766
|
| `roster` | return roads and known online presence |
|
|
698
|
-
| `inbox` | return and consume
|
|
767
|
+
| `inbox` | return and consume the next approved batch of up to 20; managed text is unavailable until the owner routes it in the Hall |
|
|
699
768
|
| `send owner/city TEXT` | send to one allowed destination |
|
|
700
769
|
| `send '*' TEXT` | send to all roads; requires at least one |
|
|
701
770
|
|
|
@@ -1550,9 +1619,28 @@ AGENTS_CITY_DATA="$HOME/.agents-city/$CITY_OWNER/product" \
|
|
|
1550
1619
|
Inside a normal session, you do not need to set `AGENTS_CITY_DATA`; it is already
|
|
1551
1620
|
injected into each window. The example makes it explicit for an outside terminal.
|
|
1552
1621
|
|
|
1553
|
-
### Case 10: connect
|
|
1622
|
+
### Case 10: connect two people on different machines
|
|
1554
1623
|
|
|
1555
|
-
|
|
1624
|
+
With a managed Road operator, each person pairs a computer. `--city` chooses the
|
|
1625
|
+
local hub that will start the owner-level reception bridge; it does not reveal
|
|
1626
|
+
that city or give the other person direct access to it:
|
|
1627
|
+
|
|
1628
|
+
```bash
|
|
1629
|
+
agents-city connect --city product --service https://connect.example.com --trust-file roots.json
|
|
1630
|
+
agents-city connect --city research --service https://connect.example.com --trust-file roots.json
|
|
1631
|
+
```
|
|
1632
|
+
|
|
1633
|
+
One person requests the connection in that service and the other accepts it.
|
|
1634
|
+
The clients learn the active bilateral person Road over their authenticated
|
|
1635
|
+
relay sessions; neither side exchanges a shared bus token, exposes a local
|
|
1636
|
+
port, or receives the other person's city catalogue. Incoming text first stops
|
|
1637
|
+
in the human reception. The recipient decides which local city or cities may
|
|
1638
|
+
read it, or lets the optional fail-closed rule router decide when one match is
|
|
1639
|
+
unambiguous. The public client contract is documented in
|
|
1640
|
+
[docs/managed-connect.md](docs/managed-connect.md).
|
|
1641
|
+
|
|
1642
|
+
To self-host the existing token-based remote transport instead, exchange the
|
|
1643
|
+
public city invitations manually. On machine A:
|
|
1556
1644
|
|
|
1557
1645
|
```bash
|
|
1558
1646
|
agents-city road invite product > product.invitation.json
|
|
@@ -1780,12 +1868,29 @@ The local hub keeps ephemeral state separate from readable configuration:
|
|
|
1780
1868
|
├── road-queue/*.json
|
|
1781
1869
|
├── road-inbox/*.json
|
|
1782
1870
|
└── road-history.jsonl
|
|
1871
|
+
|
|
1872
|
+
~/.agents-city/.runtime/reception/
|
|
1873
|
+
└── reception.sqlite3 # owner quarantine shared by local cities
|
|
1783
1874
|
```
|
|
1784
1875
|
|
|
1785
1876
|
Credentials and runtime files are created with private permissions. Outboxes let
|
|
1786
1877
|
an actor reconnect without losing an already accepted task; its ACK removes the
|
|
1787
|
-
pending item.
|
|
1788
|
-
|
|
1878
|
+
pending item. Actor outboxes and the local retry queue admit 200 pending items;
|
|
1879
|
+
the Road inbox admits 500 by default and returns at most 20 oldest items per
|
|
1880
|
+
read. Managed E2EE text first enters the separate owner reception: no city or
|
|
1881
|
+
model can consume it until a person rejects it or routes it to one or more
|
|
1882
|
+
cities in the Hall. A routed burst creates one coalesced seat wake-up rather
|
|
1883
|
+
than one model turn per message, and every native runtime runs at most one turn
|
|
1884
|
+
at a time. Full queues apply backpressure instead of silently deleting an older
|
|
1885
|
+
item. Message lifetime is 72 hours. `bus inbox` consumes approved `road-inbox`,
|
|
1886
|
+
not reception quarantine or append-only history.
|
|
1887
|
+
|
|
1888
|
+
Relay throughput is not answer throughput. For one city, safe semantic capacity
|
|
1889
|
+
is approximately grouped requests per turn divided by turn duration. The local
|
|
1890
|
+
regression drains 100 Road messages in five exact batches of 20 after one
|
|
1891
|
+
content-free wake-up; a separate 20-request slow-runtime test proves model
|
|
1892
|
+
concurrency stays at one and the durable backlog drains without loss. A sender's
|
|
1893
|
+
`queued` result never means read or answered.
|
|
1789
1894
|
|
|
1790
1895
|
### Configurable variables
|
|
1791
1896
|
|
|
@@ -1807,6 +1912,12 @@ message lifetime. `bus inbox` consumes `road-inbox`, not append-only history.
|
|
|
1807
1912
|
| `CITY_HOOKS` | `city` | `everywhere` runs the conscience hooks in every Claude session, not only city runtimes |
|
|
1808
1913
|
| `CITY_DESKTOP` | `~/Desktop`, or the Windows desktop under WSL | where `agents-city shortcut` writes |
|
|
1809
1914
|
| `CITY_CAGE` | `1` | `0` launches every window uncaged |
|
|
1915
|
+
| `CITY_ROAD_INBOX_MAX_PENDING` | `500` | local Road inbox capacity, from 20 to 10,000; a full inbox applies backpressure |
|
|
1916
|
+
| `CITY_ROAD_INBOX_WAKE_INTERVAL_MS` | `300000` | minimum interval between coalesced backlog wake-ups, from 30 seconds to 1 hour |
|
|
1917
|
+
| `CITY_RECEPTION_MAX_PENDING` | `10000` | owner-level pending remote messages before relay backpressure, from 100 to 100,000 |
|
|
1918
|
+
| `CITY_RECEPTION_MAX_BYTES` | `67108864` | total pending plaintext bytes in private local reception, from 1 MiB to 512 MiB |
|
|
1919
|
+
| `CITY_RECEPTION_PENDING_DAYS` | `30` | undecided local-message retention, from 1 to 90 days |
|
|
1920
|
+
| `CITY_RECEPTION_DELIVERY_INTERVAL_MS` | `1000` | how often a city bus claims human-approved routes, from 250 ms to 30 seconds |
|
|
1810
1921
|
| `CITY_CAGE_DENY` | empty | extra colon-separated paths to seal |
|
|
1811
1922
|
| `CITY_CAGE_ALLOW_WRITE` | empty | extra colon-separated paths to keep writable |
|
|
1812
1923
|
| `CITY_UPDATE_CHECK` | `1` | `0` never asks npm whether a newer version exists |
|
|
@@ -1936,10 +2047,18 @@ read your repos, attach to tmux, or read private files in your home. Use separat
|
|
|
1936
2047
|
accounts, VMs, or containers for untrusted code, and also apply each provider
|
|
1937
2048
|
CLI's permission controls.
|
|
1938
2049
|
|
|
1939
|
-
A remote bus expands the trust surface.
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
2050
|
+
A remote bus expands the trust surface. For the self-hosted token transport,
|
|
2051
|
+
deploy HTTPS/WSS, rotate tokens, limit scopes, and read
|
|
2052
|
+
[docs/self-host.md](docs/self-host.md). Managed Connect instead uses device
|
|
2053
|
+
signatures, witnessed key transparency, hybrid X25519 + ML-KEM-768 session
|
|
2054
|
+
establishment, an Olm Double Ratchet and sealed delivery. Its private material
|
|
2055
|
+
is encrypted under an OS-keyring wrapping key in the cage-sealed
|
|
2056
|
+
`~/.agents-city/.runtime/connect/vault/` directory; see
|
|
2057
|
+
[docs/managed-connect.md](docs/managed-connect.md). A managed Road authorises
|
|
2058
|
+
encrypted reachability to the owner's human reception, not direct model input.
|
|
2059
|
+
Only the owner's later route makes the text available to selected cities. No
|
|
2060
|
+
Road authorises execution of received commands or grants remote filesystem
|
|
2061
|
+
access.
|
|
1943
2062
|
|
|
1944
2063
|
## Troubleshooting
|
|
1945
2064
|
|
|
@@ -2096,6 +2215,114 @@ Discovery requires `.git` (a directory or worktree file) and an `origin` remote.
|
|
|
2096
2215
|
If roots just changed, run `plugin/scripts/busca.py --refresh`. `AGENTS_CITY_ORG` may be filtering the repo;
|
|
2097
2216
|
leave it empty to index every remote.
|
|
2098
2217
|
|
|
2218
|
+
### Your CLIs, as you have them
|
|
2219
|
+
|
|
2220
|
+
This does not compete with the CLI you already run. It orchestrates them, which
|
|
2221
|
+
only works if it respects what you configured in them — your plugins, your
|
|
2222
|
+
skills, your MCP servers, your model, your permissions.
|
|
2223
|
+
|
|
2224
|
+
That is a claim about your machine, so it ships as a command rather than a
|
|
2225
|
+
promise:
|
|
2226
|
+
|
|
2227
|
+
```bash
|
|
2228
|
+
agents-city doctor --config # what we add, inherit and leave alone
|
|
2229
|
+
agents-city doctor --config --json # the same, as data
|
|
2230
|
+
```
|
|
2231
|
+
|
|
2232
|
+
It prints three columns per CLI, and the difference between them is the point:
|
|
2233
|
+
|
|
2234
|
+
* **the deal** — what we add or override. It is short, every line says *why*,
|
|
2235
|
+
and it is what makes the bus the only route between agents and the cage hold.
|
|
2236
|
+
Without it there is no product.
|
|
2237
|
+
* **we inherit** — what we deliberately do *not* send, so your own CLI reads
|
|
2238
|
+
your own configuration for it. Your model, your effort, your approval policy.
|
|
2239
|
+
* **untouched** — what loads exactly as it always did.
|
|
2240
|
+
|
|
2241
|
+
The report and the runtime read the **same file** — `plugin/channel/runtime/arnes.json`
|
|
2242
|
+
— so the claim cannot drift from the behaviour. The connectors take their policy
|
|
2243
|
+
values out of that declaration instead of spelling them inline, and the suite
|
|
2244
|
+
fails if a runtime imposes something the declaration does not mention. Writing
|
|
2245
|
+
that check found two: a system prompt injected into Kimi that nothing declared,
|
|
2246
|
+
and a sandbox value written in two places.
|
|
2247
|
+
|
|
2248
|
+
Where your setting and ours meet, yours wins where it can: Codex's
|
|
2249
|
+
`approval_policy` is honoured when you set one, and `on-request` is only the
|
|
2250
|
+
fallback when you have not. The report says the consequence out loud — `never`
|
|
2251
|
+
disables app and MCP tools — instead of quietly deciding you did not mean it.
|
|
2252
|
+
|
|
2253
|
+
### Your chair keeps your own Claude Code
|
|
2254
|
+
|
|
2255
|
+
The seat window opens **Claude Code itself** — your plugins, your skills, your
|
|
2256
|
+
MCP servers, your statusline, slash-command completion, the model picker. It is
|
|
2257
|
+
the harness you already use, in the pane, and that is deliberate: the chair is
|
|
2258
|
+
where a person works by hand.
|
|
2259
|
+
|
|
2260
|
+
It is still on the bus. The city plugin's `SessionStart`, `UserPromptSubmit`,
|
|
2261
|
+
`Stop` and `SessionEnd` hooks report that session's prompts and answers as the
|
|
2262
|
+
same `conversation.*` events the gateway reports, so the town hall sees the
|
|
2263
|
+
conversation either way. And it carries the same two flags that make the bus the
|
|
2264
|
+
only route between agents — `crossSessionInbound: refuse` and
|
|
2265
|
+
`--disallowed-tools SendMessage,ListAgents`. A quieter product with a hole in it
|
|
2266
|
+
would not be a better product.
|
|
2267
|
+
|
|
2268
|
+
**Agent houses keep the gateway** and its `city>` prompt, because what the
|
|
2269
|
+
gateway buys is the bus being able to *push* work into a window — which is the
|
|
2270
|
+
whole job of a house and no part of the chair's.
|
|
2271
|
+
|
|
2272
|
+
One card key moves the chair back:
|
|
2273
|
+
|
|
2274
|
+
```yaml
|
|
2275
|
+
ui.seat: gateway # the city's own prompt in the chair, as before
|
|
2276
|
+
```
|
|
2277
|
+
|
|
2278
|
+
`CITY_UI=gateway` forces it for one launch. Houses are not asked: a house exists
|
|
2279
|
+
to receive assignments, and the gateway is what makes that possible.
|
|
2280
|
+
|
|
2281
|
+
### The engine a house runs on
|
|
2282
|
+
|
|
2283
|
+
`model.<window>` and `effort.<window>` on the card say what a house runs on, once,
|
|
2284
|
+
whatever CLI runs it. Claude takes them as flags; the native gateways parse the
|
|
2285
|
+
same spelling out of the command string and send it with the turn — which is why
|
|
2286
|
+
one key means the same thing for all four:
|
|
2287
|
+
|
|
2288
|
+
| provider | model | effort |
|
|
2289
|
+
| --- | --- | --- |
|
|
2290
|
+
| `claude` | yes, an alias the CLI resolves (`opus`, `sonnet`…) | yes |
|
|
2291
|
+
| `codex` | yes, the name your Codex uses (`~/.codex/config.toml`) | yes |
|
|
2292
|
+
| `opencode` | yes, `provider/model` | no such setting |
|
|
2293
|
+
| `kimi` | yes | no such setting |
|
|
2294
|
+
|
|
2295
|
+
A command that already carries the flag keeps it: `runs.dbt: codex --model o3`
|
|
2296
|
+
was somebody saying what they meant, and a generic key must not overrule a
|
|
2297
|
+
specific sentence. Effort is written only where it is read, because a flag
|
|
2298
|
+
nothing reads is how a control ends up looking like it works.
|
|
2299
|
+
|
|
2300
|
+
### Releasing
|
|
2301
|
+
|
|
2302
|
+
A release is a tag. Pushing `v0.5.2` runs the whole suite on Linux, macOS and
|
|
2303
|
+
Windows, checks that the tag and the three manifests name the same version, and
|
|
2304
|
+
publishes with **provenance** — a signed statement of which commit and which
|
|
2305
|
+
workflow produced that exact tarball. Anyone can check it:
|
|
2306
|
+
|
|
2307
|
+
```bash
|
|
2308
|
+
npm audit signatures
|
|
2309
|
+
```
|
|
2310
|
+
|
|
2311
|
+
No token is stored anywhere. It publishes through npm's trusted publishing,
|
|
2312
|
+
which trades a short-lived OIDC identity from the workflow for the right to
|
|
2313
|
+
publish this one package: a secret that does not exist cannot leak.
|
|
2314
|
+
|
|
2315
|
+
```bash
|
|
2316
|
+
npm version patch --no-git-tag-version # then open a PR with the bump
|
|
2317
|
+
git tag v0.5.2 && git push origin v0.5.2 # the tag is the release
|
|
2318
|
+
```
|
|
2319
|
+
|
|
2320
|
+
This exists because publishing by hand did not work. Four versions went
|
|
2321
|
+
unpublished in a single day, not because anybody was careless but because the
|
|
2322
|
+
step lived in a person's head and needed their passkey — and what reached the
|
|
2323
|
+
registry was whatever happened to be in a working directory, connected to no
|
|
2324
|
+
commit anyone could name.
|
|
2325
|
+
|
|
2099
2326
|
### Removing it completely
|
|
2100
2327
|
|
|
2101
2328
|
```bash
|