@lumenflow/cli 5.3.2 → 5.5.0

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 (71) hide show
  1. package/README.md +20 -18
  2. package/dist/agent-session.js +21 -0
  3. package/dist/agent-session.js.map +1 -1
  4. package/dist/commands/integrate.js +25 -1
  5. package/dist/commands/integrate.js.map +1 -1
  6. package/dist/gate-defaults.js +154 -9
  7. package/dist/gate-defaults.js.map +1 -1
  8. package/dist/gate-registry.js.map +1 -1
  9. package/dist/gates-runners.js +358 -0
  10. package/dist/gates-runners.js.map +1 -1
  11. package/dist/gates.js +347 -3
  12. package/dist/gates.js.map +1 -1
  13. package/dist/hooks/enforcement-generator.js +14 -8
  14. package/dist/hooks/enforcement-generator.js.map +1 -1
  15. package/dist/hooks/enforcement-sync.js +2 -1
  16. package/dist/hooks/enforcement-sync.js.map +1 -1
  17. package/dist/hooks/generators/index.js +1 -0
  18. package/dist/hooks/generators/index.js.map +1 -1
  19. package/dist/hooks/generators/signal-received.js +4 -0
  20. package/dist/hooks/generators/signal-received.js.map +1 -0
  21. package/dist/mem-converged.js +101 -0
  22. package/dist/mem-converged.js.map +1 -0
  23. package/dist/mem-inbox.js +85 -22
  24. package/dist/mem-inbox.js.map +1 -1
  25. package/dist/mem-roster.js +11 -1
  26. package/dist/mem-roster.js.map +1 -1
  27. package/dist/mem-signal.js +162 -16
  28. package/dist/mem-signal.js.map +1 -1
  29. package/dist/mem-watch.js +207 -0
  30. package/dist/mem-watch.js.map +1 -0
  31. package/dist/metrics-cli.js +19 -2
  32. package/dist/metrics-cli.js.map +1 -1
  33. package/dist/metrics-snapshot.js +25 -2
  34. package/dist/metrics-snapshot.js.map +1 -1
  35. package/dist/public-manifest.js +14 -0
  36. package/dist/public-manifest.js.map +1 -1
  37. package/dist/session-cross-link.js +14 -2
  38. package/dist/session-cross-link.js.map +1 -1
  39. package/dist/sidecar-manager.js +25 -0
  40. package/dist/sidecar-manager.js.map +1 -1
  41. package/dist/signal-hook.js +351 -0
  42. package/dist/signal-hook.js.map +1 -0
  43. package/dist/wu-done-gates.js +112 -3
  44. package/dist/wu-done-gates.js.map +1 -1
  45. package/dist/wu-done.js +30 -6
  46. package/dist/wu-done.js.map +1 -1
  47. package/dist/wu-prep.js +185 -2
  48. package/dist/wu-prep.js.map +1 -1
  49. package/dist/wu-spawn-prompt-builders.js.map +1 -1
  50. package/dist/wu-spawn-strategy-resolver.js +46 -4
  51. package/dist/wu-spawn-strategy-resolver.js.map +1 -1
  52. package/package.json +13 -11
  53. package/packs/agent-runtime/auto-session-integration.ts +14 -0
  54. package/packs/agent-runtime/package.json +1 -1
  55. package/packs/agent-runtime/session-schema.ts +44 -0
  56. package/packs/sidekick/package.json +1 -1
  57. package/packs/software-delivery/manifest.ts +3 -0
  58. package/packs/software-delivery/manifest.yaml +7 -0
  59. package/packs/software-delivery/package.json +1 -1
  60. package/packs/software-delivery/src/constants/wu-cli-constants.ts +12 -0
  61. package/packs/software-delivery/tool-impl/memory-tools.ts +56 -1
  62. package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +1 -0
  63. package/templates/core/AGENTS.md.template +98 -8
  64. package/templates/core/LUMENFLOW.md.template +197 -19
  65. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +0 -5
  66. package/templates/core/ai/onboarding/agent-safety-card.md.template +63 -1
  67. package/templates/core/ai/onboarding/initiative-orchestration.md.template +4 -0
  68. package/templates/core/ai/onboarding/release-process.md.template +7 -7
  69. package/templates/core/ai/onboarding/vendor-support.md.template +74 -10
  70. package/templates/vendors/claude/.claude/skills/frontend-design/SKILL.md.template +1 -1
  71. package/templates/vendors/claude/.claude/skills/wu-lifecycle/SKILL.md.template +28 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/cli",
