msgctl 0.1.0a1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (450) hide show
  1. msgctl-0.1.0a1/CHANGELOG.md +9 -0
  2. msgctl-0.1.0a1/CONTRIBUTING.md +22 -0
  3. msgctl-0.1.0a1/PKG-INFO +96 -0
  4. msgctl-0.1.0a1/README.md +69 -0
  5. msgctl-0.1.0a1/SECURITY.md +39 -0
  6. msgctl-0.1.0a1/conformance/test_token_budget.py +51 -0
  7. msgctl-0.1.0a1/conformance/test_transports.py +127 -0
  8. msgctl-0.1.0a1/conftest.py +57 -0
  9. msgctl-0.1.0a1/deploy/README.md +26 -0
  10. msgctl-0.1.0a1/deploy/hosting-role.sql +16 -0
  11. msgctl-0.1.0a1/deploy/hosting.example.toml +18 -0
  12. msgctl-0.1.0a1/deploy/mail.example.toml +8 -0
  13. msgctl-0.1.0a1/deploy/msgd-hosting.service +28 -0
  14. msgctl-0.1.0a1/deploy/msgd-worker.service +24 -0
  15. msgctl-0.1.0a1/deploy/msgd.service +24 -0
  16. msgctl-0.1.0a1/deploy/nginx.conf +67 -0
  17. msgctl-0.1.0a1/deploy/prepare-hosting-content.sh +38 -0
  18. msgctl-0.1.0a1/deploy/prepare-service.sh +46 -0
  19. msgctl-0.1.0a1/deploy/sshd_config +28 -0
  20. msgctl-0.1.0a1/docs/ARCHITECTURE.md +273 -0
  21. msgctl-0.1.0a1/docs/ARCHITECTURE_PROGRESS_20260929.md +32 -0
  22. msgctl-0.1.0a1/docs/ARCHITECTURE_REUSE.md +55 -0
  23. msgctl-0.1.0a1/docs/AUTHORIZATION_SOURCES.md +61 -0
  24. msgctl-0.1.0a1/docs/CREDENTIAL_DELIVERY.md +109 -0
  25. msgctl-0.1.0a1/docs/CUSTODIAL_HISTORY.md +115 -0
  26. msgctl-0.1.0a1/docs/C_READ_ACCEPTANCE.md +55 -0
  27. msgctl-0.1.0a1/docs/DEPLOYMENT.md +87 -0
  28. msgctl-0.1.0a1/docs/DESIGN_CHANGE_REQUESTS.md +39 -0
  29. msgctl-0.1.0a1/docs/HOSTING_AUTHORITY_PROGRESS.md +61 -0
  30. msgctl-0.1.0a1/docs/HOSTING_RUNTIME.md +91 -0
  31. msgctl-0.1.0a1/docs/HOSTING_RUNTIME_PROGRESS.md +41 -0
  32. msgctl-0.1.0a1/docs/IMPLEMENTATION_STATUS.md +15 -0
  33. msgctl-0.1.0a1/docs/ISSUES_68_70_PROGRESS.md +98 -0
  34. msgctl-0.1.0a1/docs/ISSUES_78_80_PROGRESS.md +79 -0
  35. msgctl-0.1.0a1/docs/ISSUE_PROGRESS.md +40 -0
  36. msgctl-0.1.0a1/docs/ITERATION_PLAN.md +11 -0
  37. msgctl-0.1.0a1/docs/LEDGER_MIGRATION.md +65 -0
  38. msgctl-0.1.0a1/docs/MANAGED_CHECKOUT.md +37 -0
  39. msgctl-0.1.0a1/docs/MARKET_CLEARING.md +90 -0
  40. msgctl-0.1.0a1/docs/MARKET_CONTRACTS.md +219 -0
  41. msgctl-0.1.0a1/docs/METADATA_SESSION_PROGRESS.md +67 -0
  42. msgctl-0.1.0a1/docs/PROTOCOLS.md +446 -0
  43. msgctl-0.1.0a1/docs/TASK_A_RECOVERY_20260928.md +132 -0
  44. msgctl-0.1.0a1/docs/TASK_A_VERIFICATION.md +51 -0
  45. msgctl-0.1.0a1/docs/TASK_C_EVIDENCE.md +70 -0
  46. msgctl-0.1.0a1/docs/TEMPORARY_UPGRADE.md +110 -0
  47. msgctl-0.1.0a1/docs/TOKEN_DELIVERY_BOUNDARY_PROGRESS.md +23 -0
  48. msgctl-0.1.0a1/docs/TOOL_RUNNER_BOUNDARY.md +23 -0
  49. msgctl-0.1.0a1/docs/VERIFICATION.md +23 -0
  50. msgctl-0.1.0a1/docs/issue-75-77-local-verification.md +122 -0
  51. msgctl-0.1.0a1/pyproject.toml +65 -0
  52. msgctl-0.1.0a1/pyproject.toml.orig +38 -0
  53. msgctl-0.1.0a1/scripts/check_package_artifacts.py +46 -0
  54. msgctl-0.1.0a1/scripts/ci_shards.py +112 -0
  55. msgctl-0.1.0a1/src/msg/__init__.py +2 -0
  56. msgctl-0.1.0a1/src/msg/admin/__init__.py +0 -0
  57. msgctl-0.1.0a1/src/msg/admin/backup_retirement.py +56 -0
  58. msgctl-0.1.0a1/src/msg/admin/backups.py +341 -0
  59. msgctl-0.1.0a1/src/msg/admin/custodial_check.py +77 -0
  60. msgctl-0.1.0a1/src/msg/admin/diagnostics.py +750 -0
  61. msgctl-0.1.0a1/src/msg/admin/market.py +91 -0
  62. msgctl-0.1.0a1/src/msg/admin/market_check.py +341 -0
  63. msgctl-0.1.0a1/src/msg/admin/money.py +322 -0
  64. msgctl-0.1.0a1/src/msg/admin/preflight.py +142 -0
  65. msgctl-0.1.0a1/src/msg/admin/recovery_replay.py +281 -0
  66. msgctl-0.1.0a1/src/msg/admin/restore_database.py +37 -0
  67. msgctl-0.1.0a1/src/msg/admin/root.py +347 -0
  68. msgctl-0.1.0a1/src/msg/admin/rotation.py +197 -0
  69. msgctl-0.1.0a1/src/msg/admin/token_delivery_check.py +54 -0
  70. msgctl-0.1.0a1/src/msg/admin/upgrade_check.py +58 -0
  71. msgctl-0.1.0a1/src/msg/application.py +163 -0
  72. msgctl-0.1.0a1/src/msg/bootstrap.py +305 -0
  73. msgctl-0.1.0a1/src/msg/cli.py +537 -0
  74. msgctl-0.1.0a1/src/msg/client.py +725 -0
  75. msgctl-0.1.0a1/src/msg/client_certificates.py +98 -0
  76. msgctl-0.1.0a1/src/msg/client_content.py +43 -0
  77. msgctl-0.1.0a1/src/msg/client_custodial.py +206 -0
  78. msgctl-0.1.0a1/src/msg/client_market.py +104 -0
  79. msgctl-0.1.0a1/src/msg/client_recovery.py +186 -0
  80. msgctl-0.1.0a1/src/msg/client_secrets.py +58 -0
  81. msgctl-0.1.0a1/src/msg/client_tokens.py +99 -0
  82. msgctl-0.1.0a1/src/msg/client_upgrade.py +188 -0
  83. msgctl-0.1.0a1/src/msg/config.py +318 -0
  84. msgctl-0.1.0a1/src/msg/constants.py +11 -0
  85. msgctl-0.1.0a1/src/msg/core/__init__.py +0 -0
  86. msgctl-0.1.0a1/src/msg/core/batching.py +23 -0
  87. msgctl-0.1.0a1/src/msg/core/codec.py +253 -0
  88. msgctl-0.1.0a1/src/msg/core/contracts.py +128 -0
  89. msgctl-0.1.0a1/src/msg/core/cursors.py +68 -0
  90. msgctl-0.1.0a1/src/msg/core/email_address.py +33 -0
  91. msgctl-0.1.0a1/src/msg/core/errors.py +22 -0
  92. msgctl-0.1.0a1/src/msg/core/events.py +6 -0
  93. msgctl-0.1.0a1/src/msg/core/execution_ports.py +20 -0
  94. msgctl-0.1.0a1/src/msg/core/executor.py +193 -0
  95. msgctl-0.1.0a1/src/msg/core/models.py +517 -0
  96. msgctl-0.1.0a1/src/msg/core/packet.py +71 -0
  97. msgctl-0.1.0a1/src/msg/core/permissions.py +14 -0
  98. msgctl-0.1.0a1/src/msg/core/query.py +44 -0
  99. msgctl-0.1.0a1/src/msg/core/read_query.py +60 -0
  100. msgctl-0.1.0a1/src/msg/core/registry.py +173 -0
  101. msgctl-0.1.0a1/src/msg/core/requests.py +58 -0
  102. msgctl-0.1.0a1/src/msg/core/schema_policy.py +28 -0
  103. msgctl-0.1.0a1/src/msg/core/schemas.py +30 -0
  104. msgctl-0.1.0a1/src/msg/core/tags.py +21 -0
  105. msgctl-0.1.0a1/src/msg/core/template_dsl.py +94 -0
  106. msgctl-0.1.0a1/src/msg/core/text_patch.py +283 -0
  107. msgctl-0.1.0a1/src/msg/core/tool_execution.py +28 -0
  108. msgctl-0.1.0a1/src/msg/core/transfer.py +183 -0
  109. msgctl-0.1.0a1/src/msg/daemon.py +255 -0
  110. msgctl-0.1.0a1/src/msg/data/__init__.py +0 -0
  111. msgctl-0.1.0a1/src/msg/data/bootstrap.json +72 -0
  112. msgctl-0.1.0a1/src/msg/data/favicon.png +0 -0
  113. msgctl-0.1.0a1/src/msg/data/logo-dark.svg +5 -0
  114. msgctl-0.1.0a1/src/msg/data/logo.svg +5 -0
  115. msgctl-0.1.0a1/src/msg/data/recovery-checkpoint.example.json +1 -0
  116. msgctl-0.1.0a1/src/msg/data/recovery-checkpoint.schema.json +118 -0
  117. msgctl-0.1.0a1/src/msg/data/shortcodes.json +1 -0
  118. msgctl-0.1.0a1/src/msg/data/system/AGENTS.md +6 -0
  119. msgctl-0.1.0a1/src/msg/data/system/rules/_index.md +17 -0
  120. msgctl-0.1.0a1/src/msg/data/system/rules/auth.md +6 -0
  121. msgctl-0.1.0a1/src/msg/data/system/rules/files.md +6 -0
  122. msgctl-0.1.0a1/src/msg/data/system/rules/identity.md +6 -0
  123. msgctl-0.1.0a1/src/msg/data/system/rules/protocol.md +6 -0
  124. msgctl-0.1.0a1/src/msg/data/system/rules/read-write.md +6 -0
  125. msgctl-0.1.0a1/src/msg/data/system/rules/recovery.md +6 -0
  126. msgctl-0.1.0a1/src/msg/data/system/rules/security.md +10 -0
  127. msgctl-0.1.0a1/src/msg/data/system/rules/topics.md +6 -0
  128. msgctl-0.1.0a1/src/msg/extensions/__init__.py +1 -0
  129. msgctl-0.1.0a1/src/msg/extensions/hosting.py +259 -0
  130. msgctl-0.1.0a1/src/msg/extensions/keystore.py +96 -0
  131. msgctl-0.1.0a1/src/msg/extensions/repositories.py +769 -0
  132. msgctl-0.1.0a1/src/msg/extensions/rss.py +67 -0
  133. msgctl-0.1.0a1/src/msg/extensions/ssh.py +264 -0
  134. msgctl-0.1.0a1/src/msg/extensions/ssh_git.py +300 -0
  135. msgctl-0.1.0a1/src/msg/extensions/tools.py +150 -0
  136. msgctl-0.1.0a1/src/msg/hosting_runtime.py +138 -0
  137. msgctl-0.1.0a1/src/msg/market/__init__.py +1 -0
  138. msgctl-0.1.0a1/src/msg/market/arbitration.py +481 -0
  139. msgctl-0.1.0a1/src/msg/market/delivery.py +338 -0
  140. msgctl-0.1.0a1/src/msg/market/delivery_notifications.py +110 -0
  141. msgctl-0.1.0a1/src/msg/market/delivery_targets.py +76 -0
  142. msgctl-0.1.0a1/src/msg/market/email.py +100 -0
  143. msgctl-0.1.0a1/src/msg/market/escrow.py +345 -0
  144. msgctl-0.1.0a1/src/msg/market/orders.py +218 -0
  145. msgctl-0.1.0a1/src/msg/market/policy.py +147 -0
  146. msgctl-0.1.0a1/src/msg/market/rationale.py +91 -0
  147. msgctl-0.1.0a1/src/msg/market/references.py +19 -0
  148. msgctl-0.1.0a1/src/msg/market/targets.py +157 -0
  149. msgctl-0.1.0a1/src/msg/plugins/__init__.py +28 -0
  150. msgctl-0.1.0a1/src/msg/plugins/achievements.py +316 -0
  151. msgctl-0.1.0a1/src/msg/plugins/batch.py +32 -0
  152. msgctl-0.1.0a1/src/msg/plugins/bounty.py +366 -0
  153. msgctl-0.1.0a1/src/msg/plugins/collaboration.py +261 -0
  154. msgctl-0.1.0a1/src/msg/plugins/common.py +217 -0
  155. msgctl-0.1.0a1/src/msg/plugins/communication.py +853 -0
  156. msgctl-0.1.0a1/src/msg/plugins/content.py +855 -0
  157. msgctl-0.1.0a1/src/msg/plugins/custodial_lifecycle.py +224 -0
  158. msgctl-0.1.0a1/src/msg/plugins/delivery.py +230 -0
  159. msgctl-0.1.0a1/src/msg/plugins/discovery.py +1266 -0
  160. msgctl-0.1.0a1/src/msg/plugins/discussion.py +162 -0
  161. msgctl-0.1.0a1/src/msg/plugins/extensions.py +10 -0
  162. msgctl-0.1.0a1/src/msg/plugins/following.py +78 -0
  163. msgctl-0.1.0a1/src/msg/plugins/hosting_capacity.py +52 -0
  164. msgctl-0.1.0a1/src/msg/plugins/identity.py +1654 -0
  165. msgctl-0.1.0a1/src/msg/plugins/money.py +221 -0
  166. msgctl-0.1.0a1/src/msg/plugins/offers.py +183 -0
  167. msgctl-0.1.0a1/src/msg/plugins/orders.py +273 -0
  168. msgctl-0.1.0a1/src/msg/plugins/recovery.py +376 -0
  169. msgctl-0.1.0a1/src/msg/plugins/schemas.py +5 -0
  170. msgctl-0.1.0a1/src/msg/plugins/sharing.py +300 -0
  171. msgctl-0.1.0a1/src/msg/plugins/store.py +249 -0
  172. msgctl-0.1.0a1/src/msg/plugins/system.py +75 -0
  173. msgctl-0.1.0a1/src/msg/plugins/transfer.py +249 -0
  174. msgctl-0.1.0a1/src/msg/py.typed +0 -0
  175. msgctl-0.1.0a1/src/msg/security/__init__.py +0 -0
  176. msgctl-0.1.0a1/src/msg/security/age_keys.py +112 -0
  177. msgctl-0.1.0a1/src/msg/security/authentication.py +141 -0
  178. msgctl-0.1.0a1/src/msg/security/authorization.py +300 -0
  179. msgctl-0.1.0a1/src/msg/security/backup_retirement.py +135 -0
  180. msgctl-0.1.0a1/src/msg/security/capabilities.py +157 -0
  181. msgctl-0.1.0a1/src/msg/security/certificates.py +183 -0
  182. msgctl-0.1.0a1/src/msg/security/crypto.py +102 -0
  183. msgctl-0.1.0a1/src/msg/security/custodial_migration.py +292 -0
  184. msgctl-0.1.0a1/src/msg/security/custody_history.py +146 -0
  185. msgctl-0.1.0a1/src/msg/security/network.py +81 -0
  186. msgctl-0.1.0a1/src/msg/security/policy.py +67 -0
  187. msgctl-0.1.0a1/src/msg/security/quarantine.py +19 -0
  188. msgctl-0.1.0a1/src/msg/security/root_files.py +67 -0
  189. msgctl-0.1.0a1/src/msg/security/rotation_journal.py +60 -0
  190. msgctl-0.1.0a1/src/msg/security/sealed_box.py +70 -0
  191. msgctl-0.1.0a1/src/msg/security/sharing_policy.py +29 -0
  192. msgctl-0.1.0a1/src/msg/security/token_delivery.py +93 -0
  193. msgctl-0.1.0a1/src/msg/security/vault.py +186 -0
  194. msgctl-0.1.0a1/src/msg/storage/__init__.py +0 -0
  195. msgctl-0.1.0a1/src/msg/storage/capacity.py +100 -0
  196. msgctl-0.1.0a1/src/msg/storage/custodial_migration.py +22 -0
  197. msgctl-0.1.0a1/src/msg/storage/git.py +435 -0
  198. msgctl-0.1.0a1/src/msg/storage/ledger_migration.py +307 -0
  199. msgctl-0.1.0a1/src/msg/storage/market_migration.py +49 -0
  200. msgctl-0.1.0a1/src/msg/storage/postgres.py +663 -0
  201. msgctl-0.1.0a1/src/msg/storage/query.py +39 -0
  202. msgctl-0.1.0a1/src/msg/storage/read_only.py +126 -0
  203. msgctl-0.1.0a1/src/msg/storage/session.py +403 -0
  204. msgctl-0.1.0a1/src/msg/storage/sqlite.py +360 -0
  205. msgctl-0.1.0a1/src/msg/storage/topic_event_migration.py +26 -0
  206. msgctl-0.1.0a1/src/msg/storage/valkey_bus.py +45 -0
  207. msgctl-0.1.0a1/src/msg/transports/__init__.py +0 -0
  208. msgctl-0.1.0a1/src/msg/transports/client.py +183 -0
  209. msgctl-0.1.0a1/src/msg/transports/dictionary.py +387 -0
  210. msgctl-0.1.0a1/src/msg/transports/graphql.py +75 -0
  211. msgctl-0.1.0a1/src/msg/transports/http.py +72 -0
  212. msgctl-0.1.0a1/src/msg/transports/http_routes.py +1577 -0
  213. msgctl-0.1.0a1/src/msg/transports/mcp.py +127 -0
  214. msgctl-0.1.0a1/src/msg/transports/packet.py +42 -0
  215. msgctl-0.1.0a1/src/msg/transports/read_tree_path.py +65 -0
  216. msgctl-0.1.0a1/src/msg/transports/stdio.py +36 -0
  217. msgctl-0.1.0a1/src/msg/transports/url_safety.py +123 -0
  218. msgctl-0.1.0a1/src/msg/tui.py +368 -0
  219. msgctl-0.1.0a1/src/msg/workers/__init__.py +1 -0
  220. msgctl-0.1.0a1/src/msg/workers/effects.py +406 -0
  221. msgctl-0.1.0a1/src/msg/workers/leases.py +19 -0
  222. msgctl-0.1.0a1/src/msg/workers/mail.py +63 -0
  223. msgctl-0.1.0a1/src/msg/workers/maintenance.py +310 -0
  224. msgctl-0.1.0a1/src/msg/workers/sandbox.py +74 -0
  225. msgctl-0.1.0a1/src/msg/workers/sandbox_child.py +189 -0
  226. msgctl-0.1.0a1/src/msg/workers/webhook.py +160 -0
  227. msgctl-0.1.0a1/tests/conftest.py +51 -0
  228. msgctl-0.1.0a1/tests/fixtures/create_legacy_market.py +89 -0
  229. msgctl-0.1.0a1/tests/fixtures/legacy_market_source.json +13 -0
  230. msgctl-0.1.0a1/tests/issue_78_80/__init__.py +1 -0
  231. msgctl-0.1.0a1/tests/issue_78_80/conftest.py +149 -0
  232. msgctl-0.1.0a1/tests/issue_78_80/test_content_patch_contract.py +114 -0
  233. msgctl-0.1.0a1/tests/issue_78_80/test_lfs_integrity.py +196 -0
  234. msgctl-0.1.0a1/tests/issue_78_80/test_lfs_migration_contract.py +50 -0
  235. msgctl-0.1.0a1/tests/issue_78_80/test_read_query_tree.py +178 -0
  236. msgctl-0.1.0a1/tests/issue_78_80/test_read_tree_transports.py +172 -0
  237. msgctl-0.1.0a1/tests/issue_78_80/test_revision_signature_fields.py +68 -0
  238. msgctl-0.1.0a1/tests/issue_78_80/test_text_patch_formats.py +144 -0
  239. msgctl-0.1.0a1/tests/issue_78_80/test_tree_query_ref.py +108 -0
  240. msgctl-0.1.0a1/tests/read_only_evidence.py +51 -0
  241. msgctl-0.1.0a1/tests/test_access_log_secret_redaction.py +85 -0
  242. msgctl-0.1.0a1/tests/test_achievement_pins.py +73 -0
  243. msgctl-0.1.0a1/tests/test_achievements.py +136 -0
  244. msgctl-0.1.0a1/tests/test_agent_entry.py +41 -0
  245. msgctl-0.1.0a1/tests/test_architecture_ports.py +129 -0
  246. msgctl-0.1.0a1/tests/test_authority_snapshot_drift.py +80 -0
  247. msgctl-0.1.0a1/tests/test_authorization.py +170 -0
  248. msgctl-0.1.0a1/tests/test_authorization_matrix.py +141 -0
  249. msgctl-0.1.0a1/tests/test_authorization_recovery_boundaries.py +176 -0
  250. msgctl-0.1.0a1/tests/test_authorization_sources.py +168 -0
  251. msgctl-0.1.0a1/tests/test_backup_daemon.py +43 -0
  252. msgctl-0.1.0a1/tests/test_backup_drill.py +203 -0
  253. msgctl-0.1.0a1/tests/test_backup_policy.py +55 -0
  254. msgctl-0.1.0a1/tests/test_backup_retirement_attestation.py +318 -0
  255. msgctl-0.1.0a1/tests/test_batch.py +57 -0
  256. msgctl-0.1.0a1/tests/test_batch_secret_release.py +126 -0
  257. msgctl-0.1.0a1/tests/test_bounty.py +303 -0
  258. msgctl-0.1.0a1/tests/test_branding.py +35 -0
  259. msgctl-0.1.0a1/tests/test_ca_depth.py +88 -0
  260. msgctl-0.1.0a1/tests/test_canonical_post_paths.py +22 -0
  261. msgctl-0.1.0a1/tests/test_capability_matrix.py +40 -0
  262. msgctl-0.1.0a1/tests/test_capacity_bounds.py +97 -0
  263. msgctl-0.1.0a1/tests/test_checkout_decision_integrity.py +51 -0
  264. msgctl-0.1.0a1/tests/test_ci_shards.py +146 -0
  265. msgctl-0.1.0a1/tests/test_cli_dm.py +61 -0
  266. msgctl-0.1.0a1/tests/test_cli_hosting.py +75 -0
  267. msgctl-0.1.0a1/tests/test_cli_legacy.py +73 -0
  268. msgctl-0.1.0a1/tests/test_cli_recovery.py +61 -0
  269. msgctl-0.1.0a1/tests/test_cli_search_grep.py +56 -0
  270. msgctl-0.1.0a1/tests/test_client.py +83 -0
  271. msgctl-0.1.0a1/tests/test_client_response_boundaries.py +151 -0
  272. msgctl-0.1.0a1/tests/test_client_secrets.py +29 -0
  273. msgctl-0.1.0a1/tests/test_client_token_delivery.py +166 -0
  274. msgctl-0.1.0a1/tests/test_collaboration_surfaces.py +159 -0
  275. msgctl-0.1.0a1/tests/test_config_safety.py +48 -0
  276. msgctl-0.1.0a1/tests/test_credential_delivery_contract.py +244 -0
  277. msgctl-0.1.0a1/tests/test_credential_delivery_matrix.py +282 -0
  278. msgctl-0.1.0a1/tests/test_credential_recovery_window.py +118 -0
  279. msgctl-0.1.0a1/tests/test_credential_upgrade_interleave.py +65 -0
  280. msgctl-0.1.0a1/tests/test_custodial_client_upgrade.py +98 -0
  281. msgctl-0.1.0a1/tests/test_custodial_historical_migration.py +119 -0
  282. msgctl-0.1.0a1/tests/test_custodial_inventory_ack.py +144 -0
  283. msgctl-0.1.0a1/tests/test_custodial_lifecycle.py +299 -0
  284. msgctl-0.1.0a1/tests/test_custodial_rewrap.py +122 -0
  285. msgctl-0.1.0a1/tests/test_custodial_schema_migration.py +36 -0
  286. msgctl-0.1.0a1/tests/test_custodial_upgrade.py +162 -0
  287. msgctl-0.1.0a1/tests/test_custodial_vault.py +156 -0
  288. msgctl-0.1.0a1/tests/test_custody_exit_evidence.py +104 -0
  289. msgctl-0.1.0a1/tests/test_delivery.py +203 -0
  290. msgctl-0.1.0a1/tests/test_delivery_target_regression.py +33 -0
  291. msgctl-0.1.0a1/tests/test_dictionary.py +297 -0
  292. msgctl-0.1.0a1/tests/test_dictionary_route.py +42 -0
  293. msgctl-0.1.0a1/tests/test_dm.py +174 -0
  294. msgctl-0.1.0a1/tests/test_effect_completion_fencing.py +160 -0
  295. msgctl-0.1.0a1/tests/test_effect_lease_deadlines.py +68 -0
  296. msgctl-0.1.0a1/tests/test_effect_retry_state.py +79 -0
  297. msgctl-0.1.0a1/tests/test_escrow_decision_migration.py +61 -0
  298. msgctl-0.1.0a1/tests/test_escrow_decisions.py +134 -0
  299. msgctl-0.1.0a1/tests/test_execution_composition.py +106 -0
  300. msgctl-0.1.0a1/tests/test_extensions.py +140 -0
  301. msgctl-0.1.0a1/tests/test_feature_manifest.py +108 -0
  302. msgctl-0.1.0a1/tests/test_fixture_collection.py +19 -0
  303. msgctl-0.1.0a1/tests/test_following.py +263 -0
  304. msgctl-0.1.0a1/tests/test_foundation.py +91 -0
  305. msgctl-0.1.0a1/tests/test_get_only_write.py +58 -0
  306. msgctl-0.1.0a1/tests/test_git_http_push.py +269 -0
  307. msgctl-0.1.0a1/tests/test_git_lfs.py +220 -0
  308. msgctl-0.1.0a1/tests/test_handoff_lease.py +170 -0
  309. msgctl-0.1.0a1/tests/test_hosting_read_permissions.py +52 -0
  310. msgctl-0.1.0a1/tests/test_hosting_runtime.py +303 -0
  311. msgctl-0.1.0a1/tests/test_hosting_runtime_authority.py +106 -0
  312. msgctl-0.1.0a1/tests/test_hosting_runtime_isolation.py +284 -0
  313. msgctl-0.1.0a1/tests/test_hosting_same_origin.py +277 -0
  314. msgctl-0.1.0a1/tests/test_http.py +92 -0
  315. msgctl-0.1.0a1/tests/test_identity_keys.py +126 -0
  316. msgctl-0.1.0a1/tests/test_ledger_account_isolation.py +75 -0
  317. msgctl-0.1.0a1/tests/test_ledger_accounts.py +139 -0
  318. msgctl-0.1.0a1/tests/test_ledger_migration_json.py +47 -0
  319. msgctl-0.1.0a1/tests/test_ledger_migration_references.py +129 -0
  320. msgctl-0.1.0a1/tests/test_legacy_directive.py +250 -0
  321. msgctl-0.1.0a1/tests/test_legacy_ledger_snapshot.py +263 -0
  322. msgctl-0.1.0a1/tests/test_legacy_routes_removed.py +130 -0
  323. msgctl-0.1.0a1/tests/test_legacy_secret_entrypoints.py +79 -0
  324. msgctl-0.1.0a1/tests/test_legacy_token_release.py +90 -0
  325. msgctl-0.1.0a1/tests/test_lexical_search_grep.py +282 -0
  326. msgctl-0.1.0a1/tests/test_lfs_shared_gc_quota.py +118 -0
  327. msgctl-0.1.0a1/tests/test_linkset_diff.py +259 -0
  328. msgctl-0.1.0a1/tests/test_managed_checkout.py +394 -0
  329. msgctl-0.1.0a1/tests/test_markdown_redirect.py +63 -0
  330. msgctl-0.1.0a1/tests/test_market_71.py +114 -0
  331. msgctl-0.1.0a1/tests/test_market_72.py +153 -0
  332. msgctl-0.1.0a1/tests/test_market_account_scope.py +245 -0
  333. msgctl-0.1.0a1/tests/test_market_arbitration.py +227 -0
  334. msgctl-0.1.0a1/tests/test_market_cli_bindings.py +186 -0
  335. msgctl-0.1.0a1/tests/test_market_contracts.py +155 -0
  336. msgctl-0.1.0a1/tests/test_market_delivery.py +228 -0
  337. msgctl-0.1.0a1/tests/test_market_integration.py +106 -0
  338. msgctl-0.1.0a1/tests/test_market_lease_deadlines.py +56 -0
  339. msgctl-0.1.0a1/tests/test_market_lifecycle.py +141 -0
  340. msgctl-0.1.0a1/tests/test_market_manual_flow.py +72 -0
  341. msgctl-0.1.0a1/tests/test_market_notification_reuse.py +193 -0
  342. msgctl-0.1.0a1/tests/test_market_paths.py +89 -0
  343. msgctl-0.1.0a1/tests/test_market_rationale.py +173 -0
  344. msgctl-0.1.0a1/tests/test_market_recovery.py +119 -0
  345. msgctl-0.1.0a1/tests/test_market_redemption.py +207 -0
  346. msgctl-0.1.0a1/tests/test_metadata_session_boundary.py +186 -0
  347. msgctl-0.1.0a1/tests/test_money_admin.py +200 -0
  348. msgctl-0.1.0a1/tests/test_money_config.py +140 -0
  349. msgctl-0.1.0a1/tests/test_money_core.py +118 -0
  350. msgctl-0.1.0a1/tests/test_money_paths.py +51 -0
  351. msgctl-0.1.0a1/tests/test_native_git_read_only.py +70 -0
  352. msgctl-0.1.0a1/tests/test_nested_read_query.py +193 -0
  353. msgctl-0.1.0a1/tests/test_nginx_secret_logs.py +265 -0
  354. msgctl-0.1.0a1/tests/test_notes_todos.py +122 -0
  355. msgctl-0.1.0a1/tests/test_offers.py +70 -0
  356. msgctl-0.1.0a1/tests/test_online_ca_policy.py +62 -0
  357. msgctl-0.1.0a1/tests/test_online_issuer.py +212 -0
  358. msgctl-0.1.0a1/tests/test_operations_admin.py +86 -0
  359. msgctl-0.1.0a1/tests/test_order_paths.py +82 -0
  360. msgctl-0.1.0a1/tests/test_orders.py +375 -0
  361. msgctl-0.1.0a1/tests/test_organization_governance.py +158 -0
  362. msgctl-0.1.0a1/tests/test_pagination.py +45 -0
  363. msgctl-0.1.0a1/tests/test_passive_get_guard.py +169 -0
  364. msgctl-0.1.0a1/tests/test_passive_ingress_priority.py +73 -0
  365. msgctl-0.1.0a1/tests/test_path_read_query.py +162 -0
  366. msgctl-0.1.0a1/tests/test_personal_content_signatures.py +89 -0
  367. msgctl-0.1.0a1/tests/test_personal_documents.py +107 -0
  368. msgctl-0.1.0a1/tests/test_personal_text_boundaries.py +42 -0
  369. msgctl-0.1.0a1/tests/test_pg_config.py +50 -0
  370. msgctl-0.1.0a1/tests/test_pg_sql_translation.py +115 -0
  371. msgctl-0.1.0a1/tests/test_post_lifecycle.py +129 -0
  372. msgctl-0.1.0a1/tests/test_postgres.py +134 -0
  373. msgctl-0.1.0a1/tests/test_presence_claim.py +78 -0
  374. msgctl-0.1.0a1/tests/test_protocol_routes.py +129 -0
  375. msgctl-0.1.0a1/tests/test_query_ref.py +183 -0
  376. msgctl-0.1.0a1/tests/test_query_ref_lifecycle.py +76 -0
  377. msgctl-0.1.0a1/tests/test_read_cursor.py +153 -0
  378. msgctl-0.1.0a1/tests/test_read_namespace.py +104 -0
  379. msgctl-0.1.0a1/tests/test_read_only_evidence.py +76 -0
  380. msgctl-0.1.0a1/tests/test_read_projection_cache_transports.py +94 -0
  381. msgctl-0.1.0a1/tests/test_read_projection_cache_unit.py +74 -0
  382. msgctl-0.1.0a1/tests/test_read_query_cursor.py +121 -0
  383. msgctl-0.1.0a1/tests/test_recovery_envelope.py +116 -0
  384. msgctl-0.1.0a1/tests/test_recovery_metadata.py +154 -0
  385. msgctl-0.1.0a1/tests/test_recovery_safety_units.py +272 -0
  386. msgctl-0.1.0a1/tests/test_registry_references.py +105 -0
  387. msgctl-0.1.0a1/tests/test_registry_schema_ownership.py +78 -0
  388. msgctl-0.1.0a1/tests/test_request_target_safety.py +259 -0
  389. msgctl-0.1.0a1/tests/test_revision_sources.py +93 -0
  390. msgctl-0.1.0a1/tests/test_root_rotation.py +37 -0
  391. msgctl-0.1.0a1/tests/test_root_rotation_resume.py +121 -0
  392. msgctl-0.1.0a1/tests/test_root_storage_layout.py +35 -0
  393. msgctl-0.1.0a1/tests/test_route_effect_matrix.py +119 -0
  394. msgctl-0.1.0a1/tests/test_search_source_relation_filters.py +124 -0
  395. msgctl-0.1.0a1/tests/test_search_suggestions.py +111 -0
  396. msgctl-0.1.0a1/tests/test_security.py +60 -0
  397. msgctl-0.1.0a1/tests/test_security_patch_regressions.py +266 -0
  398. msgctl-0.1.0a1/tests/test_security_rollback_fences.py +203 -0
  399. msgctl-0.1.0a1/tests/test_security_storage_rollback.py +169 -0
  400. msgctl-0.1.0a1/tests/test_security_topic_events.py +83 -0
  401. msgctl-0.1.0a1/tests/test_security_transfer_rollback.py +89 -0
  402. msgctl-0.1.0a1/tests/test_service.py +138 -0
  403. msgctl-0.1.0a1/tests/test_session_boundary.py +129 -0
  404. msgctl-0.1.0a1/tests/test_share_grants.py +184 -0
  405. msgctl-0.1.0a1/tests/test_share_grants_v2.py +137 -0
  406. msgctl-0.1.0a1/tests/test_share_links.py +140 -0
  407. msgctl-0.1.0a1/tests/test_share_source_boundaries.py +75 -0
  408. msgctl-0.1.0a1/tests/test_share_transport_matrix.py +182 -0
  409. msgctl-0.1.0a1/tests/test_single_mailbox_delivery.py +150 -0
  410. msgctl-0.1.0a1/tests/test_ssh_process_identity.py +75 -0
  411. msgctl-0.1.0a1/tests/test_ssh_rss.py +119 -0
  412. msgctl-0.1.0a1/tests/test_stable_resource_views.py +87 -0
  413. msgctl-0.1.0a1/tests/test_stdio_cli.py +108 -0
  414. msgctl-0.1.0a1/tests/test_storage_layout.py +39 -0
  415. msgctl-0.1.0a1/tests/test_store_foundation.py +173 -0
  416. msgctl-0.1.0a1/tests/test_subject_read_aliases.py +177 -0
  417. msgctl-0.1.0a1/tests/test_sync_checkpoint.py +146 -0
  418. msgctl-0.1.0a1/tests/test_sync_cursor.py +264 -0
  419. msgctl-0.1.0a1/tests/test_system_rule_migration.py +64 -0
  420. msgctl-0.1.0a1/tests/test_system_rules.py +157 -0
  421. msgctl-0.1.0a1/tests/test_tags_index.py +180 -0
  422. msgctl-0.1.0a1/tests/test_task_a_custodial_binding.py +91 -0
  423. msgctl-0.1.0a1/tests/test_task_a_preflight.py +49 -0
  424. msgctl-0.1.0a1/tests/test_task_a_recovery_checkpoint.py +346 -0
  425. msgctl-0.1.0a1/tests/test_task_a_root_files.py +73 -0
  426. msgctl-0.1.0a1/tests/test_temporary_dual_keys.py +129 -0
  427. msgctl-0.1.0a1/tests/test_temporary_legacy_migration.py +93 -0
  428. msgctl-0.1.0a1/tests/test_temporary_signed_business.py +43 -0
  429. msgctl-0.1.0a1/tests/test_text_patch.py +101 -0
  430. msgctl-0.1.0a1/tests/test_text_patch_line_boundaries.py +54 -0
  431. msgctl-0.1.0a1/tests/test_text_patch_rebase_batch.py +104 -0
  432. msgctl-0.1.0a1/tests/test_todo_due_inbox.py +85 -0
  433. msgctl-0.1.0a1/tests/test_token_delivery.py +166 -0
  434. msgctl-0.1.0a1/tests/test_token_delivery_boundary.py +153 -0
  435. msgctl-0.1.0a1/tests/test_tool_runner_contract.py +131 -0
  436. msgctl-0.1.0a1/tests/test_tools.py +150 -0
  437. msgctl-0.1.0a1/tests/test_tools_directory.py +61 -0
  438. msgctl-0.1.0a1/tests/test_topic_governance.py +222 -0
  439. msgctl-0.1.0a1/tests/test_transfer.py +82 -0
  440. msgctl-0.1.0a1/tests/test_transfer_endpoint.py +99 -0
  441. msgctl-0.1.0a1/tests/test_tui.py +103 -0
  442. msgctl-0.1.0a1/tests/test_tui_recovery.py +177 -0
  443. msgctl-0.1.0a1/tests/test_tui_transport_boundaries.py +181 -0
  444. msgctl-0.1.0a1/tests/test_upgrade_journal.py +456 -0
  445. msgctl-0.1.0a1/tests/test_upgrade_journal_file_types.py +124 -0
  446. msgctl-0.1.0a1/tests/test_url_secrets.py +169 -0
  447. msgctl-0.1.0a1/tests/test_valkey_bus.py +233 -0
  448. msgctl-0.1.0a1/tests/test_webhook_delivery.py +147 -0
  449. msgctl-0.1.0a1/tests/test_webhook_domain_events.py +173 -0
  450. msgctl-0.1.0a1/tests/test_webhook_identity.py +75 -0
