selftune 0.2.22 → 0.2.23

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 (94) hide show
  1. package/README.md +4 -2
  2. package/apps/local-dashboard/dist/assets/index-CwOtTrUS.css +1 -0
  3. package/apps/local-dashboard/dist/assets/index-f1HQpbeH.js +59 -0
  4. package/apps/local-dashboard/dist/assets/vendor-ui-jVSaIZey.js +12 -0
  5. package/apps/local-dashboard/dist/index.html +3 -3
  6. package/cli/selftune/adapters/pi/hook.ts +273 -0
  7. package/cli/selftune/adapters/pi/install.ts +207 -0
  8. package/cli/selftune/constants.ts +10 -1
  9. package/cli/selftune/dashboard-contract.ts +14 -0
  10. package/cli/selftune/evolution/engines/judge-engine.ts +96 -0
  11. package/cli/selftune/evolution/engines/replay-engine.ts +158 -0
  12. package/cli/selftune/evolution/evidence.ts +2 -6
  13. package/cli/selftune/evolution/evolve-body.ts +73 -20
  14. package/cli/selftune/evolution/validate-body.ts +78 -42
  15. package/cli/selftune/evolution/validate-routing.ts +45 -104
  16. package/cli/selftune/hooks/skill-eval.ts +2 -1
  17. package/cli/selftune/hooks-shared/types.ts +1 -0
  18. package/cli/selftune/index.ts +23 -5
  19. package/cli/selftune/ingestors/pi-ingest.ts +726 -0
  20. package/cli/selftune/init.ts +11 -1
  21. package/cli/selftune/localdb/direct-write.ts +85 -0
  22. package/cli/selftune/localdb/materialize.ts +6 -7
  23. package/cli/selftune/localdb/queries.ts +126 -0
  24. package/cli/selftune/localdb/schema.ts +38 -0
  25. package/cli/selftune/observability.ts +8 -1
  26. package/cli/selftune/orchestrate.ts +43 -0
  27. package/cli/selftune/registry/client.ts +74 -0
  28. package/cli/selftune/registry/history.ts +54 -0
  29. package/cli/selftune/registry/index.ts +90 -0
  30. package/cli/selftune/registry/install.ts +141 -0
  31. package/cli/selftune/registry/list.ts +44 -0
  32. package/cli/selftune/registry/push.ts +171 -0
  33. package/cli/selftune/registry/rollback.ts +49 -0
  34. package/cli/selftune/registry/status.ts +62 -0
  35. package/cli/selftune/registry/sync.ts +125 -0
  36. package/cli/selftune/repair/skill-usage.ts +4 -1
  37. package/cli/selftune/status.ts +31 -0
  38. package/cli/selftune/sync.ts +127 -23
  39. package/cli/selftune/types.ts +2 -1
  40. package/cli/selftune/utils/jsonl.ts +1 -30
  41. package/cli/selftune/utils/skill-discovery.ts +22 -0
  42. package/node_modules/@selftune/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
  43. package/node_modules/@selftune/telemetry-contract/fixtures/golden.test.ts +0 -1
  44. package/node_modules/@selftune/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
  45. package/node_modules/@selftune/telemetry-contract/package.json +1 -1
  46. package/node_modules/@selftune/telemetry-contract/src/index.ts +1 -0
  47. package/node_modules/@selftune/telemetry-contract/src/schemas.ts +22 -4
  48. package/node_modules/@selftune/telemetry-contract/src/types.ts +1 -12
  49. package/node_modules/@selftune/telemetry-contract/tests/compatibility.test.ts +0 -1
  50. package/package.json +1 -1
  51. package/packages/telemetry-contract/fixtures/evidence-only-push.ts +1 -1
  52. package/packages/telemetry-contract/fixtures/golden.test.ts +0 -1
  53. package/packages/telemetry-contract/fixtures/partial-push-unresolved-parents.ts +1 -1
  54. package/packages/telemetry-contract/package.json +1 -1
  55. package/packages/telemetry-contract/src/index.ts +1 -0
  56. package/packages/telemetry-contract/src/schemas.ts +22 -4
  57. package/packages/telemetry-contract/src/types.ts +1 -12
  58. package/packages/telemetry-contract/tests/compatibility.test.ts +0 -1
  59. package/packages/ui/AGENTS.md +16 -0
  60. package/packages/ui/README.md +1 -1
  61. package/packages/ui/package.json +1 -1
  62. package/packages/ui/src/components/ActivityTimeline.tsx +152 -168
  63. package/packages/ui/src/components/AnalyticsCharts.tsx +344 -0
  64. package/packages/ui/src/components/EvidenceViewer.tsx +153 -443
  65. package/packages/ui/src/components/EvolutionTimeline.tsx +34 -87
  66. package/packages/ui/src/components/InfoTip.tsx +1 -2
  67. package/packages/ui/src/components/InvocationsPanel.tsx +413 -0
  68. package/packages/ui/src/components/JobHistoryTimeline.tsx +156 -0
  69. package/packages/ui/src/components/OrchestrateRunsPanel.tsx +18 -36
  70. package/packages/ui/src/components/OverviewPanels.tsx +652 -0
  71. package/packages/ui/src/components/PipelineStatusBar.tsx +65 -0
  72. package/packages/ui/src/components/SkillReportGuide.tsx +215 -0
  73. package/packages/ui/src/components/SkillReportPanels.tsx +919 -0
  74. package/packages/ui/src/components/SkillsLibrary.tsx +437 -0
  75. package/packages/ui/src/components/index.ts +56 -1
  76. package/packages/ui/src/components/section-cards.tsx +18 -35
  77. package/packages/ui/src/components/skill-health-grid.tsx +47 -37
  78. package/packages/ui/src/lib/constants.tsx +0 -1
  79. package/packages/ui/src/primitives/card.tsx +1 -1
  80. package/packages/ui/src/primitives/checkbox.tsx +1 -1
  81. package/packages/ui/src/primitives/dropdown-menu.tsx +2 -2
  82. package/packages/ui/src/primitives/select.tsx +2 -2
  83. package/packages/ui/src/types.ts +172 -4
  84. package/skill/SKILL.md +18 -4
  85. package/skill/Workflows/Ingest.md +60 -2
  86. package/skill/Workflows/Initialize.md +8 -5
  87. package/skill/Workflows/PlatformHooks.md +19 -3
  88. package/skill/Workflows/Registry.md +99 -0
  89. package/skill/Workflows/Sync.md +3 -1
  90. package/apps/local-dashboard/dist/assets/index-D8O-RG1I.js +0 -60
  91. package/apps/local-dashboard/dist/assets/index-_EcLywDg.css +0 -1
  92. package/apps/local-dashboard/dist/assets/vendor-ui-CGEmUayx.js +0 -12
  93. package/cli/selftune/utils/html.ts +0 -27
  94. package/packages/ui/src/components/RecentActivityFeed.tsx +0 -117
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  import {
2
3
  closestCenter,
3
4
  DndContext,
@@ -33,27 +34,7 @@ import {
33
34
  type SortingState,
34
35
  type VisibilityState,
35
36
  } from "@tanstack/react-table";
36
- import {
37
- GripVerticalIcon,
38
- Columns3Icon,
39
- ChevronDownIcon,
40
- ChevronsLeftIcon,
41
- ChevronLeftIcon,
42
- ChevronRightIcon,
43
- ChevronsRightIcon,
44
- ClockIcon,
45
- LayersIcon,
46
- FilterIcon,
47
- CheckCircleIcon,
48
- AlertTriangleIcon,
49
- XCircleIcon,
50
- CircleDotIcon,
51
- HelpCircleIcon,
52
- } from "lucide-react";
53
- import * as React from "react";
54
37
 
55
- import { STATUS_CONFIG } from "../lib/constants";
56
- import { formatRate, timeAgo } from "../lib/format";
57
38
  import { Badge } from "../primitives/badge";
58
39
  import { Button } from "../primitives/button";
59
40
  import { Checkbox } from "../primitives/checkbox";
@@ -76,7 +57,26 @@ import {
76
57
  } from "../primitives/select";
77
58
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../primitives/table";
78
59
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../primitives/tabs";
60
+ import { STATUS_CONFIG } from "../lib/constants";
79
61
  import type { SkillCard, SkillHealthStatus } from "../types";
62
+ import { formatRate, timeAgo } from "../lib/format";
63
+ import {
64
+ GripVerticalIcon,
65
+ Columns3Icon,
66
+ ChevronDownIcon,
67
+ ChevronsLeftIcon,
68
+ ChevronLeftIcon,
69
+ ChevronRightIcon,
70
+ ChevronsRightIcon,
71
+ ClockIcon,
72
+ LayersIcon,
73
+ FilterIcon,
74
+ CheckCircleIcon,
75
+ AlertTriangleIcon,
76
+ XCircleIcon,
77
+ CircleDotIcon,
78
+ HelpCircleIcon,
79
+ } from "lucide-react";
80
80
 
81
81
  // ---------- Drag handle ----------
82
82
 
@@ -152,15 +152,27 @@ function createColumns(
152
152
  enableHiding: false,
153
153
  },
154
154
  {
155
- accessorKey: "scope",
156
- header: "Scope",
155
+ accessorKey: "platforms",
156
+ header: "Platforms",
157
157
  cell: ({ row }) => {
158
- const scope = row.original.scope;
159
- if (!scope) return <span className="text-xs text-muted-foreground">--</span>;
158
+ const platforms = row.original.platforms;
159
+ if (!platforms || platforms.length === 0) {
160
+ const scope = row.original.scope;
161
+ if (!scope) return <span className="text-xs text-muted-foreground">--</span>;
162
+ return (
163
+ <Badge variant="secondary" className="text-[10px]">
164
+ {scope}
165
+ </Badge>
166
+ );
167
+ }
160
168
  return (
161
- <Badge variant="secondary" className="text-[10px]">
162
- {scope}
163
- </Badge>
169
+ <div className="flex flex-wrap gap-1">
170
+ {platforms.map((p) => (
171
+ <Badge key={p} variant="secondary" className="text-[10px]">
172
+ {p}
173
+ </Badge>
174
+ ))}
175
+ </div>
164
176
  );
165
177
  },
166
178
  },
@@ -349,7 +361,7 @@ export function SkillHealthGrid({
349
361
  } else if (activeView === "recent") {
350
362
  filtered = cards
351
363
  .filter((c) => c.lastSeen !== null)
352
- .sort((a: SkillCard, b: SkillCard) => {
364
+ .sort((a, b) => {
353
365
  const aTime = a.lastSeen ? new Date(a.lastSeen).getTime() : 0;
354
366
  const bTime = b.lastSeen ? new Date(b.lastSeen).getTime() : 0;
355
367
  return bTime - aTime;
@@ -380,7 +392,7 @@ export function SkillHealthGrid({
380
392
  columnFilters,
381
393
  pagination,
382
394
  },
383
- getRowId: (row) => row.name,
395
+ getRowId: (row) => row.id ?? row.name,
384
396
  enableRowSelection: true,
385
397
  onRowSelectionChange: setRowSelection,
386
398
  onSortingChange: setSorting,
@@ -395,10 +407,8 @@ export function SkillHealthGrid({
395
407
  getFacetedUniqueValues: getFacetedUniqueValues(),
396
408
  });
397
409
 
398
- const dataIds = React.useMemo<UniqueIdentifier[]>(
399
- () => table.getRowModel().rows.map((r) => r.id),
400
- [table.getRowModel().rows],
401
- );
410
+ const rows = table.getRowModel().rows;
411
+ const dataIds = React.useMemo<UniqueIdentifier[]>(() => rows.map((r) => r.id), [rows]);
402
412
 
403
413
  const isSorted = sorting.length > 0;
404
414
 
@@ -407,7 +417,7 @@ export function SkillHealthGrid({
407
417
  const { active, over } = event;
408
418
  if (active && over && active.id !== over.id) {
409
419
  setData((prev) => {
410
- const ids = prev.map((d) => d.name);
420
+ const ids = prev.map((d) => d.id ?? d.name);
411
421
  const oldIndex = ids.indexOf(active.id as string);
412
422
  const newIndex = ids.indexOf(over.id as string);
413
423
  if (oldIndex === -1 || newIndex === -1) return prev;
@@ -537,8 +547,8 @@ export function SkillHealthGrid({
537
547
  checked={column.getIsVisible()}
538
548
  onCheckedChange={(value) => column.toggleVisibility(!!value)}
539
549
  >
540
- {column.id === "scope"
541
- ? "Scope"
550
+ {column.id === "platforms"
551
+ ? "Platforms"
542
552
  : column.id === "passRate"
543
553
  ? "Pass Rate"
544
554
  : column.id === "uniqueSessions"
@@ -559,7 +569,7 @@ export function SkillHealthGrid({
559
569
  value={activeView}
560
570
  className="relative flex flex-col gap-4 overflow-auto px-4 lg:px-6"
561
571
  >
562
- <div className="overflow-hidden rounded-lg border">
572
+ <div className="overflow-hidden rounded-lg border border-border/15">
563
573
  <DndContext
564
574
  collisionDetection={closestCenter}
565
575
  modifiers={[restrictToVerticalAxis]}
@@ -5,7 +5,6 @@ import {
5
5
  HelpCircleIcon,
6
6
  XCircleIcon,
7
7
  } from "lucide-react";
8
-
9
8
  import type { SkillHealthStatus } from "../types";
10
9
 
11
10
  export const STATUS_CONFIG: Record<
@@ -12,7 +12,7 @@ function Card({
12
12
  data-slot="card"
13
13
  data-size={size}
14
14
  className={cn(
15
- "group/card flex flex-col gap-4 overflow-hidden rounded-2xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/5 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
15
+ "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-muted py-4 text-sm text-card-foreground border border-border/15 shadow-none has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
16
16
  className,
17
17
  )}
18
18
  {...props}
@@ -1,7 +1,7 @@
1
1
  import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
2
- import { CheckIcon } from "lucide-react";
3
2
 
4
3
  import { cn } from "../lib/utils";
4
+ import { CheckIcon } from "lucide-react";
5
5
 
6
6
  function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
7
7
  return (
@@ -1,8 +1,8 @@
1
- import { Menu as MenuPrimitive } from "@base-ui/react/menu";
2
- import { ChevronRightIcon, CheckIcon } from "lucide-react";
3
1
  import * as React from "react";
2
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu";
4
3
 
5
4
  import { cn } from "../lib/utils";
5
+ import { ChevronRightIcon, CheckIcon } from "lucide-react";
6
6
 
7
7
  function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
8
8
  return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
@@ -1,8 +1,8 @@
1
- import { Select as SelectPrimitive } from "@base-ui/react/select";
2
- import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react";
3
1
  import * as React from "react";
2
+ import { Select as SelectPrimitive } from "@base-ui/react/select";
4
3
 
5
4
  import { cn } from "../lib/utils";
5
+ import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react";
6
6
 
7
7
  const Select = SelectPrimitive.Root;
8
8
 
@@ -3,8 +3,10 @@
3
3
  export type SkillHealthStatus = "HEALTHY" | "WARNING" | "CRITICAL" | "UNGRADED" | "UNKNOWN";
4
4
 
5
5
  export interface SkillCard {
6
+ id?: string;
6
7
  name: string;
7
8
  scope: string | null;
9
+ platforms: string[];
8
10
  passRate: number | null;
9
11
  checks: number;
10
12
  status: SkillHealthStatus;
@@ -13,6 +15,32 @@ export interface SkillCard {
13
15
  lastSeen: string | null;
14
16
  }
15
17
 
18
+ // -- Job execution types (re-declared for package independence) ---------------
19
+
20
+ export interface JobExecution {
21
+ id: string;
22
+ jobName: string;
23
+ status: "success" | "error";
24
+ startedAt: string;
25
+ durationMs: number;
26
+ metrics: Record<string, unknown>;
27
+ error?: string;
28
+ }
29
+
30
+ export interface JobScheduleEntry {
31
+ name: string;
32
+ schedule: string;
33
+ cronExpression: string;
34
+ lastRunAt: string | null;
35
+ lastRunStatus: "success" | "error" | null;
36
+ lastRunDurationMs: number | null;
37
+ nextRunAt: string;
38
+ }
39
+
40
+ export interface JobScheduleState {
41
+ jobs: JobScheduleEntry[];
42
+ }
43
+
16
44
  // -- Dashboard contract types (re-declared for package independence) ----------
17
45
 
18
46
  export interface EvalSnapshot {
@@ -31,10 +59,6 @@ export interface EvolutionEntry {
31
59
  action: string;
32
60
  details: string;
33
61
  eval_snapshot?: EvalSnapshot | null;
34
- validation_mode?: "structural_guard" | "host_replay" | "llm_judge" | null;
35
- validation_agent?: string | null;
36
- validation_fixture_id?: string | null;
37
- validation_evidence_ref?: string | null;
38
62
  }
39
63
 
40
64
  export interface UnmatchedQuery {
@@ -90,3 +114,147 @@ export interface OrchestrateRunReport {
90
114
  skipped: number;
91
115
  skill_actions: OrchestrateRunSkillAction[];
92
116
  }
117
+
118
+ // -- Overview panel types (shared between local & cloud dashboards) ----------
119
+
120
+ export type AutonomyStatusLevel = "healthy" | "watching" | "needs_review" | "blocked";
121
+
122
+ export interface AutonomyStatus {
123
+ level: AutonomyStatusLevel;
124
+ summary: string;
125
+ skills_observed: number;
126
+ attention_required: number;
127
+ pending_reviews: number;
128
+ }
129
+
130
+ export type TrustBucket = "at_risk" | "improving" | "uncertain" | "stable";
131
+
132
+ export interface TrustWatchlistEntry {
133
+ skill_name: string;
134
+ bucket: TrustBucket;
135
+ pass_rate: number | null;
136
+ reason: string;
137
+ last_seen: string | null;
138
+ }
139
+
140
+ export type AttentionSeverity = "critical" | "warning" | "info";
141
+
142
+ export interface AttentionItem {
143
+ skill_name: string;
144
+ category: string;
145
+ severity: AttentionSeverity;
146
+ reason: string;
147
+ recommended_action: string;
148
+ timestamp: string | null;
149
+ }
150
+
151
+ export type DecisionKind =
152
+ | "proposal_created"
153
+ | "proposal_rejected"
154
+ | "validation_failed"
155
+ | "proposal_deployed"
156
+ | "rollback_triggered"
157
+ | "regression_found";
158
+
159
+ export interface AutonomousDecision {
160
+ skill_name: string;
161
+ kind: DecisionKind;
162
+ summary: string;
163
+ timestamp: string;
164
+ }
165
+
166
+ // -- Trust / skill report types (shared between local & cloud dashboards) ----
167
+
168
+ export type TrustState =
169
+ | "low_sample"
170
+ | "observed"
171
+ | "watch"
172
+ | "validated"
173
+ | "deployed"
174
+ | "rolled_back";
175
+
176
+ export type ObservationKind =
177
+ | "canonical"
178
+ | "repaired_trigger"
179
+ | "repaired_contextual_miss"
180
+ | "legacy_materialized";
181
+
182
+ export type HistoricalContext = "previously_missed";
183
+
184
+ export interface ExampleRow {
185
+ timestamp: string | null;
186
+ session_id: string;
187
+ query_text: string;
188
+ triggered: boolean;
189
+ confidence: number | null;
190
+ invocation_mode: string | null;
191
+ prompt_kind: string | null;
192
+ source: string | null;
193
+ platform: string | null;
194
+ workspace_path: string | null;
195
+ query_origin: "inline_query" | "matched_prompt" | "missing";
196
+ is_system_like: boolean;
197
+ observation_kind: ObservationKind;
198
+ historical_context?: HistoricalContext | null;
199
+ }
200
+
201
+ export interface TrustFields {
202
+ trust: {
203
+ state: TrustState;
204
+ summary: string;
205
+ };
206
+ coverage: {
207
+ checks: number;
208
+ sessions: number;
209
+ workspaces: number;
210
+ first_seen: string | null;
211
+ last_seen: string | null;
212
+ };
213
+ evidence_quality: {
214
+ prompt_link_rate: number;
215
+ inline_query_rate: number;
216
+ user_prompt_rate: number;
217
+ meta_prompt_rate: number;
218
+ internal_prompt_rate: number;
219
+ no_prompt_rate: number;
220
+ system_like_rate: number;
221
+ invocation_mode_coverage: number;
222
+ confidence_coverage: number;
223
+ source_coverage: number;
224
+ scope_coverage: number;
225
+ };
226
+ routing_quality: {
227
+ missed_triggers: number;
228
+ miss_rate: number;
229
+ avg_confidence: number | null;
230
+ confidence_coverage: number;
231
+ low_confidence_rate: number | null;
232
+ };
233
+ evolution_state: {
234
+ has_evidence: boolean;
235
+ has_pending_proposals: boolean;
236
+ latest_action: string | null;
237
+ latest_timestamp: string | null;
238
+ evidence_rows: number;
239
+ evolution_rows: number;
240
+ };
241
+ data_hygiene: {
242
+ naming_variants: string[];
243
+ source_breakdown: Array<{ source: string; count: number }>;
244
+ prompt_kind_breakdown: Array<{ kind: string; count: number }>;
245
+ observation_breakdown: Array<{ kind: ObservationKind; count: number }>;
246
+ raw_checks: number;
247
+ operational_checks: number;
248
+ internal_prompt_rows: number;
249
+ internal_prompt_rate: number;
250
+ legacy_rows: number;
251
+ legacy_rate: number;
252
+ repaired_rows: number;
253
+ repaired_rate: number;
254
+ };
255
+ examples: {
256
+ good: ExampleRow[];
257
+ missed: ExampleRow[];
258
+ noisy: ExampleRow[];
259
+ };
260
+ }
package/skill/SKILL.md CHANGED
@@ -73,6 +73,7 @@ selftune ingest claude [--since DATE] [--dry-run] [--force] [--verbose]
73
73
  selftune ingest codex # (experimental)
74
74
  selftune ingest opencode # (experimental)
75
75
  selftune ingest openclaw [--agents-dir PATH] [--since DATE] [--dry-run] [--force] [--verbose] # (experimental)
76
+ selftune ingest pi [--sessions-dir PATH] [--since DATE] [--dry-run] [--force] [--verbose] # (experimental)
76
77
  selftune ingest wrap-codex -- <codex args> # (experimental)
77
78
 
78
79
  # Grade group
@@ -109,7 +110,7 @@ selftune export [TABLE...] [--output/-o DIR] [--since DATE]
109
110
 
110
111
  # Autonomous loop
111
112
  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]
112
- selftune sync [--since DATE] [--dry-run] [--force] [--no-claude] [--no-codex] [--no-opencode] [--no-openclaw] [--no-repair] [--json]
113
+ selftune sync [--since DATE] [--dry-run] [--force] [--no-claude] [--no-codex] [--no-opencode] [--no-openclaw] [--no-pi] [--no-repair] [--json]
113
114
 
114
115
  # Discovery + badges
115
116
  selftune workflows [--skill NAME] [--skill-path PATH] [--min-occurrences N] [--window N] [--json] [save --skill NAME --skill-path PATH]
@@ -132,6 +133,17 @@ selftune opencode hook
132
133
  selftune opencode install [--dry-run] [--uninstall]
133
134
  selftune cline hook
134
135
  selftune cline install [--dry-run] [--uninstall]
136
+ selftune pi hook
137
+ selftune pi install [--dry-run] [--uninstall]
138
+
139
+ # Registry (team skill distribution)
140
+ selftune registry push [name] [--version=<semver>] [--summary=<text>]
141
+ selftune registry install <name> [--global]
142
+ selftune registry sync
143
+ selftune registry status
144
+ selftune registry rollback <name> [--to=<version>] [--reason=<text>]
145
+ selftune registry history <name>
146
+ selftune registry list
135
147
 
136
148
  # Alpha enrollment (device-code flow — browser opens automatically)
137
149
  selftune init --alpha --alpha-email <email>
@@ -151,7 +163,7 @@ selftune status # shows c
151
163
  | evolve rollback, undo, restore, revert evolution, go back, undo last change | Rollback | Workflows/Rollback.md |
152
164
  | watch, monitor, regression, post-deploy, keep an eye on | Watch | Workflows/Watch.md |
153
165
  | doctor, health, hooks, broken, diagnose, not working, something wrong | Doctor | Workflows/Doctor.md |
154
- | ingest, import, codex logs, opencode, openclaw, wrap codex | Ingest | Workflows/Ingest.md |
166
+ | ingest, import, codex logs, opencode, openclaw, pi, wrap codex | Ingest | Workflows/Ingest.md |
155
167
  | replay, backfill, claude transcripts, historical sessions | Replay | Workflows/Replay.md |
156
168
  | contributions, sharing preferences, opt in creator sharing, opt out creator sharing, approve contributions, revoke contributions, preview contributions, upload contributions, relay queue, contribution upload, contribution preview | Contributions | Workflows/Contributions.md |
157
169
  | creator contributions, bundle contribution config, selftune.contribute.json, enable creator contribution, disable creator contribution, bulk enable creator contribution, enable all creator contributions, creator prefix config, --all, --prefix | CreatorContributions | Workflows/CreatorContributions.md |
@@ -177,7 +189,8 @@ selftune status # shows c
177
189
  | repair, rebuild usage, fix skill usage, trustworthy usage, repair-skill-usage | RepairSkillUsage | Workflows/RepairSkillUsage.md |
178
190
  | export canonical, canonical export, canonical telemetry, push payload | ExportCanonical | Workflows/ExportCanonical.md |
179
191
  | hook, run hook, invoke hook, manual hook, debug hook | Hook | Workflows/Hook.md |
180
- | codex hooks, codex install, codex setup, opencode hooks, opencode install, opencode setup, cline hooks, cline install, cline setup, multi-platform, platform hooks, non-claude hooks, multiple agents, multi-agent | PlatformHooks | Workflows/PlatformHooks.md |
192
+ | codex hooks, codex install, codex setup, opencode hooks, opencode install, opencode setup, cline hooks, cline install, cline setup, pi hooks, pi install, pi setup, multi-platform, platform hooks, non-claude hooks, multiple agents, multi-agent | PlatformHooks | Workflows/PlatformHooks.md |
193
+ | registry, distribute, push skill, install skill, sync skills, team skills, version control skills, rollback skill | Registry | Workflows/Registry.md |
181
194
  | export, dump, jsonl, export sqlite, debug export | Export | _(direct command — no workflow file)_ |
182
195
  | status, health summary, skill health, how are skills, skills doing, run selftune | Status | _(direct command — no workflow file)_ |
183
196
  | last, last session, recent session, what happened, what changed | Last | _(direct command — no workflow file)_ |
@@ -366,11 +379,12 @@ accomplish a task _using_ a skill, route to that skill instead.
366
379
  | `Workflows/CreatorContributions.md` | Manage bundled `selftune.contribute.json` configs | When preparing a skill package for creator contributions |
367
380
  | `Workflows/ExportCanonical.md` | Export canonical telemetry for downstream use | When exporting data for external consumption |
368
381
  | `Workflows/Hook.md` | Manual hook invocation for debugging | When debugging or testing hooks manually |
369
- | `Workflows/PlatformHooks.md` | Non-Claude-Code platform hook install/config | When setting up Codex, OpenCode, or Cline hooks |
382
+ | `Workflows/PlatformHooks.md` | Non-Claude-Code platform hook install/config | When setting up Codex, OpenCode, Cline, or Pi hooks |
370
383
  | `references/logs.md` | Log file formats (telemetry, usage, queries, audit) | When parsing or debugging log files |
371
384
  | `references/grading-methodology.md` | 3-tier grading model, evidence standards | When grading sessions or interpreting grades |
372
385
  | `references/invocation-taxonomy.md` | 4 invocation types, coverage analysis | When analyzing trigger coverage |
373
386
  | `references/interactive-config.md` | Pre-flight config pattern, model tiers | Before running mutating workflows |
374
387
  | `references/setup-patterns.md` | Platform-specific setup patterns | During complex setup scenarios |
388
+ | `Workflows/Registry.md` | Registry — team skill distribution commands | When routing to registry workflow |
375
389
  | `settings_snippet.json` | Claude Code hook configuration template | During initialization |
376
390
  | `assets/*.json` | Config templates (activation rules, settings) | During initialization |
@@ -3,8 +3,8 @@
3
3
  > **Note:** Claude Code is the fully supported platform. Codex, OpenCode, and OpenClaw adapters are experimental and may have gaps.
4
4
 
5
5
  Import sessions from agent platforms into the shared selftune log format.
6
- Covers five sub-commands: `ingest claude`, `ingest codex`, `ingest opencode`,
7
- `ingest openclaw`, and `ingest wrap-codex`.
6
+ Covers six sub-commands: `ingest claude`, `ingest codex`, `ingest opencode`,
7
+ `ingest openclaw`, `ingest pi`, and `ingest wrap-codex`.
8
8
 
9
9
  ## When to Use Each
10
10
 
@@ -14,6 +14,7 @@ Covers five sub-commands: `ingest claude`, `ingest codex`, `ingest opencode`,
14
14
  | `ingest codex` | Codex | Batch | Import existing Codex rollout logs |
15
15
  | `ingest opencode` | OpenCode | Batch | Import existing OpenCode sessions |
16
16
  | `ingest openclaw` | OpenClaw | Batch | Import existing OpenClaw agent sessions |
17
+ | `ingest pi` | Pi | Batch | Import existing Pi agent sessions |
17
18
  | `ingest wrap-codex` | Codex | Real-time | Wrap `codex exec` to capture telemetry live |
18
19
 
19
20
  ---
@@ -200,6 +201,55 @@ Writes to:
200
201
 
201
202
  ---
202
203
 
204
+ ## ingest pi
205
+
206
+ Batch ingest Pi agent session histories into the shared JSONL schema.
207
+
208
+ ### Default Command
209
+
210
+ ```bash
211
+ selftune ingest pi
212
+ ```
213
+
214
+ ### Options
215
+
216
+ | Flag | Description |
217
+ | ----------------------- | ------------------------------------------------------------------ |
218
+ | `--sessions-dir <path>` | Override default `~/.pi/agent/sessions/` directory |
219
+ | `--since <date>` | Only ingest sessions modified after this date (e.g., `2026-01-01`) |
220
+ | `--dry-run` | Show what would be ingested without writing to logs |
221
+ | `--force` | Re-ingest all sessions, ignoring the marker file |
222
+ | `--verbose` / `-v` | Show per-session progress during ingestion |
223
+
224
+ ### Source
225
+
226
+ Reads from `~/.pi/agent/sessions/`. Each session file contains Pi agent
227
+ conversation history in JSONL format.
228
+
229
+ ### Output
230
+
231
+ Writes to:
232
+
233
+ - `~/.claude/all_queries_log.jsonl` -- extracted user queries
234
+ - `~/.claude/session_telemetry_log.jsonl` -- per-session metrics with `source: "pi"`
235
+ - `~/.claude/skill_usage_log.jsonl` -- skill triggers with `source: "pi"`
236
+
237
+ ### Steps
238
+
239
+ 1. Run `selftune ingest pi --dry-run` to preview what would be ingested
240
+ 2. Run `selftune ingest pi` to ingest all sessions
241
+ 3. Run `selftune doctor` to confirm logs are healthy
242
+ 4. Run `selftune eval generate --list-skills` to see if the ingested sessions appear
243
+
244
+ ### Notes
245
+
246
+ - Idempotent: uses a marker file to track which sessions have already been ingested.
247
+ Safe to run repeatedly. Use `--force` to re-ingest everything.
248
+ - Skill detection heuristic: identifies skills by checking for `SKILL.md` file reads in
249
+ tool calls and by matching known skill names in assistant text content.
250
+
251
+ ---
252
+
203
253
  ## ingest wrap-codex
204
254
 
205
255
  Wrap `codex exec` with real-time telemetry capture. Drop-in replacement
@@ -269,6 +319,14 @@ through hooks.
269
319
 
270
320
  > Run `selftune ingest openclaw --since 2026-02-01` with an appropriate date.
271
321
 
322
+ **"Ingest Pi sessions"**
323
+
324
+ > Run `selftune ingest pi`. Reads from `~/.pi/agent/sessions/` automatically.
325
+
326
+ **"Import only recent Pi sessions"**
327
+
328
+ > Run `selftune ingest pi --since 2026-02-01` with an appropriate date.
329
+
272
330
  **"Run codex through selftune"**
273
331
 
274
332
  > Use `selftune ingest wrap-codex -- <codex args>` instead of `codex exec <args>` directly.
@@ -6,7 +6,7 @@ Bootstrap selftune for first-time use or after changing environments.
6
6
 
7
7
  - The user asks to set up selftune, configure selftune, or initialize selftune
8
8
  - The agent detects `~/.selftune/config.json` does not exist
9
- - The user has switched agent platforms (Claude Code, Codex, OpenCode)
9
+ - The user has switched agent platforms (Claude Code, Codex, OpenCode, Pi)
10
10
  - The user wants to add hooks for additional platforms (multi-agent setup)
11
11
 
12
12
  ## Default Command
@@ -21,7 +21,7 @@ selftune init --no-alpha [--force]
21
21
 
22
22
  | Flag | Description | Default |
23
23
  | ------------------------- | ------------------------------------------------------------------------- | ------------- |
24
- | `--agent <type>` | Agent platform: `claude_code`, `codex`, `opencode`, `openclaw` | Auto-detected |
24
+ | `--agent <type>` | Agent platform: `claude_code`, `codex`, `opencode`, `openclaw`, `pi` | Auto-detected |
25
25
  | `--cli-path <path>` | Override auto-detected CLI entry-point path | Auto-detected |
26
26
  | `--force` | Reinitialize even if config already exists | Off |
27
27
  | `--no-sync` | Skip historical transcript backfill during init | Sync on |
@@ -146,6 +146,7 @@ CLIs available. Run these checks:
146
146
  which codex 2>/dev/null && echo "codex available"
147
147
  which opencode 2>/dev/null && echo "opencode available"
148
148
  ls ~/Documents/Cline/Hooks/ 2>/dev/null && echo "cline available"
149
+ ls ~/.pi/agent/ 2>/dev/null && echo "pi available"
149
150
  ```
150
151
 
151
152
  If **any** additional platforms are detected, use `AskUserQuestion` listing only
@@ -168,6 +169,7 @@ For each platform the user selects, run the install command:
168
169
  selftune codex install # writes hooks.json entries
169
170
  selftune opencode install # writes shell shim + config entries
170
171
  selftune cline install # creates hook scripts
172
+ selftune pi install # creates extension hook scripts
171
173
  ```
172
174
 
173
175
  Use `--dry-run` first if the user wants to preview. See `Workflows/PlatformHooks.md`
@@ -179,6 +181,7 @@ for platform-specific details.
179
181
  selftune ingest codex # import Codex rollout sessions
180
182
  selftune ingest opencode # import OpenCode sessions from SQLite
181
183
  selftune ingest openclaw # import OpenClaw sessions
184
+ selftune ingest pi # import Pi sessions
182
185
  ```
183
186
 
184
187
  ### 5. Initialize Memory Directory
@@ -221,7 +224,7 @@ reported issues before proceeding.
221
224
 
222
225
  Init automatically runs `selftune sync` to backfill existing session
223
226
  transcripts into the SQLite database. This replays Claude Code transcripts,
224
- Codex rollouts, OpenCode sessions, and OpenClaw sessions so the eval set
227
+ Codex rollouts, OpenCode sessions, OpenClaw sessions, and Pi sessions so the eval set
225
228
  and evolution pipeline have data to work with immediately.
226
229
 
227
230
  The sync step is fail-open — if it encounters errors, init continues.
@@ -426,8 +429,8 @@ retrying with `selftune init --alpha --alpha-email <email> --force`.
426
429
 
427
430
  > Run `selftune init` for the primary agent, then offer to install hooks for
428
431
  > additional detected platforms. Run `selftune codex install`, `selftune opencode install`,
429
- > or `selftune cline install` as needed. All platforms write to the same shared
430
- > log schema — no extra config required.
432
+ > `selftune cline install`, or `selftune pi install` as needed. All platforms
433
+ > write to the same shared log schema — no extra config required.
431
434
 
432
435
  **Hooks not capturing data**
433
436