openbox-temporal-sdk-python 1.1.2__tar.gz → 1.2.1__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 (80) hide show
  1. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/.gitignore +1 -0
  2. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/CHANGELOG.md +122 -0
  3. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/PKG-INFO +121 -109
  4. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/README.md +119 -108
  5. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/docs/changelog-hook-level-governance.md +9 -0
  6. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/docs/code-standards.md +29 -48
  7. openbox_temporal_sdk_python-1.2.1/docs/codebase-summary.md +632 -0
  8. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/docs/configuration.md +45 -3
  9. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/docs/project-overview-pdr.md +42 -30
  10. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/docs/system-architecture.md +218 -511
  11. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/docs/temporal-plugin-integration-guide.md +15 -11
  12. openbox_temporal_sdk_python-1.2.1/openbox/__init__.py +125 -0
  13. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/activities.py +44 -16
  14. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/activity_interceptor.py +123 -199
  15. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/client.py +32 -8
  16. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/config.py +166 -49
  17. openbox_temporal_sdk_python-1.2.1/openbox/core_adapter.py +279 -0
  18. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/errors.py +63 -33
  19. openbox_temporal_sdk_python-1.2.1/openbox/governance_state.py +101 -0
  20. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/hitl.py +8 -12
  21. openbox_temporal_sdk_python-1.2.1/openbox/multi_agent.py +136 -0
  22. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/plugin.py +34 -36
  23. openbox_temporal_sdk_python-1.2.1/openbox/request_signing.py +89 -0
  24. openbox_temporal_sdk_python-1.2.1/openbox/tracing.py +59 -0
  25. openbox_temporal_sdk_python-1.2.1/openbox/types.py +79 -0
  26. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/verdict_handler.py +0 -1
  27. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/worker.py +35 -36
  28. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/workflow_interceptor.py +68 -61
  29. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/pyproject.toml +6 -1
  30. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/sonar-project.properties +1 -4
  31. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/tests/__init__.py +0 -1
  32. openbox_temporal_sdk_python-1.2.1/tests/conftest.py +56 -0
  33. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/tests/test_activities.py +7 -30
  34. openbox_temporal_sdk_python-1.2.1/tests/test_activity_interceptor.py +1869 -0
  35. openbox_temporal_sdk_python-1.2.1/tests/test_approval_action_precedence.py +102 -0
  36. openbox_temporal_sdk_python-1.2.1/tests/test_base_sdk_signing_parity.py +102 -0
  37. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/tests/test_config.py +0 -31
  38. openbox_temporal_sdk_python-1.2.1/tests/test_core_conformance_suite.py +261 -0
  39. openbox_temporal_sdk_python-1.2.1/tests/test_multi_agent.py +129 -0
  40. openbox_temporal_sdk_python-1.2.1/tests/test_no_import_machinery_in_governed_open_paths.py +73 -0
  41. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/tests/test_plugin.py +70 -46
  42. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/tests/test_plugin_integration.py +12 -18
  43. openbox_temporal_sdk_python-1.2.1/tests/test_public_api_compatibility.py +154 -0
  44. openbox_temporal_sdk_python-1.2.1/tests/test_request_signing.py +280 -0
  45. openbox_temporal_sdk_python-1.2.1/tests/test_signing_config.py +242 -0
  46. openbox_temporal_sdk_python-1.2.1/tests/test_temporal_hook_parity.py +129 -0
  47. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/tests/test_types.py +0 -98
  48. openbox_temporal_sdk_python-1.2.1/tests/test_worker.py +1099 -0
  49. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/tests/test_workflow_interceptor.py +219 -79
  50. openbox_temporal_sdk_python-1.2.1/tests/test_workflow_sandbox_import_safety.py +67 -0
  51. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/uv.lock +268 -1
  52. openbox_temporal_sdk_python-1.1.2/docs/codebase-summary.md +0 -786
  53. openbox_temporal_sdk_python-1.1.2/openbox/__init__.py +0 -181
  54. openbox_temporal_sdk_python-1.1.2/openbox/context_propagation.py +0 -56
  55. openbox_temporal_sdk_python-1.1.2/openbox/db_governance_hooks.py +0 -776
  56. openbox_temporal_sdk_python-1.1.2/openbox/file_governance_hooks.py +0 -396
  57. openbox_temporal_sdk_python-1.1.2/openbox/hook_governance.py +0 -437
  58. openbox_temporal_sdk_python-1.1.2/openbox/http_governance_hooks.py +0 -859
  59. openbox_temporal_sdk_python-1.1.2/openbox/otel_setup.py +0 -474
  60. openbox_temporal_sdk_python-1.1.2/openbox/span_processor.py +0 -240
  61. openbox_temporal_sdk_python-1.1.2/openbox/tracing.py +0 -297
  62. openbox_temporal_sdk_python-1.1.2/openbox/types.py +0 -188
  63. openbox_temporal_sdk_python-1.1.2/tests/conftest.py +0 -96
  64. openbox_temporal_sdk_python-1.1.2/tests/test_activity_interceptor.py +0 -2572
  65. openbox_temporal_sdk_python-1.1.2/tests/test_db_governance_hooks.py +0 -886
  66. openbox_temporal_sdk_python-1.1.2/tests/test_file_governance_hooks.py +0 -784
  67. openbox_temporal_sdk_python-1.1.2/tests/test_http_body_truncation.py +0 -75
  68. openbox_temporal_sdk_python-1.1.2/tests/test_otel_setup.py +0 -2255
  69. openbox_temporal_sdk_python-1.1.2/tests/test_psycopg2_hooks_verify.py +0 -60
  70. openbox_temporal_sdk_python-1.1.2/tests/test_span_processor.py +0 -706
  71. openbox_temporal_sdk_python-1.1.2/tests/test_tracing.py +0 -1288
  72. openbox_temporal_sdk_python-1.1.2/tests/test_worker.py +0 -1919
  73. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/.github/workflows/publish.yml +0 -0
  74. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/.github/workflows/sonarqube.yaml +0 -0
  75. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/.python-version +0 -0
  76. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/.repomixignore +0 -0
  77. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/LICENSE +0 -0
  78. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/openbox/py.typed +0 -0
  79. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/release-manifest.json +0 -0
  80. {openbox_temporal_sdk_python-1.1.2 → openbox_temporal_sdk_python-1.2.1}/repomix-output.xml +0 -0