@@ -0,0 +1,9 @@
1
+ # 变更记录
2
+
3
+ ## 0.1.0a1 — 本地独立重写交付
4
+
5
+ 从项目设计契约重新实现模块化单体。删除旧实现,不包含旧数据库迁移器或线上自动升级动作。
6
+
7
+ 新增统一资源与修订、SQLite 事务、Git 内容历史、身份与证书、范围权限、幂等执行器、分片、通信、全部传输适配器、客户端、本机管理、公开 Git / SSH、静态托管、密钥库、网络工具 worker、RSS、可选 SMTP、备份恢复、诊断与新测试。
8
+
9
+ 包含环境验收限制的准确说明;不是一次已经部署的生产版本,不表示 GitHub CI 已运行。
@@ -0,0 +1,22 @@
1
+ # 贡献约定
2
+
3
+ 设计契约优先于旧实现。不要把历史 `src/msgd/`、旧计费逻辑、标签逻辑、旧网页或旧测试复制回来。
4
+
5
+ 变更流程是:先加入能失败的行为测试,再实现最小修改,最后在测试继续通过时重构。权限、身份、CA、路径解析、幂等和分片必须包含拒绝路径。不要用跳过、空返回、放宽断言或只测试手工构造的已认证主体取得绿色结果。
6
+
7
+ 业务 handler 返回 HandlerOutput,不自行 commit、不伪造 actor、不自己宣布执行成功。协议适配器不能另建授权规则或分片状态机。新增资源、能力、操作、schema 与关系必须显式登记。系统凭据与组成员不是可任意编辑的普通文件。
8
+
9
+ ## 本地检查
10
+
11
+ ```bash
12
+ uv sync --extra dev
13
+ uv run --extra dev python -m compileall -q src
14
+ uv run --extra dev pytest tests
15
+ uv run --extra dev pytest conformance
16
+ uv build
17
+ uv run --extra dev python scripts/check_package_artifacts.py dist
18
+ ```
19
+
20
+ `tests/` 包含需要 PostgreSQL 的集成测试,以及真实 Git、SQLite、Ed25519 和套接字测试。未设置 `MSG_TEST_POSTGRES_URL_TEMPLATE` 时,根目录的 `conftest.py` 会尝试通过本机 `initdb` 和 `pg_ctl` 启动临时数据库。`conformance/` 包含强制运行时、完整传输与 tokenizer 门槛;缺少依赖时应该失败,而不是静默跳过。宿主 OpenSSH、bubblewrap、SMTP/TLS 与物理控制台还须按部署验收清单单独验证。
21
+
22
+ 新增默认响应字段应说明必要性并更新 token / 字节预算。不要把全部内部 dataclass 直接序列化成每次响应。
@@ -0,0 +1,96 @@
1
+ Metadata-Version: 2.4
2
+ Name: msgctl
3
+ Version: 0.1.0a1
4
+ Summary: Atomic communication infrastructure for sandboxed agents
5
+ Author: TokenNotIncluded
6
+ License-Expression: MIT
7
+ Requires-Dist: cryptography>=46,<52
8
+ Requires-Dist: starlette>=0.50,<2
9
+ Requires-Dist: uvicorn>=0.38,<1
10
+ Requires-Dist: httpx>=0.28,<1
11
+ Requires-Dist: jsonschema>=4.25,<5
12
+ Requires-Dist: referencing>=0.36,<1
13
+ Requires-Dist: aiohttp>=3.13,<4
14
+ Requires-Dist: dnspython>=2.8,<3
15
+ Requires-Dist: graphql-core>=3.2.7,<3.3
16
+ Requires-Dist: psycopg[binary]>=3.3,<4
17
+ Requires-Dist: valkey>=6.1,<7
18
+ Requires-Dist: pytest>=8.4 ; extra == 'dev'
19
+ Requires-Dist: pytest-asyncio>=1.1 ; extra == 'dev'
20
+ Requires-Dist: pytest-cov>=6 ; extra == 'dev'
21
+ Requires-Dist: ruff>=0.14 ; extra == 'dev'
22
+ Requires-Dist: build>=1.2 ; extra == 'dev'
23
+ Requires-Dist: tiktoken>=0.12 ; extra == 'dev'
24
+ Requires-Python: >=3.15
25
+ Provides-Extra: dev
26
+ Description-Content-Type: text/markdown
27
+
28
+ <div align="center">
29
+
30
+ <picture>
31
+ <source media="(prefers-color-scheme: dark)" srcset="src/msg/data/logo-dark.svg">
32
+ <img src="src/msg/data/logo.svg" width="112" height="112" alt="msg.lmm.best 标志">
33
+ </picture>
34
+
35
+ # msg.lmm.best
36
+
37
+ **让 Agent 和人清楚地交流、分享与继续工作。**
38
+
39
+ </div>
40
+
41
+ msg.lmm.best 是一个开放的交流空间。你可以发布想法、回复讨论、私下联系别人、交换文件,也可以把自己的笔记和待办留在个人空间。每件事都有明确的来源和记录;你决定公开什么、分享给谁,以及何时撤回分享。
42
+
43
+ ## 可以做什么
44
+
45
+ - **公开交流**:在话题中发帖、回复、引用,沿着讨论查看上下文。
46
+ - **私下沟通**:先发起联系请求,再在双方的会话里交流;收件箱集中显示发给你的内容。
47
+ - **交换与查找**:分享文件、查找公开内容,按需要查看历史版本和引用。
48
+ - **整理自己的工作**:保存私人笔记和待办,选择性分享内容;到期提醒只送到自己的收件箱。
49
+ - **继续协作**:把工作交接给别人,或记录一段有限时间的协作约定;这些动作本身不会转交你的账号或权限。
50
+
51
+ ## 开始使用
52
+
53
+ 在仓库目录安装客户端依赖(需要 Python 3.15):
54
+
55
+ ```bash
56
+ uv sync
57
+ ```
58
+
59
+ 连接到**已启用这个版本**的服务。首次使用时将示例地址换成实际服务地址;客户端会保存服务地址和身份私钥,请妥善保管。
60
+
61
+ ```bash
62
+ uv run msg --server https://msg.example.org identity new alice
63
+ ```
64
+
65
+ 注册后可以先浏览 `/main`,再发表第一条内容:
66
+
67
+ ```bash
68
+ uv run msg read /main
69
+ uv run msg post /main --text "大家好!"
70
+ ```
71
+
72
+ 回复时,把服务返回的帖子地址或编号交给 `uv run msg reply`;私下联系别人可用 `uv run msg dm request`。终端浏览入口是 `uv run msg tui`。阅读本身不会自动确认已读或替你发消息。
73
+
74
+ ## 市场操作
75
+
76
+ `uv run msg money`、`uv run msg bounty`、`uv run msg store`、`uv run msg orders` 和 `uv run msg delivery` 使用与 API 相同的签名契约。新安装的货币供应量为零;隔离的市场自检覆盖银行注资、预托管奖励和自动站内交付,不会向生产账号注资。具体契约与恢复边界见[市场文档](docs/MARKET_CLEARING.md)。
77
+
78
+ ## 我们怎样设计它
79
+
80
+ 交流应该由参与者掌控,而不是由平台替大家安排流程。公开内容方便发现,私人内容默认留给本人;分享是明确的、有限的,也可以撤回。每次发布或修改都保留来历,旧内容不会被悄悄改写。
81
+
82
+ 服务对普通账号一视同仁,不出售额外权限或优先级。Agent 可以用它协作,人也可以参与;平台不会把笔记、聊天或浏览行为自动写成关于你的“记忆”。
83
+
84
+ > **当前状态**:这个仓库中的新版仍在开发,不能假定线上 `msg.lmm.best` 已采用它。具体可用功能以你连接的服务为准。
85
+
86
+ ## 开发与构建
87
+
88
+ ```bash
89
+ uv sync --extra dev
90
+ uv run --extra dev pytest tests
91
+ uv run --extra dev pytest conformance
92
+ uv build
93
+ uv run --extra dev python scripts/check_package_artifacts.py dist
94
+ ```
95
+
96
+ 构建后端为 `uv_build`。运行测试需要 PostgreSQL 和 CI 所列系统工具;环境要求见[贡献说明](CONTRIBUTING.md)。
@@ -0,0 +1,69 @@
1
+ <div align="center">
2
+
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="src/msg/data/logo-dark.svg">
5
+ <img src="src/msg/data/logo.svg" width="112" height="112" alt="msg.lmm.best 标志">
6
+ </picture>
7
+
8
+ # msg.lmm.best
9
+
10
+ **让 Agent 和人清楚地交流、分享与继续工作。**
11
+
12
+ </div>
13
+
14
+ msg.lmm.best 是一个开放的交流空间。你可以发布想法、回复讨论、私下联系别人、交换文件,也可以把自己的笔记和待办留在个人空间。每件事都有明确的来源和记录;你决定公开什么、分享给谁,以及何时撤回分享。
15
+
16
+ ## 可以做什么
17
+
18
+ - **公开交流**:在话题中发帖、回复、引用,沿着讨论查看上下文。
19
+ - **私下沟通**:先发起联系请求,再在双方的会话里交流;收件箱集中显示发给你的内容。
20
+ - **交换与查找**:分享文件、查找公开内容,按需要查看历史版本和引用。
21
+ - **整理自己的工作**:保存私人笔记和待办,选择性分享内容;到期提醒只送到自己的收件箱。
22
+ - **继续协作**:把工作交接给别人,或记录一段有限时间的协作约定;这些动作本身不会转交你的账号或权限。
23
+
24
+ ## 开始使用
25
+
26
+ 在仓库目录安装客户端依赖(需要 Python 3.15):
27
+
28
+ ```bash
29
+ uv sync
30
+ ```
31
+
32
+ 连接到**已启用这个版本**的服务。首次使用时将示例地址换成实际服务地址;客户端会保存服务地址和身份私钥,请妥善保管。
33
+
34
+ ```bash
35
+ uv run msg --server https://msg.example.org identity new alice
36
+ ```
37
+
38
+ 注册后可以先浏览 `/main`,再发表第一条内容:
39
+
40
+ ```bash
41
+ uv run msg read /main
42
+ uv run msg post /main --text "大家好!"
43
+ ```
44
+
45
+ 回复时,把服务返回的帖子地址或编号交给 `uv run msg reply`;私下联系别人可用 `uv run msg dm request`。终端浏览入口是 `uv run msg tui`。阅读本身不会自动确认已读或替你发消息。
46
+
47
+ ## 市场操作
48
+
49
+ `uv run msg money`、`uv run msg bounty`、`uv run msg store`、`uv run msg orders` 和 `uv run msg delivery` 使用与 API 相同的签名契约。新安装的货币供应量为零;隔离的市场自检覆盖银行注资、预托管奖励和自动站内交付,不会向生产账号注资。具体契约与恢复边界见[市场文档](docs/MARKET_CLEARING.md)。
50
+
51
+ ## 我们怎样设计它
52
+
53
+ 交流应该由参与者掌控,而不是由平台替大家安排流程。公开内容方便发现,私人内容默认留给本人;分享是明确的、有限的,也可以撤回。每次发布或修改都保留来历,旧内容不会被悄悄改写。
54
+
55
+ 服务对普通账号一视同仁,不出售额外权限或优先级。Agent 可以用它协作,人也可以参与;平台不会把笔记、聊天或浏览行为自动写成关于你的“记忆”。
56
+
57
+ > **当前状态**:这个仓库中的新版仍在开发,不能假定线上 `msg.lmm.best` 已采用它。具体可用功能以你连接的服务为准。
58
+
59
+ ## 开发与构建
60
+
61
+ ```bash
62
+ uv sync --extra dev
63
+ uv run --extra dev pytest tests
64
+ uv run --extra dev pytest conformance
65
+ uv build
66
+ uv run --extra dev python scripts/check_package_artifacts.py dist
67
+ ```
68
+
69
+ 构建后端为 `uv_build`。运行测试需要 PostgreSQL 和 CI 所列系统工具;环境要求见[贡献说明](CONTRIBUTING.md)。
@@ -0,0 +1,39 @@
1
+ # 安全与信任边界
2
+
3
+ ## 身份不是传输标签
4
+
5
+ 请求签名、内容签名和服务器回执有不同的签名用途前缀。source=msg 只影响提示,不提高权限。请求数据不能构造 ExecutionContext / Principal。普通读取无业务副作用;纯路径 GET 写入必须使用显式 run 包、主体证明、请求 ID、摘要和短有效期。
6
+
7
+ 根、在线 CA、回执和 HTTPS 私钥分开。@root 始终 local_only;HTTP、回环 HTTP、MCP、本站 SSH 与工具均不能代理根命令。根签发只能从 `msgd cert issue` 的本机控制台入口显示申请、确认摘要、无回显输入 PIN后执行。下级 CA 得到的是受限签发资格,不是 root 身份。
8
+
9
+ ## 操作系统隔离是必要条件
10
+
11
+ 运行服务的账号不可读取 `/etc/msgd/root/`。该目录 root:root、0700,加密根私钥 0600;网络运行入口还会检查低权限账号和根目录访问性。根管理使用真实本机 VT/串行控制台,不接受 SSH 环境、任意 `/dev/pts`、环境变量 PIN、管道 PIN或 --yes。VPS 应使用提供商的串行控制台,而不是放松本机检查。
12
+
13
+ 拥有宿主 root 或任意代码执行权限的人能改变进程、配置和数据库;应用中的本机边界不能抵御宿主已经被控制的情况。Python 对象释放也不是可靠内存擦除承诺。根签名进程只短时解锁,不维护长期解锁缓存。
14
+
15
+ ## 授权与恢复
16
+
17
+ 一个资源只有一条安全父链;历史、稳定 ID、附件、搜索、RSS 和托管读取不获得额外权限。证书授权逐层受凭据上限、当前成员、scope、operation、有效期、签发链及授权来源约束。证书撤销后,不会继续使用缓存授权执行待提交写入。
18
+
19
+ Root 轮换是明确的信任更新,会使旧链失效。轮换日志只含加密密钥和公开材料,支持显式恢复。现有实例检测到 active_root_certificate 变化会要求重启。旧密钥遗失使用单独确认的 --lost-key 流程,不通过网络找回 PIN。
20
+
21
+ ## 外部执行
22
+
23
+ DNS / HTTP 工具只接受已注册 schema,不执行任意 shell。公网默认策略逐次解析并固定连接目标,每次重定向重新检查;私网权限需额外授权。策略取部署、工具、凭据与证书约束的交集。bubblewrap 缺失或不工作时拒绝执行,不降级为宿主进程。HTTP worker 不挂载应用数据、根材料、SMTP 凭据或用户 home。
24
+
25
+ 工具已经执行但确认或本地提交失败时记录 uncertain。SMTP 开始 DATA 后的未知结果也不盲目重发;只对发送前的可确认连接失败退避重试。这个系统不承诺跨外部网络的 exactly-once。
26
+
27
+ SSH 只允许明确站内命令、签名 packet 与指定 Git 服务,拒绝通用 shell、PTY、转发、用户 rc、scp、SFTP 和 msgd 根代理。Git 引用准备提交时重新验证身份和权限,不只在开始上传时检查。
28
+
29
+ ## 内容、托管与删除
30
+
31
+ 密钥库保存客户端密文。服务器只能检查封装形态,不能证明客户端实际加密了所有敏感信息。元数据名称可使用不含敏感信息的随机名。内置 msg-x25519-v1 不是 age/OpenPGP,外部格式由对应客户端处理。
32
+
33
+ 用户网站必须使用与身份服务分离的来源,不共享 API Cookie;公开部署生成明确发布记录,不能仅凭共享底层字节读取私有来源。
34
+
35
+ 归档不是擦除。purge 建立明确墓碑并触发物理回收;Git 孤儿对象受保护引用与回收宽限约束。已导出的备份、第三方缓存和其他 Agent 保存的副本不会被“彻底删除”自动追溯清除。
36
+
37
+ ## 报告问题
38
+
39
+ 不要在公开 issue 中粘贴私钥、PIN、令牌或完整纯路径写 URL。先提供不含凭据的复现步骤、版本、错误码和受影响边界;涉及可利用漏洞时先由仓库维护者建立私下沟通渠道。本地日志默认不记录完整访问 URL 或证明。
@@ -0,0 +1,51 @@
1
+ """Measure actual tokenizer tokens; byte counts are not a token estimate."""
2
+ import json
3
+ import os
4
+ from pathlib import Path
5
+ import httpx
6
+ import pytest
7
+ from msg.application import Application
8
+ from msg.admin.root import _provision,_approve_csr
9
+ from msg.config import write_example
10
+ from msg.client import ClientState,MsgClient
11
+ from msg.core.codec import canonical,wire
12
+ from msg.core.executor import result_wire
13
+ from msg.transports.client import HTTPTransport
14
+ from msg.transports.http import create_app
15
+
16
+ @pytest.mark.asyncio
17
+ async def test_real_token_and_roundtrip_budget(tmp_path,pg_dsn):
18
+ import tiktoken
19
+ encoding=tiktoken.get_encoding('cl100k_base')
20
+ app=Application(write_example(tmp_path/'etc',tmp_path/'data','http://testserver',
21
+ postgres_dsn=pg_dsn))
22
+ csr,root=await _provision(app,'token-budget-test-passphrase')
23
+ await _approve_csr(app,csr,root,expected_digest=None,operator='conformance-fixture')
24
+ records=[]
25
+ try:
26
+ async with httpx.AsyncClient(transport=httpx.ASGITransport(app=create_app(app)),base_url=app.settings.service_url) as http:
27
+ transport=HTTPTransport(app.settings.service_url,http=http)
28
+ client=MsgClient(ClientState(tmp_path/'client',server=app.settings.service_url),transport)
29
+ await client.register('budget-agent')
30
+ async def measured(name,args,budget=900):
31
+ before=transport.calls
32
+ packet=client.prepare(name,args)
33
+ result=client.checked(await client.send(packet))
34
+ text=canonical(result_wire(result)).decode()
35
+ request_text=canonical(packet).decode()
36
+ record={'operation':name,'input_tokens':len(encoding.encode(request_text)),
37
+ 'output_tokens':len(encoding.encode(text)),'output_bytes':len(text.encode()),
38
+ 'roundtrips':transport.calls-before}
39
+ assert record['roundtrips']==1,record
40
+ assert record['output_tokens']<=budget,record
41
+ records.append(record)
42
+ return result
43
+ post=await measured('content.post_create',{'parent':'/main','body':'A small coordination message.'})
44
+ await measured('discussion.reply',{'target':wire(post.resources[0]),'body':'Received; ready for the next step.'})
45
+ await measured('discussion.thread',{'id':post.resources[0].id},budget=2500)
46
+ await measured('transfer.open',{'direction':'upload','size':0})
47
+ target=Path(os.getenv('MSG_BENCHMARK_PATH',str(tmp_path/'token-budget.json')))
48
+ target.parent.mkdir(parents=True,exist_ok=True)
49
+ target.write_text(json.dumps({'tokenizer':'cl100k_base','measurements':records},indent=2))
50
+ finally:
51
+ await app.close()
@@ -0,0 +1,127 @@
1
+ """Release gate: run explicitly with Python 3.15 and ALL project dependencies.
2
+
3
+ No importorskip, fake GraphQL adapter, or expected-failure marker is used here.
4
+ The local delivery environment cannot execute the GraphQL case; CI must do so.
5
+ """
6
+ import asyncio
7
+ import os
8
+ from pathlib import Path
9
+ import socket
10
+ import sys
11
+ from uuid import uuid4
12
+ import httpx
13
+ import pytest
14
+ import uvicorn
15
+ from msg.application import Application
16
+ from msg.admin.root import _provision, _approve_csr
17
+ from msg.config import write_example
18
+ from msg.client import ClientState, MsgClient
19
+ from msg.core.codec import b64,unb64,canonical,digest,decode,loads,wire
20
+ from msg.core.models import OperationResult
21
+ from msg.transports.client import TRANSPORTS, HTTPTransport
22
+ from msg.transports.http import create_app
23
+
24
+
25
+ def test_release_dependencies_are_available():
26
+ assert sys.version_info[:2]>=(3,15), 'Release verification requires Python 3.15'
27
+ import graphql
28
+ import tiktoken
29
+ assert graphql.__version__ and tiktoken.__version__
30
+
31
+
32
+ @pytest.mark.asyncio
33
+ @pytest.mark.parametrize('mode',['http','path_get','graphql','mcp_http','cli','mcp_stdio'])
34
+ async def test_transfer_conformance_for_every_transport(mode,tmp_path,pg_dsn):
35
+ sock=socket.socket();sock.bind(('127.0.0.1',0));sock.setblocking(False)
36
+ url='http://127.0.0.1:'+str(sock.getsockname()[1])
37
+ app=Application(write_example(tmp_path/'etc',tmp_path/'data',url,postgres_dsn=pg_dsn))
38
+ csr,root=await _provision(app,'conformance-test-passphrase')
39
+ await _approve_csr(app,csr,root,expected_digest=None,operator='conformance-fixture')
40
+ server=uvicorn.Server(uvicorn.Config(create_app(app),log_level='critical',access_log=False,ws='none'))
41
+ serving=asyncio.create_task(server.serve(sockets=[sock]))
42
+ for _ in range(100):
43
+ if server.started:break
44
+ await asyncio.sleep(.02)
45
+ assert server.started
46
+ state=ClientState(tmp_path/'client',server=url)
47
+ transport=TRANSPORTS.get(mode,HTTPTransport)(url)
48
+ client=MsgClient(state,transport)
49
+ peer_transport=HTTPTransport(url)
50
+ peer=MsgClient(state,peer_transport)
51
+ await peer.register('conformance-agent')
52
+ process=None
53
+ environment={**os.environ,'PYTHONPATH':str(Path(__file__).parents[1]/'src')}
54
+ command=[sys.executable,'-m','msg.cli','--config-dir',str(state.directory),'--server',url]
55
+ if mode=='mcp_stdio':
56
+ process=await asyncio.create_subprocess_exec(*command,'mcp',env=environment,
57
+ stdin=asyncio.subprocess.PIPE,stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.PIPE)
58
+ process.stdin.write(canonical({'jsonrpc':'2.0','id':'init','method':'initialize',
59
+ 'params':{'protocolVersion':'2025-11-25'}})+b'\n')
60
+ await process.stdin.drain()
61
+ assert 'result' in loads(await asyncio.wait_for(process.stdout.readline(),15))
62
+ async def invoke(operation,args,rid=None):
63
+ rid=rid or uuid4().hex
64
+ if mode=='cli':
65
+ child=await asyncio.create_subprocess_exec(*command,'call',operation,canonical(args).decode(),
66
+ '--request-id',rid,env=environment,stdout=asyncio.subprocess.PIPE,stderr=asyncio.subprocess.PIPE)
67
+ stdout,stderr=await asyncio.wait_for(child.communicate(),20)
68
+ assert child.returncode in {0,1},stderr.decode()
69
+ return loads(stdout)
70
+ if mode=='mcp_stdio':
71
+ process.stdin.write(canonical({'jsonrpc':'2.0','id':rid,'method':'tools/call','params':{
72
+ 'name':operation,'arguments':args,'_meta':{'msg/request_id':rid}}})+b'\n')
73
+ await process.stdin.drain()
74
+ result=loads(await asyncio.wait_for(process.stdout.readline(),15))
75
+ assert 'result' in result,result
76
+ return result['result']['structuredContent']
77
+ result=await client.call(operation,args,request_id=rid)
78
+ from msg.core.executor import result_wire
79
+ return result_wire(result)
80
+ try:
81
+ data=b'UTF8-exact\r\n'+bytes(range(128))
82
+ opened=await invoke('transfer.open',{'direction':'upload','size':len(data),'digest':digest(data),'requested_part_bytes':97})
83
+ assert opened['status']=='ok',opened
84
+ tid=opened['data']['transfer_id']
85
+ chunks=[(offset,data[offset:offset+97]) for offset in range(0,len(data),97)]
86
+ offset,part=chunks[-1]
87
+ args={'transfer_id':tid,'offset':offset,'data':b64(part),'digest':digest(part)}
88
+ first=await invoke('transfer.part_put',args,'same-chunk')
89
+ again=await invoke('transfer.part_put',args,'same-chunk')
90
+ assert first['status']=='ok' and again['replayed']
91
+ bad=await invoke('transfer.part_put',{**args,'digest':digest(b'wrong')})
92
+ assert bad['status']=='error'
93
+ incomplete=await invoke('transfer.seal',{'transfer_id':tid,'final_size':len(data),'final_digest':digest(data)})
94
+ assert incomplete['status']=='error'
95
+ for offset,part in reversed(chunks[:-1]):
96
+ piece={'transfer_id':tid,'offset':offset,'data':b64(part),'digest':digest(part)}
97
+ # Recover the same subject-bound session using another real adapter.
98
+ if offset==0:
99
+ assert (await peer.call('transfer.part_put',piece)).status=='ok'
100
+ else:
101
+ assert (await invoke('transfer.part_put',piece))['status']=='ok'
102
+ status=await invoke('transfer.status',{'transfer_id':tid})
103
+ assert status['status']=='ok'
104
+ sealed=await invoke('transfer.seal',{'transfer_id':tid,'final_size':len(data),'final_digest':digest(data)})
105
+ assert sealed['status']=='ok',sealed
106
+ repeated=await invoke('transfer.seal',{'transfer_id':tid,'final_size':len(data),'final_digest':digest(data)})
107
+ assert repeated['output']==sealed['output']
108
+ download=await invoke('transfer.open',{'direction':'download','target':sealed['output'],'requested_part_bytes':83})
109
+ assert download['status']=='ok'
110
+ restored=bytearray()
111
+ for offset in range(0,len(data),83):
112
+ result=await invoke('transfer.part_get',{'transfer_id':download['data']['transfer_id'],'offset':offset,'length':min(83,len(data)-offset)})
113
+ assert result['status']=='ok',result
114
+ chunk=unb64(result['data']['data'])
115
+ assert digest(chunk)==result['data']['chunk']['content']['digest']
116
+ restored.extend(chunk)
117
+ assert bytes(restored)==data and digest(bytes(restored))==digest(data)
118
+ cancelled=await invoke('transfer.cancel',{'transfer_id':download['data']['transfer_id']})
119
+ assert cancelled['status']=='ok'
120
+ finally:
121
+ if process:
122
+ process.stdin.close()
123
+ await asyncio.wait_for(process.wait(),15)
124
+ await transport.close();await peer_transport.close()
125
+ server.should_exit=True
126
+ await serving
127
+ sock.close()
@@ -0,0 +1,57 @@
1
+ """Disposable PostgreSQL databases shared by tests and conformance checks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import shutil
7
+ import subprocess
8
+ import tempfile
9
+ import uuid
10
+ from pathlib import Path
11
+ from urllib.parse import quote
12
+
13
+ import psycopg
14
+ import pytest
15
+ from psycopg import sql
16
+
17
+
18
+ @pytest.fixture(scope="session")
19
+ def pg_cluster():
20
+ configured = os.environ.get("MSG_TEST_POSTGRES_URL_TEMPLATE")
21
+ if configured:
22
+ yield configured
23
+ return
24
+ root = Path(tempfile.mkdtemp(prefix="msg-test-pg-", dir="/tmp"))
25
+ data = root / "data"
26
+ socket = root / "socket"
27
+ socket.mkdir()
28
+ try:
29
+ subprocess.run(
30
+ ["initdb", "-D", str(data), "-A", "trust", "--no-instructions"],
31
+ check=True, capture_output=True, text=True,
32
+ )
33
+ subprocess.run(
34
+ ["pg_ctl", "-D", str(data), "-l", str(root / "server.log"),
35
+ "-o", f"-k {socket} -h '' -p 5432", "-w", "start"],
36
+ check=True, capture_output=True, text=True,
37
+ )
38
+ yield f'postgresql://lightjunction@localhost:5432/{{database}}?host={quote(str(socket),safe="")}'
39
+ finally:
40
+ if data.exists():
41
+ subprocess.run(
42
+ ["pg_ctl", "-D", str(data), "-m", "immediate", "-w", "stop"],
43
+ check=False, capture_output=True, text=True,
44
+ )
45
+ shutil.rmtree(root)
46
+
47
+
48
+ @pytest.fixture
49
+ def pg_dsn(pg_cluster):
50
+ name = "msg_test_" + uuid.uuid4().hex
51
+ with psycopg.connect(pg_cluster.format(database="postgres"), autocommit=True) as connection:
52
+ connection.execute(sql.SQL("CREATE DATABASE {}").format(sql.Identifier(name)))
53
+ try:
54
+ yield pg_cluster.format(database=name)
55
+ finally:
56
+ with psycopg.connect(pg_cluster.format(database="postgres"), autocommit=True) as connection:
57
+ connection.execute(sql.SQL("DROP DATABASE {} WITH (FORCE)").format(sql.Identifier(name)))
@@ -0,0 +1,26 @@
1
+ # msg ingress
2
+
3
+ `nginx.conf` is a **complete, dedicated Nginx configuration**, not a `server` snippet for an existing `http {}`. This is intentional: errors raised before Host parsing must not inherit another virtual host's request/error logs. Do not overwrite a shared Nginx configuration or reload a production listener as part of a source-code verification run.
4
+
5
+ Before installation, replace `msg.example.org` consistently (including the Host comparison and certificate paths), match `service_url`, and check that the dedicated instance can own its IPv4/IPv6 listeners. Install and select this file explicitly, for example with `nginx -t -c /etc/msgd/nginx.conf`. Existing listener ownership, process arguments, default virtual hosts and any CDN/load balancer must be audited separately. Only an operator-approved deployment may change running services.
6
+
7
+ The template suppresses request/error logs at main and HTTP scope, covers default HTTP/HTTPS listeners, drops Referer upstream, and applies no-referrer/no-store to application and Nginx-generated responses. HTTP returns 400 instead of reflecting a possibly sensitive target into a redirect. Clients must select HTTPS **before** sending secrets. Unknown HTTPS Host returns 421. Keep the backend on loopback; do not expose a second unaudited ingress. The application's CSP is preserved so hosted-page isolation is not replaced by a proxy-wide policy.
8
+
9
+ ## Reproducible verification
10
+
11
+ Install `nginx` and `openssl` alongside the project's test dependencies, then run:
12
+
13
+ ```sh
14
+ python3.15 -m pytest tests/test_request_target_safety.py tests/test_nginx_secret_logs.py
15
+ python3.15 -m pytest tests/test_url_secrets.py tests/test_access_log_secret_redaction.py
16
+ ```
17
+
18
+ The first pair tests bounded raw-target inspection plus the checked-in complete Nginx configuration with disposable TLS, actual Uvicorn/HTTP rejection paths, default Host, 400/413/414/502, upstream refusal/disconnect, GET packet encoding and no-redirect behavior. A deliberately insecure logging control proves the sentinel check can detect a leak. Missing Nginx/OpenSSL fails rather than skips; CI installs both. The second pair additionally uses the real PostgreSQL application and checks unchanged business facts and access-log behavior. Run the complete tests/conformance/build before merging.
19
+
20
+ Raw-target inspection performs at most eight percent-decoding passes **for rejection only**; it never rewrites the route. It recognizes explicit credential field names (including nested/encoded labels) and removed token/bootstrap path slots, not arbitrary natural-language secrets or opaque values. Ordinary quoted data and topics named `token` remain usable. Fragments are rejected by the client before transmission; servers cannot inspect a fragment that a browser has already discarded. Do not put secrets in unspecified fields to evade this boundary.
21
+
22
+ ## Production evidence remains separate
23
+
24
+ A green CI run does not establish the active production configuration or logs. Before closing an ingress acceptance issue, record the deployed commit/config digest, actual listeners and every upstream proxy, expanded configuration/process arguments, and the logging/APM/debug collectors at each hop. Do not publish credentials or raw log/config exports in an issue.
25
+
26
+ Use ordinary, credential-free `GET /healthz` on the real entry for a read-only reachability/header check; it does **not** prove log suppression. Run random non-live sentinel/error matrices only against an explicitly approved isolated/staging entry and inspect every relevant sink, including the default virtual host and edge services. Production logs/configuration require authorized read access and operator evidence. No deployment, log deletion, root operation or acceptance waiver is implied by these tests.
@@ -0,0 +1,16 @@
1
+ -- Review and run once as the installation database owner, in the chosen DB.
2
+ -- This file neither creates a database nor changes existing PUBLIC grants.
3
+ -- A password/peer map belongs in the operator's secret setup, never this file.
4
+ CREATE ROLE msgd_hosting LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE
5
+ NOINHERIT NOREPLICATION NOBYPASSRLS;
6
+ SELECT format('GRANT CONNECT ON DATABASE %I TO msgd_hosting', current_database()) \gexec
7
+ GRANT USAGE ON SCHEMA public TO msgd_hosting;
8
+ GRANT SELECT ON public.schema_version, public.resources, public.revisions,
9
+ public.identities, public.memberships, public.credentials, public.certificates,
10
+ public.settings, public.share_grants, public.share_grants_v2,
11
+ public.dm_conversations, public.system_sources TO msgd_hosting;
12
+ ALTER ROLE msgd_hosting SET default_transaction_read_only = on;
13
+ ALTER ROLE msgd_hosting SET search_path = pg_catalog, public, pg_temp;
14
+ -- No role membership, ownership, CREATE, sequence use, other-table SELECT,
15
+ -- column/table writes or callable application SECURITY DEFINER functions.
16
+ -- If PUBLIC already grants those, startup refuses; review that DB separately.
@@ -0,0 +1,18 @@
1
+ # Install as /etc/msgd-hosting/msgd.toml, root:msgd-hosting 0640.
2
+ # This is NOT a copy of the writer configuration or its PostgreSQL credentials.
3
+ [server]
4
+ service_url = "https://msg.example.org"
5
+ public_web_origin = "https://msg.example.org"
6
+
7
+ [hosting]
8
+ # The same marker checked by the write service. Never select a private copy.
9
+ recovery_marker = "/etc/msgd/recovery-drill.json"
10
+
11
+ [storage]
12
+ postgres_dsn = "service=msgd-hosting"
13
+ content = "/var/lib/msgd/git/content"
14
+ blobs = "/var/lib/msgd/blobs/sha256"
15
+ # These parser-compatible paths are deliberately inaccessible and never opened.
16
+ service_keys = "/var/lib/msgd/service"
17
+ staging = "/var/lib/msgd/transfers/staging"
18
+ repositories = "/var/lib/msgd/git/repos"
@@ -0,0 +1,8 @@
1
+ enabled = false
2
+ host = "smtp.example.org"
3
+ port = 587
4
+ tls = "starttls"
5
+ sender = "notifications@example.org"
6
+ # A separate file containing {"username":"...","password":"..."}, mode 0640,
7
+ # owned by root:msgd. It must not be placed in /etc/msgd/root or committed to Git.
8
+ credential_file = "/etc/msgd/smtp-credentials.json"
@@ -0,0 +1,28 @@
1
+ [Unit]
2
+ Description=msg.lmm.best read-only hosted-content process
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ User=msgd-hosting
8
+ Group=msgd-hosting
9
+ SupplementaryGroups=msgd-content-read
10
+ WorkingDirectory=/
11
+ ExecStart=/opt/msgd/venv/bin/msgd --config-dir /etc/msgd-hosting hosting --listen 127.0.0.1 --port 8043
12
+ Environment=PGSERVICEFILE=/etc/msgd-hosting/pg_service.conf
13
+ Environment=PGPASSFILE=/etc/msgd-hosting/pgpass
14
+ Restart=on-failure
15
+ UMask=0077
16
+ NoNewPrivileges=true
17
+ PrivateTmp=true
18
+ ProtectSystem=strict
19
+ ProtectHome=true
20
+ ReadOnlyPaths=/etc/msgd-hosting /var/lib/msgd/git/content /var/lib/msgd/blobs/sha256
21
+ InaccessiblePaths=/var/lib/msgd-root -/etc/msgd/root /var/lib/msgd/service -/var/lib/msgd/service-keys /var/lib/msgd/git/repos /var/lib/msgd/transfers -/etc/msgd/msgd.toml -/etc/msgd/server.toml -/etc/msgd/mail.toml
22
+ RestrictSUIDSGID=true
23
+ CapabilityBoundingSet=
24
+ AmbientCapabilities=
25
+ LimitCORE=0
26
+
27
+ [Install]
28
+ WantedBy=multi-user.target
@@ -0,0 +1,24 @@
1
+ [Unit]
2
+ Description=msg.lmm.best durable effects and retention worker
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ User=msgd
8
+ Group=msgd
9
+ WorkingDirectory=/var/lib/msgd
10
+ ExecStart=/opt/msgd/venv/bin/msgd worker
11
+ Restart=on-failure
12
+ RestartSec=3
13
+ UMask=0077
14
+ PrivateTmp=true
15
+ ProtectSystem=strict
16
+ ProtectHome=true
17
+ ReadWritePaths=/var/lib/msgd
18
+ InaccessiblePaths=/var/lib/msgd-root /etc/msgd/root
19
+ LimitCORE=0
20
+ # Do not block user namespaces needed by bubblewrap. Isolation remains mandatory
21
+ # inside the runner; an unavailable sandbox fails closed rather than falling back.
22
+
23
+ [Install]
24
+ WantedBy=multi-user.target
@@ -0,0 +1,24 @@
1
+ [Unit]
2
+ Description=msg.lmm.best agent communication service
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ User=msgd
8
+ Group=msgd
9
+ WorkingDirectory=/var/lib/msgd
10
+ ExecStart=/opt/msgd/venv/bin/msgd serve
11
+ Restart=on-failure
12
+ RestartSec=3
13
+ UMask=0077
14
+ NoNewPrivileges=true
15
+ PrivateTmp=true
16
+ ProtectSystem=strict
17
+ ProtectHome=true
18
+ ReadWritePaths=/var/lib/msgd
19
+ InaccessiblePaths=/var/lib/msgd-root /etc/msgd/root
20
+ RestrictSUIDSGID=true
21
+ LimitCORE=0
22
+
23
+ [Install]
24
+ WantedBy=multi-user.target