brainclaw 1.26.2 → 1.28.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 (88) hide show
  1. package/README.md +13 -0
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli/register-coordination.js +65 -1
  4. package/dist/commands/attempt-authority.js +80 -0
  5. package/dist/commands/harvest.js +140 -61
  6. package/dist/commands/loop.js +34 -0
  7. package/dist/commands/loops-handlers.js +143 -15
  8. package/dist/commands/mcp-catalog.js +52 -18
  9. package/dist/commands/mcp-schemas.generated.js +64 -0
  10. package/dist/commands/mcp-write-claims.js +128 -1
  11. package/dist/commands/mcp-write-coordination.js +149 -76
  12. package/dist/core/agent-capability.js +1 -1
  13. package/dist/core/agentrun-reconciler.js +148 -22
  14. package/dist/core/agentruns.js +254 -29
  15. package/dist/core/assignment-request-schema.js +7 -0
  16. package/dist/core/assignment-sweeper.js +5 -3
  17. package/dist/core/assignments.js +131 -33
  18. package/dist/core/claim-request-schema.js +7 -0
  19. package/dist/core/claims.js +53 -2
  20. package/dist/core/dispatch-status.js +16 -6
  21. package/dist/core/dispatcher.js +51 -51
  22. package/dist/core/entity-operations.js +20 -0
  23. package/dist/core/events.js +4 -0
  24. package/dist/core/execution-adapters.js +189 -14
  25. package/dist/core/execution-contract.js +345 -0
  26. package/dist/core/execution.js +130 -16
  27. package/dist/core/facade-schema.js +3 -0
  28. package/dist/core/harness-adapters/base.js +150 -0
  29. package/dist/core/harness-adapters/claude.js +39 -0
  30. package/dist/core/harness-adapters/codex.js +57 -0
  31. package/dist/core/harness-adapters/harvest.js +109 -0
  32. package/dist/core/harness-adapters/index.js +8 -0
  33. package/dist/core/harness-adapters/prompt-only.js +13 -0
  34. package/dist/core/harness-adapters/registry.js +48 -0
  35. package/dist/core/harness-adapters/result.js +33 -0
  36. package/dist/core/harness-adapters/types.js +2 -0
  37. package/dist/core/ideation-loop-close.js +25 -2
  38. package/dist/core/instruction-templates.js +3 -2
  39. package/dist/core/loop-turn-dispatch.js +235 -0
  40. package/dist/core/loops/artifact-contract.js +11 -0
  41. package/dist/core/loops/attempt-authority.js +496 -0
  42. package/dist/core/loops/attempt-generations.js +509 -0
  43. package/dist/core/loops/attempt-reservation.js +197 -35
  44. package/dist/core/loops/attempt-rollout.js +404 -0
  45. package/dist/core/loops/attempt-takeover.js +155 -0
  46. package/dist/core/loops/bootstrap-acquire.js +7 -3
  47. package/dist/core/loops/brief-assembly.js +21 -4
  48. package/dist/core/loops/evidence.js +188 -0
  49. package/dist/core/loops/facade-schema.js +75 -11
  50. package/dist/core/loops/gate-policy.js +533 -0
  51. package/dist/core/loops/impl-bind.js +91 -81
  52. package/dist/core/loops/index.js +9 -0
  53. package/dist/core/loops/iteration-engine.js +31 -19
  54. package/dist/core/loops/kind-policies.js +90 -0
  55. package/dist/core/loops/lock.js +71 -13
  56. package/dist/core/loops/reconcile-turn.js +237 -18
  57. package/dist/core/loops/result-reducers.js +113 -10
  58. package/dist/core/loops/store.js +34 -3
  59. package/dist/core/loops/turn-execution.js +480 -0
  60. package/dist/core/loops/types.js +127 -3
  61. package/dist/core/loops/verbs.js +335 -99
  62. package/dist/core/loops/verify-command.js +105 -20
  63. package/dist/core/loops/workspace-digest.js +54 -0
  64. package/dist/core/review-loop-close.js +25 -3
  65. package/dist/core/review-loop-turn-dispatch.js +210 -161
  66. package/dist/core/runtime-signals.js +62 -25
  67. package/dist/core/schema.js +40 -0
  68. package/dist/core/spawn-check.js +3 -2
  69. package/dist/core/upgrades/backup.js +27 -4
  70. package/dist/facts.js +9 -8
  71. package/dist/facts.json +8 -7
  72. package/docs/cli.md +49 -1
  73. package/docs/concepts/attempt-authority.md +407 -0
  74. package/docs/concepts/evidence-attestations.md +135 -0
  75. package/docs/concepts/execution-contract.md +166 -0
  76. package/docs/concepts/harness-adapters.md +166 -0
  77. package/docs/concepts/ideation-loop.md +5 -4
  78. package/docs/concepts/loop-engine.md +302 -113
  79. package/docs/index.md +4 -1
  80. package/docs/integrations/codex.md +3 -3
  81. package/docs/integrations/mcp.md +59 -5
  82. package/docs/loops/debug.md +144 -0
  83. package/docs/loops/ideation.md +158 -0
  84. package/docs/loops/implementation.md +174 -0
  85. package/docs/loops/research.md +136 -0
  86. package/docs/loops/review.md +200 -0
  87. package/docs/mcp-schema-changelog.md +18 -5
  88. package/package.json +1 -1