3
- "version": "5.3.2",
3
+ "version": "5.5.0",
4
4
  "description": "Command-line interface for LumenFlow workflow framework",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -98,6 +98,7 @@
98
98
  "lumenflow-validate": "./dist/validate.js",
99
99
  "mem-checkpoint": "./dist/mem-checkpoint.js",
100
100
  "mem-cleanup": "./dist/mem-cleanup.js",
101
+ "mem-converged": "./dist/mem-converged.js",
101
102
  "mem-context": "./dist/mem-context.js",
102
103
  "mem-create": "./dist/mem-create.js",
103
104
  "mem-delete": "./dist/mem-delete.js",
@@ -111,6 +112,7 @@
111
112
  "mem-start": "./dist/mem-start.js",
112
113
  "mem-summarize": "./dist/mem-summarize.js",
113
114
  "mem-triage": "./dist/mem-triage.js",
115
+ "mem-watch": "./dist/mem-watch.js",
114
116
  "metrics": "./dist/metrics-cli.js",
115
117
  "metrics-snapshot": "./dist/metrics-snapshot.js",
116
118
  "onboard": "./dist/onboard.js",
@@ -198,16 +200,16 @@
198
200
  "xstate": "^5.28.0",
199
201
  "yaml": "^2.8.2",
200
202
  "zod": "^4.3.6",
201
- "@lumenflow/agent": "5.3.2",
202
- "@lumenflow/control-plane-sdk": "5.3.2",
203
- "@lumenflow/host": "^5.3.2",
204
- "@lumenflow/initiatives": "5.3.2",
205
- "@lumenflow/kernel": "5.3.2",
206
- "@lumenflow/metrics": "5.3.2",
207
- "@lumenflow/memory": "5.3.2",
208
- "@lumenflow/packs-agent-runtime": "^5.3.2",
209
- "@lumenflow/core": "5.3.2",
210
- "@lumenflow/packs-software-delivery": "^5.3.2"
203
+ "@lumenflow/agent": "5.5.0",
204
+ "@lumenflow/host": "^5.5.0",
205
+ "@lumenflow/control-plane-sdk": "5.5.0",
206
+ "@lumenflow/initiatives": "5.5.0",
207
+ "@lumenflow/core": "5.5.0",
208
+ "@lumenflow/kernel": "5.5.0",
209
+ "@lumenflow/packs-agent-runtime": "^5.5.0",
210
+ "@lumenflow/metrics": "5.5.0",
211
+ "@lumenflow/memory": "5.5.0",
212
+ "@lumenflow/packs-software-delivery": "^5.5.0"
211
213
  },
212
214
  "devDependencies": {
213
215
  "@vitest/coverage-v8": "^4.0.18",
@@ -83,6 +83,10 @@ interface SessionFileData {
83
83
  /** ADR-014 extension 2 — which skill bundle the agent identifies as carrying (WU-2754). */
84
84
  specialty_profile?: string;
85
85
  display_name?: string;
86
+ /** Stable explicit A2A reader identity. Format hint: <owner>:<role>:<purpose>. */
87
+ agent_identity?: string;
88
+ /** Reserved cloud workspace/tenant scope slot; unused by local runtime. */
89
+ tenant_id?: string;
86
90
  /** ADR-014 extension 2 — parent delegation registry reference (WU-2754). */
87
91
  delegation_id?: string;
88
92
  }
@@ -455,6 +459,10 @@ interface StartSessionOptions {
455
459
  /** ADR-014 specialty_profile for this session (e.g. 'delivery'). */
456
460
  specialtyProfile?: string;
457
461
  displayName?: string;
462
+ /** Explicit stable A2A reader identity. Format hint: <owner>:<role>:<purpose>. */
463
+ agentIdentity?: string;
464
+ /** Reserved cloud workspace/tenant scope slot; unused by local runtime. */
465
+ tenantId?: string;
458
466
  /** Parent delegation-registry record reference (dlg-XXXX). */
459
467
  delegationId?: string;
460
468
  }
@@ -511,6 +519,8 @@ export async function startSessionForWU(options: StartSessionOptions): Promise<S
511
519
  lifecycleRole,
512
520
  specialtyProfile,
513
521
  displayName,
522
+ agentIdentity,
523
+ tenantId,
514
524
  delegationId,
515
525
  } = options;