@@ -40,3 +40,4 @@ AGENTS.md
40
40
  .claude/
41
41
  CLAUDE.md
42
42
  plans/
43
+ _notes/
@@ -2,6 +2,128 @@
2
2
 
3
3
  All notable changes to OpenBox SDK for Temporal Workflows.
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ## [1.2.1] - 2026-07-21
8
+
9
+ ### Changed
10
+
11
+ - **Resolve `openbox-sdk-python` from PyPI.** The dependency now installs from the
12
+ published package (floor raised to `>=1.0.1`) instead of a local editable checkout,
13
+ so `pip install openbox-temporal-sdk-python` works without a sibling source tree.
14
+
15
+ ## [1.2.0] - 2026-07-20
16
+
17
+ ### Changed
18
+
19
+ - **Depends on `openbox-sdk-python>=0.2.0`** (import package `openbox_core`) — the shared
20
+ base SDK owning contracts, the always-strict gate, identity/signing, the evaluate
21
+ client, context runtime, Core `SpanData` wire serialization, generic instrumentation,
22
+ and the conformance kit. The `0.2.0` floor adds Redis/MongoDB/urllib3/urllib
23
+ instrumentation in the base runtime so no hook coverage is lost in the flip.
24
+ - **Hook governance is now owned entirely by the base runtime.** The worker/plugin
25
+ build and own an `openbox_core` runtime and call `install_instrumentation()`;
26
+ HTTP/DB/file/function hooks, payload shape, evaluation, and enforcement all live in
27
+ `openbox_core`. LangGraph and Temporal now emit one identical flat hook interface.
28
+ - `request_signing` now shims over `openbox_core.identity`. Signed request bytes are
29
+ UNCHANGED — gated byte-for-byte by a golden fixture generated from the pre-migration
30
+ signer (`tests/test_base_sdk_signing_parity.py`).
31
+ - `Verdict`, `GuardrailsCheckResult`, and `WorkflowEventType` re-export the shared
32
+ contracts; `GovernanceVerdictResponse` subclasses the shared `EvaluationResult`
33
+ (same public surface, plus `fallback_used`/`diagnostics`/`raw`/`approval_expiration_time`).
34
+ - Workflow lifecycle events route through shared `EventEnvelope` factories
35
+ (sandbox-safe pure contracts; wire payloads unchanged).
36
+ - Activity execution binds the shared `ActivityContext` with a guaranteed
37
+ try/finally reset — governance context can no longer leak when an activity raises.
38
+
39
+ ### Behavior changes (regression-gated)
40
+
41
+ - **Approval decision precedence:** approval poll responses parse via the shared
42
+ `ApprovalResult`; `action` now outranks `verdict` when both are present
43
+ (previously verdict-first), and a response with NEITHER field stays PENDING
44
+ (previously implicit ALLOW). Pinned by `tests/test_approval_action_precedence.py`.
45
+
46
+ ### Known behavior differences in the core runtime
47
+
48
+ - **Completed-hook semantics:** core completed hooks never raise to the caller —
49
+ stop verdicts mark FUTURE execution blocked (abort/halt flags). Some legacy
50
+ completed hooks could raise after the operation ran (HTTP response hook, file
51
+ close); raising post-hoc cannot undo the operation, so the core model drops it
52
+ by design.
53
+ - **Fail-closed shaping:** core maps started-hook evaluation failures under
54
+ `on_api_error="fail_closed"` (and started-hook contract errors, always) to a
55
+ non-retryable `GovernanceHalt` via the adapter — same terminal effect as
56
+ legacy's HALT-shaped `GovernanceBlockedError`, different exception chain.
57
+ - **Redaction point for `activity_input`:** the core `ActivityContext` receives
58
+ the post-redaction input (what actually ran); the legacy buffer stored the
59
+ pre-redaction value. Core hook payloads therefore never leak redacted fields.
60
+
61
+ ### Added
62
+
63
+ - `openbox.governance_state.TemporalGovernanceState` — run-scoped state carrying the
64
+ Temporal effects that must survive past a base hook callback: signal BLOCK/HALT
65
+ verdicts that fail the next activity, HITL pending-approval retry markers, and the
66
+ completed-hook stop bridge (completed BLOCK skips the duplicate completed event;
67
+ completed HALT reaches the terminate path). Consumed on every activity exit path.
68
+ - `openbox.core_adapter` — `TemporalFrameworkAdapter` (maps base-SDK verdicts to
69
+ native `ApplicationError` types and the retry-based HITL loop; REQUIRE_APPROVAL marks
70
+ the pending-approval retry marker and degrades to a non-retryable block when HITL is
71
+ disabled/skipped; completed BLOCK/HALT records run-scoped stop state with the resolved
72
+ `ActivityContext`), and `create_core_runtime(...)` which builds and owns the base
73
+ runtime the worker/plugin install. `core_activity_scope` is the sole hook-context
74
+ bridge (guaranteed try/finally reset + trace registration).
75
+ - Redis, MongoDB, urllib3, and urllib governance now flow through the base runtime.
76
+ - Gates: workflow-sandbox import-safety, base-SDK conformance suite driven by the
77
+ Temporal adapter, public-API compatibility suite, and a deterministic
78
+ `llm_completion` hook-parity test (flat interface via the Temporal runtime, no live
79
+ OpenAI credentials).
80
+
81
+ ### Removed
82
+
83
+ - `WorkflowSpanProcessor`, `WorkflowSpanBuffer`, and the `setup_opentelemetry_for_governance`
84
+ entry point (public exports). Governance instrumentation is installed by the base
85
+ runtime; there is no Temporal-local OpenTelemetry setup to call.
86
+ - Temporal-local hook modules `otel_setup`, `hook_governance`, `http_governance_hooks`,
87
+ `db_governance_hooks`, `file_governance_hooks`, `span_processor`, and the dead
88
+ `context_propagation` helper (its ContextVar-to-executor propagation lives in the base
89
+ runtime). Their payload-shape/instrumentation coverage moved to the base SDK suite.
90
+ - `openbox.tracing.traced` now wraps `openbox_core.instrumentation.function.governed`;
91
+ `create_span` remains a plain span helper.
92
+
93
+ ### Fixed (legacy file instrumentation — pre-existing upstream)
94
+
95
+ - **Runtime RecursionError under file instrumentation:** governance evaluation
96
+ itself opens files (httpx/ssl, package-metadata scans via importlib_metadata/
97
+ zipp) — governing those opens re-evaluated recursively until RecursionError.
98
+ traced_open now (1) passes through any open performed on a thread already
99
+ inside file-governance work (re-entrancy guard) and (2) bypasses
100
+ interpreter-owned trees (venv, stdlib, site-packages — sys.prefix/base_prefix
101
+ + sysconfig paths): those reads are Python machinery, not application data
102
+ access. Application paths (./.env, data files, temp files) remain governed.
103
+ Same guard mirrored in the base SDK's file instrumentation.
104
+
105
+ ### Fixed (HTTP hook payloads — pre-existing upstream)
106
+
107
+ - **Mangled method on httpx spans:** OTel's httpx instrumentation passes the
108
+ method as BYTES; `str(b"POST")` shipped `http_method: "b'POST'"` on every
109
+ httpx started span. Methods now decode bytes-safely at all client paths.
110
+ - **Credential leak in governance payloads:** raw request/response headers
111
+ (`authorization`, `cookie`, `set-cookie`, `x-api-key`, …) were sent to Core
112
+ verbatim — live API keys landed in Core logs. All header dicts are now
113
+ redacted at the span-data builder choke point. Same redaction added to the
114
+ base SDK instrumentation. **Rotate any API keys that appeared in payloads.**
115
+
116
+ ### Migration notes
117
+
118
+ - Base-runtime instrumentation is the sole hook governance path
119
+ and the legacy in-repo hook stack is removed. Approval-retry, signal BLOCK/HALT, and
120
+ completed-hook BLOCK/HALT behavior are preserved (run-scoped, cleaned after use).
121
+ - Dropped coverage vs the legacy stack: direct raw-driver DB queries (psycopg2/mysql/
122
+ pymysql/sqlite3 used WITHOUT SQLAlchemy). The base runtime governs SQLAlchemy (all
123
+ backends), asyncpg, Redis, and MongoDB; activating raw dbapi driver instrumentors
124
+ interferes with SQLAlchemy's own dialect queries, so raw-driver-only governance is a
125
+ base-SDK follow-up.
126
+
5
127
  ## [1.1.2] - 2026-04-22
