oacp-cli 0.3.2__tar.gz → 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/CHANGELOG.md +23 -0
  2. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/PKG-INFO +2 -2
  3. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/QUICKSTART.md +5 -2
  4. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/README.md +1 -1
  5. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/from-claude-p.md +5 -5
  6. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/guides/prompt_caching.md +8 -6
  7. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/guides/runtime_capability_matrix.md +34 -21
  8. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/task_negotiation.md +4 -1
  9. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/pyproject.toml +1 -1
  10. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/oacp_inbox.py +8 -4
  11. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/oacp_watch.py +24 -1
  12. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/send_inbox_message.py +28 -5
  13. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_memory_archive.py +2 -0
  14. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_oacp_inbox.py +37 -0
  15. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_oacp_watch.py +63 -0
  16. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_send_inbox_message.py +129 -0
  17. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/.github/workflows/ci.yml +0 -0
  18. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/.github/workflows/release.yml +0 -0
  19. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/.gitignore +0 -0
  20. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/CONTRIBUTING.md +0 -0
  21. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/LICENSE +0 -0
  22. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/Makefile +0 -0
  23. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/SECURITY.md +0 -0
  24. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/SPEC.md +0 -0
  25. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/guides/adoption.md +0 -0
  26. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/guides/doctor.md +0 -0
  27. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/guides/setup.md +0 -0
  28. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/guides/unified_skill_spec.md +0 -0
  29. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/guides/versioning.md +0 -0
  30. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/img/oacp-cli-demo.png +0 -0
  31. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/img/oacp-filesystem-tree.png +0 -0
  32. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/img/oacp-fleet-thread.png +0 -0
  33. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/agent_profiles.md +0 -0
  34. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/agent_safety_defaults.md +0 -0
  35. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/autonomy.md +0 -0
  36. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/credential_scoping.md +0 -0
  37. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/cross_runtime_sync.md +0 -0
  38. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/dispatch_states.yaml +0 -0
  39. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/inbox_outbox.md +0 -0
  40. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/mcp_integration.md +0 -0
  41. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/multi_agent_shared_workspace.md +0 -0
  42. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/org_memory.md +0 -0
  43. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/packet_states.yaml +0 -0
  44. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/review_loop.md +0 -0
  45. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/runtime_capabilities.md +0 -0
  46. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/session_init.md +0 -0
  47. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/docs/protocol/skills_manifest.yaml +0 -0
  48. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/examples/quickstart/README.md +0 -0
  49. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/mcp_servers/oacp_coordinator.py +0 -0
  50. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/oacp/__init__.py +0 -0
  51. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/oacp/cli.py +0 -0
  52. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/_oacp_constants.py +0 -0
  53. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/_oacp_env.py +0 -0
  54. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/add_agent.py +0 -0
  55. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/agent_profile.py +0 -0
  56. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/autonomy_gate.py +0 -0
  57. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/check_quality_gate.py +0 -0
  58. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/codex_session_init.py +0 -0
  59. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/create_handoff_packet.py +0 -0
  60. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/handoff_schema.py +0 -0
  61. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/init_org_memory.py +0 -0
  62. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/init_packet.sh +0 -0
  63. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/init_project_workspace.py +0 -0
  64. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/init_project_workspace.sh +0 -0
  65. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/memory_archive_common.py +0 -0
  66. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/memory_cli.py +0 -0
  67. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/memory_sync.py +0 -0
  68. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/normalize_findings.py +0 -0
  69. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/oacp_doctor.py +0 -0
  70. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/preflight.py +0 -0
  71. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/promote_to_archive.py +0 -0
  72. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/restore_from_archive.py +0 -0
  73. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/session_lifecycle_hooks.py +0 -0
  74. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/setup_runtime.py +0 -0
  75. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/update_workspace.sh +0 -0
  76. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/validate_agent_card.py +0 -0
  77. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/validate_message.py +0 -0
  78. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/scripts/write_event.py +0 -0
  79. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/agent_card.template.yaml +0 -0
  80. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/agent_profile.template.yaml +0 -0
  81. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/agent_status.template.yaml +0 -0
  82. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/checkpoint.template.md +0 -0
  83. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/claude/agents/role_agent.template.md +0 -0
  84. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/claude/rules/guardrail.template.md +0 -0
  85. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/findings_packet.template.yaml +0 -0
  86. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/github_actions_quality_gate.yaml +0 -0
  87. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/guardrails/coding_standards.template.md +0 -0
  88. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/guardrails/safe_commands.template.md +0 -0
  89. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/guardrails/secrets_rules.template.md +0 -0
  90. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/handoff_packet.template.yaml +0 -0
  91. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/inbox_message.template.yaml +0 -0
  92. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/manual_validation.template.md +0 -0
  93. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/merge_decision.template.md +0 -0
  94. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/org-memory/decisions.md +0 -0
  95. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/org-memory/events/.gitkeep +0 -0
  96. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/org-memory/events/20260317-170120-example-api-convention.md +0 -0
  97. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/org-memory/recent.md +0 -0
  98. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/org-memory/rules.md +0 -0
  99. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/receiver_config.template.yaml +0 -0
  100. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/review_packet.template.md +0 -0
  101. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/roles/role_baseline.template.md +0 -0
  102. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/roles/role_definition.template.yaml +0 -0
  103. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/runtime_capabilities.yaml +0 -0
  104. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/skills_manifest.template.yaml +0 -0
  105. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/templates/test_packet.template.md +0 -0
  106. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/README.md +0 -0
  107. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/actuals/checkpoint_breach.yaml +0 -0
  108. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/actuals/continuation_drift.yaml +0 -0
  109. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/actuals/continuation_within.yaml +0 -0
  110. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/actuals/top_level_side_effect_keys.yaml +0 -0
  111. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/configs/always_pause.yaml +0 -0
  112. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/configs/auto_review_continuation_enabled.yaml +0 -0
  113. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/configs/auto_review_standard.yaml +0 -0
  114. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/configs/auto_review_tight.yaml +0 -0
  115. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/configs/malformed_config.yaml +0 -0
  116. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/always_pause_task.yaml +0 -0
  117. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/ambiguous_scope_pauses.yaml +0 -0
  118. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/brainstorm_destructive_pauses.yaml +0 -0
  119. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/brainstorm_side_effect_verbs_auto_accepts.yaml +0 -0
  120. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/brainstorm_without_profile_auto_accepts.yaml +0 -0
  121. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/checkpoint_breach_pauses.yaml +0 -0
  122. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/clean_auto_review_task.yaml +0 -0
  123. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/continuation_grant_destructive_pauses.yaml +0 -0
  124. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/continuation_grant_disabled_pauses.yaml +0 -0
  125. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/continuation_grant_drift_pauses.yaml +0 -0
  126. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/continuation_grant_enabled_auto_accepts.yaml +0 -0
  127. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/continuation_grant_external_uncovered_pauses.yaml +0 -0
  128. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/hard_stop_dangerously_skip_permissions_pauses.yaml +0 -0
  129. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/hard_stop_external_side_effects_pauses.yaml +0 -0
  130. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/hard_stop_force_pauses.yaml +0 -0
  131. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/hard_stop_no_verify_pauses.yaml +0 -0
  132. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/hard_stop_no_verify_upper_pauses.yaml +0 -0
  133. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/hard_stop_rm_rf_pauses.yaml +0 -0
  134. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/hard_stop_sensitive_scope_pauses.yaml +0 -0
  135. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/malformed_config_pauses.yaml +0 -0
  136. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/missing_task_profile_pauses.yaml +0 -0
  137. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/path_like_deploy_auto_accepts.yaml +0 -0
  138. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/risk_obvious_no_profile_pauses.yaml +0 -0
  139. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/side_effect_booleans_pause.yaml +0 -0
  140. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/threshold_breach_pauses.yaml +0 -0
  141. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/tight_threshold_pauses.yaml +0 -0
  142. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/top_level_side_effect_actuals_ignored.yaml +0 -0
  143. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/expected/unparsable_task_profile_pauses.yaml +0 -0
  144. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/ambiguous_scope.yaml +0 -0
  145. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/brainstorm_destructive.yaml +0 -0
  146. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/brainstorm_side_effect_verbs.yaml +0 -0
  147. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/brainstorm_without_profile.yaml +0 -0
  148. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/clean_task.yaml +0 -0
  149. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/continuation_grant.yaml +0 -0
  150. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/continuation_grant_destructive.yaml +0 -0
  151. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/continuation_grant_external_uncovered.yaml +0 -0
  152. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/hard_stop_dangerously_skip_permissions.yaml +0 -0
  153. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/hard_stop_external_side_effects.yaml +0 -0
  154. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/hard_stop_force.yaml +0 -0
  155. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/hard_stop_no_verify.yaml +0 -0
  156. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/hard_stop_no_verify_upper.yaml +0 -0
  157. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/hard_stop_rm_rf.yaml +0 -0
  158. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/hard_stop_sensitive_scope.yaml +0 -0
  159. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/missing_task_profile.yaml +0 -0
  160. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/path_like_deploy.yaml +0 -0
  161. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/risk_obvious_no_profile.yaml +0 -0
  162. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/side_effect_booleans.yaml +0 -0
  163. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/threshold_breach.yaml +0 -0
  164. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/conformance/autonomy/messages/unparsable_task_profile.yaml +0 -0
  165. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_add_agent.py +0 -0
  166. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_agent_profile.py +0 -0
  167. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_autonomy_conformance_fixtures.py +0 -0
  168. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_autonomy_gate.py +0 -0
  169. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_codex_session_init.py +0 -0
  170. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_create_handoff_packet.py +0 -0
  171. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_github_workflows.py +0 -0
  172. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_handoff_schema.py +0 -0
  173. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_init_project_workspace.py +0 -0
  174. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_oacp_cli.py +0 -0
  175. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_oacp_constants.py +0 -0
  176. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_oacp_coordinator.py +0 -0
  177. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_oacp_doctor.py +0 -0
  178. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_oacp_env.py +0 -0
  179. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_preflight.py +0 -0
  180. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_review_loop.py +0 -0
  181. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_session_lifecycle_hooks.py +0 -0
  182. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_setup_runtime.py +0 -0
  183. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_update_workspace.py +0 -0
  184. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_validate_agent_card.py +0 -0
  185. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_validate_message.py +0 -0
  186. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_workspace_discovery.py +0 -0
  187. {oacp_cli-0.3.2 → oacp_cli-0.3.3}/tests/test_write_event.py +0 -0
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.3] - 2026-06-11
9
+
10
+ ### Added
11
+
12
+ - `oacp watch --state-id <id>` for per-subscriber cursor files, allowing
13
+ concurrent watchers of the same agent inbox to receive the same new-message
14
+ events without sharing a cursor.
15
+
16
+ ### Changed
17
+
18
+ - Docs: refreshed the runtime capability matrix and prompt-caching guidance
19
+ for current runtime releases.
20
+
21
+ ### Fixed
22
+
23
+ - `oacp send --oacp-dir` and `oacp inbox --oacp-dir` now expand `~` through the
24
+ shared OACP home resolver instead of treating it as a literal path component.
25
+ - Inbox and outbox delivery writes now use same-directory temp files plus
26
+ atomic replace so readers do not observe partial `.yaml` messages.
27
+ - Memory archive tests now isolate git config while preserving test identities,
28
+ so local commit-signing settings do not break the suite.
29
+
8
30
  ## [0.3.2] - 2026-05-26
