apsimo 1.3.0__py3-none-any.whl

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 (614) hide show
  1. apsimo/__init__.py +38 -0
  2. apsimo/__main__.py +6 -0
  3. apsimo/agent/__init__.py +6 -0
  4. apsimo/agent/client.py +276 -0
  5. apsimo/agent/models.py +46 -0
  6. apsimo/agents/__init__.py +20 -0
  7. apsimo/agents/models.py +264 -0
  8. apsimo/agents/store.py +861 -0
  9. apsimo/agents/websocket.py +522 -0
  10. apsimo/api/__init__.py +1 -0
  11. apsimo/api/auth_telemetry.py +287 -0
  12. apsimo/api/authority.py +1203 -0
  13. apsimo/api/contact_grants.py +347 -0
  14. apsimo/api/middleware.py +483 -0
  15. apsimo/api/routers/__init__.py +1 -0
  16. apsimo/api/routers/commitment_work.py +265 -0
  17. apsimo/api/routers/context_gate.py +123 -0
  18. apsimo/api/routers/executions.py +140 -0
  19. apsimo/api/routers/followup_plans.py +147 -0
  20. apsimo/api/routers/governed_actions.py +162 -0
  21. apsimo/api/routers/host.py +14473 -0
  22. apsimo/api/routers/initiative_work.py +115 -0
  23. apsimo/api/routers/mining.py +104 -0
  24. apsimo/api/routers/observations.py +110 -0
  25. apsimo/api/routers/social_state.py +225 -0
  26. apsimo/api/routers/task_queue.py +2715 -0
  27. apsimo/api/routers/temporal_followups.py +251 -0
  28. apsimo/api/routers/transport.py +110 -0
  29. apsimo/api/routers/transport_ingress_api.py +240 -0
  30. apsimo/api/schemas/__init__.py +1 -0
  31. apsimo/api/schemas/host.py +1949 -0
  32. apsimo/autonomy/cli.py +110 -0
  33. apsimo/autonomy/condition_worker.py +437 -0
  34. apsimo/autonomy/config.py +424 -0
  35. apsimo/autonomy/loop.py +4316 -0
  36. apsimo/autonomy/registry.py +339 -0
  37. apsimo/autonomy/scheduler.py +1822 -0
  38. apsimo/autonomy/synthesis.py +449 -0
  39. apsimo/backup.py +962 -0
  40. apsimo/beliefs/__init__.py +23 -0
  41. apsimo/beliefs/contradictions.py +109 -0
  42. apsimo/beliefs/decay.py +61 -0
  43. apsimo/beliefs/engine.py +479 -0
  44. apsimo/beliefs/models.py +67 -0
  45. apsimo/beliefs/promotion.py +41 -0
  46. apsimo/beliefs/resolve.py +58 -0
  47. apsimo/beliefs/source_claims.py +690 -0
  48. apsimo/beliefs/source_projection.py +883 -0
  49. apsimo/beliefs/source_time.py +208 -0
  50. apsimo/beliefs/store.py +133 -0
  51. apsimo/briefings/aggregators.py +824 -0
  52. apsimo/briefings/composer.py +420 -0
  53. apsimo/briefings/config.py +55 -0
  54. apsimo/briefings/delivery.py +439 -0
  55. apsimo/briefings/engagement.py +97 -0
  56. apsimo/briefings/engine.py +274 -0
  57. apsimo/briefings/enhancer.py +99 -0
  58. apsimo/briefings/models.py +183 -0
  59. apsimo/briefings/scheduler.py +382 -0
  60. apsimo/briefings/store.py +435 -0
  61. apsimo/chain/__init__.py +48 -0
  62. apsimo/chain/block.py +100 -0
  63. apsimo/chain/cli.py +704 -0
  64. apsimo/chain/genesis.py +443 -0
  65. apsimo/chain/identity.py +416 -0
  66. apsimo/chain/keys.py +1025 -0
  67. apsimo/chain/local_keys.py +187 -0
  68. apsimo/chain/manager.py +290 -0
  69. apsimo/chain/node.py +163 -0
  70. apsimo/chain/plugin_transactions.py +371 -0
  71. apsimo/chain/protocol.py +220 -0
  72. apsimo/chain/state_machine.py +676 -0
  73. apsimo/chain/storage.py +503 -0
  74. apsimo/chain/transactions.py +250 -0
  75. apsimo/chain/validation.py +397 -0
  76. apsimo/channels/__init__.py +1 -0
  77. apsimo/channels/manifest.py +31 -0
  78. apsimo/channels/migrations/001_channels_schema.sql +12 -0
  79. apsimo/channels/phone_gateways.py +42 -0
  80. apsimo/channels/presence.py +188 -0
  81. apsimo/channels/router.py +235 -0
  82. apsimo/channels/store.py +231 -0
  83. apsimo/cli.py +2688 -0
  84. apsimo/cognition/__init__.py +11 -0
  85. apsimo/cognition/charter.py +398 -0
  86. apsimo/cognition/drive_governance.py +3530 -0
  87. apsimo/cognition/evidence_pipeline.py +1627 -0
  88. apsimo/cognition/external_events.py +932 -0
  89. apsimo/cognition/goal_spine.py +3488 -0
  90. apsimo/cognition/introspection.py +214 -0
  91. apsimo/cognition/prompt.py +150 -0
  92. apsimo/cognition/runtime.py +108 -0
  93. apsimo/cognition/trigger.py +154 -0
  94. apsimo/commitments/__init__.py +18 -0
  95. apsimo/commitments/local_work.py +355 -0
  96. apsimo/commitments/store.py +1052 -0
  97. apsimo/commitments/work.py +91 -0
  98. apsimo/compat.py +53 -0
  99. apsimo/compression/__init__.py +467 -0
  100. apsimo/connectors/__init__.py +21 -0
  101. apsimo/connectors/base.py +152 -0
  102. apsimo/connectors/caldav_calendar.py +125 -0
  103. apsimo/connectors/fs_documents.py +85 -0
  104. apsimo/connectors/imap_email.py +138 -0
  105. apsimo/connectors/manager.py +218 -0
  106. apsimo/connectors/webhook_pull.py +88 -0
  107. apsimo/contacts/__init__.py +33 -0
  108. apsimo/contacts/comms.py +357 -0
  109. apsimo/contacts/config.py +79 -0
  110. apsimo/contacts/exporters/__init__.py +1 -0
  111. apsimo/contacts/exporters/vcard.py +71 -0
  112. apsimo/contacts/identity_links.py +251 -0
  113. apsimo/contacts/importer.py +280 -0
  114. apsimo/contacts/importers/__init__.py +1 -0
  115. apsimo/contacts/importers/batch.py +43 -0
  116. apsimo/contacts/importers/macos_contacts.py +101 -0
  117. apsimo/contacts/migrations/001_contacts_schema.sql +141 -0
  118. apsimo/contacts/migrations/002_trust_scopes.sql +36 -0
  119. apsimo/contacts/migrations/003_open_gateway_enum.sql +32 -0
  120. apsimo/contacts/migrations/004_contact_provision_operations.sql +18 -0
  121. apsimo/contacts/migrations/005_identity_links.sql +27 -0
  122. apsimo/contacts/models.py +308 -0
  123. apsimo/contacts/scoring.py +16 -0
  124. apsimo/contacts/store.py +1623 -0
  125. apsimo/contacts/transport_ingress.py +252 -0
  126. apsimo/contacts/world_bridge.py +314 -0
  127. apsimo/contextgate/__init__.py +69 -0
  128. apsimo/contextgate/chunker.py +169 -0
  129. apsimo/contextgate/estimate.py +54 -0
  130. apsimo/contextgate/gate.py +313 -0
  131. apsimo/contextgate/retrieve.py +115 -0
  132. apsimo/delivery/__init__.py +16 -0
  133. apsimo/delivery/bridge.py +1260 -0
  134. apsimo/delivery/channels.py +526 -0
  135. apsimo/delivery/classification.py +50 -0
  136. apsimo/delivery/rate_limiter.py +268 -0
  137. apsimo/delivery/reachout_policy.py +206 -0
  138. apsimo/directed/__init__.py +22 -0
  139. apsimo/directed/audit.py +167 -0
  140. apsimo/directed/intake.py +95 -0
  141. apsimo/directed/models.py +191 -0
  142. apsimo/directed/service.py +509 -0
  143. apsimo/directives/__init__.py +25 -0
  144. apsimo/directives/evidence.py +87 -0
  145. apsimo/directives/extractor.py +188 -0
  146. apsimo/directives/guard.py +364 -0
  147. apsimo/directives/models.py +206 -0
  148. apsimo/directives/service.py +372 -0
  149. apsimo/directives/store.py +167 -0
  150. apsimo/doctor.py +2173 -0
  151. apsimo/environment.py +43 -0
  152. apsimo/events/__init__.py +33 -0
  153. apsimo/events/broadcaster.py +98 -0
  154. apsimo/events/bus.py +217 -0
  155. apsimo/events/journal.py +863 -0
  156. apsimo/events/stream.py +131 -0
  157. apsimo/events/types.py +150 -0
  158. apsimo/execution_results.py +357 -0
  159. apsimo/feedback/__init__.py +5 -0
  160. apsimo/feedback/store.py +76 -0
  161. apsimo/feeds/__init__.py +19 -0
  162. apsimo/feeds/cli.py +84 -0
  163. apsimo/feeds/engine.py +437 -0
  164. apsimo/feeds/example-feed.yaml +77 -0
  165. apsimo/feeds/hermes_cron.py +126 -0
  166. apsimo/feeds/manager.py +235 -0
  167. apsimo/feeds/spec.py +250 -0
  168. apsimo/feeds/template.py +202 -0
  169. apsimo/gate/__init__.py +18 -0
  170. apsimo/gate/audit.py +61 -0
  171. apsimo/gate/communication_policy.py +166 -0
  172. apsimo/gate/config.py +72 -0
  173. apsimo/gate/context_provenance.py +170 -0
  174. apsimo/gate/env_risk.py +226 -0
  175. apsimo/gate/guard_audit.py +353 -0
  176. apsimo/gate/layers/__init__.py +1 -0
  177. apsimo/gate/layers/base.py +15 -0
  178. apsimo/gate/layers/l1_recipient.py +66 -0
  179. apsimo/gate/layers/l2_pii.py +134 -0
  180. apsimo/gate/layers/l3_cross_context.py +50 -0
  181. apsimo/gate/layers/l4_trust_tier.py +78 -0
  182. apsimo/gate/layers/l5_injection.py +199 -0
  183. apsimo/gate/layers/l6_review.py +86 -0
  184. apsimo/gate/layers/l7_delay.py +100 -0
  185. apsimo/gate/layers/tom2_epistemic.py +185 -0
  186. apsimo/gate/models.py +64 -0
  187. apsimo/gate/pending_dispatch.py +5 -0
  188. apsimo/gate/pipeline.py +206 -0
  189. apsimo/gate/rejection.py +259 -0
  190. apsimo/gate/response_guard.py +700 -0
  191. apsimo/gate/rulesets/injection_v1.yaml +51 -0
  192. apsimo/gate/surface_policy.py +189 -0
  193. apsimo/gate/taint.py +226 -0
  194. apsimo/genesis.json +9 -0
  195. apsimo/goals/__init__.py +100 -0
  196. apsimo/goals/config.py +38 -0
  197. apsimo/goals/decomposer.py +421 -0
  198. apsimo/goals/engine.py +617 -0
  199. apsimo/goals/inference.py +354 -0
  200. apsimo/goals/models.py +302 -0
  201. apsimo/goals/priority.py +270 -0
  202. apsimo/goals/queue_bridge.py +149 -0
  203. apsimo/goals/replan.py +450 -0
  204. apsimo/goals/schema.sql +89 -0
  205. apsimo/goals/store.py +692 -0
  206. apsimo/governed_actions.py +1708 -0
  207. apsimo/harness_integration/__init__.py +45 -0
  208. apsimo/harness_integration/context.py +41 -0
  209. apsimo/harness_integration/skills.py +231 -0
  210. apsimo/identity/__init__.py +26 -0
  211. apsimo/identity/participants.py +181 -0
  212. apsimo/identity/resolver.py +329 -0
  213. apsimo/identity_bootstrap/__init__.py +5 -0
  214. apsimo/identity_bootstrap/builder.py +208 -0
  215. apsimo/identity_bootstrap/corpus.py +443 -0
  216. apsimo/identity_bootstrap/models.py +54 -0
  217. apsimo/identity_bootstrap/runner.py +353 -0
  218. apsimo/identity_bootstrap/seeders/__init__.py +25 -0
  219. apsimo/identity_bootstrap/seeders/briefings.py +109 -0
  220. apsimo/identity_bootstrap/seeders/chain.py +57 -0
  221. apsimo/identity_bootstrap/seeders/goals.py +128 -0
  222. apsimo/identity_bootstrap/seeders/memory.py +191 -0
  223. apsimo/identity_bootstrap/seeders/neo4j_cognition.py +79 -0
  224. apsimo/identity_bootstrap/seeders/relationship.py +152 -0
  225. apsimo/identity_bootstrap/seeders/sessions.py +67 -0
  226. apsimo/identity_bootstrap/seeders/skills.py +92 -0
  227. apsimo/identity_bootstrap/seeders/task_queue.py +72 -0
  228. apsimo/identity_bootstrap/seeders/world_model.py +143 -0
  229. apsimo/identity_bootstrap/self_query.py +92 -0
  230. apsimo/identity_bootstrap/self_reflection.py +155 -0
  231. apsimo/identity_bootstrap/skill.py +37 -0
  232. apsimo/identity_bootstrap/verifier.py +436 -0
  233. apsimo/initiatives/__init__.py +20 -0
  234. apsimo/initiatives/action_registry.py +454 -0
  235. apsimo/initiatives/approval_authority.py +2105 -0
  236. apsimo/initiatives/approval_policy.py +123 -0
  237. apsimo/initiatives/assignment.py +263 -0
  238. apsimo/initiatives/backup_evidence.py +100 -0
  239. apsimo/initiatives/context_freshness.py +103 -0
  240. apsimo/initiatives/models.py +318 -0
  241. apsimo/initiatives/native_work.py +270 -0
  242. apsimo/initiatives/standing_approvals.py +232 -0
  243. apsimo/initiatives/store.py +1081 -0
  244. apsimo/initiatives/temporal_followup.py +410 -0
  245. apsimo/intelligence/__init__.py +1 -0
  246. apsimo/intelligence/cognition/__init__.py +24 -0
  247. apsimo/intelligence/cognition/gap_detector.py +148 -0
  248. apsimo/intelligence/cognition/metalearner.py +547 -0
  249. apsimo/intelligence/cognition/metrics_collector.py +217 -0
  250. apsimo/intelligence/cognition/performance_index.py +299 -0
  251. apsimo/intelligence/cognition/registry.py +192 -0
  252. apsimo/intelligence/cognition/strategy_adjuster.py +222 -0
  253. apsimo/intelligence/cognition/types.py +16 -0
  254. apsimo/intelligence/components/__init__.py +66 -0
  255. apsimo/intelligence/components/anomaly_detector.py +413 -0
  256. apsimo/intelligence/components/initiative_engine.py +2643 -0
  257. apsimo/intelligence/components/preference_learner.py +521 -0
  258. apsimo/intelligence/components/research_orchestrator.py +358 -0
  259. apsimo/intelligence/components/self_directed_thinker.py +221 -0
  260. apsimo/intelligence/components/self_reflector.py +252 -0
  261. apsimo/intelligence/components/session_continuity.py +154 -0
  262. apsimo/intelligence/components/task_planner.py +320 -0
  263. apsimo/intelligence/components/tool_learner.py +217 -0
  264. apsimo/intelligence/graph/__init__.py +79 -0
  265. apsimo/intelligence/graph/client.py +2483 -0
  266. apsimo/intelligence/graph/consolidator.py +405 -0
  267. apsimo/intelligence/graph/distiller.py +312 -0
  268. apsimo/intelligence/graph/migrations.py +129 -0
  269. apsimo/intelligence/graph/queries.py +248 -0
  270. apsimo/intelligence/graph/recall.py +281 -0
  271. apsimo/intelligence/graph/reconciler.py +144 -0
  272. apsimo/intelligence/graph/schema.py +337 -0
  273. apsimo/intelligence/graph/selection.py +252 -0
  274. apsimo/intelligence/learning/__init__.py +17 -0
  275. apsimo/intelligence/learning/continuous_learner.py +245 -0
  276. apsimo/intelligence/learning/feedback_store.py +321 -0
  277. apsimo/intelligence/mind_model/__init__.py +1 -0
  278. apsimo/intelligence/mind_model/graph_baseline.py +136 -0
  279. apsimo/intelligence/mind_model/signal_collector.py +361 -0
  280. apsimo/intelligence/relationships/__init__.py +11 -0
  281. apsimo/intelligence/relationships/profiler.py +389 -0
  282. apsimo/intelligence/relationships/scorer.py +560 -0
  283. apsimo/intelligence/relationships/signal_floor.py +66 -0
  284. apsimo/intelligence/relationships/trust_tiers.py +300 -0
  285. apsimo/intelligence/synthesis/__init__.py +40 -0
  286. apsimo/intelligence/synthesis/connection_discoverer.py +379 -0
  287. apsimo/intelligence/synthesis/cross_domain_analyzer.py +287 -0
  288. apsimo/intelligence/synthesis/insight_deliverer.py +171 -0
  289. apsimo/intelligence/synthesis/insight_store.py +79 -0
  290. apsimo/intelligence/synthesis/insight_validator.py +183 -0
  291. apsimo/intelligence/synthesis/novelty_scorer.py +267 -0
  292. apsimo/intelligence/turn_middleware/__init__.py +15 -0
  293. apsimo/intelligence/turn_middleware/memory_sync.py +119 -0
  294. apsimo/mcp/__init__.py +41 -0
  295. apsimo/mcp/__main__.py +6 -0
  296. apsimo/mcp/config.py +287 -0
  297. apsimo/mcp/server.py +501 -0
  298. apsimo/migrations.py +187 -0
  299. apsimo/mining/__init__.py +27 -0
  300. apsimo/mining/corpus.py +239 -0
  301. apsimo/mining/escalations.py +289 -0
  302. apsimo/mining/models.py +169 -0
  303. apsimo/mining/store.py +210 -0
  304. apsimo/models/__init__.py +30 -0
  305. apsimo/models/memory.py +80 -0
  306. apsimo/models/mesh.py +72 -0
  307. apsimo/models/person.py +104 -0
  308. apsimo/models/signal.py +108 -0
  309. apsimo/observations/__init__.py +15 -0
  310. apsimo/observations/store.py +277 -0
  311. apsimo/patterns/__init__.py +6 -0
  312. apsimo/patterns/extract.py +187 -0
  313. apsimo/patterns/store.py +227 -0
  314. apsimo/persona/__init__.py +1 -0
  315. apsimo/persona/engine.py +611 -0
  316. apsimo/persona/manifest.py +140 -0
  317. apsimo/projects/__init__.py +28 -0
  318. apsimo/projects/engine.py +1681 -0
  319. apsimo/projects/event_outbox.py +188 -0
  320. apsimo/projects/models.py +216 -0
  321. apsimo/projects/planner.py +181 -0
  322. apsimo/projects/store.py +1446 -0
  323. apsimo/proposals/__init__.py +12 -0
  324. apsimo/proposals/engine.py +114 -0
  325. apsimo/proposals/models.py +207 -0
  326. apsimo/qualification/__init__.py +1 -0
  327. apsimo/qualification/cases.py +75 -0
  328. apsimo/qualification/cli.py +51 -0
  329. apsimo/qualification/memory_cases.py +209 -0
  330. apsimo/qualification/records.py +92 -0
  331. apsimo/qualification/report.py +87 -0
  332. apsimo/qualification/runner.py +311 -0
  333. apsimo/qualification/structured_cases.py +131 -0
  334. apsimo/reasoning/__init__.py +13 -0
  335. apsimo/reasoning/executor.py +506 -0
  336. apsimo/reasoning/loop.py +373 -0
  337. apsimo/reasoning/native_tools/__init__.py +16 -0
  338. apsimo/reasoning/native_tools/calculate.py +141 -0
  339. apsimo/reasoning/native_tools/file_ops.py +150 -0
  340. apsimo/reasoning/native_tools/web_search.py +49 -0
  341. apsimo/reasoning/tool_policy.py +182 -0
  342. apsimo/redact/__init__.py +176 -0
  343. apsimo/repos/__init__.py +5 -0
  344. apsimo/repos/mirrors.py +204 -0
  345. apsimo/research/__init__.py +41 -0
  346. apsimo/research/artifact.py +482 -0
  347. apsimo/research/gatherer.py +387 -0
  348. apsimo/research/pipeline.py +513 -0
  349. apsimo/research/search/__init__.py +7 -0
  350. apsimo/research/search/base.py +41 -0
  351. apsimo/research/search/brave.py +59 -0
  352. apsimo/research/search/cache.py +51 -0
  353. apsimo/research/search/duckduckgo.py +103 -0
  354. apsimo/research/search/orchestrator.py +119 -0
  355. apsimo/research/search/serpapi.py +59 -0
  356. apsimo/research/search/tavily.py +59 -0
  357. apsimo/research/synthesizer.py +309 -0
  358. apsimo/router/__init__.py +30 -0
  359. apsimo/router/complexity_scorer.py +148 -0
  360. apsimo/router/endpoints.py +153 -0
  361. apsimo/router/fallback.py +58 -0
  362. apsimo/router/functions.py +243 -0
  363. apsimo/router/native_policy.py +52 -0
  364. apsimo/router/router.py +762 -0
  365. apsimo/router/self_learning.py +174 -0
  366. apsimo/router/tiers.py +677 -0
  367. apsimo/sandbox/__init__.py +21 -0
  368. apsimo/sandbox/backend.py +195 -0
  369. apsimo/sandbox/manager.py +173 -0
  370. apsimo/scope_bounds.py +7 -0
  371. apsimo/secrets/__init__.py +6 -0
  372. apsimo/secrets/backends/__init__.py +8 -0
  373. apsimo/secrets/backends/base.py +42 -0
  374. apsimo/secrets/backends/env.py +110 -0
  375. apsimo/secrets/backends/keyring.py +72 -0
  376. apsimo/secrets/backends/onepassword.py +232 -0
  377. apsimo/secrets/cli.py +191 -0
  378. apsimo/secrets/manager.py +160 -0
  379. apsimo/secrets/migration.py +101 -0
  380. apsimo/secrets/types.py +98 -0
  381. apsimo/seed.py +41 -0
  382. apsimo/self_model/__init__.py +37 -0
  383. apsimo/self_model/appraisals.py +673 -0
  384. apsimo/self_model/benchmark.py +1314 -0
  385. apsimo/self_model/brief.py +40 -0
  386. apsimo/self_model/event_concerns.py +1128 -0
  387. apsimo/self_model/execution_forecasts.py +353 -0
  388. apsimo/self_model/expectations.py +1595 -0
  389. apsimo/self_model/experiments.py +1150 -0
  390. apsimo/self_model/journal.py +148 -0
  391. apsimo/self_model/judgments.py +705 -0
  392. apsimo/self_model/native_outcomes.py +55 -0
  393. apsimo/self_model/params.py +220 -0
  394. apsimo/self_model/perspective.py +246 -0
  395. apsimo/self_model/reconcile.py +183 -0
  396. apsimo/self_model/reply_forecasts.py +381 -0
  397. apsimo/self_model/runtime_forecasts.py +296 -0
  398. apsimo/self_model/runtime_models.py +67 -0
  399. apsimo/self_model/settlement.py +207 -0
  400. apsimo/self_model/situation.py +1731 -0
  401. apsimo/self_model/store.py +883 -0
  402. apsimo/self_model/supervised.py +137 -0
  403. apsimo/self_model/thinker.py +99 -0
  404. apsimo/self_model/trust.py +388 -0
  405. apsimo/self_model/workspace.py +2388 -0
  406. apsimo/server.py +4197 -0
  407. apsimo/services/__init__.py +1 -0
  408. apsimo/services/agent_bridge.py +474 -0
  409. apsimo/services/initiative_executor.py +914 -0
  410. apsimo/services/instance.py +297 -0
  411. apsimo/sessions/__init__.py +22 -0
  412. apsimo/sessions/config.py +13 -0
  413. apsimo/sessions/context_loader.py +88 -0
  414. apsimo/sessions/federation_session.py +75 -0
  415. apsimo/sessions/isolated_session.py +98 -0
  416. apsimo/sessions/reports.py +84 -0
  417. apsimo/sessions/store.py +148 -0
  418. apsimo/setup.py +2818 -0
  419. apsimo/setup_hermes.py +879 -0
  420. apsimo/setup_local_work.py +218 -0
  421. apsimo/setup_native_goals.py +134 -0
  422. apsimo/setup_native_reviews.py +115 -0
  423. apsimo/skills/__init__.py +10 -0
  424. apsimo/skills/base.py +108 -0
  425. apsimo/skills/budget.py +28 -0
  426. apsimo/skills/executor.py +493 -0
  427. apsimo/skills/executors/__init__.py +1 -0
  428. apsimo/skills/executors/behavioral_correction.py +75 -0
  429. apsimo/skills/executors/capability_gap.py +38 -0
  430. apsimo/skills/executors/data_quality.py +163 -0
  431. apsimo/skills/executors/knowledge_acquisition.py +41 -0
  432. apsimo/skills/executors/operational_hygiene.py +185 -0
  433. apsimo/skills/executors/subsystem_health.py +169 -0
  434. apsimo/skills/hermes_export.py +431 -0
  435. apsimo/skills/index.py +123 -0
  436. apsimo/skills/learning/__init__.py +21 -0
  437. apsimo/skills/learning/novelty_detector.py +206 -0
  438. apsimo/skills/learning/pattern_extractor.py +199 -0
  439. apsimo/skills/learning/triggers.py +159 -0
  440. apsimo/skills/loader.py +246 -0
  441. apsimo/skills/migrations/002_progressive_loading.sql +6 -0
  442. apsimo/skills/migrations/backfill_triggers.py +20 -0
  443. apsimo/skills/models.py +202 -0
  444. apsimo/skills/packager.py +128 -0
  445. apsimo/skills/protocols.py +70 -0
  446. apsimo/skills/registry.py +191 -0
  447. apsimo/skills/runtime.py +58 -0
  448. apsimo/skills/sandbox_runner.py +229 -0
  449. apsimo/skills/scheduler.py +129 -0
  450. apsimo/skills/schema.py +79 -0
  451. apsimo/skills/security/__init__.py +12 -0
  452. apsimo/skills/security/guards.py +53 -0
  453. apsimo/skills/security/scanner.py +223 -0
  454. apsimo/skills_memory/__init__.py +26 -0
  455. apsimo/skills_memory/distill.py +159 -0
  456. apsimo/skills_memory/models.py +85 -0
  457. apsimo/skills_memory/retrieve.py +62 -0
  458. apsimo/skills_memory/store.py +172 -0
  459. apsimo/surprise/__init__.py +6 -0
  460. apsimo/surprise/accumulation.py +57 -0
  461. apsimo/surprise/scorer.py +102 -0
  462. apsimo/surprise/store.py +203 -0
  463. apsimo/task_queue/__init__.py +69 -0
  464. apsimo/task_queue/action_receipts.py +148 -0
  465. apsimo/task_queue/approval_relay_canary.py +108 -0
  466. apsimo/task_queue/config.py +85 -0
  467. apsimo/task_queue/contract.py +361 -0
  468. apsimo/task_queue/events.py +130 -0
  469. apsimo/task_queue/governor.py +1031 -0
  470. apsimo/task_queue/handlers/__init__.py +16 -0
  471. apsimo/task_queue/handlers/base.py +37 -0
  472. apsimo/task_queue/handlers/inference.py +640 -0
  473. apsimo/task_queue/handlers/monitoring.py +116 -0
  474. apsimo/task_queue/handlers/registry.py +75 -0
  475. apsimo/task_queue/handlers/subtask_handler.py +173 -0
  476. apsimo/task_queue/handlers/system_maintenance.py +147 -0
  477. apsimo/task_queue/mesh_integration.py +111 -0
  478. apsimo/task_queue/models.py +317 -0
  479. apsimo/task_queue/queue_manager.py +8286 -0
  480. apsimo/task_queue/routing.py +287 -0
  481. apsimo/task_queue/scheduler.py +252 -0
  482. apsimo/task_queue/schema.sql +197 -0
  483. apsimo/task_queue/work_control.py +342 -0
  484. apsimo/task_queue/worker.py +993 -0
  485. apsimo/telemetry.py +145 -0
  486. apsimo/tom/__init__.py +6 -0
  487. apsimo/tom/affect.py +387 -0
  488. apsimo/tom/approvals.py +171 -0
  489. apsimo/tom/arcs.py +896 -0
  490. apsimo/tom/asymmetry.py +131 -0
  491. apsimo/tom/eligibility.py +248 -0
  492. apsimo/tom/engagement.py +214 -0
  493. apsimo/tom/exposure.py +214 -0
  494. apsimo/tom/extractor.py +306 -0
  495. apsimo/tom/fact_adapters.py +144 -0
  496. apsimo/tom/facts.py +326 -0
  497. apsimo/tom/integration.py +592 -0
  498. apsimo/tom/leveled.py +118 -0
  499. apsimo/tom/levels.py +247 -0
  500. apsimo/tom/recipient_audit.py +995 -0
  501. apsimo/tom/recipient_simulator.py +593 -0
  502. apsimo/tom/source_lineage.py +93 -0
  503. apsimo/tom/tom2.py +277 -0
  504. apsimo/tom/visibility.py +559 -0
  505. apsimo/tom/visibility_store.py +414 -0
  506. apsimo/tools/__init__.py +0 -0
  507. apsimo/tools/definitions.py +740 -0
  508. apsimo/tools/handlers.py +943 -0
  509. apsimo/toolsmith/__init__.py +26 -0
  510. apsimo/toolsmith/authority.py +166 -0
  511. apsimo/toolsmith/engine.py +559 -0
  512. apsimo/toolsmith/integrity.py +100 -0
  513. apsimo/toolsmith/miner.py +145 -0
  514. apsimo/toolsmith/policy.py +110 -0
  515. apsimo/toolsmith/registry.py +635 -0
  516. apsimo/turns/__init__.py +17 -0
  517. apsimo/turns/audio.py +134 -0
  518. apsimo/turns/documents.py +235 -0
  519. apsimo/turns/executions.py +486 -0
  520. apsimo/turns/hermes_history.py +245 -0
  521. apsimo/turns/hermes_kanban.py +268 -0
  522. apsimo/turns/hermes_work.py +96 -0
  523. apsimo/turns/idempotency.py +752 -0
  524. apsimo/turns/local_work.py +115 -0
  525. apsimo/turns/media.py +581 -0
  526. apsimo/turns/reported_workers.py +196 -0
  527. apsimo/turns/source_annotations.py +283 -0
  528. apsimo/turns/source_attribution.py +154 -0
  529. apsimo/turns/source_read.py +351 -0
  530. apsimo/turns/source_vectors.py +263 -0
  531. apsimo/turns/video.py +210 -0
  532. apsimo/util/autonomy_preset.py +220 -0
  533. apsimo/util/instance.py +92 -0
  534. apsimo/util/model_output.py +25 -0
  535. apsimo/util/quiet_hours.py +27 -0
  536. apsimo/util/session_safety.py +37 -0
  537. apsimo/util/temporal.py +343 -0
  538. apsimo/vector/__init__.py +75 -0
  539. apsimo/vector/backfill.py +171 -0
  540. apsimo/vector/caption.py +114 -0
  541. apsimo/vector/collections.py +51 -0
  542. apsimo/vector/config.py +102 -0
  543. apsimo/vector/embedder.py +670 -0
  544. apsimo/vector/image_preprocess.py +406 -0
  545. apsimo/vector/image_store.py +296 -0
  546. apsimo/vector/indexes.py +162 -0
  547. apsimo/vector/migrate.py +334 -0
  548. apsimo/vector/multimodal_provider.py +417 -0
  549. apsimo/vector/multimodal_types.py +87 -0
  550. apsimo/vector/openai_provider.py +119 -0
  551. apsimo/vector/query.py +49 -0
  552. apsimo/vector/reranker.py +565 -0
  553. apsimo/vector/safety_image.py +159 -0
  554. apsimo/vector/scanner.py +197 -0
  555. apsimo/vector/setup.py +289 -0
  556. apsimo/vector/store.py +533 -0
  557. apsimo/vector/tiers.py +263 -0
  558. apsimo/work_orders.py +925 -0
  559. apsimo/workers/__init__.py +21 -0
  560. apsimo/workers/agent_bridge.py +640 -0
  561. apsimo/workers/colony_worker.py +382 -0
  562. apsimo/workers/queue_worker.py +441 -0
  563. apsimo/workers/skills_sync.py +152 -0
  564. apsimo/world_model/__init__.py +71 -0
  565. apsimo/world_model/causal_maintenance.py +131 -0
  566. apsimo/world_model/causal_policy.py +43 -0
  567. apsimo/world_model/causal_query.py +125 -0
  568. apsimo/world_model/confidence.py +54 -0
  569. apsimo/world_model/config.py +64 -0
  570. apsimo/world_model/constants.py +97 -0
  571. apsimo/world_model/entities.py +145 -0
  572. apsimo/world_model/expectation_resolvers.py +177 -0
  573. apsimo/world_model/extraction/__init__.py +7 -0
  574. apsimo/world_model/extraction/base.py +62 -0
  575. apsimo/world_model/extraction/conversation_extractor.py +262 -0
  576. apsimo/world_model/extraction/detector.py +74 -0
  577. apsimo/world_model/extraction/document_extractor.py +78 -0
  578. apsimo/world_model/extraction/formats/__init__.py +24 -0
  579. apsimo/world_model/extraction/formats/csv_fmt.py +68 -0
  580. apsimo/world_model/extraction/formats/html_fmt.py +72 -0
  581. apsimo/world_model/extraction/formats/json_fmt.py +68 -0
  582. apsimo/world_model/extraction/formats/pdf.py +43 -0
  583. apsimo/world_model/extraction/formats/text.py +27 -0
  584. apsimo/world_model/extraction/llm_extractor.py +164 -0
  585. apsimo/world_model/extraction/pipeline.py +73 -0
  586. apsimo/world_model/integrations/__init__.py +5 -0
  587. apsimo/world_model/integrations/mind_model_bridge.py +115 -0
  588. apsimo/world_model/integrations/social_intel_bridge.py +120 -0
  589. apsimo/world_model/jobs/__init__.py +4 -0
  590. apsimo/world_model/jobs/extraction_job.py +168 -0
  591. apsimo/world_model/llm_extract.py +572 -0
  592. apsimo/world_model/neo4j/__init__.py +5 -0
  593. apsimo/world_model/neo4j/backend.py +654 -0
  594. apsimo/world_model/observations.py +155 -0
  595. apsimo/world_model/populator.py +307 -0
  596. apsimo/world_model/postgres/__init__.py +1 -0
  597. apsimo/world_model/postgres/backend.py +683 -0
  598. apsimo/world_model/relationships.py +25 -0
  599. apsimo/world_model/resolution/__init__.py +13 -0
  600. apsimo/world_model/resolution/entity_resolver.py +232 -0
  601. apsimo/world_model/resolution/merge_audit.py +16 -0
  602. apsimo/world_model/resolution/merge_workflow.py +117 -0
  603. apsimo/world_model/source_reports.py +121 -0
  604. apsimo/world_model/sqlite/__init__.py +4 -0
  605. apsimo/world_model/sqlite/backend.py +855 -0
  606. apsimo/world_model/sqlite/schema.sql +132 -0
  607. apsimo/world_model/store.py +545 -0
  608. apsimo-1.3.0.dist-info/METADATA +78 -0
  609. apsimo-1.3.0.dist-info/RECORD +614 -0
  610. apsimo-1.3.0.dist-info/WHEEL +5 -0
  611. apsimo-1.3.0.dist-info/entry_points.txt +11 -0
  612. apsimo-1.3.0.dist-info/licenses/LICENSE +21 -0
  613. apsimo-1.3.0.dist-info/top_level.txt +2 -0
  614. colony_sidecar/__init__.py +4 -0
