feat(persona, dispatch): Phase 0 — full §6 schema + dispatch envelope contracts#95
Conversation
|
Warning Review limit reached
Your plan currently allows 1 review/hour. Refill in 51 minutes and 52 seconds. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more review capacity refills, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (19)
📝 WalkthroughWalkthroughThis PR introduces two new TypeScript contract packages to the monorepo: ChangesDispatch and Persona Contract Packages
🎯 3 (Moderate) | ⏱️ ~25 minutes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/persona/src/consumer-fixture.test.ts (1)
8-8: ⚡ Quick winUse
PERSONA_SCHEMA_URLinstead of repeating the schema literal.This prevents fixture drift when the schema URL/version changes.
Suggested update
-import type { PersonaDefinition } from "./index.js"; +import { PERSONA_SCHEMA_URL, type PersonaDefinition } from "./index.js"; @@ - $schema: "https://schemas.agent-assistant.dev/persona/0.1.0/persona.schema.json", + $schema: PERSONA_SCHEMA_URL, @@ - $schema: "https://schemas.agent-assistant.dev/persona/0.1.0/persona.schema.json", + $schema: PERSONA_SCHEMA_URL, @@ - $schema: "https://schemas.agent-assistant.dev/persona/0.1.0/persona.schema.json", + $schema: PERSONA_SCHEMA_URL, @@ - $schema: "https://schemas.agent-assistant.dev/persona/0.1.0/persona.schema.json", + $schema: PERSONA_SCHEMA_URL,Also applies to: 65-65, 120-120, 176-176
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/persona/src/consumer-fixture.test.ts` at line 8, Replace the hard-coded schema string ("https://schemas.agent-assistant.dev/persona/0.1.0/persona.schema.json") in the test fixtures with the shared constant PERSONA_SCHEMA_URL: import or reference PERSONA_SCHEMA_URL and use it wherever the $schema literal appears (the occurrences noted around the file), ensuring all fixtures ($schema keys at each occurrence) use PERSONA_SCHEMA_URL to avoid repeating the literal and prevent drift when the schema URL/version changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/publish.yml:
- Around line 93-94: The PACKAGES array was updated to include "persona" and
"dispatch" but the build ORDER array (used by the build loop and later
copy/publish steps referencing packages/$pkg/dist) was not updated, so add
"persona" and "dispatch" to the ORDER array in the workflow OR remove them from
PACKAGES if they should not be built/published; update the ORDER definition (the
variable named ORDER) to include the same package names in the correct sequence
so the build loop and subsequent copy/publish steps operate on the same set of
packages.
In `@packages/persona/MIGRATION-0.4.35.md`:
- Around line 64-77: Add a single blank line after the Markdown nested table
(the table containing rows like `router.endpoint` → `router.url`,
`sandbox.lifecycle?` → `sandbox.lifecycle`, and `sandbox.maxConcurrentBorrows?`
→ `sandbox.maxConcurrentBorrows`) so the following list item starting with "-
**`inbox` entries require `pattern`.**" is separated from the table for proper
markdown parsing.
---
Nitpick comments:
In `@packages/persona/src/consumer-fixture.test.ts`:
- Line 8: Replace the hard-coded schema string
("https://schemas.agent-assistant.dev/persona/0.1.0/persona.schema.json") in the
test fixtures with the shared constant PERSONA_SCHEMA_URL: import or reference
PERSONA_SCHEMA_URL and use it wherever the $schema literal appears (the
occurrences noted around the file), ensuring all fixtures ($schema keys at each
occurrence) use PERSONA_SCHEMA_URL to avoid repeating the literal and prevent
drift when the schema URL/version changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 455c2f2e-0310-408a-be2c-218b8c7e59ab
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (19)
.github/workflows/publish.ymlpackage.jsonpackages/dispatch/CHANGELOG.mdpackages/dispatch/README.mdpackages/dispatch/package.jsonpackages/dispatch/src/index.tspackages/dispatch/src/types.test.tspackages/dispatch/src/types.tspackages/dispatch/tsconfig.jsonpackages/persona/CHANGELOG.mdpackages/persona/MIGRATION-0.4.35.mdpackages/persona/README.mdpackages/persona/package.jsonpackages/persona/src/consumer-fixture.test.tspackages/persona/src/index.tspackages/persona/src/types.test.tspackages/persona/src/types.tspackages/persona/tsconfig.build.jsonpackages/persona/tsconfig.json
| PACKAGES='["persona","dispatch","traits","connectivity","coordination","core","sessions","surfaces","policy","proactive","harness","telemetry","memory","turn-context","inbox","continuation","sdk","vfs","specialists","webhook-runtime"]' | ||
| FIRST='persona' |
There was a problem hiding this comment.
Matrix now includes packages that the build loop never builds.
After adding persona and dispatch to PACKAGES (Line 93), they are still missing from the build ORDER array (Line 170). That means this workflow can skip building them, then fail when copying packages/$pkg/dist (Line 275) or publish stale artifacts.
Suggested fix
- ORDER=(traits connectivity coordination core sessions surfaces policy proactive harness telemetry memory turn-context inbox continuation sdk vfs specialists webhook-runtime)
+ ORDER=(persona dispatch traits connectivity coordination core sessions surfaces policy proactive harness telemetry memory turn-context inbox continuation sdk vfs specialists webhook-runtime)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/publish.yml around lines 93 - 94, The PACKAGES array was
updated to include "persona" and "dispatch" but the build ORDER array (used by
the build loop and later copy/publish steps referencing packages/$pkg/dist) was
not updated, so add "persona" and "dispatch" to the ORDER array in the workflow
OR remove them from PACKAGES if they should not be built/published; update the
ORDER definition (the variable named ORDER) to include the same package names in
the correct sequence so the build loop and subsequent copy/publish steps operate
on the same set of packages.
| | 0.4.35 nested field | 0.5.0 nested field | | ||
| | --- | --- | | ||
| | `router.endpoint` | `router.url` | | ||
| | `router.timeoutMs` | `router.timeoutSeconds` (convert milliseconds to seconds) | | ||
| | `router.method` | Removed; 0.5.0 does not model an HTTP method here. | | ||
| | `router.headers` | Use `router.auth` for shared-secret auth or move provider-specific headers into integration config. | | ||
| | — | Add required `router.kind` (for example, `"workerd-service"`). | | ||
| | — | Add required `router.auth` with `kind: "shared-secret"` and `envVar`. | | ||
| | `sandbox.lifecycle?` | `sandbox.lifecycle` is now required (`"warm-pool"` or `"ephemeral"`). | | ||
| | `sandbox.ttlSeconds` | Use `sandbox.idleStopMinutes` when modeling warm-pool idle shutdown. | | ||
| | `sandbox.capabilities` | Removed from `SandboxBorrowConfig`; model capabilities outside persona schema if still needed. | | ||
| | — | Add required `sandbox.borrowProtocol: "v1"`. | | ||
| | `sandbox.maxConcurrentBorrows?` | `sandbox.maxConcurrentBorrows` is now required. | | ||
| - **`inbox` entries require `pattern`.** Convert old channel/event filters into a |
There was a problem hiding this comment.
Add blank line after nested table.
Markdown tables should be surrounded by blank lines for proper rendering and parser compatibility. The nested table at lines 64-76 needs a blank line before the next list item.
📝 Proposed fix
| `sandbox.capabilities` | Removed from `SandboxBorrowConfig`; model capabilities outside persona schema if still needed. |
| — | Add required `sandbox.borrowProtocol: "v1"`. |
| `sandbox.maxConcurrentBorrows?` | `sandbox.maxConcurrentBorrows` is now required. |
+
- **`inbox` entries require `pattern`.** Convert old channel/event filters into a
single canonical pattern such as `"`#sage`"`, `"`@self`"`, a channel id, or a user id.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | 0.4.35 nested field | 0.5.0 nested field | | |
| | --- | --- | | |
| | `router.endpoint` | `router.url` | | |
| | `router.timeoutMs` | `router.timeoutSeconds` (convert milliseconds to seconds) | | |
| | `router.method` | Removed; 0.5.0 does not model an HTTP method here. | | |
| | `router.headers` | Use `router.auth` for shared-secret auth or move provider-specific headers into integration config. | | |
| | — | Add required `router.kind` (for example, `"workerd-service"`). | | |
| | — | Add required `router.auth` with `kind: "shared-secret"` and `envVar`. | | |
| | `sandbox.lifecycle?` | `sandbox.lifecycle` is now required (`"warm-pool"` or `"ephemeral"`). | | |
| | `sandbox.ttlSeconds` | Use `sandbox.idleStopMinutes` when modeling warm-pool idle shutdown. | | |
| | `sandbox.capabilities` | Removed from `SandboxBorrowConfig`; model capabilities outside persona schema if still needed. | | |
| | — | Add required `sandbox.borrowProtocol: "v1"`. | | |
| | `sandbox.maxConcurrentBorrows?` | `sandbox.maxConcurrentBorrows` is now required. | | |
| - **`inbox` entries require `pattern`.** Convert old channel/event filters into a | |
| | 0.4.35 nested field | 0.5.0 nested field | | |
| | --- | --- | | |
| | `router.endpoint` | `router.url` | | |
| | `router.timeoutMs` | `router.timeoutSeconds` (convert milliseconds to seconds) | | |
| | `router.method` | Removed; 0.5.0 does not model an HTTP method here. | | |
| | `router.headers` | Use `router.auth` for shared-secret auth or move provider-specific headers into integration config. | | |
| | — | Add required `router.kind` (for example, `"workerd-service"`). | | |
| | — | Add required `router.auth` with `kind: "shared-secret"` and `envVar`. | | |
| | `sandbox.lifecycle?` | `sandbox.lifecycle` is now required (`"warm-pool"` or `"ephemeral"`). | | |
| | `sandbox.ttlSeconds` | Use `sandbox.idleStopMinutes` when modeling warm-pool idle shutdown. | | |
| | `sandbox.capabilities` | Removed from `SandboxBorrowConfig`; model capabilities outside persona schema if still needed. | | |
| | — | Add required `sandbox.borrowProtocol: "v1"`. | | |
| | `sandbox.maxConcurrentBorrows?` | `sandbox.maxConcurrentBorrows` is now required. | | |
| - **`inbox` entries require `pattern`.** Convert old channel/event filters into a | |
| single canonical pattern such as `"`#sage`"`, `"`@self`"`, a channel id, or a user id. |
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 76-76: Tables should be surrounded by blank lines
(MD058, blanks-around-tables)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/persona/MIGRATION-0.4.35.md` around lines 64 - 77, Add a single
blank line after the Markdown nested table (the table containing rows like
`router.endpoint` → `router.url`, `sandbox.lifecycle?` → `sandbox.lifecycle`,
and `sandbox.maxConcurrentBorrows?` → `sandbox.maxConcurrentBorrows`) so the
following list item starting with "- **`inbox` entries require `pattern`.**" is
separated from the table for proper markdown parsing.
| export interface PersonaDefinition { | ||
| $schema?: typeof PERSONA_SCHEMA_URL | string; | ||
| id: string; | ||
| intent: string; | ||
| description: string; | ||
| tags?: string[]; | ||
| cloud?: boolean; | ||
| useSubscription?: boolean; | ||
| ownerService?: string; | ||
| schedules?: PersonaSchedule[]; | ||
| inbox?: InboxTrigger[]; | ||
| integrations?: Record<string, IntegrationDecl>; | ||
| watch?: WatchRule[]; | ||
| mount?: PersonaMount; | ||
| executor: PersonaExecutor; | ||
| memory?: MemoryConfig; | ||
| delivery?: DeliveryChannel[]; | ||
| onEvent?: string; | ||
| harness?: "claude" | "codex" | "opencode"; | ||
| model?: string; | ||
| systemPrompt?: string; | ||
| harnessSettings?: HarnessSettings; | ||
| inputs?: Record<string, InputDecl>; |
There was a problem hiding this comment.
Encode executor-specific fields as a discriminated union.
The current PersonaDefinition allows ephemeral-only fields for non-ephemeral executors, so invalid persona documents can still type-check.
Suggested contract hardening
-export interface PersonaDefinition {
+interface PersonaDefinitionBase {
$schema?: typeof PERSONA_SCHEMA_URL | string;
id: string;
intent: string;
description: string;
tags?: string[];
cloud?: boolean;
useSubscription?: boolean;
ownerService?: string;
schedules?: PersonaSchedule[];
inbox?: InboxTrigger[];
integrations?: Record<string, IntegrationDecl>;
watch?: WatchRule[];
mount?: PersonaMount;
- executor: PersonaExecutor;
memory?: MemoryConfig;
delivery?: DeliveryChannel[];
+}
+
+interface EphemeralPersonaDefinition extends PersonaDefinitionBase {
+ executor: { kind: "ephemeral-sandbox" };
onEvent?: string;
harness?: "claude" | "codex" | "opencode";
model?: string;
systemPrompt?: string;
harnessSettings?: HarnessSettings;
inputs?: Record<string, InputDecl>;
}
+
+interface RoutedPersonaDefinition extends PersonaDefinitionBase {
+ executor:
+ | { kind: "http-delegate"; router: RouterConfig }
+ | { kind: "hybrid"; router: RouterConfig; sandbox: SandboxBorrowConfig };
+ onEvent?: never;
+ harness?: never;
+ model?: never;
+ systemPrompt?: never;
+ harnessSettings?: never;
+ inputs?: never;
+}
+
+export type PersonaDefinition = EphemeralPersonaDefinition | RoutedPersonaDefinition;There was a problem hiding this comment.
2 issues found across 20 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="package.json">
<violation number="1" location="package.json:31">
P2: Root `typecheck` script only covers 2 of 13+ packages that have typecheck scripts. The generic name implies full project coverage, but it will miss TypeScript errors in the other 11+ packages (traits, core, routing, sdk, etc.). Consider using `npm run typecheck --workspaces --if-present` so all workspaces with typecheck scripts are covered, or rename this to something specific like `typecheck:dispatch-persona` if it's intentionally scoped.</violation>
</file>
<file name=".github/workflows/publish.yml">
<violation number="1" location=".github/workflows/publish.yml:93">
P1: The publish matrix includes `persona`/`dispatch`, but the dependency-aware build order does not build them before artifacts are collected.</violation>
</file>
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
| FIRST='traits' | ||
| # persona + dispatch (Phase 0 of proactive-unification) are types-only | ||
| # packages with zero runtime deps — added at the head of the matrix. | ||
| PACKAGES='["persona","dispatch","traits","connectivity","coordination","core","sessions","surfaces","policy","proactive","harness","telemetry","memory","turn-context","inbox","continuation","sdk","vfs","specialists","webhook-runtime"]' |
There was a problem hiding this comment.
P1: The publish matrix includes persona/dispatch, but the dependency-aware build order does not build them before artifacts are collected.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/publish.yml, line 93:
<comment>The publish matrix includes `persona`/`dispatch`, but the dependency-aware build order does not build them before artifacts are collected.</comment>
<file context>
@@ -88,8 +88,10 @@ jobs:
- FIRST='traits'
+ # persona + dispatch (Phase 0 of proactive-unification) are types-only
+ # packages with zero runtime deps — added at the head of the matrix.
+ PACKAGES='["persona","dispatch","traits","connectivity","coordination","core","sessions","surfaces","policy","proactive","harness","telemetry","memory","turn-context","inbox","continuation","sdk","vfs","specialists","webhook-runtime"]'
+ FIRST='persona'
;;
</file context>
| "packages/webhook-runtime" | ||
| ], | ||
| "scripts": { | ||
| "typecheck": "npm run typecheck -w @agent-assistant/dispatch && npm run typecheck -w @agent-assistant/persona", |
There was a problem hiding this comment.
P2: Root typecheck script only covers 2 of 13+ packages that have typecheck scripts. The generic name implies full project coverage, but it will miss TypeScript errors in the other 11+ packages (traits, core, routing, sdk, etc.). Consider using npm run typecheck --workspaces --if-present so all workspaces with typecheck scripts are covered, or rename this to something specific like typecheck:dispatch-persona if it's intentionally scoped.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At package.json, line 31:
<comment>Root `typecheck` script only covers 2 of 13+ packages that have typecheck scripts. The generic name implies full project coverage, but it will miss TypeScript errors in the other 11+ packages (traits, core, routing, sdk, etc.). Consider using `npm run typecheck --workspaces --if-present` so all workspaces with typecheck scripts are covered, or rename this to something specific like `typecheck:dispatch-persona` if it's intentionally scoped.</comment>
<file context>
@@ -16,16 +16,19 @@
"packages/webhook-runtime"
],
"scripts": {
+ "typecheck": "npm run typecheck -w @agent-assistant/dispatch && npm run typecheck -w @agent-assistant/persona",
"build:sdk": "npm run build -w @agent-assistant/sdk",
"agent": "RELAY_AUTO_SPAWN=false RELAY_CHANNEL=specialists RELAY_WORKER=specialist-worker RELAY_CLI=claude RELAY_MODEL=claude-sonnet-4-6 npm run cli -w @agent-assistant/webhook-runtime",
</file context>
| "typecheck": "npm run typecheck -w @agent-assistant/dispatch && npm run typecheck -w @agent-assistant/persona", | |
| "typecheck": "npm run typecheck --workspaces --if-present", |
… contracts Lands the substrate for the proactive-unification effort (sage/specs/proactive-unification.md §16.5 PR-0.1 + PR-0.2): - packages/persona@0.5.0: full canonical-spec §6 PersonaDefinition. Replaces the reduced 0.4.35 schema with the 16-field shape Sage's dispatcher actually routes against (schedules[]/inbox[]/integrations/ watch[]/mount). Breaking from 0.4.35 — see MIGRATION-0.4.35.md. - packages/dispatch@0.1.0: NEW. DispatchEnvelope + DispatchResponse + callback types from canonical spec §7.2 + §7.5. - publish.yml runtime-core matrix: prepend persona + dispatch. - package.json + package-lock.json: register the two new workspaces. Build + test green for both packages (9 + 7 tests). Downstream sage keeps its local mirrors until 0.5.0 / 0.1.0 publish to npm; see sage/specs/proactive-unification/by-repo/sage.md PR-3.3 fallback. Generated by the proactive-unification orchestrator (sage/scripts/run-proactive-unification.mjs); manually shipped because the generated workflow omitted GitHub primitive shipping steps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8b45c11 to
108ba54
Compare
Summary
Phase 0 substrate for the proactive-unification effort. Driven by canonical spec
sage/specs/proactive-unification.md§16.5 PR-0.1 + PR-0.2.@agent-assistant/persona@0.5.0— full canonical-spec §6PersonaDefinition(16 fields withschedules[],inbox[],integrations,watch[],mount). Breaking from the published 0.4.35 stub, which had a reducedtriggers[]union that downstream consumers (sage's dispatcher, cloud's persona-register endpoint) cannot route against. Migration table:packages/persona/MIGRATION-0.4.35.md.@agent-assistant/dispatch@0.1.0(new) —DispatchEnvelope+DispatchResponse+ callback types from canonical spec §7.2 + §7.5.publish.yml— prependpersona+dispatchto theruntime-corematrix so aworkflow_dispatchpublishes them alongside the rest.package.json+package-lock.json— register the two new workspaces. The lockfile diff also normalizes ~1180 lines of pre-existing stale entries (npm install ran on a workspace that drifted prior to this PR); the net change for THIS PR is the two new workspace links.Why this was shipped manually
This was generated by the proactive-unification orchestrator (
sage/scripts/run-proactive-unification.mjs). Ricky completed lead-plan → implement → reviewer-claude + reviewer-codex → fix loops → final-hard-validation → final-signoff successfully, but the generated workflow omitted the GitHub primitive shipping steps (createGitHubStep/gh pr create). The orchestrator caught this aspublish-failed: no open ricky/* PRs found in this repo. Manual commit + push + PR to unblock downstream sage / workforce / cloud work.What this unblocks
workforce#130follow-up:persona-kitmigrates to@agent-assistant/persona@^0.5.0.sagePR #214 follow-up (PR-3.4): drops local mirrors insrc/proactive-dispatch/{contracts,persona-types}.ts; imports from the published packages instead.cloudPR-1.1:/api/v1/personas/registerendpoint validates against@agent-assistant/persona@^0.5.0.Verification
packages/persona/src/consumer-fixture.test.tsconstructs sage's four canonical personas (morning-briefing,follow-up-sweep,pr-matcher,stale-threads) using the new types — no TS errors.Publish flow
After merge, trigger:
This will publish
@agent-assistant/persona@0.5.0and@agent-assistant/dispatch@0.1.0(alongside a minor bump of all other runtime-core packages). If publishing only the new packages is preferred, use-f custom_version=per-package or split the matrix into a newpackage_group=phase0-substratevalue.Test plan
npm run build -w @agent-assistant/persona && npm test -w @agent-assistant/personanpm run build -w @agent-assistant/dispatch && npm test -w @agent-assistant/dispatchMIGRATION-0.4.35.mdaccurately describes the breaking changepublish.ymlmatrix change is acceptable, or operator prefers a separate package_groupnpm installregenerate as a follow-up commit)Ricky run metadata
276d85ac4c495632707a3b6e(in agent-assistant.agent-relay/workflow-runs.jsonl)agent-assistant/.trajectories/active/sage/.agent-relay/run-proactive-unification.json🤖 Generated with Claude Code