516
526
 
@@ -542,6 +552,8 @@ export async function startSessionForWU(options: StartSessionOptions): Promise<S
542
552
  lifecycle_role: lifecycleRole,
543
553
  specialty_profile: specialtyProfile,
544
554
  display_name: displayName,
555
+ agent_identity: agentIdentity,
556
+ tenant_id: tenantId,
545
557
  delegation_id: delegationId,
546
558
  });
547
559
  const resolvedDisplayName = roleAxes.display_name ?? acquireDisplayName(workspaceRoot, sessionId);
@@ -564,6 +576,8 @@ export async function startSessionForWU(options: StartSessionOptions): Promise<S
564
576
  lifecycle_role: roleAxes.lifecycle_role,
565
577
  specialty_profile: roleAxes.specialty_profile,
566
578
  display_name: resolvedDisplayName,
579
+ ...(roleAxes.agent_identity ? { agent_identity: roleAxes.agent_identity } : {}),
580
+ ...(roleAxes.tenant_id ? { tenant_id: roleAxes.tenant_id } : {}),
567
581
  ...(roleAxes.delegation_id ? { delegation_id: roleAxes.delegation_id } : {}),
568
582
  };
569
583
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/packs-agent-runtime",
3
- "version": "5.3.2",
3
+ "version": "5.5.0",
4
4
  "description": "Agent runtime pack scaffold for LumenFlow — governed model-turn execution, pack config, and provider capability baselines",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -70,6 +70,7 @@ export const DISPLAY_NAME_POOL_RELATIVE_PATH = '.lumenflow/agents/display-name-p
70
70
  export const DISPLAY_NAME_RESERVATIONS_RELATIVE_PATH =
71
71
  '.lumenflow/state/display-name-reservations.jsonl';
72
72
  export const DISPLAY_NAME_RESERVATION_TTL_HOURS = 12;
73
+ export const AGENT_IDENTITY_MIN_LENGTH = 3;
73
74
 
74
75
  /** Regex for delegation_id references back into delegation registry. */
75
76
  export const DELEGATION_ID_PATTERN = /^dlg-[0-9a-f]{4}$/;
@@ -93,6 +94,14 @@ export const SessionRoleAxesSchema = z.object({
93
94
  .optional(),
94
95
  });
95
96
 
