freeharness 0.4.1

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 (375) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +108 -0
  3. package/README.md +134 -0
  4. package/canonical/HARVEST.yaml +858 -0
  5. package/canonical/PROVENANCE.yaml +740 -0
  6. package/canonical/agents/README.md +95 -0
  7. package/canonical/agents/agentic-architect.md +18 -0
  8. package/canonical/agents/database-reviewer.md +41 -0
  9. package/canonical/agents/explorer-ai-engineer-analyst.md +65 -0
  10. package/canonical/agents/pr-reviewer.md +96 -0
  11. package/canonical/agents/python-reviewer.md +55 -0
  12. package/canonical/agents/report-formatter.md +19 -0
  13. package/canonical/agents/security-reviewer.md +53 -0
  14. package/canonical/agents/test-writer.md +34 -0
  15. package/canonical/commands/fh-context.md +37 -0
  16. package/canonical/evals/promptfoo.redteam.yaml +108 -0
  17. package/canonical/hooks/cost-prices.json +14 -0
  18. package/canonical/hooks/freeharness-auto-memory.mjs +158 -0
  19. package/canonical/hooks/freeharness-config-guard.mjs +162 -0
  20. package/canonical/hooks/freeharness-context-monitor.mjs +198 -0
  21. package/canonical/hooks/freeharness-converge.mjs +227 -0
  22. package/canonical/hooks/freeharness-cost-tracker.mjs +1027 -0
  23. package/canonical/hooks/freeharness-memory-guard.mjs +57 -0
  24. package/canonical/hooks/freeharness-output-pruner.mjs +333 -0
  25. package/canonical/hooks/freeharness-precompact.mjs +323 -0
  26. package/canonical/hooks/freeharness-repeat-tool.mjs +208 -0
  27. package/canonical/hooks/freeharness-security-guidance.mjs +164 -0
  28. package/canonical/hooks/freeharness-session-start +583 -0
  29. package/canonical/hooks/hooks.auto-memory.claude-code.json +16 -0
  30. package/canonical/hooks/hooks.claude-code.json +17 -0
  31. package/canonical/hooks/hooks.config-guard.claude-code.json +16 -0
  32. package/canonical/hooks/hooks.context-monitor.claude-code.json +15 -0
  33. package/canonical/hooks/hooks.converge.claude-code.json +15 -0
  34. package/canonical/hooks/hooks.cost-tracker.claude-code.json +37 -0
  35. package/canonical/hooks/hooks.memory-guard.claude-code.json +16 -0
  36. package/canonical/hooks/hooks.output-pruner.claude-code.json +16 -0
  37. package/canonical/hooks/hooks.precompact.claude-code.json +15 -0
  38. package/canonical/hooks/hooks.repeat-tool.claude-code.json +25 -0
  39. package/canonical/hooks/hooks.security-guidance.claude-code.json +16 -0
  40. package/canonical/mcp/servers.json +20 -0
  41. package/canonical/openspec/config.base.yaml +89 -0
  42. package/canonical/openspec/schema.spec-driven.yaml +277 -0
  43. package/canonical/openspec/templates/data-contract.md +36 -0
  44. package/canonical/openspec/templates/design.md +84 -0
  45. package/canonical/openspec/templates/eval-plan.md +33 -0
  46. package/canonical/openspec/templates/follow-ups.md +2 -0
  47. package/canonical/openspec/templates/proposal.md +45 -0
  48. package/canonical/openspec/templates/spec.md +42 -0
  49. package/canonical/openspec/templates/tasks.md +38 -0
  50. package/canonical/profiles/local-llamacpp.LOCAL-MODELS.md +47 -0
  51. package/canonical/profiles/local-llamacpp.json +27 -0
  52. package/canonical/profiles/local-ollama.json +20 -0
  53. package/canonical/profiles/mcp.json +91 -0
  54. package/canonical/rules/CLAUDE.md +78 -0
  55. package/canonical/rules/project-CLAUDE.template.md +62 -0
  56. package/canonical/rules/routing.md +20 -0
  57. package/canonical/rules/safety.md +41 -0
  58. package/canonical/settings/settings.cache-hygiene.claude-code.json +5 -0
  59. package/canonical/skills/agent-evaluation/SKILL.md +102 -0
  60. package/canonical/skills/agent-evaluation/assets/evaluation_report_template.md +206 -0
  61. package/canonical/skills/agent-evaluation/evals/cases.yaml +106 -0
  62. package/canonical/skills/agent-evaluation/references/dataset-preparation.md +351 -0
  63. package/canonical/skills/agent-evaluation/references/scorers-constraints.md +165 -0
  64. package/canonical/skills/agent-evaluation/references/scorers.md +431 -0
  65. package/canonical/skills/agent-evaluation/references/setup-guide.md +252 -0
  66. package/canonical/skills/agent-evaluation/references/tracing-integration.md +164 -0
  67. package/canonical/skills/agent-evaluation/references/troubleshooting.md +514 -0
  68. package/canonical/skills/agent-evaluation/scripts/analyze_results.py +462 -0
  69. package/canonical/skills/agent-evaluation/scripts/create_dataset_template.py +382 -0
  70. package/canonical/skills/agent-evaluation/scripts/list_datasets.py +273 -0
  71. package/canonical/skills/agent-evaluation/scripts/run_evaluation_template.py +309 -0
  72. package/canonical/skills/agent-evaluation/scripts/setup_mlflow.py +353 -0
  73. package/canonical/skills/agent-evaluation/scripts/utils/__init__.py +27 -0
  74. package/canonical/skills/agent-evaluation/scripts/utils/env_validation.py +123 -0
  75. package/canonical/skills/agent-evaluation/scripts/utils/tracing_utils.py +108 -0
  76. package/canonical/skills/agent-evaluation/scripts/validate_agent_tracing.py +148 -0
  77. package/canonical/skills/agent-evaluation/scripts/validate_auth.py +240 -0
  78. package/canonical/skills/agent-evaluation/scripts/validate_environment.py +185 -0
  79. package/canonical/skills/agent-evaluation/scripts/validate_tracing_runtime.py +318 -0
  80. package/canonical/skills/agentic-architecture/SKILL.md +41 -0
  81. package/canonical/skills/agentic-architecture/evals/cases.yaml +94 -0
  82. package/canonical/skills/agentic-architecture/reference/context-engineering.md +75 -0
  83. package/canonical/skills/agentic-architecture/reference/patterns.md +76 -0
  84. package/canonical/skills/agentic-architecture/reference/reliability-observability.md +94 -0
  85. package/canonical/skills/agentic-architecture/reference/review-framework.md +59 -0
  86. package/canonical/skills/code-review/SKILL.md +52 -0
  87. package/canonical/skills/code-review/evals/cases.yaml +197 -0
  88. package/canonical/skills/git-workflow/SKILL.md +41 -0
  89. package/canonical/skills/git-workflow/evals/cases.yaml +92 -0
  90. package/canonical/skills/local-code/SKILL.md +24 -0
  91. package/canonical/skills/local-code/evals/cases.yaml +85 -0
  92. package/canonical/skills/local-code/scripts/query_llama.py +68 -0
  93. package/canonical/skills/report-formatting/SKILL.md +62 -0
  94. package/canonical/skills/report-formatting/evals/cases.yaml +83 -0
  95. package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +135 -0
  96. package/canonical/skills/report-formatting/reference/HELPERS.md +120 -0
  97. package/canonical/skills/report-formatting/reference/PPTX.md +136 -0
  98. package/canonical/skills/report-formatting/reference/RELEASE.md +99 -0
  99. package/canonical/skills/report-formatting/reference/TEMPLATES.md +48 -0
  100. package/canonical/skills/report-formatting/reference/authoring.md +66 -0
  101. package/canonical/skills/report-formatting/scripts/architecture-template.md +271 -0
  102. package/canonical/skills/report-formatting/scripts/assets/claro-logo.png +0 -0
  103. package/canonical/skills/report-formatting/scripts/assets/claro-wordmark.svg +1 -0
  104. package/canonical/skills/report-formatting/scripts/build-architecture.js +57 -0
  105. package/canonical/skills/report-formatting/scripts/build-md-claro.js +224 -0
  106. package/canonical/skills/report-formatting/scripts/build-release.js +51 -0
  107. package/canonical/skills/report-formatting/scripts/check-env.js +58 -0
  108. package/canonical/skills/report-formatting/scripts/docmodel.js +283 -0
  109. package/canonical/skills/report-formatting/scripts/example-build.js +119 -0
  110. package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +195 -0
  111. package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +114 -0
  112. package/canonical/skills/report-formatting/scripts/package.json +17 -0
  113. package/canonical/skills/report-formatting/scripts/pptx/example_build_StatusReport_pptx.py +223 -0
  114. package/canonical/skills/report-formatting/scripts/pptx/example_build_WeeklyStatus_pptx.py +245 -0
  115. package/canonical/skills/report-formatting/scripts/pptx/pptx_office.py +144 -0
  116. package/canonical/skills/report-formatting/scripts/pptx/requirements.txt +7 -0
  117. package/canonical/skills/report-formatting/scripts/pptx/status_report_blocks.py +193 -0
  118. package/canonical/skills/report-formatting/scripts/pptx/theme_claro_pptx.py +473 -0
  119. package/canonical/skills/report-formatting/scripts/release-template.md +80 -0
  120. package/canonical/skills/report-formatting/scripts/render-mermaid.js +105 -0
  121. package/canonical/skills/report-formatting/scripts/theme-claro.js +403 -0
  122. package/canonical/skills/subagent-driven-development/SKILL.md +60 -0
  123. package/canonical/skills/subagent-driven-development/evals/cases.yaml +208 -0
  124. package/canonical/skills/subagent-driven-development/reference/brief.md +91 -0
  125. package/canonical/skills/subagent-driven-development/reference/handoff.md +118 -0
  126. package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +850 -0
  127. package/canonical/skills/systematic-debugging/SKILL.md +44 -0
  128. package/canonical/skills/systematic-debugging/evals/cases.yaml +90 -0
  129. package/canonical/skills/test-driven-development/SKILL.md +42 -0
  130. package/canonical/skills/test-driven-development/evals/cases.yaml +86 -0
  131. package/canonical/skills/test-driven-development/reference/writing-good-tests.md +52 -0
  132. package/canonical/skills/verification-before-completion/SKILL.md +53 -0
  133. package/canonical/skills/verification-before-completion/evals/cases.yaml +107 -0
  134. package/dist/adapters/content/language-lint.d.ts +46 -0
  135. package/dist/adapters/content/language-lint.js +191 -0
  136. package/dist/adapters/harness/claude-code.d.ts +57 -0
  137. package/dist/adapters/harness/claude-code.js +385 -0
  138. package/dist/adapters/harness/index.d.ts +3 -0
  139. package/dist/adapters/harness/index.js +17 -0
  140. package/dist/adapters/harness/opencode.d.ts +7 -0
  141. package/dist/adapters/harness/opencode.js +166 -0
  142. package/dist/adapters/harness/plugin.d.ts +22 -0
  143. package/dist/adapters/harness/plugin.js +257 -0
  144. package/dist/adapters/memory/doctor.d.ts +480 -0
  145. package/dist/adapters/memory/doctor.js +1217 -0
  146. package/dist/adapters/memory/vendored.d.ts +150 -0
  147. package/dist/adapters/memory/vendored.js +487 -0
  148. package/dist/adapters/package/node.d.ts +9 -0
  149. package/dist/adapters/package/node.js +20 -0
  150. package/dist/adapters/prompt/readline.d.ts +19 -0
  151. package/dist/adapters/prompt/readline.js +53 -0
  152. package/dist/adapters/sync/diff.d.ts +43 -0
  153. package/dist/adapters/sync/diff.js +380 -0
  154. package/dist/cli/cleanup.d.ts +86 -0
  155. package/dist/cli/cleanup.js +382 -0
  156. package/dist/cli/cost.d.ts +304 -0
  157. package/dist/cli/cost.js +501 -0
  158. package/dist/cli/doctor.d.ts +205 -0
  159. package/dist/cli/doctor.js +654 -0
  160. package/dist/cli/executor.d.ts +5 -0
  161. package/dist/cli/executor.js +48 -0
  162. package/dist/cli/plugin-validate.d.ts +37 -0
  163. package/dist/cli/plugin-validate.js +256 -0
  164. package/dist/cli/prefix.d.ts +68 -0
  165. package/dist/cli/prefix.js +218 -0
  166. package/dist/cli/profile.d.ts +170 -0
  167. package/dist/cli/profile.js +285 -0
  168. package/dist/cli/runner.d.ts +10 -0
  169. package/dist/cli/runner.js +27 -0
  170. package/dist/cli/uninstall.d.ts +65 -0
  171. package/dist/cli/uninstall.js +147 -0
  172. package/dist/index.d.ts +8 -0
  173. package/dist/index.js +989 -0
  174. package/dist/infra/dogfood.d.ts +31 -0
  175. package/dist/infra/dogfood.js +51 -0
  176. package/dist/infra/fsutil.d.ts +40 -0
  177. package/dist/infra/fsutil.js +143 -0
  178. package/dist/infra/manifest.d.ts +76 -0
  179. package/dist/infra/manifest.js +92 -0
  180. package/dist/infra/paths.d.ts +19 -0
  181. package/dist/infra/paths.js +74 -0
  182. package/dist/infra/routing.d.ts +4 -0
  183. package/dist/infra/routing.js +7 -0
  184. package/node_modules/@freeharness/core/dist/context.d.ts +30 -0
  185. package/node_modules/@freeharness/core/dist/context.js +1 -0
  186. package/node_modules/@freeharness/core/dist/index.d.ts +5 -0
  187. package/node_modules/@freeharness/core/dist/index.js +6 -0
  188. package/node_modules/@freeharness/core/dist/planner.d.ts +13 -0
  189. package/node_modules/@freeharness/core/dist/planner.js +18 -0
  190. package/node_modules/@freeharness/core/dist/ports.d.ts +90 -0
  191. package/node_modules/@freeharness/core/dist/ports.js +1 -0
  192. package/node_modules/@freeharness/core/dist/registry.d.ts +41 -0
  193. package/node_modules/@freeharness/core/dist/registry.js +124 -0
  194. package/node_modules/@freeharness/core/dist/tiers.d.ts +30 -0
  195. package/node_modules/@freeharness/core/dist/tiers.js +99 -0
  196. package/node_modules/@freeharness/core/package.json +34 -0
  197. package/node_modules/@freeharness/sdd/PROVENANCE.yaml +175 -0
  198. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.d.ts +2 -0
  199. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +166 -0
  200. package/node_modules/@freeharness/sdd/dist/src/index.d.ts +14 -0
  201. package/node_modules/@freeharness/sdd/dist/src/index.js +11 -0
  202. package/node_modules/@freeharness/sdd/dist/src/init.d.ts +39 -0
  203. package/node_modules/@freeharness/sdd/dist/src/init.js +190 -0
  204. package/node_modules/@freeharness/sdd/dist/src/root-resolver.d.ts +8 -0
  205. package/node_modules/@freeharness/sdd/dist/src/root-resolver.js +32 -0
  206. package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +81 -0
  207. package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +483 -0
  208. package/node_modules/@freeharness/sdd/dist/src/shim/context.d.ts +4 -0
  209. package/node_modules/@freeharness/sdd/dist/src/shim/context.js +48 -0
  210. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +57 -0
  211. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +279 -0
  212. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +67 -0
  213. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +460 -0
  214. package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +5 -0
  215. package/node_modules/@freeharness/sdd/dist/src/shim/list.js +95 -0
  216. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.d.ts +6 -0
  217. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +150 -0
  218. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.d.ts +4 -0
  219. package/node_modules/@freeharness/sdd/dist/src/shim/schemas.js +23 -0
  220. package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +56 -0
  221. package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +140 -0
  222. package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +8 -0
  223. package/node_modules/@freeharness/sdd/dist/src/shim/status.js +85 -0
  224. package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +6 -0
  225. package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +229 -0
  226. package/node_modules/@freeharness/sdd/dist/src/validate-change.d.ts +40 -0
  227. package/node_modules/@freeharness/sdd/dist/src/validate-change.js +114 -0
  228. package/node_modules/@freeharness/sdd/dist/src/validate.d.ts +24 -0
  229. package/node_modules/@freeharness/sdd/dist/src/validate.js +72 -0
  230. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.d.ts +130 -0
  231. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +981 -0
  232. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.d.ts +46 -0
  233. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-metadata.js +128 -0
  234. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +26 -0
  235. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +32 -0
  236. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.d.ts +50 -0
  237. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/file-system.js +394 -0
  238. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.d.ts +15 -0
  239. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/global-config.js +49 -0
  240. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.d.ts +71 -0
  241. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/graph.js +164 -0
  242. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +11 -0
  243. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +21 -0
  244. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.d.ts +102 -0
  245. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/instruction-loader.js +230 -0
  246. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +18 -0
  247. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +138 -0
  248. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.d.ts +82 -0
  249. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/resolver.js +333 -0
  250. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.d.ts +12 -0
  251. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/schema.js +110 -0
  252. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.d.ts +11 -0
  253. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/state.js +32 -0
  254. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.d.ts +33 -0
  255. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +149 -0
  256. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.d.ts +39 -0
  257. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +49 -0
  258. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.d.ts +12 -0
  259. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/claude.js +31 -0
  260. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.d.ts +10 -0
  261. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/index.js +10 -0
  262. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.d.ts +12 -0
  263. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/adapters/opencode.js +26 -0
  264. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.d.ts +28 -0
  265. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/generator.js +41 -0
  266. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.d.ts +23 -0
  267. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/index.js +25 -0
  268. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.d.ts +72 -0
  269. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/invocation.js +76 -0
  270. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.d.ts +39 -0
  271. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/registry.js +53 -0
  272. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.d.ts +62 -0
  273. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/types.js +7 -0
  274. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.d.ts +35 -0
  275. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-generation/yaml.js +47 -0
  276. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.d.ts +33 -0
  277. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/command-references.js +55 -0
  278. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.d.ts +11 -0
  279. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/allowed-tools.js +11 -0
  280. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.d.ts +48 -0
  281. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/shared/skill-generation.js +99 -0
  282. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.d.ts +19 -0
  283. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/skill-templates.js +18 -0
  284. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.d.ts +18 -0
  285. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/types.js +4 -0
  286. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.d.ts +19 -0
  287. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +207 -0
  288. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.d.ts +12 -0
  289. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +409 -0
  290. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.d.ts +9 -0
  291. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/bulk-archive-change.js +673 -0
  292. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.d.ts +9 -0
  293. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/continue-change.js +230 -0
  294. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.d.ts +12 -0
  295. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +550 -0
  296. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.d.ts +8 -0
  297. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/feedback.js +107 -0
  298. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.d.ts +12 -0
  299. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/ff-change.js +228 -0
  300. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.d.ts +9 -0
  301. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/new-change.js +147 -0
  302. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.d.ts +9 -0
  303. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/onboard.js +571 -0
  304. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.d.ts +12 -0
  305. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +322 -0
  306. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.d.ts +7 -0
  307. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/store-selection.js +7 -0
  308. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.d.ts +9 -0
  309. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +518 -0
  310. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.d.ts +9 -0
  311. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +176 -0
  312. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.d.ts +9 -0
  313. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/verify-change.js +344 -0
  314. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +39 -0
  315. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +54 -0
  316. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.d.ts +35 -0
  317. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/delta-resolution.js +171 -0
  318. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +27 -0
  319. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +210 -0
  320. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.d.ts +14 -0
  321. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/code-fence.js +48 -0
  322. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.d.ts +22 -0
  323. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +186 -0
  324. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +65 -0
  325. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +409 -0
  326. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +55 -0
  327. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +98 -0
  328. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.d.ts +8 -0
  329. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +77 -0
  330. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.d.ts +44 -0
  331. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +116 -0
  332. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.d.ts +12 -0
  333. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/base.schema.js +17 -0
  334. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.d.ts +72 -0
  335. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/change.schema.js +30 -0
  336. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.d.ts +3 -0
  337. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/index.js +3 -0
  338. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.d.ts +17 -0
  339. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/schemas/spec.schema.js +14 -0
  340. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +39 -0
  341. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +114 -0
  342. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +45 -0
  343. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +105 -0
  344. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.d.ts +15 -0
  345. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-numbering.js +56 -0
  346. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.d.ts +17 -0
  347. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/types.js +1 -0
  348. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +94 -0
  349. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +756 -0
  350. package/node_modules/@freeharness/sdd/package.json +57 -0
  351. package/node_modules/@freeharness/sdd/vendor/openspec/LICENSE.upstream +22 -0
  352. package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +232 -0
  353. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/README.md +19 -0
  354. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +187 -0
  355. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +181 -0
  356. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +338 -0
  357. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +117 -0
  358. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +342 -0
  359. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +116 -0
  360. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +76 -0
  361. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +560 -0
  362. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +162 -0
  363. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +261 -0
  364. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +90 -0
  365. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +174 -0
  366. package/package.json +70 -0
  367. package/provenance/canonical.PROVENANCE.yaml +740 -0
  368. package/provenance/claude-mem.LICENSE.upstream +202 -0
  369. package/provenance/memory.PROVENANCE.yaml +399 -0
  370. package/provenance/sdd.PROVENANCE.yaml +175 -0
  371. package/vendor-licenses/caveman.LICENSE +27 -0
  372. package/vendor-licenses/deepseek-harness.LICENSE +21 -0
  373. package/vendor-licenses/ecc.LICENSE +21 -0
  374. package/vendor-licenses/pi.LICENSE +21 -0
  375. package/vendor-licenses/superpowers.LICENSE +21 -0
