cairndev 0.1.3__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.
Files changed (620) hide show
  1. cairn/cli/__init__.py +10 -0
  2. cairn/cli/commands/__init__.py +9 -0
  3. cairn/cli/commands/compute.py +149 -0
  4. cairn/cli/commands/config.py +50 -0
  5. cairn/cli/commands/connect.py +533 -0
  6. cairn/cli/commands/demo.py +86 -0
  7. cairn/cli/commands/deploy.py +99 -0
  8. cairn/cli/commands/dev.py +191 -0
  9. cairn/cli/commands/doctor.py +1340 -0
  10. cairn/cli/commands/export.py +286 -0
  11. cairn/cli/commands/flow.py +189 -0
  12. cairn/cli/commands/gate.py +213 -0
  13. cairn/cli/commands/init.py +979 -0
  14. cairn/cli/commands/lineage.py +235 -0
  15. cairn/cli/commands/lock.py +212 -0
  16. cairn/cli/commands/ls.py +424 -0
  17. cairn/cli/commands/pack.py +616 -0
  18. cairn/cli/commands/pipeline.py +517 -0
  19. cairn/cli/commands/remote.py +1215 -0
  20. cairn/cli/commands/replay.py +226 -0
  21. cairn/cli/commands/run.py +1057 -0
  22. cairn/cli/commands/test.py +52 -0
  23. cairn/cli/commands/validate.py +180 -0
  24. cairn/cli/commands/visualize.py +64 -0
  25. cairn/cli/commands/worker.py +192 -0
  26. cairn/cli/main.py +169 -0
  27. cairn/cli/providers.py +142 -0
  28. cairn/cli/runs/__init__.py +51 -0
  29. cairn/cli/runs/paths.py +86 -0
  30. cairn/cli/runs/reader.py +81 -0
  31. cairn/cli/runs/writer.py +103 -0
  32. cairn/cli/tui/__init__.py +10 -0
  33. cairn/cli/tui/app.py +825 -0
  34. cairn/connectors/README.md +40 -0
  35. cairn/connectors/github.toml +28 -0
  36. cairn/connectors/notion.toml +22 -0
  37. cairn/connectors/slack.toml +25 -0
  38. cairn/core/__init__.py +12 -0
  39. cairn/core/_aio.py +32 -0
  40. cairn/core/_time.py +15 -0
  41. cairn/core/account.py +850 -0
  42. cairn/core/admin.py +657 -0
  43. cairn/core/admission_door.py +182 -0
  44. cairn/core/app_client.py +123 -0
  45. cairn/core/approval/__init__.py +13 -0
  46. cairn/core/approval/enforce.py +305 -0
  47. cairn/core/approval/policy_source.py +104 -0
  48. cairn/core/approval/reaper.py +224 -0
  49. cairn/core/approval/resolver.py +175 -0
  50. cairn/core/approval/surface.py +65 -0
  51. cairn/core/auth_tokens.py +126 -0
  52. cairn/core/backend_connections.py +107 -0
  53. cairn/core/backend_selection.py +139 -0
  54. cairn/core/backends/__init__.py +29 -0
  55. cairn/core/backends/protocol.py +64 -0
  56. cairn/core/budget_reservations.py +459 -0
  57. cairn/core/bus/__init__.py +223 -0
  58. cairn/core/bus/postgres.py +186 -0
  59. cairn/core/clients/__init__.py +0 -0
  60. cairn/core/clients/llm_client.py +11 -0
  61. cairn/core/clients/mcp_client.py +294 -0
  62. cairn/core/clients/memory_client.py +11 -0
  63. cairn/core/compute_lifecycle.py +376 -0
  64. cairn/core/connection_probe.py +559 -0
  65. cairn/core/connections.py +977 -0
  66. cairn/core/dataflow/__init__.py +79 -0
  67. cairn/core/dataflow/capture.py +186 -0
  68. cairn/core/dataflow/checkpoints.py +155 -0
  69. cairn/core/dataflow/conformance.py +406 -0
  70. cairn/core/dataflow/conformance_check.py +158 -0
  71. cairn/core/dataflow/contract.py +339 -0
  72. cairn/core/dataflow/defs.py +537 -0
  73. cairn/core/dataflow/engine.py +129 -0
  74. cairn/core/dataflow/engine_door.py +129 -0
  75. cairn/core/dataflow/engine_registry.py +154 -0
  76. cairn/core/dataflow/export.py +356 -0
  77. cairn/core/dataflow/fetch.py +100 -0
  78. cairn/core/dataflow/gate_split.py +213 -0
  79. cairn/core/dataflow/manifest.py +75 -0
  80. cairn/core/dataflow/resources.py +114 -0
  81. cairn/core/dataflow/results.py +63 -0
  82. cairn/core/dataflow/runner.py +623 -0
  83. cairn/core/dataflow/stage_loader.py +150 -0
  84. cairn/core/dataflow/sysmetrics.py +149 -0
  85. cairn/core/dataset_readers.py +64 -0
  86. cairn/core/dataset_roles.py +436 -0
  87. cairn/core/demo_seed.py +360 -0
  88. cairn/core/deploy_check.py +902 -0
  89. cairn/core/dispatch/__init__.py +0 -0
  90. cairn/core/dispatch/bus_bridge.py +91 -0
  91. cairn/core/dispatch/coordination.py +232 -0
  92. cairn/core/dispatch/dispatcher.py +1623 -0
  93. cairn/core/dispatch/event_triggers.py +117 -0
  94. cairn/core/dispatch/leg_executor.py +679 -0
  95. cairn/core/dispatch/leg_hooks.py +301 -0
  96. cairn/core/dispatch/pipeline_bridge.py +3374 -0
  97. cairn/core/dispatch/pipeline_doors.py +293 -0
  98. cairn/core/dispatch/pipeline_launch.py +491 -0
  99. cairn/core/dispatch/pipeline_preview.py +309 -0
  100. cairn/core/dispatch/pipeline_resume.py +100 -0
  101. cairn/core/dispatch/schedule_catchup.py +275 -0
  102. cairn/core/dispatch/scheduler.py +494 -0
  103. cairn/core/dispatch/sse_bridge.py +82 -0
  104. cairn/core/dispatch/start.py +470 -0
  105. cairn/core/dispatch/target_concurrency.py +147 -0
  106. cairn/core/eligibility.py +128 -0
  107. cairn/core/engine/__init__.py +0 -0
  108. cairn/core/engine/artifacts.py +110 -0
  109. cairn/core/engine/bundle.py +430 -0
  110. cairn/core/engine/bundle_pipeline.py +322 -0
  111. cairn/core/engine/compiled.py +141 -0
  112. cairn/core/engine/compiler.py +2025 -0
  113. cairn/core/engine/condition_registry.py +233 -0
  114. cairn/core/engine/expr.py +606 -0
  115. cairn/core/engine/flatten.py +119 -0
  116. cairn/core/engine/pipeline.py +1159 -0
  117. cairn/core/engine/pipeline_explain.py +1026 -0
  118. cairn/core/engine/pipeline_gate.py +127 -0
  119. cairn/core/engine/pipeline_inherit.py +259 -0
  120. cairn/core/engine/pipeline_loop.py +242 -0
  121. cairn/core/engine/pipeline_resolve.py +335 -0
  122. cairn/core/engine/pipeline_resolved.py +405 -0
  123. cairn/core/engine/pipeline_triggers.py +317 -0
  124. cairn/core/engine/python_function_registry.py +724 -0
  125. cairn/core/engine/runner.py +606 -0
  126. cairn/core/engine/schema.py +1020 -0
  127. cairn/core/engine/schemas.py +251 -0
  128. cairn/core/engine/skill_engine.py +481 -0
  129. cairn/core/engine/triggers_grammar.py +1129 -0
  130. cairn/core/engine/triggers_presets.py +108 -0
  131. cairn/core/engine/triggers_spec.py +530 -0
  132. cairn/core/engine/visualize.py +63 -0
  133. cairn/core/engine/workflow_config.py +241 -0
  134. cairn/core/eval/__init__.py +90 -0
  135. cairn/core/eval/actuation.py +274 -0
  136. cairn/core/eval/auto_eval.py +342 -0
  137. cairn/core/eval/cluster.py +109 -0
  138. cairn/core/eval/comparison.py +258 -0
  139. cairn/core/eval/continuous.py +87 -0
  140. cairn/core/eval/cost_baseline.py +141 -0
  141. cairn/core/eval/diagnosis.py +86 -0
  142. cairn/core/eval/recipe.py +386 -0
  143. cairn/core/eval/scorecard.py +216 -0
  144. cairn/core/eval/scorer.py +205 -0
  145. cairn/core/eval/scoring.py +95 -0
  146. cairn/core/eval/suggest.py +135 -0
  147. cairn/core/eval/taxonomy.py +527 -0
  148. cairn/core/eval_cutoff.py +220 -0
  149. cairn/core/features.py +517 -0
  150. cairn/core/gate_notify.py +209 -0
  151. cairn/core/gateway.py +181 -0
  152. cairn/core/graph_view.py +357 -0
  153. cairn/core/guards/__init__.py +0 -0
  154. cairn/core/guards/citation_validator.py +227 -0
  155. cairn/core/guards/critique.py +140 -0
  156. cairn/core/holdout.py +531 -0
  157. cairn/core/intake.py +635 -0
  158. cairn/core/interrupts.py +50 -0
  159. cairn/core/job_channel_door.py +124 -0
  160. cairn/core/judge_agreement.py +599 -0
  161. cairn/core/leadership.py +269 -0
  162. cairn/core/liveness.py +565 -0
  163. cairn/core/llm/__init__.py +0 -0
  164. cairn/core/llm/client.py +266 -0
  165. cairn/core/llm/deepeval_model.py +137 -0
  166. cairn/core/llm/models.py +240 -0
  167. cairn/core/llm/models.yaml +32 -0
  168. cairn/core/model_license_gate.py +138 -0
  169. cairn/core/notifier.py +372 -0
  170. cairn/core/oauth/__init__.py +36 -0
  171. cairn/core/oauth/broker.py +299 -0
  172. cairn/core/oauth/catalog.py +88 -0
  173. cairn/core/oauth/providers.yaml +76 -0
  174. cairn/core/oauth/store.py +250 -0
  175. cairn/core/oauth_login.py +310 -0
  176. cairn/core/obs/__init__.py +67 -0
  177. cairn/core/obs/audit.py +167 -0
  178. cairn/core/obs/base.py +201 -0
  179. cairn/core/obs/cost.py +124 -0
  180. cairn/core/obs/events.py +40 -0
  181. cairn/core/obs/guard.py +41 -0
  182. cairn/core/obs/metrics.py +114 -0
  183. cairn/core/obs/redact.py +143 -0
  184. cairn/core/obs/replay.py +39 -0
  185. cairn/core/obs/telemetry.py +291 -0
  186. cairn/core/operator/__init__.py +222 -0
  187. cairn/core/operator/batch.py +202 -0
  188. cairn/core/operator/binding.py +250 -0
  189. cairn/core/operator/binding_validate.py +125 -0
  190. cairn/core/operator/config.py +398 -0
  191. cairn/core/operator/effective.py +304 -0
  192. cairn/core/operator/elaborate.py +76 -0
  193. cairn/core/operator/executor.py +175 -0
  194. cairn/core/operator/guard.py +75 -0
  195. cairn/core/operator/job_channel.py +374 -0
  196. cairn/core/operator/job_control.py +381 -0
  197. cairn/core/operator/job_store.py +798 -0
  198. cairn/core/operator/jobs.py +516 -0
  199. cairn/core/operator/learning.py +67 -0
  200. cairn/core/operator/loader.py +289 -0
  201. cairn/core/operator/manifest_sync.py +395 -0
  202. cairn/core/operator/pins.py +188 -0
  203. cairn/core/operator/protocol.py +524 -0
  204. cairn/core/operator/registry.py +300 -0
  205. cairn/core/operator/report_ingest.py +206 -0
  206. cairn/core/operator/reports.py +236 -0
  207. cairn/core/operator/runtime.py +1225 -0
  208. cairn/core/operator/secrets.py +124 -0
  209. cairn/core/operator/sharded.py +330 -0
  210. cairn/core/operator/stage_events.py +68 -0
  211. cairn/core/operator/testing.py +173 -0
  212. cairn/core/operator/watch_probe.py +61 -0
  213. cairn/core/pack/__init__.py +158 -0
  214. cairn/core/pack/composition.py +377 -0
  215. cairn/core/pack/contracts.py +812 -0
  216. cairn/core/pack/curation.py +188 -0
  217. cairn/core/pack/demos.py +153 -0
  218. cairn/core/pack/discovery.py +51 -0
  219. cairn/core/pack/drift.py +227 -0
  220. cairn/core/pack/loader.py +676 -0
  221. cairn/core/pack/manifest.py +1596 -0
  222. cairn/core/pack/model_catalogs.py +82 -0
  223. cairn/core/pack/profile.py +616 -0
  224. cairn/core/pack/protocol.py +305 -0
  225. cairn/core/pack/provisioning.py +54 -0
  226. cairn/core/pack/registry.py +371 -0
  227. cairn/core/pack/run_hooks.py +158 -0
  228. cairn/core/pack/seeds.py +120 -0
  229. cairn/core/pack/visibility.py +179 -0
  230. cairn/core/pg_schema_init.py +164 -0
  231. cairn/core/pipeline_presets.py +283 -0
  232. cairn/core/plan.py +244 -0
  233. cairn/core/policy/__init__.py +0 -0
  234. cairn/core/policy/engine.py +302 -0
  235. cairn/core/policy/pipeline_gates.py +232 -0
  236. cairn/core/policy/store.py +289 -0
  237. cairn/core/preflight.py +303 -0
  238. cairn/core/profile_backends.py +377 -0
  239. cairn/core/profile_store.py +278 -0
  240. cairn/core/provider_settings.py +167 -0
  241. cairn/core/pull_worker.py +337 -0
  242. cairn/core/pull_worker_door.py +128 -0
  243. cairn/core/refs.py +157 -0
  244. cairn/core/registry.py +92 -0
  245. cairn/core/registry_catalog.py +244 -0
  246. cairn/core/registry_install.py +470 -0
  247. cairn/core/reporting.py +138 -0
  248. cairn/core/run_bundle.py +316 -0
  249. cairn/core/run_failure.py +226 -0
  250. cairn/core/run_progress.py +64 -0
  251. cairn/core/runtime/__init__.py +58 -0
  252. cairn/core/runtime/base.py +148 -0
  253. cairn/core/runtime/checkpointer.py +291 -0
  254. cairn/core/runtime/dbos/__init__.py +46 -0
  255. cairn/core/runtime/dbos/registry.py +102 -0
  256. cairn/core/runtime/dbos/runtime.py +243 -0
  257. cairn/core/runtime/dbos/workflow.py +115 -0
  258. cairn/core/runtime/inprocess.py +116 -0
  259. cairn/core/runtime/node_events.py +75 -0
  260. cairn/core/runtime/node_record.py +56 -0
  261. cairn/core/runtime/node_stream.py +115 -0
  262. cairn/core/runtime/reconciler.py +585 -0
  263. cairn/core/runtime/retry.py +155 -0
  264. cairn/core/runtime/temporal/__init__.py +46 -0
  265. cairn/core/runtime/temporal/activities.py +180 -0
  266. cairn/core/runtime/temporal/pipeline_activities.py +523 -0
  267. cairn/core/runtime/temporal/pipeline_workflow.py +336 -0
  268. cairn/core/runtime/temporal/registry.py +125 -0
  269. cairn/core/runtime/temporal/runtime.py +230 -0
  270. cairn/core/runtime/temporal/worker.py +357 -0
  271. cairn/core/runtime/temporal/workflow.py +130 -0
  272. cairn/core/schema/__init__.py +79 -0
  273. cairn/core/schema/registry.py +220 -0
  274. cairn/core/schema/uri.py +151 -0
  275. cairn/core/schema/yaml_loader.py +267 -0
  276. cairn/core/secrets_store.py +329 -0
  277. cairn/core/settings.py +1230 -0
  278. cairn/core/signup.py +243 -0
  279. cairn/core/ssh_exec.py +270 -0
  280. cairn/core/storage/README.md +225 -0
  281. cairn/core/storage/__init__.py +232 -0
  282. cairn/core/storage/artifact_bytes.py +250 -0
  283. cairn/core/storage/artifacts.py +1285 -0
  284. cairn/core/storage/backend.py +167 -0
  285. cairn/core/storage/backfill_pipelines.py +499 -0
  286. cairn/core/storage/episodic.py +80 -0
  287. cairn/core/storage/eval_ledger.py +517 -0
  288. cairn/core/storage/fingerprints.py +438 -0
  289. cairn/core/storage/hydration.py +151 -0
  290. cairn/core/storage/judge_labels.py +258 -0
  291. cairn/core/storage/judges.py +509 -0
  292. cairn/core/storage/knowledge_corpora.py +290 -0
  293. cairn/core/storage/memory/__init__.py +7 -0
  294. cairn/core/storage/memory/runs.py +160 -0
  295. cairn/core/storage/migrations.py +92 -0
  296. cairn/core/storage/pipeline_store.py +422 -0
  297. cairn/core/storage/postgres/__init__.py +18 -0
  298. cairn/core/storage/postgres/pool.py +98 -0
  299. cairn/core/storage/postgres/runs.py +571 -0
  300. cairn/core/storage/protocols.py +745 -0
  301. cairn/core/storage/rag.py +87 -0
  302. cairn/core/storage/rag_catalog.py +302 -0
  303. cairn/core/storage/respell_packs.py +423 -0
  304. cairn/core/storage/retention.py +171 -0
  305. cairn/core/storage/reviews.py +405 -0
  306. cairn/core/storage/schedule_store.py +428 -0
  307. cairn/core/storage/sqlite/__init__.py +10 -0
  308. cairn/core/storage/sqlite/runs.py +472 -0
  309. cairn/core/storage/suggestions.py +421 -0
  310. cairn/core/storage/transitions.py +133 -0
  311. cairn/core/storage/trigger_inbox.py +471 -0
  312. cairn/core/storage/trigger_store.py +378 -0
  313. cairn/core/triggers/__init__.py +54 -0
  314. cairn/core/triggers/auth.py +808 -0
  315. cairn/core/triggers/console_support.py +329 -0
  316. cairn/core/triggers/declared.py +13 -0
  317. cairn/core/triggers/feature_gate.py +33 -0
  318. cairn/core/triggers/inbox.py +12 -0
  319. cairn/core/triggers/main.py +126 -0
  320. cairn/core/triggers/mcp.py +179 -0
  321. cairn/core/triggers/presets.py +13 -0
  322. cairn/core/triggers/provider.py +162 -0
  323. cairn/core/triggers/router.py +499 -0
  324. cairn/core/triggers/router_providers.py +117 -0
  325. cairn/core/triggers/routers/__init__.py +9 -0
  326. cairn/core/triggers/routers/accounts.py +466 -0
  327. cairn/core/triggers/routers/ingress.py +206 -0
  328. cairn/core/triggers/routers/jobs.py +165 -0
  329. cairn/core/triggers/routers/oauth.py +33 -0
  330. cairn/core/triggers/routers/pipelines.py +877 -0
  331. cairn/core/triggers/routers/registry.py +198 -0
  332. cairn/core/triggers/routers/reviews.py +64 -0
  333. cairn/core/triggers/routers/run_control.py +342 -0
  334. cairn/core/triggers/routers/runs.py +443 -0
  335. cairn/core/triggers/routers/schedules.py +282 -0
  336. cairn/core/triggers/routers/start.py +278 -0
  337. cairn/core/triggers/routers/templates.py +184 -0
  338. cairn/core/triggers/schedule_store.py +12 -0
  339. cairn/core/triggers/server.py +1300 -0
  340. cairn/core/triggers/spec.py +13 -0
  341. cairn/core/triggers/store.py +12 -0
  342. cairn/core/ui_contract.py +360 -0
  343. cairn/core/ui_render.py +158 -0
  344. cairn/core/validate.py +500 -0
  345. cairn/core/workflow_config_store.py +698 -0
  346. cairn/core/workflow_registry.py +876 -0
  347. cairn/core/workspace.py +404 -0
  348. cairn/core/workspace_variables.py +277 -0
  349. cairn/pipeline_file.py +190 -0
  350. cairn/profiles/__init__.py +37 -0
  351. cairn/profiles/local-dev.toml +62 -0
  352. cairn/profiles/prod-infisical.toml +34 -0
  353. cairn/profiles/sandbox.toml +34 -0
  354. cairn/profiles/secure.toml +24 -0
  355. cairn/providers/__init__.py +7 -0
  356. cairn/providers/vectorstores/__init__.py +8 -0
  357. cairn/providers/vectorstores/pinecone.py +38 -0
  358. cairn/providers/vectorstores/qdrant.py +196 -0
  359. cairn/py.typed +0 -0
  360. cairn/services/__init__.py +0 -0
  361. cairn/services/data/__init__.py +33 -0
  362. cairn/services/data/loaders.py +172 -0
  363. cairn/services/data/profile.py +231 -0
  364. cairn/services/data/quality.py +173 -0
  365. cairn/services/llm/__init__.py +0 -0
  366. cairn/services/llm/factory.py +158 -0
  367. cairn/services/llm/gateway.py +119 -0
  368. cairn/services/llm/redacting.py +135 -0
  369. cairn/services/mcp/__init__.py +0 -0
  370. cairn/services/mcp/client.py +268 -0
  371. cairn/services/mcp/presets.py +70 -0
  372. cairn/services/mcp/tool_adapter.py +78 -0
  373. cairn/services/memory/__init__.py +0 -0
  374. cairn/services/memory/store.py +168 -0
  375. cairn/services/memory/writer.py +214 -0
  376. cairn/services/rag/__init__.py +45 -0
  377. cairn/services/rag/byo.py +117 -0
  378. cairn/services/rag/embeddings.py +210 -0
  379. cairn/services/rag/idempotency.py +44 -0
  380. cairn/services/rag/indexer.py +162 -0
  381. cairn/services/rag/ingest.py +251 -0
  382. cairn/services/rag/inject.py +157 -0
  383. cairn/services/rag/lifecycle.py +175 -0
  384. cairn/services/rag/plan.py +97 -0
  385. cairn/services/rag/query.py +227 -0
  386. cairn/services/rag/readers.py +252 -0
  387. cairn/services/rag/roles.py +71 -0
  388. cairn/services/rag/schedule.py +123 -0
  389. cairn/services/rag/schemas.py +18 -0
  390. cairn/services/rag/stores/__init__.py +95 -0
  391. cairn/services/rag/stores/base.py +73 -0
  392. cairn/services/rag/stores/pgvector.py +341 -0
  393. cairn/services/rag/stores/sqlite_vec.py +406 -0
  394. cairn_contracts/cairn-contracts-artifact/capabilities/artifact.promote.json +9 -0
  395. cairn_contracts/cairn-contracts-artifact/contracts.toml +29 -0
  396. cairn_contracts/cairn-contracts-artifact/schemas/artifact.promote.configuration.json +7 -0
  397. cairn_contracts/cairn-contracts-artifact/schemas/artifact.promote.input.json +22 -0
  398. cairn_contracts/cairn-contracts-artifact/schemas/artifact.promote.output.json +18 -0
  399. cairn_contracts/cairn-contracts-audit/capabilities/audit.sink.json +9 -0
  400. cairn_contracts/cairn-contracts-audit/contracts.toml +29 -0
  401. cairn_contracts/cairn-contracts-audit/schemas/audit.sink.configuration.json +7 -0
  402. cairn_contracts/cairn-contracts-audit/schemas/audit.sink.input.json +31 -0
  403. cairn_contracts/cairn-contracts-audit/schemas/audit.sink.output.json +15 -0
  404. cairn_contracts/cairn-contracts-data/capabilities/data.profile.json +9 -0
  405. cairn_contracts/cairn-contracts-data/contracts.toml +29 -0
  406. cairn_contracts/cairn-contracts-data/schemas/data.profile.configuration.json +7 -0
  407. cairn_contracts/cairn-contracts-data/schemas/data.profile.input.json +96 -0
  408. cairn_contracts/cairn-contracts-data/schemas/data.profile.output.json +37 -0
  409. cairn_contracts/cairn-contracts-dataflow/capabilities/dataflow.run.json +9 -0
  410. cairn_contracts/cairn-contracts-dataflow/capabilities/ml.run.json +9 -0
  411. cairn_contracts/cairn-contracts-dataflow/contracts.toml +53 -0
  412. cairn_contracts/cairn-contracts-dataflow/schemas/dataflow.run.configuration.json +7 -0
  413. cairn_contracts/cairn-contracts-dataflow/schemas/dataflow.run.input.json +35 -0
  414. cairn_contracts/cairn-contracts-dataflow/schemas/dataflow.run.output.json +16 -0
  415. cairn_contracts/cairn-contracts-dataflow/schemas/ml.run.configuration.json +7 -0
  416. cairn_contracts/cairn-contracts-dataflow/schemas/ml.run.input.json +40 -0
  417. cairn_contracts/cairn-contracts-dataflow/schemas/ml.run.output.json +16 -0
  418. cairn_contracts/cairn-contracts-mcp/capabilities/mcp.call.json +9 -0
  419. cairn_contracts/cairn-contracts-mcp/contracts.toml +29 -0
  420. cairn_contracts/cairn-contracts-mcp/schemas/mcp.call.configuration.json +7 -0
  421. cairn_contracts/cairn-contracts-mcp/schemas/mcp.call.input.json +22 -0
  422. cairn_contracts/cairn-contracts-mcp/schemas/mcp.call.output.json +13 -0
  423. cairn_contracts/cairn-contracts-memory/capabilities/memory.search.json +9 -0
  424. cairn_contracts/cairn-contracts-memory/capabilities/memory.write.json +9 -0
  425. cairn_contracts/cairn-contracts-memory/contracts.toml +53 -0
  426. cairn_contracts/cairn-contracts-memory/schemas/memory.search.configuration.json +7 -0
  427. cairn_contracts/cairn-contracts-memory/schemas/memory.search.input.json +30 -0
  428. cairn_contracts/cairn-contracts-memory/schemas/memory.search.output.json +25 -0
  429. cairn_contracts/cairn-contracts-memory/schemas/memory.write.configuration.json +7 -0
  430. cairn_contracts/cairn-contracts-memory/schemas/memory.write.input.json +28 -0
  431. cairn_contracts/cairn-contracts-memory/schemas/memory.write.output.json +13 -0
  432. cairn_contracts/cairn-contracts-monitor/capabilities/monitor.dispatch.json +9 -0
  433. cairn_contracts/cairn-contracts-monitor/capabilities/monitor.propose.json +9 -0
  434. cairn_contracts/cairn-contracts-monitor/capabilities/monitor.threshold.json +9 -0
  435. cairn_contracts/cairn-contracts-monitor/contracts.toml +77 -0
  436. cairn_contracts/cairn-contracts-monitor/schemas/monitor.dispatch.configuration.json +7 -0
  437. cairn_contracts/cairn-contracts-monitor/schemas/monitor.dispatch.input.json +44 -0
  438. cairn_contracts/cairn-contracts-monitor/schemas/monitor.dispatch.output.json +32 -0
  439. cairn_contracts/cairn-contracts-monitor/schemas/monitor.propose.configuration.json +7 -0
  440. cairn_contracts/cairn-contracts-monitor/schemas/monitor.propose.input.json +27 -0
  441. cairn_contracts/cairn-contracts-monitor/schemas/monitor.propose.output.json +19 -0
  442. cairn_contracts/cairn-contracts-monitor/schemas/monitor.threshold.configuration.json +7 -0
  443. cairn_contracts/cairn-contracts-monitor/schemas/monitor.threshold.input.json +45 -0
  444. cairn_contracts/cairn-contracts-monitor/schemas/monitor.threshold.output.json +24 -0
  445. cairn_contracts/cairn-contracts-rag/capabilities/rag.fetch.json +9 -0
  446. cairn_contracts/cairn-contracts-rag/capabilities/rag.rerank.json +9 -0
  447. cairn_contracts/cairn-contracts-rag/capabilities/rag.search.json +9 -0
  448. cairn_contracts/cairn-contracts-rag/contracts.toml +77 -0
  449. cairn_contracts/cairn-contracts-rag/schemas/rag.fetch.configuration.json +7 -0
  450. cairn_contracts/cairn-contracts-rag/schemas/rag.fetch.input.json +16 -0
  451. cairn_contracts/cairn-contracts-rag/schemas/rag.fetch.output.json +22 -0
  452. cairn_contracts/cairn-contracts-rag/schemas/rag.rerank.configuration.json +7 -0
  453. cairn_contracts/cairn-contracts-rag/schemas/rag.rerank.input.json +26 -0
  454. cairn_contracts/cairn-contracts-rag/schemas/rag.rerank.output.json +29 -0
  455. cairn_contracts/cairn-contracts-rag/schemas/rag.search.configuration.json +7 -0
  456. cairn_contracts/cairn-contracts-rag/schemas/rag.search.input.json +30 -0
  457. cairn_contracts/cairn-contracts-rag/schemas/rag.search.output.json +25 -0
  458. cairn_contracts/cairn-contracts-redact/capabilities/redact.text.json +9 -0
  459. cairn_contracts/cairn-contracts-redact/contracts.toml +29 -0
  460. cairn_contracts/cairn-contracts-redact/schemas/redact.text.configuration.json +7 -0
  461. cairn_contracts/cairn-contracts-redact/schemas/redact.text.input.json +8 -0
  462. cairn_contracts/cairn-contracts-redact/schemas/redact.text.output.json +19 -0
  463. cairn_contracts/cairn-contracts-remote/capabilities/remote.exec.json +9 -0
  464. cairn_contracts/cairn-contracts-remote/contracts.toml +29 -0
  465. cairn_contracts/cairn-contracts-remote/schemas/remote.exec.configuration.json +7 -0
  466. cairn_contracts/cairn-contracts-remote/schemas/remote.exec.input.json +39 -0
  467. cairn_contracts/cairn-contracts-remote/schemas/remote.exec.output.json +26 -0
  468. cairn_contracts/cairn-contracts-secrets/capabilities/secrets.store.json +9 -0
  469. cairn_contracts/cairn-contracts-secrets/contracts.toml +29 -0
  470. cairn_contracts/cairn-contracts-secrets/schemas/secrets.store.configuration.json +7 -0
  471. cairn_contracts/cairn-contracts-secrets/schemas/secrets.store.input.json +10 -0
  472. cairn_contracts/cairn-contracts-secrets/schemas/secrets.store.output.json +14 -0
  473. cairn_contracts/cairn-contracts-storage/capabilities/storage.get.json +9 -0
  474. cairn_contracts/cairn-contracts-storage/capabilities/storage.put.json +9 -0
  475. cairn_contracts/cairn-contracts-storage/contracts.toml +53 -0
  476. cairn_contracts/cairn-contracts-storage/schemas/storage.get.configuration.json +7 -0
  477. cairn_contracts/cairn-contracts-storage/schemas/storage.get.input.json +33 -0
  478. cairn_contracts/cairn-contracts-storage/schemas/storage.get.output.json +20 -0
  479. cairn_contracts/cairn-contracts-storage/schemas/storage.put.configuration.json +7 -0
  480. cairn_contracts/cairn-contracts-storage/schemas/storage.put.input.json +34 -0
  481. cairn_contracts/cairn-contracts-storage/schemas/storage.put.output.json +16 -0
  482. cairn_contracts/cairn-contracts-train/capabilities/train.eval_loss.json +10 -0
  483. cairn_contracts/cairn-contracts-train/capabilities/train.finetune.json +10 -0
  484. cairn_contracts/cairn-contracts-train/contracts.toml +65 -0
  485. cairn_contracts/cairn-contracts-train/reports/train.eval_loss.report.json +6 -0
  486. cairn_contracts/cairn-contracts-train/reports/train.finetune.report.json +10 -0
  487. cairn_contracts/cairn-contracts-train/schemas/train.eval_loss.configuration.json +7 -0
  488. cairn_contracts/cairn-contracts-train/schemas/train.eval_loss.input.json +30 -0
  489. cairn_contracts/cairn-contracts-train/schemas/train.eval_loss.output.json +11 -0
  490. cairn_contracts/cairn-contracts-train/schemas/train.finetune.configuration.json +16 -0
  491. cairn_contracts/cairn-contracts-train/schemas/train.finetune.input.json +44 -0
  492. cairn_contracts/cairn-contracts-train/schemas/train.finetune.output.json +22 -0
  493. cairndev-0.1.3.dist-info/METADATA +275 -0
  494. cairndev-0.1.3.dist-info/RECORD +620 -0
  495. cairndev-0.1.3.dist-info/WHEEL +4 -0
  496. cairndev-0.1.3.dist-info/entry_points.txt +45 -0
  497. cairndev-0.1.3.dist-info/licenses/LICENSE +202 -0
  498. cairndev-0.1.3.dist-info/licenses/NOTICE +19 -0
  499. cairndev-0.1.3.dist-info/licenses/THIRD_PARTY_NOTICES.md +197 -0
  500. operator_artifact_local/__init__.py +17 -0
  501. operator_artifact_local/_fs.py +71 -0
  502. operator_artifact_local/operators/__init__.py +0 -0
  503. operator_artifact_local/operators/get.py +107 -0
  504. operator_artifact_local/operators/put.py +99 -0
  505. operator_artifact_local/pack.toml +68 -0
  506. operator_artifact_local/py.typed +0 -0
  507. operator_artifact_local/schemas/__init__.py +0 -0
  508. operator_artifact_local/schemas/get.py +53 -0
  509. operator_artifact_local/schemas/put.py +54 -0
  510. operator_audit_store/__init__.py +0 -0
  511. operator_audit_store/operators/__init__.py +0 -0
  512. operator_audit_store/operators/audit_store.py +150 -0
  513. operator_audit_store/pack.toml +40 -0
  514. operator_audit_store/schemas/__init__.py +0 -0
  515. operator_audit_store/schemas/audit_store.py +21 -0
  516. operator_data_profile/__init__.py +0 -0
  517. operator_data_profile/operators/__init__.py +0 -0
  518. operator_data_profile/operators/profile.py +42 -0
  519. operator_data_profile/pack.toml +36 -0
  520. operator_data_profile/py.typed +0 -0
  521. operator_data_profile/schemas/__init__.py +0 -0
  522. operator_data_profile/schemas/profile.py +26 -0
  523. operator_dataflow/__init__.py +1 -0
  524. operator_dataflow/engine/__init__.py +1 -0
  525. operator_dataflow/engine/entry.py +104 -0
  526. operator_dataflow/engine/runner.py +13 -0
  527. operator_dataflow/engines.py +215 -0
  528. operator_dataflow/engines_ssh.py +466 -0
  529. operator_dataflow/operators/__init__.py +1 -0
  530. operator_dataflow/operators/promote.py +76 -0
  531. operator_dataflow/operators/run.py +164 -0
  532. operator_dataflow/operators/run_ml.py +113 -0
  533. operator_dataflow/pack.toml +72 -0
  534. operator_dataflow/schemas/__init__.py +1 -0
  535. operator_dataflow/schemas/promote.py +22 -0
  536. operator_dataflow/schemas/run.py +49 -0
  537. operator_dataflow/schemas/run_ml.py +49 -0
  538. operator_dataflow/stages.py +19 -0
  539. operator_mcp/__init__.py +13 -0
  540. operator_mcp/operators/__init__.py +0 -0
  541. operator_mcp/operators/call.py +94 -0
  542. operator_mcp/pack.toml +52 -0
  543. operator_mcp/schemas/__init__.py +0 -0
  544. operator_mcp/schemas/call.py +52 -0
  545. operator_memory_local/__init__.py +18 -0
  546. operator_memory_local/operators/__init__.py +0 -0
  547. operator_memory_local/operators/search.py +128 -0
  548. operator_memory_local/operators/write.py +83 -0
  549. operator_memory_local/pack.toml +71 -0
  550. operator_memory_local/py.typed +0 -0
  551. operator_memory_local/schemas/__init__.py +0 -0
  552. operator_memory_local/schemas/search.py +55 -0
  553. operator_memory_local/schemas/write.py +50 -0
  554. operator_monitor_threshold/__init__.py +0 -0
  555. operator_monitor_threshold/operators/__init__.py +0 -0
  556. operator_monitor_threshold/operators/dispatch.py +78 -0
  557. operator_monitor_threshold/operators/propose.py +46 -0
  558. operator_monitor_threshold/operators/threshold.py +106 -0
  559. operator_monitor_threshold/pack.toml +74 -0
  560. operator_monitor_threshold/py.typed +0 -0
  561. operator_monitor_threshold/schemas/__init__.py +2 -0
  562. operator_monitor_threshold/schemas/dispatch.py +23 -0
  563. operator_monitor_threshold/schemas/propose.py +23 -0
  564. operator_monitor_threshold/schemas/threshold.py +41 -0
  565. operator_monitor_threshold/source_guard.py +126 -0
  566. operator_rag_local/__init__.py +17 -0
  567. operator_rag_local/operators/__init__.py +0 -0
  568. operator_rag_local/operators/fetch.py +107 -0
  569. operator_rag_local/operators/search.py +124 -0
  570. operator_rag_local/pack.toml +70 -0
  571. operator_rag_local/py.typed +0 -0
  572. operator_rag_local/schemas/__init__.py +0 -0
  573. operator_rag_local/schemas/fetch.py +45 -0
  574. operator_rag_local/schemas/search.py +55 -0
  575. operator_rag_rerank/__init__.py +0 -0
  576. operator_rag_rerank/operators/__init__.py +0 -0
  577. operator_rag_rerank/operators/rerank.py +125 -0
  578. operator_rag_rerank/pack.toml +46 -0
  579. operator_rag_rerank/py.typed +0 -0
  580. operator_rag_rerank/schemas/__init__.py +0 -0
  581. operator_rag_rerank/schemas/rerank.py +33 -0
  582. operator_redact_regex/__init__.py +0 -0
  583. operator_redact_regex/operators/__init__.py +0 -0
  584. operator_redact_regex/operators/redact_text.py +119 -0
  585. operator_redact_regex/pack.toml +38 -0
  586. operator_redact_regex/py.typed +0 -0
  587. operator_redact_regex/schemas/__init__.py +0 -0
  588. operator_redact_regex/schemas/redact_text.py +16 -0
  589. operator_remote/__init__.py +1 -0
  590. operator_remote/operators/__init__.py +0 -0
  591. operator_remote/operators/exec.py +403 -0
  592. operator_remote/pack.toml +31 -0
  593. operator_remote/py.typed +0 -0
  594. operator_remote/schemas/__init__.py +0 -0
  595. operator_remote/schemas/exec.py +34 -0
  596. operator_secrets_env/__init__.py +0 -0
  597. operator_secrets_env/operators/__init__.py +0 -0
  598. operator_secrets_env/operators/env.py +60 -0
  599. operator_secrets_env/pack.toml +37 -0
  600. operator_secrets_env/py.typed +0 -0
  601. operator_secrets_env/schemas/__init__.py +0 -0
  602. operator_secrets_env/schemas/env.py +17 -0
  603. operator_secrets_infisical/__init__.py +0 -0
  604. operator_secrets_infisical/_infisical.py +92 -0
  605. operator_secrets_infisical/operators/__init__.py +0 -0
  606. operator_secrets_infisical/operators/infisical.py +91 -0
  607. operator_secrets_infisical/pack.toml +51 -0
  608. operator_secrets_infisical/py.typed +0 -0
  609. operator_secrets_infisical/schemas/__init__.py +0 -0
  610. operator_secrets_infisical/schemas/infisical.py +17 -0
  611. operator_train_local/__init__.py +0 -0
  612. operator_train_local/finetune.py +244 -0
  613. operator_train_local/operators/__init__.py +0 -0
  614. operator_train_local/operators/eval_loss.py +46 -0
  615. operator_train_local/operators/lora.py +75 -0
  616. operator_train_local/pack.toml +60 -0
  617. operator_train_local/py.typed +0 -0
  618. operator_train_local/schemas/__init__.py +0 -0
  619. operator_train_local/schemas/train.py +71 -0
  620. operator_train_local/stages.py +66 -0
