selftune 0.2.22 → 0.2.24

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 (270) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +95 -15
  3. package/apps/local-dashboard/dist/assets/index-DgY2KGP-.css +1 -0
  4. package/apps/local-dashboard/dist/assets/index-Dmx7LPVX.js +15 -0
  5. package/apps/local-dashboard/dist/assets/vendor-react-C5oyHiV1.js +11 -0
  6. package/apps/local-dashboard/dist/assets/{vendor-table-BIiI3YhS.js → vendor-table-Bc_bbKd8.js} +1 -1
  7. package/apps/local-dashboard/dist/assets/vendor-ui-B3BPIYy7.js +1 -0
  8. package/apps/local-dashboard/dist/index.html +5 -5
  9. package/cli/selftune/adapters/codex/install.ts +310 -78
  10. package/cli/selftune/adapters/opencode/install.ts +3 -4
  11. package/cli/selftune/adapters/pi/hook.ts +273 -0
  12. package/cli/selftune/adapters/pi/install.ts +207 -0
  13. package/cli/selftune/alpha-upload/build-payloads.ts +3 -3
  14. package/cli/selftune/alpha-upload/stage-canonical.ts +17 -11
  15. package/cli/selftune/auto-update.ts +200 -8
  16. package/cli/selftune/canonical-export.ts +55 -25
  17. package/cli/selftune/command-surface.ts +397 -0
  18. package/cli/selftune/constants.ts +10 -1
  19. package/cli/selftune/contribute/contribute.ts +64 -13
  20. package/cli/selftune/contribution-config.ts +57 -3
  21. package/cli/selftune/contribution-preferences.ts +117 -0
  22. package/cli/selftune/contribution-signals.ts +8 -4
  23. package/cli/selftune/contribution-staging.ts +13 -2
  24. package/cli/selftune/contributions.ts +55 -121
  25. package/cli/selftune/creator-contributions.ts +29 -10
  26. package/cli/selftune/cron/setup.ts +7 -3
  27. package/cli/selftune/dashboard-contract.ts +87 -0
  28. package/cli/selftune/dashboard-server.ts +168 -17
  29. package/cli/selftune/dashboard.ts +350 -17
  30. package/cli/selftune/eval/baseline.ts +21 -5
  31. package/cli/selftune/eval/execution-eval.ts +170 -0
  32. package/cli/selftune/eval/family-overlap.ts +2 -2
  33. package/cli/selftune/eval/hooks-to-evals.ts +228 -82
  34. package/cli/selftune/eval/import-skillsbench.ts +2 -2
  35. package/cli/selftune/eval/invocation-classifier.ts +56 -0
  36. package/cli/selftune/eval/synthetic-evals.ts +5 -3
  37. package/cli/selftune/eval/unit-test-cli.ts +7 -4
  38. package/cli/selftune/evolution/apply-proposal.ts +295 -0
  39. package/cli/selftune/evolution/engines/judge-engine.ts +96 -0
  40. package/cli/selftune/evolution/engines/replay-engine.ts +180 -0
  41. package/cli/selftune/evolution/evidence.ts +2 -6
  42. package/cli/selftune/evolution/evolve-body.ts +152 -38
  43. package/cli/selftune/evolution/evolve.ts +244 -52
  44. package/cli/selftune/evolution/rollback.ts +0 -1
  45. package/cli/selftune/evolution/validate-body.ts +111 -49
  46. package/cli/selftune/evolution/validate-host-replay.ts +510 -60
  47. package/cli/selftune/evolution/validate-proposal.ts +11 -150
  48. package/cli/selftune/evolution/validate-routing.ts +51 -108
  49. package/cli/selftune/evolution/validation-contract.ts +91 -0
  50. package/cli/selftune/grading/auto-grade.ts +11 -7
  51. package/cli/selftune/grading/grade-session.ts +10 -16
  52. package/cli/selftune/hooks/skill-eval.ts +2 -1
  53. package/cli/selftune/hooks-shared/types.ts +1 -0
  54. package/cli/selftune/index.ts +58 -15
  55. package/cli/selftune/ingestors/claude-replay.ts +15 -10
  56. package/cli/selftune/ingestors/codex-wrapper.ts +3 -3
  57. package/cli/selftune/ingestors/opencode-ingest.ts +2 -2
  58. package/cli/selftune/ingestors/pi-ingest.ts +727 -0
  59. package/cli/selftune/init.ts +38 -4
  60. package/cli/selftune/localdb/direct-write.ts +120 -1
  61. package/cli/selftune/localdb/materialize.ts +6 -7
  62. package/cli/selftune/localdb/queries/cron.ts +34 -0
  63. package/cli/selftune/localdb/queries/dashboard.ts +834 -0
  64. package/cli/selftune/localdb/queries/evolution.ts +158 -0
  65. package/cli/selftune/localdb/queries/execution.ts +133 -0
  66. package/cli/selftune/localdb/queries/json.ts +18 -0
  67. package/cli/selftune/localdb/queries/monitoring.ts +263 -0
  68. package/cli/selftune/localdb/queries/raw.ts +95 -0
  69. package/cli/selftune/localdb/queries/staging.ts +270 -0
  70. package/cli/selftune/localdb/queries/trust.ts +392 -0
  71. package/cli/selftune/localdb/queries.ts +60 -2162
  72. package/cli/selftune/localdb/schema.ts +59 -0
  73. package/cli/selftune/monitoring/watch.ts +96 -29
  74. package/cli/selftune/normalization.ts +3 -0
  75. package/cli/selftune/observability.ts +12 -3
  76. package/cli/selftune/orchestrate/cli.ts +161 -0
  77. package/cli/selftune/orchestrate/execute.ts +295 -0
  78. package/cli/selftune/orchestrate/finalize.ts +157 -0
  79. package/cli/selftune/orchestrate/locks.ts +40 -0
  80. package/cli/selftune/orchestrate/plan.ts +131 -0
  81. package/cli/selftune/orchestrate/post-run.ts +59 -0
  82. package/cli/selftune/orchestrate/prepare.ts +334 -0
  83. package/cli/selftune/orchestrate/report.ts +182 -0
  84. package/cli/selftune/orchestrate/runtime.ts +120 -0
  85. package/cli/selftune/orchestrate/signals.ts +48 -0
  86. package/cli/selftune/orchestrate.ts +162 -1142
  87. package/cli/selftune/registry/client.ts +74 -0
  88. package/cli/selftune/registry/history.ts +54 -0
  89. package/cli/selftune/registry/index.ts +90 -0
  90. package/cli/selftune/registry/install.ts +141 -0
  91. package/cli/selftune/registry/list.ts +44 -0
  92. package/cli/selftune/registry/push.ts +171 -0
  93. package/cli/selftune/registry/rollback.ts +49 -0
  94. package/cli/selftune/registry/status.ts +62 -0
  95. package/cli/selftune/registry/sync.ts +125 -0
  96. package/cli/selftune/repair/skill-usage.ts +9 -3
  97. package/cli/selftune/routes/overview.ts +5 -2
  98. package/cli/selftune/routes/skill-report.ts +15 -2
  99. package/cli/selftune/schedule.ts +5 -5
  100. package/cli/selftune/status.ts +70 -2
  101. package/cli/selftune/sync.ts +127 -23
  102. package/cli/selftune/testing-readiness.ts +597 -0
  103. package/cli/selftune/types.ts +46 -5
  104. package/cli/selftune/uninstall.ts +2 -1
  105. package/cli/selftune/utils/canonical-log.ts +1 -9
  106. package/cli/selftune/utils/cli-error.ts +9 -0
  107. package/cli/selftune/utils/jsonl.ts +1 -30
  108. package/cli/selftune/utils/llm-call.ts +126 -6
  109. package/cli/selftune/utils/skill-discovery.ts +24 -0
  110. package/cli/selftune/workflows/proposals.ts +184 -0
  111. package/cli/selftune/workflows/skill-scaffold.ts +241 -0
  112. package/cli/selftune/workflows/workflows.ts +100 -26
  113. package/node_modules/@selftune/telemetry-contract/fixtures/complete-push.ts +1 -1
  114. package/node_modules/@selftune/telemetry-contract/fixtures/evidence-only-push.ts +2 -2
  115. package/node_modules/@selftune/telemetry-contract/fixtures/golden.test.ts +0 -1
  116. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
  117. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +2 -2
  118. package/node_modules/@selftune/telemetry-contract/package.json +1 -1
  119. package/node_modules/@selftune/telemetry-contract/src/index.ts +1 -0
  120. package/node_modules/@selftune/telemetry-contract/src/schemas.ts +63 -5
  121. package/node_modules/@selftune/telemetry-contract/src/types.ts +97 -7
  122. package/node_modules/@selftune/telemetry-contract/tests/compatibility.test.ts +0 -1
  123. package/package.json +25 -9
  124. package/packages/dashboard-core/AGENTS.md +18 -0
  125. package/packages/dashboard-core/README.md +30 -0
  126. package/packages/dashboard-core/index.ts +3 -0
  127. package/packages/dashboard-core/package.json +39 -0
  128. package/packages/dashboard-core/src/chrome/DashboardChrome.tsx +74 -0
  129. package/packages/dashboard-core/src/chrome/DashboardHeader.tsx +200 -0
  130. package/packages/dashboard-core/src/chrome/DashboardSidebar.tsx +219 -0
  131. package/packages/dashboard-core/src/chrome/RuntimeBadge.tsx +46 -0
  132. package/packages/dashboard-core/src/chrome/index.ts +14 -0
  133. package/packages/dashboard-core/src/chrome/types.ts +81 -0
  134. package/packages/dashboard-core/src/chrome/utils.ts +23 -0
  135. package/packages/dashboard-core/src/gates/FeatureGate.tsx +11 -0
  136. package/packages/dashboard-core/src/gates/LockedRoute.tsx +29 -0
  137. package/packages/dashboard-core/src/gates/UpgradeCard.tsx +89 -0
  138. package/packages/dashboard-core/src/gates/index.ts +3 -0
  139. package/packages/dashboard-core/src/host/DashboardHostProvider.tsx +62 -0
  140. package/packages/dashboard-core/src/host/adapter.ts +47 -0
  141. package/packages/dashboard-core/src/host/capabilities.ts +55 -0
  142. package/packages/dashboard-core/src/host/index.ts +3 -0
  143. package/packages/dashboard-core/src/models/analytics.ts +39 -0
  144. package/packages/dashboard-core/src/models/index.ts +4 -0
  145. package/packages/dashboard-core/src/models/overview.ts +98 -0
  146. package/packages/dashboard-core/src/models/runtime.ts +7 -0
  147. package/packages/dashboard-core/src/models/skills.ts +34 -0
  148. package/packages/dashboard-core/src/routes/index.ts +2 -0
  149. package/packages/dashboard-core/src/routes/manifest.test.ts +70 -0
  150. package/packages/dashboard-core/src/routes/manifest.ts +451 -0
  151. package/packages/dashboard-core/src/routes/types.ts +39 -0
  152. package/packages/dashboard-core/src/screens/analytics/AnalyticsScreen.tsx +278 -0
  153. package/packages/dashboard-core/src/screens/analytics/index.ts +1 -0
  154. package/packages/dashboard-core/src/screens/index.ts +37 -0
  155. package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.test.ts +101 -0
  156. package/packages/dashboard-core/src/screens/overview/OverviewComparisonSurface.tsx +393 -0
  157. package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.test.tsx +113 -0
  158. package/packages/dashboard-core/src/screens/overview/OverviewCompositionSurface.tsx +72 -0
  159. package/packages/dashboard-core/src/screens/overview/OverviewCoreSurface.tsx +71 -0
  160. package/packages/dashboard-core/src/screens/overview/OverviewOnboardingBanner.tsx +90 -0
  161. package/packages/dashboard-core/src/screens/overview/OverviewRunSummary.tsx +40 -0
  162. package/packages/dashboard-core/src/screens/overview/index.ts +16 -0
  163. package/packages/dashboard-core/src/screens/overview/types.ts +13 -0
  164. package/packages/dashboard-core/src/screens/skill-report/SkillReportDailyBreakdownSection.tsx +99 -0
  165. package/packages/dashboard-core/src/screens/skill-report/SkillReportDataQualityTabContent.tsx +35 -0
  166. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceRail.tsx +71 -0
  167. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceSection.tsx +63 -0
  168. package/packages/dashboard-core/src/screens/skill-report/SkillReportEvidenceTabContent.tsx +25 -0
  169. package/packages/dashboard-core/src/screens/skill-report/SkillReportInvocationsSection.tsx +24 -0
  170. package/packages/dashboard-core/src/screens/skill-report/SkillReportMissedQueriesSection.tsx +79 -0
  171. package/packages/dashboard-core/src/screens/skill-report/SkillReportScaffold.tsx +150 -0
  172. package/packages/dashboard-core/src/screens/skill-report/SkillReportSections.test.tsx +224 -0
  173. package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.test.tsx +76 -0
  174. package/packages/dashboard-core/src/screens/skill-report/SkillReportTabs.tsx +88 -0
  175. package/packages/dashboard-core/src/screens/skill-report/SkillReportTrendSection.tsx +33 -0
  176. package/packages/dashboard-core/src/screens/skill-report/SkillReportTrustBadge.tsx +67 -0
  177. package/packages/dashboard-core/src/screens/skill-report/index.ts +45 -0
  178. package/packages/dashboard-core/src/screens/skills/SkillsLibraryScreen.tsx +162 -0
  179. package/packages/dashboard-core/src/screens/skills/index.ts +6 -0
  180. package/packages/telemetry-contract/fixtures/complete-push.ts +1 -1
  181. package/packages/telemetry-contract/fixtures/evidence-only-push.ts +2 -2
  182. package/packages/telemetry-contract/fixtures/golden.test.ts +0 -1
  183. package/packages/telemetry-contract/fixtures/partial-push-no-sessions.ts +1 -1
  184. package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +2 -2
  185. package/packages/telemetry-contract/package.json +1 -1
  186. package/packages/telemetry-contract/src/index.ts +1 -0
  187. package/packages/telemetry-contract/src/schemas.ts +63 -5
  188. package/packages/telemetry-contract/src/types.ts +97 -7
  189. package/packages/telemetry-contract/tests/compatibility.test.ts +0 -1
  190. package/packages/ui/AGENTS.md +16 -0
  191. package/packages/ui/README.md +1 -1
  192. package/packages/ui/package.json +1 -1
  193. package/packages/ui/src/components/ActivityTimeline.tsx +152 -168
  194. package/packages/ui/src/components/AnalyticsCharts.tsx +344 -0
  195. package/packages/ui/src/components/EvidenceViewer.tsx +229 -464
  196. package/packages/ui/src/components/EvolutionTimeline.tsx +34 -87
  197. package/packages/ui/src/components/InfoTip.tsx +1 -2
  198. package/packages/ui/src/components/InvocationsPanel.tsx +413 -0
  199. package/packages/ui/src/components/JobHistoryTimeline.tsx +156 -0
  200. package/packages/ui/src/components/OrchestrateRunsPanel.tsx +18 -36
  201. package/packages/ui/src/components/OverviewPanels.tsx +693 -0
  202. package/packages/ui/src/components/PipelineStatusBar.tsx +65 -0
  203. package/packages/ui/src/components/SkillReportGuide.tsx +215 -0
  204. package/packages/ui/src/components/SkillReportPanels.tsx +919 -0
  205. package/packages/ui/src/components/SkillsLibrary.tsx +437 -0
  206. package/packages/ui/src/components/index.ts +56 -1
  207. package/packages/ui/src/components/section-cards.tsx +18 -35
  208. package/packages/ui/src/components/skill-health-grid.tsx +47 -37
  209. package/packages/ui/src/lib/constants.tsx +0 -1
  210. package/packages/ui/src/primitives/card.tsx +1 -1
  211. package/packages/ui/src/primitives/checkbox.tsx +1 -1
  212. package/packages/ui/src/primitives/dropdown-menu.tsx +2 -2
  213. package/packages/ui/src/primitives/select.tsx +2 -2
  214. package/packages/ui/src/primitives/tabs.tsx +7 -6
  215. package/packages/ui/src/types.ts +182 -4
  216. package/skill/SKILL.md +130 -318
  217. package/skill/agents/diagnosis-analyst.md +3 -3
  218. package/skill/agents/evolution-reviewer.md +3 -3
  219. package/skill/agents/integration-guide.md +3 -3
  220. package/skill/agents/pattern-analyst.md +2 -2
  221. package/skill/references/cli-quick-reference.md +89 -0
  222. package/skill/references/creator-playbook.md +131 -0
  223. package/skill/references/examples.md +48 -0
  224. package/skill/references/troubleshooting.md +47 -0
  225. package/skill/references/version-history.md +1 -1
  226. package/skill/selftune.contribute.json +11 -0
  227. package/skill/{Workflows → workflows}/Baseline.md +20 -1
  228. package/skill/{Workflows → workflows}/Contribute.md +23 -10
  229. package/skill/{Workflows → workflows}/Contributions.md +13 -5
  230. package/skill/workflows/CreateTestDeploy.md +170 -0
  231. package/skill/{Workflows → workflows}/CreatorContributions.md +18 -6
  232. package/skill/{Workflows → workflows}/Cron.md +1 -1
  233. package/skill/{Workflows → workflows}/Dashboard.md +20 -0
  234. package/skill/{Workflows → workflows}/Doctor.md +1 -1
  235. package/skill/{Workflows → workflows}/Evals.md +67 -2
  236. package/skill/{Workflows → workflows}/Evolve.md +119 -30
  237. package/skill/{Workflows → workflows}/EvolveBody.md +41 -1
  238. package/skill/{Workflows → workflows}/Grade.md +1 -1
  239. package/skill/{Workflows → workflows}/Ingest.md +60 -2
  240. package/skill/{Workflows → workflows}/Initialize.md +16 -9
  241. package/skill/{Workflows → workflows}/Orchestrate.md +13 -3
  242. package/skill/{Workflows → workflows}/PlatformHooks.md +19 -3
  243. package/skill/workflows/Registry.md +99 -0
  244. package/skill/{Workflows → workflows}/Schedule.md +3 -3
  245. package/skill/workflows/SignalsDashboard.md +87 -0
  246. package/skill/{Workflows → workflows}/Sync.md +3 -1
  247. package/skill/{Workflows → workflows}/UnitTest.md +19 -0
  248. package/skill/{Workflows → workflows}/Watch.md +42 -2
  249. package/skill/{Workflows → workflows}/Workflows.md +39 -2
  250. package/apps/local-dashboard/dist/assets/index-D8O-RG1I.js +0 -60
  251. package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +0 -1
  252. package/apps/local-dashboard/dist/assets/vendor-react-CKkiCskZ.js +0 -11
  253. package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +0 -12
  254. package/cli/selftune/utils/html.ts +0 -27
  255. package/packages/ui/src/components/RecentActivityFeed.tsx +0 -117
  256. /package/skill/{Workflows → workflows}/AlphaUpload.md +0 -0
  257. /package/skill/{Workflows → workflows}/AutoActivation.md +0 -0
  258. /package/skill/{Workflows → workflows}/Badge.md +0 -0
  259. /package/skill/{Workflows → workflows}/Composability.md +0 -0
  260. /package/skill/{Workflows → workflows}/EvolutionMemory.md +0 -0
  261. /package/skill/{Workflows → workflows}/ExportCanonical.md +0 -0
  262. /package/skill/{Workflows → workflows}/Hook.md +0 -0
  263. /package/skill/{Workflows → workflows}/ImportSkillsBench.md +0 -0
  264. /package/skill/{Workflows → workflows}/Quickstart.md +0 -0
  265. /package/skill/{Workflows → workflows}/Recover.md +0 -0
  266. /package/skill/{Workflows → workflows}/RepairSkillUsage.md +0 -0
  267. /package/skill/{Workflows → workflows}/Replay.md +0 -0
  268. /package/skill/{Workflows → workflows}/Rollback.md +0 -0
  269. /package/skill/{Workflows → workflows}/Telemetry.md +0 -0
  270. /package/skill/{Workflows → workflows}/Uninstall.md +0 -0
