@team-agent/installer 0.5.60 → 0.5.61

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 (54) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +44 -1
  4. package/crates/team-agent/src/cli/diagnose.rs +183 -0
  5. package/crates/team-agent/src/cli/emit.rs +63 -14
  6. package/crates/team-agent/src/cli/leader.rs +8 -1
  7. package/crates/team-agent/src/cli/mod.rs +263 -5
  8. package/crates/team-agent/src/cli/named_address.rs +18 -1
  9. package/crates/team-agent/src/cli/send/presentation.rs +2 -0
  10. package/crates/team-agent/src/cli/spec.rs +4 -1
  11. package/crates/team-agent/src/cli/status_port/store.rs +7 -3
  12. package/crates/team-agent/src/cli/tests/named_address.rs +65 -0
  13. package/crates/team-agent/src/cli/types.rs +33 -0
  14. package/crates/team-agent/src/communication_mode/mod.rs +53 -0
  15. package/crates/team-agent/src/compiler/tests.rs +5 -5
  16. package/crates/team-agent/src/compiler.rs +53 -1
  17. package/crates/team-agent/src/db/message_store.rs +45 -1
  18. package/crates/team-agent/src/fake_worker.rs +21 -1
  19. package/crates/team-agent/src/leader/start.rs +732 -94
  20. package/crates/team-agent/src/leader/tests/identity.rs +64 -57
  21. package/crates/team-agent/src/leader/tests/identity_session_names.rs +42 -0
  22. package/crates/team-agent/src/lib.rs +4 -0
  23. package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +1 -1
  24. package/crates/team-agent/src/lifecycle/launch/spawn.rs +1 -1
  25. package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -1
  26. package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
  27. package/crates/team-agent/src/lifecycle/worker_command_context.rs +29 -11
  28. package/crates/team-agent/src/mcp_server/normalize.rs +1 -0
  29. package/crates/team-agent/src/mcp_server/tests/send.rs +26 -0
  30. package/crates/team-agent/src/mcp_server/tests/wire.rs +1 -1
  31. package/crates/team-agent/src/mcp_server/tools.rs +100 -66
  32. package/crates/team-agent/src/mcp_server/types.rs +5 -0
  33. package/crates/team-agent/src/mcp_server/wire.rs +27 -21
  34. package/crates/team-agent/src/messaging/delivery.rs +105 -38
  35. package/crates/team-agent/src/messaging/leader_channel.rs +33 -10
  36. package/crates/team-agent/src/messaging/leader_receiver.rs +40 -23
  37. package/crates/team-agent/src/messaging/presentation.rs +109 -0
  38. package/crates/team-agent/src/messaging/results.rs +165 -17
  39. package/crates/team-agent/src/messaging/send.rs +94 -81
  40. package/crates/team-agent/src/messaging/tests/leader_channel.rs +6 -6
  41. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +187 -0
  42. package/crates/team-agent/src/messaging/tests/runtime.rs +13 -6
  43. package/crates/team-agent/src/messaging/types.rs +5 -0
  44. package/crates/team-agent/src/messaging/watchers.rs +5 -0
  45. package/crates/team-agent/src/model/mod.rs +1 -0
  46. package/crates/team-agent/src/model/pane_authority_refusal.rs +358 -0
  47. package/crates/team-agent/src/model/spec.rs +16 -0
  48. package/crates/team-agent/src/provider/session/capture.rs +40 -18
  49. package/crates/team-agent/src/provider/session_scan/claude.rs +92 -3
  50. package/crates/team-agent/src/provider/session_scan/common.rs +23 -7
  51. package/crates/team-agent/src/provider/session_scan.rs +5 -0
  52. package/crates/team-agent/src/topology.rs +3 -0
  53. package/package.json +4 -4
  54. package/skills/team-agent/command-coverage.json +379 -0
@@ -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() {
@@ -26,6 +26,7 @@
26
26
  use std::fs;
27
27
  use std::path::Path;
28
28
 
29
+ use crate::communication_mode::CommunicationMode;
29
30
  use crate::model::enums::{Provider, ProviderEffort};
30
31
  use crate::model::yaml::Value;
31
32
  use crate::model::{paths, spec, yaml, ModelError};
@@ -133,6 +134,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
133
134
  }
134
135
 
135
136
  let (team_meta, team_body) = read_front_matter(&team_md)?;
137
+ let team_communication_mode =
138
+ communication_mode_field(&team_meta, &team_md)?.unwrap_or_default();
136
139
  let mut role_paths = Vec::new();