9
31
 
10
32
  ### Added
@@ -158,6 +180,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
158
180
  - Checkout step in github-release workflow job (#19)
159
181
  - Pre-release audit fixes: SHA-pinned actions, dangling doc refs (#15, #16)
160
182
 
183
+ [0.3.3]: https://github.com/kiloloop/oacp/compare/v0.3.2...v0.3.3
161
184
  [0.3.2]: https://github.com/kiloloop/oacp/compare/v0.3.1...v0.3.2
162
185
  [0.3.1]: https://github.com/kiloloop/oacp/compare/v0.3.0...v0.3.1
163
186
  [0.3.0]: https://github.com/kiloloop/oacp/compare/v0.2.3...v0.3.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oacp-cli
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: Open Agent Coordination Protocol CLI for file-based multi-agent workflows
5
5
  Project-URL: Homepage, https://github.com/kiloloop/oacp
6
6
  Project-URL: Repository, https://github.com/kiloloop/oacp
@@ -270,7 +270,7 @@ uv tool install .
270
270
 
271
271
  **`oacp send`**: `--in-reply-to`, `--expires`, `--body-file`, `--channel`, `--dry-run`, `--json`, `--quiet`
272
272
 
273
- **`oacp watch`**: `--agent`, repeatable `--project`, `--all-projects`, `--json`, `--since` (default `now`), `--show-archived`
273
+ **`oacp watch`**: `--agent`, repeatable `--project`, `--all-projects`, `--json`, `--since` (default `now`), `--state-id <id>` for per-subscriber cursors, `--show-archived`
274
274
 
275
275
  **`oacp doctor`**: `--fix` (auto-fix safe issues), `--memory`, `--json`, `-o/--output`
276
276
 
@@ -157,11 +157,14 @@ body: |
157
157
 
158
158
  To watch for new messages from a standing runtime or Monitor, use `oacp watch`.
159
159
  A single `oacp watch` run scans once and exits, so keep re-running it when you
160
- want a persistent worker:
160
+ want a persistent worker. If more than one watcher follows the same agent
161
+ inbox, give each watcher a stable `--state-id` so each subscriber has its own
162
+ cursor:
161
163
 
162
164
  ```bash
165
+ OACP_WATCH_STATE_ID="${OACP_WATCH_STATE_ID:-$(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')}"
163
166
  while true; do
164
- oacp watch --project my-first-project --agent codex || true
167
+ oacp watch --project my-first-project --agent codex --state-id "$OACP_WATCH_STATE_ID" || true
165
168
  sleep 120
166
169
  done
167
170
  ```
@@ -244,7 +244,7 @@ uv tool install .
244
244
 
245
245
  **`oacp send`**: `--in-reply-to`, `--expires`, `--body-file`, `--channel`, `--dry-run`, `--json`, `--quiet`
246
246
 
247
- **`oacp watch`**: `--agent`, repeatable `--project`, `--all-projects`, `--json`, `--since` (default `now`), `--show-archived`
247
+ **`oacp watch`**: `--agent`, repeatable `--project`, `--all-projects`, `--json`, `--since` (default `now`), `--state-id <id>` for per-subscriber cursors, `--show-archived`
248
248
 
249
249
  **`oacp doctor`**: `--fix` (auto-fix safe issues), `--memory`, `--json`, `-o/--output`
250
250
 
@@ -79,10 +79,9 @@ Set me up as an async OACP worker for this repo.
79
79
  --project form checks this workspace's inbox, schema, and status.
80
80
  6. Start a Monitor that keeps oacp watch re-running for the claude
81
81
  agent on this project. A single oacp watch does one scan and exits,
82
- so it has to run on a loop — while true; do oacp watch --project
83
- <project> --agent claude || true; sleep 120; done — otherwise you
84
- only pick up tasks that happened to be there at setup time. Then
85
- tell me the exact oacp send command I use to dispatch a task to you.
82
+ so it has to run on a loop. Use a stable --state-id for that Monitor
83
+ so concurrent watchers each keep their own cursor. Then tell me the
84
+ exact oacp send command I use to dispatch a task to you.
86
85
 
87
86
  Protocol reference: https://github.com/kiloloop/oacp/blob/main/QUICKSTART.md
88
87
  ~~~
@@ -116,8 +115,9 @@ oacp doctor --project my-project
116
115
  Then, in a Claude Code session, arm the watcher in a Monitor. `oacp watch` does one scan and exits, so it has to run on a loop:
117
116
 
118
117
  ```
118
+ OACP_WATCH_STATE_ID="${OACP_WATCH_STATE_ID:-$(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')}"
119
119
  while true; do
120
- oacp watch --project my-project --agent claude || true
120
+ oacp watch --project my-project --agent claude --state-id "$OACP_WATCH_STATE_ID" || true
121
121
  sleep 120
122
122
  done
123
123
  ```
@@ -5,8 +5,8 @@ How to maximize prompt cache hits across Claude, Codex, and Gemini to reduce cos
5
5
  ## Why It Matters
6
6
 
7
7
  Prompt caching avoids reprocessing static context (system prompts, CLAUDE.md, project facts) on every turn. In practice:
8
- - **Cache read**: 10x cheaper than uncached input ($1.50/MTok vs $15/MTok for Opus)
9
- - **Cache write**: 1.25x input price (one-time cost, amortized over subsequent reads)
8
+ - **Cache read**: 10x cheaper than uncached input ($0.50/MTok vs $5.00/MTok for Opus 4.8)
9
+ - **Cache write**: 1.25x input price for the default 5-minute TTL, 2x for the 1-hour TTL (one-time cost, amortized over subsequent reads)
10
10
  - **Observed savings**: 83-95% cost reduction on cached input in multi-turn agent sessions
11
11
 
12
12
  ## Claude
@@ -127,13 +127,14 @@ Gemini supports implicit context caching for large prompts. The API automaticall
127
127
 
128
128
  ## Cost Comparison
129
129
 
130
- Approximate pricing as of early 2026 (per million tokens). Check each provider's current pricing page for up-to-date rates:
130
+ Approximate pricing as of June 2026 (per million tokens). Cache read is 0.1x input; cache write is shown at the default 5-minute TTL (1.25x input) — the 1-hour TTL costs 2x input. Check each provider's current pricing page for up-to-date rates:
131
131
 
132
132
  | Runtime | Input | Cached Read | Cache Write | Output |
133
133
  |---------|------:|------------:|------------:|-------:|
134
- | Claude Opus | $15.00 | $1.50 | $18.75 | $75.00 |
135
- | Claude Sonnet | $3.00 | $0.30 | $3.75 | $15.00 |
136
- | Claude Haiku | $0.80 | $0.08 | $1.00 | $4.00 |
134
+ | Claude Fable 5 | $10.00 | $1.00 | $12.50 | $50.00 |
135
+ | Claude Opus (4.6/4.7/4.8) | $5.00 | $0.50 | $6.25 | $25.00 |
136
+ | Claude Sonnet 4.6 | $3.00 | $0.30 | $3.75 | $15.00 |
137
+ | Claude Haiku 4.5 | $1.00 | $0.10 | $1.25 | $5.00 |
137
138
  | Codex | varies | N/A | N/A | varies |
138
139
  | Gemini Pro | $1.25 | $0.31 | — | $10.00 |
139
140
 
@@ -146,3 +147,4 @@ Approximate pricing as of early 2026 (per million tokens). Check each provider's
146
147
  - Injecting timestamps or random IDs into system prompts
147
148
  - Reordering tool definitions between turns
148
149
  - Changing the user message prefix frequently
150
+ 5. **Mind the minimum cacheable prefix** — prefixes below the model minimum silently don't cache (no error; `cache_creation_input_tokens` stays 0). The minimum is 2,048 tokens on Fable 5 and Sonnet 4.6, and 4,096 tokens on Opus 4.8/4.7/4.6 and Haiku 4.5.
@@ -1,12 +1,12 @@
1
1
  # Cross-Runtime Parity Matrix
2
2
 
3
- **Date**: 2026-04-29
3
+ **Date**: 2026-06-09
4
4
 
5
5
  This is a capability comparison across the currently profiled agent runtimes (Claude Code, Codex, Gemini), compiled from each runtime's self-report and current runtime changelogs. Cursor support is scaffold-only until Cursor-owned onboarding lands, so Cursor is intentionally excluded from this comparison table; see `docs/protocol/runtime_capabilities.md` for its conservative scaffold defaults.
6
6
 
7
- Claude was last checked against Claude Code `v2.1.123`.
7
+ Claude was last checked against Claude Code `v2.1.170` with Claude Fable 5 (`claude-fable-5`, serving model verified in-session on the 1M-context variant). Fable 5 (released 2026-06-09, first Mythos-class model) is included at no extra cost on Pro/Max/Team/Enterprise plans Jun 9–22, 2026, with usage credits required after; Opus 4.8 remains available and serves as Fable 5's safeguard-fallback model.
8
8
 
9
- Codex was last checked against app update `26.415`, CLI `0.123.0`, and OpenAI's GPT-5.5 launch note from 2026-04-23.
9
+ Codex was last checked against app update `26.602`, CLI `0.137.0`, OpenAI's GPT-5.5 launch note from 2026-04-23, and the June 2026 Codex/API entries for Sites and Amazon Bedrock.
10
10
 
11
11
  ---
12
12
 
@@ -15,19 +15,19 @@ Codex was last checked against app update `26.415`, CLI `0.123.0`, and OpenAI's
15
15
  | Capability | Claude (Claude Code CLI) | Codex (Desktop App) | Gemini |
16
16
  | ---------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
17
17
  | Spawn background tasks | Yes — Task tool + Bash `run_in_background` | Yes — shell background processes | Yes — `run_command` async mode |
18
- | Spawn subagents | Yes — typed agents (Explore, Plan, general-purpose, code-reviewer, etc.) | Yes — native `spawn_agent` lifecycle with `default`, `explorer`, and `worker` agents | Partial — `browser_subagent` only |
18
+ | Spawn subagents | Yes — typed agents (Explore, Plan, general-purpose, code-reviewer, etc.) | Yes — native multi-agent lifecycle with runtime metadata and follow-up defaults | Partial — `browser_subagent` only |
19
19
  | Parallel agent teams | Yes — TeamCreate, task lists, SendMessage, broadcast | Partial — parallel spawned agents are supported, but there is no team/task-list primitive | No — parallel tool calls but no independent agent instances |
20
- | MCP tools | Yes — extensible via MCP servers | Yes — MCP/plugin support with `/mcp verbose` diagnostics; configuration-dependent | Yes — MCP server support |
21
- | Web search | Yes — native WebSearch tool | Yes — web search/fetch tools | Yes — native `search_web` tool |
22
- | Browser interaction | Partial — WebFetch (read-only, HTML→markdown) | Partial — web tools plus early in-app browser for local/public pages without sign-in | Yes — full browser control (click, type, navigate, screenshot, video) |
23
- | File system access | Sandboxed — configurable read/write allowlists | Policy-dependent per session; sandbox profiles can include deny-read rules | Full — unrestricted |
20
+ | MCP tools | Yes — extensible via MCP servers | Yes — MCP/plugin support with `/mcp verbose`, per-server environment targeting, read-only MCP parallelism, and scriptable plugin inventory | Yes — MCP server support |
21
+ | Web search | Yes — native WebSearch tool | Yes — web search/fetch tools; hosted web tools are expanding in code-mode flows | Yes — native `search_web` tool |
22
+ | Browser interaction | Partial — WebFetch (read-only, HTML→markdown) | Partial — in-app browser and Chrome extension can inspect local/public and approved browser contexts, with faster asset extraction and read-only JS structured-data extraction; not full browser automation | Yes — full browser control (click, type, navigate, screenshot, video) |
23
+ | File system access | Sandboxed — configurable read/write allowlists | Policy-dependent per session; named permission profiles can include deny-read rules and managed requirements | Full — unrestricted |
24
24
  | Git operations | Yes — via Bash (may need sandbox configuration) | Yes — native | Yes — via shell |
25
25
  | GitHub CLI (gh) | Yes — via Bash (may need sandbox configuration) | Yes — authenticated | Yes — native |
26
26
  | Session memory | Strong — auto-loaded MEMORY.md + optional MCP memory | Partial — app memories where available plus OACP file memory; app memories are not protocol SSOT | Partial — Knowledge Items (not directly writable), conversation logs |
27
- | Interactive mode | Yes — CLI chat with permissions, plan mode | Yes — desktop app and CLI/TUI, including Plan Mode and side conversations | Yes — chat with task UI, artifacts |
28
- | Context window | ~1M with Opus 4.7 (auto-compaction extends indefinitely) | Model-dependent; GPT-5.5 in Codex is documented at 400K, with no auto-compaction guarantee | ~1M tokens |
29
- | Cost model | Token-based, visible in statusline | Not surfaced per session; GPT-5.5 Fast mode trades 2.5x cost for 1.5x token generation speed | Token-based |
30
- | Sandbox restrictions | Yes — configurable allowlists | Session-dependent; supports deny-read policies, isolated `codex exec`, and remote sandbox requirements | None — full system access |
27
+ | Interactive mode | Yes — CLI chat with permissions, plan mode | Yes — desktop app and CLI/TUI, including Plan Mode, Goal mode, side conversations, and archive/unarchive flows | Yes — chat with task UI, artifacts |
28
+ | Context window | ~1M with Fable 5 or Opus 4.8 (auto-compaction extends indefinitely) | Model-dependent; GPT-5.5 in Codex is documented at 400K, with no auto-compaction guarantee | ~1M tokens |
29
+ | Cost model | Token-based, visible in statusline; Fable 5 API rate is $10/$50 per MTok (2× Opus 4.8's $5/$25) | Not surfaced per session; GPT-5.5 Fast mode trades 2.5x cost for 1.5x token generation speed | Token-based |
30
+ | Sandbox restrictions | Yes — configurable allowlists | Session-dependent; supports deny-read policies, isolated `codex exec`, named permission profiles, managed requirements, and explicit approval policies | None — full system access |
31
31
 
32
32
  ---
33
33
 
@@ -37,6 +37,7 @@ Codex was last checked against app update `26.415`, CLI `0.123.0`, and OpenAI's
37
37
  | -------------------------------- | ------------- | ---------------------------------------------------------------------------- |
38
38
  | Typed subagent orchestration | Claude | Multiple agent types with scoped tools and model selection |
39
39
  | Team coordination primitive | Claude | TeamCreate + task lists + assignment + broadcast + shutdown |
40
+ | Dynamic multi-agent workflows | Claude | Workflow tool orchestrates tens–hundreds of agents; `/workflows` to view |
40
41
  | Plan mode | Claude, Codex | Claude has structured explore → plan → approve → implement; Codex CLI can move from planning into fresh-context implementation |
41
42
  | Auto-compaction | Claude | Context auto-compresses, enabling unlimited session length |
42
43
  | Cross-session semantic search | Claude | MCP-based searchable memory (optional) |
@@ -48,8 +49,14 @@ Codex was last checked against app update `26.415`, CLI `0.123.0`, and OpenAI's
48
49
  | PTY / terminal stdin | Codex, Gemini | Codex: native PTY; Gemini: `send_command_input` (Claude lacks stdin support) |
49
50
  | `apply_patch` editing | Codex | Grammar-based file edits |
50
51
  | App-level computer use | Codex | macOS app, simulator, and GUI-only workflows; unavailable in EEA, UK, and Switzerland at launch |
52
+ | Windows computer use | Codex | Codex app can operate Windows desktop apps in the foreground when available |
53
+ | Remote host control | Codex | Mobile or desktop remote control can run work on connected Mac or Windows hosts with host-local files, credentials, plugins, skills, and config |
51
54
  | App-level artifact review | Codex | Sidebar preview for generated PDFs, spreadsheets, documents, and presentations |
52
55
  | App-level PR review | Codex | PR sidebar can inspect changed files, review comments, and follow-up fixes |
56
+ | App-server automation | Codex | JSON-RPC app-server, SDK, schema generation, thread APIs, and websocket/Unix-socket transports for custom clients |
57
+ | Hosted site deployment | Codex | Sites preview can create, deploy, inspect, and manage hosted websites or internal tools through the Codex app |
58
+ | Plugin marketplace inventory | Codex | Plugin directory plus `codex plugin list --json` for installed plugin inventory and marketplace-aware diagnostics |
59
+ | Goal mode | Codex | Stable long-running objective mode with dedicated state; candidate for OACP wait/review-loop experiments |
53
60
 
54
61
  ---
55
62
 
@@ -71,9 +78,9 @@ Scope: skills shipped in [`kiloloop/oacp-skills`](https://github.com/kiloloop/oa
71
78
 
72
79
  | Dimension | Claude | Codex | Gemini |
73
80
  | --------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------- |
74
- | Best at | Orchestration, multi-agent teams, persistent memory, plan-then-execute | Terminal-native execution, GPT-5.5 agentic coding, fast iterative patching, plan-to-implementation handoff, app-assisted PR/artifact review, protocol discipline | Web research, browser automation, visual verification, large context |
75
- | Ideal task type | Team coordination, complex multi-file refactors, long-running sessions | Shell-heavy workflows, long-horizon coding, targeted file edits, deterministic scripts, PR follow-up, artifact review, CLI planning passes | External research, UI testing, document review, MCP integrations |
76
- | Cost profile | Flexible (haiku subagents for cheap tasks, opus for complex) | Per-session cost not visible; GPT-5.5 is described as more token-efficient than GPT-5.4 for Codex tasks | Token-based, web search has additional costs |
81
+ | Best at | Orchestration, multi-agent teams, persistent memory, plan-then-execute | Terminal-native execution, GPT-5.5 agentic coding, fast iterative patching, plan-to-implementation handoff, app-assisted PR/artifact review, app-server automation, protocol discipline | Web research, browser automation, visual verification, large context |
82
+ | Ideal task type | Team coordination, complex multi-file refactors, long-running sessions | Shell-heavy workflows, long-horizon coding, targeted file edits, deterministic scripts, PR follow-up, artifact review, CLI planning passes, plugin/app-server automation prototypes | External research, UI testing, document review, MCP integrations |
83
+ | Cost profile | Flexible (haiku subagents for cheap tasks, opus for complex, Fable 5 at 2× Opus API rates for the hardest work) | Per-session cost not visible; GPT-5.5 is described as more token-efficient than GPT-5.4 for Codex tasks | Token-based, web search has additional costs |
77
84
 
78
85
  ---
79
86
 
@@ -82,7 +89,7 @@ Scope: skills shipped in [`kiloloop/oacp-skills`](https://github.com/kiloloop/oa
82
89
  | Limitation | Claude | Codex | Gemini |
83
90
  | ----------------------------- | ----------------------------- | -------------------------------------------------------------- | ---------------------- |
84
91
  | No subagents | — | Yes | Partial (browser only) |
85
- | No browser automation | Yes (read-only) | Partial (in-app browser is not full automation and excludes sign-in flows) | — |
92
+ | No browser automation | Yes (read-only) | Partial (in-app browser and Chrome extension are useful for review/verification, but not a general full-browser automation substitute) | — |
86
93
  | No image generation | Yes | — | — |
87
94
  | No persistent writable memory | — | Partial (app memories are not a replacement for OACP durable memory) | Yes |
88
95
  | Sandbox friction | Yes (configurable) | Session-dependent | — |
@@ -90,6 +97,7 @@ Scope: skills shipped in [`kiloloop/oacp-skills`](https://github.com/kiloloop/oa
90
97
  | Context limits | Auto-compaction mitigates | Model-dependent; GPT-5.5 in Codex is 400K, but there is no documented auto-compaction behavior | Large but finite |
91
98
  | No terminal stdin | Yes | — | — |
92
99
  | Cost not surfaced | — | Yes | — |
100
+ | Serving model can change mid-session | Yes (Fable 5 only — cyber/bio-chem/distillation classifiers fall back to Opus 4.8; default and non-configurable in Claude interfaces incl. Claude Code, with a session event emitted; <5% of sessions — system card §1.5) | — | — |
93
101
 
94
102
  ---
95
103
 
@@ -102,7 +110,7 @@ These are the highest-impact gaps where one runtime's limitation blocks effectiv
102
110
  | No team orchestration | Codex, Gemini | Cannot run parallel agent teams | Agent cards — let runtimes discover and delegate to capable peers |
103
111
  | Memory asymmetry | Codex (partial), Gemini (KIs only) | Cross-session context degrades without MEMORY.md equivalent | Standardize memory protocol; each runtime implements its own persistence layer |
104
112
  | Sandbox blocks git/gh | Claude | Every git/gh call needs sandbox configuration | Configure sandbox allowlists or disable sandbox for specific commands |
105
- | Full browser automation gap | Claude, Codex | Claude is read-only; Codex has early browser review but not full automation or sign-in flows | Delegate full browser tasks to Gemini; use Codex in-app browser for local/public page review |
113
+ | Full browser automation gap | Claude, Codex | Claude is read-only; Codex has stronger browser review and Chrome-extension support but not full autonomous browser automation | Delegate full browser tasks to Gemini; use Codex browser/Chrome workflows for local, public, or approved signed-in page review |
106
114
  | Reviewer cost | All (especially Claude) | High cost for single PR review with polling pattern | Stateless reviewer rounds — one round per invocation |
107
115
  | Public skill coverage | Gemini | `kiloloop/oacp-skills` ships `claude/` and `codex/` variants for all 5 public skills; no `gemini/` variants — Gemini users must rely on convention-based adoption | Add `gemini/` variants to each public skill, or document the convention-based pattern as a first-class install path |
108
116
 
@@ -114,25 +122,30 @@ These are the highest-impact gaps where one runtime's limitation blocks effectiv
114
122
  | ---------------------------- | -------------------------------- | ------------------------------------------ | --------------------------------------------- |
115
123
  | Max parallel tool calls | ~10+ | Yes (parallel independent calls) | ~10 (practical) |
116
124
  | Side conversations | No | Yes (`/side` in CLI/TUI) | No |
117
- | Hooks system | Yes (pre/post tool call hooks) | No | No |
118
- | Automation scheduling | Yes (`CronCreate`, `ScheduleWakeup`, `/loop`, `/schedule` skills) | Yes (desktop app thread automations wake a thread on a schedule, with user request) | No |
125
+ | Hooks system | Yes (pre/post tool call hooks) | Yes (stable hooks and extension lifecycle hooks; plugin-bundled hooks are configuration-dependent) | No |
126
+ | Automation scheduling | Yes (`CronCreate`, `ScheduleWakeup`, `/loop`, `/schedule` skills) | Yes (desktop app thread automations, Goal mode, and app-server/SDK automation surfaces) | No |
119
127
  | Notebook editing | Yes (NotebookEdit tool) | No | No |
120
128
  | PDF reading | Yes (max 20 pages/request) | No native tool | Via `read_url_content` |
121
129
  | Image reading (multimodal) | Yes | Yes (desktop app local image/view support) | Yes |
122
130
  | Artifact system | No | Yes (sidebar preview for generated files) | Yes (task.md, implementation plans) |
123
131
  | Video recording | No | No | Yes (WebP via browser) |
124
132
  | Image generation | No | Yes (enabled by default in CLI) | Yes |
125
- | MCP diagnostics | Partial | Yes (`/mcp verbose`) | Partial |
133
+ | MCP diagnostics | Partial | Yes (`/mcp verbose`, per-server environment targeting, read-only MCP parallelism, plugin JSON inventory) | Partial |
126
134
  | Multi-file editing primitive | Edit tool (one file at a time) | `apply_patch` (one file) | `multi_replace_file_content` (non-contiguous) |
127
135
  | Workflow file format | SKILL.md with YAML frontmatter | SKILL.md with YAML frontmatter | Markdown with YAML frontmatter |
128
- | Policy visibility at runtime | Partial (sandbox config visible) | Yes (session policy in system context) | Yes (`SafeToAutoRun` flags) |
136
+ | Policy visibility at runtime | Partial (sandbox config visible) | Yes (session policy, approval policy, sandbox, and named permission profiles) | Yes (`SafeToAutoRun` flags) |
129
137
  | Long-running shell sessions | Bash tool (no stdin) | Yes (PTY + stdin; multiple terminals in app) | Yes (`send_command_input`) |
138
+ | App-server / SDK | No | Yes (JSON-RPC app-server, Python SDK, archive/thread APIs, schema generation) | No |
139
+ | Hosted site deployment | No | Yes (Sites preview, app-only/cloud-hosted with separate secret management) | No |
130
140
 
131
141
  ---
132
142
 
133
143
  ## 8. Source Notes
134
144
 
135
145
  - GPT-5.5 Codex availability, 400K context, Fast mode, token-efficiency, and API timing come from OpenAI's 2026-04-23 release note: <https://openai.com/index/introducing-gpt-5-5/>.
146
+ - Codex app/CLI capability changes through app `26.602` and CLI `0.137.0` come from OpenAI's Codex changelog: <https://developers.openai.com/codex/changelog>.
147
+ - Sites, Amazon Bedrock, app-server, plugin, and permissions details come from the official Codex docs under <https://developers.openai.com/codex/>.
148
+ - Claude Fable 5 release date, pricing, and plan-inclusion window come from Anthropic's 2026-06-09 announcement: <https://www.anthropic.com/news/claude-fable-5-mythos-5>. Safeguard-fallback behavior comes from the Fable 5 / Mythos 5 system card §1.5 ("Novel safeguards"): client apps and Claude interfaces auto-fall back to Opus 4.8 (default and non-configurable in interfaces, session event emitted), while the Messages API blocks by default with a structured refusal category and offers opt-in server-side fallback. The serving model in the header was verified in-session by the Claude runtime.
136
149
 
137
150
  ---
138
151
 
@@ -153,7 +153,10 @@ Agents that lack headless mode (e.g., Gemini in some configurations):
153
153
 
154
154
  ### Codex
155
155
 
156
- - Codex operates in `--full-auto` headless mode by default.
156
+ - Codex can run interactively, from the desktop app or CLI, or through
157
+ explicit automation flows. Do not assume legacy `--full-auto` behavior;
158
+ set the intended approval policy, sandbox, and permission profile for the
159
+ receiving environment.
157
160
  - Codex can both propose and receive proposals.
158
161
  - When Codex receives a proposal, it processes the inbox at session start per the inbox/outbox polling convention.
159
162
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oacp-cli"
7
- version = "0.3.2"
7
+ version = "0.3.3"
8
8
  description = "Open Agent Coordination Protocol CLI for file-based multi-agent workflows"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -21,7 +21,7 @@ import datetime as dt
21
21
  import json
22
22
  import sys
23
23
  from pathlib import Path
24
- from typing import Any, Dict, List, Optional, Sequence
24
+ from typing import Any, Dict, List, Optional, Sequence, Union
25
25
 
26
26
  try:
27
27
  import yaml
@@ -35,6 +35,10 @@ def _resolve_oacp_home(explicit: Optional[str] = None) -> Path:
35
35
  return resolve_oacp_home(explicit)
36
36
 
37
37
 
38
+ def _coerce_oacp_home(explicit: Optional[Union[str, Path]]) -> Path:
39
+ return _resolve_oacp_home(str(explicit)) if explicit is not None else _resolve_oacp_home()
40
+
41
+
38
42
  def _load_yaml_mapping(path: Path) -> Dict[str, Any]:
39
43
  raw = path.read_text(encoding="utf-8")
40
44
  if yaml is not None:
@@ -134,14 +138,14 @@ def list_inbox(
134
138
  *,
135
139
  agent: Optional[str] = None,
136
140
  list_all: bool = False,
137
- oacp_dir: Optional[Path] = None,
141
+ oacp_dir: Optional[Union[str, Path]] = None,
138
142
  now: Optional[dt.datetime] = None,
139
143
  ) -> Dict[str, Any]:
140
144
  """Return inbox metadata for one agent or all project agents."""
141
145
  if agent is None and not list_all:
142
146
  raise ValueError("either --agent or --all is required")
143
147
 
144
- oacp_root = oacp_dir or _resolve_oacp_home()
148
+ oacp_root = _coerce_oacp_home(oacp_dir)
145
149
  project_dir = oacp_root / "projects" / project
146
150
  if not project_dir.is_dir():
147
151
  raise ValueError(f"project '{project}' not found under {oacp_root / 'projects'}")
@@ -228,7 +232,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
228
232
  args.project,
229
233
  agent=args.agent,
230
234
  list_all=args.list_all,
231
- oacp_dir=Path(args.oacp_dir) if args.oacp_dir else None,
235
+ oacp_dir=args.oacp_dir if args.oacp_dir else None,
232
236
  )
233
237
  except ValueError as exc:
234
238
  print(f"ERROR: {exc}", file=sys.stderr)
@@ -17,6 +17,7 @@ from __future__ import annotations
17
17
 
18
18
  import argparse
19
19
  import json
20
+ import re
20
21
  import sys
21
22
  import time
22
23
  from dataclasses import dataclass
@@ -33,6 +34,7 @@ except ImportError: # pragma: no cover
33
34
  STATE_VERSION = 1
34
35
 
35
36
  _DURATION_UNITS = {"s": 1, "m": 60, "h": 3600, "d": 86400}
37
+ _STATE_ID_RE = re.compile(r"^[A-Za-z0-9._-]{1,64}$")
36
38
 
37
39
 
38
40
  def _parse_since(spec: str, *, now: float) -> float:
@@ -70,6 +72,7 @@ class WatchTarget:
70
72
  agent: str
71
73
  inbox_dir: Path
72
74
  state_file: Path
75
+ state_id: Optional[str] = None
73
76
 
74
77
 
75
78
  def _resolve_oacp_home(explicit: Optional[str] = None) -> Path:
@@ -183,12 +186,18 @@ def _dedupe_keep_order(values: Iterable[str]) -> List[str]:
183
186
  return result
184
187
 
185
188
 
189
+ def _watch_state_file(project_dir: Path, agent: str, state_id: Optional[str]) -> Path:
190
+ state_name = f"{agent}.json" if state_id is None else f"{agent}.{state_id}.json"
191
+ return project_dir / "state" / "watch" / state_name
192
+
193
+
186
194
  def _resolve_targets(
187
195
  *,
188
196
  projects: Optional[List[str]],
189
197
  all_projects: bool,
190
198
  agent: str,
191
199
  oacp_root: Path,
200
+ state_id: Optional[str] = None,
192
201
  ) -> tuple[List[WatchTarget], List[Dict[str, Any]]]:
193
202
  errors: List[Dict[str, Any]] = []
194
203
  if all_projects:
@@ -243,13 +252,14 @@ def _resolve_targets(
243
252
  )
244
253
  )
245
254
  continue
246
- state_file = project_dir / "state" / "watch" / f"{agent}.json"
255
+ state_file = _watch_state_file(project_dir, agent, state_id)
247
256
  targets.append(
248
257
  WatchTarget(
249
258
  project=project,
250
259
  agent=agent,
251
260
  inbox_dir=inbox_dir,
252
261
  state_file=state_file,
262
+ state_id=state_id,
253
263
  )
254
264
  )
255
265
  return targets, errors
@@ -373,6 +383,14 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
373
383
  parser.add_argument("--agent", required=True, help="Agent inbox name to watch")
374
384
  parser.add_argument("--oacp-dir", default=None, help="Override OACP home directory")
375
385
  parser.add_argument("--json", action="store_true", dest="json_output", help="Emit JSON Lines")
386
+ parser.add_argument(
387
+ "--state-id",
388
+ default=None,
389
+ help=(
390
+ "Use a per-subscriber cursor file state/watch/<agent>.<state-id>.json. "
391
+ "Omit for the legacy shared state/watch/<agent>.json cursor."
392
+ ),
393
+ )
376
394
  parser.add_argument(
377
395
  "--since",
378
396
  default="now",
@@ -394,6 +412,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
394
412
  )
395
413
 
396
414
  args = parser.parse_args(list(argv) if argv is not None else None)
415
+ if args.state_id is not None and not _STATE_ID_RE.fullmatch(args.state_id):
416
+ parser.error("--state-id must match [A-Za-z0-9._-]{1,64}")
397
417
  try:
398
418
  since_epoch = _parse_since(args.since, now=time.time())
399
419
  except argparse.ArgumentTypeError as exc:
@@ -405,6 +425,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
405
425
  all_projects=args.all_projects,
406
426
  agent=args.agent,
407
427
  oacp_root=oacp_root,
428
+ state_id=args.state_id,
408
429
  )
409
430
  had_errors = False
410
431
  if target_errors:
@@ -457,6 +478,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
457
478
  "agent": target.agent,
458
479
  "messages": current_messages,
459
480
  }
481
+ if target.state_id is not None:
482
+ payload["state_id"] = target.state_id
460
483
  try:
461
484
  _write_state(target.state_file, payload)
462
485
  except Exception as exc:
@@ -408,8 +408,8 @@ def write_message_files(
408
408
  inbox_path = inbox_dir / filename
409
409
  outbox_path = outbox_dir / filename
410
410
 
411
- inbox_path.write_text(yaml_content, encoding="utf-8")
412
- outbox_path.write_text(yaml_content, encoding="utf-8")
411
+ _atomic_write_text(inbox_path, yaml_content)
412
+ _atomic_write_text(outbox_path, yaml_content)
413
413
 
414
414
  return inbox_path, outbox_path
415
415
 
@@ -431,19 +431,34 @@ def write_broadcast_files(
431
431
  outbox_dir = project_dir / "agents" / sender / "outbox"
432
432
  outbox_dir.mkdir(parents=True, exist_ok=True)
433
433
  outbox_path = outbox_dir / filename
434
- outbox_path.write_text(yaml_content, encoding="utf-8")
434
+ _atomic_write_text(outbox_path, yaml_content)
435
435
 
436
436
  inbox_paths: List[Path] = []
437
437
  for recipient in recipients:
438
438
  inbox_dir = project_dir / "agents" / recipient / "inbox"
439
439
  inbox_dir.mkdir(parents=True, exist_ok=True)
440
440
  inbox_path = inbox_dir / filename
441
- inbox_path.write_text(yaml_content, encoding="utf-8")
441
+ _atomic_write_text(inbox_path, yaml_content)
442
442
  inbox_paths.append(inbox_path)
443
443
 
444
444
  return inbox_paths, outbox_path
445
445
 
446
446
 
447
+ def _atomic_write_text(path: Path, content: str) -> None:
448
+ """Write content via a same-directory temp file, then atomically replace."""
449
+ temp_name = f".{path.name}.tmp-{os.getpid()}-{secrets.token_hex(3)}"
450
+ temp_path = path.with_name(temp_name)
451
+ try:
452
+ temp_path.write_text(content, encoding="utf-8")
453
+ os.replace(temp_path, path)
454
+ finally:
455
+ try:
456
+ if temp_path.exists():
457
+ temp_path.unlink()
458
+ except OSError:
459
+ pass
460
+
461
+
447
462
  def _parse_status_yaml(raw: str) -> Optional[str]:
448
463
  """Extract the 'status' field value from a status.yaml file.
449
464
 
@@ -521,7 +536,10 @@ def send_message(
521
536
  """
522
537
  if oacp_dir is None:
523
538
  from _oacp_env import resolve_oacp_home
539
+
524
540
  oacp_dir = resolve_oacp_home()
541
+ else:
542
+ oacp_dir = Path(oacp_dir).expanduser()
525
543
 
526
544
  # Parse recipient(s)
527
545
  recipients_list = [r.strip() for r in recipient.split(",") if r.strip()]
@@ -738,7 +756,12 @@ def main() -> int:
738
756
  parser.add_argument("--quiet", action="store_true", help="Suppress success output")
739
757
 
740
758
  args = parser.parse_args()
741
- oacp_dir = Path(args.oacp_dir) if args.oacp_dir else None
759
+ if args.oacp_dir:
760
+ from _oacp_env import resolve_oacp_home
761
+
762
+ oacp_dir = resolve_oacp_home(args.oacp_dir)
763
+ else:
764
+ oacp_dir = None
742
765
 
743
766
  try:
744
767
  sender = infer_sender(args.project, args.sender, oacp_dir=oacp_dir)
@@ -51,6 +51,8 @@ class TestMemoryArchiveScripts(unittest.TestCase):
51
51
  "GIT_AUTHOR_EMAIL": "oacp-test@example.com",
52
52
  "GIT_COMMITTER_NAME": "OACP Test",
53
53
  "GIT_COMMITTER_EMAIL": "oacp-test@example.com",
54
+ "GIT_CONFIG_GLOBAL": os.devnull,
55
+ "GIT_CONFIG_SYSTEM": os.devnull,
54
56
  "OACP_AGENT": "codex",
55
57
  },
56
58
  ):
@@ -7,10 +7,12 @@ from __future__ import annotations
7
7
  import datetime as dt
8
8
  import io
9
9
  import json
10
+ import os
10
11
  import sys
11
12
  import tempfile
12
13
  import unittest
13
14
  from pathlib import Path
15
+ from unittest import mock
14
16
 
15
17
  sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "scripts"))
