dominus-sdk-python 4.6.2__py3-none-any.whl → 5.1.0__py3-none-any.whl

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.
dominus/__init__.py CHANGED
@@ -90,14 +90,12 @@ from .namespaces.health import HealthNamespace
90
90
  # Export new namespaces (Node.js SDK parity)
91
91
  from .namespaces.artifacts import (
92
92
  ARTIFACT_REF_PREFIX,
93
- DISPLAY_REF_PREFIX,
94
93
  ARTIFACT_ENVIRONMENTS,
95
94
  ArtifactsNamespace,
96
95
  build_artifact_ref,
97
96
  build_v2_artifact_ref,
98
97
  build_pinned_artifact_ref,
99
98
  build_legacy_artifact_ref,
100
- build_display_artifact_ref,
101
99
  parse_artifact_ref,
102
100
  try_parse_artifact_ref,
103
101
  validate_artifact_address,
@@ -105,7 +103,6 @@ from .namespaces.artifacts import (
105
103
  is_pinned_artifact_ref,
106
104
  is_head_artifact_ref,
107
105
  is_legacy_artifact_ref,
108
- is_display_artifact_ref,
109
106
  )
110
107
  from .namespaces.jobs import JobsNamespace
111
108
  from .namespaces.processor import ProcessorNamespace
@@ -165,7 +162,7 @@ from .errors import (
165
162
  TimeoutError as DominusTimeoutError,
166
163
  )
167
164
 
168
- __version__ = "4.6.2"
165
+ __version__ = "5.1.0"
169
166
  __all__ = [
170
167
  # Main SDK instance
171
168
  "dominus",
@@ -195,14 +192,12 @@ __all__ = [
195
192
  "HealthNamespace",
196
193
  # New namespaces (Node.js SDK parity)
197
194
  "ARTIFACT_REF_PREFIX",
198
- "DISPLAY_REF_PREFIX",
199
195
  "ARTIFACT_ENVIRONMENTS",
200
196
  "ArtifactsNamespace",
201
197
  "build_artifact_ref",
202
198
  "build_v2_artifact_ref",
203
199
  "build_pinned_artifact_ref",
204
200
  "build_legacy_artifact_ref",
205
- "build_display_artifact_ref",
206
201
  "parse_artifact_ref",
207
202
  "try_parse_artifact_ref",
208
203
  "validate_artifact_address",
@@ -210,7 +205,6 @@ __all__ = [
210
205
  "is_pinned_artifact_ref",
211
206
  "is_head_artifact_ref",
212
207
  "is_legacy_artifact_ref",
213
- "is_display_artifact_ref",
214
208
  "JobsNamespace",
215
209
  "ProcessorNamespace",
216
210
  "SyncNamespace",
@@ -35,10 +35,13 @@ def _safe_string(value: Any) -> str:
35
35
 
36
36
 
37
37
  ARTIFACT_REF_PREFIX = "ar://"
38
- DISPLAY_REF_PREFIX = "art:r:"
39
38
  ARTIFACT_ENVIRONMENTS = ("development", "staging", "production")
40
39
 
41
40
 
41
+ def _legacy_project_head_ref(project_id: str, environment: str, key: str) -> str:
42
+ return f"{ARTIFACT_REF_PREFIX}dominus/project:{project_id}/{environment}/legacy/{quote(key, safe='')}"
43
+
44
+
42
45
  def build_artifact_ref(
43
46
  *,
44
47
  project_slug: Optional[str] = None,
@@ -109,13 +112,6 @@ def build_pinned_artifact_ref(
109
112
  return f"{ref}@v{version}"
110
113
 
111
114
 
112
- def build_display_artifact_ref(artifact_key: str) -> Optional[str]:
113
- normalized_key = _safe_string(artifact_key)
114
- if not normalized_key:
115
- return None
116
- return f"{DISPLAY_REF_PREFIX}{normalized_key}"
117
-
118
-
119
115
  def build_legacy_artifact_ref(
120
116
  *,
121
117
  project_slug: str,
@@ -146,15 +142,6 @@ def parse_artifact_ref(artifact_ref: str) -> Optional[Dict[str, Any]]:
146
142
  normalized = _safe_string(artifact_ref)
147
143
  if not normalized:
148
144
  return None
149
- if normalized.startswith(DISPLAY_REF_PREFIX):
150
- artifact_key = normalized[len(DISPLAY_REF_PREFIX):]
151
- if not artifact_key:
152
- return None
153
- return {
154
- "format": "display",
155
- "raw": normalized,
156
- "artifact_key": artifact_key,
157
- }
158
145
  if not normalized.startswith(ARTIFACT_REF_PREFIX):
159
146
  return None
160
147
 
@@ -245,10 +232,6 @@ def is_legacy_artifact_ref(artifact_ref: Dict[str, Any]) -> bool:
245
232
  return artifact_ref.get("format") == "v1"
246
233
 
247
234
 
248
- def is_display_artifact_ref(artifact_ref: Dict[str, Any]) -> bool:
249
- return artifact_ref.get("format") == "display"
250
-
251
-
252
235
  def _split_version_suffix(value: str) -> tuple[str, Optional[str]]:
253
236
  if "@" not in value:
254
237
  return value, None
@@ -366,10 +349,10 @@ class ArtifactsNamespace:
366
349
  category=category,
367
350
  content_type=content_type,
368
351
  )
369
- disp = build_display_artifact_ref(use_key)
352
+ fallback_ref = _legacy_project_head_ref(project_id, environment, use_key)
370
353
  return {
371
354
  "key": use_key,
372
- "ref": v2.get("compatibility_ref") or v2.get("head_ref") or disp,
355
+ "ref": v2.get("head_ref") or fallback_ref,
373
356
  "storage_type": v2.get("storage_type") or "redis",
374
357
  "size_bytes": v2.get("size_bytes", 0),
375
358
  "expires_at": v2.get("expires_at") or "",
@@ -377,14 +360,14 @@ class ArtifactsNamespace:
377
360
 
378
361
  async def retrieve(self, key: str) -> Dict[str, Any]:
379
362
  """
380
- Retrieve by key via V2 display ref + target_project_id (compat with legacy data).
363
+ Retrieve by key via the addressed V2 compatibility head.
381
364
  """
382
- project_id, _environment = await self._legacy_project_context()
365
+ project_id, environment = await self._legacy_project_context()
366
+ ref = _legacy_project_head_ref(project_id, environment, key)
383
367
  return await self._api(
384
368
  "/api/artifact/v2/retrieve",
385
369
  body={
386
- "ref": f"{DISPLAY_REF_PREFIX}{key}",
387
- "target_project_id": project_id,
370
+ "ref": ref,
388
371
  },
389
372
  )
390
373
 
@@ -2,8 +2,8 @@
2
2
  Authority Namespace - Dominus Authority service surface.
3
3
 
4
4
  Canonical SDK entry point for the dominus-authority service. Mirrors the MCP
5
- ``authority_*`` tool surface so application code can drive runs, companies,
6
- deploys, managed clients, timelines, dossiers, and Authority context resolution
5
+ ``authority_*`` tool surface so application code can drive runs, provisioning
6
+ targets, deploys, managed clients, timelines, dossiers, and Authority context resolution
7
7
  without touching workflow-manager / client-worker / deploy-worker routes
8
8
  directly.
9
9
 
@@ -44,8 +44,8 @@ def _normalize_run_kind_token(raw: Optional[str]) -> str:
44
44
  return s
45
45
 
46
46
 
47
- def _is_company_bootstrap_run_kind(run_kind: Optional[str]) -> bool:
48
- return _normalize_run_kind_token(run_kind) == "company_bootstrap"
47
+ def _is_provisioning_bootstrap_run_kind(run_kind: Optional[str]) -> bool:
48
+ return _normalize_run_kind_token(run_kind) == "provisioning_bootstrap"
49
49
 
50
50
 
51
51
  def _query_string(params: Mapping[str, Any]) -> str:
@@ -62,7 +62,7 @@ class AuthorityNamespace:
62
62
  Usage::
63
63
 
64
64
  await dominus.authority.ensure_run(workflow_id="...", subject="PCM47474562")
65
- await dominus.authority.list_companies()
65
+ await dominus.authority.list_provisioning_targets()
66
66
  await dominus.authority.get_run_dossier(run_id)
67
67
  """
68
68
 
@@ -170,9 +170,8 @@ class AuthorityNamespace:
170
170
  workflow_id: Optional[str] = None,
171
171
  workflow_ref: Optional[str] = None,
172
172
  run_kind: Optional[str] = None,
173
- bootstrap_profile: Optional[str] = None,
174
- company_slug: Optional[str] = None,
175
- slug: Optional[str] = None,
173
+ bootstrap_profile_ref: Optional[str] = None,
174
+ provisioning_target_slug: Optional[str] = None,
176
175
  instance_id: Optional[str] = None,
177
176
  instance_key: Optional[str] = None,
178
177
  group: Optional[str] = None,
@@ -209,22 +208,20 @@ class AuthorityNamespace:
209
208
 
210
209
  Calls ``POST /api/authority/runs/ensure``.
211
210
 
212
- For company bootstrap, pass ``run_kind="company.bootstrap"`` (or ``company_bootstrap``) plus
213
- ``company``, ``company_slug``, or ``slug``. Optional bootstrap fields mirror
214
- ``bootstrap_company`` (``execution_mode``, ``region``, ``bootstrap_profile``, ).
211
+ For provisioning bootstrap, pass ``run_kind="provisioning.bootstrap"`` plus
212
+ ``provisioning_target_slug``. Optional bootstrap fields mirror
213
+ ``bootstrap_provisioning_target`` (``execution_mode``, ``region``, ``bootstrap_profile_ref``, ...).
215
214
  """
216
- bootstrap = _is_company_bootstrap_run_kind(run_kind)
215
+ bootstrap = _is_provisioning_bootstrap_run_kind(run_kind)
217
216
  if not bootstrap and not workflow_id and not workflow_ref:
218
217
  raise ValueError(
219
218
  "ensure_run requires workflow_id or workflow_ref unless run_kind is "
220
- "company.bootstrap / company_bootstrap"
219
+ "provisioning.bootstrap"
221
220
  )
222
221
  if bootstrap:
223
- co = (company_slug or slug or company or "").strip()
224
- if not co:
225
- raise ValueError(
226
- "ensure_run with run_kind company.bootstrap requires company, company_slug, or slug"
227
- )
222
+ target_slug = (provisioning_target_slug or "").strip()
223
+ if not target_slug:
224
+ raise ValueError("ensure_run with run_kind provisioning.bootstrap requires provisioning_target_slug")
228
225
  if mode == "streaming":
229
226
  raise ValueError(
230
227
  "Authority runs do not support streaming mode; "
@@ -237,7 +234,8 @@ class AuthorityNamespace:
237
234
  if bootstrap:
238
235
  body = _compact({
239
236
  "run_kind": run_kind,
240
- "bootstrap_profile": bootstrap_profile,
237
+ "bootstrap_profile_ref": bootstrap_profile_ref,
238
+ "provisioning_target_slug": provisioning_target_slug,
241
239
  "workflow_id": workflow_id,
242
240
  "workflow_ref": workflow_ref,
243
241
  "instance_id": instance_id,
@@ -245,9 +243,6 @@ class AuthorityNamespace:
245
243
  "group": group,
246
244
  "owner": owner,
247
245
  "subject": subject,
248
- "company": company,
249
- "company_slug": company_slug,
250
- "slug": slug,
251
246
  "bindings": bindings,
252
247
  "inputs": inputs,
253
248
  "context": context,
@@ -269,7 +264,6 @@ class AuthorityNamespace:
269
264
  body = _compact({
270
265
  "workflow_id": workflow_id,
271
266
  "workflow_ref": workflow_ref,
272
- "bootstrap_profile": bootstrap_profile,
273
267
  "instance_id": instance_id,
274
268
  "instance_key": instance_key,
275
269
  "group": group,
@@ -779,13 +773,13 @@ class AuthorityNamespace:
779
773
  )
780
774
 
781
775
  # ==================================================================
782
- # Companies
776
+ # Provisioning Targets
783
777
  # ==================================================================
784
778
 
785
- async def create_company(
779
+ async def create_provisioning_target(
786
780
  self,
787
781
  *,
788
- company_slug: str,
782
+ provisioning_target_slug: str,
789
783
  display_name: Optional[str] = None,
790
784
  description: Optional[str] = None,
791
785
  bootstrap_status: Optional[str] = None,
@@ -794,34 +788,43 @@ class AuthorityNamespace:
794
788
  app_slug: Optional[str] = None,
795
789
  env: Optional[str] = None,
796
790
  target_org_id: Optional[str] = None,
791
+ target_app_slug: Optional[str] = None,
797
792
  target_env: Optional[str] = None,
793
+ shared_app_slug: Optional[str] = None,
798
794
  initiator_type: Optional[str] = None,
799
795
  initiator_id: Optional[str] = None,
800
796
  idempotency_key: Optional[str] = None,
801
797
  timeout: Optional[float] = None,
802
798
  ) -> Dict[str, Any]:
803
- """Create a new company. ``POST /api/authority/companies``."""
804
- if not company_slug:
805
- raise ValueError("create_company requires company_slug")
799
+ """Create a new provisioning target. ``POST /api/authority/provisioning-targets``."""
800
+ if not provisioning_target_slug:
801
+ raise ValueError("create_provisioning_target requires provisioning_target_slug")
806
802
  body = _compact({
807
- "company_slug": company_slug,
803
+ "provisioning_target_slug": provisioning_target_slug,
808
804
  "display_name": display_name,
809
805
  "description": description,
810
806
  "bootstrap_status": bootstrap_status,
811
807
  "bootstrap_run_id": bootstrap_run_id,
812
808
  "metadata": metadata,
813
809
  **self._initiator(initiator_type, initiator_id, idempotency_key),
814
- **self._scope(app_slug, env, target_org_id, target_env),
810
+ **self._scope(
811
+ app_slug,
812
+ env,
813
+ target_org_id,
814
+ target_env,
815
+ target_app_slug=target_app_slug,
816
+ shared_app_slug=shared_app_slug,
817
+ ),
815
818
  })
816
819
  return await self._post(
817
- "/api/authority/companies",
820
+ "/api/authority/provisioning-targets",
818
821
  body,
819
822
  timeout=self._http_timeout(timeout, 30.0),
820
823
  )
821
824
 
822
- async def get_company(
825
+ async def get_provisioning_target(
823
826
  self,
824
- company_slug: str,
827
+ provisioning_target_slug: str,
825
828
  *,
826
829
  app_slug: Optional[str] = None,
827
830
  env: Optional[str] = None,
@@ -829,9 +832,9 @@ class AuthorityNamespace:
829
832
  target_env: Optional[str] = None,
830
833
  timeout: Optional[float] = None,
831
834
  ) -> Dict[str, Any]:
832
- """Get an Authority company. ``GET /api/authority/companies/{company}``."""
833
- if not company_slug:
834
- raise ValueError("company_slug is required")
835
+ """Get an Authority provisioning target. ``GET /api/authority/provisioning-targets/{provisioning_target_slug}``."""
836
+ if not provisioning_target_slug:
837
+ raise ValueError("provisioning_target_slug is required")
835
838
  tid, tev = self._target_query_params(target_org_id, target_env)
836
839
  qs = _query_string({
837
840
  "app_slug": app_slug,
@@ -840,11 +843,11 @@ class AuthorityNamespace:
840
843
  "target_env": tev,
841
844
  })
842
845
  return await self._get(
843
- f"/api/authority/companies/{quote(company_slug, safe='')}{qs}",
846
+ f"/api/authority/provisioning-targets/{quote(provisioning_target_slug, safe='')}{qs}",
844
847
  timeout=self._http_timeout(timeout, 30.0),
845
848
  )
846
849
 
847
- async def list_companies(
850
+ async def list_provisioning_targets(
848
851
  self,
849
852
  *,
850
853
  status: Optional[str] = None,
@@ -856,7 +859,7 @@ class AuthorityNamespace:
856
859
  offset: int = 0,
857
860
  timeout: Optional[float] = None,
858
861
  ) -> Dict[str, Any]:
859
- """List Authority companies. ``GET /api/authority/companies``."""
862
+ """List Authority provisioning targets. ``GET /api/authority/provisioning-targets``."""
860
863
  tid, tev = self._target_query_params(target_org_id, target_env)
861
864
  qs = _query_string({
862
865
  "app_slug": app_slug,
@@ -868,18 +871,18 @@ class AuthorityNamespace:
868
871
  "offset": offset,
869
872
  })
870
873
  return await self._get(
871
- f"/api/authority/companies{qs}",
874
+ f"/api/authority/provisioning-targets{qs}",
872
875
  timeout=self._http_timeout(timeout, 30.0),
873
876
  )
874
877
 
875
- async def bootstrap_company(
878
+ async def bootstrap_provisioning_target(
876
879
  self,
877
- company_slug: str,
880
+ provisioning_target_slug: str,
878
881
  *,
879
882
  action: Optional[str] = None,
880
883
  run_id: Optional[str] = None,
881
884
  reason: Optional[str] = None,
882
- bootstrap_profile: Optional[str] = None,
885
+ bootstrap_profile_ref: Optional[str] = None,
883
886
  shared_app_slug: Optional[str] = None,
884
887
  region: Optional[str] = None,
885
888
  system: Optional[str] = None,
@@ -902,14 +905,14 @@ class AuthorityNamespace:
902
905
  idempotency_key: Optional[str] = None,
903
906
  timeout: Optional[float] = None,
904
907
  ) -> Dict[str, Any]:
905
- """Trigger or replay company bootstrap. ``POST /api/authority/companies/{company}/bootstrap``."""
906
- if not company_slug:
907
- raise ValueError("company_slug is required")
908
+ """Trigger or replay provisioning target bootstrap. ``POST /api/authority/provisioning-targets/{provisioning_target_slug}/bootstrap``."""
909
+ if not provisioning_target_slug:
910
+ raise ValueError("provisioning_target_slug is required")
908
911
  body = _compact({
909
912
  "action": action,
910
913
  "run_id": run_id,
911
914
  "reason": reason,
912
- "bootstrap_profile": bootstrap_profile,
915
+ "bootstrap_profile_ref": bootstrap_profile_ref,
913
916
  "shared_app_slug": shared_app_slug,
914
917
  "region": region,
915
918
  "system": system,
@@ -933,36 +936,36 @@ class AuthorityNamespace:
933
936
  ),
934
937
  })
935
938
  return await self._post(
936
- f"/api/authority/companies/{quote(company_slug, safe='')}/bootstrap",
939
+ f"/api/authority/provisioning-targets/{quote(provisioning_target_slug, safe='')}/bootstrap",
937
940
  body,
938
941
  timeout=self._http_timeout(timeout, 60.0),
939
942
  )
940
943
 
941
- async def get_company_bootstrap(
944
+ async def get_provisioning_target_bootstrap(
942
945
  self,
943
- company_slug: str,
946
+ provisioning_target_slug: str,
944
947
  *,
945
948
  run_id: Optional[str] = None,
946
949
  app_slug: Optional[str] = None,
947
950
  env: Optional[str] = None,
948
951
  timeout: Optional[float] = None,
949
952
  ) -> Dict[str, Any]:
950
- """Get company bootstrap state. ``GET /api/authority/companies/{company}/bootstrap``."""
951
- if not company_slug:
952
- raise ValueError("company_slug is required")
953
+ """Get provisioning target bootstrap state. ``GET /api/authority/provisioning-targets/{provisioning_target_slug}/bootstrap``."""
954
+ if not provisioning_target_slug:
955
+ raise ValueError("provisioning_target_slug is required")
953
956
  qs = _query_string({
954
957
  "app_slug": app_slug,
955
958
  "env": env,
956
959
  "run_id": run_id,
957
960
  })
958
961
  return await self._get(
959
- f"/api/authority/companies/{quote(company_slug, safe='')}/bootstrap{qs}",
962
+ f"/api/authority/provisioning-targets/{quote(provisioning_target_slug, safe='')}/bootstrap{qs}",
960
963
  timeout=self._http_timeout(timeout, 30.0),
961
964
  )
962
965
 
963
- async def get_company_dossier(
966
+ async def get_provisioning_target_dossier(
964
967
  self,
965
- company_slug: str,
968
+ provisioning_target_slug: str,
966
969
  *,
967
970
  app_slug: Optional[str] = None,
968
971
  env: Optional[str] = None,
@@ -974,9 +977,9 @@ class AuthorityNamespace:
974
977
  limit: Optional[int] = None,
975
978
  timeout: Optional[float] = None,
976
979
  ) -> Dict[str, Any]:
977
- """Get full Authority dossier for a company. ``GET /api/authority/dossiers/company/{company}``."""
978
- if not company_slug:
979
- raise ValueError("company_slug is required")
980
+ """Get full Authority dossier for a provisioning target. ``GET /api/authority/dossiers/provisioning-target/{provisioning_target_slug}``."""
981
+ if not provisioning_target_slug:
982
+ raise ValueError("provisioning_target_slug is required")
980
983
  tid, tev = self._target_query_params(target_org_id, target_env)
981
984
  qs = _query_string({
982
985
  "app_slug": app_slug,
@@ -989,7 +992,7 @@ class AuthorityNamespace:
989
992
  "limit": limit,
990
993
  })
991
994
  return await self._get(
992
- f"/api/authority/dossiers/company/{quote(company_slug, safe='')}{qs}",
995
+ f"/api/authority/dossiers/provisioning-target/{quote(provisioning_target_slug, safe='')}{qs}",
993
996
  timeout=self._http_timeout(timeout, 30.0),
994
997
  )
995
998
 
@@ -104,6 +104,14 @@ class WorkflowNamespace:
104
104
  return {"workflow_id": str(workflow_id).strip()}
105
105
  raise ValueError("workflow_id or workflow_ref is required")
106
106
 
107
+ @staticmethod
108
+ def _is_workflow_recipe_ref(value: Optional[str]) -> bool:
109
+ return str(value or "").strip().startswith("recipe://workflow-recipe-v1/")
110
+
111
+ @staticmethod
112
+ def _is_pipeline_recipe_ref(value: Optional[str]) -> bool:
113
+ return str(value or "").strip().startswith("recipe://pipeline-recipe-v1/")
114
+
107
115
  @staticmethod
108
116
  def _instance_base_endpoint(workflow_id: str) -> str:
109
117
  from urllib.parse import quote
@@ -210,9 +218,11 @@ class WorkflowNamespace:
210
218
 
211
219
  def _build_authority_ensure_body(
212
220
  self,
213
- workflow_id: str,
221
+ workflow_id: Optional[str] = None,
214
222
  *,
215
223
  workflow_ref: Optional[str] = None,
224
+ workflow_recipe_ref: Optional[str] = None,
225
+ pipeline_recipe_ref: Optional[str] = None,
216
226
  subject: Optional[str] = None,
217
227
  company: Optional[str] = None,
218
228
  inputs: Optional[Dict[str, Any]] = None,
@@ -227,12 +237,30 @@ class WorkflowNamespace:
227
237
  idempotency_key: Optional[str] = None,
228
238
  ) -> Dict[str, Any]:
229
239
  body: Dict[str, Any] = {"mode": mode}
230
- if workflow_ref:
231
- body["workflow_ref"] = workflow_ref
232
- elif self._is_workflow_ref(workflow_id):
233
- body["workflow_ref"] = workflow_id
234
- else:
235
- body["workflow_id"] = workflow_id
240
+ launch_sources: List[tuple[str, str]] = []
241
+ normalized_workflow_id = str(workflow_id or "").strip()
242
+ if workflow_ref and str(workflow_ref).strip():
243
+ launch_sources.append(("workflow_ref", str(workflow_ref).strip()))
244
+ if workflow_recipe_ref and str(workflow_recipe_ref).strip():
245
+ launch_sources.append(("workflow_recipe_ref", str(workflow_recipe_ref).strip()))
246
+ if pipeline_recipe_ref and str(pipeline_recipe_ref).strip():
247
+ launch_sources.append(("pipeline_recipe_ref", str(pipeline_recipe_ref).strip()))
248
+ if normalized_workflow_id:
249
+ if self._is_workflow_ref(normalized_workflow_id):
250
+ launch_sources.append(("workflow_ref", normalized_workflow_id))
251
+ elif self._is_workflow_recipe_ref(normalized_workflow_id):
252
+ launch_sources.append(("workflow_recipe_ref", normalized_workflow_id))
253
+ elif self._is_pipeline_recipe_ref(normalized_workflow_id):
254
+ launch_sources.append(("pipeline_recipe_ref", normalized_workflow_id))
255
+ else:
256
+ launch_sources.append(("workflow_id", normalized_workflow_id))
257
+ if len(launch_sources) != 1:
258
+ raise ValueError(
259
+ "ensure requires exactly one of workflow_id, workflow_ref, "
260
+ "workflow_recipe_ref, or pipeline_recipe_ref"
261
+ )
262
+ field, value = launch_sources[0]
263
+ body[field] = value
236
264
  if subject is not None:
237
265
  body["subject"] = subject
238
266
  if company is not None:
@@ -855,7 +883,7 @@ class WorkflowNamespace:
855
883
 
856
884
  async def ensure(
857
885
  self,
858
- workflow_id: str,
886
+ workflow_id: Optional[str] = None,
859
887
  *,
860
888
  instance_id: Optional[str] = None,
861
889
  group: Optional[str] = None,
@@ -866,6 +894,8 @@ class WorkflowNamespace:
866
894
  mode: str = "blocking",
867
895
  context: Optional[Dict[str, Any]] = None,
868
896
  workflow_ref: Optional[str] = None,
897
+ workflow_recipe_ref: Optional[str] = None,
898
+ pipeline_recipe_ref: Optional[str] = None,
869
899
  subject: Optional[str] = None,
870
900
  company: Optional[str] = None,
871
901
  inputs: Optional[Dict[str, Any]] = None,
@@ -886,6 +916,8 @@ class WorkflowNamespace:
886
916
  body=self._build_authority_ensure_body(
887
917
  workflow_id,
888
918
  workflow_ref=workflow_ref,
919
+ workflow_recipe_ref=workflow_recipe_ref,
920
+ pipeline_recipe_ref=pipeline_recipe_ref,
889
921
  subject=subject,
890
922
  company=company,
891
923
  inputs=inputs,
dominus/start.py CHANGED
@@ -168,7 +168,7 @@ class Dominus:
168
168
  from .namespaces.sync import SyncNamespace
169
169
  self.sync = SyncNamespace(self)
170
170
 
171
- # Authority service (runs, companies, deploys, managed clients, dossiers)
171
+ # Authority service (runs, provisioning targets, deploys, managed clients, dossiers)
172
172
  from .namespaces.authority import AuthorityNamespace
173
173
  self.authority = AuthorityNamespace(self)
174
174
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dominus-sdk-python
3
- Version: 4.6.2
3
+ Version: 5.1.0
4
4
  Summary: Python SDK for the Dominus gateway-first platform
5
5
  Author-email: CareBridge Systems <dev@carebridge.io>
6
6
  License: Proprietary
@@ -43,7 +43,7 @@ Async Python SDK for the Dominus gateway-first service plane.
43
43
  - Gateway-scoped client mode for MCP and other user-JWT sessions
44
44
  - Transport compatibility for wrapped `{success,data}` responses and unwrapped Warden/control-plane success objects
45
45
  - Local helpers for JWT verification, trace propagation, retries, and console capture
46
- - Current package version: `4.0.8`
46
+ - Current package version: `5.1.0`
47
47
 
48
48
  ## Install
49
49
 
@@ -71,6 +71,12 @@ run = await dominus.workflow.ensure(
71
71
  company="summit-radiology",
72
72
  )
73
73
 
74
+ recipe_run = await dominus.workflow.ensure(
75
+ workflow_recipe_ref="recipe://workflow-recipe-v1/report-cycle@v3",
76
+ subject="PCM47474562",
77
+ company="summit-radiology",
78
+ )
79
+
74
80
  timeline = await dominus.authority.get_run_timeline(
75
81
  run["run_id"],
76
82
  since="2026-04-11T08:33:00Z",
@@ -198,7 +204,7 @@ JWT and selected scope headers directly through Gateway.
198
204
  | `jobs` | Job Worker | Enqueue, poll, dead-letter management |
199
205
  | `processor` | Processor | Batch and single-job processing |
200
206
  | `sync` | Sync Worker | KV synchronization |
201
- | `authority` | Dominus Authority | Runs, companies, deploys, managed clients, context |
207
+ | `authority` | Dominus Authority | Runs, provisioning targets, deploys, managed clients, context |
202
208
  | `browser` | Browser Worker | Browser run health, ensure/start/status/result/retry/nudge/cancel/timeline/dossier |
203
209
  | `deployer` | Deployer | Thin operator control-plane request surface |
204
210
  | `warden` | Warden | Thin operator control-plane request surface |
@@ -1,6 +1,6 @@
1
- dominus/__init__.py,sha256=fXMmrG8nn-vuCCSCbWfUYjZTWuTgPPgSlBERSxiba5s,7070
1
+ dominus/__init__.py,sha256=SJGv9hmrFgiNNyNHNxo78UsjW_RIFXG32HDrIlg92hM,6894
2
2
  dominus/errors.py,sha256=NthcR-o1Q1nQsE3ZSHStcW_RdZ8LQ06mPDSenY1txgM,8547
3
- dominus/start.py,sha256=Dn6uN2z0KkiJmM8rOLU20JlslZ-xhOLQb2hcJOzHEYo,49839
3
+ dominus/start.py,sha256=rZsBQQw5khy-N_Pk_0pEgJfZSrWp_sroYe3pdKpT_fY,49850
4
4
  dominus/config/__init__.py,sha256=nvLLNh4dM_MCqcfF3XFS2NnVn44q0RYHEfAPP-2G5To,434
5
5
  dominus/config/endpoints.py,sha256=IFioVY3jQ5Mqy65L6rNbEXyPUfYTaXRQkfyGdKv33A8,4140
6
6
  dominus/helpers/__init__.py,sha256=cyoBvw1QJugtGt0gYitIz1yxOaMmBa-wMXqbh-fi4PU,61
@@ -14,9 +14,9 @@ dominus/helpers/trace.py,sha256=i0dRYR4Y46LAnQr0Cm5htbyZ0VA4UQCLMx-q2CQQXSc,2686
14
14
  dominus/namespaces/__init__.py,sha256=4zOayF2IoRHPCVpm41vBF15eoVsScIXv_BVTLsjU3bU,1494
15
15
  dominus/namespaces/admin.py,sha256=qkGoteAJ6cqdNub4zL1mtyxAQtsM3-nUplRSgw2fMZY,1640
16
16
  dominus/namespaces/ai.py,sha256=Kr_eY-SkEfC-b1fhVVv40pXn_GHkxRzMGD47WoTgu9M,48555
17
- dominus/namespaces/artifacts.py,sha256=MgjkjSmUP_5XGTAFU2UQ1VU3Vju3kVuvDqxChosP2J0,22246
17
+ dominus/namespaces/artifacts.py,sha256=Kt1-YBnGAGZmzxG12KOvwENKZ-fGM0SPb_gFknGDZW8,21752
18
18
  dominus/namespaces/auth.py,sha256=YA61WjeRewatrz6BTPhRC95jDgYk3b2QDlH0xdGUceg,67795
19
- dominus/namespaces/authority.py,sha256=vfXNc6A-eAeOzSuyMpBmkWjUvFVXvuelrn3O9YcIY9E,76874
19
+ dominus/namespaces/authority.py,sha256=11QgW6-EC37qP5Xt-hO_GM7JvX5aaKepgAWnIQDAzlw,77645
20
20
  dominus/namespaces/browser.py,sha256=mFxQCvwFy5XmSVIXwwOP2B5WpDnm62U-n-nDlCVn_e8,9042
21
21
  dominus/namespaces/courier.py,sha256=7ZuwTWzVGBPTnqPV1VqPdme6PkPyhQOddwaI1wxrlE8,8324
22
22
  dominus/namespaces/db.py,sha256=dv4IZACziub7OE8i_4q_Z31uVYJglE12TFkFIbFnYjw,15157
@@ -36,9 +36,9 @@ dominus/namespaces/secure.py,sha256=9idGY5R6k7b-JM1SAF_1Gt-YV5OempyxFBflgLJieLo,
36
36
  dominus/namespaces/stash.py,sha256=rdDHl0b0zVyoP_CQxyBxVLPo2O4m_Y1z2YuUWmYXdEM,9945
37
37
  dominus/namespaces/sync.py,sha256=mGwMNwc_iWoKgS94n1staPdsKBHNvliMG7omokl7Qmk,2198
38
38
  dominus/namespaces/warden.py,sha256=ebbCeBJJwK9uALEj2aDbvWJ5HTlOXOpXJOwzokH1cso,1139
39
- dominus/namespaces/workflow.py,sha256=1LMzlYoVImtdpnuenJDtpx7dB2wdNVE3tSBFn-ZAyJA,47204
39
+ dominus/namespaces/workflow.py,sha256=xzUrVFdw7lQYe_ax1IAqs6nUVGJiE5gKIZlKeYmNS0Y,49109
40
40
  dominus/services/__init__.py,sha256=LQl5sx6DHhX1xCN3MRoUgffxqwm3Mfm525hijyFods8,43
41
- dominus_sdk_python-4.6.2.dist-info/METADATA,sha256=nfp-o802nj5qms1_1exjBlmGebXLKAwYiOSiHKO4_zM,8900
42
- dominus_sdk_python-4.6.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
43
- dominus_sdk_python-4.6.2.dist-info/top_level.txt,sha256=515zxMIbX0DpheRbjvNqKIt_AFqdFjX41jtyp_SqLf4,8
44
- dominus_sdk_python-4.6.2.dist-info/RECORD,,
41
+ dominus_sdk_python-5.1.0.dist-info/METADATA,sha256=qgY9jc9bsY9InD_wtioZdKci8jf-FLAqDR3U2SInkCo,9088
42
+ dominus_sdk_python-5.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
43
+ dominus_sdk_python-5.1.0.dist-info/top_level.txt,sha256=515zxMIbX0DpheRbjvNqKIt_AFqdFjX41jtyp_SqLf4,8
44
+ dominus_sdk_python-5.1.0.dist-info/RECORD,,