@@ -0,0 +1,309 @@
1
+ """
2
+ Generate a template script for running agent evaluation.
3
+
4
+ This script creates a customized Python script that executes the agent
5
+ on an evaluation dataset and collects trace IDs for scoring.
6
+
7
+ Usage:
8
+ python run_evaluation_template.py # Auto-detect everything
9
+ python run_evaluation_template.py --module my_agent.agent # Specify module
10
+ python run_evaluation_template.py --entry-point run_agent # Specify entry point
11
+ python run_evaluation_template.py --dataset-name my-dataset # Specify dataset
12
+ python run_evaluation_template.py --module my_agent --entry-point run_agent --dataset-name my-dataset
13
+ """
14
+
15
+ import argparse
16
+ import os
17
+ import subprocess
18
+ import sys
19
+
20
+ from utils import validate_env_vars
21
+
22
+
23
+ def list_datasets() -> list[str]:
24
+ """List available datasets in the experiment."""
25
+ try:
26
+ code = """
27
+ import os
28
+ from mlflow import MlflowClient
29
+
30
+ client = MlflowClient()
31
+ experiment_id = os.getenv("MLFLOW_EXPERIMENT_ID")
32
+
33
+ datasets = client.search_datasets(experiment_ids=[experiment_id])
34
+ for dataset in datasets:
35
+ print(dataset.name)
36
+ """
37
+ result = subprocess.run(["python", "-c", code], capture_output=True, text=True, check=True)
38
+ return [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]
39
+ except Exception:
40
+ return []
41
+
42
+
43
+ def generate_evaluation_code(
44
+ tracking_uri: str, experiment_id: str, dataset_name: str, agent_module: str, entry_point: str
45
+ ) -> str:
46
+ """Generate Python code for running evaluation."""
47
+
48
+ return f'''#!/usr/bin/env python3
49
+ """
50
+ Run agent on evaluation dataset and collect traces.
51
+
52
+ Generated by run_evaluation_template.py
53
+ """
54
+
55
+ import os
56
+ import sys
57
+ import mlflow
58
+ from mlflow.genai.datasets import get_dataset
59
+
60
+ # Set environment variables
61
+ os.environ["MLFLOW_TRACKING_URI"] = "{tracking_uri}"
62
+ os.environ["MLFLOW_EXPERIMENT_ID"] = "{experiment_id}"
63
+
64
+ # Import agent
65
+ from {agent_module} import {entry_point}
66
+
67
+ # Configuration
68
+ DATASET_NAME = "{dataset_name}"
69
+
70
+ print("=" * 60)
71
+ print("Running Agent on Evaluation Dataset")
72
+ print("=" * 60)
73
+ print()
74
+
75
+ # Load dataset
76
+ # IMPORTANT: Do not modify this section. It uses the official MLflow API.
77
+ # Spark or databricks-sdk approaches are NOT recommended.
78
+ print("Loading evaluation dataset...")
79
+ try:
80
+ dataset = get_dataset(DATASET_NAME)
81
+ df = dataset.to_df()
82
+ print(f" Dataset: {{DATASET_NAME}}")
83
+ print(f" Total queries: {{len(df)}}")
84
+ print()
85
+ except Exception as e:
86
+ print(f"✗ Failed to load dataset: {{e}}")
87
+ print()
88
+ print("Common issues:")
89
+ print(" 1. Dataset name incorrect - check with: mlflow datasets list")
90
+ print(" 2. Not authenticated - run: databricks auth login")
91
+ print(" 3. Wrong experiment - verify MLFLOW_EXPERIMENT_ID")
92
+ sys.exit(1)
93
+
94
+ # TODO: Configure your agent's LLM provider or other dependencies here
95
+ # Example:
96
+ # from your_agent.llm import LLMConfig, LLMProvider
97
+ # llm_config = LLMConfig(model="gpt-4", temperature=0.0)
98
+ # llm_provider = LLMProvider(config=llm_config)
99
+
100
+ print("⚠ IMPORTANT: Configure your agent's dependencies above before running!")
101
+ print(" Update the TODO section with your agent's setup code")
102
+ print()
103
+
104
+ # Run agent on each query
105
+ trace_ids = []
106
+ successful = 0
107
+ failed = 0
108
+
109
+ print("Running agent on dataset queries...")
110
+ print()
111
+
112
+ for index, row in df.iterrows():
113
+ inputs = row['inputs']
114
+
115
+ # Extract query from inputs
116
+ query = inputs.get('query', inputs.get('question', str(inputs)))
117
+
118
+ print(f"[{{index + 1}}/{{len(df)}}] Query: {{query[:80]}}{{'...' if len(query) > 80 else ''}}")
119
+
120
+ try:
121
+ # TODO: Adjust the function call to match your agent's signature
122
+ # Examples:
123
+ # response = {entry_point}(query, llm_provider)
124
+ # response = {entry_point}(query)
125
+ # response = {entry_point}(**inputs)
126
+
127
+ response = {entry_point}(query) # <-- UPDATE THIS LINE
128
+
129
+ # Capture trace ID
130
+ trace_id = mlflow.get_last_active_trace_id()
131
+
132
+ if trace_id:
133
+ trace_ids.append(trace_id)
134
+ successful += 1
135
+ print(f" ✓ Success (trace: {{trace_id}})")
136
+ else:
137
+ print(f" ✗ No trace captured")
138
+ failed += 1
139
+
140
+ except Exception as e:
141
+ print(f" ✗ Error: {{str(e)[:100]}}")
142
+ failed += 1
143
+
144
+ print()
145
+
146
+ # Summary
147
+ print("=" * 60)
148
+ print("Execution Summary")
149
+ print("=" * 60)
150
+ print(f" Total queries: {{len(df)}}")
151
+ print(f" Successful: {{successful}}")
152
+ print(f" Failed: {{failed}}")
153
+ print(f" Traces collected: {{len(trace_ids)}}")
154
+ print()
155
+
156
+ # Save trace IDs
157
+ if trace_ids:
158
+ traces_file = "evaluation_trace_ids.txt"
159
+ with open(traces_file, 'w') as f:
160
+ f.write(','.join(trace_ids))
161
+
162
+ print(f"Trace IDs saved to: {{traces_file}}")
163
+ print()
164
+
165
+ # Print evaluation command
166
+ print("=" * 60)
167
+ print("Next Step: Evaluate Traces with Scorers")
168
+ print("=" * 60)
169
+ print()
170
+ print("Run the following command to evaluate all traces:")
171
+ print()
172
+ print(f" mlflow traces evaluate \\\\")
173
+ print(f" --trace-ids {{','.join(trace_ids[:3])}}{{',...' if len(trace_ids) > 3 else ''}} \\\\")
174
+ print(f" --scorers <scorer1>,<scorer2>,... \\\\")
175
+ print(f" --output json")
176
+ print()
177
+ print("Replace <scorer1>,<scorer2>,... with your registered scorers")
178
+ print(" Example: RelevanceToQuery,Completeness,ToolUsageAppropriate")
179
+ print()
180
+ else:
181
+ print("✗ No traces were collected. Please check for errors above.")
182
+ print()
183
+
184
+ print("=" * 60)
185
+ '''
186
+
187
+
188
+ def main():
189
+ """Main workflow."""
190
+ # Parse command-line arguments
191
+ parser = argparse.ArgumentParser(
192
+ description="Generate evaluation execution template script",
193
+ formatter_class=argparse.RawDescriptionHelpFormatter,
194
+ )
195
+ parser.add_argument("--module", help="Agent module name (e.g., 'my_agent.agent')")
196
+ parser.add_argument("--entry-point", help="Entry point function name (e.g., 'run_agent')")
197
+ parser.add_argument("--dataset-name", help="Dataset name to use")
198
+ parser.add_argument("--output", default="run_agent_evaluation.py", help="Output file name")
199
+ args = parser.parse_args()
200
+
201
+ print("=" * 60)
202
+ print("MLflow Evaluation Execution Template Generator")
203
+ print("=" * 60)
204
+ print()
205
+
206
+ # Check environment
207
+ errors = validate_env_vars()
208
+ if errors:
209
+ print("✗ Environment validation failed:")
210
+ for error in errors:
211
+ print(f" - {error}")
212
+ print("\nRun scripts/setup_mlflow.py first")
213
+ sys.exit(1)
214
+
215
+ tracking_uri = os.getenv("MLFLOW_TRACKING_URI")
216
+ experiment_id = os.getenv("MLFLOW_EXPERIMENT_ID")
217
+
218
+ print(f"Tracking URI: {tracking_uri}")
219
+ print(f"Experiment ID: {experiment_id}")
220
+ print()
221
+
222
+ # Get agent module (must be specified manually)
223
+ print("Agent module configuration...")
224
+ agent_module = args.module
225
+ if not agent_module:
226
+ print(" ✗ Agent module not specified")
227
+ print(" Use --module to specify your agent module")
228
+ print(" Example: --module my_agent.agent")
229
+ print("\n To find your agent module:")
230
+ print(" grep -r 'def.*agent' . --include='*.py'")
231
+ sys.exit(1)
232
+ else:
233
+ print(f" ✓ Using specified: {agent_module}")
234
+
235
+ # Get entry point (must be specified manually)
236
+ print("\nEntry point configuration...")
237
+ entry_point = args.entry_point
238
+ if not entry_point:
239
+ print(" ✗ Entry point not specified")
240
+ print(" Use --entry-point to specify your agent's main function")
241
+ print(" Example: --entry-point run_agent")
242
+ print("\n To find entry points with @mlflow.trace:")
243
+ print(" grep -r '@mlflow.trace' . --include='*.py'")
244
+ sys.exit(1)
245
+ else:
246
+ print(f" ✓ Using specified: {entry_point}")
247
+
248
+ # Get dataset name
249
+ print("\nFetching available datasets...")
250
+ dataset_name = args.dataset_name
251
+ if not dataset_name:
252
+ datasets = list_datasets()
253
+
254
+ if datasets:
255
+ print(f"\n✓ Found {len(datasets)} dataset(s):")
256
+ for i, name in enumerate(datasets, 1):
257
+ print(f" {i}. {name}")
258
+
259
+ # Auto-select first dataset
260
+ dataset_name = datasets[0]
261
+ print(f"\n✓ Auto-selected: {dataset_name}")
262
+ print(" (Use --dataset-name to specify a different dataset)")
263
+ else:
264
+ print(" ✗ No datasets found")
265
+ print(" Please create a dataset first or specify with --dataset-name")
266
+ sys.exit(1)
267
+ else:
268
+ print(f" ✓ Using specified: {dataset_name}")
269
+
270
+ # Generate code
271
+ print("\n" + "=" * 60)
272
+ print("Generating Evaluation Execution Script")
273
+ print("=" * 60)
274
+
275
+ code = generate_evaluation_code(
276
+ tracking_uri, experiment_id, dataset_name, agent_module, entry_point
277
+ )
278
+
279
+ # Write to file
280
+ output_file = args.output
281
+ with open(output_file, "w") as f:
282
+ f.write(code)
283
+
284
+ print(f"\n✓ Script generated: {output_file}")
285
+ print()
286
+
287
+ # Make executable
288
+ try:
289
+ os.chmod(output_file, 0o755)
290
+ print(f"✓ Made executable: chmod +x {output_file}")
291
+ except Exception:
292
+ pass
293
+
294
+ print()
295
+ print("=" * 60)
296
+ print("Next Steps")
297
+ print("=" * 60)
298
+ print()
299
+ print(f"1. Review the generated script: {output_file}")
300
+ print("2. Update the TODO sections with your agent's setup code")
301
+ print("3. Update the agent call to match your signature")
302
+ print(f"4. Execute it: python {output_file}")
303
+ print("5. Use the trace IDs to run evaluation with scorers")
304
+ print()
305
+ print("=" * 60)
306
+
307
+
308
+ if __name__ == "__main__":
309
+ main()
@@ -0,0 +1,353 @@
1
+ """
2
+ MLflow environment setup script with auto-detection and convenience features.
3
+
4
+ This script configures MLFLOW_TRACKING_URI and MLFLOW_EXPERIMENT_ID
5
+ for agent evaluation using auto-detection with optional overrides.
6
+
7
+ Features:
8
+ - Auto-detects Databricks profiles or local SQLite
9
+ - Search experiments by name (post-processes `mlflow experiments list` output)
10
+ - Single command instead of multiple CLI calls
11
+ - Creates experiments if they don't exist
12
+
13
+ Note: Uses MLflow CLI commands underneath (`mlflow experiments list`, `mlflow experiments create`).
14
+ For direct CLI usage, see MLflow documentation.
15
+ """
16
+
17
+ import argparse
18
+ import os
19
+ import subprocess
20
+ import sys
21
+ from pathlib import Path
22
+
23
+
24
+ def parse_arguments():
25
+ """Parse command-line arguments."""
26
+ parser = argparse.ArgumentParser(
27
+ description="Configure MLflow for agent evaluation with auto-detection"
28
+ )
29
+ parser.add_argument(
30
+ "--tracking-uri",
31
+ help="MLflow tracking URI (default: auto-detect from env/Databricks/local)",
32
+ )
33
+ parser.add_argument("--experiment-id", help="Experiment ID to use (default: from env or search)")
34
+ parser.add_argument("--experiment-name", help="Experiment name (for search or creation)")
35
+ parser.add_argument(
36
+ "--create", action="store_true", help="Create new experiment with --experiment-name"
37
+ )
38
+ return parser.parse_args()
39
+
40
+
41
+ def check_mlflow_installed() -> bool:
42
+ """Check if MLflow >=3.6.0 is installed."""
43
+ try:
44
+ result = subprocess.run(["mlflow", "--version"], capture_output=True, text=True, check=True)
45
+ version = result.stdout.strip().split()[-1]
46
+ print(f"✓ MLflow {version} is installed")
47
+ return True
48
+ except (subprocess.CalledProcessError, FileNotFoundError):
49
+ print("✗ MLflow is not installed")
50
+ print(" Install with: uv pip install mlflow")
51
+ return False
52
+
53
+
54
+ def detect_databricks_profiles() -> list[str]:
55
+ """Detect available Databricks profiles."""
56
+ try:
57
+ result = subprocess.run(
58
+ ["databricks", "auth", "profiles"], capture_output=True, text=True, check=True
59
+ )
60
+ lines = result.stdout.strip().split("\n")
61
+ # Skip first line (header: "Name Host Valid")
62
+ # and filter empty lines
63
+ return [line.strip() for line in lines[1:] if line.strip()]
64
+ except (subprocess.CalledProcessError, FileNotFoundError):
65
+ return []
66
+
67
+
68
+ def check_databricks_auth(profile: str) -> bool:
69
+ """Check if a Databricks profile is authenticated."""
70
+ try:
71
+ # Try a simple API call to check auth
72
+ result = subprocess.run(
73
+ ["databricks", "auth", "env", "-p", profile], capture_output=True, text=True, check=True
74
+ )
75
+ return "DATABRICKS_TOKEN" in result.stdout or "DATABRICKS_HOST" in result.stdout
76
+ except subprocess.CalledProcessError:
77
+ return False
78
+
79
+
80
+ def start_local_mlflow_server(port: int = 5050) -> bool:
81
+ """Start local MLflow server in the background."""
82
+ print(f"\nStarting local MLflow server on port {port}...")
83
+
84
+ try:
85
+ # Create mlruns directory if it doesn't exist
86
+ Path("./mlruns").mkdir(exist_ok=True)
87
+
88
+ # Start server in background
89
+ cmd = [
90
+ "mlflow",
91
+ "server",
92
+ "--port",
93
+ str(port),
94
+ "--backend-store-uri",
95
+ "sqlite:///mlflow.db",
96
+ "--default-artifact-root",
97
+ "./mlruns",
98
+ ]
99
+
100
+ print(f" Command: {' '.join(cmd)}")
101
+ print(" Running in background...")
102
+
103
+ # Note: In production, you might want to use nohup or subprocess.Popen with proper detachment
104
+ print("\n To start the server manually, run:")
105
+ print(f" {' '.join(cmd)} &")
106
+ print(f"\n Server will be available at: http://127.0.0.1:{port}")
107
+
108
+ return True
109
+ except Exception as e:
110
+ print(f"✗ Error starting server: {e}")
111
+ return False
112
+
113
+
114
+ def auto_detect_tracking_uri() -> str:
115
+ """Auto-detect best tracking URI.
116
+
117
+ Priority:
118
+ 1. Existing MLFLOW_TRACKING_URI environment variable
119
+ 2. DEFAULT Databricks profile
120
+ 3. First available Databricks profile
121
+ 4. Local SQLite (sqlite:///mlflow.db)
122
+ """
123
+ # Priority 1: Use existing MLFLOW_TRACKING_URI if set
124
+ existing = os.getenv("MLFLOW_TRACKING_URI")
125
+ if existing:
126
+ print(f"✓ Using existing MLFLOW_TRACKING_URI: {existing}")
127
+ return existing
128
+
129
+ # Priority 2: Try DEFAULT Databricks profile
130
+ profiles = detect_databricks_profiles()
131
+ if profiles:
132
+ # Look for DEFAULT profile
133
+ if "DEFAULT" in profiles:
134
+ uri = "databricks://DEFAULT"
135
+ print(f"✓ Auto-detected Databricks profile: {uri}")
136
+ return uri
137
+
138
+ # Fallback to first profile
139
+ first_profile = profiles[0]
140
+ uri = f"databricks://{first_profile}"
141
+ print(f"✓ Auto-detected Databricks profile: {uri}")
142
+ return uri
143
+
144
+ # Priority 3: Fallback to local SQLite
145
+ uri = "sqlite:///mlflow.db"
146
+ print(f"✓ Auto-detected tracking URI: {uri}")
147
+ print(" (No Databricks profiles found, using local SQLite)")
148
+ return uri
149
+
150
+
151
+ def configure_tracking_uri(args_uri: str | None = None) -> str:
152
+ """Configure MLFLOW_TRACKING_URI with auto-detection.
153
+
154
+ Args:
155
+ args_uri: Tracking URI from CLI arguments (optional)
156
+
157
+ Returns:
158
+ Tracking URI to use
159
+ """
160
+ print("\n" + "=" * 60)
161
+ print("Step 1: Configure MLFLOW_TRACKING_URI")
162
+ print("=" * 60)
163
+ print()
164
+
165
+ # If URI provided via CLI, use it
166
+ if args_uri:
167
+ print(f"✓ Using specified tracking URI: {args_uri}")
168
+ return args_uri
169
+
170
+ # Otherwise auto-detect
171
+ return auto_detect_tracking_uri()
172
+
173
+
174
+ def list_experiments(tracking_uri: str) -> list[dict]:
175
+ """List available experiments."""
176
+ try:
177
+ env = os.environ.copy()
178
+ env["MLFLOW_TRACKING_URI"] = tracking_uri
179
+
180
+ result = subprocess.run(
181
+ ["mlflow", "experiments", "list"], capture_output=True, text=True, check=True, env=env
182
+ )
183
+
184
+ # Parse output (simplified)
185
+ lines = result.stdout.strip().split("\n")
186
+ experiments = []
187
+
188
+ for line in lines[2:]: # Skip header
189
+ if line.strip():
190
+ parts = [p.strip() for p in line.split("|") if p.strip()]
191
+ if len(parts) >= 2:
192
+ exp_id = parts[0]
193
+ name = parts[1]
194
+ experiments.append({"id": exp_id, "name": name})
195
+
196
+ return experiments
197
+ except Exception as e:
198
+ print(f"✗ Error listing experiments: {e}")
199
+ return []
200
+
201
+
202
+ def create_experiment(tracking_uri: str, name: str) -> str | None:
203
+ """Create a new experiment."""
204
+ try:
205
+ env = os.environ.copy()
206
+ env["MLFLOW_TRACKING_URI"] = tracking_uri
207
+
208
+ result = subprocess.run(
209
+ ["mlflow", "experiments", "create", "-n", name],
210
+ capture_output=True,
211
+ text=True,
212
+ check=True,
213
+ env=env,
214
+ )
215
+
216
+ # Extract experiment ID from output
217
+ for line in result.stdout.split("\n"):
218
+ if "Experiment" in line and "created" in line:
219
+ # Try to extract ID
220
+ words = line.split()
221
+ for i, word in enumerate(words):
222
+ if word.lower() == "id" and i + 1 < len(words):
223
+ return words[i + 1].strip()
224
+
225
+ # If can't parse, return None (but experiment was created)
226
+ return None
227
+ except subprocess.CalledProcessError as e:
228
+ print(f"✗ Error creating experiment: {e.stderr}")
229
+ return None
230
+
231
+
232
+ def configure_experiment_id(
233
+ tracking_uri: str,
234
+ args_exp_id: str | None = None,
235
+ args_exp_name: str | None = None,
236
+ create_new: bool = False,
237
+ ) -> str:
238
+ """Configure MLFLOW_EXPERIMENT_ID with auto-detection.
239
+
240
+ Args:
241
+ tracking_uri: MLflow tracking URI
242
+ args_exp_id: Experiment ID from CLI arguments (optional)
243
+ args_exp_name: Experiment name from CLI arguments (optional)
244
+ create_new: Create new experiment with args_exp_name if not found
245
+
246
+ Returns:
247
+ Experiment ID to use
248
+ """
249
+ print("\n" + "=" * 60)
250
+ print("Step 2: Configure MLFLOW_EXPERIMENT_ID")
251
+ print("=" * 60)
252
+ print()
253
+
254
+ # Priority 1: Use experiment ID from CLI args
255
+ if args_exp_id:
256
+ print(f"✓ Using specified experiment ID: {args_exp_id}")
257
+ return args_exp_id
258
+
259
+ # Priority 2: Use existing MLFLOW_EXPERIMENT_ID from environment
260
+ existing = os.getenv("MLFLOW_EXPERIMENT_ID")
261
+ if existing and not args_exp_name:
262
+ # Only use existing if not explicitly searching for a different experiment
263
+ print(f"✓ Using existing MLFLOW_EXPERIMENT_ID: {existing}")
264
+ return existing
265
+
266
+ # Priority 3: Create new experiment if --create and --experiment-name provided
267
+ if create_new and args_exp_name:
268
+ print(f"✓ Creating experiment: {args_exp_name}")
269
+ exp_id = create_experiment(tracking_uri, args_exp_name)
270
+ if exp_id:
271
+ print(f"✓ Experiment created with ID: {exp_id}")
272
+ return exp_id
273
+ else:
274
+ # Try to find it by name (might have been created but ID not parsed)
275
+ experiments = list_experiments(tracking_uri)
276
+ for exp in experiments:
277
+ if exp["name"] == args_exp_name:
278
+ print(f"✓ Found experiment ID: {exp['id']}")
279
+ return exp["id"]
280
+ print(f"✗ Failed to create or find experiment '{args_exp_name}'")
281
+ sys.exit(1)
282
+
283
+ # Priority 4: Search for experiment by name if provided
284
+ if args_exp_name:
285
+ print(f"✓ Searching for experiment: {args_exp_name}")
286
+ experiments = list_experiments(tracking_uri)
287
+ for exp in experiments:
288
+ if exp["name"] == args_exp_name:
289
+ print(f"✓ Found experiment ID: {exp['id']}")
290
+ return exp["id"]
291
+
292
+ # Not found - fail with clear message
293
+ print(f"✗ Experiment '{args_exp_name}' not found")
294
+ print(" Use --create flag to create it: --experiment-name '{args_exp_name}' --create")
295
+ sys.exit(1)
296
+
297
+ # Priority 5: Auto-select first available experiment
298
+ print("Auto-detecting experiment...")
299
+ experiments = list_experiments(tracking_uri)
300
+
301
+ if experiments:
302
+ # Use first experiment
303
+ exp = experiments[0]
304
+ print(f"✓ Auto-selected experiment: {exp['name']} (ID: {exp['id']})")
305
+ if len(experiments) > 1:
306
+ print(f" ({len(experiments) - 1} other experiment(s) available)")
307
+ return exp["id"]
308
+
309
+ # No experiments found - fail with clear message
310
+ print("✗ No experiments found")
311
+ print(" Create one with: --experiment-name <name> --create")
312
+ sys.exit(1)
313
+
314
+
315
+ def main():
316
+ """Main setup flow with auto-detection."""
317
+ # Parse command-line arguments
318
+ args = parse_arguments()
319
+
320
+ print("=" * 60)
321
+ print("MLflow Environment Setup for Agent Evaluation")
322
+ print("=" * 60)
323
+
324
+ # Check MLflow installation
325
+ if not check_mlflow_installed():
326
+ sys.exit(1)
327
+
328
+ print()
329
+
330
+ # Configure tracking URI (auto-detects if not provided)
331
+ tracking_uri = configure_tracking_uri(args.tracking_uri)
332
+
333
+ # Configure experiment ID (auto-detects if not provided)
334
+ experiment_id = configure_experiment_id(
335
+ tracking_uri, args.experiment_id, args.experiment_name, args.create
336
+ )
337
+
338
+ # Summary
339
+ print("\n" + "=" * 60)
340
+ print("Setup Complete!")
341
+ print("=" * 60)
342
+ print()
343
+ print("Export these environment variables:")
344
+ print()
345
+ print(f'export MLFLOW_TRACKING_URI="{tracking_uri}"')
346
+ print(f'export MLFLOW_EXPERIMENT_ID="{experiment_id}"')
347
+ print()
348
+ print("Or add them to your shell configuration (~/.bashrc, ~/.zshrc, etc.)")
349
+ print("=" * 60)
350
+
351
+
352
+ if __name__ == "__main__":
353
+ main()
@@ -0,0 +1,27 @@
1
+ """Shared utilities for agent evaluation scripts."""
2
+
3
+ from .env_validation import (
4
+ check_databricks_config,
5
+ get_env_vars,
6
+ test_mlflow_connection,
7
+ validate_env_vars,
8
+ validate_mlflow_version,
9
+ )
10
+ from .tracing_utils import (
11
+ check_import_order,
12
+ check_session_id_capture,
13
+ verify_mlflow_imports,
14
+ )
15
+
16
+ __all__ = [
17
+ # env_validation
18
+ "check_databricks_config",
19
+ "get_env_vars",
20
+ "test_mlflow_connection",
21
+ "validate_env_vars",
22
+ "validate_mlflow_version",
23
+ # tracing_utils (for validation scripts)
24
+ "check_import_order",
25
+ "check_session_id_capture",
26
+ "verify_mlflow_imports",
27
+ ]