137
140
  if agents_dir.is_dir() {
138
141
  for entry in fs::read_dir(&agents_dir)
@@ -170,7 +173,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
170
173
  let mut agents = Vec::new();
171
174
  let mut agent_ids = Vec::new();
172
175
  for path in role_paths {
173
- let compiled = compile_role_agent(&path, &team_meta, &workspace_s)?;
176
+ let compiled =
177
+ compile_role_agent_with_mode(&path, &team_meta, &workspace_s, team_communication_mode)?;
174
178
  agent_ids.push(compiled.id);
175
179
  agents.push(compiled.agent);
176
180
  }
@@ -371,8 +375,21 @@ pub fn compile_role_agent(
371
375
  role_path: &Path,
372
376
  team_meta: &Value,
373
377
  workspace_s: &str,
378
+ ) -> Result<CompiledRole, ModelError> {
379
+ let team_communication_mode =
380
+ communication_mode_field(team_meta, role_path)?.unwrap_or_default();
381
+ compile_role_agent_with_mode(role_path, team_meta, workspace_s, team_communication_mode)
382
+ }
383
+
384
+ fn compile_role_agent_with_mode(
385
+ role_path: &Path,
386
+ team_meta: &Value,
387
+ workspace_s: &str,
388
+ team_communication_mode: CommunicationMode,
374
389
  ) -> Result<CompiledRole, ModelError> {
375
390
  let (meta, body) = read_front_matter(role_path)?;
391
+ let communication_mode =
392
+ communication_mode_field(&meta, role_path)?.unwrap_or(team_communication_mode);
376
393
  let id = required_string(&meta, role_path, "name")?;
377
394
  let role = required_string(&meta, role_path, "role")?;
378
395
  let provider = required_string(&meta, role_path, "provider")?;
@@ -404,6 +421,10 @@ pub fn compile_role_agent(
404
421
  ),
405
422
  ("tools", list_str(tools)),
406
423
  ("permission_mode", Value::Str("restricted".to_string())),
424
+ (
425
+ "communication_mode",
426
+ Value::Str(communication_mode.as_str().to_string()),
427
+ ),
407
428
  ("preferred_for", list_str(vec![id.clone(), role.clone()])),
408
429
  ("avoid_for", Value::List(Vec::new())),
409
430
  (
@@ -469,6 +490,37 @@ pub fn compile_role_agent(
469
490
  })
470
491
  }
471
492
 
493
+ fn communication_mode_field(
494
+ meta: &Value,
495
+ path: &Path,
496
+ ) -> Result<Option<CommunicationMode>, ModelError> {
497
+ let Some(raw) = meta.get("communication_mode") else {
498
+ return Ok(None);
499
+ };
500
+ let Some(value) = raw.as_str() else {
501
+ return Err(ModelError::Validation(format!(
502
+ "{}: unknown communication_mode (allowed: {})",
503
+ path.display(),
504
+ CommunicationMode::ALL
505
+ .iter()
506
+ .map(|mode| mode.as_str())
507
+ .collect::<Vec<_>>()
508
+ .join("|")
509
+ )));
510
+ };
511
+ CommunicationMode::parse(value).map(Some).ok_or_else(|| {
512
+ ModelError::Validation(format!(
513
+ "{}: unknown communication_mode '{value}' (allowed: {})",
514
+ path.display(),
515
+ CommunicationMode::ALL
516
+ .iter()
517
+ .map(|mode| mode.as_str())
518
+ .collect::<Vec<_>>()
519
+ .join("|")
520
+ ))
521
+ })
522
+ }
523
+
472
524
  fn map(items: Vec<(&str, Value)>) -> Value {
473
525
  Value::Map(items.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
474
526
  }
@@ -97,6 +97,7 @@ pub enum MessageRowStatus {
97
97
  QueuedPaneMissing,
98
98
  TargetResolved,
99
99
  SubmittedAwaitingReceipt,
100
+ InjectedAwaitingReceipt,
100
101
  SubmittedUnverified,
101
102
  Delivered,
102
103
  Acknowledged,
@@ -115,6 +116,7 @@ impl MessageRowStatus {
115
116
  Self::QueuedPaneMissing,
116
117
  Self::TargetResolved,
117
118
  Self::SubmittedAwaitingReceipt,
119
+ Self::InjectedAwaitingReceipt,
118
120
  Self::SubmittedUnverified,
119
121
  Self::Delivered,
120
122
  Self::Acknowledged,
@@ -133,6 +135,7 @@ impl MessageRowStatus {
133
135
  Self::QueuedPaneMissing => "queued_pane_missing",
134
136
  Self::TargetResolved => "target_resolved",
135
137
  Self::SubmittedAwaitingReceipt => "submitted_pending_acceptance",
138
+ Self::InjectedAwaitingReceipt => "injected_awaiting_receipt",
136
139
  Self::SubmittedUnverified => "submitted_unverified",
137
140
  Self::Delivered => "delivered",
138
141
  Self::Acknowledged => "acknowledged",
@@ -394,7 +397,10 @@ impl MessageStore {
394
397
  acknowledged_at = case when ?2 = 'acknowledged' then ?3 else acknowledged_at end,
395
398
  error = case when ?2 = 'delivered' then null else coalesce(?4, error) end
396
399
  where message_id = ?1
397
- and status not in ('acknowledged', 'consumed', 'submitted_pending_acceptance')
400
+ and status not in (
401
+ 'acknowledged', 'consumed', 'submitted_pending_acceptance',
402
+ 'injected_awaiting_receipt'
403
+ )
398
404
  and (status != 'delivered' or ?2 in ('delivered', 'acknowledged'))
399
405
  and (?2 != 'acknowledged' or status = 'delivered')",
400
406
  params![message_id, status, now, error],
@@ -468,6 +474,44 @@ impl MessageStore {
468
474
  Ok(())
469
475
  }
470
476
 
477
+ /// Persist a verified leader transport submission when no provider receipt
478
+ /// source is available. This state is claim/requeue-ineligible but does not
479
+ /// clear the delivery obligation; `consumed_at` remains unset until a
480
+ /// provider-side receipt reaches `mark_delivered_with_receipt`.
481
+ pub fn mark_injected_awaiting_receipt(
482
+ &self,
483
+ message_id: &str,
484
+ ) -> Result<(), MessageStoreError> {
485
+ let conn = crate::db::schema::open_db(&self.path)?;
486
+ let changed = conn.execute(
487
+ "update messages
488
+ set status = ?2,
489
+ updated_at = ?3,
490
+ error = 'leader_receipt_source_unavailable'
491
+ where message_id = ?1
492
+ and status in (?4, ?5, ?6)
493
+ and exists (
494
+ select 1 from delivery_tokens
495
+ where delivery_tokens.message_id = messages.message_id
496
+ and delivery_tokens.injected_at is not null
497
+ )",
498
+ params![
499
+ message_id,
500
+ MessageRowStatus::InjectedAwaitingReceipt.as_str(),
501
+ now_ts(),
502
+ MessageRowStatus::TargetResolved.as_str(),
503
+ MessageRowStatus::SubmittedAwaitingReceipt.as_str(),
504
+ MessageRowStatus::InjectedAwaitingReceipt.as_str(),
505
+ ],
506
+ )?;
507
+ if changed != 1 {
508
+ return Err(MessageStoreError::DeliveryReceiptMissing(
509
+ message_id.to_string(),
510
+ ));
511
+ }
512
+ Ok(())
513
+ }
514
+
471
515
  /// Atomically persist the provider-side receipt and advance the message to
472
516
  /// delivered. A transport-only caller cannot use this without first
473
517
  /// recording the submission row above.
@@ -153,7 +153,7 @@ fn fake_envelope(
153
153
  ) -> serde_json::Value {
154
154
  serde_json::json!({
155
155
  "schema_version": "result_envelope_v1",
156
- "task_id": task_id.unwrap_or("manual"),
156
+ "task_id": task_id.unwrap_or(message_id),
157
157
  "agent_id": agent_id,
158
158
  "status": "success",
159
159
  "summary": format!("Fake worker handled message {message_id}"),
@@ -280,4 +280,24 @@ mod tests {
280
280
  "rendered form prints WORKING per line; got {printed}"
281
281
  );
282
282
  }
283
+
284
+ #[test]
285
+ fn fake_worker_direct_message_uses_message_scope_instead_of_manual() {
286
+ let ws = fake_ws();
287
+ let input = "Team Agent message from leader:\nplease do X\n[team-agent-token:m1]\n";
288
+ let mut out: Vec<u8> = Vec::new();
289
+ run(&ws, "w1", Cursor::new(input.as_bytes()), &mut out).expect("fake worker run");
290
+
291
+ let (task_id, agent_id, status, envelope) = stored_result(&ws);
292
+ assert_eq!(
293
+ (task_id.as_str(), agent_id.as_str(), status.as_str()),
294
+ ("m1", "w1", "success"),
295
+ "a direct-message result must use its message id for message-scope collection"
296
+ );
297
+ assert_ne!(
298
+ envelope["task_id"],
299
+ serde_json::json!("manual"),
300
+ "the fake worker must not emit the production-impossible manual fallback"
301
+ );
302
+ }
283
303
  }