16
18
 
@@ -156,6 +158,41 @@ class TestMainCli(unittest.TestCase):
156
158
  self.assertEqual(payload["project"], "demo")
157
159
  self.assertEqual(payload["agents"][0]["messages"][0]["type"], "task_request")
158
160
 
161
+ def test_cli_oacp_dir_expands_tilde(self) -> None:
162
+ with tempfile.TemporaryDirectory() as tmpdir:
163
+ home = Path(tmpdir) / "home"
164
+ cwd = Path(tmpdir) / "cwd"
165
+ root = home / "oacp-tilde-test"
166
+ home.mkdir()
167
+ cwd.mkdir()
168
+ _write_message(
169
+ root,
170
+ "demo",
171
+ "claude",
172
+ "20260319120000_codex_task_request.yaml",
173
+ sender="codex",
174
+ msg_type="task_request",
175
+ priority="P1",
176
+ subject="Implement feature",
177
+ created_at_utc="2026-03-19T12:00:00Z",
178
+ )
179
+ old_cwd = Path.cwd()
180
+ try:
181
+ os.chdir(cwd)
182
+ with mock.patch.dict(os.environ, {"HOME": str(home)}, clear=False):
183
+ code, stdout, stderr = self._run_main(
184
+ ["demo", "--agent", "claude", "--oacp-dir", "~/oacp-tilde-test", "--json"]
185
+ )
186
+ finally:
187
+ os.chdir(old_cwd)
188
+
189
+ self.assertEqual(code, 0)
190
+ self.assertEqual(stderr, "")
191
+ payload = json.loads(stdout)
192
+ self.assertEqual(payload["agents"][0]["message_count"], 1)
193
+ self.assertTrue(payload["agents"][0]["inbox_path"].startswith(str(home)))
194
+ self.assertFalse((cwd / "~").exists())
195
+
159
196
  def test_missing_project_returns_error(self) -> None:
160
197
  code, stdout, stderr = self._run_main(["missing", "--all"])
161
198
  self.assertEqual(code, 1)