orizu 0.5.6 → 0.5.8

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.
@@ -0,0 +1,524 @@
1
+ interface ReportCommentPerson {
2
+ name: string
3
+ initials?: string
4
+ color?: string
5
+ }
6
+
7
+ interface ReportCommentAuthor {
8
+ kind?: 'human'
9
+ person?: ReportCommentPerson
10
+ name?: string
11
+ initials?: string
12
+ color?: string
13
+ via?: string
14
+ actor?: 'agent'
15
+ onBehalfOf?: string
16
+ }
17
+
18
+ interface ReportCommentAnchor {
19
+ text: string | null
20
+ startLine: number | null
21
+ endLine: number | null
22
+ }
23
+
24
+ interface ReportCommentReply {
25
+ id: string
26
+ body: string
27
+ author: ReportCommentAuthor
28
+ createdAt: string
29
+ updatedAt: string
30
+ editedAt?: string | null
31
+ }
32
+
33
+ interface ReportCommentThread {
34
+ id: string
35
+ status: 'open' | 'resolved'
36
+ body: string
37
+ anchor: ReportCommentAnchor | null
38
+ author: ReportCommentAuthor
39
+ createdAt: string
40
+ updatedAt: string
41
+ editedAt?: string | null
42
+ createdByUserId?: string | null
43
+ resolvedAt: string | null
44
+ resolvedByUserId: string | null
45
+ replyCount: number
46
+ replies: ReportCommentReply[]
47
+ }
48
+
49
+ interface ReportCommentMutationPayload {
50
+ comment: ReportCommentThread | ReportCommentReply
51
+ }
52
+
53
+ interface ReportCommentsPayload {
54
+ subject?: {
55
+ type: 'prompt_version' | 'optimization_run_report' | 'task_report'
56
+ id: string
57
+ projectId: string
58
+ }
59
+ project?: {
60
+ id: string
61
+ name: string
62
+ slug: string
63
+ teamName: string | null
64
+ teamSlug: string | null
65
+ } | null
66
+ prompt?: {
67
+ id: string
68
+ name: string
69
+ role: string
70
+ description?: string | null
71
+ }
72
+ version?: {
73
+ id: string
74
+ versionNumber?: number
75
+ versionLabel?: string | null
76
+ status?: string | null
77
+ }
78
+ run?: {
79
+ id: string
80
+ }
81
+ task?: {
82
+ id: string
83
+ title?: string | null
84
+ }
85
+ summary: {
86
+ threadCount: number
87
+ openThreadCount: number
88
+ resolvedThreadCount: number
89
+ replyCount: number
90
+ }
91
+ comments: ReportCommentThread[]
92
+ }
93
+
94
+ export interface ReportCommentsCliContext {
95
+ getArg: (name: string) => string | null
96
+ getPositionalArg: (index: number) => string | null
97
+ rejectDashPrefixedOptionValue: (name: string, value: string | null) => void
98
+ resolveProjectSlug: (preferredProject: string | null) => Promise<string>
99
+ readSourceFile: (pathArg: string) => string
100
+ authedFetch: (path: string, init?: RequestInit) => Promise<Response>
101
+ parseJsonResponse: <T>(response: Response, context: string) => Promise<T>
102
+ hasJsonFlag: () => boolean
103
+ printJson: (value: Record<string, unknown>) => void
104
+ printLine: (message?: string) => void
105
+ sanitizeTerminalText: (value: unknown) => string
106
+ }
107
+
108
+ const COMMENTS_TARGET_USAGE =
109
+ 'Use exactly one of --prompt <id-or-name>, --run <run-id>, or --task <task-id>'
110
+
111
+ function reportCommentsUsage(action: string): string {
112
+ const target =
113
+ '(--prompt <id-or-name> --project <team/project> [--label <label> | --version <id>] | --run <run-id> | --task <task-id>)'
114
+ if (action === 'list') {
115
+ return `Usage: orizu comments list ${target} [--json]`
116
+ }
117
+ if (action === 'add') {
118
+ return `Usage: orizu comments add ${target} --body <text|@file> [--anchor <text>] [--lines <start:end>] [--via <name>] [--json]`
119
+ }
120
+ if (action === 'reply') {
121
+ return 'Usage: orizu comments reply <comment-id> --body <text|@file> [--via <name>] [--json]'
122
+ }
123
+ if (action === 'edit') {
124
+ return 'Usage: orizu comments edit <comment-id> --body <text|@file> [--json]'
125
+ }
126
+ return `Usage: orizu comments ${action} <comment-id> [--json]`
127
+ }
128
+
129
+ function compactTerminalText(
130
+ ctx: ReportCommentsCliContext,
131
+ value: string,
132
+ maxLength = 160
133
+ ): string {
134
+ const compact = ctx.sanitizeTerminalText(value).replace(/\s+/g, ' ').trim()
135
+ if (compact.length <= maxLength) {
136
+ return compact
137
+ }
138
+
139
+ return `${compact.slice(0, Math.max(0, maxLength - 1)).trim()}…`
140
+ }
141
+
142
+ async function readReportCommentError(
143
+ ctx: ReportCommentsCliContext,
144
+ response: Response
145
+ ): Promise<string> {
146
+ const status = response.status
147
+ ? `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ''}`
148
+ : 'request failed'
149
+ const contentType = response.headers.get('content-type') || ''
150
+
151
+ if (!contentType.toLowerCase().includes('application/json')) {
152
+ return status
153
+ }
154
+
155
+ try {
156
+ const parsed = await response.clone().json()
157
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
158
+ const error = (parsed as { error?: unknown }).error
159
+ if (typeof error === 'string' && error.trim()) {
160
+ return compactTerminalText(ctx, error, 220)
161
+ }
162
+ }
163
+ } catch {
164
+ // Fall through to the status-only message for malformed JSON errors.
165
+ }
166
+
167
+ return status
168
+ }
169
+
170
+ function printIndentedBody(
171
+ ctx: ReportCommentsCliContext,
172
+ value: string,
173
+ indent: string
174
+ ) {
175
+ const lines = ctx.sanitizeTerminalText(value || '').split(/\r?\n/)
176
+ for (const line of lines) {
177
+ ctx.printLine(`${indent}${line}`)
178
+ }
179
+ }
180
+
181
+ function formatReportCommentAnchor(
182
+ ctx: ReportCommentsCliContext,
183
+ anchor: ReportCommentAnchor | null
184
+ ): string | null {
185
+ if (!anchor) {
186
+ return null
187
+ }
188
+
189
+ const lineLabel = anchor.startLine && anchor.endLine
190
+ ? anchor.startLine === anchor.endLine
191
+ ? `line ${anchor.startLine}`
192
+ : `lines ${anchor.startLine}-${anchor.endLine}`
193
+ : null
194
+ const selectedText = anchor.text ? `"${compactTerminalText(ctx, anchor.text, 180)}"` : null
195
+
196
+ if (lineLabel && selectedText) {
197
+ return `${lineLabel}: ${selectedText}`
198
+ }
199
+ return lineLabel || selectedText
200
+ }
201
+
202
+ function reportCommentAuthorName(author: ReportCommentAuthor | null | undefined): string {
203
+ const personName = author?.person?.name
204
+ const name = personName || author?.name || 'Unknown'
205
+ const via = author?.via ? ` via ${author.via}` : ''
206
+ const agent = author?.actor === 'agent'
207
+ ? author.onBehalfOf
208
+ ? ` (agent on behalf of ${author.onBehalfOf})`
209
+ : ' (agent)'
210
+ : ''
211
+ return `${name}${via}${agent}`
212
+ }
213
+
214
+ function printReportCommentSubject(
215
+ ctx: ReportCommentsCliContext,
216
+ data: ReportCommentsPayload
217
+ ) {
218
+ if (data.prompt && data.version) {
219
+ const versionLabel = data.version.versionLabel || (
220
+ data.version.versionNumber ? `v${data.version.versionNumber}` : data.version.id
221
+ )
222
+ ctx.printLine(`Prompt: ${ctx.sanitizeTerminalText(data.prompt.name)} (${ctx.sanitizeTerminalText(data.prompt.id)})`)
223
+ ctx.printLine(`Version: ${ctx.sanitizeTerminalText(String(versionLabel))} (${ctx.sanitizeTerminalText(data.version.id)})`)
224
+ return
225
+ }
226
+
227
+ if (data.run) {
228
+ ctx.printLine(`Optimization run: ${ctx.sanitizeTerminalText(data.run.id)}`)
229
+ return
230
+ }
231
+
232
+ if (data.task) {
233
+ const title = data.task.title ? `${ctx.sanitizeTerminalText(data.task.title)} ` : ''
234
+ ctx.printLine(`Task: ${title}(${ctx.sanitizeTerminalText(data.task.id)})`)
235
+ return
236
+ }
237
+
238
+ if (data.subject) {
239
+ ctx.printLine(`Subject: ${ctx.sanitizeTerminalText(data.subject.type)} ${ctx.sanitizeTerminalText(data.subject.id)}`)
240
+ }
241
+ }
242
+
243
+ function printReportComments(
244
+ ctx: ReportCommentsCliContext,
245
+ data: ReportCommentsPayload
246
+ ) {
247
+ printReportCommentSubject(ctx, data)
248
+ ctx.printLine(
249
+ `Comments: ${data.summary.threadCount} thread${data.summary.threadCount === 1 ? '' : 's'} ` +
250
+ `(${data.summary.openThreadCount} open, ${data.summary.resolvedThreadCount} resolved, ${data.summary.replyCount} replies)`
251
+ )
252
+
253
+ if (data.comments.length === 0) {
254
+ ctx.printLine('\nNo comments found for this report.')
255
+ return
256
+ }
257
+
258
+ for (const [index, thread] of data.comments.entries()) {
259
+ const authorName = reportCommentAuthorName(thread.author)
260
+ const anchor = formatReportCommentAnchor(ctx, thread.anchor)
261
+ ctx.printLine('')
262
+ ctx.printLine(
263
+ `${index + 1}. [${thread.status}] ${ctx.sanitizeTerminalText(thread.id)} · ` +
264
+ `${ctx.sanitizeTerminalText(authorName)} · ${ctx.sanitizeTerminalText(thread.createdAt)}`
265
+ )
266
+ if (thread.editedAt) {
267
+ ctx.printLine(` Edited: ${ctx.sanitizeTerminalText(thread.editedAt)}`)
268
+ }
269
+ if (anchor) {
270
+ ctx.printLine(` Selection: ${anchor}`)
271
+ }
272
+ printIndentedBody(ctx, thread.body, ' ')
273
+
274
+ if (thread.replies.length > 0) {
275
+ ctx.printLine(` Replies (${thread.replies.length})`)
276
+ for (const reply of thread.replies) {
277
+ const replyAuthor = reportCommentAuthorName(reply.author)
278
+ ctx.printLine(
279
+ ` - ${ctx.sanitizeTerminalText(reply.id)} · ` +
280
+ `${ctx.sanitizeTerminalText(replyAuthor)} · ${ctx.sanitizeTerminalText(reply.createdAt)}`
281
+ )
282
+ if (reply.editedAt) {
283
+ ctx.printLine(` Edited: ${ctx.sanitizeTerminalText(reply.editedAt)}`)
284
+ }
285
+ printIndentedBody(ctx, reply.body, ' ')
286
+ }
287
+ }
288
+ }
289
+ }
290
+
291
+ async function reportCommentsTargetParams(
292
+ ctx: ReportCommentsCliContext,
293
+ action: string
294
+ ): Promise<URLSearchParams> {
295
+ const promptRef = ctx.getArg('--prompt')
296
+ const runId = ctx.getArg('--run') || ctx.getArg('--run-id')
297
+ const taskId = ctx.getArg('--task')
298
+
299
+ ctx.rejectDashPrefixedOptionValue('--prompt', promptRef)
300
+ ctx.rejectDashPrefixedOptionValue('--run', runId)
301
+ ctx.rejectDashPrefixedOptionValue('--task', taskId)
302
+
303
+ const present = [
304
+ promptRef ? 'prompt' : null,
305
+ runId ? 'run' : null,
306
+ taskId ? 'task' : null,
307
+ ].filter(Boolean)
308
+
309
+ if (present.length !== 1) {
310
+ throw new Error(`${reportCommentsUsage(action)}\n${COMMENTS_TARGET_USAGE}`)
311
+ }
312
+
313
+ const params = new URLSearchParams()
314
+ if (promptRef) {
315
+ const project = ctx.getArg('--project') || await ctx.resolveProjectSlug(null)
316
+ const label = ctx.getArg('--label')
317
+ const version = ctx.getArg('--version')
318
+ ctx.rejectDashPrefixedOptionValue('--project', project)
319
+ ctx.rejectDashPrefixedOptionValue('--label', label)
320
+ ctx.rejectDashPrefixedOptionValue('--version', version)
321
+ if (label && version) {
322
+ throw new Error('Use either --label or --version, not both')
323
+ }
324
+ params.set('prompt', promptRef)
325
+ params.set('project', project)
326
+ if (label) params.set('label', label)
327
+ if (version) params.set('version', version)
328
+ return params
329
+ }
330
+
331
+ if (runId) {
332
+ params.set('run', runId)
333
+ return params
334
+ }
335
+
336
+ params.set('task', taskId as string)
337
+ return params
338
+ }
339
+
340
+ function readReportCommentBodyInput(ctx: ReportCommentsCliContext, action: string): string {
341
+ const body = ctx.getArg('--body')
342
+ ctx.rejectDashPrefixedOptionValue('--body', body)
343
+ if (!body) {
344
+ throw new Error(reportCommentsUsage(action))
345
+ }
346
+ if (body === '@') {
347
+ throw new Error('Usage: --body <text|@file>')
348
+ }
349
+
350
+ const value = body.startsWith('@') ? ctx.readSourceFile(body.slice(1)) : body
351
+ if (!value.trim()) {
352
+ throw new Error('Comment body must not be blank')
353
+ }
354
+ return value
355
+ }
356
+
357
+ function readReportCommentAnchorInput(ctx: ReportCommentsCliContext): ReportCommentAnchor | null {
358
+ const anchor = ctx.getArg('--anchor')
359
+ const lines = ctx.getArg('--lines')
360
+ ctx.rejectDashPrefixedOptionValue('--anchor', anchor)
361
+ ctx.rejectDashPrefixedOptionValue('--lines', lines)
362
+
363
+ let startLine: number | null = null
364
+ let endLine: number | null = null
365
+ if (lines) {
366
+ const match = lines.match(/^(\d+):(\d+)$/)
367
+ if (!match) {
368
+ throw new Error('--lines must use format <start:end>')
369
+ }
370
+ startLine = Number(match[1])
371
+ endLine = Number(match[2])
372
+ if (!Number.isInteger(startLine) || !Number.isInteger(endLine) || startLine < 1 || endLine < startLine) {
373
+ throw new Error('--lines must contain positive integers where end is greater than or equal to start')
374
+ }
375
+ }
376
+
377
+ if (!anchor && startLine === null) {
378
+ return null
379
+ }
380
+
381
+ return {
382
+ text: anchor ? anchor.trim() : null,
383
+ startLine,
384
+ endLine,
385
+ }
386
+ }
387
+
388
+ function readReportCommentViaInput(ctx: ReportCommentsCliContext): string | undefined {
389
+ const via = ctx.getArg('--via')
390
+ ctx.rejectDashPrefixedOptionValue('--via', via)
391
+ return via?.trim() || undefined
392
+ }
393
+
394
+ async function listReportComments(ctx: ReportCommentsCliContext) {
395
+ const params = await reportCommentsTargetParams(ctx, 'list')
396
+ const response = await ctx.authedFetch(`/api/cli/report-comments?${params.toString()}`)
397
+ if (!response.ok) {
398
+ throw new Error(`Failed to fetch report comments: ${await readReportCommentError(ctx, response)}`)
399
+ }
400
+
401
+ const data = await ctx.parseJsonResponse<ReportCommentsPayload>(response, 'Report comments')
402
+ if (ctx.hasJsonFlag()) {
403
+ ctx.printJson(data as unknown as Record<string, unknown>)
404
+ return
405
+ }
406
+
407
+ printReportComments(ctx, data)
408
+ }
409
+
410
+ async function addReportComment(ctx: ReportCommentsCliContext) {
411
+ const params = await reportCommentsTargetParams(ctx, 'add')
412
+ const body = readReportCommentBodyInput(ctx, 'add')
413
+ const response = await ctx.authedFetch(`/api/cli/report-comments?${params.toString()}`, {
414
+ method: 'POST',
415
+ headers: { 'Content-Type': 'application/json' },
416
+ body: JSON.stringify({
417
+ body,
418
+ via: readReportCommentViaInput(ctx),
419
+ anchor: readReportCommentAnchorInput(ctx),
420
+ }),
421
+ })
422
+
423
+ if (!response.ok) {
424
+ throw new Error(`Failed to add report comment: ${await readReportCommentError(ctx, response)}`)
425
+ }
426
+
427
+ const data = await ctx.parseJsonResponse<ReportCommentMutationPayload>(response, 'Report comment add')
428
+ if (ctx.hasJsonFlag()) {
429
+ ctx.printJson(data as unknown as Record<string, unknown>)
430
+ return
431
+ }
432
+ ctx.printLine(`Added comment ${ctx.sanitizeTerminalText(data.comment.id)}`)
433
+ }
434
+
435
+ async function replyReportComment(ctx: ReportCommentsCliContext) {
436
+ const commentId = ctx.getPositionalArg(2)
437
+ if (!commentId) {
438
+ throw new Error(reportCommentsUsage('reply'))
439
+ }
440
+
441
+ const response = await ctx.authedFetch(`/api/cli/report-comments/${encodeURIComponent(commentId)}`, {
442
+ method: 'POST',
443
+ headers: { 'Content-Type': 'application/json' },
444
+ body: JSON.stringify({
445
+ body: readReportCommentBodyInput(ctx, 'reply'),
446
+ via: readReportCommentViaInput(ctx),
447
+ }),
448
+ })
449
+
450
+ if (!response.ok) {
451
+ throw new Error(`Failed to reply to report comment: ${await readReportCommentError(ctx, response)}`)
452
+ }
453
+
454
+ const data = await ctx.parseJsonResponse<ReportCommentMutationPayload>(response, 'Report comment reply')
455
+ if (ctx.hasJsonFlag()) {
456
+ ctx.printJson(data as unknown as Record<string, unknown>)
457
+ return
458
+ }
459
+ ctx.printLine(`Added reply ${ctx.sanitizeTerminalText(data.comment.id)} to ${ctx.sanitizeTerminalText(commentId)}`)
460
+ }
461
+
462
+ async function updateReportComment(
463
+ ctx: ReportCommentsCliContext,
464
+ action: 'resolve' | 'unresolve' | 'edit'
465
+ ) {
466
+ const commentId = ctx.getPositionalArg(2)
467
+ if (!commentId) {
468
+ throw new Error(reportCommentsUsage(action))
469
+ }
470
+
471
+ const payload = action === 'edit'
472
+ ? { body: readReportCommentBodyInput(ctx, 'edit') }
473
+ : { resolved: action === 'resolve' }
474
+
475
+ const response = await ctx.authedFetch(`/api/cli/report-comments/${encodeURIComponent(commentId)}`, {
476
+ method: 'PATCH',
477
+ headers: { 'Content-Type': 'application/json' },
478
+ body: JSON.stringify(payload),
479
+ })
480
+
481
+ if (!response.ok) {
482
+ throw new Error(`Failed to ${action} report comment: ${await readReportCommentError(ctx, response)}`)
483
+ }
484
+
485
+ const data = await ctx.parseJsonResponse<ReportCommentMutationPayload>(response, `Report comment ${action}`)
486
+ if (ctx.hasJsonFlag()) {
487
+ ctx.printJson(data as unknown as Record<string, unknown>)
488
+ return
489
+ }
490
+
491
+ const verb = action === 'unresolve' ? 'Reopened' : action === 'edit' ? 'Edited' : 'Resolved'
492
+ ctx.printLine(`${verb} comment ${ctx.sanitizeTerminalText(data.comment.id)}`)
493
+ }
494
+
495
+ export async function reportCommentsCommand(
496
+ action: string | undefined,
497
+ ctx: ReportCommentsCliContext
498
+ ) {
499
+ if (action === 'list') {
500
+ await listReportComments(ctx)
501
+ return
502
+ }
503
+ if (action === 'add') {
504
+ await addReportComment(ctx)
505
+ return
506
+ }
507
+ if (action === 'reply') {
508
+ await replyReportComment(ctx)
509
+ return
510
+ }
511
+ if (action === 'resolve' || action === 'unresolve' || action === 'edit') {
512
+ await updateReportComment(ctx, action)
513
+ return
514
+ }
515
+ throw new Error(
516
+ 'Usage: orizu comments <list|add|reply|resolve|unresolve|edit> ...'
517
+ )
518
+ }
519
+
520
+ export function throwDeprecatedPromptCommentsCommand(): never {
521
+ throw new Error(
522
+ 'orizu prompts comments has moved. Use `orizu comments list --prompt <prompt-id-or-name> --project <team/project> [--label <label> | --version <id>]`.'
523
+ )
524
+ }
@@ -28,6 +28,8 @@ export const SKILL_INSTALL_TARGETS = [
28
28
  'codex-project',
29
29
  'claude-user',
30
30
  'claude-project',
31
+ 'opencode-user',
32
+ 'opencode-project',
31
33
  'agents-md',
32
34
  ] as const