97
+ const AgentIdentitySchema = z
98
+ .string()
99
+ .trim()
100
+ .min(AGENT_IDENTITY_MIN_LENGTH, {
101
+ message: `agent_identity must be at least ${AGENT_IDENTITY_MIN_LENGTH} characters`,
102
+ });
103
+ const TenantIdSchema = z.string().trim().min(1, { message: 'tenant_id must be non-empty' });
104
+
96
105
  /**
97
106
  * Base session schema — shared fields across v1 and v2.
98
107
  *
@@ -104,6 +113,8 @@ const SessionRecordBaseSchema = z.object({
104
113
  session_id: z.string().min(1),
105
114
  wu_id: z.string().min(1),
106
115
  started: z.string().min(1),
116
+ agent_identity: AgentIdentitySchema.optional(),
117
+ tenant_id: TenantIdSchema.optional(),
107
118
  });
108
119
 
109
120
  /**
@@ -172,11 +183,15 @@ export function withV2RoleDefaults(input: {
172
183
  specialty_profile?: string | null;
173
184
  display_name?: string | null;
174
185
  delegation_id?: string | null;
186
+ agent_identity?: string | null;
187
+ tenant_id?: string | null;
175
188
  }): {
176
189
  lifecycle_role: string;
177
190
  specialty_profile: string;
178
191
  display_name?: string;
179
192
  delegation_id?: string;
193
+ agent_identity?: string;
194
+ tenant_id?: string;
180
195
  } {
181
196
  const lifecycle_role =
182
197
  typeof input.lifecycle_role === 'string' && input.lifecycle_role.trim().length > 0
@@ -194,11 +209,14 @@ export function withV2RoleDefaults(input: {
194
209
  typeof input.display_name === 'string' && input.display_name.trim().length > 0
195
210
  ? input.display_name.trim()
196
211
  : undefined;
212
+ const identityFields = normalizeOptionalSessionIdentityFields(input);
197
213
  const out: {
198
214
  lifecycle_role: string;
199
215
  specialty_profile: string;
200
216
  display_name?: string;
201
217
  delegation_id?: string;
218
+ agent_identity?: string;
219
+ tenant_id?: string;
202
220
  } = {
203
221
  lifecycle_role,
204
222
  specialty_profile,
@@ -209,6 +227,32 @@ export function withV2RoleDefaults(input: {
209
227
  if (delegation_id) {
210
228
  out.delegation_id = delegation_id;
211
229
  }
230
+ if (identityFields.agent_identity) {
231
+ out.agent_identity = identityFields.agent_identity;
232
+ }
233
+ if (identityFields.tenant_id) {
234
+ out.tenant_id = identityFields.tenant_id;
235
+ }
236
+ return out;
237
+ }
238
+
239
+ export function normalizeOptionalSessionIdentityFields(input: {
240
+ agent_identity?: string | null;
241
+ tenant_id?: string | null;
242
+ }): {
243
+ agent_identity?: string;
244
+ tenant_id?: string;
245
+ } {
246
+ const out: {
247
+ agent_identity?: string;
248
+ tenant_id?: string;
249
+ } = {};
250
+ if (typeof input.agent_identity === 'string' && input.agent_identity.trim().length > 0) {
251
+ out.agent_identity = AgentIdentitySchema.parse(input.agent_identity);
252
+ }
253
+ if (typeof input.tenant_id === 'string' && input.tenant_id.trim().length > 0) {
254
+ out.tenant_id = TenantIdSchema.parse(input.tenant_id);
255
+ }
212
256
  return out;
213
257
  }
214
258
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/packs-sidekick",
3
- "version": "5.3.2",
3
+ "version": "5.5.0",
4
4
  "description": "Sidekick personal assistant pack for LumenFlow — 16 tools for task management, typed memory, channels, routines, and audit",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -140,6 +140,7 @@ const MEM_DELETE_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memDeleteTool';
140
140
  const MEM_EXPORT_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memExportTool';
141
141
  const MEM_INBOX_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memInboxTool';
142
142
  const MEM_SIGNAL_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memSignalTool';
143
+ const MEM_CONVERGED_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memConvergedTool';
143
144
  const MEM_SUMMARIZE_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memSummarizeTool';
144
145
  const MEM_TRIAGE_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memTriageTool';
145
146
  const MEM_RECOVER_TOOL_ENTRY = 'tool-impl/memory-tools.ts#memRecoverTool';
@@ -245,6 +246,7 @@ const TOOL_PERMISSIONS = {
245
246
  'wu:validate': 'read',
246
247
  'mem:checkpoint': 'write',
247
248
  'mem:cleanup': 'write',
249
+ 'mem:converged': 'read',
248
250
  'mem:context': 'read',
249
251
  'mem:create': 'write',
250
252
  'mem:delete': 'write',
@@ -371,6 +373,7 @@ const TOOL_ENTRY_OVERRIDES: Partial<Record<ToolName, string>> = {
371
373
  'mem:export': MEM_EXPORT_TOOL_ENTRY,
372
374
  'mem:inbox': MEM_INBOX_TOOL_ENTRY,
373
375
  'mem:signal': MEM_SIGNAL_TOOL_ENTRY,
376
+ 'mem:converged': MEM_CONVERGED_TOOL_ENTRY,
374
377
  'mem:summarize': MEM_SUMMARIZE_TOOL_ENTRY,
375
378
  'mem:triage': MEM_TRIAGE_TOOL_ENTRY,
376
379
  'mem:recover': MEM_RECOVER_TOOL_ENTRY,
@@ -244,6 +244,13 @@ tools:
244
244
  entry: tool-impl/memory-tools.ts#memCleanupTool
245
245
  permission: write
246
246
  required_scopes: *softwareDeliveryWriteScopes
247
+ - name: mem:converged
248
+ entry: tool-impl/memory-tools.ts#memConvergedTool
249
+ permission: read
250
+ required_scopes:
251
+ - type: path
252
+ pattern: '**'
253
+ access: read
247
254
  - name: mem:context
248
255
  entry: tool-impl/memory-tools.ts#memContextTool
249
256
  permission: read
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/packs-software-delivery",
3
- "version": "5.3.2",
3
+ "version": "5.5.0",
4
4
  "description": "Software delivery pack for LumenFlow — work units, gates, lanes, initiatives, and agent coordination",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -87,6 +87,10 @@ export const SCRIPTS = {
87
87
  LINT: 'lint',
88
88
  TEST: 'test',
89
89
  TEST_UNIT: 'test:unit',
90
+ /** WU-2927: opt-in local-prep integration-test gate script */
91
+ TEST_INTEGRATION: 'test:integration',
92
+ /** WU-2927: opt-in local-prep e2e-smoke gate script */
93
+ TEST_E2E: 'test:e2e',
90
94
  BUILD: 'build',