@@ -0,0 +1,397 @@
1
+ export interface PublicCommandFlag {
2
+ token: string;
3
+ helpLabel: string;
4
+ description: string;
5
+ }
6
+
7
+ export interface PublicCommandSurface {
8
+ command: string;
9
+ summary: string;
10
+ usage: string;
11
+ flags: readonly PublicCommandFlag[];
12
+ quickReference: string;
13
+ extraHelpSections?: readonly string[];
14
+ }
15
+
16
+ function formatOptionLines(flags: readonly PublicCommandFlag[]): string[] {
17
+ const width = Math.max(...flags.map((flag) => flag.helpLabel.length), 0) + 2;
18
+ return flags.map((flag) => ` ${flag.helpLabel.padEnd(width)}${flag.description}`);
19
+ }
20
+
21
+ export function renderCommandHelp(surface: PublicCommandSurface): string {
22
+ const lines = [
23
+ `${surface.command} — ${surface.summary}`,
24
+ "",
25
+ "Usage:",
26
+ ` ${surface.usage}`,
27
+ "",
28
+ "Options:",
29
+ ...formatOptionLines(surface.flags),
30
+ ];
31
+
32
+ for (const section of surface.extraHelpSections ?? []) {
33
+ lines.push("", ...section.split("\n"));
34
+ }
35
+
36
+ return lines.join("\n");
37
+ }
38
+
39
+ export const PUBLIC_COMMAND_SURFACES = {
40
+ evalGenerate: {
41
+ command: "selftune eval generate",
42
+ summary: "Build eval sets from logs or SKILL.md",
43
+ usage: "selftune eval generate --skill <name> [options]",
44
+ flags: [
45
+ {
46
+ token: "--skill",
47
+ helpLabel: "--skill",
48
+ description: "Skill name (required unless --list-skills)",
49
+ },
50
+ {
51
+ token: "--list-skills",
52
+ helpLabel: "--list-skills",
53
+ description: "List skills with trusted-vs-raw readiness counts",
54
+ },
55
+ {
56
+ token: "--stats",
57
+ helpLabel: "--stats",
58
+ description: "Show aggregate telemetry stats for the skill",
59
+ },
60
+ {
61
+ token: "--max",
62
+ helpLabel: "--max",
63
+ description: "Maximum eval entries per side (default: 50)",
64
+ },
65
+ {
66
+ token: "--seed",
67
+ helpLabel: "--seed",
68
+ description: "Deterministic shuffle seed (default: 42)",
69
+ },
70
+ {
71
+ token: "--output",
72
+ helpLabel: "--output, --out",
73
+ description: "Output file path (default: <skill>_trigger_eval.json)",
74
+ },
75
+ {
76
+ token: "--no-negatives",
77
+ helpLabel: "--no-negatives",
78
+ description: "Exclude negative examples from output",
79
+ },
80
+ {
81
+ token: "--no-taxonomy",
82
+ helpLabel: "--no-taxonomy",
83
+ description: "Skip invocation_type classification",
84
+ },
85
+ {
86
+ token: "--skill-log",
87
+ helpLabel: "--skill-log",
88
+ description: "Path to skill_usage_log.jsonl",
89
+ },
90
+ {
91
+ token: "--query-log",
92
+ helpLabel: "--query-log",
93
+ description: "Path to all_queries_log.jsonl",
94
+ },
95
+ {
96
+ token: "--telemetry-log",
97
+ helpLabel: "--telemetry-log",
98
+ description: "Path to session_telemetry_log.jsonl",
99
+ },
100
+ {
101
+ token: "--synthetic",
102
+ helpLabel: "--synthetic",
103
+ description: "Generate evals from SKILL.md via LLM (no logs needed)",
104
+ },
105
+ {
106
+ token: "--auto-synthetic",
107
+ helpLabel: "--auto-synthetic",
108
+ description: "Fall back to SKILL.md cold-start evals when no trusted triggers exist",
109
+ },
110
+ {
111
+ token: "--blend",
112
+ helpLabel: "--blend",
113
+ description: "Blend log-based and synthetic evals into one set",
114
+ },
115
+ {
116
+ token: "--skill-path",
117
+ helpLabel: "--skill-path",
118
+ description: "Path to SKILL.md (required with --synthetic, used by --blend)",
119
+ },
120
+ {
121
+ token: "--model",
122
+ helpLabel: "--model",
123
+ description: "Override the synthetic-generation LLM model",
124
+ },
125
+ {
126
+ token: "--help",
127
+ helpLabel: "--help",
128
+ description: "Show this help message",
129
+ },
130
+ ],
131
+ quickReference:
132
+ "selftune eval generate --skill <name> [--list-skills] [--stats] [--max N] [--seed N] [--output PATH] [--blend]",
133
+ extraHelpSections: [
134
+ `Recommended creator loop:
135
+ 1. selftune eval generate --skill <name>
136
+ 2. selftune eval unit-test --skill <name> --generate --skill-path <path>
137
+ 3. selftune evolve --skill <name> --skill-path <path> --dry-run --validation-mode replay
138
+ 4. selftune grade baseline --skill <name> --skill-path <path>
139
+
140
+ Generated evals are also mirrored into ~/.selftune/eval-sets/<skill>.json so the dashboard and status surfaces can track readiness.`,
141
+ ],
142
+ },
143
+ evolve: {
144
+ command: "selftune evolve",
145
+ summary: "Evolve a skill description via failure patterns",
146
+ usage: "selftune evolve --skill <name> --skill-path <path> [options]",
147
+ flags: [
148
+ { token: "--skill", helpLabel: "--skill", description: "Skill name (required)" },
149
+ {
150
+ token: "--skill-path",
151
+ helpLabel: "--skill-path",
152
+ description: "Path to SKILL.md (required)",
153
+ },
154
+ {
155
+ token: "--eval-set",
156
+ helpLabel: "--eval-set",
157
+ description: "Path to eval set JSON (optional, builds from logs if omitted)",
158
+ },
159
+ {
160
+ token: "--agent",
161
+ helpLabel: "--agent",
162
+ description: "Agent CLI to use (claude, codex, opencode)",
163
+ },
164
+ {
165
+ token: "--dry-run",
166
+ helpLabel: "--dry-run",
167
+ description: "Validate proposal without deploying",
168
+ },
169
+ {
170
+ token: "--confidence",
171
+ helpLabel: "--confidence",
172
+ description: "Confidence threshold 0.0-1.0 (default: 0.6)",
173
+ },
174
+ {
175
+ token: "--max-iterations",
176
+ helpLabel: "--max-iterations",
177
+ description: "Max retry iterations (default: 3)",
178
+ },
179
+ {
180
+ token: "--pareto",
181
+ helpLabel: "--pareto",
182
+ description: "Enable Pareto multi-candidate selection",
183
+ },
184
+ {
185
+ token: "--candidates",
186
+ helpLabel: "--candidates",
187
+ description: "Number of candidates to generate (default: 3, max: 5)",
188
+ },
189
+ {
190
+ token: "--token-efficiency",
191
+ helpLabel: "--token-efficiency",
192
+ description: "Enable 5D Pareto with token efficiency scoring",
193
+ },
194
+ {
195
+ token: "--with-baseline",
196
+ helpLabel: "--with-baseline",
197
+ description: "Gate deployment on baseline lift > 0.05",
198
+ },
199
+ {
200
+ token: "--validation-mode",
201
+ helpLabel: "--validation-mode",
202
+ description: "Validation strategy: auto|replay|judge (default: auto)",
203
+ },
204
+ {
205
+ token: "--validation-model",
206
+ helpLabel: "--validation-model",
207
+ description: "Model for trigger-check validation calls (default: haiku)",
208
+ },
209
+ {
210
+ token: "--cheap-loop",
211
+ helpLabel: "--cheap-loop",
212
+ description: "Use cheap models for loop, expensive for gate (default: on)",
213
+ },
214
+ {
215
+ token: "--full-model",
216
+ helpLabel: "--full-model",
217
+ description: "Use same model for all stages (disables cheap-loop)",
218
+ },
219
+ {
220
+ token: "--gate-model",
221
+ helpLabel: "--gate-model",
222
+ description: "Model for final gate validation (default: sonnet)",
223
+ },
224
+ {
225
+ token: "--gate-effort",
226
+ helpLabel: "--gate-effort",
227
+ description: "Thinking effort for final gate (low|medium|high|max)",
228
+ },
229
+ {
230
+ token: "--adaptive-gate",
231
+ helpLabel: "--adaptive-gate",
232
+ description: "Escalate risky gate checks to opus + high effort",
233
+ },
234
+ {
235
+ token: "--proposal-model",
236
+ helpLabel: "--proposal-model",
237
+ description: "Model for proposal generation LLM calls",
238
+ },
239
+ {
240
+ token: "--sync-first",
241
+ helpLabel: "--sync-first",
242
+ description: "Refresh source-truth telemetry before building evals/failure patterns",
243
+ },
244
+ {
245
+ token: "--sync-force",
246
+ helpLabel: "--sync-force",
247
+ description: "Force a full rescan during --sync-first",
248
+ },
249
+ {
250
+ token: "--verbose",
251
+ helpLabel: "--verbose",
252
+ description: "Output full EvolveResult JSON (default: compact summary)",
253
+ },
254
+ {
255
+ token: "--help",
256
+ helpLabel: "--help",
257
+ description: "Show this help message",
258
+ },
259
+ ],
260
+ quickReference:
261
+ "selftune evolve --skill <name> --skill-path <path> [--dry-run] [--validation-mode auto|replay|judge]",
262
+ },
263
+ watch: {
264
+ command: "selftune watch",
265
+ summary: "Monitor post-deploy skill health",
266
+ usage: "selftune watch --skill <name> --skill-path <path> [options]",
267
+ flags: [
268
+ { token: "--skill", helpLabel: "--skill", description: "Skill name (required)" },
269
+ {
270
+ token: "--skill-path",
271
+ helpLabel: "--skill-path",
272
+ description: "Path to SKILL.md (required)",
273
+ },
274
+ {
275
+ token: "--window",
276
+ helpLabel: "--window",
277
+ description: "Number of recent sessions to consider (default: 20)",
278
+ },
279
+ {
280
+ token: "--threshold",
281
+ helpLabel: "--threshold",
282
+ description: "Regression threshold below baseline (default: 0.1)",
283
+ },
284
+ {
285
+ token: "--auto-rollback",
286
+ helpLabel: "--auto-rollback",
287
+ description: "Automatically rollback on regression detection",
288
+ },
289
+ {
290
+ token: "--grade-threshold",
291
+ helpLabel: "--grade-threshold",
292
+ description: "Grade regression threshold (default: 0.15)",
293
+ },
294
+ {
295
+ token: "--no-grade-watch",
296
+ helpLabel: "--no-grade-watch",
297
+ description: "Disable grade-based regression watch (enabled by default)",
298
+ },
299
+ {
300
+ token: "--sync-first",
301
+ helpLabel: "--sync-first",
302
+ description: "Refresh source-truth telemetry before reading watch inputs",
303
+ },
304
+ {
305
+ token: "--sync-force",
306
+ helpLabel: "--sync-force",
307
+ description: "Force a full rescan during --sync-first",
308
+ },
309
+ {
310
+ token: "--help",
311
+ helpLabel: "--help",
312
+ description: "Show this help message",
313
+ },
314
+ ],
315
+ quickReference:
316
+ "selftune watch --skill <name> --skill-path <path> [--auto-rollback] [--grade-threshold N] [--no-grade-watch]",
317
+ },
318
+ orchestrate: {
319
+ command: "selftune orchestrate",
320
+ summary: "Autonomous core loop",
321
+ usage: "selftune orchestrate [options]",
322
+ flags: [
323
+ {
324
+ token: "--dry-run",
325
+ helpLabel: "--dry-run",
326
+ description: "Preview actions without mutations",
327
+ },
328
+ {
329
+ token: "--review-required",
330
+ helpLabel: "--review-required",
331
+ description: "Validate candidates but require human review before deploy",
332
+ },
333
+ {
334
+ token: "--auto-approve",
335
+ helpLabel: "--auto-approve",
336
+ description: "Deprecated alias; autonomous mode is now the default",
337
+ },
338
+ {
339
+ token: "--skill",
340
+ helpLabel: "--skill <name>",
341
+ description: "Scope to a single skill",
342
+ },
343
+ {
344
+ token: "--max-skills",
345
+ helpLabel: "--max-skills <n>",
346
+ description: "Cap skills processed per run (default: 5)",
347
+ },
348
+ {
349
+ token: "--recent-window",
350
+ helpLabel: "--recent-window <hrs>",
351
+ description: "Hours to look back for watch targets (default: 48)",
352
+ },
353
+ {
354
+ token: "--sync-force",
355
+ helpLabel: "--sync-force",
356
+ description: "Force full rescan during sync",
357
+ },
358
+ {
359
+ token: "--max-auto-grade",
360
+ helpLabel: "--max-auto-grade <n>",
361
+ description: "Max ungraded skills to auto-grade per run (default: 5, 0 to disable)",
362
+ },
363
+ {
364
+ token: "--loop",
365
+ helpLabel: "--loop",
366
+ description: "Run in continuous loop mode (never stops)",
367
+ },
368
+ {
369
+ token: "--loop-interval",
370
+ helpLabel: "--loop-interval <s>",
371
+ description: "Seconds between iterations (default: 3600, min: 60)",
372
+ },
373
+ {
374
+ token: "--help",
375
+ helpLabel: "-h, --help",
376
+ description: "Show this help message",
377
+ },
378
+ ],
379
+ quickReference:
380
+ "selftune orchestrate [--dry-run] [--review-required] [--auto-approve] [--skill NAME] [--max-skills N] [--recent-window HOURS] [--sync-force] [--max-auto-grade N] [--loop] [--loop-interval SECS]",
381
+ extraHelpSections: [
382
+ `Safety:
383
+ By default, low-risk description evolution runs autonomously after
384
+ validation. Use --review-required to keep a human in the loop, or
385
+ --dry-run to preview the whole loop without mutations. Every deploy
386
+ still passes validation gates first.`,
387
+ `Examples:
388
+ selftune orchestrate # autonomous description evolution
389
+ selftune orchestrate --review-required # validate but do not deploy
390
+ selftune orchestrate --dry-run # preview only
391
+ selftune orchestrate --skill Research # single skill
392
+ selftune orchestrate --max-skills 3 # limit scope
393
+ selftune orchestrate --loop # continuous loop (hourly)
394
+ selftune orchestrate --loop --loop-interval 600 # every 10 minutes`,
395
+ ],
396
+ },
397
+ } satisfies Record<string, PublicCommandSurface>;
@@ -13,6 +13,8 @@ const claudeHomeDir =
13
13
  const openclawHomeDir =
