From c319d15e0ca3aa378fa432cc9119463235f45656 Mon Sep 17 00:00:00 2001 From: Ricky Schema Cascade Date: Wed, 13 May 2026 10:38:58 +0200 Subject: [PATCH 1/5] chore(publish): add runtime + deploy + mcp-workforce to the publish allow-list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The publish.yml allow-list was last updated when the workspace had 5 packages (persona-kit, workload-router, cli, daytona-runner, agentworkforce). The deploy-v1 cascade shipped 3 more under @agentworkforce/* that the existing cli already depends on: - @agentworkforce/runtime (consumed by deploy, mcp-workforce) - @agentworkforce/deploy (consumed by cli) - @agentworkforce/mcp-workforce (consumed by harness CLIs via MCP) cli@3.0.1 already declares `@agentworkforce/deploy@0.0.0` as a runtime dep, but deploy was never published — the 0.0.0 on npm is a placeholder, so `npm i agentworkforce` today pulls a stub for `workforce deploy`. The same applies to deploy/mcp-workforce's runtime dep. This change preserves lockstep umbrella semantics and orders the publish in topological order (runtime before deploy/mcp-workforce, deploy before cli, cli before agentworkforce). personas-core stays on publish-personas.yml as before — not added here. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/publish.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9066e8b6..d238e4dc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -85,11 +85,17 @@ jobs: - name: Resolve target packages id: targets run: | - # Dependency order: persona-kit → workload-router → cli → agentworkforce. - # persona-kit is a leaf dep consumed by workload-router and cli, so it - # must publish first. The top-level `agentworkforce` wrapper depends on - # `@agentworkforce/cli`, so it must publish last. - echo "packages=persona-kit workload-router cli daytona-runner agentworkforce" >> "$GITHUB_OUTPUT" + # Dependency order (topological): + # persona-kit (leaf — consumed by everyone) + # runtime (→ persona-kit; consumed by deploy + mcp-workforce) + # workload-router (→ persona-kit; consumed by cli) + # deploy (→ persona-kit + runtime; consumed by cli) + # mcp-workforce (→ persona-kit + runtime) + # daytona-runner (no workspace deps) + # cli (→ persona-kit + workload-router + deploy) + # agentworkforce (→ cli — umbrella wrapper, must publish last) + # personas-core publishes via the separate publish-personas.yml workflow. + echo "packages=persona-kit runtime workload-router deploy mcp-workforce daytona-runner cli agentworkforce" >> "$GITHUB_OUTPUT" # Lockstep baseline heal. The workspace publishes every package at the # same version, so if any package's local version lags either its own From 0d908785d526ec6b4e7f159ad8e8f230019d31d2 Mon Sep 17 00:00:00 2001 From: Ricky Schema Cascade Date: Wed, 13 May 2026 10:43:34 +0200 Subject: [PATCH 2/5] fix(mcp-workforce): align memory scope enum with PersonaMemoryScope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mcp-workforce was landed in #91 against an older `PersonaMemoryScope` shape (`session | user | workspace | org | object`). #94 then tightened the type to `workspace | user | global`. Both PRs passed CI independently, but main is now broken at build time because the zod enum in `server.ts` and the runtime `VALID_SCOPES` Set in `tools/memory.ts` still reference the removed literals. Aligning both call sites to the canonical persona-kit shape: - `MEMORY_SCOPE_ENUM` → z.enum(['workspace', 'user', 'global']) - `VALID_SCOPES` → new Set(['workspace', 'user', 'global']) - memory.save tool description updated to match The default scope stays `workspace`. Callers that previously passed `'session'`/`'org'`/`'object'` will now get a validation error from the zod schema before the runtime check — preferable to silently mapping them to a different scope. Verified: `pnpm -F @agentworkforce/mcp-workforce typecheck` + `build` + `test` (23/23) all pass. Co-Authored-By: Claude Opus 4.7 --- packages/mcp-workforce/src/server.ts | 4 ++-- packages/mcp-workforce/src/tools/memory.ts | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/mcp-workforce/src/server.ts b/packages/mcp-workforce/src/server.ts index e4f36d5a..c9d0f808 100644 --- a/packages/mcp-workforce/src/server.ts +++ b/packages/mcp-workforce/src/server.ts @@ -10,7 +10,7 @@ import { type IntegrationToolName } from './tools/integrations.js'; -const MEMORY_SCOPE_ENUM = z.enum(['session', 'user', 'workspace', 'org', 'object']); +const MEMORY_SCOPE_ENUM = z.enum(['workspace', 'user', 'global']); /** * Build an `McpServer` with workforce-flavored tools registered. Exposed @@ -62,7 +62,7 @@ export function createWorkforceMcpServer(config: WorkforceMcpConfig): McpServer { title: 'Save a memory entry', description: - 'Persist a memory entry for the active workspace. Scopes follow @agent-assistant/memory semantics: session, user, workspace, org, object. Tags are deduped; workspace/scope tags are added automatically.', + 'Persist a memory entry for the active workspace. Scope is one of workspace (default) / user / global, matching @agentworkforce/persona-kit\'s PersonaMemoryScope. Tags are deduped; workspace/scope tags are added automatically.', inputSchema: { content: z.string().min(1), tags: z.array(z.string()).optional(), diff --git a/packages/mcp-workforce/src/tools/memory.ts b/packages/mcp-workforce/src/tools/memory.ts index 54a4ddb3..0400f637 100644 --- a/packages/mcp-workforce/src/tools/memory.ts +++ b/packages/mcp-workforce/src/tools/memory.ts @@ -36,11 +36,9 @@ export interface MemoryToolDeps { } const VALID_SCOPES: ReadonlySet = new Set([ - 'session', - 'user', 'workspace', - 'org', - 'object' + 'user', + 'global' ]); /** From c3e478ff6fc9d2f95bb19b02fa9c84e6e6fda932 Mon Sep 17 00:00:00 2001 From: Ricky Schema Cascade Date: Wed, 13 May 2026 10:45:51 +0200 Subject: [PATCH 3/5] fix(publish): sync release-notes packageOrder with expanded allow-list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit + Devin both flagged that the `packageOrder` array used to sort release-note entries was not updated alongside the publish allow-list, so `runtime` / `deploy` / `mcp-workforce` would have `indexOf === -1` and sort first (or in an arbitrary order depending on the sort impl). Mirror the topological order from "Resolve target packages": persona-kit → runtime → workload-router → deploy → mcp-workforce → daytona-runner → cli → agentworkforce Co-Authored-By: Claude Opus 4.7 --- .github/workflows/publish.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d238e4dc..c7d3521e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -695,7 +695,19 @@ jobs: // didn't publish an umbrella stamp (e.g. version: none re-runs). const releaseVersion = process.env.RELEASE_VERSION || canonicalVersion; - const packageOrder = ['persona-kit', 'workload-router', 'cli', 'daytona-runner', 'agentworkforce']; + // Mirrors the topological order used in the "Resolve target + // packages" step. Sorting release-notes entries by this order + // ensures missing packages don't all collapse to indexOf=-1. + const packageOrder = [ + 'persona-kit', + 'runtime', + 'workload-router', + 'deploy', + 'mcp-workforce', + 'daytona-runner', + 'cli', + 'agentworkforce', + ]; const entries = versionsRaw.trim().split(/\s+/).filter(Boolean).map((entry) => { const idx = entry.indexOf(':'); return { pkg: entry.slice(0, idx), ver: entry.slice(idx + 1) }; From 458194679cfb6242a0bc0179fe63d9be9707d51f Mon Sep 17 00:00:00 2001 From: Ricky Schema Cascade Date: Wed, 13 May 2026 10:51:02 +0200 Subject: [PATCH 4/5] fix(examples): linear-shipper read spec metadata from inputSpecs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ctx.persona.inputs` is `Record` (resolved values) on WorkforcePersonaContext; the raw `PersonaInputSpec` with `.env` and `.default` lives at `ctx.persona.inputSpecs`. The earlier env-var- precedence patch on PR #93 read .env / .default off `.inputs`, which only worked while the type was loose. The post-cascade readonly tightening exposed the bug at typecheck time and broke the examples typecheck job. Also fold the runtime-resolved value into the fallback chain so we prefer env > resolved > spec.default — matching `resolvePersonaInputs`. Verified: `pnpm run typecheck` + `pnpm run typecheck:examples` both clean after rebuilding @agentworkforce/deploy dist. Co-Authored-By: Claude Opus 4.7 --- examples/linear-shipper/agent.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/linear-shipper/agent.ts b/examples/linear-shipper/agent.ts index a4659065..ab61d8d9 100644 --- a/examples/linear-shipper/agent.ts +++ b/examples/linear-shipper/agent.ts @@ -6,11 +6,20 @@ type LinearIssueEvent = { function inputDefault(ctx: Parameters[0]>[0], name: string): string { // Mirror `resolvePersonaInputs` precedence (packages/persona-kit/src/inputs.ts): - // explicit env var (spec.env ?? input name) wins over the static JSON default. - const spec = ctx.persona.inputs?.[name]; + // explicit env var (spec.env ?? input name) wins over the runtime-resolved + // value, which in turn wins over the static spec default. + // + // NOTE: the raw spec lives at `ctx.persona.inputSpecs` (Record); + // `ctx.persona.inputs` is the already-resolved Record. The earlier + // version of this helper read .env / .default off `inputs` directly, which only + // worked because the type was looser before the WorkforceCtx readonly tightening. + const spec = ctx.persona.inputSpecs?.[name]; const envName = spec?.env ?? name; const fromEnv = process.env[envName]; - const value = (fromEnv !== undefined && fromEnv !== '' ? fromEnv : undefined) ?? spec?.default; + const value = + (fromEnv !== undefined && fromEnv !== '' ? fromEnv : undefined) ?? + ctx.persona.inputs?.[name] ?? + spec?.default; if (!value) throw new Error(`${name} input is required`); return value; } From f68e999849ad83f1dbc5dd107e0581a613db15e0 Mon Sep 17 00:00:00 2001 From: Ricky Schema Cascade Date: Wed, 13 May 2026 10:57:35 +0200 Subject: [PATCH 5/5] fix(persona-kit): make integration-source fixtures pass the schema test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `emit-schema.test` failed on main because PR #97 (IntegrationConfig.source discriminator) added three new fixtures but they were missing two schema-required fields (`onEvent` for cloud personas, `skills`) and the test's hardcoded expected-filename list wasn't updated. Three small fixes: 1. `emit-schema.test.ts`: add the three new fixture names to the expected-filenames deepEqual. 2. `integration-source-{deployer,workspace,service-account}.json`: add `"onEvent": "./agent.ts"` and `"skills": []` to each, matching the pattern used in `full.json` / `cron-only.json`. The fixtures still exercise their intended IntegrationSource shapes (no-source default-inject, explicit `workspace`, explicit `workspace_service_account`) — only the cross-cutting required-for-cloud fields were added. Verified: `pnpm -F @agentworkforce/persona-kit test` → 162/162 pass. Co-Authored-By: Claude Opus 4.7 --- .../src/__fixtures__/personas/integration-source-deployer.json | 2 ++ .../personas/integration-source-service-account.json | 2 ++ .../__fixtures__/personas/integration-source-workspace.json | 2 ++ packages/persona-kit/src/emit-schema.test.ts | 3 +++ 4 files changed, 9 insertions(+) diff --git a/packages/persona-kit/src/__fixtures__/personas/integration-source-deployer.json b/packages/persona-kit/src/__fixtures__/personas/integration-source-deployer.json index 7e515a7a..92f7f3f6 100644 --- a/packages/persona-kit/src/__fixtures__/personas/integration-source-deployer.json +++ b/packages/persona-kit/src/__fixtures__/personas/integration-source-deployer.json @@ -3,11 +3,13 @@ "intent": "documentation", "tags": ["documentation"], "description": "Fixture: persona declaring a GitHub integration with no explicit source. Exercises the default-injection path that fills in { kind: 'deployer_user' } during parse.", + "skills": [], "harness": "claude", "model": "anthropic/claude-3-5-sonnet", "systemPrompt": "Fixture persona for IntegrationSource default-injection. Not used at runtime.", "harnessSettings": { "reasoning": "medium", "timeoutSeconds": 300 }, "cloud": true, + "onEvent": "./agent.ts", "integrations": { "github": { "scope": { "repo": "AgentWorkforce/workforce" }, diff --git a/packages/persona-kit/src/__fixtures__/personas/integration-source-service-account.json b/packages/persona-kit/src/__fixtures__/personas/integration-source-service-account.json index 2bb07df0..fe18dfde 100644 --- a/packages/persona-kit/src/__fixtures__/personas/integration-source-service-account.json +++ b/packages/persona-kit/src/__fixtures__/personas/integration-source-service-account.json @@ -3,11 +3,13 @@ "intent": "documentation", "tags": ["documentation"], "description": "Fixture: persona declaring a GitHub integration resolved via a named workspace service account ('release-bot').", + "skills": [], "harness": "claude", "model": "anthropic/claude-3-5-sonnet", "systemPrompt": "Fixture persona for IntegrationSource={ kind: 'workspace_service_account', name: 'release-bot' }. Not used at runtime.", "harnessSettings": { "reasoning": "medium", "timeoutSeconds": 300 }, "cloud": true, + "onEvent": "./agent.ts", "integrations": { "github": { "source": { "kind": "workspace_service_account", "name": "release-bot" }, diff --git a/packages/persona-kit/src/__fixtures__/personas/integration-source-workspace.json b/packages/persona-kit/src/__fixtures__/personas/integration-source-workspace.json index 11b7839b..9bfe19b2 100644 --- a/packages/persona-kit/src/__fixtures__/personas/integration-source-workspace.json +++ b/packages/persona-kit/src/__fixtures__/personas/integration-source-workspace.json @@ -3,11 +3,13 @@ "intent": "documentation", "tags": ["documentation"], "description": "Fixture: persona declaring a Slack integration resolved from the workspace's default workspace_integrations row.", + "skills": [], "harness": "claude", "model": "anthropic/claude-3-5-sonnet", "systemPrompt": "Fixture persona for IntegrationSource={ kind: 'workspace' }. Not used at runtime.", "harnessSettings": { "reasoning": "medium", "timeoutSeconds": 300 }, "cloud": true, + "onEvent": "./agent.ts", "integrations": { "slack": { "source": { "kind": "workspace" }, diff --git a/packages/persona-kit/src/emit-schema.test.ts b/packages/persona-kit/src/emit-schema.test.ts index 35b2b414..64f89192 100644 --- a/packages/persona-kit/src/emit-schema.test.ts +++ b/packages/persona-kit/src/emit-schema.test.ts @@ -19,6 +19,9 @@ test('persona fixtures validate against generated schema and parse', async () => assert.deepEqual(fixtureNames, [ 'cron-only.json', 'full.json', + 'integration-source-deployer.json', + 'integration-source-service-account.json', + 'integration-source-workspace.json', 'invalid-unknown-trigger.json', 'minimal.json' ]);