cairn/cli/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+ """cairn CLI surface.
2
+
3
+ Top-level dispatcher (:mod:`cairn.cli.main`) registers one Typer command
4
+ per file in :mod:`cairn.cli.commands`. The CLI is a thin shell: every
5
+ command wires args → calls into :mod:`cairn.core` → renders a result.
6
+ Business logic stays out of this layer.
7
+
8
+ Entry point is wired in ``pyproject.toml`` as the ``cairn`` script —
9
+ ``pip install -e .`` puts ``cairn`` on PATH.
10
+ """
@@ -0,0 +1,9 @@
1
+ """CLI command modules.
2
+
3
+ One file per command. Each module exposes a Typer-compatible function
4
+ (decorated/registered in :mod:`cairn.cli.main`) and any helpers it needs.
5
+ Command modules MUST NOT contain business logic — they wire args → call into
6
+ :mod:`cairn.core` → render a result. The single exception is the doctor
7
+ module, whose probe logic lived in core/ before the CLI existed and was moved
8
+ here intact as part of the CLI-layer extraction.
9
+ """
@@ -0,0 +1,149 @@
1
+ """``cairn compute`` — the lifecycle of a governed compute box (#1787, ADR-0097).
2
+
3
+ Two verbs, both thin faces on :mod:`cairn.core.compute_lifecycle` (the same
4
+ module ``compute/acquire`` and ``compute/release`` call, so the CLI and the
5
+ operators can never disagree about what "stopped" means — #1376):
6
+
7
+ * ``cairn compute status <connection>`` — what state is the box in, what does it
8
+ bill, and when does its lease expire?
9
+ * ``cairn compute sweep`` — **the watchdog**. Stop every cairn-managed instance
10
+ whose ``cairn:release-after`` lease has expired.
11
+
12
+ Why the sweep exists, stated plainly. ``max_hours`` on ``compute/acquire`` stamps
13
+ a deadline TAG on the instance; this verb is what acts on it. Because the
14
+ deadline lives on the instance and the credentials are all this verb needs, the
15
+ guard does not depend on the pipeline's control plane surviving — any host, any
16
+ cron, can enforce every lease:
17
+
18
+ */10 * * * * cairn compute sweep --apply --region eu-central-1
19
+
20
+ That is a watchdog, not instance-side enforcement, and this docstring is the
21
+ place that says so. True cloud-side enforcement — an EventBridge one-shot
22
+ schedule targeting ``ec2:StopInstances``, or an ``arn:aws:automate:…:ec2:stop``
23
+ alarm action — needs an IAM role created in the owner's account, which is
24
+ deliberately not something this PR does on its own.
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import asyncio
29
+ import json as _json
30
+ from typing import Optional
31
+
32
+ import typer
33
+ from rich.console import Console
34
+ from rich.table import Table
35
+
36
+ from cairn.core.compute_lifecycle import (
37
+ ComputeLifecycleError,
38
+ describe_state,
39
+ load_box,
40
+ sweep_expired,
41
+ )
42
+
43
+ app = typer.Typer(
44
+ help="Governed compute boxes — status + the expired-lease sweep (ADR-0097).",
45
+ no_args_is_help=True,
46
+ )
47
+ _console = Console()
48
+
49
+
50
+ def _run(coro):
51
+ return asyncio.run(coro)
52
+
53
+
54
+ @app.command("status")
55
+ def status(
56
+ connection: Optional[str] = typer.Argument(
57
+ None, help="Name of the `compute.ssh` connection (list them: `cairn connect ls`)."),
58
+ json: bool = typer.Option(False, "--json", help="Emit the raw dict."),
59
+ ) -> None:
60
+ """What state is this box in, and what is it costing while it is up?"""
61
+ if not connection:
62
+ # #2536 — the usage error a missing argument always gave (exit 2), plus where
63
+ # the names come from.
64
+ typer.echo("cairn compute status needs a `compute.ssh` connection name — list "
65
+ "them with `cairn connect ls`", err=True)
66
+ raise typer.Exit(2)
67
+ try:
68
+ row = _run(_status(connection))
69
+ except ComputeLifecycleError as e:
70
+ _console.print(f"[red]✗[/red] {e}")
71
+ raise typer.Exit(2) from None
72
+ if json:
73
+ typer.echo(_json.dumps(row))
74
+ return
75
+ price = f"${row['hourly_usd']:.2f}/hr" if row["hourly_usd"] else "(hourly_usd not declared)"
76
+ _console.print(f"[bold]{row['connection']}[/bold] {row['instance_id'] or '(no instance_id)'}"
77
+ f" region={row['region'] or '(default)'}")
78
+ _console.print(f" state: [cyan]{row['state'] or 'unknown'}[/cyan] {price}"
79
+ f" host={row['host'] or '(none)'}")
80
+
81
+
82
+ async def _status(name: str) -> dict:
83
+ box = await load_box(name)
84
+ state = ""
85
+ if box.instance_id:
86
+ state = await describe_state(box.instance_id, region=box.region)
87
+ return {"connection": box.name, "instance_id": box.instance_id,
88
+ "region": box.region, "host": box.host,
89
+ "hourly_usd": box.hourly_usd, "state": state}
90
+
91
+
92
+ def _aws_setup_hint(e: BaseException) -> Optional[str]:
93
+ """A one-line fix for botocore's "not configured" errors, else None."""
94
+ try:
95
+ from botocore.exceptions import NoCredentialsError, NoRegionError # noqa: PLC0415
96
+ except ImportError:
97
+ return None
98
+ if isinstance(e, NoRegionError):
99
+ return ("no AWS region: pass --region (e.g. --region eu-central-1) or set "
100
+ "AWS_DEFAULT_REGION.")
101
+ if isinstance(e, NoCredentialsError):
102
+ return ("no AWS credentials: set AWS_PROFILE or AWS_ACCESS_KEY_ID/"
103
+ "AWS_SECRET_ACCESS_KEY (the sweep needs ec2:DescribeInstances).")
104
+ return None
105
+
106
+
107
+ @app.command("sweep")
108
+ def sweep(
109
+ region: str = typer.Option("", "--region", help="AWS region (else AWS_DEFAULT_REGION)."),
110
+ apply: bool = typer.Option(
111
+ False, "--apply",
112
+ help="Actually stop the expired instances. Without it the sweep only REPORTS — "
113
+ "the shape a human runs first and a cron runs with --apply."),
114
+ json: bool = typer.Option(False, "--json", help="Emit the rows as JSON."),
115
+ ) -> None:
116
+ """Stop every cairn-managed box whose `cairn:release-after` lease has expired.
117
+
118
+ Scoped by the `cairn:managed` tag AND a readable, past deadline, so it can
119
+ never touch a box cairn did not turn on and never acts on a tag it could not
120
+ parse. Exit code 1 when anything was found expired, so a cron can alert.
121
+ """
122
+ try:
123
+ rows = _run(sweep_expired(region=region, apply=apply))
124
+ except Exception as e: # noqa: BLE001 — only botocore's own setup errors are answered here
125
+ hint = _aws_setup_hint(e)
126
+ if hint is None:
127
+ raise
128
+ _console.print(f"[red]✗[/red] {hint}")
129
+ raise typer.Exit(2) from None
130
+ if json:
131
+ typer.echo(_json.dumps(rows))
132
+ else:
133
+ if not rows:
134
+ _console.print("no cairn-managed instances are running.")
135
+ else:
136
+ t = Table("instance", "state", "release-after", "expired", "acted", "note")
137
+ for r in rows:
138
+ t.add_row(r["instance_id"], r["state"], r["release_after"] or "—",
139
+ "YES" if r["expired"] else "no",
140
+ "stopped" if r["stopped"] else "—", r["note"])
141
+ _console.print(t)
142
+ if not apply and any(r["expired"] for r in rows):
143
+ _console.print("[yellow]report only[/yellow] — re-run with "
144
+ "[cyan]--apply[/cyan] to stop them.")
145
+ if any(r["expired"] for r in rows):
146
+ raise typer.Exit(1)
147
+
148
+
149
+ __all__ = ["app"]
@@ -0,0 +1,50 @@
1
+ """``cairn config`` — operator/workflow configuration tooling (ADR-0068 / ADR-0070).
2
+
3
+ ``cairn config workflow <template-ref>`` prints the COMPOSED config surface for a
4
+ workflow: every tunable knob across its reachable operators, grouped by operator,
5
+ each labelled **governance** (env-owned, read-only for a workflow/run) or
6
+ **operational** (tunable per workflow/run). The surface a workflow author edits
7
+ instead of hunting operator-by-operator in a profile (ADR-0070, #748).
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import json as _json
12
+
13
+ import typer
14
+
15
+ app = typer.Typer(help="Operator / workflow configuration.", no_args_is_help=True)
16
+
17
+
18
+ @app.command("workflow")
19
+ def workflow_cmd(
20
+ template_ref: str = typer.Argument(..., help="Template ref, e.g. training/finetune-remote."),
21
+ as_json: bool = typer.Option(False, "--json", help="Emit the composed surface as JSON."),
22
+ ) -> None:
23
+ """Show the composed config surface for a workflow (its reachable operators'
24
+ knobs, governance vs operational)."""
25
+ from cairn.core.engine.workflow_config import compose_workflow_config
26
+
27
+ composed = compose_workflow_config(template_ref)
28
+ if as_json:
29
+ typer.echo(_json.dumps(composed, indent=2, default=str))
30
+ return
31
+
32
+ if not composed:
33
+ typer.echo(f"No configurable operators reachable from {template_ref!r}.")
34
+ return
35
+
36
+ typer.echo(f"Config surface for workflow: {template_ref}\n")
37
+ for op_name in sorted(composed):
38
+ part = composed[op_name]
39
+ gov, ops = part.get("governance", []), part.get("operational", [])
40
+ typer.echo(f" {op_name}")
41
+ for label, knobs in (("governance (env-owned)", gov), ("operational (tunable)", ops)):
42
+ if not knobs:
43
+ continue
44
+ typer.echo(f" {label}:")
45
+ for k in knobs:
46
+ default = k.get("default")
47
+ dtxt = "" if default is None else f" [default: {default}]"
48
+ title = k.get("title") or k["path"]
49
+ typer.echo(f" - {k['path']} — {title}{dtxt}")
50
+ typer.echo("")