@team-agent/installer 0.5.60 → 0.5.62

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 (265) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +49 -3
  4. package/crates/team-agent/src/cli/attach_app_server_leader.rs +1 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +184 -0
  6. package/crates/team-agent/src/cli/emit.rs +104 -21
  7. package/crates/team-agent/src/cli/helpers.rs +1 -0
  8. package/crates/team-agent/src/cli/leader.rs +14 -2
  9. package/crates/team-agent/src/cli/leaders.rs +2 -0
  10. package/crates/team-agent/src/cli/mod.rs +296 -8
  11. package/crates/team-agent/src/cli/named_address.rs +26 -2
  12. package/crates/team-agent/src/cli/profile.rs +2 -1
  13. package/crates/team-agent/src/cli/send/coordinator.rs +1 -0
  14. package/crates/team-agent/src/cli/send/mailbox.rs +3 -0
  15. package/crates/team-agent/src/cli/send/persist.rs +1 -0
  16. package/crates/team-agent/src/cli/send/presentation.rs +3 -0
  17. package/crates/team-agent/src/cli/send/resolve.rs +206 -1
  18. package/crates/team-agent/src/cli/send.rs +2 -1
  19. package/crates/team-agent/src/cli/spec.rs +5 -1
  20. package/crates/team-agent/src/cli/status.rs +2 -1
  21. package/crates/team-agent/src/cli/status_port/compact.rs +1 -0
  22. package/crates/team-agent/src/cli/status_port/format.rs +1 -0
  23. package/crates/team-agent/src/cli/status_port/inbox.rs +1 -0
  24. package/crates/team-agent/src/cli/status_port/store.rs +7 -3
  25. package/crates/team-agent/src/cli/tests/named_address.rs +65 -0
  26. package/crates/team-agent/src/cli/tests/verb_profile.rs +38 -0
  27. package/crates/team-agent/src/cli/types.rs +36 -2
  28. package/crates/team-agent/src/communication_mode/mod.rs +54 -0
  29. package/crates/team-agent/src/compiler/tests.rs +5 -5
  30. package/crates/team-agent/src/compiler.rs +54 -1
  31. package/crates/team-agent/src/conpty/backend.rs +1 -0
  32. package/crates/team-agent/src/conpty/mod.rs +1 -0
  33. package/crates/team-agent/src/coordinator/backoff.rs +5 -8
  34. package/crates/team-agent/src/coordinator/conpty_shim.rs +3 -2
  35. package/crates/team-agent/src/coordinator/health.rs +1 -0
  36. package/crates/team-agent/src/coordinator/mod.rs +2 -2
  37. package/crates/team-agent/src/coordinator/orphan.rs +4 -116
  38. package/crates/team-agent/src/coordinator/runtime_detectors.rs +1 -0
  39. package/crates/team-agent/src/coordinator/runtime_observation.rs +1 -0
  40. package/crates/team-agent/src/coordinator/steps/abnormal.rs +6 -5
  41. package/crates/team-agent/src/coordinator/steps/delivery.rs +1 -0
  42. package/crates/team-agent/src/coordinator/steps/health_sync.rs +1 -0
  43. package/crates/team-agent/src/coordinator/steps/mod.rs +2 -0
  44. package/crates/team-agent/src/coordinator/steps/persist.rs +1 -0
  45. package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +1 -0
  46. package/crates/team-agent/src/coordinator/steps/session_gate.rs +1 -0
  47. package/crates/team-agent/src/coordinator/tests/abnormal.rs +0 -174
  48. package/crates/team-agent/src/coordinator/tests/api_error_recovery.rs +0 -9
  49. package/crates/team-agent/src/coordinator/tests/basics.rs +0 -184
  50. package/crates/team-agent/src/coordinator/tests/mod.rs +2 -17
  51. package/crates/team-agent/src/coordinator/tests/tick_core.rs +0 -42
  52. package/crates/team-agent/src/coordinator/tick.rs +24 -28
  53. package/crates/team-agent/src/coordinator/types.rs +3 -176
  54. package/crates/team-agent/src/db/agent_health_capture.rs +1 -0
  55. package/crates/team-agent/src/db/message_store.rs +47 -2
  56. package/crates/team-agent/src/db/migration.rs +5 -4
  57. package/crates/team-agent/src/db/mod.rs +1 -0
  58. package/crates/team-agent/src/db/schema.rs +1 -0
  59. package/crates/team-agent/src/diagnose/comms.rs +2 -1
  60. package/crates/team-agent/src/diagnose/mod.rs +1 -0
  61. package/crates/team-agent/src/diagnose/orphans.rs +1 -0
  62. package/crates/team-agent/src/fake_worker.rs +21 -1
  63. package/crates/team-agent/src/layout/manager.rs +3 -7
  64. package/crates/team-agent/src/layout/mod.rs +2 -2
  65. package/crates/team-agent/src/layout/overlay.rs +6 -1
  66. package/crates/team-agent/src/layout/placement.rs +1 -0
  67. package/crates/team-agent/src/layout/recovery.rs +3 -0
  68. package/crates/team-agent/src/layout/runtime_sessions.rs +8 -3
  69. package/crates/team-agent/src/layout/sessions.rs +8 -1
  70. package/crates/team-agent/src/layout/tmux_endpoint.rs +3 -0
  71. package/crates/team-agent/src/layout/worker_env.rs +3 -0
  72. package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
  73. package/crates/team-agent/src/leader/helpers.rs +1 -0
  74. package/crates/team-agent/src/leader/incident.rs +1 -0
  75. package/crates/team-agent/src/leader/lease.rs +27 -22
  76. package/crates/team-agent/src/leader/mod.rs +2 -3
  77. package/crates/team-agent/src/leader/owner_bind.rs +13 -3
  78. package/crates/team-agent/src/leader/provider_attribution.rs +1 -0
  79. package/crates/team-agent/src/leader/rediscover.rs +4 -17
  80. package/crates/team-agent/src/leader/registry.rs +3 -15
  81. package/crates/team-agent/src/leader/start.rs +1072 -186
  82. package/crates/team-agent/src/leader/takeover.rs +10 -232
  83. package/crates/team-agent/src/leader/tests/claim_leader_mailbox_flush_contract.rs +544 -0
  84. package/crates/team-agent/src/leader/tests/historical_inventory_upgrade_gate_red.rs +624 -0
  85. package/crates/team-agent/src/leader/tests/identity.rs +71 -59
  86. package/crates/team-agent/src/leader/tests/identity_session_names.rs +42 -0
  87. package/crates/team-agent/src/leader/tests/idle.rs +0 -193
  88. package/crates/team-agent/src/leader/tests/lease_api.rs +0 -45
  89. package/crates/team-agent/src/leader/tests/mod.rs +4 -41
  90. package/crates/team-agent/src/leader/tests/rehomed_env.rs +83 -0
  91. package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1273 -0
  92. package/crates/team-agent/src/leader/tests/terminal_and_replay_vs_rerender_invariants_red.rs +417 -0
  93. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +22 -103
  94. package/crates/team-agent/src/leader/types.rs +1 -28
  95. package/crates/team-agent/src/lib.rs +7 -0
  96. package/crates/team-agent/src/lifecycle/display.rs +7 -1
  97. package/crates/team-agent/src/lifecycle/helpers.rs +3 -1
  98. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +2 -2
  99. package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +1 -0
  100. package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +1 -1
  101. package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +1 -0
  102. package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +1 -0
  103. package/crates/team-agent/src/lifecycle/launch/plan.rs +2 -2
  104. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +4 -26
  105. package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -27
  106. package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -28
  107. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +4 -32
  108. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +1 -0
  109. package/crates/team-agent/src/lifecycle/launch.rs +11 -12
  110. package/crates/team-agent/src/lifecycle/mod.rs +2 -1
  111. package/crates/team-agent/src/lifecycle/restart/agent.rs +4 -4
  112. package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
  113. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +2 -2
  114. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +13 -5
  115. package/crates/team-agent/src/lifecycle/restart/remove.rs +1 -1
  116. package/crates/team-agent/src/lifecycle/restart/selection.rs +3 -3
  117. package/crates/team-agent/src/lifecycle/restart.rs +13 -11
  118. package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1007 -0
  119. package/crates/team-agent/src/lifecycle/tests/b0_legacy_snapshot_nonauthority_contract.rs +265 -0
  120. package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +459 -0
  121. package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +849 -0
  122. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +323 -0
  123. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +423 -0
  124. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +737 -0
  125. package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +1187 -0
  126. package/crates/team-agent/src/lifecycle/tests/codex_weak_window_attribution_red.rs +683 -0
  127. package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +394 -0
  128. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +1856 -0
  129. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +917 -0
  130. package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +481 -0
  131. package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +301 -0
  132. package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +516 -0
  133. package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +986 -0
  134. package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +651 -0
  135. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -0
  136. package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +332 -0
  137. package/crates/team-agent/src/lifecycle/tests/realmachine_clusters_1_6_red.rs +846 -0
  138. package/crates/team-agent/src/lifecycle/tests/realmachine_residual_g1_g4_red.rs +648 -0
  139. package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +910 -0
  140. package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +630 -0
  141. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1083 -0
  142. package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +1677 -0
  143. package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +410 -0
  144. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +428 -0
  145. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1032 -0
  146. package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +869 -0
  147. package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1249 -0
  148. package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +342 -0
  149. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +542 -0
  150. package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1103 -0
  151. package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1276 -0
  152. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_roster_red.rs +145 -0
  153. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +603 -0
  154. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +837 -0
  155. package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +928 -0
  156. package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +951 -0
  157. package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +327 -0
  158. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +760 -0
  159. package/crates/team-agent/src/lifecycle/tests.rs +59 -0
  160. package/crates/team-agent/src/lifecycle/types.rs +0 -9
  161. package/crates/team-agent/src/lifecycle/worker_command_context.rs +29 -11
  162. package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
  163. package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +1 -0
  164. package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +1 -0
  165. package/crates/team-agent/src/mcp_server/mod.rs +1 -0
  166. package/crates/team-agent/src/mcp_server/normalize.rs +5 -3
  167. package/crates/team-agent/src/mcp_server/tests/send.rs +26 -0
  168. package/crates/team-agent/src/mcp_server/tests/wire.rs +1 -1
  169. package/crates/team-agent/src/mcp_server/tools.rs +101 -66
  170. package/crates/team-agent/src/mcp_server/types.rs +6 -18
  171. package/crates/team-agent/src/mcp_server/wire.rs +32 -26
  172. package/crates/team-agent/src/messaging/activity.rs +1 -0
  173. package/crates/team-agent/src/messaging/address.rs +1 -0
  174. package/crates/team-agent/src/messaging/delivery.rs +109 -41
  175. package/crates/team-agent/src/messaging/helpers.rs +2 -1
  176. package/crates/team-agent/src/messaging/leader_channel.rs +34 -10
  177. package/crates/team-agent/src/messaging/leader_receiver.rs +42 -24
  178. package/crates/team-agent/src/messaging/mod.rs +10 -14
  179. package/crates/team-agent/src/messaging/peers.rs +2 -0
  180. package/crates/team-agent/src/messaging/persist.rs +3 -1
  181. package/crates/team-agent/src/messaging/presentation.rs +111 -1
  182. package/crates/team-agent/src/messaging/results.rs +166 -17
  183. package/crates/team-agent/src/messaging/scheduler.rs +1 -0
  184. package/crates/team-agent/src/messaging/selftest.rs +1 -1
  185. package/crates/team-agent/src/messaging/send.rs +135 -89
  186. package/crates/team-agent/src/messaging/tests/leader_channel.rs +6 -6
  187. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +187 -0
  188. package/crates/team-agent/src/messaging/tests/mod.rs +5 -0
  189. package/crates/team-agent/src/messaging/tests/runtime.rs +13 -6
  190. package/crates/team-agent/src/messaging/types.rs +7 -2
  191. package/crates/team-agent/src/messaging/watchers.rs +24 -13
  192. package/crates/team-agent/src/model/enums.rs +1 -0
  193. package/crates/team-agent/src/model/errors.rs +1 -0
  194. package/crates/team-agent/src/model/ids.rs +1 -0
  195. package/crates/team-agent/src/model/mod.rs +2 -0
  196. package/crates/team-agent/src/model/name_similarity.rs +1 -0
  197. package/crates/team-agent/src/model/pane_authority_refusal.rs +359 -0
  198. package/crates/team-agent/src/model/paths.rs +1 -0
  199. package/crates/team-agent/src/model/permissions.rs +3 -2
  200. package/crates/team-agent/src/model/routing.rs +1 -0
  201. package/crates/team-agent/src/model/spec.rs +17 -0
  202. package/crates/team-agent/src/model/task_graph.rs +1 -0
  203. package/crates/team-agent/src/model/yaml/tests.rs +1 -0
  204. package/crates/team-agent/src/model/yaml.rs +1 -0
  205. package/crates/team-agent/src/packaging/install.rs +9 -147
  206. package/crates/team-agent/src/packaging/migrate.rs +2 -0
  207. package/crates/team-agent/src/packaging/mod.rs +1 -0
  208. package/crates/team-agent/src/packaging/repair.rs +2 -0
  209. package/crates/team-agent/src/packaging/tests.rs +29 -218
  210. package/crates/team-agent/src/packaging/types.rs +8 -15
  211. package/crates/team-agent/src/platform/argv.rs +4 -0
  212. package/crates/team-agent/src/platform/errors.rs +10 -1
  213. package/crates/team-agent/src/platform/file_lock.rs +4 -157
  214. package/crates/team-agent/src/platform/mod.rs +0 -61
  215. package/crates/team-agent/src/platform/process.rs +1 -0
  216. package/crates/team-agent/src/provider/adapter.rs +1 -0
  217. package/crates/team-agent/src/provider/adapters/claude.rs +1 -0
  218. package/crates/team-agent/src/provider/adapters/claude_fork.rs +1 -0
  219. package/crates/team-agent/src/provider/adapters/codex.rs +1 -0
  220. package/crates/team-agent/src/provider/adapters/copilot.rs +1 -0
  221. package/crates/team-agent/src/provider/adapters/copilot_fork.rs +1 -0
  222. package/crates/team-agent/src/provider/adapters/fake.rs +1 -0
  223. package/crates/team-agent/src/provider/adapters/mod.rs +1 -0
  224. package/crates/team-agent/src/provider/approvals/mod.rs +1 -0
  225. package/crates/team-agent/src/provider/approvals/parsing.rs +2 -5
  226. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +6 -5
  227. package/crates/team-agent/src/provider/classify.rs +1 -0
  228. package/crates/team-agent/src/provider/faults.rs +1 -26
  229. package/crates/team-agent/src/provider/helpers.rs +1 -0
  230. package/crates/team-agent/src/provider/mod.rs +1 -1
  231. package/crates/team-agent/src/provider/session/capture.rs +41 -22
  232. package/crates/team-agent/src/provider/session/context_fork/claude.rs +1 -0
  233. package/crates/team-agent/src/provider/session/context_fork/codex.rs +1 -0
  234. package/crates/team-agent/src/provider/session/context_fork/outcome.rs +1 -0
  235. package/crates/team-agent/src/provider/session/context_fork.rs +1 -0
  236. package/crates/team-agent/src/provider/session/mod.rs +2 -4
  237. package/crates/team-agent/src/provider/session/resume.rs +2 -209
  238. package/crates/team-agent/src/provider/session_scan/claude.rs +93 -3
  239. package/crates/team-agent/src/provider/session_scan/codex.rs +1 -0
  240. package/crates/team-agent/src/provider/session_scan/common.rs +24 -7
  241. package/crates/team-agent/src/provider/session_scan/copilot.rs +1 -0
  242. package/crates/team-agent/src/provider/session_scan.rs +6 -42
  243. package/crates/team-agent/src/provider/startup_prompt.rs +1 -0
  244. package/crates/team-agent/src/provider/types.rs +1 -0
  245. package/crates/team-agent/src/provider/wire.rs +1 -0
  246. package/crates/team-agent/src/state/identity.rs +16 -5
  247. package/crates/team-agent/src/state/identity_keys.rs +1 -0
  248. package/crates/team-agent/src/state/mod.rs +2 -0
  249. package/crates/team-agent/src/state/owner_gate.rs +5 -0
  250. package/crates/team-agent/src/state/ownership.rs +10 -4
  251. package/crates/team-agent/src/state/paths.rs +12 -0
  252. package/crates/team-agent/src/state/persist.rs +9 -3
  253. package/crates/team-agent/src/state/projection.rs +15 -2
  254. package/crates/team-agent/src/state/repository/intent.rs +1 -0
  255. package/crates/team-agent/src/state/repository/tests.rs +1 -0
  256. package/crates/team-agent/src/state/repository.rs +7 -0
  257. package/crates/team-agent/src/state/selector.rs +1 -0
  258. package/crates/team-agent/src/tmux_backend/tests.rs +39 -0
  259. package/crates/team-agent/src/tmux_backend.rs +63 -0
  260. package/crates/team-agent/src/topology.rs +3 -0
  261. package/crates/team-agent/src/transport.rs +15 -0
  262. package/package.json +4 -4
  263. package/skills/team-agent/command-coverage.json +379 -0
  264. package/crates/team-agent/src/leader/inject.rs +0 -33
  265. package/crates/team-agent/src/provider/command.rs +0 -80
