agents-city 0.3.0-beta.21

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 (440) hide show
  1. package/.claude-plugin/marketplace.json +16 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/README.es.md +2021 -0
  5. package/README.md +1999 -0
  6. package/benchmarks/committee/README.md +39 -0
  7. package/benchmarks/committee/metrics.py +51 -0
  8. package/benchmarks/committee/run.py +64 -0
  9. package/benchmarks/committee/traces/01-single.json +8 -0
  10. package/benchmarks/committee/traces/02-mesh.json +16 -0
  11. package/benchmarks/committee/traces/03-chair.json +15 -0
  12. package/benchmarks/latency/README.md +35 -0
  13. package/benchmarks/latency/fake-claude-cli.mjs +119 -0
  14. package/benchmarks/latency/fake-native-server.mjs +340 -0
  15. package/benchmarks/latency/fake-tui.py +91 -0
  16. package/benchmarks/latency/live.py +380 -0
  17. package/benchmarks/stress/README.md +20 -0
  18. package/benchmarks/stress/run.py +487 -0
  19. package/bin/agents +4 -0
  20. package/bin/agents-city.js +116 -0
  21. package/bin/benchmark +17 -0
  22. package/bin/bus +6 -0
  23. package/bin/cities +3 -0
  24. package/bin/city +86 -0
  25. package/bin/committee +6 -0
  26. package/bin/demo +200 -0
  27. package/bin/exit +5 -0
  28. package/bin/hall +73 -0
  29. package/bin/hall.html +426 -0
  30. package/bin/logs +3 -0
  31. package/bin/report.py +14 -0
  32. package/bin/reset +3 -0
  33. package/bin/road +3 -0
  34. package/bin/seat +10 -0
  35. package/bin/serve.py +1428 -0
  36. package/bin/setup.py +753 -0
  37. package/bin/skills +3 -0
  38. package/bin/test +131 -0
  39. package/bin/test-adapter.py +183 -0
  40. package/bin/test-admision.py +99 -0
  41. package/bin/test-avatar.py +58 -0
  42. package/bin/test-benchmark.py +40 -0
  43. package/bin/test-broker.py +334 -0
  44. package/bin/test-cage.py +206 -0
  45. package/bin/test-card.py +402 -0
  46. package/bin/test-channel.py +379 -0
  47. package/bin/test-cities.py +453 -0
  48. package/bin/test-claude-runtime.py +252 -0
  49. package/bin/test-committee.py +340 -0
  50. package/bin/test-contracts.py +544 -0
  51. package/bin/test-crecimiento.py +164 -0
  52. package/bin/test-demo.py +308 -0
  53. package/bin/test-doctor.py +106 -0
  54. package/bin/test-domains.py +151 -0
  55. package/bin/test-evidencia.py +50 -0
  56. package/bin/test-exit.py +128 -0
  57. package/bin/test-hall-protocol.py +93 -0
  58. package/bin/test-launch.py +169 -0
  59. package/bin/test-live-feed.py +508 -0
  60. package/bin/test-pairing.py +99 -0
  61. package/bin/test-parcels.py +283 -0
  62. package/bin/test-runtime-failures.py +252 -0
  63. package/bin/test-runtime-ui.py +488 -0
  64. package/bin/test-runtime.py +268 -0
  65. package/bin/test-rutas.py +80 -0
  66. package/bin/test-seat.py +1386 -0
  67. package/bin/test-security.py +150 -0
  68. package/bin/test-serve.py +1057 -0
  69. package/bin/test-stress.py +64 -0
  70. package/bin/test-widgets.py +143 -0
  71. package/bin/test-workspace.py +188 -0
  72. package/bin/testlib.py +95 -0
  73. package/bin/tokens.py +14 -0
  74. package/bus/scripts/deploy.sh +60 -0
  75. package/bus/scripts/mint-token.sh +68 -0
  76. package/bus/scripts/setup-dev.sh +79 -0
  77. package/bus/scripts/test-channel.ts +8 -0
  78. package/bus/scripts/test-hub.ts +266 -0
  79. package/bus/scripts/test-local.sh +40 -0
  80. package/bus/scripts/test-queue.ts +132 -0
  81. package/bus/worker/package-lock.json +1971 -0
  82. package/bus/worker/package.json +17 -0
  83. package/bus/worker/src/index.ts +485 -0
  84. package/bus/worker/tsconfig.json +13 -0
  85. package/bus/worker/wrangler.toml +32 -0
  86. package/city/oven/README.md +59 -0
  87. package/city/oven/collect.py +43 -0
  88. package/city/oven/oven.html +4 -0
  89. package/city/scripts/history.py +120 -0
  90. package/city/scripts/seed.py +442 -0
  91. package/city/web/assets/modelos/License.txt +28 -0
  92. package/city/web/assets/modelos/PROCEDENCIA.txt +3 -0
  93. package/city/web/assets/modelos/building-a.glb +0 -0
  94. package/city/web/assets/modelos/building-b.glb +0 -0
  95. package/city/web/assets/modelos/building-c.glb +0 -0
  96. package/city/web/assets/modelos/building-d.glb +0 -0
  97. package/city/web/assets/modelos/building-e.glb +0 -0
  98. package/city/web/assets/modelos/building-f.glb +0 -0
  99. package/city/web/assets/modelos/building-g.glb +0 -0
  100. package/city/web/assets/modelos/building-h.glb +0 -0
  101. package/city/web/assets/sprites/building-a.png +0 -0
  102. package/city/web/assets/sprites/building-b.png +0 -0
  103. package/city/web/assets/sprites/building-c.png +0 -0
  104. package/city/web/assets/sprites/building-d.png +0 -0
  105. package/city/web/assets/sprites/building-e.png +0 -0
  106. package/city/web/assets/sprites/building-f.png +0 -0
  107. package/city/web/assets/sprites/building-g.png +0 -0
  108. package/city/web/assets/sprites/building-h.png +0 -0
  109. package/city/web/assets/sprites/building-i.png +0 -0
  110. package/city/web/assets/sprites/building-j.png +0 -0
  111. package/city/web/assets/sprites/building-k.png +0 -0
  112. package/city/web/assets/sprites/building-l.png +0 -0
  113. package/city/web/assets/sprites/building-m.png +0 -0
  114. package/city/web/assets/sprites/building-n.png +0 -0
  115. package/city/web/assets/sprites/building-skyscraper-a.png +0 -0
  116. package/city/web/assets/sprites/building-skyscraper-b.png +0 -0
  117. package/city/web/assets/sprites/building-skyscraper-c.png +0 -0
  118. package/city/web/assets/sprites/building-skyscraper-d.png +0 -0
  119. package/city/web/assets/sprites/building-skyscraper-e.png +0 -0
  120. package/city/web/assets/sprites/catalogo.json +47 -0
  121. package/city/web/assets/sprites/detail-awning-wide.png +0 -0
  122. package/city/web/assets/sprites/detail-awning.png +0 -0
  123. package/city/web/assets/sprites/detail-overhang-wide.png +0 -0
  124. package/city/web/assets/sprites/detail-overhang.png +0 -0
  125. package/city/web/assets/sprites/detail-parasol-a.png +0 -0
  126. package/city/web/assets/sprites/detail-parasol-b.png +0 -0
  127. package/city/web/assets/sprites/low-detail-building-a.png +0 -0
  128. package/city/web/assets/sprites/low-detail-building-b.png +0 -0
  129. package/city/web/assets/sprites/low-detail-building-c.png +0 -0
  130. package/city/web/assets/sprites/low-detail-building-d.png +0 -0
  131. package/city/web/assets/sprites/low-detail-building-e.png +0 -0
  132. package/city/web/assets/sprites/low-detail-building-f.png +0 -0
  133. package/city/web/assets/sprites/low-detail-building-g.png +0 -0
  134. package/city/web/assets/sprites/low-detail-building-h.png +0 -0
  135. package/city/web/assets/sprites/low-detail-building-i.png +0 -0
  136. package/city/web/assets/sprites/low-detail-building-j.png +0 -0
  137. package/city/web/assets/sprites/low-detail-building-k.png +0 -0
  138. package/city/web/assets/sprites/low-detail-building-l.png +0 -0
  139. package/city/web/assets/sprites/low-detail-building-m.png +0 -0
  140. package/city/web/assets/sprites/low-detail-building-n.png +0 -0
  141. package/city/web/assets/sprites/low-detail-building-wide-a.png +0 -0
  142. package/city/web/assets/sprites/low-detail-building-wide-b.png +0 -0
  143. package/city/web/assets/sprites/medidas.json +248 -0
  144. package/city/web/dist/city.js +939 -0
  145. package/city/web/dist/index.html +294 -0
  146. package/city/web/dist/modelos/License.txt +28 -0
  147. package/city/web/dist/modelos/PROCEDENCIA.txt +3 -0
  148. package/city/web/dist/modelos/building-a.glb +0 -0
  149. package/city/web/dist/modelos/building-b.glb +0 -0
  150. package/city/web/dist/modelos/building-c.glb +0 -0
  151. package/city/web/dist/modelos/building-d.glb +0 -0
  152. package/city/web/dist/modelos/building-e.glb +0 -0
  153. package/city/web/dist/modelos/building-f.glb +0 -0
  154. package/city/web/dist/modelos/building-g.glb +0 -0
  155. package/city/web/dist/modelos/building-h.glb +0 -0
  156. package/city/web/dist/sprites/building-a.png +0 -0
  157. package/city/web/dist/sprites/building-b.png +0 -0
  158. package/city/web/dist/sprites/building-c.png +0 -0
  159. package/city/web/dist/sprites/building-d.png +0 -0
  160. package/city/web/dist/sprites/building-e.png +0 -0
  161. package/city/web/dist/sprites/building-f.png +0 -0
  162. package/city/web/dist/sprites/building-g.png +0 -0
  163. package/city/web/dist/sprites/building-h.png +0 -0
  164. package/city/web/dist/sprites/building-i.png +0 -0
  165. package/city/web/dist/sprites/building-j.png +0 -0
  166. package/city/web/dist/sprites/building-k.png +0 -0
  167. package/city/web/dist/sprites/building-l.png +0 -0
  168. package/city/web/dist/sprites/building-m.png +0 -0
  169. package/city/web/dist/sprites/building-n.png +0 -0
  170. package/city/web/dist/sprites/building-skyscraper-a.png +0 -0
  171. package/city/web/dist/sprites/building-skyscraper-b.png +0 -0
  172. package/city/web/dist/sprites/building-skyscraper-c.png +0 -0
  173. package/city/web/dist/sprites/building-skyscraper-d.png +0 -0
  174. package/city/web/dist/sprites/building-skyscraper-e.png +0 -0
  175. package/city/web/dist/sprites/catalogo.json +47 -0
  176. package/city/web/dist/sprites/detail-awning-wide.png +0 -0
  177. package/city/web/dist/sprites/detail-awning.png +0 -0
  178. package/city/web/dist/sprites/detail-overhang-wide.png +0 -0
  179. package/city/web/dist/sprites/detail-overhang.png +0 -0
  180. package/city/web/dist/sprites/detail-parasol-a.png +0 -0
  181. package/city/web/dist/sprites/detail-parasol-b.png +0 -0
  182. package/city/web/dist/sprites/low-detail-building-a.png +0 -0
  183. package/city/web/dist/sprites/low-detail-building-b.png +0 -0
  184. package/city/web/dist/sprites/low-detail-building-c.png +0 -0
  185. package/city/web/dist/sprites/low-detail-building-d.png +0 -0
  186. package/city/web/dist/sprites/low-detail-building-e.png +0 -0
  187. package/city/web/dist/sprites/low-detail-building-f.png +0 -0
  188. package/city/web/dist/sprites/low-detail-building-g.png +0 -0
  189. package/city/web/dist/sprites/low-detail-building-h.png +0 -0
  190. package/city/web/dist/sprites/low-detail-building-i.png +0 -0
  191. package/city/web/dist/sprites/low-detail-building-j.png +0 -0
  192. package/city/web/dist/sprites/low-detail-building-k.png +0 -0
  193. package/city/web/dist/sprites/low-detail-building-l.png +0 -0
  194. package/city/web/dist/sprites/low-detail-building-m.png +0 -0
  195. package/city/web/dist/sprites/low-detail-building-n.png +0 -0
  196. package/city/web/dist/sprites/low-detail-building-wide-a.png +0 -0
  197. package/city/web/dist/sprites/low-detail-building-wide-b.png +0 -0
  198. package/city/web/dist/sprites/medidas.json +248 -0
  199. package/city/web/dist-hall/hall.js +264 -0
  200. package/city/web/index.html +294 -0
  201. package/city/web/package.json +18 -0
  202. package/city/web/sella.py +21 -0
  203. package/city/web/src/activity-actors.ts +47 -0
  204. package/city/web/src/activity.ts +172 -0
  205. package/city/web/src/ayuntamiento.ts +580 -0
  206. package/city/web/src/draw.ts +640 -0
  207. package/city/web/src/game-speech.ts +79 -0
  208. package/city/web/src/hall.ts +1867 -0
  209. package/city/web/src/main.ts +2225 -0
  210. package/city/web/src/oven.ts +124 -0
  211. package/city/web/src/people.ts +244 -0
  212. package/city/web/src/presencia.ts +193 -0
  213. package/city/web/src/puertas.ts +180 -0
  214. package/city/web/src/repo-roles.ts +59 -0
  215. package/city/worker/package.json +16 -0
  216. package/city/worker/schema.sql +117 -0
  217. package/city/worker/src/index.ts +702 -0
  218. package/city/worker/src/square.ts +218 -0
  219. package/city/worker/wrangler.toml +58 -0
  220. package/demo/ada.md +50 -0
  221. package/demo/bruno.md +62 -0
  222. package/demo/camila.md +56 -0
  223. package/demo/city/ada.md +40 -0
  224. package/demo/city/city.yml +8 -0
  225. package/demo/city/parcels.yml +15 -0
  226. package/demo/city/roads.json +4 -0
  227. package/demo/city/units.yml +10 -0
  228. package/demo/clinica/city.yml +8 -0
  229. package/demo/clinica/parcels.yml +15 -0
  230. package/demo/clinica/roads.json +4 -0
  231. package/demo/clinica/units.yml +9 -0
  232. package/demo/clinica/vera.md +46 -0
  233. package/demo/dante.md +54 -0
  234. package/demo/despacho/city.yml +8 -0
  235. package/demo/despacho/marta.md +46 -0
  236. package/demo/despacho/parcels.yml +15 -0
  237. package/demo/despacho/roads.json +4 -0
  238. package/demo/despacho/units.yml +9 -0
  239. package/demo/elsa.md +50 -0
  240. package/demo/farid.md +52 -0
  241. package/demo/greta.md +50 -0
  242. package/demo/hugo.md +49 -0
  243. package/demo/iris.md +49 -0
  244. package/demo/jonas.md +51 -0
  245. package/demo/kira.md +51 -0
  246. package/demo/luca.md +49 -0
  247. package/demo/parcels.yml +92 -0
  248. package/demo/seed.py +20 -0
  249. package/demo/show.py +161 -0
  250. package/demo/stories.py +824 -0
  251. package/demo/units.yml +33 -0
  252. package/docs/agents-first.md +99 -0
  253. package/docs/glossary.md +55 -0
  254. package/docs/map-live-layers.md +73 -0
  255. package/docs/security.md +231 -0
  256. package/docs/self-host.md +151 -0
  257. package/docs/testing.md +205 -0
  258. package/package.json +73 -0
  259. package/plugin/.claude-plugin/plugin.json +62 -0
  260. package/plugin/.mcp.json +15 -0
  261. package/plugin/channel/activity-cli.ts +16 -0
  262. package/plugin/channel/adapter-prompts.ts +113 -0
  263. package/plugin/channel/adapter.js +4292 -0
  264. package/plugin/channel/adapter.ts +133 -0
  265. package/plugin/channel/bus.js +20188 -0
  266. package/plugin/channel/bus.ts +131 -0
  267. package/plugin/channel/city-config.ts +125 -0
  268. package/plugin/channel/claude-channel.ts +58 -0
  269. package/plugin/channel/cli-args.ts +75 -0
  270. package/plugin/channel/client.js +4200 -0
  271. package/plugin/channel/client.ts +38 -0
  272. package/plugin/channel/committee/activity.ts +256 -0
  273. package/plugin/channel/committee/collection.ts +154 -0
  274. package/plugin/channel/committee/decision.ts +175 -0
  275. package/plugin/channel/committee/floor.ts +135 -0
  276. package/plugin/channel/committee/guards.ts +30 -0
  277. package/plugin/channel/committee/history.ts +38 -0
  278. package/plugin/channel/committee/render.ts +102 -0
  279. package/plugin/channel/committee/service.ts +72 -0
  280. package/plugin/channel/committee/storage.ts +92 -0
  281. package/plugin/channel/committee/types.ts +163 -0
  282. package/plugin/channel/committee/view.ts +63 -0
  283. package/plugin/channel/committee-cli.ts +109 -0
  284. package/plugin/channel/delivery-metrics.ts +61 -0
  285. package/plugin/channel/delivery-queue.ts +118 -0
  286. package/plugin/channel/hub/activity-controller.ts +72 -0
  287. package/plugin/channel/hub/activity-feed.ts +169 -0
  288. package/plugin/channel/hub/committee-controller.ts +60 -0
  289. package/plugin/channel/hub/connections.ts +48 -0
  290. package/plugin/channel/hub/diagnostics.ts +67 -0
  291. package/plugin/channel/hub/envelope-validity.ts +109 -0
  292. package/plugin/channel/hub/envelopes.ts +66 -0
  293. package/plugin/channel/hub/lifecycle.ts +91 -0
  294. package/plugin/channel/hub/local-roads.ts +89 -0
  295. package/plugin/channel/hub/remote-roads.ts +165 -0
  296. package/plugin/channel/hub/road-controller.ts +99 -0
  297. package/plugin/channel/hub-client.ts +149 -0
  298. package/plugin/channel/local-hub.js +5995 -0
  299. package/plugin/channel/local-hub.ts +349 -0
  300. package/plugin/channel/map-reporter.ts +48 -0
  301. package/plugin/channel/package-lock.json +1731 -0
  302. package/plugin/channel/package.json +19 -0
  303. package/plugin/channel/protocol.ts +98 -0
  304. package/plugin/channel/road-cli.ts +18 -0
  305. package/plugin/channel/run.sh +15 -0
  306. package/plugin/channel/runtime/claude.ts +458 -0
  307. package/plugin/channel/runtime/codex-config.ts +77 -0
  308. package/plugin/channel/runtime/codex.ts +669 -0
  309. package/plugin/channel/runtime/command.ts +62 -0
  310. package/plugin/channel/runtime/factory.ts +15 -0
  311. package/plugin/channel/runtime/json-rpc.ts +154 -0
  312. package/plugin/channel/runtime/kimi.ts +277 -0
  313. package/plugin/channel/runtime/opencode.ts +248 -0
  314. package/plugin/channel/runtime/process.ts +84 -0
  315. package/plugin/channel/runtime/types.ts +45 -0
  316. package/plugin/channel/runtime-files.ts +73 -0
  317. package/plugin/channel/runtime-gateway.js +6396 -0
  318. package/plugin/channel/runtime-gateway.ts +358 -0
  319. package/plugin/channel/runtime-metrics.ts +52 -0
  320. package/plugin/channel/runtime-subscription.ts +180 -0
  321. package/plugin/channel/terminal-delivery.ts +131 -0
  322. package/plugin/channel/untrusted.ts +60 -0
  323. package/plugin/commands/committee.md +31 -0
  324. package/plugin/commands/exit.md +32 -0
  325. package/plugin/commands/goals.md +20 -0
  326. package/plugin/commands/join.md +18 -0
  327. package/plugin/commands/notice.md +20 -0
  328. package/plugin/commands/propose.md +19 -0
  329. package/plugin/commands/round.md +17 -0
  330. package/plugin/commands/session.md +22 -0
  331. package/plugin/commands/settings.md +25 -0
  332. package/plugin/commands/setup.md +21 -0
  333. package/plugin/commands/team.md +23 -0
  334. package/plugin/domains/custom.md +27 -0
  335. package/plugin/domains/finance.md +31 -0
  336. package/plugin/domains/healthcare.md +34 -0
  337. package/plugin/domains/legal.md +31 -0
  338. package/plugin/domains/marketing.md +33 -0
  339. package/plugin/domains/operations.md +31 -0
  340. package/plugin/domains/research.md +32 -0
  341. package/plugin/domains/sales.md +30 -0
  342. package/plugin/domains/software.md +37 -0
  343. package/plugin/hooks/activity.sh +6 -0
  344. package/plugin/hooks/digging.sh +68 -0
  345. package/plugin/hooks/growth.sh +42 -0
  346. package/plugin/hooks/hooks.json +106 -0
  347. package/plugin/hooks/notice-on-pr.sh +35 -0
  348. package/plugin/hooks/notice-on-stop.sh +80 -0
  349. package/plugin/hooks/notice-pending.sh +58 -0
  350. package/plugin/hooks/solo-en-ciudad.sh +23 -0
  351. package/plugin/hooks/tokens.sh +47 -0
  352. package/plugin/roles/examples/account-executive.md +25 -0
  353. package/plugin/roles/examples/ai-manager.md +34 -0
  354. package/plugin/roles/examples/associate.md +24 -0
  355. package/plugin/roles/examples/brand-lead.md +20 -0
  356. package/plugin/roles/examples/cfo.md +20 -0
  357. package/plugin/roles/examples/city-lead.md +25 -0
  358. package/plugin/roles/examples/clinical-director.md +26 -0
  359. package/plugin/roles/examples/clinical-ops.md +25 -0
  360. package/plugin/roles/examples/clinician.md +25 -0
  361. package/plugin/roles/examples/compliance.md +27 -0
  362. package/plugin/roles/examples/content.md +24 -0
  363. package/plugin/roles/examples/controller.md +27 -0
  364. package/plugin/roles/examples/cpto.md +41 -0
  365. package/plugin/roles/examples/customer-success.md +25 -0
  366. package/plugin/roles/examples/data-engineer.md +37 -0
  367. package/plugin/roles/examples/data.md +60 -0
  368. package/plugin/roles/examples/dev.md +37 -0
  369. package/plugin/roles/examples/devops.md +39 -0
  370. package/plugin/roles/examples/enablement.md +24 -0
  371. package/plugin/roles/examples/ethics.md +24 -0
  372. package/plugin/roles/examples/fin-analytics.md +27 -0
  373. package/plugin/roles/examples/health-compliance.md +25 -0
  374. package/plugin/roles/examples/health-data.md +26 -0
  375. package/plugin/roles/examples/knowledge.md +25 -0
  376. package/plugin/roles/examples/lifecycle.md +26 -0
  377. package/plugin/roles/examples/llm-engineer.md +34 -0
  378. package/plugin/roles/examples/managing-partner.md +20 -0
  379. package/plugin/roles/examples/methods.md +23 -0
  380. package/plugin/roles/examples/operations-lead.md +23 -0
  381. package/plugin/roles/examples/ops.md +24 -0
  382. package/plugin/roles/examples/patient-safety.md +26 -0
  383. package/plugin/roles/examples/performance.md +27 -0
  384. package/plugin/roles/examples/po.md +36 -0
  385. package/plugin/roles/examples/process-owner.md +23 -0
  386. package/plugin/roles/examples/product-design.md +39 -0
  387. package/plugin/roles/examples/program-manager.md +24 -0
  388. package/plugin/roles/examples/quality.md +25 -0
  389. package/plugin/roles/examples/research-director.md +24 -0
  390. package/plugin/roles/examples/research-ops.md +25 -0
  391. package/plugin/roles/examples/researcher.md +25 -0
  392. package/plugin/roles/examples/revenue-lead.md +25 -0
  393. package/plugin/roles/examples/revops.md +26 -0
  394. package/plugin/roles/examples/seo.md +27 -0
  395. package/plugin/roles/examples/specialist.md +24 -0
  396. package/plugin/scripts/admision.py +165 -0
  397. package/plugin/scripts/apaga.py +232 -0
  398. package/plugin/scripts/avatar.py +211 -0
  399. package/plugin/scripts/broker.py +531 -0
  400. package/plugin/scripts/cage.py +252 -0
  401. package/plugin/scripts/capabilities.py +197 -0
  402. package/plugin/scripts/card.py +312 -0
  403. package/plugin/scripts/cities.py +520 -0
  404. package/plugin/scripts/city-env.sh +90 -0
  405. package/plugin/scripts/city-runtime.sh +87 -0
  406. package/plugin/scripts/city-session.sh +526 -0
  407. package/plugin/scripts/city_env.py +67 -0
  408. package/plugin/scripts/crecimiento.py +140 -0
  409. package/plugin/scripts/deliberations.py +48 -0
  410. package/plugin/scripts/doctor.py +172 -0
  411. package/plugin/scripts/domains.py +201 -0
  412. package/plugin/scripts/evidencia.py +64 -0
  413. package/plugin/scripts/find-repos.sh +111 -0
  414. package/plugin/scripts/gh.py +159 -0
  415. package/plugin/scripts/hall_protocol.py +147 -0
  416. package/plugin/scripts/hook_activity.py +139 -0
  417. package/plugin/scripts/launch.py +94 -0
  418. package/plugin/scripts/logs.py +98 -0
  419. package/plugin/scripts/pairing.py +185 -0
  420. package/plugin/scripts/parcels.py +132 -0
  421. package/plugin/scripts/read-card.py +51 -0
  422. package/plugin/scripts/report.py +201 -0
  423. package/plugin/scripts/reset.py +180 -0
  424. package/plugin/scripts/roads.py +230 -0
  425. package/plugin/scripts/roles.py +274 -0
  426. package/plugin/scripts/runtime_log.py +69 -0
  427. package/plugin/scripts/runtime_processes.py +132 -0
  428. package/plugin/scripts/rutas.py +83 -0
  429. package/plugin/scripts/seat.py +1349 -0
  430. package/plugin/scripts/tokens.py +194 -0
  431. package/plugin/scripts/trust-repos.py +59 -0
  432. package/plugin/scripts/ui.py +280 -0
  433. package/plugin/scripts/units.py +80 -0
  434. package/plugin/scripts/workspace.py +364 -0
  435. package/plugin/skills/city/SKILL.md +191 -0
  436. package/templates/blank.md +39 -0
  437. package/templates/finance.md +44 -0
  438. package/templates/legal.md +45 -0
  439. package/templates/marketing.md +48 -0
  440. package/templates/product.md +45 -0
