owlrunkit 0.16.1 → 0.17.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 (25) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +48 -9
  3. package/docs/architecture/OWLCODA_RUNKIT_017_AGENT_NATIVE_PRODUCT_DEFINITION.md +154 -0
  4. package/integrations/codex/skills/owlcoda-runkit/SKILL.md +59 -14
  5. package/integrations/codex/skills/owlcoda-runkit/assets/templates/config.json +3 -3
  6. package/package.json +1 -1
  7. package/packages/attest/distribution-manifest-v1.json +5 -0
  8. package/packages/attest/src/quick.mjs +5 -0
  9. package/registry-release-policy-v1.json +5 -5
  10. package/sbom.spdx.json +5 -5
  11. package/scripts/runkit-contract/core-contract.mjs +12 -2
  12. package/scripts/runkit-contract/formal-workflow.mjs +201 -0
  13. package/scripts/runkit-contract/lifecycle-orchestration.mjs +7 -2
  14. package/scripts/runkit-contract/runkit-cli.mjs +99 -8
  15. package/scripts/runkit-contract/schemas/team-project-definition-v1.schema.json +108 -0
  16. package/scripts/runkit-contract/schemas/team-project-event-v1.schema.json +99 -0
  17. package/scripts/runkit-contract/schemas/team-project-status-v1.schema.json +50 -0
  18. package/scripts/runkit-contract/schemas/verification-envelope-v1.schema.json +102 -0
  19. package/scripts/runkit-contract/sync-release-identity.mjs +224 -0
  20. package/scripts/runkit-contract/team-project.mjs +1006 -0
  21. package/scripts/runkit-contract/templates/team-project-definition.json +30 -0
  22. package/scripts/runkit-contract/templates/team-project-event.json +9 -0
  23. package/scripts/runkit-contract/templates/verification-envelope.json +28 -0
  24. package/scripts/runkit-contract/verification-envelope-check.mjs +45 -0
  25. package/scripts/runkit-contract/verification-envelope.mjs +846 -0
@@ -6,6 +6,7 @@ import {
6
6
  realpathSync,
7
7
  } from "node:fs";
8
8
  import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
9
10
 