91
95
  FORMAT: 'format',
92
96
  FORMAT_CHECK: 'format:check',
@@ -137,6 +141,10 @@ export const GATE_NAMES = {
137
141
  LANE_HEALTH: 'lane-health',
138
142
  /** WU-1315: Onboarding smoke test (init + wu:create validation) */
139
143
  ONBOARDING_SMOKE_TEST: 'onboarding-smoke-test',
144
+ /** WU-2927: Opt-in local-prep build gate (wraps SCRIPTS.BUILD) */
145
+ BUILD: 'build',
146
+ /** WU-2927: Opt-in local-prep Playwright smoke gate */
147
+ E2E_SMOKE: 'e2e-smoke',
140
148
  };
141
149
 
142
150
  /**
@@ -159,6 +167,10 @@ export const GATE_COMMANDS = {
159
167
  TIERED_TEST: 'tiered-test',
160
168
  /** WU-1315: Triggers onboarding smoke test */
161
169
  ONBOARDING_SMOKE_TEST: 'onboarding-smoke-test',
170
+ /** WU-2927: Triggers opt-in local-prep build gate */
171
+ BUILD: 'build-gate',
172
+ /** WU-2927: Triggers opt-in local-prep e2e-smoke gate */
173
+ E2E_SMOKE: 'e2e-smoke-gate',
162
174
  };
163
175
 