33
35
 
@@ -35,7 +37,7 @@ export type SkillInstallTarget = typeof SKILL_INSTALL_TARGETS[number]
35
37
 
36
38
  export const SKILL_META_FILENAME = '.orizu-skill-meta.json'
37
39
 
38
- export const SKILL_INSTALL_AGENTS = ['claude', 'codex'] as const
40
+ export const SKILL_INSTALL_AGENTS = ['claude', 'codex', 'opencode'] as const
39
41
 
40
42
  export type SkillInstallAgent = typeof SKILL_INSTALL_AGENTS[number]
41
43
 
@@ -47,6 +49,7 @@ const PROJECT_LEVEL_TARGETS: readonly SkillInstallTarget[] = [
47
49
  'agents-project',
48
50
  'codex-project',
49
51
  'claude-project',
52
+ 'opencode-project',
50
53
  ]
51
54
 
52
55
  export interface SkillInstallOptions {
@@ -218,6 +221,17 @@ export function getSkillInstallPath(
218
221
  return resolve(cwd, '.claude', 'skills', SKILL_NAME)
219
222
  }
220
223
 
224
+ // OpenCode discovers user skills under XDG config (~/.config/opencode/skills)
225
+ // and project skills under .opencode/skills (ALI-1044). The copy/link machinery
226
+ // is agent-neutral; only the destination path differs.
227
+ if (target === 'opencode-user') {
228
+ return resolve(home, '.config', 'opencode', 'skills', SKILL_NAME)
229
+ }
230
+
231
+ if (target === 'opencode-project') {
232
+ return resolve(cwd, '.opencode', 'skills', SKILL_NAME)
233
+ }
234
+
221
235
  return resolve(cwd, 'AGENTS.md')
222
236
  }