14
14
  process.env.SELFTUNE_OPENCLAW_DIR ??
15
15
  (resolvedHome ? join(defaultHome, ".openclaw") : join(homedir(), ".openclaw"));
16
+ const piHomeDir =
17
+ process.env.SELFTUNE_PI_DIR ?? (resolvedHome ? join(defaultHome, ".pi") : join(homedir(), ".pi"));
16
18
 
17
19
  export const SELFTUNE_CONFIG_DIR =
18
20
  (process.env.SELFTUNE_CONFIG_DIR || undefined) ??
@@ -100,7 +102,7 @@ export const REQUIRED_FIELDS: Record<string, Set<string>> = {
100
102
  };
101
103
 
102
104
  /** Agent CLI candidates in detection order. */
103
- export const AGENT_CANDIDATES = ["claude", "codex", "opencode", "openclaw"] as const;
105
+ export const AGENT_CANDIDATES = ["claude", "codex", "opencode", "openclaw", "pi"] as const;
104
106
 
105
107
  /** Required Claude Code hook keys in settings.json. */
106
108
  export const CLAUDE_CODE_HOOK_KEYS = [
@@ -158,6 +160,13 @@ export const OPENCLAW_AGENTS_DIR =
158
160
  /** Marker file tracking which OpenClaw sessions have been ingested. */
159
161
  export const OPENCLAW_INGEST_MARKER = join(SELFTUNE_CONFIG_DIR, "openclaw-ingest-marker.json");
160
162
 
163
+ /** Pi sessions directory. */
164
+ export const PI_SESSIONS_DIR =
165
+ process.env.SELFTUNE_PI_SESSIONS_DIR ?? join(piHomeDir, "agent", "sessions");
166
+
167
+ /** Marker file tracking which Pi sessions have been ingested. */
168
+ export const PI_INGEST_MARKER = join(SELFTUNE_CONFIG_DIR, "pi-ingest-marker.json");
169
+
161
170
  /** Default output directory for contribution bundles. */
162
171
  export const CONTRIBUTIONS_DIR = join(SELFTUNE_CONFIG_DIR, "contributions");
163
172
  /** Creator-directed contribution preferences (per-skill opt-in state). */
@@ -11,8 +11,11 @@ import { spawnSync } from "node:child_process";
11
11
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
12
12
  import { parseArgs } from "node:util";
13
13
 
14
- import { CONTRIBUTIONS_DIR } from "../constants.js";
14
+ import { readAlphaIdentity } from "../alpha-identity.js";
15
+ import { CONTRIBUTIONS_DIR, SELFTUNE_CONFIG_PATH } from "../constants.js";
16
+ import { findCreatorContributionConfig } from "../contribution-config.js";
15
17
  import { handleCLIError } from "../utils/cli-error.js";
18
+ import { getSelftuneVersion } from "../utils/selftune-meta.js";
16
19
  import { assembleBundle } from "./bundle.js";
17
20
  import { sanitizeBundle } from "./sanitize.js";
18
21
 
@@ -29,7 +32,7 @@ export async function cliMain(): Promise<void> {
29
32
  sanitize: { type: "string", default: "conservative" },
30
33
  since: { type: "string" },
31
34
  submit: { type: "boolean", default: false },
32
- endpoint: { type: "string", default: "https://selftune-api.fly.dev" },
35
+ endpoint: { type: "string" },
33
36
  github: { type: "boolean", default: false },
34
37
  help: { type: "boolean", short: "h", default: false },
35
38
  },
@@ -37,16 +40,16 @@ export async function cliMain(): Promise<void> {
37
40
  });