@@ -15,7 +15,7 @@ export const REVIEW_MODES = ['asymmetric', 'symmetric'];
15
15
  */
16
16
  export const SLOT_STATUSES = ['open', 'assigned', 'working', 'waiting_input', 'done', 'failed', 'cancelled'];
17
17
  export const TERMINAL_SLOT_STATUSES = ['done', 'failed', 'cancelled'];
18
- export const LOOP_REF_KINDS = ['plan', 'sequence', 'claim', 'handoff', 'candidate', 'message'];
18
+ export const LOOP_REF_KINDS = ['plan', 'sequence', 'claim', 'handoff', 'candidate', 'message', 'commit', 'branch'];
19
19
  export const LoopRefSchema = z.object({
20
20
  kind: z.enum(LOOP_REF_KINDS),
21
21
  id: z.string().min(1),
@@ -23,6 +23,8 @@ export const LoopRefSchema = z.object({
23
23
  export const LoopLinksSchema = z.object({
24
24
  plan_ids: z.array(z.string().min(1)).optional(),
25
25
  sequence_ids: z.array(z.string().min(1)).optional(),
26
+ /** Upstream loop in an ideation → implementation → review pipeline. */
27
+ source_loop_id: z.string().regex(/^lop_[0-9a-z]+$/).optional(),
26
28
  });
27
29
  /**
28
30
  * Memory categories a loop phase can request via `context_filter` (pln#492).
@@ -155,6 +157,13 @@ export const LoopSlotSchema = z.object({
155
157
  assignment_id: z.string().optional(),
156
158
  claim_id: z.string().optional(),
157
159
  phase: z.string().optional(),
160
+ /** Implementation-loop lane bound from the linked sequence at bind time. */
161
+ lane: z.string().optional(),
162
+ /** File/path scope carried by the bound sequence lane. */
163
+ scope_hint: z.string().optional(),
164
+ /** Plans and steps executed by this lane (derived, never worker-authored). */
165
+ plan_ids: z.array(z.string().min(1)).optional(),
166
+ step_ids: z.array(z.string().min(1)).optional(),
158
167
  status: z.enum(SLOT_STATUSES),
159
168
  /**
160
169
  * pln#630 PR2b-a (§13 R1) — pointer to the immutable turn-attempt record for
@@ -312,6 +321,74 @@ export const REF_BASED_ARTIFACT_TYPES = new Set([
312
321
  'signals_report',
313
322
  'file_diff',
314
323
  ]);
324
+ export const EVIDENCE_ATTESTATION_KINDS = ['claim', 'observation', 'verification', 'approval'];
325
+ export const EVIDENCE_PRODUCER_KINDS = ['engine', 'slot', 'coordinator', 'operator'];
326
+ export const EVIDENCE_CHANNELS = [
327
+ 'complete_turn',
328
+ 'reconcile_turn',
329
+ 'verify_command',
330
+ 'add_artifact',
331
+ 'operator_input',
332
+ 'system_hook',
333
+ ];
334
+ export const EvidenceSubjectSchema = z.object({
335
+ loop_id: z.string().regex(/^lop_[0-9a-z]+$/),
336
+ artifact_id: z.string().min(1),
337
+ phase: z.string().min(1),
338
+ iteration: z.number().int().nonnegative(),
339
+ slot_id: z.string().optional(),
340
+ turn_id: z.string().optional(),
341
+ assignment_id: z.string().optional(),
342
+ claim_id: z.string().optional(),
343
+ run_id: z.string().optional(),
344
+ nonce_digest: z.string().regex(/^[0-9a-f]{64}$/).optional(),
345
+ attempt_epoch: z.number().int().nonnegative().optional(),
346
+ execution_contract_hash: z.string().regex(/^[0-9a-f]{64}$/).optional(),
347
+ command_digest: z.string().regex(/^[0-9a-f]{64}$/).optional(),
348
+ workspace_digest: z.string().regex(/^[0-9a-f]{64}$/).optional(),
349
+ });
350
+ export const EvidenceProducerSchema = z.object({
351
+ kind: z.enum(EVIDENCE_PRODUCER_KINDS),
352
+ id: z.string().min(1),
353
+ agent_id: z.string().optional(),
354
+ channel: z.enum(EVIDENCE_CHANNELS),
355
+ });
356
+ export const EvidenceAttestationSchema = z.object({
357
+ kind: z.enum(EVIDENCE_ATTESTATION_KINDS),
358
+ issuer: z.string().min(1),
359
+ issued_at: z.string().datetime(),
360
+ subject_digest: z.string().regex(/^[0-9a-f]{64}$/),
361
+ rights: z.array(z.string().min(1)).min(1),
362
+ });
363
+ /**
364
+ * EvidenceEnvelope v1 is sealed by the loop engine at the artifact commit
365
+ * boundary. The seal is an integrity checksum, not a remote identity
366
+ * signature: ingress schemas never accept this object from a caller.
367
+ */
368
+ export const EvidenceEnvelopeSchema = z.object({
369
+ version: z.literal(1),
370
+ evidence_id: z.string().regex(/^evd_[0-9a-z]+$/),
371
+ evidence_type: z.literal('artifact_commit'),
372
+ policy_version: z.literal('gate-policy-v1'),
373
+ subject: EvidenceSubjectSchema,
374
+ producer: EvidenceProducerSchema,
375
+ artifact_digest: z.string().regex(/^[0-9a-f]{64}$/),
376
+ issued_at: z.string().datetime(),
377
+ observed_at: z.string().datetime(),
378
+ validity: z.object({
379
+ not_before: z.string().datetime(),
380
+ not_after: z.string().datetime().optional(),
381
+ }),
382
+ attestations: z.array(EvidenceAttestationSchema).min(1),
383
+ seal: z.object({
384
+ algorithm: z.literal('sha256'),
385
+ digest: z.string().regex(/^[0-9a-f]{64}$/),
386
+ }),
387
+ });
388
+ export const EvidencePolicyBindingSchema = z.object({
389
+ version: z.literal('gate-policy-v1'),
390
+ mode: z.enum(['shadow', 'strict']),
391
+ });
315
392
  /**
316
393
  * Lookup table mapping known artifact types to their body Zod schemas.
317
394
  * Step 2 handlers (request_input/provide_input) parse `artifact.body` as
@@ -339,6 +416,7 @@ export const REF_BASED_ARTIFACT_TYPES = new Set([
339
416
  */
340
417
  export const VerifyReportBodySchema = z.object({
341
418
  command: z.string().min(1),
419
+ command_argv: z.array(z.string()).min(1).optional(),
342
420
  exit_code: z.number().int().nullable(),
343
421
  passed: z.boolean(),
344
422
  duration_ms: z.number().int().nonnegative().optional(),
@@ -346,6 +424,11 @@ export const VerifyReportBodySchema = z.object({
346
424
  timed_out: z.boolean().optional(),
347
425
  stdout_tail: z.string().max(1024).optional(),
348
426
  stderr_tail: z.string().max(1024).optional(),
427
+ command_digest: z.string().regex(/^[0-9a-f]{64}$/).optional(),
428
+ workspace_digest: z.string().regex(/^[0-9a-f]{64}$/).optional(),
429
+ workspace_stable: z.boolean().optional(),
430
+ /** Implementation lane whose worktree was verified. */
431
+ lane: z.string().optional(),
349
432
  });
350
433
  export const KNOWN_ARTIFACT_BODY_SCHEMAS = {
351
434
  // inline JSON body: body = JSON.stringify({ ...fields per OperatorQuestionBodySchema })
@@ -385,6 +468,8 @@ export const LoopArtifactSchema = z
385
468
  * critique artifact) is deferred to v1.1 per the plan.
386
469
  */
387
470
  addresses_critique: z.array(z.string().min(1)).optional(),
471
+ /** Executable acceptance command carried from synthesis into implementation. */
472
+ implementation_verify: LoopVerifyConfigSchema.optional(),
388
473
  /**
389
474
  * pln#492 phase 2.b — iteration window the artifact was produced in.
390
475
  * 0-indexed (proposal/early phases produce iteration=0). Optional for
@@ -394,6 +479,14 @@ export const LoopArtifactSchema = z
394
479
  * at artifact creation time so callers don't have to track it.
395
480
  */
396
481
  iteration: z.number().int().nonnegative().optional(),
482
+ /**
483
+ * Explicit migration provenance. Optional on read so artifacts persisted
484
+ * before P2 remain valid; use artifactEvidenceProvenance() to infer their
485
+ * effective value without rewriting historical records.
486
+ */
487
+ provenance: z.enum(['legacy', 'attested']).optional(),
488
+ /** Server-sealed provenance and independent attestations (P2). */
489
+ evidence: EvidenceEnvelopeSchema.optional(),
397
490
  })
398
491
  .superRefine((artifact, ctx) => {
399
492
  if (artifact.body !== undefined && Buffer.byteLength(artifact.body, 'utf8') > LOOP_ARTIFACT_BODY_MAX_BYTES) {
@@ -500,6 +593,8 @@ export const LoopThreadSchema = z
500
593
  artifacts: z.array(LoopArtifactSchema),
501
594
  linked: LoopLinksSchema.optional(),
502
595
  stop_condition: StopConditionSchema.optional(),
596
+ /** Absent means a pre-policy/legacy thread. New loops bind this at open. */
597
+ evidence_policy: EvidencePolicyBindingSchema.optional(),
503
598
  /**
504
599
  * pln#508 step 1 — set of unresolved operator_question artifact ids.
505
600
  * The engine maintains this on every request_input / provide_input
@@ -580,6 +675,17 @@ const LoopEventBaseShape = {
580
675
  by: z.string().optional(),
581
676
  mutation_id: z.string().min(1),
582
677
  };
678
+ export const GateDecisionSchema = z.object({
679
+ passed: z.boolean(),
680
+ /** Strict and legacy dimensions remain observable during a shadow rollout. */
681
+ strict_passed: z.boolean().optional(),
682
+ legacy_passed: z.boolean().optional(),
683
+ policy_version: z.enum(['legacy', 'gate-policy-v1']),
684
+ mode: z.enum(['legacy', 'shadow', 'strict']),
685
+ condition_digest: z.string().regex(/^[0-9a-f]{64}$/),
686
+ accepted_evidence_ids: z.array(z.string()),
687
+ rejected: z.array(z.object({ artifact_id: z.string(), reason: z.string() })),
688
+ });
583
689
  export const LoopEventSchema = z.discriminatedUnion('kind', [
584
690
  z.object({
585
691
  ...LoopEventBaseShape,
@@ -594,6 +700,7 @@ export const LoopEventSchema = z.discriminatedUnion('kind', [
594
700
  to_phase: z.string().min(1),
595
701
  iteration: z.number().int().nonnegative(),
596
702
  reason: z.string().optional(),
703
+ gate_decision: GateDecisionSchema.optional(),
597
704
  }),
598
705
  z.object({
599
706
  ...LoopEventBaseShape,
@@ -615,6 +722,19 @@ export const LoopEventSchema = z.discriminatedUnion('kind', [
615
722
  phase: z.string().min(1),
616
723
  turn_id: z.string().min(1),
617
724
  }),
725
+ z.object({
726
+ ...LoopEventBaseShape,
727
+ kind: z.literal('attempt_generation_changed'),
728
+ slot_id: z.string().min(1),
729
+ turn_id: z.string().min(1),
730
+ assignment_id: z.string().min(1),
731
+ from_epoch: z.number().int().nonnegative(),
732
+ to_epoch: z.number().int().positive(),
733
+ from_run_id: z.string().min(1),
734
+ to_run_id: z.string().min(1),
735
+ close_digest: z.string().regex(/^[a-f0-9]{64}$/),
736
+ cause: z.string().min(1),
737
+ }),
618
738
  z.object({
619
739
  ...LoopEventBaseShape,
620
740
  kind: z.literal('turn_completed'),
@@ -631,6 +751,7 @@ export const LoopEventSchema = z.discriminatedUnion('kind', [
631
751
  phase: z.string().min(1),
632
752
  type: z.string().min(1),
633
753
  produced_by: z.string().optional(),
754
+ evidence_id: z.string().optional(),
634
755
  }),
635
756
  z.object({
636
757
  ...LoopEventBaseShape,
@@ -651,6 +772,7 @@ export const LoopEventSchema = z.discriminatedUnion('kind', [
651
772
  kind: z.literal('closed'),
652
773
  final_status: z.enum(['completed', 'cancelled', 'blocked']),
653
774
  reason: z.string().optional(),
775
+ gate_decision: GateDecisionSchema.optional(),
654
776
  }),
655
777
  // pln#492 — system events emitted by the iteration / phase-advance gate.
656
778
  // Carried in the same event journal rather than as artifacts so consumers
@@ -660,6 +782,7 @@ export const LoopEventSchema = z.discriminatedUnion('kind', [
660
782
  kind: z.literal('phase_advance_blocked'),
661
783
  phase: z.string().min(1),
662
784
  gate_reason: z.string().min(1),
785
+ gate_decision: GateDecisionSchema.optional(),
663
786
  }),
664
787
  z.object({
665
788
  ...LoopEventBaseShape,
@@ -783,8 +906,9 @@ export const DEFAULT_PROTOCOLS = {
783
906
  },
784
907
  // pln#609 — implementation loop v2. The loop ADDS to the dispatch pipeline
785
908
  // what it lacked: a deterministic command_green gate + a bounded fix↔verify
786
- // cycle + per-phase context sculpting. `bind` is an ENGINE action (bind
787
- // plan+sequence and dispatch) not narration; execute↔verify iterates until
909
+ // cycle + per-phase context sculpting. `bind` is an engine-only link
910
+ // validation/advance; worker launch belongs to turn(dispatch=true).
911
+ // execute↔verify iterates until
788
912
  // the verify command is green (a passing verify_report this iteration) or
789
913
  // the cycle cap is hit (→ handoff_ready with the red report → blocked).
790
914
  implementation: {