apsimo/chain/cli.py ADDED
@@ -0,0 +1,704 @@
1
+ """CLI commands for ColonyChain management.
2
+
3
+ Usage:
4
+ colony chain status # Show chain state summary
5
+ colony chain genesis --name NAME # Initialize genesis block
6
+ colony chain info --block N # Show block details
7
+ colony chain tx --tx-id ID # Show transaction details
8
+ colony chain list-colonies # List registered colonies
9
+ colony chain list-sentinels # List active sentinels
10
+ colony chain verify # Verify chain integrity
11
+ colony chain mempool # Show pending mempool transactions
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import hashlib
17
+ import json
18
+ import sys
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ _DEFAULT_DB = Path.home() / ".colony" / "chain.db"
23
+
24
+
25
+ def _load_store(db_path: str | None = None) -> "ChainStore":
26
+ from apsimo.chain.storage import ChainStore
27
+ path = Path(db_path) if db_path else _DEFAULT_DB
28
+ return ChainStore(path)
29
+
30
+
31
+ def _load_state(db_path: str | None = None) -> "ChainState":
32
+ from apsimo.chain.state_machine import ChainStateMachine
33
+ store = _load_store(db_path)
34
+ sm = ChainStateMachine(store)
35
+ return sm.get_current_state()
36
+
37
+
38
+ def cmd_chain_status(args) -> int:
39
+ """Show chain state summary."""
40
+ try:
41
+ store = _load_store(getattr(args, "db", None))
42
+ from apsimo.chain.state_machine import ChainStateMachine
43
+ sm = ChainStateMachine(store)
44
+ state = sm.get_current_state()
45
+ height = store.get_height()
46
+
47
+ print("ColonyChain Status")
48
+ print("==================")
49
+ print(f" Height: {height}")
50
+ print(f" Last block hash: {state.last_block_hash[:24]}...")
51
+ print(f" Network ID: {state.network_id[:24]}..." if state.network_id else " Network ID: (none)")
52
+ print(f" Genesis admin: {state.genesis_admin_id or '(none)'}")
53
+ print(f" Colonies: {len(state.colony_registry)}")
54
+ print(f" Suspended: {len(state.suspended_colonies)}")
55
+ print(f" Sentinels: {len(state.active_sentinels())}")
56
+ print(f" Trust edges: {len(state.trust_graph)}")
57
+ print(f" Mempool size: {store.mempool_size()}")
58
+ print(f" Block interval: {state.protocol_config.block_interval_secs}s")
59
+ print(f" Untrust threshold:{state.protocol_config.untrust_threshold}")
60
+ return 0
61
+ except Exception as exc:
62
+ print(f"Error: {exc}", file=sys.stderr)
63
+ return 1
64
+
65
+
66
+ def cmd_chain_genesis(args) -> int:
67
+ """Initialize a new ColonyChain with a genesis block."""
68
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
69
+ from cryptography.hazmat.primitives.serialization import (
70
+ Encoding, PublicFormat, PrivateFormat, NoEncryption
71
+ )
72
+ from apsimo.chain.genesis import GenesisConfig, create_genesis_block
73
+ from apsimo.chain.storage import ChainStore
74
+
75
+ name = getattr(args, "name", None) or "genesis"
76
+ db_path = getattr(args, "db", None)
77
+ key_file = getattr(args, "key_file", None)
78
+
79
+ db = Path(db_path) if db_path else _DEFAULT_DB
80
+ db.parent.mkdir(parents=True, exist_ok=True)
81
+
82
+ store = ChainStore(db)
83
+ if store.get_height() >= 0:
84
+ print("Error: chain already initialized (genesis block exists)", file=sys.stderr)
85
+ return 1
86
+
87
+ # Generate or load key
88
+ if key_file and Path(key_file).exists():
89
+ raw = bytes.fromhex(Path(key_file).read_text().strip())
90
+ priv = Ed25519PrivateKey.from_private_bytes(raw)
91
+ print(f"Loaded key from {key_file}")
92
+ else:
93
+ priv = Ed25519PrivateKey.generate()
94
+ if key_file:
95
+ raw_bytes = priv.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
96
+ Path(key_file).write_text(raw_bytes.hex())
97
+ print(f"Generated new key → {key_file}")
98
+ else:
99
+ print("Generated ephemeral key (not saved). Use --key-file to persist.")
100
+
101
+ pub = priv.public_key()
102
+ pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
103
+ colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
104
+
105
+ def sign_fn(data: bytes) -> str:
106
+ return priv.sign(data).hex()
107
+
108
+ cfg = GenesisConfig(
109
+ genesis_colony_name=name,
110
+ genesis_colony_id=colony_id,
111
+ genesis_pubkey_hex=pub_hex,
112
+ )
113
+ block = create_genesis_block(cfg, sign_fn=sign_fn)
114
+ store.append_block(block)
115
+
116
+ print(f"Genesis block created:")
117
+ print(f" Colony name: {name}")
118
+ print(f" Colony ID: {colony_id}")
119
+ print(f" Block hash: {block.block_hash[:24]}...")
120
+ print(f" Network ID: {block.metadata.get('network_id', '')[:24]}...")
121
+ print(f" DB path: {db}")
122
+ return 0
123
+
124
+
125
+ def cmd_chain_info(args) -> int:
126
+ """Show block details."""
127
+ block_index = getattr(args, "block", None)
128
+ if block_index is None:
129
+ print("Error: --block N required", file=sys.stderr)
130
+ return 1
131
+ try:
132
+ block_index = int(block_index)
133
+ store = _load_store(getattr(args, "db", None))
134
+ block = store.get_block(block_index)
135
+ if block is None:
136
+ print(f"Block {block_index} not found", file=sys.stderr)
137
+ return 1
138
+ d = block.to_dict()
139
+ # Truncate tx list for display
140
+ tx_count = len(d["transactions"])
141
+ d["transactions"] = f"<{tx_count} transactions>"
142
+ print(json.dumps(d, indent=2, default=str))
143
+ return 0
144
+ except Exception as exc:
145
+ print(f"Error: {exc}", file=sys.stderr)
146
+ return 1
147
+
148
+
149
+ def cmd_chain_tx(args) -> int:
150
+ """Show transaction details."""
151
+ tx_id = getattr(args, "tx_id", None)
152
+ if not tx_id:
153
+ print("Error: --tx-id required", file=sys.stderr)
154
+ return 1
155
+ try:
156
+ store = _load_store(getattr(args, "db", None))
157
+ txs = store.get_transactions_for_colony("")
158
+ # search all by fetching blocks
159
+ height = store.get_height()
160
+ for idx in range(height + 1):
161
+ block = store.get_block(idx)
162
+ if block:
163
+ for tx in block.transactions:
164
+ if tx.tx_id == tx_id:
165
+ d = tx.to_dict()
166
+ d["block_index"] = idx
167
+ print(json.dumps(d, indent=2, default=str))
168
+ return 0
169
+ print(f"Transaction {tx_id!r} not found", file=sys.stderr)
170
+ return 1
171
+ except Exception as exc:
172
+ print(f"Error: {exc}", file=sys.stderr)
173
+ return 1
174
+
175
+
176
+ def cmd_chain_list_colonies(args) -> int:
177
+ """List all registered colonies."""
178
+ try:
179
+ state = _load_state(getattr(args, "db", None))
180
+ if not state.colony_registry:
181
+ print("No colonies registered.")
182
+ return 0
183
+ fmt = "{:<20} {:<12} {:<16} {}"
184
+ print(fmt.format("NAME", "STATUS", "COLONY_ID (prefix)", "ENDPOINT"))
185
+ print("-" * 80)
186
+ for colony_id, record in sorted(state.colony_registry.items(), key=lambda x: x[1].name):
187
+ flags = ""
188
+ if record.is_genesis_admin:
189
+ flags = " [genesis]"
190
+ print(fmt.format(
191
+ record.name + flags,
192
+ record.status,
193
+ colony_id[:16],
194
+ record.endpoint or "(local)",
195
+ ))
196
+ return 0
197
+ except Exception as exc:
198
+ print(f"Error: {exc}", file=sys.stderr)
199
+ return 1
200
+
201
+
202
+ def cmd_chain_list_sentinels(args) -> int:
203
+ """List Sentinel validators."""
204
+ try:
205
+ state = _load_state(getattr(args, "db", None))
206
+ if not state.sentinel_roster:
207
+ print("No sentinels registered.")
208
+ return 0
209
+ fmt = "{:<36} {:<12} {:<20} {}"
210
+ print(fmt.format("SENTINEL_ID", "STATUS", "HOST:PORT", "COLONY_ID (prefix)"))
211
+ print("-" * 80)
212
+ for sid, record in state.sentinel_roster.items():
213
+ print(fmt.format(
214
+ sid,
215
+ record.status,
216
+ f"{record.host}:{record.port}",
217
+ record.colony_id[:16],
218
+ ))
219
+ return 0
220
+ except Exception as exc:
221
+ print(f"Error: {exc}", file=sys.stderr)
222
+ return 1
223
+
224
+
225
+ def cmd_chain_verify(args) -> int:
226
+ """Verify chain hash integrity from genesis."""
227
+ try:
228
+ store = _load_store(getattr(args, "db", None))
229
+ height = store.get_height()
230
+ if height < 0:
231
+ print("Chain is empty (no blocks).")
232
+ return 0
233
+
234
+ errors = 0
235
+ prev_hash = "0" * 64
236
+ for idx in range(height + 1):
237
+ block = store.get_block(idx)
238
+ if block is None:
239
+ print(f" MISSING block {idx}", file=sys.stderr)
240
+ errors += 1
241
+ continue
242
+
243
+ if idx == 0:
244
+ if block.previous_hash != "0" * 64:
245
+ print(f" FAIL block 0: previous_hash must be zeros")
246
+ errors += 1
247
+ else:
248
+ if block.previous_hash != prev_hash:
249
+ print(f" FAIL block {idx}: previous_hash mismatch")
250
+ errors += 1
251
+
252
+ from apsimo.chain.block import build_merkle_root
253
+ tx_ids = [tx.tx_id for tx in block.transactions]
254
+ expected_merkle = build_merkle_root(tx_ids)
255
+ if block.merkle_root != expected_merkle:
256
+ print(f" FAIL block {idx}: merkle_root mismatch")
257
+ errors += 1
258
+
259
+ prev_hash = block.block_hash
260
+
261
+ if errors == 0:
262
+ print(f"Chain verified OK: {height + 1} blocks, no errors.")
263
+ return 0
264
+ else:
265
+ print(f"Chain verification FAILED: {errors} error(s).", file=sys.stderr)
266
+ return 1
267
+ except Exception as exc:
268
+ print(f"Error: {exc}", file=sys.stderr)
269
+ return 1
270
+
271
+
272
+ def cmd_chain_mempool(args) -> int:
273
+ """Show pending mempool transactions."""
274
+ try:
275
+ store = _load_store(getattr(args, "db", None))
276
+ txs = store.get_mempool(limit=100)
277
+ if not txs:
278
+ print("Mempool is empty.")
279
+ return 0
280
+ print(f"Mempool: {len(txs)} pending transaction(s)")
281
+ fmt = "{:<36} {:<24} {:<8} {}"
282
+ print(fmt.format("TX_ID", "TYPE", "NONCE", "FROM (prefix)"))
283
+ print("-" * 80)
284
+ for tx in txs:
285
+ print(fmt.format(
286
+ tx.tx_id,
287
+ tx.type.value if hasattr(tx.type, "value") else str(tx.type),
288
+ str(tx.nonce),
289
+ tx.from_colony_id[:16],
290
+ ))
291
+ return 0
292
+ except Exception as exc:
293
+ print(f"Error: {exc}", file=sys.stderr)
294
+ return 1
295
+
296
+
297
+ def cmd_chain_state(args) -> int:
298
+ """Dump current chain state summary."""
299
+ try:
300
+ state = _load_state(getattr(args, "db", None))
301
+ import json as _json
302
+ summary = {
303
+ "height": state.height,
304
+ "last_block_hash": state.last_block_hash,
305
+ "network_id": state.network_id,
306
+ "genesis_admin_id": state.genesis_admin_id,
307
+ "colony_count": len(state.colony_registry),
308
+ "suspended_count": len(state.suspended_colonies),
309
+ "sentinel_count": len(state.active_sentinels()),
310
+ "trust_edges": len(state.trust_graph),
311
+ "protocol_config": {
312
+ "block_interval_secs": state.protocol_config.block_interval_secs,
313
+ "untrust_threshold": state.protocol_config.untrust_threshold,
314
+ "min_sentinels": state.protocol_config.min_sentinels,
315
+ },
316
+ "upgrade_history_count": len(state.upgrade_history),
317
+ }
318
+ print(_json.dumps(summary, indent=2, default=str))
319
+ return 0
320
+ except Exception as exc:
321
+ print(f"Error: {exc}", file=sys.stderr)
322
+ return 1
323
+
324
+
325
+ def cmd_chain_register(args) -> int:
326
+ """Register this colony on-chain (colony_register transaction)."""
327
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
328
+ from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat, PrivateFormat, NoEncryption
329
+ from apsimo.chain.transactions import TxType, Transaction
330
+ import hashlib
331
+
332
+ key_file = getattr(args, "key_file", None)
333
+ name = getattr(args, "name", None)
334
+ endpoint = getattr(args, "endpoint", "") or ""
335
+ description = getattr(args, "description", "") or ""
336
+ db_path = getattr(args, "db", None)
337
+
338
+ if not name:
339
+ print("Error: --name required", file=sys.stderr)
340
+ return 1
341
+ if not key_file:
342
+ print("Error: --key-file required", file=sys.stderr)
343
+ return 1
344
+ if not Path(key_file).exists():
345
+ print(f"Error: key file not found: {key_file}", file=sys.stderr)
346
+ return 1
347
+
348
+ try:
349
+ raw = bytes.fromhex(Path(key_file).read_text().strip())
350
+ priv = Ed25519PrivateKey.from_private_bytes(raw)
351
+ pub = priv.public_key()
352
+ pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
353
+ colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
354
+
355
+ def sign_fn(data: bytes) -> str:
356
+ return priv.sign(data).hex()
357
+
358
+ store = _load_store(db_path)
359
+ from apsimo.chain.state_machine import ChainStateMachine
360
+ sm = ChainStateMachine(store)
361
+ state = sm.get_current_state()
362
+
363
+ nonce_map = {}
364
+ for cid, rec in state.colony_registry.items():
365
+ pass
366
+ last_nonce = 0
367
+ for block_idx in range(store.get_height() + 1):
368
+ block = store.get_block(block_idx)
369
+ if block:
370
+ for tx in block.transactions:
371
+ if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
372
+ last_nonce = tx.nonce
373
+
374
+ tx = Transaction.create(
375
+ tx_type=TxType.COLONY_REGISTER,
376
+ from_colony_id=colony_id,
377
+ nonce=last_nonce + 1,
378
+ payload={
379
+ "name": name,
380
+ "public_key_hex": pub_hex,
381
+ "colony_id": colony_id,
382
+ "endpoint": endpoint,
383
+ "description": description[:256],
384
+ "protocol_version": "1.0.0",
385
+ "capabilities": ["task_delegation", "memory_sharing"],
386
+ "genesis_admin": False,
387
+ "metadata": {},
388
+ },
389
+ sign_fn=sign_fn,
390
+ )
391
+ store.add_to_mempool(tx)
392
+ print(f"Submitted colony_register to mempool:")
393
+ print(f" tx_id: {tx.tx_id}")
394
+ print(f" colony_id: {colony_id}")
395
+ print(f" name: {name}")
396
+ return 0
397
+ except Exception as exc:
398
+ print(f"Error: {exc}", file=sys.stderr)
399
+ return 1
400
+
401
+
402
+ def cmd_chain_rotate_key(args) -> int:
403
+ """Rotate this colony's Ed25519 key on-chain."""
404
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
405
+ from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat, PrivateFormat, NoEncryption
406
+ from apsimo.chain.transactions import TxType, Transaction
407
+ import hashlib
408
+
409
+ old_key_file = getattr(args, "old_key_file", None)
410
+ new_key_file = getattr(args, "new_key_file", None)
411
+ db_path = getattr(args, "db", None)
412
+
413
+ if not old_key_file or not new_key_file:
414
+ print("Error: --old-key-file and --new-key-file required", file=sys.stderr)
415
+ return 1
416
+
417
+ try:
418
+ old_raw = bytes.fromhex(Path(old_key_file).read_text().strip())
419
+ old_priv = Ed25519PrivateKey.from_private_bytes(old_raw)
420
+ old_pub = old_priv.public_key()
421
+ old_pub_hex = old_pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
422
+ colony_id = hashlib.sha256(bytes.fromhex(old_pub_hex)).hexdigest()
423
+
424
+ if Path(new_key_file).exists():
425
+ new_raw = bytes.fromhex(Path(new_key_file).read_text().strip())
426
+ new_priv = Ed25519PrivateKey.from_private_bytes(new_raw)
427
+ else:
428
+ new_priv = Ed25519PrivateKey.generate()
429
+ new_raw_bytes = new_priv.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
430
+ Path(new_key_file).write_text(new_raw_bytes.hex())
431
+ print(f"Generated new key → {new_key_file}")
432
+
433
+ new_pub = new_priv.public_key()
434
+ new_pub_hex = new_pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
435
+
436
+ def sign_fn(data: bytes) -> str:
437
+ return old_priv.sign(data).hex()
438
+
439
+ store = _load_store(db_path)
440
+ last_nonce = 0
441
+ for block_idx in range(store.get_height() + 1):
442
+ block = store.get_block(block_idx)
443
+ if block:
444
+ for tx in block.transactions:
445
+ if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
446
+ last_nonce = tx.nonce
447
+
448
+ tx = Transaction.create(
449
+ tx_type=TxType.COLONY_ROTATE_KEY,
450
+ from_colony_id=colony_id,
451
+ nonce=last_nonce + 1,
452
+ payload={
453
+ "new_public_key_hex": new_pub_hex,
454
+ "old_public_key_hex": old_pub_hex,
455
+ "reason": "scheduled_rotation",
456
+ },
457
+ sign_fn=sign_fn,
458
+ )
459
+ store.add_to_mempool(tx)
460
+ print(f"Submitted colony_rotate_key to mempool:")
461
+ print(f" tx_id: {tx.tx_id}")
462
+ print(f" colony_id: {colony_id}")
463
+ print(f" new_pubkey: {new_pub_hex[:24]}...")
464
+ return 0
465
+ except Exception as exc:
466
+ print(f"Error: {exc}", file=sys.stderr)
467
+ return 1
468
+
469
+
470
+ def cmd_chain_trust(args) -> int:
471
+ """Submit trust_attest for a peer colony."""
472
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
473
+ from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
474
+ from apsimo.chain.transactions import TxType, Transaction
475
+ import hashlib
476
+
477
+ key_file = getattr(args, "key_file", None)
478
+ target = getattr(args, "target", None) or getattr(args, "colony", None)
479
+ level_raw = getattr(args, "level", None) or getattr(args, "trust_level", "1")
480
+ db_path = getattr(args, "db", None)
481
+
482
+ if not key_file or not target:
483
+ print("Error: --key-file and --target (or positional colony name) required", file=sys.stderr)
484
+ return 1
485
+
486
+ try:
487
+ level = int(level_raw)
488
+ if not 0 <= level <= 4:
489
+ print("Error: trust level must be 0-4", file=sys.stderr)
490
+ return 1
491
+
492
+ raw = bytes.fromhex(Path(key_file).read_text().strip())
493
+ priv = Ed25519PrivateKey.from_private_bytes(raw)
494
+ pub = priv.public_key()
495
+ pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
496
+ colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
497
+
498
+ def sign_fn(data: bytes) -> str:
499
+ return priv.sign(data).hex()
500
+
501
+ store = _load_store(db_path)
502
+ state = _load_state(db_path)
503
+
504
+ # Resolve target: may be a name or colony_id
505
+ target_id = state.colony_id_for_name(target) or (target if target in state.colony_registry else None)
506
+ if not target_id:
507
+ print(f"Error: colony {target!r} not found in chain state", file=sys.stderr)
508
+ return 1
509
+
510
+ last_nonce = 0
511
+ for block_idx in range(store.get_height() + 1):
512
+ block = store.get_block(block_idx)
513
+ if block:
514
+ for tx in block.transactions:
515
+ if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
516
+ last_nonce = tx.nonce
517
+
518
+ tx = Transaction.create(
519
+ tx_type=TxType.TRUST_ATTEST,
520
+ from_colony_id=colony_id,
521
+ nonce=last_nonce + 1,
522
+ payload={
523
+ "to_colony_id": target_id,
524
+ "trust_level": level,
525
+ "evidence_tx_ids": [],
526
+ },
527
+ sign_fn=sign_fn,
528
+ )
529
+ store.add_to_mempool(tx)
530
+ print(f"Submitted trust_attest to mempool:")
531
+ print(f" tx_id: {tx.tx_id}")
532
+ print(f" target: {target_id[:24]}... (level={level})")
533
+ return 0
534
+ except Exception as exc:
535
+ print(f"Error: {exc}", file=sys.stderr)
536
+ return 1
537
+
538
+
539
+ def cmd_chain_untrust(args) -> int:
540
+ """Submit untrust_attest for a peer colony."""
541
+ from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
542
+ from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
543
+ from apsimo.chain.transactions import TxType, Transaction
544
+ import hashlib
545
+
546
+ key_file = getattr(args, "key_file", None)
547
+ target = getattr(args, "target", None) or getattr(args, "colony", None)
548
+ db_path = getattr(args, "db", None)
549
+ report_abuse = getattr(args, "report_abuse", False)
550
+
551
+ if not key_file or not target:
552
+ print("Error: --key-file and --target required", file=sys.stderr)
553
+ return 1
554
+
555
+ try:
556
+ raw = bytes.fromhex(Path(key_file).read_text().strip())
557
+ priv = Ed25519PrivateKey.from_private_bytes(raw)
558
+ pub = priv.public_key()
559
+ pub_hex = pub.public_bytes(Encoding.Raw, PublicFormat.Raw).hex()
560
+ colony_id = hashlib.sha256(bytes.fromhex(pub_hex)).hexdigest()
561
+
562
+ def sign_fn(data: bytes) -> str:
563
+ return priv.sign(data).hex()
564
+
565
+ store = _load_store(db_path)
566
+ state = _load_state(db_path)
567
+
568
+ target_id = state.colony_id_for_name(target) or (target if target in state.colony_registry else None)
569
+ if not target_id:
570
+ print(f"Error: colony {target!r} not found", file=sys.stderr)
571
+ return 1
572
+
573
+ last_nonce = 0
574
+ for block_idx in range(store.get_height() + 1):
575
+ block = store.get_block(block_idx)
576
+ if block:
577
+ for tx in block.transactions:
578
+ if tx.from_colony_id == colony_id and tx.nonce > last_nonce:
579
+ last_nonce = tx.nonce
580
+
581
+ tx = Transaction.create(
582
+ tx_type=TxType.UNTRUST_ATTEST,
583
+ from_colony_id=colony_id,
584
+ nonce=last_nonce + 1,
585
+ payload={
586
+ "to_colony_id": target_id,
587
+ "reason": getattr(args, "reason", "") or "",
588
+ "report_abuse": bool(report_abuse),
589
+ "evidence_tx_ids": [],
590
+ },
591
+ sign_fn=sign_fn,
592
+ )
593
+ store.add_to_mempool(tx)
594
+ print(f"Submitted untrust_attest to mempool:")
595
+ print(f" tx_id: {tx.tx_id}")
596
+ print(f" target: {target_id[:24]}...")
597
+ return 0
598
+ except Exception as exc:
599
+ print(f"Error: {exc}", file=sys.stderr)
600
+ return 1
601
+
602
+
603
+ def run_chain_command(args: list) -> int:
604
+ """Dispatch 'colony chain <subcommand>'."""
605
+ if not args:
606
+ _print_chain_help()
607
+ return 1
608
+
609
+ sub = args[0]
610
+ remaining = args[1:]
611
+
612
+ # Parse simple key=value style args from remaining
613
+ parsed = _parse_args(remaining)
614
+
615
+ class FakeArgs:
616
+ pass
617
+
618
+ fa = FakeArgs()
619
+ for k, v in parsed.items():
620
+ setattr(fa, k, v)
621
+
622
+ dispatch = {
623
+ "status": cmd_chain_status,
624
+ "genesis": cmd_chain_genesis,
625
+ "info": cmd_chain_info,
626
+ "block": cmd_chain_info,
627
+ "tx": cmd_chain_tx,
628
+ "state": cmd_chain_state,
629
+ "list-colonies": cmd_chain_list_colonies,
630
+ "list_colonies": cmd_chain_list_colonies,
631
+ "list-sentinels": cmd_chain_list_sentinels,
632
+ "list_sentinels": cmd_chain_list_sentinels,
633
+ "verify": cmd_chain_verify,
634
+ "mempool": cmd_chain_mempool,
635
+ "register": cmd_chain_register,
636
+ "rotate-key": cmd_chain_rotate_key,
637
+ "rotate_key": cmd_chain_rotate_key,
638
+ "trust": cmd_chain_trust,
639
+ "untrust": cmd_chain_untrust,
640
+ }
641
+
642
+ handler = dispatch.get(sub)
643
+ if handler is None:
644
+ print(f"Unknown chain subcommand: {sub!r}", file=sys.stderr)
645
+ _print_chain_help()
646
+ return 1
647
+
648
+ return handler(fa)
649
+
650
+
651
+ def _parse_args(args: list) -> dict:
652
+ """Parse --key value or --key=value pairs into a dict."""
653
+ result: dict[str, Any] = {}
654
+ i = 0
655
+ while i < len(args):
656
+ arg = args[i]
657
+ if arg.startswith("--"):
658
+ stripped = arg[2:]
659
+ if "=" in stripped:
660
+ raw_key, v = stripped.split("=", 1)
661
+ k = raw_key.replace("-", "_")
662
+ result[k] = v
663
+ else:
664
+ key = stripped.replace("-", "_")
665
+ if i + 1 < len(args) and not args[i + 1].startswith("--"):
666
+ result[key] = args[i + 1]
667
+ i += 1
668
+ else:
669
+ result[key] = True
670
+ i += 1
671
+ return result
672
+
673
+
674
+ def _print_chain_help() -> None:
675
+ print("""Usage: colony chain <subcommand> [options]
676
+
677
+ Subcommands:
678
+ status Show chain state summary
679
+ state Dump full chain state as JSON
680
+ genesis Initialize genesis block
681
+ info / block Show block details (--block N)
682
+ tx Show transaction (--tx-id ID)
683
+ list-colonies List registered colonies
684
+ list-sentinels List sentinel validators
685
+ verify Verify chain hash integrity
686
+ mempool Show pending mempool transactions
687
+ register Register this colony on-chain
688
+ rotate-key Rotate colony Ed25519 key on-chain
689
+ trust Submit trust_attest (--target NAME --level 0-4)
690
+ untrust Submit untrust_attest (--target NAME)
691
+
692
+ Options:
693
+ --db PATH SQLite database path (default: ~/.colony/chain.db)
694
+ --name NAME Colony name
695
+ --key-file PATH Ed25519 private key file (hex)
696
+ --old-key-file PATH Current key file (for rotate-key)
697
+ --new-key-file PATH New key file (for rotate-key)
698
+ --block N Block index for info command
699
+ --tx-id ID Transaction ID for tx command
700
+ --target NAME Target colony name or ID (trust/untrust)
701
+ --level N Trust level 0-4 (trust command)
702
+ --endpoint URL Colony endpoint URL (register)
703
+ --description TEXT Colony description (register)
704
+ """)