@@ -0,0 +1,32 @@
1
+ ---
2
+ id: research
3
+ order: 70
4
+ name: Research & education
5
+ summary: Coordinate questions, evidence, methods, ethics and reusable knowledge.
6
+ parcel: a study, course, corpus or research repository
7
+ source: github|disk
8
+ grows_with: reviewed findings or learning outcomes
9
+ grow_command:
10
+ roles:
11
+ - research-director # on by default
12
+ - researcher # on by default
13
+ - methods # on by default
14
+ - research-ops
15
+ - ethics
16
+ - knowledge
17
+ - blank
18
+ units:
19
+ - Studies ; 3fb8a0
20
+ - Methods ; 4a9ede
21
+ - Teaching ; e08a3c
22
+ - Knowledge ; 8f7ae6
23
+ ---
24
+ # Research & education
25
+
26
+ State the question, population, method, evidence quality and limits before the
27
+ conclusion. Preserve null results, competing explanations and provenance. Do not
28
+ upgrade correlation to causation or a preliminary result to settled knowledge.
29
+
30
+ The chair synthesises; methods and ethics roles remain independent checks. Reuse
31
+ existing evidence when it fits, but do not carry a result into a new context
32
+ without testing whether its assumptions still hold.
@@ -0,0 +1,30 @@
1
+ ---
2
+ id: sales
3
+ order: 60
4
+ name: Sales & customer success
5
+ summary: Coordinate pipeline, accounts, revenue operations and customer outcomes.
6
+ parcel: an account segment, playbook or revenue repository
7
+ source: github|disk
8
+ grows_with: verified customer outcomes and correctly closed opportunities
9
+ grow_command:
10
+ roles:
11
+ - revenue-lead # on by default
12
+ - account-executive # on by default
13
+ - revops # on by default
14
+ - customer-success
15
+ - enablement
16
+ - blank
17
+ units:
18
+ - New business ; 3fb8a0
19
+ - Expansion ; 8f7ae6
20
+ - Customer success ; 4a9ede
21
+ - Revenue operations ; e08a3c
22
+ ---
23
+ # Sales & customer success
24
+
25
+ Keep account facts, buyer intent, commitments and forecast judgement separate.
26
+ Never invent a customer statement or turn missing CRM data into a confident
27
+ pipeline claim. A promised feature, price or date must have an accountable owner.
28
+
29
+ Optimise for durable customer outcomes, not activity counts alone. Surface churn
30
+ risk, handoff gaps, stale stages and conflicting commitments across accounts.
@@ -0,0 +1,37 @@
1
+ ---
2
+ id: software
3
+ order: 10
4
+ name: Software development
5
+ summary: Build, operate and evolve software products and their repositories.
6
+ parcel: a repository or working folder
7
+ source: github|disk
8
+ grows_with: verified changes shipped
9
+ grow_command: git log --since=30.days --oneline | wc -l
10
+ roles:
11
+ - cpto # on by default
12
+ - dev # on by default
13
+ - data-engineer # on by default
14
+ - devops # on by default
15
+ - data # on by default
16
+ - product-design
17
+ - po
18
+ - llm-engineer
19
+ - ai-manager
20
+ - blank
21
+ units:
22
+ - Platform ; 3fb8a0
23
+ - Product ; e08a3c
24
+ - Mobile ; 8f7ae6
25
+ - Data ; 4a9ede
26
+ ---
27
+ # Software development
28
+
29
+ The city coordinates evidence and decisions across repositories. A support
30
+ agent owns the context of its repo; the seat owns direction and the final call.
31
+
32
+ Ask for reproducible code, tests, logs and diffs. Treat a green build as evidence
33
+ for the checks it ran, not proof that the product behaves correctly. Changes to
34
+ public interfaces, schemas, security, costs, analytics or shared UI should reach
35
+ the relevant role even when the code itself still compiles.
36
+
37
+ Repo skills stay in their repos and are invoked by their own runtime.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -u
3
+ # Outside a city runtime the whole plugin stays silent (see the guard).
4
+ . "$(dirname "$0")/solo-en-ciudad.sh"
5
+ ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
6
+ exec python3 "$ROOT/scripts/hook_activity.py" "${1:-}"
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+ # PreToolUse / Edit|Write|MultiEdit — leave a note saying where the digging is.
3
+ #
4
+ # This hook does not publish on the bus. It writes a note on disk and the seat
5
+ # reports it. Repo runtimes receive chaired assignments through their adapter,
6
+ # but never get road credentials or authority to address peers directly.
7
+ #
8
+ # It runs before every edit, so the fast path has to be cheap: one check of the
9
+ # remote and a one-line file.
10
+ set -uo pipefail
11
+ # Outside a city runtime the whole plugin stays silent (see the guard).
12
+ . "$(dirname "$0")/solo-en-ciudad.sh"
13
+ nada() { printf '{}\n'; exit 0; }
14
+
15
+ # One resolver for settings and for "does this repo belong to the city".
16
+ # It used to be a hardcoded organisation name, which meant this hook did nothing
17
+ # at all for anybody who was not that one company.
18
+ . "${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}/scripts/city-env.sh"
19
+ REPO="$(repo_de_la_ciudad)" || nada
20
+
21
+ CITY_SCOPE="$(printf '%s' "${CITY_ADDRESS:-city}" | tr -c 'A-Za-z0-9_.@-' '-')"
22
+ DIR="$CITY_DIR/digging/$CITY_SCOPE"
23
+ mkdir -p "$DIR" 2>/dev/null || nada
24
+
25
+ # The parcel comes from the file being touched, matched against parcels.yml in
26
+ # the data repo. Without that, the house is the whole repo.
27
+ ENTRADA="$(cat)"
28
+ FICHERO="$(sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' <<<"$ENTRADA" | head -1)"
29
+ RAIZ="$(git rev-parse --show-toplevel 2>/dev/null || echo '')"
30
+ REL="${FICHERO#$RAIZ/}"
31
+
32
+ PARCELA="$REPO"
33
+ EQUIPO="${AGENTS_CITY_DATA:-$HOME/agents-city-data}"
34
+ if [ -n "$REL" ] && [ -f "$EQUIPO/parcelas.yml" ]; then
35
+ EN_REPO=0
36
+ while IFS= read -r linea; do
37
+ case "$linea" in
38
+ " $REPO:") EN_REPO=1; continue ;;
39
+ " "[a-zA-Z0-9_.-]*":") EN_REPO=0; continue ;;
40
+ esac
41
+ [ "$EN_REPO" -eq 1 ] || continue
42
+ case "$linea" in *"- ruta:"*) ;; *) continue ;; esac
43
+ RUTA="$(sed -n 's/.*- ruta:[[:space:]]*"\([^"]*\)".*/\1/p' <<<"$linea")"
44
+ [ -z "$RUTA" ] && { PARCELA="$REPO"; break; } # empty path = the whole repo
45
+ # shellcheck disable=SC2254
46
+ case "$REL" in $RUTA) PARCELA="$REPO:$RUTA"; break ;; esac
47
+ done < "$EQUIPO/parcelas.yml"
48
+ fi
49
+
50
+ # El agente no es la persona, y tampoco es el repo: es ESTA ventana. Una persona
51
+ # tiene la del puesto y una por repo, y si trabaja con worktrees, una por
52
+ # worktree — mismo repo, ramas distintas, agentes distintos. Se distinguen por
53
+ # el directorio del worktree y la rama, que es lo que de verdad los separa.
54
+ DIRTRAB="$(basename "$RAIZ")"
55
+ RAMA="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo '')"
56
+ PRINCIPAL="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')"
57
+ [ -z "$PRINCIPAL" ] && PRINCIPAL=main
58
+
59
+ AGENTE="$DIRTRAB"
60
+ if [ -n "$RAMA" ] && [ "$RAMA" != "$PRINCIPAL" ] && [ "$RAMA" != "HEAD" ]; then
61
+ AGENTE="$DIRTRAB@$RAMA"
62
+ fi
63
+
64
+ # Un fichero por agente, no por repo: dos worktrees del mismo repo son dos.
65
+ SEGURO="$(printf '%s' "$AGENTE" | tr -c 'A-Za-z0-9_.@-' '-')"
66
+ printf '{"repo":"%s","parcela":"%s","agente":"%s","rama":"%s","ts":%s}\n' \
67
+ "$REPO" "$PARCELA" "$AGENTE" "$RAMA" "$(date +%s)" > "$DIR/$SEGURO.json"
68
+ nada
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+ # Stop — report how much each parcel has grown, once a day.
3
+ #
4
+ # The city's cron can count merged pull requests on its own. It cannot run a
5
+ # command inside somebody's folders, and in a marketing, legal or finance city
6
+ # that is exactly what growth is: pieces published, matters filed, periods
7
+ # closed. So it has to be reported from where the folders are, and if that means
8
+ # somebody remembering to run a script, the map stops growing in week two.
9
+ #
10
+ # Once every twenty hours, not on every turn: these are real commands in real
11
+ # folders — a find, a wc, sometimes a query — and the number they return does not
12
+ # change by the minute. Detached and silent, like the spend report.
13
+ set -uo pipefail
14
+ # Outside a city runtime the whole plugin stays silent (see the guard).
15
+ . "$(dirname "$0")/solo-en-ciudad.sh"
16
+ nada() { printf '{}\n'; exit 0; }
17
+
18
+ RAIZ="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
19
+ . "$RAIZ/scripts/city-env.sh"
20
+
21
+ [ -n "${AGENTS_CITY_URL:-}" ] || nada
22
+ [ -n "${CITY_BUS_TOKEN:-}" ] || nada
23
+ [ -n "${AGENTS_CITY_DATA:-}" ] || nada
24
+ [ -d "${AGENTS_CITY_DATA:-}" ] || nada
25
+ command -v python3 >/dev/null 2>&1 || nada
26
+
27
+ MARCA="$CITY_DIR/growth-last"
28
+ mkdir -p "$CITY_DIR" 2>/dev/null || nada
29
+ AHORA="$(date +%s)"
30
+ if [ -f "$MARCA" ]; then
31
+ ANTES="$(cat "$MARCA" 2>/dev/null || echo 0)"
32
+ case "$ANTES" in ''|*[!0-9]*) ANTES=0 ;; esac
33
+ [ $((AHORA - ANTES)) -lt 72000 ] && nada
34
+ fi
35
+ printf '%s' "$AHORA" > "$MARCA"
36
+
37
+ ( AGENTS_CITY_URL="$AGENTS_CITY_URL" CITY_BUS_TOKEN="$CITY_BUS_TOKEN" \
38
+ AGENTS_CITY_DATA="$AGENTS_CITY_DATA" \
39
+ python3 "$RAIZ/scripts/report.py" --push --quiet \
40
+ >/dev/null 2>&1 & ) >/dev/null 2>&1
41
+
42
+ nada
@@ -0,0 +1,106 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "Bash",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/notice-on-pr.sh\"",
10
+ "timeout": 10
11
+ }
12
+ ]
13
+ },
14
+ {
15
+ "matcher": "Edit|Write|MultiEdit|NotebookEdit",
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/digging.sh\"",
20
+ "timeout": 5
21
+ }
22
+ ]
23
+ }
24
+ ],
25
+ "SessionStart": [
26
+ {
27
+ "hooks": [
28
+ {
29
+ "type": "command",
30
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/activity.sh\" SessionStart",
31
+ "timeout": 10
32
+ }
33
+ ]
34
+ },
35
+ {
36
+ "hooks": [
37
+ {
38
+ "type": "command",
39
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/notice-pending.sh\"",
40
+ "timeout": 15
41
+ }
42
+ ]
43
+ }
44
+ ],
45
+ "UserPromptSubmit": [
46
+ {
47
+ "hooks": [
48
+ {
49
+ "type": "command",
50
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/activity.sh\" UserPromptSubmit",
51
+ "timeout": 10
52
+ }
53
+ ]
54
+ }
55
+ ],
56
+ "Stop": [
57
+ {
58
+ "hooks": [
59
+ {
60
+ "type": "command",
61
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/activity.sh\" Stop",
62
+ "timeout": 10
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ "hooks": [
68
+ {
69
+ "type": "command",
70
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/notice-on-stop.sh\"",
71
+ "timeout": 10
72
+ }
73
+ ]
74
+ },
75
+ {
76
+ "hooks": [
77
+ {
78
+ "type": "command",
79
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/tokens.sh\"",
80
+ "timeout": 10
81
+ }
82
+ ]
83
+ },
84
+ {
85
+ "hooks": [
86
+ {
87
+ "type": "command",
88
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/growth.sh\"",
89
+ "timeout": 10
90
+ }
91
+ ]
92
+ }
93
+ ],
94
+ "SessionEnd": [
95
+ {
96
+ "hooks": [
97
+ {
98
+ "type": "command",
99
+ "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/activity.sh\" SessionEnd",
100
+ "timeout": 10
101
+ }
102
+ ]
103
+ }
104
+ ]
105
+ }
106
+ }
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ # PreToolUse / Bash — when a PR is opened, hand the question to the agent.
3
+ #
4
+ # The hook matcher cannot filter Bash by the content of the command, so the filter
5
+ # is here and it comes first: if the command does not open a PR, leave. This runs
6
+ # before EVERY shell command, so the fast path has to be cheap.
7
+ #
8
+ # Like the rest of the notice hooks, this judges nothing: it only spots the
9
+ # moment. Which property the change touches, and who it hurts, is the agent's
10
+ # call.
11
+ set -uo pipefail
12
+ # Outside a city runtime the whole plugin stays silent (see the guard).
13
+ . "$(dirname "$0")/solo-en-ciudad.sh"
14
+
15
+ nada() { printf '{}\n'; exit 0; }
16
+
17
+ ENTRADA="$(cat)"
18
+ grep -qE 'gh[[:space:]]+pr[[:space:]]+create' <<<"$ENTRADA" || nada
19
+
20
+ # One resolver for settings and for "does this repo belong to the city".
21
+ # It used to be a hardcoded organisation name, which meant this hook did nothing
22
+ # at all for anybody who was not that one company.
23
+ . "${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}/scripts/city-env.sh"
24
+ REPO="$(repo_de_la_ciudad)" || nada
25
+
26
+ python3 - "$REPO" "${CITY_SEAT_NAME:-seat}" <<'PY'
27
+ import json, sys
28
+ repo, seat = sys.argv[1:3]
29
+ msg = f"""You are opening a PR in {repo}. As soon as it exists, judge whether what it carries touches a domain owned by a connected city, before moving on to anything else: this is the best moment there is, because after the merge it is decided and the destination seat can only ask for a rewrite.
30
+
31
+ Follow /city:notice: compare the PR's diff against the "What reaches you" section of each roles/<role>.md, and work out who owns each property from the cards and the unit map.
32
+
33
+ Two things about this window: it has no roads — repo windows deliberately do not get them — so hand the written notice to the city seat named "{seat}" and let it send. And if there is nothing to send, do not send anything and do not comment on it: silence is the right answer most of the time."""
34
+ print(json.dumps({"hookSpecificOutput": {"hookEventName": "PreToolUse", "additionalContext": msg}}))
35
+ PY
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bash
2
+ # Stop — at the end of a turn where something changed, hand the question to the
3
+ # agent.
4
+ #
5
+ # This hook does NOT decide whether to send a notice. It cannot: whether a change
6
+ # breaks somebody else's property is a judgement, and no pattern is going to get
7
+ # it right. All the code decides is whether there is new material nobody has
8
+ # judged yet — that part is deterministic and cheap. The judgement belongs to the
9
+ # agent, which has the diff and the roles in front of it.
10
+ set -uo pipefail
11
+ # Outside a city runtime the whole plugin stays silent (see the guard).
12
+ . "$(dirname "$0")/solo-en-ciudad.sh"
13
+
14
+ # Silent exit. It returns {} rather than nothing: with empty output, Claude Code
15
+ # logs a "Hook output does not start with {" and a spurious error.
16
+ nada() { printf '{}\n'; exit 0; }
17
+
18
+ ENTRADA="$(cat)"
19
+
20
+ # stop_hook_active arrives true when this hook already forced a continuation.
21
+ # Without this exit, infinite loop.
22
+ if grep -q '"stop_hook_active"[[:space:]]*:[[:space:]]*true' <<<"$ENTRADA"; then
23
+ nada
24
+ fi
25
+
26
+ # One resolver for settings and for "does this repo belong to the city".
27
+ # It used to be a hardcoded organisation name, which meant this hook did nothing
28
+ # at all for anybody who was not that one company.
29
+ . "${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}/scripts/city-env.sh"
30
+ REPO="$(repo_de_la_ciudad)" || nada
31
+
32
+ HEAD_SHA="$(git rev-parse HEAD 2>/dev/null || true)"
33
+ [ -z "$HEAD_SHA" ] && nada
34
+
35
+ # The fingerprint includes the CONTENT of the change, not just which files are
36
+ # touched: `git status --porcelain` returns the same thing the first time you edit
37
+ # a file and the fifth, so the second change — which may be the dangerous one —
38
+ # would never be judged.
39
+ SUCIO="$( { git status --porcelain 2>/dev/null
40
+ git diff HEAD 2>/dev/null
41
+ # Y el contenido de los ficheros nuevos, que no salen en el diff.
42
+ # Acotado a 200: esto corre al final de cada turno y no puede costar.
43
+ git ls-files --others --exclude-standard 2>/dev/null | head -200 \
44
+ | tr '\n' '\0' | xargs -0 shasum -a 256 2>/dev/null
45
+ } | shasum -a 256 | cut -d' ' -f1)"
46
+ HUELLA="$HEAD_SHA:$SUCIO"
47
+
48
+ CITY_SCOPE="$(printf '%s' "${CITY_ADDRESS:-city}" | tr -c 'A-Za-z0-9_.@-' '-')"
49
+ DIR="$CITY_DIR/notices-judged/$CITY_SCOPE"
50
+ mkdir -p "$DIR" 2>/dev/null || nada
51
+ MARCA="$DIR/$REPO"
52
+
53
+ # This exact state has already been asked about.
54
+ if [ -f "$MARCA" ] && [ "$(cat "$MARCA")" = "$HUELLA" ]; then
55
+ nada
56
+ fi
57
+
58
+ # First time in this repo: take note and do not interrupt. Otherwise the first
59
+ # session in any repo would open with a question nobody asked for.
60
+ if [ ! -f "$MARCA" ]; then
61
+ printf '%s\n' "$HUELLA" > "$MARCA"
62
+ nada
63
+ fi
64
+
65
+ printf '%s\n' "$HUELLA" > "$MARCA"
66
+
67
+ python3 - "$REPO" "${CITY_SEAT_NAME:-seat}" <<'PY'
68
+ import json, sys
69
+ repo, seat = sys.argv[1:3]
70
+ razon = f"""Before you finish: you changed things in {repo}, and nobody has judged yet whether they touch another role's property.
71
+
72
+ Judge it yourself — you have the diff in front of you, and no pattern can decide this. Compare what you changed against the "What reaches you" section of each roles/<role>.md, and against the unit map to work out whose it is when a property has more than one owner.
73
+
74
+ Almost always the right answer is that there is nothing to send. If so, say it in one line and finish.
75
+
76
+ If there is something: write it the way /city:notice says — [property] first, evidence with file and line, why it reaches them, what to look at, and that it does not block — and hand it to the city seat named "{seat}", which is the one with the roads. This window does not have them, on purpose.
77
+
78
+ When in doubt, do not send one — except for anything about measurement (analytics, tags, pixels, consent, URLs, schemas, events): there, when in doubt, send it. It is the one property where arriving late cannot be fixed afterwards."""
79
+ print(json.dumps({"decision": "block", "reason": razon}))
80
+ PY
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ # SessionStart — catches what the other two triggers could not see.
3
+ #
4
+ # A PR opened from GitHub's web UI, or commits that arrived through a pull, never
5
+ # pass through a command in this session. So when the repo window opens, look for
6
+ # commits nobody has reviewed since the last pass.
7
+ #
8
+ # The FIRST time in a repo it says nothing and only leaves the mark. Otherwise
9
+ # the first session in a repo with two years of history sets off an avalanche.
10
+ set -uo pipefail
11
+ # Outside a city runtime the whole plugin stays silent (see the guard).
12
+ . "$(dirname "$0")/solo-en-ciudad.sh"
13
+
14
+ nada() { printf '{}\n'; exit 0; }
15
+
16
+ # One resolver for settings and for "does this repo belong to the city".
17
+ # It used to be a hardcoded organisation name, which meant this hook did nothing
18
+ # at all for anybody who was not that one company.
19
+ . "${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}/scripts/city-env.sh"
20
+ REPO="$(repo_de_la_ciudad)" || nada
21
+
22
+ CITY_SCOPE="$(printf '%s' "${CITY_ADDRESS:-city}" | tr -c 'A-Za-z0-9_.@-' '-')"
23
+ DIR="$CITY_DIR/notices-seen/$CITY_SCOPE"
24
+ mkdir -p "$DIR" 2>/dev/null || nada
25
+ MARCA="$DIR/$REPO"
26
+ HEAD_SHA="$(git rev-parse HEAD 2>/dev/null || true)"
27
+ [ -z "$HEAD_SHA" ] && nada
28
+
29
+ if [ ! -f "$MARCA" ]; then
30
+ printf '%s\n' "$HEAD_SHA" > "$MARCA"
31
+ nada
32
+ fi
33
+
34
+ VISTO="$(cat "$MARCA")"
35
+ [ "$VISTO" = "$HEAD_SHA" ] && nada
36
+ if ! git cat-file -e "$VISTO" 2>/dev/null; then
37
+ printf '%s\n' "$HEAD_SHA" > "$MARCA"
38
+ nada
39
+ fi
40
+
41
+ # First-parent and no merges: in a repo with many merges, counting everything
42
+ # gives absurd figures — 85 commits for five real ones.
43
+ N="$(git rev-list --count --first-parent --no-merges "$VISTO..HEAD" 2>/dev/null || echo 0)"
44
+ [ "$N" -eq 0 ] && nada
45
+
46
+ python3 - "$REPO" "$VISTO" "$N" "$MARCA" "$HEAD_SHA" "${CITY_SEAT_NAME:-seat}" <<'PY'
47
+ import json, sys
48
+ repo, visto, n, marca, head, seat = sys.argv[1:7]
49
+ msg = f"""In {repo} there are {n} commit(s) nobody has reviewed since {visto[:8]}.
50
+
51
+ Before starting on whatever this session brings, judge whether any of them touch another role's property: look at {visto[:8]}..HEAD and follow /city:notice. No pattern can decide this; it has to be read.
52
+
53
+ If something does, write the notice and hand it to the city seat named "{seat}", which is the one with the roads. If nothing does, do not send anything and do not comment on it.
54
+
55
+ When you are done, bring the mark up to date so the pass is not repeated:
56
+ echo {head} > {marca}"""
57
+ print(json.dumps({"hookSpecificOutput": {"hookEventName": "SessionStart", "additionalContext": msg}}))
58
+ PY
@@ -0,0 +1,23 @@
1
+ # shellcheck shell=bash
2
+ # Sourced first by every hook: the plugin's conscience runs only inside a city.
3
+ #
4
+ # Installing the plugin must not enrol every Claude conversation on the machine.
5
+ # A city runtime always carries its actor identity in the environment —
6
+ # CITY_BUS_ACTOR, set by city-session.sh for the seat and every repo window — and
7
+ # a plain session carries none, so that is the gate. Outside a city every hook
8
+ # answers `{}` and leaves: no passes, no digging notes, no judgements, no counters.
9
+ #
10
+ # Somebody who WANTS the old machine-wide conscience sets CITY_HOOKS=everywhere,
11
+ # in the environment or in $CITY_DIR/.env. It is an explicit choice, never the
12
+ # default: second-order effects should be opted into, not discovered.
13
+ _CITY_DIR="${CITY_DIR:-$HOME/.claude/channels/city-bus}"
14
+ _ambito="${CITY_HOOKS:-}"
15
+ if [ -z "$_ambito" ] && [ -f "$_CITY_DIR/.env" ]; then
16
+ _ambito="$(sed -n 's/^CITY_HOOKS=//p' "$_CITY_DIR/.env" | head -1)"
17
+ _ambito="${_ambito%\"}"; _ambito="${_ambito#\"}"
18
+ fi
19
+ if [ "$_ambito" != "everywhere" ] && [ -z "${CITY_BUS_ACTOR:-}" ]; then
20
+ # `{}` rather than nothing: empty hook output logs a spurious error upstream.
21
+ printf '{}\n'
22
+ exit 0
23
+ fi
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ # Stop — report what this machine has spent on tokens, at most twice an hour.
3
+ #
4
+ # The counter on the map is global: everybody's spend, one number, no ranking.
5
+ # For that number to mean anything it has to arrive on its own — a reporter you
6
+ # have to remember to run is a reporter that runs once, the day it is written,
7
+ # and then the map quietly starts lying about the cost of the whole thing.
8
+ #
9
+ # What leaves the machine: a day, a model name, and four counts. Never a prompt,
10
+ # never a file name, never a project path. The reporter reads the transcripts
11
+ # Claude Code already writes; nothing new is recorded to make this work.
12
+ #
13
+ # Three rules, because this runs at the end of every turn:
14
+ # - Throttled. Twice an hour is plenty for a number shown per day.
15
+ # - Detached. The turn does not wait for a network call.
16
+ # - Silent. A spend report is not worth a word in somebody's terminal, and it
17
+ # is certainly not worth an error there.
18
+ set -uo pipefail
19
+ # Outside a city runtime the whole plugin stays silent (see the guard).
20
+ . "$(dirname "$0")/solo-en-ciudad.sh"
21
+ nada() { printf '{}\n'; exit 0; }
22
+
23
+ RAIZ="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
24
+ . "$RAIZ/scripts/city-env.sh"
25
+
26
+ # Nothing to report to, or nothing to report with: this seat is not on a map.
27
+ [ -n "${AGENTS_CITY_URL:-}" ] || nada
28
+ [ -n "${CITY_BUS_TOKEN:-}" ] || nada
29
+ command -v python3 >/dev/null 2>&1 || nada
30
+
31
+ MARCA="$CITY_DIR/tokens-last"
32
+ mkdir -p "$CITY_DIR" 2>/dev/null || nada
33
+ AHORA="$(date +%s)"
34
+ if [ -f "$MARCA" ]; then
35
+ ANTES="$(cat "$MARCA" 2>/dev/null || echo 0)"
36
+ case "$ANTES" in ''|*[!0-9]*) ANTES=0 ;; esac
37
+ [ $((AHORA - ANTES)) -lt 1800 ] && nada
38
+ fi
39
+ printf '%s' "$AHORA" > "$MARCA"
40
+
41
+ # Detached, output discarded. Whatever happens out there is not this turn's
42
+ # problem; the next run picks up whatever this one failed to send.
43
+ ( AGENTS_CITY_URL="$AGENTS_CITY_URL" CITY_BUS_TOKEN="$CITY_BUS_TOKEN" \
44
+ python3 "$RAIZ/scripts/tokens.py" --push --quiet --days 30 \
45
+ >/dev/null 2>&1 & ) >/dev/null 2>&1
46
+
47
+ nada
@@ -0,0 +1,25 @@
1
+ ---
2
+ role: account-executive
3
+ trade: Master builder
4
+ cross_cutting: false
5
+ ---
6
+
7
+ ## Domain
8
+
9
+ The opportunities and accounts you carry: buyer context, objections, decisions
10
+ and commitments made.
11
+
12
+ ## What you ask others
13
+
14
+ - Whether a proposed promise is approved and deliverable.
15
+ - Which customer evidence is current and directly observed.
16
+ - Who owns the next dependency outside the account.
17
+
18
+ ## What reaches you
19
+
20
+ A product, price, delivery or policy change affecting one of your opportunities.
21
+
22
+ ## What you can answer
23
+
24
+ What the customer actually said, what remains inferred and why the opportunity is
25
+ in its current state.
@@ -0,0 +1,34 @@
1
+ ---
2
+ role: ai-manager
3
+ trade: Works inspector
4
+ cross_cutting: true
5
+ ---
6
+
7
+ ## Domain
8
+
9
+ The portfolio of AI initiatives: what is being built, where it overlaps, what
10
+ actually gets adopted, and what the whole thing costs.
11
+
12
+ In the city you are the **works inspector**. You walk every site: what is being
13
+ built twice, what got built and nobody uses, and what the total costs.
14
+
15
+ ## What you ask others
16
+
17
+ - What is being automated with AI in each repo, and in what state.
18
+ - Overlaps: two teams solving the same thing separately.
19
+ - What was built and nobody uses.
20
+ - Aggregate cost, and which initiative it comes from.
21
+ - What it would take for something working in one place to serve another.
22
+
23
+ ## What reaches you
24
+
25
+ - A new AI initiative in a repo.
26
+ - Something starting to be built that already exists solved elsewhere.
27
+
28
+ The rest of your domain — adoption, aggregate cost, overlaps — does not show up
29
+ in a commit: that comes out in rounds, not in notices.
30
+
31
+ ## What you can answer
32
+
33
+ What already exists in the house before they build something new, and who they
34
+ should talk to.
@@ -0,0 +1,24 @@
1
+ ---
2
+ role: associate
3
+ trade: Master builder
4
+ cross_cutting: false
5
+ ---
6
+
7
+ ## Domain
8
+
9
+ The matters you carry. You know their history, what was argued, what was conceded, and what is deliberately not in writing.
10
+
11
+ ## What you ask others
12
+
13
+ - Whether a change to a shared template affects your matters.
14
+ - Who else is acting for the same client.
15
+ - Whether a precedent for this already exists in the firm.
16
+
17
+ ## What reaches you
18
+
19
+ - A shared template or clause library changing.
20
+ - A deadline moving on a matter you carry.
21
+
22
+ ## What you can answer
23
+
24
+ The state of your matters, what is deliberate, and what risk you have taken on knowingly. With the file open, not from memory.