6
128
 
7
129
  ### Security
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openbox-temporal-sdk-python
3
- Version: 1.1.2
3
+ Version: 1.2.1
4
4
  Summary: OpenBox SDK - Governance and observability for Temporal workflows
5
5
  Project-URL: Homepage, https://github.com/OpenBox-AI/temporal-sdk-python
6
6
  Project-URL: Documentation, https://github.com/OpenBox-AI/temporal-sdk-python#readme
@@ -24,6 +24,7 @@ Requires-Python: >=3.11
24
24
  Requires-Dist: asyncpg>=0.29.0
25
25
  Requires-Dist: httpx<1,>=0.28.0
26
26
  Requires-Dist: mysql-connector-python>=8.0.0
27
+ Requires-Dist: openbox-sdk-python>=1.0.1
27
28
  Requires-Dist: opentelemetry-api<1.40.0,>=1.38.0
28
29
  Requires-Dist: opentelemetry-instrumentation-asyncpg<0.61b0,>=0.59b0
29
30
  Requires-Dist: opentelemetry-instrumentation-httpx<0.61b0,>=0.59b0
@@ -51,7 +52,8 @@ Description-Content-Type: text/markdown
51
52
  OpenBox SDK provides **governance and observability** for Temporal workflows by capturing workflow/activity lifecycle events, HTTP telemetry, database queries, and file operations, then sending them to OpenBox Core for policy evaluation.
