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.
- package/README.md +13 -0
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli/register-coordination.js +65 -1
- package/dist/commands/attempt-authority.js +80 -0
- package/dist/commands/harvest.js +140 -61
- package/dist/commands/loop.js +34 -0
- package/dist/commands/loops-handlers.js +143 -15
- package/dist/commands/mcp-catalog.js +52 -18
- package/dist/commands/mcp-schemas.generated.js +64 -0
- package/dist/commands/mcp-write-claims.js +128 -1
- package/dist/commands/mcp-write-coordination.js +149 -76
- package/dist/core/agent-capability.js +1 -1
- package/dist/core/agentrun-reconciler.js +148 -22
- package/dist/core/agentruns.js +254 -29
- package/dist/core/assignment-request-schema.js +7 -0
- package/dist/core/assignment-sweeper.js +5 -3
- package/dist/core/assignments.js +131 -33
- package/dist/core/claim-request-schema.js +7 -0
- package/dist/core/claims.js +53 -2
- package/dist/core/dispatch-status.js +16 -6
- package/dist/core/dispatcher.js +51 -51
- package/dist/core/entity-operations.js +20 -0
- package/dist/core/events.js +4 -0
- package/dist/core/execution-adapters.js +189 -14
- package/dist/core/execution-contract.js +345 -0
- package/dist/core/execution.js +130 -16
- package/dist/core/facade-schema.js +3 -0
- package/dist/core/harness-adapters/base.js +150 -0
- package/dist/core/harness-adapters/claude.js +39 -0
- package/dist/core/harness-adapters/codex.js +57 -0
- package/dist/core/harness-adapters/harvest.js +109 -0
- package/dist/core/harness-adapters/index.js +8 -0
- package/dist/core/harness-adapters/prompt-only.js +13 -0
- package/dist/core/harness-adapters/registry.js +48 -0
- package/dist/core/harness-adapters/result.js +33 -0
- package/dist/core/harness-adapters/types.js +2 -0
- package/dist/core/ideation-loop-close.js +25 -2
- package/dist/core/instruction-templates.js +3 -2
- package/dist/core/loop-turn-dispatch.js +235 -0
- package/dist/core/loops/artifact-contract.js +11 -0
- package/dist/core/loops/attempt-authority.js +496 -0
- package/dist/core/loops/attempt-generations.js +509 -0
- package/dist/core/loops/attempt-reservation.js +197 -35
- package/dist/core/loops/attempt-rollout.js +404 -0
- package/dist/core/loops/attempt-takeover.js +155 -0
- package/dist/core/loops/bootstrap-acquire.js +7 -3
- package/dist/core/loops/brief-assembly.js +21 -4
- package/dist/core/loops/evidence.js +188 -0
- package/dist/core/loops/facade-schema.js +75 -11
- package/dist/core/loops/gate-policy.js +533 -0
- package/dist/core/loops/impl-bind.js +91 -81
- package/dist/core/loops/index.js +9 -0
- package/dist/core/loops/iteration-engine.js +31 -19
- package/dist/core/loops/kind-policies.js +90 -0
- package/dist/core/loops/lock.js +71 -13
- package/dist/core/loops/reconcile-turn.js +237 -18
- package/dist/core/loops/result-reducers.js +113 -10
- package/dist/core/loops/store.js +34 -3
- package/dist/core/loops/turn-execution.js +480 -0
- package/dist/core/loops/types.js +127 -3
- package/dist/core/loops/verbs.js +335 -99
- package/dist/core/loops/verify-command.js +105 -20
- package/dist/core/loops/workspace-digest.js +54 -0
- package/dist/core/review-loop-close.js +25 -3
- package/dist/core/review-loop-turn-dispatch.js +210 -161
- package/dist/core/runtime-signals.js +62 -25
- package/dist/core/schema.js +40 -0
- package/dist/core/spawn-check.js +3 -2
- package/dist/core/upgrades/backup.js +27 -4
- package/dist/facts.js +9 -8
- package/dist/facts.json +8 -7
- package/docs/cli.md +49 -1
- package/docs/concepts/attempt-authority.md +407 -0
- package/docs/concepts/evidence-attestations.md +135 -0
- package/docs/concepts/execution-contract.md +166 -0
- package/docs/concepts/harness-adapters.md +166 -0
- package/docs/concepts/ideation-loop.md +5 -4
- package/docs/concepts/loop-engine.md +302 -113
- package/docs/index.md +4 -1
- package/docs/integrations/codex.md +3 -3
- package/docs/integrations/mcp.md +59 -5
- package/docs/loops/debug.md +144 -0
- package/docs/loops/ideation.md +158 -0
- package/docs/loops/implementation.md +174 -0
- package/docs/loops/research.md +136 -0
- package/docs/loops/review.md +200 -0
- package/docs/mcp-schema-changelog.md +18 -5
- package/package.json +1 -1
package/dist/core/loops/types.js
CHANGED
|
@@ -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
|
|
787
|
-
//
|
|
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: {
|