@@ -189,7 +189,7 @@ fn front_matter_non_object_errors() {
189
189
  // separators=(",",":"))` with the workspace path templated to __WS__.
190
190
  // (team-agent-public v0.2.11, /tmp/probe_compiler.py.)
191
191
 
192
- const BASE_NOPROFILE_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks and report result_envelope_v1.","file":null},"tools":["fs_read","fs_write","execute_bash","mcp_team"],"permission_mode":"restricted","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
192
+ const BASE_NOPROFILE_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks and report result_envelope_v1.","file":null},"tools":["fs_read","fs_write","execute_bash","mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
193
193
 
194
194
  #[test]
195
195
  fn compile_base_noprofile_matches_python_dict_order_and_values() {
@@ -259,7 +259,7 @@ tools:
259
259
  Implement bounded tasks.
260
260
  ";
261
261
 
262
- const RUNTIME_DEFAULTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.4","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["fs_read","mcp_team"],"permission_mode":"restricted","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"ghostty_window","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":true,"fast":true,"tick_interval_sec":1,"push_min_interval_sec":3,"stuck_timeout_sec":5},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
262
+ const RUNTIME_DEFAULTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.4","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["fs_read","mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"ghostty_window","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":true,"fast":true,"tick_interval_sec":1,"push_min_interval_sec":3,"stuck_timeout_sec":5},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
263
263
 
264
264
  #[test]
265
265
  fn compile_runtime_front_matter_defaults_match_python() {
@@ -299,7 +299,7 @@ tools:
299
299
  Edit and defend the argument.
300
300
  ";
301
301
 
302
- const ALIAS_JSON: &str = r#"{"version":1,"team":{"name":"debate-team","mode":"supervisor_worker","objective":"Compile thin role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"editor","role":"Editor and Defender","provider":"claude_code","model":"claude-sonnet-4-6","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Edit and defend the argument.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["editor","Editor and Defender"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"editor","rules":[{"id":"route-editor","match":{"assignee":["editor"]},"assign_to":"editor","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-debate-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["editor"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"editor","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
302
+ const ALIAS_JSON: &str = r#"{"version":1,"team":{"name":"debate-team","mode":"supervisor_worker","objective":"Compile thin role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"editor","role":"Editor and Defender","provider":"claude_code","model":"claude-sonnet-4-6","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Edit and defend the argument.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["editor","Editor and Defender"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"editor","rules":[{"id":"route-editor","match":{"assignee":["editor"]},"assign_to":"editor","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-debate-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["editor"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"editor","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
303
303
 
304
304
  #[test]
305
305
  fn compile_provider_models_claude_code_falls_back_to_claude_alias() {
@@ -332,7 +332,7 @@ tools:
332
332
  Implement bounded tasks.
333
333
  ";
334
334
 
335
- const BUILTIN_JSON: &str = r#"{"version":1,"team":{"name":"default-model-team","mode":"supervisor_worker","objective":"Compile role docs without model fields.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-default-model-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
335
+ const BUILTIN_JSON: &str = r#"{"version":1,"team":{"name":"default-model-team","mode":"supervisor_worker","objective":"Compile role docs without model fields.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-default-model-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
336
336
 
337
337
  #[test]
338
338
  fn compile_subscription_without_model_uses_builtin_provider_default() {
@@ -372,7 +372,7 @@ tools:
372
372
  Bravo body.
373
373
  ";
374
374
 
375
- const TWO_AGENTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"alpha","role":"Alpha Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Alpha body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["alpha","Alpha Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}},{"id":"bravo","role":"Bravo Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Bravo body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["bravo","Bravo Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"alpha","rules":[{"id":"route-alpha","match":{"assignee":["alpha"]},"assign_to":"alpha","priority":10},{"id":"route-bravo","match":{"assignee":["bravo"]},"assign_to":"bravo","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":2,"startup_order":["alpha","bravo"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"alpha","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
375
+ const TWO_AGENTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"alpha","role":"Alpha Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Alpha body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["alpha","Alpha Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}},{"id":"bravo","role":"Bravo Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Bravo body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["bravo","Bravo Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"alpha","rules":[{"id":"route-alpha","match":{"assignee":["alpha"]},"assign_to":"alpha","priority":10},{"id":"route-bravo","match":{"assignee":["bravo"]},"assign_to":"bravo","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":2,"startup_order":["alpha","bravo"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"alpha","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
376
376
 
377
377
  #[test]
378
378
  fn compile_two_agents_sorted_by_filename_with_routing_and_startup_order() {
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! step 6 · compiler — doc-driven team source → canonical `team.spec` dict.
2
3
  //!
3
4
  //! Truth source (READ-ONLY): `team-agent-public` @ v0.2.11, `team_agent/compiler.py`.
@@ -26,6 +27,7 @@
26
27
  use std::fs;
27
28
  use std::path::Path;
28
29
 
30
+ use crate::communication_mode::CommunicationMode;
29
31
  use crate::model::enums::{Provider, ProviderEffort};
30
32
  use crate::model::yaml::Value;
31
33
  use crate::model::{paths, spec, yaml, ModelError};
@@ -133,6 +135,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
133
135
  }
134
136
 
135
137
  let (team_meta, team_body) = read_front_matter(&team_md)?;
138
+ let team_communication_mode =
139
+ communication_mode_field(&team_meta, &team_md)?.unwrap_or_default();
136
140
  let mut role_paths = Vec::new();
137
141
  if agents_dir.is_dir() {
138
142
  for entry in fs::read_dir(&agents_dir)
@@ -170,7 +174,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
170
174
  let mut agents = Vec::new();
171
175
  let mut agent_ids = Vec::new();
172
176
  for path in role_paths {
173
- let compiled = compile_role_agent(&path, &team_meta, &workspace_s)?;
177
+ let compiled =
178
+ compile_role_agent_with_mode(&path, &team_meta, &workspace_s, team_communication_mode)?;
174
179
  agent_ids.push(compiled.id);
175
180
  agents.push(compiled.agent);
176
181
  }
@@ -371,8 +376,21 @@ pub fn compile_role_agent(
371
376
  role_path: &Path,
372
377
  team_meta: &Value,
373
378
  workspace_s: &str,
379
+ ) -> Result<CompiledRole, ModelError> {
380
+ let team_communication_mode =
381
+ communication_mode_field(team_meta, role_path)?.unwrap_or_default();
382
+ compile_role_agent_with_mode(role_path, team_meta, workspace_s, team_communication_mode)
383
+ }
384
+
385
+ fn compile_role_agent_with_mode(
386
+ role_path: &Path,
387
+ team_meta: &Value,
388
+ workspace_s: &str,
389
+ team_communication_mode: CommunicationMode,
374
390
  ) -> Result<CompiledRole, ModelError> {
375
391
  let (meta, body) = read_front_matter(role_path)?;
392
+ let communication_mode =
393
+ communication_mode_field(&meta, role_path)?.unwrap_or(team_communication_mode);
376
394
  let id = required_string(&meta, role_path, "name")?;
377
395
  let role = required_string(&meta, role_path, "role")?;
378
396
  let provider = required_string(&meta, role_path, "provider")?;
@@ -404,6 +422,10 @@ pub fn compile_role_agent(
404
422
  ),
405
423
  ("tools", list_str(tools)),
406
424
  ("permission_mode", Value::Str("restricted".to_string())),
425
+ (
426
+ "communication_mode",
427
+ Value::Str(communication_mode.as_str().to_string()),
428
+ ),
407
429
  ("preferred_for", list_str(vec![id.clone(), role.clone()])),
408
430
  ("avoid_for", Value::List(Vec::new())),
409
431
  (
@@ -469,6 +491,37 @@ pub fn compile_role_agent(
469
491
  })
470
492
  }
471
493
 
494
+ fn communication_mode_field(
495
+ meta: &Value,
496
+ path: &Path,
497
+ ) -> Result<Option<CommunicationMode>, ModelError> {
498
+ let Some(raw) = meta.get("communication_mode") else {
499
+ return Ok(None);
500
+ };
501
+ let Some(value) = raw.as_str() else {
502
+ return Err(ModelError::Validation(format!(
503
+ "{}: unknown communication_mode (allowed: {})",
504
+ path.display(),
505
+ CommunicationMode::ALL
506
+ .iter()
507
+ .map(|mode| mode.as_str())
508
+ .collect::<Vec<_>>()
509
+ .join("|")
510
+ )));
511
+ };
512
+ CommunicationMode::parse(value).map(Some).ok_or_else(|| {
513
+ ModelError::Validation(format!(
514
+ "{}: unknown communication_mode '{value}' (allowed: {})",
515
+ path.display(),
516
+ CommunicationMode::ALL
517
+ .iter()
518
+ .map(|mode| mode.as_str())
519
+ .collect::<Vec<_>>()
520
+ .join("|")
521
+ ))
522
+ })
523
+ }
524
+
472
525
  fn map(items: Vec<(&str, Value)>) -> Value {
473
526
  Value::Map(items.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
474
527
  }
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! `ConPtyBackend` — implements the existing `Transport` trait using the
2
3
  //! named-pipe protocol in `super::protocol`.
3
4
  //!
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! 0.5.x Windows-native transport Phase 1: ConPTY backend.
2
3
  //!
3
4
  //! Wire protocol + portable shim state machine live in the
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! daemon 主循环面(`__main__.py`)—— 退避序列 + tick 间隔解析 + 子进程入口。
2
3
 
3
4
  use thiserror::Error;
@@ -10,7 +11,7 @@ use crate::provider::ProviderAdapter;
10
11
  use super::health::{coordinator_pid_path, write_coordinator_metadata};
11
12
  use super::tick::{write_coordinator_heartbeat, TickError, TickReport, HEARTBEAT_STATUS_PANIC};
12
13
  use super::types::{
13
- ErrorLists, MetadataSource, Pid, ProviderRegistry, WorkspacePath, BACKOFF_MAX_SEC,
14
+ MetadataSource, Pid, ProviderRegistry, WorkspacePath, BACKOFF_MAX_SEC,
14
15
  DEFAULT_TICK_INTERVAL_SEC,
15
16
  };
16
17
  use super::Coordinator;
@@ -122,7 +123,7 @@ pub fn run_daemon(args: DaemonArgs) -> Result<(), DaemonError> {
122
123
  run_daemon_with_coordinator_and_boot_tmux(&args, &coordinator, Some(tmux_metadata))
123
124
  }
124
125
 
125
- pub fn run_daemon_with_coordinator(
126
+ pub(crate) fn run_daemon_with_coordinator(
126
127
  args: &DaemonArgs,
127
128
  coordinator: &Coordinator,
128
129
  ) -> Result<(), DaemonError> {
@@ -519,14 +520,14 @@ fn current_ppid() -> u32 {
519
520
 
520
521
  /// 计算 tick 间隔(`_tick_interval`,`__main__.py:104-115`)。读 spec `runtime.tick_interval_sec`,
521
522
  /// 缺失/出错 → `DEFAULT_TICK_INTERVAL_SEC`;并确保 schema 存在(`MessageStore(workspace)`)。
522
- pub fn resolve_tick_interval(workspace: &WorkspacePath) -> Result<f64, TickError> {
523
+ pub(super) fn resolve_tick_interval(workspace: &WorkspacePath) -> Result<f64, TickError> {
523
524
  let _ = MessageStore::open(workspace.as_path())?;
524
525
  Ok(DEFAULT_TICK_INTERVAL_SEC)
525
526
  }
526
527
 
527
528
  /// 退避序列(`__main__.py:65`):`min(interval * 2^min(failures-1, 5), 60.0)` → 5→10→20→40→60→60s。
528
529
  /// unit test 锁死本序列(card §85)。**纯函数,无 I/O,可直接 impl 钉死**(但 ROUND-0 仍占位)。
529
- pub fn backoff_sleep_sec(interval: f64, consecutive_failures: u32) -> f64 {
530
+ pub(super) fn backoff_sleep_sec(interval: f64, consecutive_failures: u32) -> f64 {
530
531
  let failures = consecutive_failures.saturating_sub(1).min(5);
531
532
  let exp = i32::try_from(failures).unwrap_or(5);
532
533
  (interval * 2f64.powi(exp)).min(BACKOFF_MAX_SEC)
@@ -538,10 +539,6 @@ impl ProviderRegistry for RealProviderRegistry {
538
539
  fn adapter_for(&self, provider: Provider) -> Box<dyn ProviderAdapter> {
539
540
  crate::provider::get_adapter(provider)
540
541
  }
541
-
542
- fn error_lists(&self, _provider: Provider) -> ErrorLists {
543
- ErrorLists::default()
544
- }
545
542
  }
546
543
 
547
544
  fn sleep_seconds(seconds: f64) {
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! Windows ConPTY shim lifecycle manager.
2
3
  //!
3
4
  //! 0.5.x Windows portability Batch 6 Option A. The design's
@@ -160,7 +161,7 @@ pub enum ShimError {
160
161
  /// installations.
161
162
  /// 2. Env override `TEAM_AGENT_WINDOWS_SHIM_PATH` — tests + CI
162
163
  /// harness (Batch 6 SSH real-machine harness sets this).
163
- pub fn locate_shim_binary() -> Result<PathBuf, ShimError> {
164
+ fn locate_shim_binary() -> Result<PathBuf, ShimError> {
164
165
  if let Ok(explicit) = std::env::var("TEAM_AGENT_WINDOWS_SHIM_PATH") {
165
166
  let p = PathBuf::from(&explicit);
166
167
  if p.exists() {
@@ -218,7 +219,7 @@ fn fresh_pipe_token() -> String {
218
219
  /// downstream `transport_factory::conpty_pipe_ready(...)` opens on
219
220
  /// the next factory resolve. The `pipe_token` is NOT persisted (CR
220
221
  /// C-1); it stays in `ShimHandle` memory only.
221
- pub fn spawn_shim_and_handshake(
222
+ fn spawn_shim_and_handshake(
222
223
  workspace: &Path,
223
224
  team_key: &str,
224
225
  workspace_hash: &str,
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! coordinator 健康/身份 & 只读可观测面:metadata 身份原语 + coordinator 路径 + watch 实时流。
2
3
 
3
4
  use std::io::{Read, Seek, SeekFrom};
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! step 12 · coordinator — daemon lifecycle / single-tick orchestration SKELETON (ROUND-0).
2
3
  //!
3
4
  //! Card: `docs/phase0/subsystems/12-coordinator.md`.
@@ -10,8 +11,7 @@
10
11
  //! - `coordinator/metadata.py` (COORDINATOR_PROTOCOL_VERSION=2, pid_is_running, read/write/ok meta)
11
12
  //! - `coordinator/paths.py` (coordinator.pid / coordinator.json / coordinator.log paths)
12
13
  //! - `watch/__init__.py` (run_watch / collect_watch_lines / render_event_line / WatchCursor)
13
- //! - `abnormal_track.py` (Gap 32 §4 provider-neutral abnormal track:
14
- //! process_abnormal_records / detect_whole_team_gone)
14
+ //! - `abnormal_track.py` (Gap 32 §4 provider-neutral whole-team-gone detection)
15
15
  //!
16
16
  //! 职责(card §职责):per-workspace daemon 生命周期 + 单次 tick 编排。tick 按固定顺序把
17
17
  //! step 8-11 的原子操作串成一个只读 + 投递既定 obligation 的回路 —— **绝不**在无 pending
@@ -1,18 +1,11 @@
1
- //! 孤儿自终止判定(Gap 37b)+ provider-neutral 异常轨(abnormal_track:整队消失检测 + 去重通知)。
2
-
3
- use std::hash::{Hash, Hasher};
4
-
5
- use serde_json::Value;
6
-
7
- use crate::model::enums::Provider;
8
- use crate::provider::{ProcessLiveness, Signature, TurnId, TurnState};
1
+ //!
2
+ //! 孤儿自终止判定(Gap 37b)+ provider-neutral 整队消失检测。
9
3
 
10
4
  use super::types::{
11
- AbnormalDecision, AbnormalError, AbnormalNotification, AbnormalNotificationState,
12
- AbnormalProcessOutput, MarkerStore, ProviderRegistry, TeamPresenceSnapshot, WholeTeamGoneClass,
13
- WholeTeamGoneReport, WorkspacePath,
5
+ MarkerStore, TeamPresenceSnapshot, WholeTeamGoneClass, WholeTeamGoneReport, WorkspacePath,
14
6
  };
15
7
 
8
+ ///
16
9
  /// 孤儿自终止判定(`__main__.py:51-59`,Gap 37b)。仅当
17
10
  /// `current_ppid != initial_ppid ∧ current_ppid == 1 ∧ !workspace.exists()` 三者**同时**成立 → true。
18
11
  /// 少一个条件都不能误杀正常 daemon(card §91)。
@@ -28,104 +21,7 @@ pub fn should_orphan_self_terminate(
28
21
  // abnormal_track 公共面(abnormal_track.py)—— Gap 32 §4 provider-neutral
29
22
  // ===========================================================================
30
23
 
31
- /// #236 dedicated `worker.abnormal_exit` surface.
32
24
  ///
33
- /// This is intentionally separate from `process_abnormal_records`: the generic
34
- /// abnormal path is transcript-only, while `worker.abnormal_exit` requires a fresh
35
- /// latest explicit provider error before leader notification.
36
- #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
37
- #[serde(tag = "event")]
38
- pub enum WorkerAbnormalExitSurface {
39
- #[serde(rename = "worker.abnormal_exit")]
40
- WorkerAbnormalExit {
41
- agent_id: String,
42
- provider: Provider,
43
- path: String,
44
- provider_process_dead: bool,
45
- latest_explicit_error: bool,
46
- signature: Signature,
47
- turn_id: Option<TurnId>,
48
- process_liveness: ProcessLiveness,
49
- },
50
- #[serde(rename = "abnormal_exit.single_signal_suppressed")]
51
- SingleSignalSuppressed {
52
- agent_id: String,
53
- provider: Provider,
54
- path: String,
55
- provider_process_dead: bool,
56
- latest_explicit_error: bool,
57
- reason: String,
58
- },
59
- }
60
-
61
- /// `process_abnormal_records`(`abnormal_track.py:14`)。把原始 provider session records 经
62
- /// provider reader 翻译成结构化 fault facts(本 module **不命名 provider、不读屏**),catch-bias
63
- /// (C9)+ `(signature, turn_id|fingerprint)` 去重(C8)。`registry` 携带 provider + 黑白名单。
64
- pub fn process_abnormal_records(
65
- records: &[Value],
66
- registry: &dyn ProviderRegistry,
67
- provider: Provider,
68
- notification_state: &AbnormalNotificationState,
69
- ) -> Result<AbnormalProcessOutput, AbnormalError> {
70
- let lists = registry.error_lists(provider);
71
- let mut state = notification_state.clone();
72
- let mut notifications = Vec::new();
73
- for record in records {
74
- let raw = record
75
- .get("raw")
76
- .and_then(Value::as_str)
77
- .unwrap_or_else(|| record.as_str().unwrap_or(""))
78
- .to_string();
79
- let signature = record
80
- .get("signature")
81
- .and_then(Value::as_str)
82
- .unwrap_or("unknown")
83
- .to_string();
84
- let signature_lower = signature.to_lowercase();
85
- let turn_id = record
86
- .get("turn_id")
87
- .and_then(Value::as_str)
88
- .map(TurnId::new);
89
- let bucket = match &turn_id {
90
- Some(id) => id.as_str().to_string(),
91
- None => stable_fingerprint(record),
92
- };
93
- let key = format!("{signature}\0{bucket}");
94
- if state.seen.contains(&key) {
95
- continue;
96
- }
97
- state.seen.insert(key);
98
- if lists.whitelist.iter().any(|needle| raw.contains(needle)) {
99
- continue;
100
- }
101
- let decision =
102
- if lists.blacklist.iter().any(|needle| {
103
- raw.contains(needle) || signature_lower.contains(&needle.to_lowercase())
104
- }) {
105
- AbnormalDecision::NotifyBlacklist
106
- } else {
107
- AbnormalDecision::NotifyDefault
108
- };
109
- let kind = record.get("kind").and_then(Value::as_str);
110
- notifications.push(AbnormalNotification {
111
- signature,
112
- turn_id,
113
- state: if kind == Some("approval") {
114
- TurnState::BlockedOnHuman
115
- } else {
116
- TurnState::Abnormal
117
- },
118
- decision,
119
- provider: Some(provider),
120
- raw: record.clone(),
121
- });
122
- }
123
- Ok(AbnormalProcessOutput {
124
- notifications,
125
- notification_state: state,
126
- })
127
- }
128
-
129
25
  /// `detect_whole_team_gone`(`abnormal_track.py:91`,C10/C13)。coordinator-independent 整队消失检测:
130
26
  /// 全死(coordinator + leader + 所有 worker + 所有 session)且非 clean_shutdown/restart →
131
27
  /// 写 durable marker + 延迟到下条 leader 命令再 escalate。clean/restart 静默。
@@ -166,14 +62,6 @@ pub fn detect_whole_team_gone(
166
62
  )
167
63
  }
168
64
 
169
- fn stable_fingerprint(value: &Value) -> String {
170
- let mut hasher = std::collections::hash_map::DefaultHasher::new();
171
- serde_json::to_string(value)
172
- .unwrap_or_else(|_| value.to_string())
173
- .hash(&mut hasher);
174
- format!("{:016x}", hasher.finish())
175
- }
176
-
177
65
  fn whole_team_report(
178
66
  whole_team_gone: bool,
179
67
  classification: WholeTeamGoneClass,
@@ -1,3 +1,4 @@
1
+ //!
1
2
  use std::collections::BTreeMap;
2
3
  use std::path::Path;
3
4
 
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! Shared coordinator runtime observation seam.
2
3
  //!
3
4
  //! S0 only defines the typed capture/result surface. Lane 1 fills capture facts;
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `abnormal` step group.
2
3
  //!
3
4
  //! Abnormal-exit detection + classification step extracted from
@@ -15,6 +16,7 @@ use super::super::health::pid_is_running;
15
16
  use super::super::tick::TickError;
16
17
  use super::super::types::Pid;
17
18
 
19
+ ///
18
20
  /// #236 `worker.abnormal_exit` watcher.
19
21
  ///
20
22
  /// Notify only when the bounded transcript/rollout tail contains a latest explicit
@@ -967,6 +969,7 @@ fn abnormal_last_error_observation_cohort(state: &Value, agent_id: &str) -> Opti
967
969
  /// P1: Python `_TAIL_BYTES` parity (idle_takeover_wiring.py:13) — RS must not read less.
968
970
  const ABNORMAL_TAIL_BYTES: u64 = 131_072;
969
971
 
972
+ ///
970
973
  /// P1: bounded tail read; a partial first line is harmless (the consumer only parses
971
974
  /// the latest complete JSONL record) and lossy UTF-8 keeps a mid-codepoint seek safe.
972
975
  pub(crate) fn read_tail_text(path: &Path, max_bytes: u64) -> std::io::Result<String> {
@@ -1347,6 +1350,7 @@ impl ApiErrorRecoveryClass {
1347
1350
  }
1348
1351
  }
1349
1352
 
1353
+ ///
1350
1354
  /// 0.5.36 §7.1: rules keyed on status/error text.
1351
1355
  pub(crate) fn classify_api_error_recovery(
1352
1356
  signature: &str,
@@ -1871,6 +1875,7 @@ fn process_api_error_recovery_intent(
1871
1875
  // path (which owns its own save).
1872
1876
  // ─────────────────────────────────────────────────────────────────────────
1873
1877
 
1878
+ ///
1874
1879
  /// 0.5.36 §7.3: process all due recovery intents. Called from tick.rs
1875
1880
  /// AFTER atomic_save has flushed the detector-written intent. Reloads a
1876
1881
  /// fresh state each call so the caller's stale in-memory state cannot
@@ -2168,7 +2173,7 @@ fn write_recovery_intent_result(workspace: &Path, agent_id: &str, update: Recove
2168
2173
  mod tests {
2169
2174
  use super::*;
2170
2175
  use crate::coordinator::tick::Coordinator;
2171
- use crate::coordinator::types::{ErrorLists, ProviderRegistry, WorkspacePath};
2176
+ use crate::coordinator::types::{ProviderRegistry, WorkspacePath};
2172
2177
  use std::io::Write as _;
2173
2178
 
2174
2179
  struct NormalRegistry;
@@ -2180,10 +2185,6 @@ mod tests {
2180
2185
  ) -> Box<dyn crate::provider::ProviderAdapter> {
2181
2186
  crate::provider::get_adapter(provider)
2182
2187
  }
2183
-
2184
- fn error_lists(&self, _provider: crate::provider::Provider) -> ErrorLists {
2185
- ErrorLists::default()
2186
- }
2187
2188
  }
2188
2189
  #[test]
2189
2190
  fn abnormal_stale_error_baselines_then_fresh_alive_error_notifies() {
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `delivery` step group.
2
3
  //!
3
4
  //! Future home for the message-delivery FSM ticks from
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `health_sync` step group.
2
3
  //!
3
4
  //! Future home for worker-liveness reconciliation steps from
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick steps namespace.
2
3
  //!
3
4
  //! The 3083 LOC `coordinator/tick.rs` orchestrator runs an ordered
@@ -47,6 +48,7 @@ impl TickStepGroup {
47
48
  }
48
49
  }
49
50
 
51
+ ///
50
52
  /// Canonical ordering as a const slice — exhaustive over the enum.
51
53
  pub fn ordered() -> &'static [TickStepGroup] {
52
54
  &[
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `persist` step group.
2
3
  //!
3
4
  //! Future home for the durable state-persistence step at the end of each
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `runtime_prompts` step group.
2
3
  //!
3
4
  //! Future home for the startup / approval / abnormal-exit prompt steps
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `session_gate` step group.
2
3
  //!
3
4
  //! Future home for the provider session-capture + readiness-gate steps