38
41
 
39
42
  if (values.help) {
40
- console.log(`selftune contribute — Export an anonymized community bundle
43
+ console.log(`selftune contribute — Export an anonymized community export bundle
41
44
 
42
45
  Usage:
43
46
  selftune contribute --skill <name> [--preview] [--sanitize conservative|aggressive]
44
47
  selftune contribute --skill <name> [--output <file>] [--submit]
45
48
 
46
49
  Purpose:
47
- Build a sanitized community contribution bundle from local SQLite data.
50
+ Build a sanitized community export bundle from local SQLite data.
48
51
  This is separate from:
49
- selftune contributions Creator-directed sharing preferences
52
+ selftune contributions Sharing preferences (creator-directed opt-in/out)
50
53
  selftune alpha upload Personal cloud upload cycle
51
54
 
52
55
  Options:
@@ -131,7 +134,8 @@ Options:
131
134
  const ok = submitToGitHub(json, outputPath);
132
135
  if (!ok) process.exit(1);
133
136
  } else {
134
- const endpoint = values.endpoint ?? "https://selftune-api.fly.dev";
137
+ const auth = getLocalAuthConfig();
138
+ const endpoint = values.endpoint ?? auth?.apiUrl ?? "https://api.selftune.dev";
135
139
  const ok = await submitToService(json, endpoint, skillName);
136
140
  if (!ok) {
137
141
  console.log("Falling back to GitHub submission...");
@@ -143,7 +147,27 @@ Options:
143
147
  }
144
148
 
145
149
  // ---------------------------------------------------------------------------
146
- // Service submission
150
+ // Auth helpers
151
+ // ---------------------------------------------------------------------------
152
+
153
+ function getLocalAuthConfig(): { apiUrl: string; apiKey: string } | null {
154
+ try {
155
+ const identity = readAlphaIdentity(SELFTUNE_CONFIG_PATH);
156
+ if (!identity?.api_key) return null;
157
+ const apiUrl = identity.cloud_api_url || "https://api.selftune.dev";
158
+ return { apiUrl, apiKey: identity.api_key };
159
+ } catch {
160
+ return null;
161
+ }
162
+ }
163
+
164
+ function resolveCreatorId(skillName: string): string | null {
165
+ const config = findCreatorContributionConfig(skillName);
166
+ return config?.creator_id ?? null;
167
+ }
168
+
169
+ // ---------------------------------------------------------------------------
170
+ // Service submission (cloud endpoint)
147
171
  // ---------------------------------------------------------------------------
148
172
 
149
173
  async function submitToService(
@@ -151,12 +175,39 @@ async function submitToService(
151
175
  endpoint: string,
152
176
  skillName: string,
153
177
  ): Promise<boolean> {
178
+ // Resolve creator_id from the installed selftune.contribute.json
179
+ const creatorId = resolveCreatorId(skillName);
180
+ if (!creatorId) {
181
+ console.error(
182
+ `[ERROR] No creator_id found for skill "${skillName}". ` +
183
+ `Ensure selftune.contribute.json exists in the skill directory with a valid creator_id.`,
184
+ );
185
+ return false;
186
+ }
187
+
188
+ // Resolve auth from local config
189
+ const auth = getLocalAuthConfig();
190
+
154
191
  try {
155
- const url = `${endpoint}/api/submit`;
192
+ const url = `${endpoint}/api/v1/community/bundles`;
193
+ // Wrap the already-serialized bundle in the submission envelope
194
+ // without an unnecessary parse/stringify cycle
195
+ const payload = `{"creator_id":${JSON.stringify(creatorId)},"skill_name":${JSON.stringify(skillName)},"bundle":${json}}`;
196
+
197
+ const headers: Record<string, string> = {
198
+ "Content-Type": "application/json",
199
+ "User-Agent": `selftune/${getSelftuneVersion()}`,
200
+ };
201
+
202
+ if (auth?.apiKey) {
203
+ headers.Authorization = `Bearer ${auth.apiKey}`;
204
+ }
205
+
156
206
  const res = await fetch(url, {
157
207
  method: "POST",
158
- headers: { "Content-Type": "application/json" },
159
- body: json,
208
+ headers,
209
+ body: payload,
210
+ signal: AbortSignal.timeout(60_000),
160
211
  });
161
212
 
162
213
  if (!res.ok) {
@@ -165,9 +216,9 @@ async function submitToService(
165
216
  return false;
166
217
  }
167
218
 
168
- console.log(`\nSubmitted to ${endpoint}`);
169
- console.log(` Badge: ${endpoint}/badge/${encodeURIComponent(skillName)}`);
170
- console.log(` Report: ${endpoint}/report/${encodeURIComponent(skillName)}`);
219
+ console.log(`\nSubmitted to ${endpoint}/api/v1/community/bundles`);
220
+ console.log(` Skill: ${skillName}`);
221
+ console.log(` Creator: ${creatorId}`);
171
222
  return true;
172
223
  } catch (err) {
173
224
  console.error(
@@ -7,21 +7,62 @@ import {
7
7
  findRepositorySkillDirs,
8
8
  } from "./utils/skill-discovery.js";
9
9
 
10
+ /**
11
+ * The canonical UUID pattern for `creator_id`. This field must always be the
12
+ * creator's cloud user UUID (the `cloud_user_id` from alpha enrollment), e.g.
13
+ * "550e8400-e29b-41d4-a716-446655440000". Non-UUID values are accepted during
14
+ * local development but will be rejected by the relay endpoint.
15
+ */
16
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17
+ export const SUPPORTED_CONTRIBUTION_SIGNALS = ["trigger", "grade", "miss_category"] as const;
18
+ export type SupportedContributionSignal = (typeof SUPPORTED_CONTRIBUTION_SIGNALS)[number];
19
+
20
+ /** Returns `true` when `value` looks like a valid UUID v4 (case-insensitive). */
21
+ export function isValidCreatorUUID(value: string): boolean {
22
+ return UUID_RE.test(value);
23
+ }
24
+
25
+ export function isSupportedContributionSignal(value: string): value is SupportedContributionSignal {
26
+ return SUPPORTED_CONTRIBUTION_SIGNALS.includes(value as SupportedContributionSignal);
27
+ }
28
+
29
+ export function normalizeSupportedContributionSignals(
30
+ rawSignals: string[],
31
+ ): SupportedContributionSignal[] {
32
+ const normalized = [...new Set(rawSignals.map((signal) => signal.trim()).filter(Boolean))];
33
+ if (normalized.length === 0) {
34
+ throw new Error(
35
+ `At least one contribution signal is required. Supported signals: ${SUPPORTED_CONTRIBUTION_SIGNALS.join(", ")}`,
36
+ );
37
+ }
38
+
39
+ const invalid = normalized.filter((signal) => !isSupportedContributionSignal(signal));
40
+ if (invalid.length > 0) {
41
+ throw new Error(
42
+ `Unsupported contribution signals: ${invalid.join(", ")}. Supported signals: ${SUPPORTED_CONTRIBUTION_SIGNALS.join(", ")}`,
43
+ );
44
+ }
45
+
46
+ return normalized as SupportedContributionSignal[];
47
+ }
48
+
10
49
  export interface CreatorContributionConfig {
11
50
  version: 1;
51
+ /** Must be the creator's cloud user UUID (`cloud_user_id`). */
12
52
  creator_id: string;
13
53
  skill_name: string;
14
54
  config_path: string;
15
55
  skill_path: string;
16
56
  contribution: {
17
57
  enabled: boolean;
18
- signals: string[];
58
+ signals: SupportedContributionSignal[];
19
59
  message?: string;
20
60
  privacy_url?: string;
21
61
  };
22
62
  }
23
63
 
24
64
  export interface CreatorContributionConfigInput {
65
+ /** Must be the creator's cloud user UUID (`cloud_user_id`). */
25
66
  creator_id: string;
26
67
  skill_name: string;
27
68
  skill_path: string;
@@ -95,6 +136,13 @@ function normalizeContributionConfig(
95
136
  .filter(Boolean);
96
137
  if (signals.length === 0) return null;
97
138
 
139
+ if (!isValidCreatorUUID(creatorId)) {
140
+ process.stderr.write(
141
+ `[selftune] warning: creator_id "${creatorId}" is not a valid UUID. ` +
142
+ `Expected a cloud user UUID (e.g. "550e8400-e29b-41d4-a716-446655440000").\n`,
143
+ );
144
+ }
145
+
98
146
  return {
99
147
  version: 1,
100
148
  creator_id: creatorId,
@@ -103,7 +151,7 @@ function normalizeContributionConfig(
103
151
  skill_path: skillPath,
104
152
  contribution: {
105
153
  enabled: true,
106
- signals: [...new Set(signals)],
154
+ signals: normalizeSupportedContributionSignals(signals),
107
155
  message: typeof raw.contribution.message === "string" ? raw.contribution.message : undefined,
108
156
  privacy_url:
109
157
  typeof raw.contribution.privacy_url === "string" ? raw.contribution.privacy_url : undefined,
@@ -150,6 +198,12 @@ export function resolveContributionSkillPath(
150
198
  export function writeCreatorContributionConfig(
151
199
  input: CreatorContributionConfigInput,
152
200
  ): CreatorContributionConfig {
201
+ if (!isValidCreatorUUID(input.creator_id)) {
202
+ throw new Error(
203
+ `creator_id must be the creator's cloud user UUID. Received "${input.creator_id}".`,
204
+ );
205
+ }
206
+ const signals = normalizeSupportedContributionSignals(input.signals);
153
207
  const normalized = normalizeContributionConfig(
154
208
  {
155
209
  version: 1,
@@ -157,7 +211,7 @@ export function writeCreatorContributionConfig(
157
211
  skill_name: input.skill_name,
158
212
  contribution: {
159
213
  enabled: true,
160
- signals: input.signals,
214
+ signals,
161
215
  message: input.message,
162
216
  privacy_url: input.privacy_url,
163
217
  },