164
176
  /**
@@ -16,6 +16,7 @@ const MEMORY_TOOLS = {
16
16
  MEM_EXPORT: 'mem:export',
17
17
  MEM_INBOX: 'mem:inbox',
18
18
  MEM_SIGNAL: 'mem:signal',
19
+ MEM_CONVERGED: 'mem:converged',
19
20
  MEM_SUMMARIZE: 'mem:summarize',
20
21
  MEM_TRIAGE: 'mem:triage',
21
22
  MEM_RECOVER: 'mem:recover',
@@ -35,6 +36,7 @@ const MEMORY_TOOL_ERROR_CODES: Record<MemoryToolName, string> = {
35
36
  'mem:export': 'MEM_EXPORT_ERROR',
36
37
  'mem:inbox': 'MEM_INBOX_ERROR',
37
38
  'mem:signal': 'MEM_SIGNAL_ERROR',
39
+ 'mem:converged': 'MEM_CONVERGED_ERROR',
38
40
  'mem:summarize': 'MEM_SUMMARIZE_ERROR',
39
41
  'mem:triage': 'MEM_TRIAGE_ERROR',
40
42
  'mem:recover': 'MEM_RECOVER_ERROR',
@@ -55,6 +57,7 @@ const MEMORY_TOOL_COMMANDS: Record<
55
57
  'mem:export': RUNTIME_CLI_COMMANDS.MEM_EXPORT,
56
58
  'mem:inbox': RUNTIME_CLI_COMMANDS.MEM_INBOX,
57
59
  'mem:signal': RUNTIME_CLI_COMMANDS.MEM_SIGNAL,
60
+ 'mem:converged': RUNTIME_CLI_COMMANDS.MEM_CONVERGED,
58
61
  'mem:summarize': RUNTIME_CLI_COMMANDS.MEM_SUMMARIZE,
59
62
  'mem:triage': RUNTIME_CLI_COMMANDS.MEM_TRIAGE,
60
63
  'mem:recover': RUNTIME_CLI_COMMANDS.MEM_RECOVER,
@@ -338,6 +341,18 @@ export async function memInboxTool(input: unknown): Promise<ToolOutput> {
338
341
  if (lane) {
339
342
  args.push('--lane', lane);
340
343
  }
344
+ const reader = toStringValue(parsed.for);
345
+ if (reader) {
346
+ args.push('--for', reader);
347
+ }
348
+ const thread = toStringValue(parsed.thread);
349
+ if (thread) {
350
+ args.push('--thread', thread);
351
+ }
352
+ const intent = toStringValue(parsed.intent);
353
+ if (intent) {
354
+ args.push('--intent', intent);
355
+ }
341
356
 
342
357
  return executeMemoryTool(MEMORY_TOOLS.MEM_INBOX, args);
343
358
  }
@@ -354,7 +369,47 @@ export async function memSignalTool(input: unknown): Promise<ToolOutput> {
354
369
  return createMissingParameterOutput(MISSING_PARAMETER_MESSAGES.WU_REQUIRED);
355
370
  }
356
371
 
357
- return executeMemoryTool(MEMORY_TOOLS.MEM_SIGNAL, [message, '--wu', wu]);
372
+ const args = [message, '--wu', wu];
373
+ const to = toStringValue(parsed.to);
374
+ if (to) {
375
+ args.push('--to', to);
376
+ }
377
+ const thread = toStringValue(parsed.thread);
378
+ if (thread) {
379
+ args.push('--thread', thread);
380
+ }
381
+ const replyTo = toStringValue(parsed.reply_to);
382
+ if (replyTo) {
383
+ args.push('--reply-to', replyTo);
384
+ }
385
+ const intent = toStringValue(parsed.intent);
386
+ if (intent) {
387
+ args.push('--intent', intent);
388
+ }
389
+ const interrupt = toStringValue(parsed.interrupt);
390
+ if (interrupt) {
391
+ args.push('--interrupt', interrupt);
392
+ }
393
+ if (parsed.requires_ack === true) {
394
+ args.push('--requires-ack');
395
+ }
396
+
397
+ return executeMemoryTool(MEMORY_TOOLS.MEM_SIGNAL, args);
398
+ }
399
+
400
+ export async function memConvergedTool(input: unknown): Promise<ToolOutput> {
401
+ const parsed = toRecord(input);
402
+ const thread = toStringValue(parsed.thread);
403
+ if (!thread) {
404
+ return createMissingParameterOutput('thread is required');
405
+ }
406
+
407
+ const args = ['--thread', thread];
408
+ if (parsed.quiet === true) {
409
+ args.push('--quiet');
410
+ }
411
+
412
+ return executeMemoryTool(MEMORY_TOOLS.MEM_CONVERGED, args);
358
413
  }
359
414
 
360
415
  export async function memSummarizeTool(input: unknown): Promise<ToolOutput> {
@@ -47,6 +47,7 @@ export const RUNTIME_CLI_COMMANDS = {
47
47
  MEM_DELETE: 'mem-delete',
48
48
  MEM_EXPORT: 'mem-export',
49
49
  MEM_INBOX: 'mem-inbox',
50
+ MEM_CONVERGED: 'mem-converged',
50
51
  MEM_INIT: 'mem-init',
51
52
  MEM_READY: 'mem-ready',
52
53
  MEM_RECOVER: 'mem-recover',
@@ -1,3 +1,5 @@
1
+ <!-- LUMENFLOW:START -->
2
+
1
3
  # Universal Agent Instructions
2
4
 
3
5
  **Last updated:** {{DATE}}
@@ -87,6 +89,44 @@ pnpm mem:checkpoint --wu WU-XXXX --note '<progress>' --next-steps '<what is next
87
89
 
88
90
  **Shell-quoting footgun:** always **single-quote** the `--title` value. Bash expands `$var`, `$0`, backticks, and `!hist` inside double-quoted strings, silently corrupting prose containing prices (`$49`), positional refs, or exclamation marks. See [Memory section in LUMENFLOW.md](LUMENFLOW.md#memory-shared-vs-vendor-personal) for the full mem:\* contract.
89
91
 
92
+ ### Agent-to-Agent Coordination
93
+
94
+ The shared memory signal layer now speaks the exported `A2A.V1` contract from
95
+ `@lumenflow/control-plane-sdk/a2a`. Local JSONL, generated Claude hooks, and
96
+ `mem:watch` are adapters; lumenflow.cloud uses the same contract over hosted
97
+ tenant/workspace transport (`workspace_id` is optional locally and required in
98
+ hosted buses).
99
+
100
+ Use stable identities when a role should keep receipt state across restarts:
101
+
102
+ ```bash
103
+ pnpm agent:session --agent-identity codex:implementer:init-066 --wu WU-XXXX
104
+ pnpm mem:signal 'approve this boundary' --wu WU-XXXX --to claude:reviewer:init-066 --intent PROPOSE --requires-ack
105
+ pnpm mem:inbox --for codex:implementer:init-066
106
+ ```
107
+
108
+ Signals addressed with `--to` persist canonical `recipients[]`; legacy
109
+ `target_agent` is only a read-compatible single-recipient alias. Receipts are
110
+ per reader identity, so one agent reading a signal does not hide it from another
111
+ recipient. Threads and `INFO|PROPOSE|COUNTER|AGREE|REJECT` intents make
112
+ coordination decisions machine-readable, `requires_ack` expects a same-thread
113
+ `AGREE` or `REJECT`, and interrupt classes are
114
+ `advisory|priority|urgent` with `soon|immediate` accepted as compatibility
115
+ aliases.
116
+
117
+ Claude Code receives addressed `signal:received` events through generated
118
+ `PostToolUse` hooks. Other clients should run the daemon fallback in a side
119
+ terminal when they need active delivery:
120
+
121
+ ```bash
122
+ pnpm mem:watch --session <session_id|display_name|agent_identity>
123
+ ```
124
+
125
+ Before `mem:checkpoint`, `wu:prep`, or a handoff, unread directed signals are a
126
+ decision point. Read and ACK/REJECT them before continuing, or use
127
+ `pnpm wu:prep --allow-unread-signals --reason '<audit reason>'` only when the
128
+ override is intentional and auditable.
129
+
90
130
  ### Before wu:done
91
131
 
92
132
  ```bash
@@ -152,7 +192,45 @@ For detailed troubleshooting, see [troubleshooting-wu-done.md]({{DOCS_ONBOARDING
152
192
 
153
193
  1. **Fit-For-Surface Verification**: Choose the least brittle verification that gives strong confidence. Prefer TDD for runtime logic when policy requires it; avoid brittle UI implementation-detail tests.
154
194
  2. **Worktree Discipline**: After `wu:claim`, work ONLY in the worktree
155
- 3. **Gates Before Done**: Run `pnpm gates` before `wu:done`
195
+ 3. **Gates Before Done**: Run `pnpm gates` before `wu:done`. Per-gate skip
196
+ (`--skip-gate <name>`, repeatable) is the preferred bypass surface as of
197
+ WU-2925; legacy `--skip-gates` is deprecated for one minor cycle. Only gates
198
+ marked `skippable: true` (allow-list: `migration-verify`, `lane-health`,
199
+ `tdd-diff-evidence`, plus the WU-2927 opt-in local-prep gates `build`,
200
+ `integration-test`, `e2e-smoke`) or overridden via
201
+ `software_delivery.gates.overrides.<gate_id>.skippable=true` may be skipped.
202
+ Both flags require `--reason` and `--fix-wu`.
203
+
204
+ **Safety-critical gates (NEVER skippable, no override):** `format`, `lint`,
205
+ `typecheck`, `co-change`, `spec:linter`, `claim-validation`,
206
+ `unread-directed-signal`, `invariants`, `safety-critical-test`. To narrow
207
+ their reach without flipping the default, set
208
+ `software_delivery.gates.overrides.<gate_id>.applicability_paths` to a
209
+ glob list — never flip `skippable` on these.
210
+
211
+ **`GateResult` state legend (WU-2926).** Each gate produces one of six
212
+ discriminated `GateResult` states with stable glyphs:
213
+ - `passed` ✅ — gate ran successfully
214
+ - `failed` ❌ — gate ran and failed (or applicable + missing + skippable + `'fail'`)
215
+ - `skipped-by-agent` ⏭ — explicit `--skip-gate <name>` (audit `source: 'agent'`)
216
+ - `skipped-auto-not-applicable` ⊘ — gate doesn't apply to this change set
217
+ - `skipped-auto-missing-prereq` ⊘ — applicable + missing prereq + skippable + auto-skip
218
+ - `blocked-missing-prereq` 🚫 — applicable + missing prereq + `skippable: false`
219
+ (silent-bypass guard; exits non-zero, cannot be `--skip-gate`'d). Override
220
+ per-repo via `software_delivery.gates.overrides.<gate_id>.skippable=true`
221
+ only when the missing prerequisite is genuinely environmental.
222
+
223
+ Auto-skip + blocked states write audit NDJSON with the discriminated
224
+ `source` field; CFR only counts `source: 'agent'` rows. Public reference:
225
+ [Gates Reference](https://lumenflow.dev/reference/gates).
226
+
227
+ **Local-prep profile (WU-2927).** The opt-in
228
+ `software_delivery.gates.local_prep` profile extends `wu:prep` with
229
+ `build`, `integration-test`, and `e2e-smoke` gates that previously only ran
230
+ in CI. All three are `skippable: true` and on the per-gate skip allow-list.
231
+ See [LUMENFLOW.md gates section](LUMENFLOW.md#extended-local-prep-profile-wu-2927)
232
+ for the schema and latency budget.
233
+
156
234
  4. **Never Bypass Hooks**: No `--no-verify`
157
235
  5. **Vendor-Agnostic Dirty-Main Guard**: `wu:prep` and `wu:done` hard-block when main has non-allowlisted dirty files during worktree WUs (including MCP/tool-originated writes). `branch-pr` mode is exempt.
158
236
  6. **Docs Parity For Behavior Changes**: If you change LumenFlow behavior or workflow guidance, update internal docs, Starlight docs, or both as appropriate. Generated reference docs do not cover narrative behavior changes by themselves.
@@ -204,14 +282,24 @@ LumenFlow enforces safety at the repository level via git wrappers and hooks. Fo
204
282
 
205
283
  This file provides universal guidance for all AI agents. LumenFlow skills live in `.lumenflow/skills/` as `SKILL.md` files and are projected to each vendor via `pnpm lumenflow:integrate --client <x>`.
206
284
 
207
- | Vendor | Skill / rules surface | Invocation |
208
- | ------------ | --------------------------------------------------- | ---------------------------------------------------------------------- |
209
- | Claude Code | `.claude/skills/` + `.claude/CLAUDE.md` | `Skill` tool call, or `/skill <name>` in interactive CLI |
285
+ Agent plugins are a discovery and invocation on-ramp, not a replacement for repo-level LumenFlow
286
+ integration. **Plugin packaging is scoped under INIT-065 and not yet shipped as of 5.4.0** — the
287
+ guidance below applies once the packaging WUs land. If a plugin is installed alongside standalone
288
+ projections, use the surface-specific name: standalone skills keep local names such as
289
+ `design-first`, Claude plugin skills use names such as `/lumenflow:design-first`, and Codex plugin
290
+ use should select the installed `lumenflow` plugin or bundled skill through Codex's `@` plugin
291
+ selection surface. Plugin installation must not delete `.claude/skills/` or `.agents/skills/`, and
292
+ governed repo enforcement still requires `npx lumenflow init`, `pnpm lumenflow:integrate`, or
293
+ `pnpm lumenflow:integrate --sync`.
294
+
295
+ | Vendor | Skill / rules surface | Invocation |
296
+ | ------------ | -------------------------------------------------- | ---------------------------------------------------------------------- |
297
+ | Claude Code | `.claude/skills/` + `.claude/CLAUDE.md` | `Skill` tool call, or `/skill <name>` in interactive CLI |
210
298
  | OpenAI Codex | `AGENTS.md` + `.agents/skills/` + `.codex/agents/` | `/skills`, `$<name>` mention, implicit skills, explicit subagent usage |
211
- | Cursor | `.cursor/rules/` + `.agents/skills/` | `/skills` or auto-discovery |
212
- | Windsurf | `.windsurf/rules/` + `.agents/skills/` | Auto-discovery; workflows via `/<workflow-name>` |
213
- | Aider | `CONVENTIONS.md` | `/read CONVENTIONS.md` or `aider --read CONVENTIONS.md` |
214
- | Cline | `.clinerules` | Auto-loaded |
299
+ | Cursor | `.cursor/rules/` + `.agents/skills/` | `/skills` or auto-discovery |
300
+ | Windsurf | `.windsurf/rules/` + `.agents/skills/` | Auto-discovery; workflows via `/<workflow-name>` |
301
+ | Aider | `CONVENTIONS.md` | `/read CONVENTIONS.md` or `aider --read CONVENTIONS.md` |
302
+ | Cline | `.clinerules` | Auto-loaded |
215
303
 
216
304
  Shared cross-vendor surfaces: `AGENTS.md` and `.agents/skills/`.
217
305
  Vendor-specific overlays: `.claude/agents/`, `.codex/agents/`, `.cursor/rules/`, and `.windsurf/rules/`.
@@ -315,3 +403,5 @@ pnpm wu:brief --id WU-XXX --client codex-cli
315
403
 
316
404
  Recovery files contain your last checkpoint, acceptance criteria, code paths, and changed files.
317
405
  Always save checkpoints before long operations: `pnpm mem:checkpoint "progress note" --wu WU-XXX`
406
+
407
+ <!-- LUMENFLOW:END -->