223
237
 
@@ -228,6 +242,9 @@ export function getTargetForAgent(
228
242
  if (agent === 'claude') {
229
243
  return scope === 'global' ? 'claude-user' : 'claude-project'
230
244
  }
245
+ if (agent === 'opencode') {
246
+ return scope === 'global' ? 'opencode-user' : 'opencode-project'
247
+ }
231
248
  return scope === 'global' ? 'codex-user' : 'agents-project'
232
249
  }
233
250
 
@@ -105,7 +105,7 @@ Deeper: `references/primer.md` (Step 2); `references/cli-reference.md` (apps + t
105
105
 
106
106
  ## 3. Judge — turn labels into automated evaluators
107
107
 
108
- Use the Phase 0 prompt control plane when the user wants judges stored in Orizu as versioned prompt artifacts, runner zips, scorer definitions, and submitted score results. Read **`references/prompt-control-plane.md`** before using those commands. When the user mentions prompt feedback, prompt comments, or asks what to focus on for the next prompt version, inspect comment threads with `orizu prompts comments <prompt-id-or-name> --project <team>/<project>` before editing or pushing.
108
+ Use the Phase 0 prompt control plane when the user wants judges stored in Orizu as versioned prompt artifacts, runner zips, scorer definitions, and submitted score results. Read **`references/prompt-control-plane.md`** before using those commands. When the user mentions prompt feedback, prompt comments, or asks what to focus on for the next prompt version, inspect comment threads with `orizu comments list --prompt <prompt-id-or-name> --project <team>/<project>` before editing or pushing.
109
109
 
110
110
  Judge construction details are still useful when authoring the evaluator itself.
111
111
 
@@ -192,4 +192,11 @@ Detailed walkthrough — GEPA mechanics, Orizu-tracked optimization, optional DS
192
192
  - Prompt control-plane commands should use ids for dataset versions, split sets, prompt versions, scorer versions, runner versions, optimizer versions, and optimization runs.
193
193
  - Optimization exports default to `<run-id>.optimization.json`; prefer the existing `logs/<run-id>` directory from `run-gepa` when it is available because it contains the full local trace without needing server rehydration.
194
194
  - When ending an optimization run, attach a markdown report with `--report-file` when possible. Use `references/optimization-reports.md` for what to include.
195
- - Use `orizu prompts comments <prompt-id-or-name> --project <team>/<project> [--label <label> | --version <id>] [--json]` to list prompt-level discussion threads with open/resolved status, selected text/line context, and replies.
195
+ - Use `orizu comments list --prompt <prompt-id-or-name> --project <team>/<project> [--label <label> | --version <id>] [--json]` to list prompt-level discussion threads with open/resolved status, selected text/line context, and replies.
196
+
197
+ # Where things live
198
+
199
+ - **Orizu is the source of truth for run metadata and pointers**: production/default prompt/scorer/runner pointers, version lineage, score runs, optimization runs, and report history all live in Orizu — query them with `orizu ...` commands (e.g. `orizu prompts list`, `orizu prompts versions`, `orizu runs ...`), never by reading repo files.
200
+ - **The repo is the working set (files only)**: source, configs, `App.tsx`, schemas, and local traces under `logs/<run-id>`. It is the scratch space you edit and commit; it does NOT hold the canonical pointer/run state — that is in Orizu.
201
+ - **Hosted sessions ship a pre-authenticated CLI**: inside a hosted agent sandbox the `orizu` CLI is already authenticated via `ORIZU_TOKEN_FILE` (with `ORIZU_BASE_URL` pointing at the API). You do NOT run `orizu login` — just call `orizu ...`. The bearer carries a **team-curator READ scope**: you can read projects, datasets (+ content/artifact bytes), prompts, scorers, runners/optimizers, runs, and reports across your own team, and execute runs / submit scores / create artifacts / create promotion manifests as the agent actor.
202
+ - **Human-only actions will 403**: manifest approve / reject / apply, production and default pointer flips, and team/member/billing/integration admin are deliberately outside the agent envelope. Do not attempt them from a hosted session — they return 403 by design. Prepare a promotion manifest and hand it to a human curator to approve and apply.
@@ -350,7 +350,7 @@ orizu --local prompts restore <prompt-id-or-name> --project <team>/<project>
350
350
  List prompt comment threads for the latest version, or a specific label/version:
351
351
 
352
352
  ```bash
353
- orizu --local prompts comments <prompt-id-or-name> \
353
+ orizu --local comments list --prompt <prompt-id-or-name> \
354
354
  --project <team>/<project> \
355
355
  [--label production | --version <prompt-version-id>] \
356
356
  [--json]