52
53
 
53
54
  **Key Features:**
54
- - 6 event types (WorkflowStarted, WorkflowCompleted, WorkflowFailed, SignalReceived, ActivityStarted, ActivityCompleted)
55
+ - 7 event types (WorkflowStarted, WorkflowCompleted, WorkflowFailed, SignalReceived, ActivityStarted, ActivityCompleted, Handoff)
56
+ - Multi-agent sessions — propagate a shared `multi_agent_session_id` across workflow + activity events
55
57
  - 5-tier verdict system (ALLOW, CONSTRAIN, REQUIRE_APPROVAL, BLOCK, HALT)
56
58
  - **Hook-level governance** — per-operation evaluation (HTTP requests, file I/O, database queries, function tracing) with started/completed stages
57
59
  - HTTP/Database/File I/O instrumentation via OpenTelemetry
@@ -199,8 +201,6 @@ worker = create_openbox_worker(
199
201
 
200
202
  # Database instrumentation
201
203
  instrument_databases=True,
202
- db_libraries={"psycopg2", "sqlalchemy"}, # None = all available
203
- sqlalchemy_engine=engine, # pass pre-existing engine for query capture
204
204
 
205
205
  # File I/O instrumentation
206
206
  instrument_file_io=False, # disabled by default
@@ -247,6 +247,48 @@ OpenBox Core returns a verdict indicating what action the SDK should take.
247
247
  | SignalReceived | Signal received | workflow_id, signal_name, signal_args |
248
248
  | ActivityStarted | Activity begins | activity_id, activity_type, activity_input |
249
249
  | ActivityCompleted | Activity ends | activity_id, activity_type, activity_input, activity_output, spans, status, duration |
250
+ | Handoff | Agent hands off to another agent | from_agent_did, multi_agent_session_id |
251
+
252
+ When a workflow runs as part of a multi-agent session (see below), every event
253
+ above also carries `multi_agent_session_id`. The field is omitted when no
254
+ session id is supplied.
255
+
256
+ ---
257
+
258
+ ## Multi-Agent Sessions
259
+
260
+ Group the work of several agents under one shared `multi_agent_session_id`. The
261
+ SDK only **propagates** the id you supply — it never invents one, and it owns no
262
+ routing, session minting, or agent registry (those stay in your application).
263
+
264
+ **Supply the id** via the Temporal workflow memo at start time:
265
+
266
+ ```python
267
+ await client.start_workflow(
268
+ MyWorkflow.run,
269
+ arg,
270
+ id="order-123",
271
+ task_queue="my-queue",
272
+ memo={"openbox_multi_agent_session_id": session_id},
273
+ )
274
+ ```
275
+
276
+ The SDK then tags every governance event (workflow, activity, and hook events)
277
+ with that id, propagating it from the workflow to its activities automatically.
278
+
279
+ **Emit an explicit handoff** from inside workflow code:
280
+
281
+ ```python
282
+ from openbox import emit_handoff
283
+
284
+ await emit_handoff(
285
+ multi_agent_session_id=session_id,
286
+ from_agent_did="did:aip:...", # the sending agent
287
+ )
288
+ ```
289
+
290
+ The receiving agent is derived server-side from the signed identity and is never
291
+ sent. `emit_handoff` validates its arguments locally before any network call.
250
292
 
251
293
  ---
252
294
 
@@ -279,7 +321,7 @@ OpenBox Core can validate and redact sensitive data before/after activity execut
279
321
 
280
322
  ## Error Handling
281
323
 
282
- Configure error policy via `on_api_error` (constants available as `hook_governance.FAIL_OPEN` / `FAIL_CLOSED`):
324
+ Configure error policy via the `governance_policy` parameter (`"fail_open"` / `"fail_closed"`):
283
325
 
284
326
  | Policy | Behavior |
285
327
  |--------|----------|
@@ -307,15 +349,12 @@ Configure error policy via `on_api_error` (constants available as `hook_governan
307
349
  - `redis` — native OTel `request_hook`/`response_hook`
308
350
  - `sqlalchemy` — `before/after_cursor_execute` event listeners
309
351
 
310
- **SQLAlchemy Note:** If your SQLAlchemy engine is created before `create_openbox_worker()` runs (e.g., at module import time), you must pass it via the `sqlalchemy_engine` parameter. Without this, `SQLAlchemyInstrumentor` only patches future `create_engine()` calls and won't capture queries on pre-existing engines.
352
+ **SQLAlchemy Note:** Query-level governance works on pre-existing engines automatically — even engines created before `create_openbox_worker()` runs (e.g., at module import time) because the base runtime governs SQLAlchemy via a global `Engine` event listener. No engine handle needs to be passed in. The `db_libraries` and `sqlalchemy_engine` parameters are still accepted for backward compatibility but are no longer required and have no effect: the base runtime installs every available database instrumentor best-effort.
311
353
 
312
354
  ```python
313
- from db.engine import engine
314
-
315
355
  worker = create_openbox_worker(
316
356
  ...,
317
- db_libraries={"psycopg2", "sqlalchemy"},
318
- sqlalchemy_engine=engine,
357
+ instrument_databases=True, # default; installs all available DB instrumentors
319
358
  )
320
359
  ```
321
360
 
@@ -411,7 +450,7 @@ Every database operation is evaluated at `started` (pre-query, can block) and `c
411
450
 
412
451
  ### Function Tracing
413
452
 
414
- Functions decorated with `@traced` are automatically governed when `hook_governance` is configured:
453
+ Functions decorated with `@traced` are automatically governed when a worker (or plugin) has installed the base runtime. `@traced` wraps the base SDK's `governed()` decorator:
415
454
 
416
455
  | Stage | Trigger | Data Available |
417
456
  |-------|---------|----------------|
@@ -420,15 +459,13 @@ Functions decorated with `@traced` are automatically governed when `hook_governa
420
459
 
421
460
  **How it works (Function Tracing):**
422
461
 
423
- 1. `@traced` decorator wrapper starts OTel span
424
- 2. → SDK sends `started` governance evaluation with function name and module
425
- 3. If verdict is BLOCK/HALT → `GovernanceBlockedError` raised, function never executes
462
+ 1. `@traced` delegates to the base SDK's `governed()` decorator
463
+ 2. → the base runtime sends a `started` FUNCTION_CALL evaluation with function name and module
464
+ 3. If verdict is BLOCK/HALT → the call is blocked and the function never executes
426
465
  4. Function executes normally
427
- 5. → SDK sends `completed` governance evaluation with result or error info
428
- 6. If verdict is BLOCK/HALT → `GovernanceBlockedError` raised after execution
429
- 7. When `hook_governance` is not configured zero overhead, no governance calls
430
-
431
- **Governed span tracking:** When hook-level governance is active, the SDK marks HTTP spans as "governed" so the OTel `on_end` processor skips buffering them — preventing duplicate spans.
466
+ 5. → the base runtime sends a `completed` FUNCTION_CALL evaluation with result or error info
467
+ 6. If verdict is BLOCK/HALT → the block is surfaced after execution
468
+ 7. When no base runtime is installedtransparent passthrough, zero governance calls
432
469
 
433
470
  ---
434
471
 
@@ -439,116 +476,87 @@ See [System Architecture](./docs/system-architecture.md) for detailed component
439
476
  **High-Level Flow:**
440
477
 
441
478
  ```
442
- Workflow/Activity → Interceptors Span Processor → OpenBox Core API
443
-
444
- Returns Verdict
445
-
446
- (ALLOW, BLOCK, HALT, etc.)
447
-
448
- Hook-Level (per HTTP request):
449
- Activity HTTP Call OTel Hookhook_governance API (started) → Allow/Block
450
- Response hook_governance API (completed) → Allow/Block
451
-
452
- Hook-Level (per file operation):
453
- Activity open() → hook_governance → API (started) → Allow/Block
454
- Activity read/write() → hook_governance → API (started) → Allow/Block
455
- → hook_governance → API (completed) → Allow/Block
456
- Activity close() → hook_governance → API (completed) → Allow/Block
457
-
458
- Hook-Level (per DB query):
459
- Activity DB Call → db_governance_hooks → hook_governance → API (started) → Allow/Block
460
- → Query executes → hook_governance → API (completed)
461
-
462
- Hook-Level (per @traced function):
463
- @traced call → hook_governance → API (started) → Allow/Block
464
- → Function runs → hook_governance → API (completed)
479
+ Workflow / Activity lifecycle Temporal SDK interceptors → OpenBox Core API
480
+
481
+ Returns Verdict
482
+
483
+ (ALLOW, BLOCK, HALT, REQUIRE_APPROVAL)
484
+
485
+ Hook-Level (per HTTP request / DB query / file op / @traced fn):
486
+ Operationbase-SDK instrumentationOpenBox Core API (started) → Allow/Block
487
+ Operation runs OpenBox Core API (completed) → Allow/Block
465
488
  ```
466
489
 
467
- **Module responsibilities:**
468
- - `otel_setup.py` OTel instrumentation, hooks, TracedFile wrapper
469
- - `hook_governance.py` Shared governance evaluator (payload building, API calls, verdict handling)
470
- - `db_governance_hooks.py` — Per-library DB governance wrappers (wrapt, OTel hooks, SQLAlchemy events)
471
- - `span_processor.py` — Span buffering, activity context tracking
472
- - `activity_interceptor.py` — Activity lifecycle governance events
490
+ The Temporal worker/plugin builds and owns an `openbox_core` runtime that installs
491
+ all hook instrumentation. Hook payload building, evaluation, and enforcement are
492
+ owned entirely by the base SDK; the Temporal SDK maps the resulting verdicts onto
493
+ Temporal-native effects.
473
494
 
474
- ---
495
+ **Responsibility split:**
475
496
 
476
- ## Advanced Usage
497
+ Base SDK (`openbox_core`):
498
+ - HTTP / DB / file / function hook instrumentation
499
+ - Hook payload shape, evaluation, and enforcement
477
500
 
478
- For manual control, import individual components:
501
+ Temporal SDK (this package):
502
+ - `workflow_interceptor.py` / `activity_interceptor.py` — workflow/activity/signal lifecycle governance events (via workflow-safe activities)
503
+ - `governance_state.py` — `TemporalGovernanceState`: signal-verdict bridging, HITL pending-approval markers, completed-hook stop/halt propagation
504
+ - `core_adapter.py` — builds the base runtime (`create_core_runtime`) and maps base verdicts to Temporal effects (`TemporalFrameworkAdapter`)
479
505
 
480
- ```python
481
- from openbox import (
482
- initialize,
483
- WorkflowSpanProcessor,
484
- GovernanceInterceptor,
485
- GovernanceConfig,
486
- )
487
- from openbox.otel_setup import setup_opentelemetry_for_governance
488
- from openbox.activity_interceptor import ActivityGovernanceInterceptor
489
- from openbox.activities import build_governance_activities
490
- from openbox.hook_governance import FAIL_OPEN, FAIL_CLOSED # error policy constants
506
+ ---
491
507
 
492
- # 1. Initialize SDK
493
- initialize(api_url="http://localhost:8086", api_key="obx_test_key_1")
508
+ ## Advanced Usage
494
509
 
495
- # 2. Create span processor
496
- span_processor = WorkflowSpanProcessor(
497
- ignored_url_prefixes=["http://localhost:8086"]
498
- )
510
+ The supported integration is a single call. Both `create_openbox_worker(...)` and
511
+ `OpenBoxPlugin(...)` build and own the base `openbox_core` runtime, install all
512
+ hook instrumentation, register the governance interceptors, and wire the
513
+ `send_governance_event` activity for you — there is no manual OpenTelemetry or
514
+ span-processor setup to perform.
499
515
 
500
- # 3. Setup OTel instrumentation (governance always enabled)
501
- setup_opentelemetry_for_governance(
502
- span_processor,
503
- api_url="http://localhost:8086",
504
- api_key="obx_test_key_1",
505
- sqlalchemy_engine=engine, # optional: instrument pre-existing engine
506
- )
516
+ Worker factory:
507
517
 
508
- # 4. Create governance config
509
- config = GovernanceConfig(
510
- on_api_error="fail_closed",
511
- api_timeout=30.0,
512
- )
518
+ ```python
519
+ import os
520
+ from openbox import create_openbox_worker
513
521
 
514
- # 5. Create interceptors
515
- workflow_interceptor = GovernanceInterceptor(
516
- api_url="http://localhost:8086",
517
- api_key="obx_test_key_1",
518
- span_processor=span_processor,
519
- config=config,
522
+ worker = create_openbox_worker(
523
+ client=client,
524
+ task_queue="my-task-queue",
525
+ workflows=[MyWorkflow],
526
+ activities=[my_activity],
527
+ openbox_url=os.getenv("OPENBOX_URL"),
528
+ openbox_api_key=os.getenv("OPENBOX_API_KEY"),
529
+ governance_policy="fail_closed",
530
+ governance_timeout=30.0,
531
+ instrument_databases=True,
532
+ instrument_file_io=True,
520
533
  )
521
534
 
522
- activity_interceptor = ActivityGovernanceInterceptor(
523
- api_url="http://localhost:8086",
524
- api_key="obx_test_key_1",
525
- span_processor=span_processor,
526
- config=config,
527
- )
535
+ await worker.run()
536
+ ```
528
537
 
529
- # 6. Build the governance activity instance (credentials captured on `self`
530
- # so they never flow through workflow history).
531
- governance_activities = build_governance_activities(
532
- api_url="http://localhost:8086",
533
- api_key="obx_test_key_1",
534
- )
538
+ Plugin (Temporal >= 1.23.0) attach to a plain `Worker`:
535
539
 
536
- # 7. Create worker
540
+ ```python
537
541
  from temporalio.worker import Worker
538
- from temporalio.contrib.opentelemetry import TracingInterceptor
542
+ from openbox.plugin import OpenBoxPlugin
543
+
539
544
  worker = Worker(
540
- client=client,
545
+ client,
541
546
  task_queue="my-task-queue",
542
547
  workflows=[MyWorkflow],
543
- activities=[my_activity, governance_activities.send_governance_event],
544
- interceptors=[
545
- workflow_interceptor,
546
- activity_interceptor,
547
- TracingInterceptor(), # W3C header propagation for OTel spans
548
- ],
548
+ activities=[my_activity],
549
+ plugins=[OpenBoxPlugin(
550
+ openbox_url=os.getenv("OPENBOX_URL"),
551
+ openbox_api_key=os.getenv("OPENBOX_API_KEY"),
552
+ governance_policy="fail_closed",
553
+ )],
549
554
  )
550
555
  ```
551
556
 
557
+ Both entry points accept the same governance, HITL, signing, and instrumentation
558
+ options (see [Configuration](./docs/configuration.md)).
559
+
552
560
  ---
553
561
 
554
562
  ## Documentation
@@ -563,13 +571,17 @@ worker = Worker(
563
571
 
564
572
  ## Testing
565
573
 
566
- The SDK includes comprehensive test coverage with 15 test files:
574
+ The SDK includes comprehensive test coverage under `tests/`:
567
575
 
568
576
  ```bash
569
577
  pytest tests/
570
578
  ```
571
579
 
572
- Test files: `test_activities.py`, `test_activity_interceptor.py`, `test_config.py`, `test_db_governance_hooks.py`, `test_file_governance_hooks.py`, `test_otel_hook_pause.py`, `test_otel_hook_pause_db.py`, `test_otel_setup.py`, `test_plugin.py`, `test_plugin_integration.py`, `test_span_processor.py`, `test_tracing.py`, `test_types.py`, `test_worker.py`, `test_workflow_interceptor.py`
580
+ Coverage spans the worker factory and plugin, workflow/activity/signal
581
+ interceptors, HITL approval flow, request signing, public-API compatibility, and
582
+ parity with the base SDK's hook governance (`test_temporal_hook_parity.py`,
583
+ `test_core_conformance_suite.py`). Hook instrumentation internals (HTTP/DB/file
584
+ payload shape) are verified in the base SDK's own conformance suite.
573
585
 
574
586
  ---
575
587