10
11
  import {
11
12
  acceptedCloseoutVerificationIssues,
@@ -33,6 +34,16 @@ import {
33
34
  } from "./source-candidate.mjs";
34
35
  import { validateReceiptLineage } from "./receipt-lineage.mjs";
35
36
  import { verificationContextFingerprint } from "./verification-context.mjs";
37
+ import {
38
+ runVerificationEnvelopeV1,
39
+ validateVerificationEnvelopeV1,
40
+ verifyVerificationEnvelopeReceiptV1,
41
+ } from "./verification-envelope.mjs";
42
+
43
+ const VERIFICATION_ENVELOPE_CHECKER = fileURLToPath(new URL(
44
+ "./verification-envelope-check.mjs",
45
+ import.meta.url,
46
+ ));
36
47
 
37
48
  const FORBIDDEN_EXTERNAL_TOOLS = new Set([
38
49
  "curl",
@@ -623,6 +634,184 @@ export function recordFormalCheckV1(options) {
623
634
  );
624
635
  }
625
636
 
637
+ async function recordFormalEnvelopeCheckWithinControlTransaction({
638
+ workspaceRoot,
639
+ runId,
640
+ workItemId,
641
+ checkId,
642
+ envelope,
643
+ hooks = {},
644
+ }) {
645
+ safeIdentifier(checkId, "checkId");
646
+ const root = realpathSync(workspaceRoot);
647
+ const { executionRoot, pinGate } = loadActiveExecution(root, runId);
648
+ if (pinGate.status !== "valid") return { ...pinGate, authorizationGranted: false };
649
+ const validatedEnvelope = validateVerificationEnvelopeV1({
650
+ workspaceRoot: root,
651
+ envelope,
652
+ });
653
+ const receiptPath = path.join(checkRoot(executionRoot), `${checkId}.json`);
654
+ const candidateResult = resumeOrFreezeCandidate({
655
+ workspaceRoot: root,
656
+ executionRoot,
657
+ runId,
658
+ workItemId,
659
+ checkId,
660
+ });
661
+ const candidate = candidateResult.candidate;
662
+ if (candidate.status !== "source_candidate_frozen") return candidate;
663
+ hooks.afterCandidatePersist?.();
664
+ const candidateDocument = readJson(path.join(root, candidate.candidatePath));
665
+ const envelopePath = path.join(
666
+ executionRoot,
667
+ "formal-envelopes",
668
+ `${checkId}.json`,
669
+ );
670
+ const envelopeResult = writeOrResumeExactJson(
671
+ envelopePath,
672
+ validatedEnvelope.envelope,
673
+ "Formal Verification Envelope",
674
+ );
675
+ const envelopeArtifactRoot = path.join(
676
+ executionRoot,
677
+ "verification-envelopes",
678
+ checkId,
679
+ );
680
+ const envelopeReceipt = await runVerificationEnvelopeV1({
681
+ workspaceRoot: root,
682
+ envelope: envelopeResult.value,
683
+ artifactRoot: envelopeArtifactRoot,
684
+ });
685
+ hooks.afterEnvelopePersist?.();
686
+ const commandArgv = [
687
+ realpathSync(process.execPath),
688
+ VERIFICATION_ENVELOPE_CHECKER,
689
+ "--workspace",
690
+ root,
691
+ "--receipt",
692
+ envelopeReceipt.receiptPath,
693
+ ];
694
+ const verificationCommandPolicy = {
695
+ schemaVersion: "OwlCodaRunKitFormalVerificationCommandPolicyV1",
696
+ mode: "verification_envelope_v1",
697
+ riskClassification: "enforced_verification_envelope",
698
+ profileCommandIds: [],
699
+ executable: commandArgv[0],
700
+ argv: commandArgv.slice(1),
701
+ envelopeSha256: validatedEnvelope.envelopeSha256,
702
+ envelopeReceiptSha256: envelopeReceipt.receiptSha256,
703
+ authorizationGranted: false,
704
+ };
705
+ const context = derivedVerificationContext(root);
706
+ const request = {
707
+ schemaVersion: "OwlCodaRunKitSnapshotRequestV1",
708
+ snapshotId: `${checkId}-snapshot`,
709
+ mode: "project",
710
+ targetRoot: root,
711
+ cwd: ".",
712
+ executable: verificationCommandPolicy.executable,
713
+ argv: verificationCommandPolicy.argv,
714
+ launcherVersion: "owlrunkit-formal-envelope-v1",
715
+ toolVersions: structuredClone(context.toolchains),
716
+ selectedPaths: candidateDocument.sourceManifest.entries
717
+ .filter((entry) => entry.operation !== "deleted")
718
+ .map((entry) => entry.path)
719
+ .sort(),
720
+ statusMode: "porcelain-v1-z-untracked-all-runkit-excluded",
721
+ verificationContext: context,
722
+ };
723
+ const requestPath = path.join(
724
+ executionRoot,
725
+ "formal-check-requests",
726
+ `${checkId}.json`,
727
+ );
728
+ const requestResult = writeOrResumeExactJson(
729
+ requestPath,
730
+ request,
731
+ "Formal check request",
732
+ );
733
+ hooks.afterRequestPersist?.();
734
+ const snapshotResult = resumeSnapshot({
735
+ workspaceRoot: root,
736
+ executionRoot,
737
+ runId,
738
+ request: requestResult.value,
739
+ candidateDocument,
740
+ });
741
+ const snapshot = snapshotResult.snapshot;
742
+ hooks.afterSnapshotPersist?.();
743
+ const savedSnapshot = readJson(path.join(root, snapshot.snapshotPath));
744
+ const existingReceipt = existsSync(receiptPath)
745
+ ? readRegularJson(receiptPath, "Formal check receipt")
746
+ : null;
747
+ const sequence = existingReceipt?.sequence
748
+ ?? readChecks(executionRoot).length + 1;
749
+ const status = snapshot.status === "snapshot_passed"
750
+ && envelopeReceipt.formalEligible
751
+ ? "formal_check_passed"
752
+ : "formal_check_failed";
753
+ const receipt = {
754
+ schemaVersion: "OwlCodaRunKitFormalCheckV1",
755
+ runId,
756
+ checkId,
757
+ sequence,
758
+ status,
759
+ candidatePath: candidate.candidatePath,
760
+ candidateSha256: candidate.candidateSha256,
761
+ payloadSha256: candidate.payloadSha256,
762
+ sourceFingerprint: candidate.sourceFingerprint,
763
+ verificationContext: context,
764
+ verificationContextFingerprint: verificationContextFingerprint(context),
765
+ snapshotRequestPath: relativeToWorkspace(root, requestPath),
766
+ snapshotPath: snapshot.snapshotPath,
767
+ commandExitCode: savedSnapshot.command.exitCode,
768
+ verificationCommandPolicy: {
769
+ schemaVersion: verificationCommandPolicy.schemaVersion,
770
+ mode: verificationCommandPolicy.mode,
771
+ riskClassification: verificationCommandPolicy.riskClassification,
772
+ profileCommandIds: verificationCommandPolicy.profileCommandIds,
773
+ envelopeSha256: verificationCommandPolicy.envelopeSha256,
774
+ envelopeReceiptSha256: verificationCommandPolicy.envelopeReceiptSha256,
775
+ authorizationGranted: false,
776
+ },
777
+ envelopePath: relativeToWorkspace(root, envelopePath),
778
+ envelopeSha256: validatedEnvelope.envelopeSha256,
779
+ envelopeReceiptPath: relativeToWorkspace(root, envelopeReceipt.receiptPath),
780
+ envelopeReceiptSha256: envelopeReceipt.receiptSha256,
781
+ envelopeFormalEligible: envelopeReceipt.formalEligible,
782
+ finalized: false,
783
+ authorizationGranted: false,
784
+ };
785
+ const receiptResult = writeOrResumeExactJson(
786
+ receiptPath,
787
+ receipt,
788
+ "Formal check receipt",
789
+ );
790
+ hooks.afterReceiptPersist?.();
791
+ return {
792
+ ...receiptResult.value,
793
+ exitCode: status === "formal_check_passed" ? 0 : 2,
794
+ checkReceiptPath: relativeToWorkspace(root, receiptPath),
795
+ resumed: candidateResult.resumed
796
+ || envelopeResult.resumed
797
+ || envelopeReceipt.resumed
798
+ || requestResult.resumed
799
+ || snapshotResult.resumed
800
+ || receiptResult.resumed,
801
+ };
802
+ }
803
+
804
+ export function recordFormalEnvelopeCheckV1(options) {
805
+ const workspaceRoot = realpathSync(options.workspaceRoot);
806
+ return withControlTransaction(
807
+ workspaceRoot,
808
+ () => recordFormalEnvelopeCheckWithinControlTransaction({
809
+ ...options,
810
+ workspaceRoot,
811
+ }),
812
+ );
813
+ }
814
+
626
815
  function finalizeFormalChecksWithinControlTransaction({
627
816
  workspaceRoot,
628
817
  runId,
@@ -651,6 +840,18 @@ function finalizeFormalChecksWithinControlTransaction({
651
840
  if (latest.status !== "formal_check_passed" || selected.length === 0) {
652
841
  throw new Error("Formal finish requires the latest source to have a passed check.");
653
842
  }
843
+ for (const check of selected) {
844
+ if (!check.envelopeReceiptPath) continue;
845
+ const verifiedEnvelope = verifyVerificationEnvelopeReceiptV1({
846
+ workspaceRoot: root,
847
+ receiptPath: path.join(root, check.envelopeReceiptPath),
848
+ });
849
+ if (!verifiedEnvelope.formalEligible
850
+ || verifiedEnvelope.receiptSha256 !== check.envelopeReceiptSha256
851
+ || verifiedEnvelope.envelopeSha256 !== check.envelopeSha256) {
852
+ throw new Error(`Formal finish requires a valid Formal-eligible envelope receipt: ${check.checkId}.`);
853
+ }
854
+ }
654
855
  const request = {
655
856
  schemaVersion: "OwlCodaRunKitFinalizeRequestV1",
656
857
  receiptId: `${finalizeId}-receipt`,
@@ -486,6 +486,7 @@ export function activeAcceptedGate({ workspaceRoot, runId }) {
486
486
  }
487
487
  }
488
488
  const distinctMatchingPackets = collapseByteIdenticalDeliveryCandidates(matchingPackets);
489
+ const declaredSourceArtifact = validated.active.receipt.sourceArtifact;
489
490
  let matchingCandidate = null;
490
491
  if (distinctMatchingPackets.length === 0) {
491
492
  const candidateRoot = path.join(executionRoot, "source-candidates");
@@ -524,7 +525,12 @@ export function activeAcceptedGate({ workspaceRoot, runId }) {
524
525
  candidates.map(({ candidate }) => candidate.sourceManifest.sha256),
525
526
  );
526
527
  if (manifestFingerprints.size === 1) {
527
- [matchingCandidate] = candidates;
528
+ matchingCandidate = candidates.find(({ candidatePath }) => (
529
+ declaredSourceArtifact?.kind === "source_candidate_v2"
530
+ && declaredSourceArtifact.path
531
+ === relativeToWorkspace(workspaceRoot, candidatePath)
532
+ && declaredSourceArtifact.sha256 === sha256(readFileSync(candidatePath))
533
+ )) ?? candidates[0];
528
534
  }
529
535
  }
530
536
  if (
@@ -537,7 +543,6 @@ export function activeAcceptedGate({ workspaceRoot, runId }) {
537
543
  throw new Error("Accepted finish requires one fresh source binding matching the active verification gate; source drift remains unresolved.");
538
544
  }
539
545
  const [matchingPacket] = distinctMatchingPackets;
540
- const declaredSourceArtifact = validated.active.receipt.sourceArtifact;
541
546
  if (declaredSourceArtifact !== undefined) {
542
547
  const selectedPath = matchingCandidate === null
543
548
  ? matchingPacket.packetPath
@@ -65,6 +65,7 @@ import {
65
65
  import {
66
66
  finalizeFormalChecksV1,
67
67
  recordFormalCheckV1,
68
+ recordFormalEnvelopeCheckV1,
68
69
  resumeCompletedFormalFinishV1,
69
70
  validateLegacyVerificationSideEffectsV1,
70
71
  } from "./formal-workflow.mjs";
@@ -135,6 +136,13 @@ import {
135
136
  runRegistryAdoption,
136
137
  } from "./registry-adoption.mjs";
137
138
  import { OFFICIAL_NPM_REGISTRY } from "./registry-adoption-gate.mjs";
139
+ import {
140
+ appendTeamProjectEventV1,
141
+ buildTeamProjectTakeoverV1,
142
+ formatTeamProjectStatusHumanV1,
143
+ initializeTeamProjectV1,
144
+ readTeamProjectStatusV1,
145
+ } from "./team-project.mjs";
138
146
 
139
147
  const TOP_LEVEL_HELP = `OwlRunKit ${CORE_VERSION}
140
148
 
@@ -170,16 +178,16 @@ Fleet and status
170
178
  owlrunkit fleet rollback-registry --receipt <file> --rollback-receipt <file>
171
179
  owlrunkit fleet discover; owlrunkit status --workspace .
172
180
 
181
+ Agent team projects
182
+ owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]
183
+ Durable Agent work, dependencies, decisions, gates, progress, and handoffs.
173
184
  Core successor
174
185
  owlrunkit core-successor <plan|apply|resume> --workspace . [...]
175
186
 
176
187
  Other onboarding commands:
177
- owlrunkit profiles validate --workspace .
178
- owlrunkit profiles impact --workspace . --changed <path>
188
+ owlrunkit profiles validate --workspace .; owlrunkit profiles impact --workspace . --changed <path>
179
189
  owlrunkit inspect --workspace . --json
180
-
181
- Quick receipts cannot become Formal acceptance.
182
- Formal accepted does not grant Git or release authority.
190
+ Formal accepted does not grant Git or release authority; Quick cannot become Formal.
183
191
  `;
184
192
 
185
193
  const COMMAND_HELP = Object.freeze({
@@ -255,7 +263,12 @@ Creates the execution and exact writer lease.
255
263
  `,
256
264
  "formal check": `Usage:
257
265
  owlrunkit formal check --workspace <directory> --run-id <id>
258
- --work-item <id> --check-id <id> --cwd <directory> -- <command> [args...]
266
+ --work-item <id> --check-id <id> --envelope <verification-envelope.json>
267
+ owlrunkit formal check --workspace <directory> --run-id <id>
268
+ --work-item <id> --check-id <id> --cwd <directory> -- <built-in-command> [args...]
269
+
270
+ Verification Envelopes admit real project commands only when file, network,
271
+ process, environment, output, timeout, and cleanup constraints are enforced.
259
272
  `,
260
273
  "formal finish": `Usage:
261
274
  owlrunkit formal finish --workspace <directory> --run-id <id>
@@ -324,6 +337,24 @@ profile, preflight, lineage, and result. --request is an advanced legacy path.
324
337
 
325
338
  Shows completed milestones, current state, remaining gates, and the next allowed
326
339
  action without granting any authority.
340
+ `,
341
+ project: `Usage:
342
+ owlrunkit project init --workspace <directory> --definition <project.json>
343
+ owlrunkit project <assign|checkpoint|handoff|decision|capture> --workspace <directory> --request <event.json>
344
+ owlrunkit project status --workspace <directory> [--json]
345
+ owlrunkit project takeover --workspace <directory> --agent <id> [--json]
346
+
347
+ Project status is derived from durable work items, Agent assignments,
348
+ dependencies, decisions, checkpoints, integration gates, and evidence refs.
349
+ No self-reported percentage is accepted.
350
+ `,
351
+ "project status": `Usage:
352
+ owlrunkit project status --workspace <directory> [--json]
353
+ `,
354
+ "project takeover": `Usage:
355
+ owlrunkit project takeover --workspace <directory> --agent <id> [--json]
356
+
357
+ Builds a read-only blank-session recovery packet for one Agent.
327
358
  `,
328
359
  });
329
360
 
@@ -1589,6 +1620,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
1589
1620
  "formal",
1590
1621
  "lease",
1591
1622
  "profiles",
1623
+ "project",
1592
1624
  ]).has(command);
1593
1625
  const [action, ...nestedOptions] = nested ? optionValues : [null, ...optionValues];
1594
1626
  const helpRequested = optionValues.includes("--help")
@@ -1623,6 +1655,8 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
1623
1655
  ? ["json", "verbose", "history"]
1624
1656
  : command === "init"
1625
1657
  ? ["json"]
1658
+ : command === "project" && new Set(["status", "takeover"]).has(action)
1659
+ ? ["json"]
1626
1660
  : command === "doctor" || command === "adopt" || command === "status"
1627
1661
  ? ["json"]
1628
1662
  : command === "profiles"
@@ -2230,10 +2264,30 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2230
2264
  });
2231
2265
  }
2232
2266
  if (action === "check") {
2267
+ const workItemId = options["work-item"] ?? options["from-lease"] ?? "delivery";
2268
+ if (
2269
+ options["work-item"] !== undefined
2270
+ && options["from-lease"] !== undefined
2271
+ && options["work-item"] !== options["from-lease"]
2272
+ ) {
2273
+ throw new Error("formal check work-item and legacy from-lease must match.");
2274
+ }
2275
+ if (options.envelope !== undefined) {
2276
+ if (commandArgv.length > 0) {
2277
+ throw new Error("formal check accepts either --envelope or an exact built-in command, not both.");
2278
+ }
2279
+ return await recordFormalEnvelopeCheckV1({
2280
+ workspaceRoot: workspace(options),
2281
+ runId: safeRunId(requireOption(options, "run-id")),
2282
+ workItemId,
2283
+ checkId: requireOption(options, "check-id"),
2284
+ envelope: readJson(realpathSync(requireOption(options, "envelope"))),
2285
+ });
2286
+ }
2233
2287
  return recordFormalCheckV1({
2234
2288
  workspaceRoot: workspace(options),
2235
2289
  runId: safeRunId(requireOption(options, "run-id")),
2236
- workItemId: options["from-lease"] ?? "delivery",
2290
+ workItemId,
2237
2291
  checkId: requireOption(options, "check-id"),
2238
2292
  cwd: options.cwd ?? ".",
2239
2293
  commandArgv,
@@ -2350,6 +2404,43 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2350
2404
  ].join("\n"),
2351
2405
  );
2352
2406
  }
2407
+ if (command === "project") {
2408
+ const root = requireOption(options, "workspace");
2409
+ if (action === "init") {
2410
+ return initializeTeamProjectV1({
2411
+ workspaceRoot: root,
2412
+ definition: readJson(realpathSync(requireOption(options, "definition"))),
2413
+ });
2414
+ }
2415
+ if (new Set(["assign", "checkpoint", "handoff", "decision", "capture"]).has(action)) {
2416
+ return appendTeamProjectEventV1({
2417
+ workspaceRoot: root,
2418
+ event: readJson(realpathSync(requireOption(options, "request"))),
2419
+ });
2420
+ }
2421
+ if (action === "status") {
2422
+ const status = readTeamProjectStatusV1({ workspaceRoot: root });
2423
+ return options.json === true
2424
+ ? status
2425
+ : withHumanOutput(status, formatTeamProjectStatusHumanV1(status));
2426
+ }
2427
+ if (action === "takeover") {
2428
+ const takeover = buildTeamProjectTakeoverV1({
2429
+ workspaceRoot: root,
2430
+ agentId: requireOption(options, "agent"),
2431
+ });
2432
+ return options.json === true
2433
+ ? takeover
2434
+ : withHumanOutput(takeover, [
2435
+ `${takeover.projectId}: ${takeover.objective}`,
2436
+ `Agent: ${takeover.agentId}`,
2437
+ `Responsibility: ${takeover.currentResponsibility?.workItemId ?? "none"}`,
2438
+ `Next: ${takeover.nextAction ?? "none"}`,
2439
+ "",
2440
+ ].join("\n"));
2441
+ }
2442
+ throw new Error("Usage: owlrunkit project <init|assign|checkpoint|handoff|decision|capture|status|takeover> [options]");
2443
+ }
2353
2444
  if (command === "profiles") {
2354
2445
  const root = requireOption(options, "workspace");
2355
2446
  if (action === "detect") {
@@ -2513,7 +2604,7 @@ export async function runCli(argv = process.argv.slice(2), runtimeHooks = {}) {
2513
2604
  return withControlTransaction(root, () => closeout(options));
2514
2605
  }
2515
2606
  if (command === "finish") return finishExecution(options);
2516
- throw new Error("Usage: owlrunkit <init|doctor|adopt|assurance|fleet|profiles|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-attest|quick-metrics|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
2607
+ throw new Error("Usage: owlrunkit <init|doctor|adopt|assurance|fleet|profiles|project|status|formal|candidate|deployment|core-successor|start|verify|repair|offline-export|offline-import|quick-verify|quick-attest|quick-metrics|finish|plan|inspect|lease|delivery|coverage-adopt|resume|verify-plan|resource-preflight|snapshot|visual-smoke|finalize|ready-for-commit|closeout> [options]");
2517
2608
  } catch (error) {
2518
2609
  return {
2519
2610
  status: "invalid_input",
@@ -0,0 +1,108 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://owlcoda.com/schemas/runkit/team-project-definition-v1.schema.json",
4
+ "title": "OwlCoda RunKit Team Project Definition V1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "projectId", "objective", "milestones", "workstreams", "workItems", "integrationGates"],
8
+ "properties": {
9
+ "schemaVersion": { "const": "OwlCodaRunKitTeamProjectDefinitionV1" },
10
+ "projectId": { "$ref": "#/$defs/id" },
11
+ "objective": { "type": "string", "minLength": 1 },
12
+ "milestones": {
13
+ "type": "array",
14
+ "items": { "$ref": "#/$defs/milestone" }
15
+ },
16
+ "workstreams": {
17
+ "type": "array",
18
+ "items": { "$ref": "#/$defs/workstream" }
19
+ },
20
+ "workItems": {
21
+ "type": "array",
22
+ "minItems": 1,
23
+ "items": { "$ref": "#/$defs/workItem" }
24
+ },
25
+ "integrationGates": {
26
+ "type": "array",
27
+ "items": { "$ref": "#/$defs/integrationGate" }
28
+ }
29
+ },
30
+ "$defs": {
31
+ "id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$" },
32
+ "strings": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
33
+ "milestone": {
34
+ "type": "object",
35
+ "additionalProperties": false,
36
+ "required": ["id", "title"],
37
+ "properties": {
38
+ "id": { "$ref": "#/$defs/id" },
39
+ "title": { "type": "string", "minLength": 1 }
40
+ }
41
+ },
42
+ "workstream": {
43
+ "type": "object",
44
+ "additionalProperties": false,
45
+ "required": ["id", "title", "milestoneId"],
46
+ "properties": {
47
+ "id": { "$ref": "#/$defs/id" },
48
+ "title": { "type": "string", "minLength": 1 },
49
+ "milestoneId": { "$ref": "#/$defs/id" }
50
+ }
51
+ },
52
+ "workItem": {
53
+ "type": "object",
54
+ "additionalProperties": false,
55
+ "required": ["id", "title", "milestoneId", "workstreamId", "dependencies", "ownedPaths"],
56
+ "properties": {
57
+ "id": { "$ref": "#/$defs/id" },
58
+ "title": { "type": "string", "minLength": 1 },
59
+ "milestoneId": { "$ref": "#/$defs/id" },
60
+ "workstreamId": { "$ref": "#/$defs/id" },
61
+ "dependencies": { "$ref": "#/$defs/strings" },
62
+ "ownedPaths": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
63
+ "measurable": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "required": ["unit", "total"],
67
+ "properties": {
68
+ "unit": { "type": "string", "minLength": 1 },
69
+ "total": { "type": "integer", "minimum": 1 }
70
+ }
71
+ }
72
+ }
73
+ },
74
+ "integrationGate": {
75
+ "type": "object",
76
+ "additionalProperties": false,
77
+ "required": ["id", "title", "requiredWorkItemIds", "requiredDecisionIds"],
78
+ "properties": {
79
+ "id": { "$ref": "#/$defs/id" },
80
+ "title": { "type": "string", "minLength": 1 },
81
+ "requiredWorkItemIds": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/id" } },
82
+ "requiredDecisionIds": { "$ref": "#/$defs/strings" }
83
+ }
84
+ }
85
+ },
86
+ "examples": [{
87
+ "schemaVersion": "OwlCodaRunKitTeamProjectDefinitionV1",
88
+ "projectId": "release-017",
89
+ "objective": "Ship OwlRunKit 0.17",
90
+ "milestones": [{ "id": "m1", "title": "Product" }],
91
+ "workstreams": [{ "id": "runtime", "title": "Runtime", "milestoneId": "m1" }],
92
+ "workItems": [{
93
+ "id": "engine",
94
+ "title": "Implement the engine",
95
+ "milestoneId": "m1",
96
+ "workstreamId": "runtime",
97
+ "dependencies": [],
98
+ "ownedPaths": ["scripts/runkit-contract/**"],
99
+ "measurable": { "unit": "acceptance_tests", "total": 4 }
100
+ }],
101
+ "integrationGates": [{
102
+ "id": "ready",
103
+ "title": "Ready",
104
+ "requiredWorkItemIds": ["engine"],
105
+ "requiredDecisionIds": []
106
+ }]
107
+ }]
108
+ }
@@ -0,0 +1,99 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://owlcoda.com/schemas/runkit/team-project-event-v1.schema.json",
4
+ "title": "OwlCoda RunKit Team Project Event V1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "eventId", "type", "occurredAt"],
8
+ "properties": {
9
+ "schemaVersion": { "const": "OwlCodaRunKitTeamProjectEventV1" },
10
+ "eventId": { "$ref": "#/$defs/id" },
11
+ "type": { "enum": ["agent_assigned", "checkpoint_recorded", "handoff_recorded", "decision_opened", "decision_resolved", "integration_gate_passed", "data_candidate_recorded"] },
12
+ "occurredAt": { "type": "string", "minLength": 24 },
13
+ "assignmentId": { "$ref": "#/$defs/id" },
14
+ "supersedesAssignmentId": { "$ref": "#/$defs/id" },
15
+ "workItemId": { "$ref": "#/$defs/id" },
16
+ "agentId": { "$ref": "#/$defs/id" },
17
+ "executionRunId": { "$ref": "#/$defs/id" },
18
+ "executionWorkItemId": { "$ref": "#/$defs/id" },
19
+ "state": { "enum": ["active", "waiting_dependency", "waiting_decision", "verifying", "ready_to_integrate", "completed", "failed"] },
20
+ "summary": { "type": "string", "minLength": 1 },
21
+ "completedUnits": { "type": "integer", "minimum": 0 },
22
+ "evidenceRefs": { "$ref": "#/$defs/strings" },
23
+ "blockerRefs": { "$ref": "#/$defs/strings" },
24
+ "decisionRefs": { "$ref": "#/$defs/strings" },
25
+ "nextAction": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
26
+ "sourceFingerprint": { "type": "string", "pattern": "^(sha256:)?[a-f0-9]{64}$" },
27
+ "fromAgentId": { "$ref": "#/$defs/id" },
28
+ "toAgentId": { "$ref": "#/$defs/id" },
29
+ "decisionId": { "$ref": "#/$defs/id" },
30
+ "title": { "type": "string", "minLength": 1 },
31
+ "question": { "type": "string", "minLength": 1 },
32
+ "ownerAgentId": { "$ref": "#/$defs/id" },
33
+ "blockingWorkItemIds": { "$ref": "#/$defs/strings" },
34
+ "options": { "$ref": "#/$defs/strings" },
35
+ "resolution": { "type": "string", "minLength": 1 },
36
+ "rationale": { "type": "string", "minLength": 1 },
37
+ "gateId": { "$ref": "#/$defs/id" },
38
+ "candidateId": { "$ref": "#/$defs/id" },
39
+ "sourceRef": { "type": "string", "minLength": 1 },
40
+ "rights": { "type": "string", "minLength": 1 },
41
+ "inputRef": { "type": "string", "minLength": 1 },
42
+ "outputRef": { "type": "string", "minLength": 1 },
43
+ "decisionRef": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
44
+ "verificationRefs": { "$ref": "#/$defs/strings" },
45
+ "outcomeRef": { "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] },
46
+ "version": { "type": "string", "minLength": 1 }
47
+ },
48
+ "allOf": [
49
+ {
50
+ "if": { "properties": { "type": { "const": "agent_assigned" } }, "required": ["type"] },
51
+ "then": {
52
+ "required": ["assignmentId", "workItemId", "agentId"],
53
+ "dependentRequired": {
54
+ "executionRunId": ["executionWorkItemId"],
55
+ "executionWorkItemId": ["executionRunId"]
56
+ }
57
+ }
58
+ },
59
+ {
60
+ "if": { "properties": { "type": { "const": "checkpoint_recorded" } }, "required": ["type"] },
61
+ "then": { "required": ["assignmentId", "workItemId", "state", "summary", "evidenceRefs", "blockerRefs", "decisionRefs", "nextAction"] }
62
+ },
63
+ {
64
+ "if": { "properties": { "type": { "const": "handoff_recorded" } }, "required": ["type"] },
65
+ "then": { "required": ["assignmentId", "workItemId", "fromAgentId", "toAgentId", "summary", "evidenceRefs", "nextAction"] }
66
+ },
67
+ {
68
+ "if": { "properties": { "type": { "const": "decision_opened" } }, "required": ["type"] },
69
+ "then": { "required": ["decisionId", "title", "question", "ownerAgentId", "blockingWorkItemIds", "options"] }
70
+ },
71
+ {
72
+ "if": { "properties": { "type": { "const": "decision_resolved" } }, "required": ["type"] },
73
+ "then": { "required": ["decisionId", "resolution", "rationale", "evidenceRefs"] }
74
+ },
75
+ {
76
+ "if": { "properties": { "type": { "const": "integration_gate_passed" } }, "required": ["type"] },
77
+ "then": { "required": ["gateId", "summary", "evidenceRefs"] }
78
+ },
79
+ {
80
+ "if": { "properties": { "type": { "const": "data_candidate_recorded" } }, "required": ["type"] },
81
+ "then": { "required": ["candidateId", "sourceRef", "rights", "inputRef", "outputRef", "decisionRef", "verificationRefs", "outcomeRef", "version"] }
82
+ }
83
+ ],
84
+ "$defs": {
85
+ "id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$" },
86
+ "strings": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } }
87
+ },
88
+ "examples": [{
89
+ "schemaVersion": "OwlCodaRunKitTeamProjectEventV1",
90
+ "eventId": "event-001",
91
+ "type": "agent_assigned",
92
+ "occurredAt": "2026-08-08T00:00:00.000Z",
93
+ "assignmentId": "assignment-001",
94
+ "workItemId": "engine",
95
+ "agentId": "agent-runtime",
96
+ "executionRunId": "formal-engine-001",
97
+ "executionWorkItemId": "delivery"
98
+ }]
99
+ }