Skip to content

Preserve trigger maxConcurrency in persona-kit - #230

Merged
khaliqgant merged 3 commits into
mainfrom
fix/trigger-max-concurrency
Jun 12, 2026
Merged

khaliqgant merged 3 commits into
mainfrom
fix/trigger-max-concurrency

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Jun 12, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes #229.

Persona-kit now preserves trigger-level maxConcurrency from defineAgent specs instead of stripping it during parseAgentSpec().

Changes:

  • Add maxConcurrency?: number to PersonaIntegrationTrigger.
  • Add maxConcurrency?: number to the typed authoring TypedTrigger<P> surface used by runtime defineAgent trigger maps.
  • Preserve only positive integer values in parseIntegrationTrigger(); invalid values are treated as unset to match Cloud #2092 semantics.
  • Document the intentional parser asymmetry: match/where remain strict and throw when present-but-invalid, while maxConcurrency is lenient because it is an optional backpressure hint and Cloud treats invalid values as unset.
  • Regenerate packages/persona-kit/schemas/agent.schema.json so maxConcurrency is schema-visible.
  • Cover valid preservation, absent value, invalid omission cases, unchanged match/where strictness, and typed authoring in tests.

Out of scope: Cloud still keeps its #2092 raw-read stopgap until the later Cloud follow-up consumes parsed trigger fields.

Worktree provenance: implemented in /tmp/wt-workforce-bp-pr1, branched from workforce origin/main at 96273fd, not from fix/normalize-trigger-aliases-rebased.

Validation

Passed:

  • pnpm install --frozen-lockfile
  • pnpm --filter @agentworkforce/persona-kit test (277 tests)
  • pnpm --filter @agentworkforce/persona-kit build
  • pnpm run build
  • git diff --check

CI/bot status at the first PR head:

  • GitHub CI check: SUCCESS
  • CodeRabbit: SUCCESS, no actionable comments
  • Gemini Code Assist: no feedback
  • Cubic: neutral/skipped
  • agent-relay-code pr-reviewer failed to run with harness exit code 1 and posted no review; no code finding was produced to address. Bot audit comment: Preserve trigger maxConcurrency in persona-kit #230 (comment)

Caveat:

  • pnpm run check passed lint and typecheck after pnpm run build, then failed in packages/cli/dist/local-personas.test.js with 34 local persona cascade assertions about missing lower-layer personas/sidecars. Those failures are outside the touched package and unrelated to maxConcurrency; details are recorded in /tmp/subs-fix/REPORT-followup-bp.md.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an optional integer maxConcurrency (minimum 1) to persona integration triggers: new type fields and examples, parsing that preserves only positive integer values, schema emission tightening to integer+minimum, and tests covering valid/invalid cases.

Changes

Trigger maxConcurrency Support

Layer / File(s) Summary
Type contracts and JSON schema
packages/persona-kit/src/types.ts, packages/persona-kit/src/define.ts, packages/persona-kit/schemas/agent.schema.json, packages/persona-kit/scripts/emit-schema.mjs
Adds optional maxConcurrency?: number to PersonaIntegrationTrigger and TypedTrigger, updates examples, and post-processes generated AgentSpec schema so PersonaIntegrationTrigger.maxConcurrency is an integer with minimum: 1.
Parsing and validation logic
packages/persona-kit/src/parse.ts
parseIntegrationTrigger now reads maxConcurrency and preserves it only when it's an integer ≥ 1; otherwise the field is omitted (lenient behavior).
Test coverage and assertions
packages/persona-kit/src/parse.test.ts, packages/persona-kit/src/define.test.ts, packages/persona-kit/src/emit-schema.test.ts
Typed-trigger test updated to include maxConcurrency; parseAgentSpec tests assert preservation and add cases ensuring invalid values (0, negative, fractional, NaN, Infinity, non-numeric) are omitted; schema tests assert minimum: 1 and integer enforcement.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 I hopped through types and tests today,
A tiny integer found its way,
From define to parse, the hint stays true,
Schema guards integers, one not two,
Valid stays, the bad ones stray.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically identifies the main change: adding and preserving maxConcurrency support to persona-kit triggers.
Description check ✅ Passed The description provides detailed context linking to issue #229, explains the changes made, lists validation steps, and acknowledges related caveats.
Linked Issues check ✅ Passed All acceptance criteria from issue #229 are addressed: maxConcurrency field added to TypedTrigger and PersonaIntegrationTrigger, parseIntegrationTrigger preserves positive integers and treats invalid values as unset, schema regenerated, and tests cover valid/invalid cases.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing maxConcurrency support across types, parsing, schema, and tests for persona-kit; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/trigger-max-concurrency

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #230 in AgentWorkforce/workforce.
The review harness exited with code 1.
No review was posted; this needs operator attention.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an optional maxConcurrency property to the agent trigger specification, which serves as a delivery backpressure hint. The parser has been updated to validate and preserve only positive integers, treating invalid values as unset. The changes include updates to TypeScript interfaces, JSON schemas, and unit tests to support and verify this new field. There are no review comments, so I have no feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@agent-relay-code

Copy link
Copy Markdown
Contributor

pr-reviewer could not complete review for #230 in AgentWorkforce/workforce.
The review harness exited with code 1.
No review was posted; this needs operator attention.

@khaliqgant

Copy link
Copy Markdown
Member Author

Bot/CI audit at HEAD a7d3e6d:\n\n- GitHub CI check: SUCCESS.\n- CodeRabbit: SUCCESS, no actionable comments. It reports one docstring-coverage warning as a generic pre-merge check, but this PR adds documented interface fields and no new public functions requiring docstrings. No code change needed.\n- Gemini Code Assist: COMMENTED with no feedback.\n- Cubic: NEUTRAL/skipped.\n- agent-relay-code pr-reviewer: failed to run with harness exit code 1 and posted no review. No code finding was produced to address; leaving this for operator/reviewer visibility.\n\nLocal validation is in the PR body and /tmp/subs-fix/REPORT-followup-bp.md.

@khaliqgant

Copy link
Copy Markdown
Member Author

Current-head audit after reviewer-requested follow-up at HEAD 866e65f:\n\n- Added the intentional-leniency parser comment for .\n- Added absent-value coverage and explicit assertions that / remain strict and throw when present-but-invalid.\n- Local focused gates rerun:

@agentworkforce/persona-kit@4.0.3 test /private/tmp/wt-workforce-bp-pr1/packages/persona-kit
tsc -p tsconfig.json && node --test dist/*.test.js

✔ definePersona returns authored specs that parse successfully (60.201459ms)
✔ TypedTriggerMap gives per-provider event autocomplete; arbitrary providers fall back to string (0.077625ms)
✔ TypedScopeMap gives per-provider scope key autocomplete while allowing future keys (0.068167ms)
✔ definePersona types tags against the closed PersonaTag vocabulary (0.058125ms)
✔ definePersona type allows interactive personas without onEvent (0.049583ms)
✔ persona fixtures validate against generated schema and parse (connection-only) (64.683167ms)
✔ agent fixtures validate against agent schema, parse, and lint triggers (16.790291ms)
✔ emit-schema script is idempotent (persona + agent schemas) (1027.045208ms)
✔ generated schema requires onEvent for cloud personas (0.845375ms)
✔ generated schema reflects locked v1 persona fields (2.051875ms)
✔ persona schema keeps mount.enabled but drops the moved listener fields (1.074125ms)
✔ agent schema exposes launchedBy/triggers/schedules/watch (0.423625ms)
✔ resolves $VAR references against the provided env (0.961916ms)
✔ passes literal strings through untouched (0.10275ms)
✔ refuses un-braced partial interpolation — prefix-$VAR stays literal (0.048209ms)
✔ resolves braced ${VAR} interpolation anywhere in a string (0.813833ms)
✔ interpolates multiple ${VAR} occurrences in the same string (2.330875ms)
✔ missing ${VAR} inside a longer string errors with the field and var (0.278041ms)
✔ throws MissingEnvRefError with the referenced name and field (0.072041ms)
✔ treats empty-string env vars as missing (explicit unset) (0.067875ms)
✔ resolveStringMap walks every value and reports the originating field (0.81075ms)
✔ resolveStringMap returns undefined for undefined input (0.09475ms)
✔ lenient resolver reports missing refs instead of throwing (0.105125ms)
✔ resolveStringMapLenient drops missing entries and reports them (0.126792ms)
✔ resolveStringMapLenient returns value=undefined when all entries dropped (0.050042ms)
✔ writePersonaSidecars overwrite + dispose restores empty target (66.911791ms)
✔ writePersonaSidecars resolves sourcePath at write time (6.324459ms)
✔ writePersonaSidecars rejects unsafe filenames (5.595084ms)
✔ writePersonaSidecars extend joins existing content with delimiter (24.38325ms)
✔ materializePersonaConfigFiles writes nested paths and restores them (12.898916ms)
✔ materializePersonaConfigFiles rejects unsafe paths before writing (5.021042ms)
✔ runSkillInstalls rejects cleanup paths that escape cwd (86.5635ms)
✔ runSkillInstalls scaffolds the session install root and disposes it (16.359792ms)
✔ runSkillInstalls spawns the chained install command for a non-session plan (93.935542ms)
✔ runSkillInstalls surfaces a non-zero install with SkillInstallError (66.069958ms)
✔ executePersonaSpawnPlan happy path orders side effects and disposes them in LIFO (3.079375ms)
✔ executePersonaSpawnPlan lets grok AGENTS.md sidecar override generated systemPrompt file (3.2785ms)
✔ executePersonaSpawnPlan empty-skills path is a no-op for skills (0.56925ms)
✔ executePersonaSpawnPlan disposes prior handles when a later step fails (2.7075ms)
✔ PERSONA_INTENTS includes the unrouted "review" intent for pack consumers (0.776583ms)
✔ claude is a recognized harness value (0.053625ms)
✔ grok is a recognized harness value (0.041334ms)
✔ HARNESS_SKILL_TARGETS covers every harness value (12.872083ms)
✔ materializeSkills emits a codex-scoped prpm install for a prpm.dev URL (1.128417ms)
✔ materializeSkills routes claude skills to .claude/skills via --as claude (0.168125ms)
✔ materializeSkills routes grok skills to .grok/skills via --as grok (0.096708ms)
✔ materializeSkills emits a skill.sh install for a github#skill source (0.173917ms)
✔ materializeSkills accepts GitHub tree URLs for skill.sh skill directories (0.256583ms)
✔ materializeSkills rejects unsafe skill.sh skill names (0.252791ms)
✔ prpm installs carry a harness-scoped cleanup path, not the lockfile (0.065167ms)
✔ materializeSkills with installRoot stages claude skills under the stage dir (0.155875ms)
✔ materializeSkills rejects installRoot for non-claude harnesses (0.049083ms)
✔ materializeSkills with installRoot and no skills still reports the sessionInstallRoot (0.03525ms)
✔ materializeSkills rejects unknown skill sources (0.043125ms)
✔ materializeSkills handles personas with no skills (0.029333ms)
✔ materializeSkills emits a mkdir+cp install for a local .md source (0.10725ms)
✔ local sources accept ./-prefixed and absolute paths and strip the .md extension for the installed name (0.063458ms)
✔ local sources using SKILL.md adopt the parent dir name as the installed name (0.044875ms)
✔ local source with repoRoot absoluteifies the cp source path (0.05225ms)
✔ local source absolute path is left alone even with repoRoot (0.042084ms)
✔ local source survives installRoot session mode by embedding the absolute repo path (0.083459ms)
✔ local source does NOT shadow prpm bare references like coreyhaines31/marketingskills (0.032042ms)
✔ local source rejects paths without .md suffix (0.037667ms)
✔ resolveSidecar: path + mode pass through directly from the spec (0.087417ms)
✔ resolveSidecar: defaults claudeMdMode to overwrite and surfaces inlined content (0.038417ms)
✔ resolvePersonaInputs prefers explicit values over env and defaults (1.317167ms)
✔ resolvePersonaInputs falls back to configured env var then default (0.071375ms)
✔ resolvePersonaInputs fails hard when a declared input is unset (0.192333ms)
✔ resolvePersonaInputs substitutes optional inputs with empty when unset (6.944125ms)
✔ resolvePersonaInputs uses provided value over optional empty fallback (0.439792ms)
✔ renderPersonaInputs substitutes $NAME and ${NAME} without touching longer names (0.305917ms)
✔ renderPersonaInputs treats replacement values literally (0.063375ms)
✔ claude branch always emits --mcp-config + --strict-mcp-config (10.262584ms)
✔ claude branch serializes resolved mcpServers into the --mcp-config payload (0.199167ms)
✔ claude branch translates permissions to flags (0.067ms)
✔ claude branch omits permission flags when unset or empty (1.99825ms)
✔ codex carries system prompt as initial positional; strips provider prefix from model (2.5775ms)
✔ codex translates sandbox harness settings to launch flags (0.100083ms)
✔ codex emits the single bypass flag when dangerouslyBypassApprovalsAndSandbox is set (0.057ms)
✔ codex warns for approvalPolicy even when dangerouslyBypassApprovalsAndSandbox is also set (0.06875ms)
✔ codex translates http mcpServers into --config mcp_servers.* args (8.75025ms)
✔ codex translates stdio mcpServers into command/args/env config args (0.645667ms)
✔ codex quotes mcp server names in TOML keys when bare-key rules do not allow them (0.158834ms)
✔ codex warns for unsupported permission wiring and sse transport hints (0.129625ms)
✔ opencode defines a per-persona agent in opencode.json and selects it with --agent (0.069334ms)
✔ opencode configFiles carries a well-formed opencode.json with the agent definition (0.142208ms)
✔ grok launches the Grok Build CLI and writes systemPrompt to AGENTS.md (0.067875ms)
✔ grok maps bypassPermissions to always-approve and wires plugin dirs (0.047833ms)
✔ grok warns for unsupported permission fields (0.043875ms)
✔ grok non-interactive spec uses single-shot mode with cwd and always-approve (0.105417ms)
✔ grok non-interactive spec still adds always-approve for unsupported permission modes (0.037583ms)
✔ claude and codex emit an empty configFiles array; grok does so only with an empty systemPrompt (0.049709ms)
✔ claude branch omits --append-system-prompt when systemPrompt is empty (0.033958ms)
✔ claude non-interactive spec omits unsupported --name while preserving run flags (0.049292ms)
✔ opencode omits agent.prompt when systemPrompt is empty (0.047792ms)
✔ codex passes empty systemPrompt through as a falsy initialPrompt (0.026166ms)
✔ claude branch appends --plugin-dir per entry in pluginDirs (0.047458ms)
✔ claude branch omits --plugin-dir when pluginDirs is empty or absent (0.038708ms)
✔ codex and opencode warn and ignore pluginDirs (0.135917ms)
✔ warnings are returned, not printed — library consumers route I/O themselves (0.029583ms)
✔ relayMcp injects a relaycast server into the claude --mcp-config payload (0.088584ms)
✔ relayMcp omits RELAY_BASE_URL / RELAY_DEFAULT_WORKSPACE when not provided (0.038458ms)
✔ relayMcp merges alongside persona-declared servers; a persona relaycast wins (0.045791ms)
✔ aiHist injects an ai-hist server into the claude --mcp-config payload (0.064458ms)
✔ aiHist omits TRAJECTORY_ROOT / AI_HIST_DB env when not provided (0.048041ms)
✔ aiHist merges alongside relaycast + persona servers; a persona ai-hist wins (0.065083ms)
✔ without aiHist the claude payload carries no ai-hist server (0.02675ms)
✔ without relayMcp the claude payload carries no relaycast server (0.041958ms)
✔ relayMcp wires relaycast into codex --config args (0.140417ms)
✔ relayMcp under opencode warns that MCP injection is unsupported (0.053791ms)
✔ relayMcp under grok warns that MCP injection is unsupported (0.031208ms)
✔ opencode warning names both persona and broker MCP sources when both are present (0.034875ms)
✔ grok warning names both persona and broker MCP sources when both are present (0.03475ms)
✔ applyPersonaMount: undefined policy returns a no-op handle whose cwd matches options.cwd (0.694416ms)
✔ applyPersonaMount: undefined policy ignores missing mountDir + personaId (0.060375ms)
✔ applyPersonaMount: declared policy without mountDir throws a clear error (0.248042ms)
✔ applyPersonaMount: declared policy without personaId throws a clear error (0.108166ms)
✔ parsePersonaSpec accepts a minimal valid flat spec (4.805833ms)
✔ parsePersonaSpec strips unknown top-level fields silently (0.282709ms)
✔ parsePersonaSpec accepts deploy-v1 optional fields (connection-only integrations) (0.854ms)
✔ parsePersonaSpec hard-rejects triggers/schedules/watch (moved to the agent) (0.327875ms)
✔ parsePersonaSpec rejects removed deploy-v1 traits but accepts sandbox (0.154ms)
✔ parsePersonaSpec accepts the Relayfile-VFS example personas (1.012417ms)
✔ parsePersonaSpec throws when intent does not match the expected intent (0.076709ms)
✔ parsePersonaSpec throws with a precise field path on a malformed harnessSettings (0.072125ms)
✔ parsePersonaSpec throws when required runtime fields are missing (0.290166ms)
✔ parsePersonaSpec requires harness/model/systemPrompt for interactive personas (no onEvent) (0.325042ms)
✔ parsePersonaSpec allows handler personas (onEvent) to omit harness/model/systemPrompt (0.258084ms)
✔ parsePersonaSpec still validates harness enum for handler personas when provided (0.172084ms)
✔ parsePersonaSpec defers malformed skills[i].source to plan time (does not throw at parse) (0.185083ms)
✔ parsePermissions throws on an invalid permission mode (0.106791ms)
✔ parseMount accepts ignoredPatterns + readonlyPatterns; drops empties to undefined (0.162083ms)
✔ parseMount accepts enabled without pattern lists (0.109417ms)
✔ parseMount throws when patterns are not non-empty strings (0.1525ms)
✔ INPUT_NAME_RE matches env-var convention (0.253333ms)
✔ assertInputName throws on names that violate the env-var convention (0.15075ms)
✔ parseInputs accepts a string default and an object with description+env+default (0.127833ms)
✔ parseInputs forbids combining optional:true with a default (0.067125ms)
✔ parseInputs rejects names that violate the env-var convention (0.047958ms)
✔ parseInputs keeps a picker alongside env/optional (0.050375ms)
✔ parseInputs rejects a picker missing provider or resource (0.070125ms)
✔ parseHarnessSettings accepts optional codex fields and rejects bad ones (0.230833ms)
✔ parseHarnessSettings accepts dangerouslyBypassApprovalsAndSandbox alone (0.053417ms)
✔ parseHarnessSettings rejects dangerouslyBypassApprovalsAndSandbox with conflicting fields (0.149ms)
✔ parseHarnessSettings rejects dangerouslyBypassApprovalsAndSandbox:false with conflicting fields (1.090875ms)
✔ parseHarnessSettings rejects non-boolean dangerouslyBypassApprovalsAndSandbox (0.042208ms)
✔ parseTags accepts an array of arbitrary string tags (0.043625ms)
✔ parseTags returns undefined when tags is missing (0.021791ms)
✔ parseTags returns undefined when tags is null (0.021ms)
✔ parseTags returns undefined when tags is an empty array (0.027041ms)
✔ parseTags rejects non-string entries (0.0495ms)
✔ parseTags rejects empty / whitespace-only strings (0.057291ms)
✔ parseTags rejects entries over 64 characters (0.051416ms)
✔ parseTags rejects non-array input (0.03675ms)
✔ parsePersonaSpec omits tags from the spec when the field is missing (0.055541ms)
✔ parseSkills returns [] for undefined, validates shape per entry (0.044292ms)
✔ parseStringList drops undefined and rejects empty strings (0.039209ms)
✔ parseStringMap rejects non-string values (0.044375ms)
✔ parseMcpServers validates the http/sse/stdio union (0.098666ms)
✔ assertSidecarPath rejects absolute paths and ".." traversal (0.126917ms)
✔ parsePersonaSpec rejects a non-object spec (0.047417ms)
✔ parseMemory accepts boolean + object forms and validates scopes (0.047958ms)
✔ parseMemory rejects unknown scopes and non-positive ttl (0.098ms)
✔ parseSchedules validates cron, requires unique names, preserves tz when set (0.250458ms)
✔ parseIntegrations preserves scope (connection-only); rejects persona-level triggers (0.076875ms)
✔ parseAgentSpec validates launchedBy plus provider-keyed triggers, schedules, and watch (0.22475ms)
✔ parseAgentSpec omits invalid trigger maxConcurrency values (0.05825ms)
✔ parseAgentSpec rejects malformed triggers maps with precise field paths (0.115834ms)
✔ parseIntegrations default-injects source=deployer_user when the persona omits it (0.035916ms)
✔ parseIntegrations round-trips all three valid IntegrationSource kinds (0.079208ms)
✔ parseIntegrations rejects an unknown source.kind with a precise field path (0.03775ms)
✔ parseIntegrations rejects workspace_service_account missing name (0.035042ms)
✔ parseIntegrations rejects workspace_service_account with non-kebab-case name (0.050833ms)
✔ IntegrationSource fixtures round-trip through parsePersonaSpec (0.248917ms)
✔ parseIntegrations rejects extra name on deployer_user / workspace kinds (0.061334ms)
✔ parseOnEvent enforces relative path with a supported extension (0.094208ms)
✔ parseOnEvent rejects Windows-absolute path shapes too (0.06025ms)
✔ parseSchedules trims name/cron/tz before validation and dedupe (0.055292ms)
✔ parseWatch accepts relayfile watch rules and dedupes events (0.04275ms)
✔ parseWatch rejects malformed relayfile watch rules with precise field paths (0.165458ms)
✔ parsePersonaSpec round-trips mount.enabled=false (watch now lives on the agent) (0.064791ms)
✔ parsePersonaSpec rejects non-boolean cloud / useSubscription (0.079208ms)
✔ parsePersonaSpec keeps boolean shorthand memory through round-trip (0.033625ms)
✔ parseCapabilities preserves unknown consumer-defined capabilities (teamSolve) (0.057375ms)
✔ parseCapabilities rejects arrays for the capabilities map and values (0.052375ms)
✔ parsePersonaSpec round-trip preserves a declared teamSolve capability (0.043208ms)
✔ buildPersonaSpawnPlan returns the persona, cli, and args for claude (3.01625ms)
✔ buildPersonaSpawnPlan injects ai-hist when memory.aiMemory is opted in (0.387458ms)
✔ buildPersonaSpawnPlan threads ai-hist env overrides when aiMemory is on (0.099417ms)
✔ buildPersonaSpawnPlan: memory.aiMemory.dbPath overrides the history DB (0.084292ms)
✔ buildPersonaSpawnPlan omits ai-hist when memory.aiMemory is not opted in (0.097916ms)
✔ buildPersonaSpawnPlan emits initialPrompt for codex (0.1005ms)
✔ buildPersonaSpawnPlan emits configFiles for opencode (0.4065ms)
✔ buildPersonaSpawnPlan emits AGENTS.md configFile for grok systemPrompt (0.154292ms)
✔ buildPersonaSpawnPlan resolves sidecars from claudeMdContent / agentsMdContent (0.12725ms)
✔ buildPersonaSpawnPlan threads mount policy through when patterns present (0.599625ms)
✔ buildPersonaSpawnPlan suppresses mount policy when explicitly disabled (0.275042ms)
✔ buildPersonaSpawnPlan drops empty mount policy (0.458167ms)
✔ buildPersonaSpawnPlan resolves inputs into env bindings (0.422541ms)
✔ buildPersonaSpawnPlan persona env wins over inputs and overrides (0.125875ms)
✔ buildPersonaSpawnPlan is JSON-serializable (0.109167ms)
✔ buildPersonaSpawnPlan threads installRoot into the skill plan (0.425167ms)
✔ buildPersonaSpawnPlan emits sourcePath when only claudeMd path is set (0.050208ms)
✔ buildPersonaSpawnPlan emits sourcePath for AGENTS.md harness agentsMd path (0.064959ms)
✔ buildPersonaSpawnPlan does not capture ambient env by default (0.04075ms)
✔ buildPersonaSpawnPlan opt-in includeProcessEnv captures process.env (0.215292ms)
✔ buildPersonaSpawnPlan empty-skills case keeps installs empty (0.05875ms)
✔ parseRelay accepts the boolean shorthand (1.453541ms)
✔ parseRelay parses and normalizes the object form (2.136209ms)
✔ parseRelay rejects malformed shapes (0.258834ms)
✔ parsePersonaSpec threads the relay field through (1.978458ms)
✔ resolvePersonaRelayMcp returns disabled when off (0.214834ms)
✔ resolvePersonaRelayMcp flags a missing secret rather than dropping silently (0.087375ms)
✔ resolvePersonaRelayMcp merges declared intent with env secrets (0.06675ms)
✔ resolvePersonaRelayMcp: explicit agentName and env workspace (1.503875ms)
✔ consumed scope-key catalog exposes github owner/repo (1.288708ms)
✔ ScopeKeysFor narrows to the provider scope keys; typed authoring accepts them (0.524459ms)
✔ writePersonaSidecars: extend mode preserves the original on dispose (25.948291ms)
✔ writePersonaSidecars: overwrite of an existing file restores prior contents on dispose (4.172625ms)
✔ writePersonaSidecars: extend mode against an empty cwd writes the persona body verbatim (4.360708ms)
✔ writePersonaSidecars: rejects sourcePath that is not absolute (14.746458ms)
✔ writePersonaSidecars: dispose runs in LIFO order (later write restored before earlier) (87.213417ms)
✔ buildPersonaSpawnPlan + writePersonaSidecars round-trip a path-backed sidecar (8.673125ms)
✔ computeSkillCacheFingerprint: deterministic for the same input (27.471334ms)
✔ computeSkillCacheFingerprint: order-independent over skills (4.693167ms)
✔ computeSkillCacheFingerprint: harness change invalidates (42.687833ms)
✔ computeSkillCacheFingerprint: source change invalidates (1.042209ms)
✔ computeSkillCacheFingerprint: description change does NOT invalidate (4.0095ms)
✔ computeSkillCacheFingerprint: local skill content changes invalidate (31.173375ms)
✔ computeSkillCacheFingerprint: missing local file does not throw (0.173541ms)
✔ skillCacheRoot / resolveSkillCacheDir: under ~/.agentworkforce/workforce/cache/plugins (0.115041ms)
✔ writeSkillCacheMarker / readSkillCacheMarker round-trips (1.485583ms)
✔ readSkillCacheMarker: returns null for missing/malformed marker (0.662292ms)
✔ readSkillCacheMarker: returns null for unknown schema version (0.958458ms)
✔ isSkillCacheValid: requires fingerprint match (0.581166ms)
✔ readSkillCacheMarker: upgrades a v1 marker in place (no upstream records) (0.79975ms)
✔ writeSkillCacheMarker / readSkillCacheMarker: prpm upstream round-trip (0.458292ms)
✔ readSkillCacheMarker: drops a malformed upstream block but keeps the skill (0.551459ms)
✔ updateSkillCacheMarkerUpstream: bumps timestamp, overlays records, keeps others (0.668791ms)
✔ updateSkillCacheMarkerUpstream: no-ops when marker missing (0.273333ms)
✔ parseCheckInterval: units (1.330208ms)
✔ parseCheckInterval: sentinels (0.081625ms)
✔ parseCheckInterval: unparseable / empty → undefined (caller default) (1.354792ms)
✔ isUpstreamCheckDue: never (null) is always false (0.08375ms)
✔ isUpstreamCheckDue: always (0) is always true (0.778125ms)
✔ isUpstreamCheckDue: no prior check → due (0.044791ms)
✔ isUpstreamCheckDue: respects the interval window (0.051834ms)
✔ isUpstreamCheckDue: corrupt timestamp → due (0.040709ms)
✔ buildUpstreamRecordsFromCacheDir: prpm version from prpm.lock (6.537167ms)
✔ buildUpstreamRecordsFromCacheDir: github blob sha from skills-lock.json + GitHub GET (1.979334ms)
✔ buildUpstreamRecordsFromCacheDir: local source → undefined record (0.718209ms)
✔ buildUpstreamRecordsFromCacheDir: github GET failure → undefined (fail-open) (1.368166ms)
✔ detectSkillUpstreamDrift: prpm version unchanged → no drift (0.216875ms)
✔ detectSkillUpstreamDrift: prpm version bumped → drift (0.069625ms)
✔ detectSkillUpstreamDrift: prpm registry 500 → fail-open (no drift) (0.055875ms)
✔ detectSkillUpstreamDrift: github 304 (If-None-Match) → no drift (0.055625ms)
✔ detectSkillUpstreamDrift: github new sha → drift (0.077625ms)
✔ detectSkillUpstreamDrift: github 404 → fail-open (no drift) (0.048541ms)
✔ detectSkillUpstreamDrift: remote skill missing upstream record → drift (capture next time) (0.040792ms)
✔ detectSkillUpstreamDrift: local skill missing upstream record → skipped (no drift) (0.032583ms)
✔ detectSkillUpstreamDrift: mixed set — one drift flips the whole result (0.106542ms)
✔ detectSkillUpstreamDrift: probe timeout → fail-open (51.264584ms)
✔ runSkillInstalls: empty plan with no installs and no session root spawns nothing (8.873ms)
✔ runSkillInstalls: cleanupOnDispose=false leaves cleanupPaths intact (57.863375ms)
✔ runSkillInstalls: cleanupOnDispose=true removes per-install cleanupPaths (65.510875ms)
✔ runSkillInstalls: session install root scaffolds plugin.json and dispose removes the root (12.241458ms)
✔ runSkillInstalls: session-root cleanupOnDispose=false leaves the root in place (9.327791ms)
✔ KNOWN_TRIGGERS ships a non-empty list per shipped provider (1.040625ms)
✔ lintTriggers returns no issues for an agent with no triggers (0.902083ms)
✔ lintTriggers returns no issues for known providers and known triggers (0.07ms)
✔ lintTriggers accepts cloud provider aliases backed by adapter trigger catalogs (0.050958ms)
✔ lintTriggers warns per unknown trigger for aliased cloud providers (0.0635ms)
✔ lintTriggers warns once per unknown provider (0.055083ms)
✔ lintTriggers warns per unknown trigger for a known provider (0.7425ms)
✔ lintTriggers returns no issues for valid relayfile watch rules (0.077625ms)
✔ lintTriggers warns for non-absolute relayfile watch paths (0.137125ms)
✔ lintTriggers warns for relayfile watch rules with empty events (0.11875ms)
ℹ tests 277
ℹ suites 0
ℹ pass 277
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1270.434958 (277 tests),

@agentworkforce/persona-kit@4.0.3 build /private/tmp/wt-workforce-bp-pr1/packages/persona-kit
tsc -p tsconfig.json && npm run emit:schema

@agentworkforce/persona-kit@4.0.3 emit:schema
node ./scripts/emit-schema.mjs, all passed.\n- GitHub CI : SUCCESS.\n- CodeRabbit: SUCCESS.\n- Cubic: NEUTRAL/skipped.\n\nReady for clr-bp re-verification at current head.

@khaliqgant

Copy link
Copy Markdown
Member Author

Current-head audit after reviewer-requested follow-up at HEAD 866e65f:

  • Added the intentional-leniency parser comment for maxConcurrency.
  • Added absent-value coverage and explicit assertions that match/where remain strict and throw when present-but-invalid.
  • Local focused gates rerun: pnpm --filter @agentworkforce/persona-kit test (277 tests), pnpm --filter @agentworkforce/persona-kit build, git diff --check all passed.
  • GitHub CI check: SUCCESS.
  • CodeRabbit status context: SUCCESS. Note: CodeRabbit's latest comment says the incremental review hit a rate limit, so there is no fresh CodeRabbit textual review for the 2-file follow-up; previous full review had no actionable comments.
  • Cubic: NEUTRAL/skipped.

Ready for clr-bp re-verification at current head.

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #230 against the current checkout and current GitHub PR state. I found no reproducible breakage and made no code changes.

Validation

  • pnpm install --frozen-lockfile: passed via temporary local Corepack pnpm shim.
  • pnpm -r run build: passed.
  • pnpm run lint: passed.
  • pnpm run typecheck: passed, including examples.
  • pnpm run test: passed.
  • GitHub API currently reports PR head 866e65f910d987bd7359fde550b47b4fabf70eb8, mergeable: true, mergeable_state: clean, Actions check: success, CodeRabbit status success, Cubic neutral.

Addressed comments

  • coderabbitai[bot]: raised a rate-limit notice plus a generic docstring coverage warning. No code change: current PR adds documented trigger fields at packages/persona-kit/src/types.ts:203 and schema docs at packages/persona-kit/schemas/agent.schema.json:52; no new undocumented public function finding was produced.
  • agent-relay-code[bot] comment 4690399242: review harness exited with code 1 and posted no review. No code change: no actionable code finding was produced.
  • agent-relay-code[bot] comment 4690429183: repeated review harness failure with no review. No code change: duplicate non-code operational failure.
  • gemini-code-assist[bot]: commented with a summary and explicitly said there were no review comments. No code change: no actionable finding.
  • khaliqgant: posted prior bot/CI audit noting no actionable CodeRabbit/Gemini/Cubic findings and agent-relay-code harness failure. No code change: confirmed current checkout preserves/omits maxConcurrency as intended in packages/persona-kit/src/parse.ts:546 and tests cover it at packages/persona-kit/src/parse.test.ts:694.

Advisory Notes
None.

@agent-relay-code

Copy link
Copy Markdown
Contributor

Implemented one scoped fix for the PR.

The parser only preserves positive integer maxConcurrency, but the generated agent schema still emitted it as any number. I fixed the schema generator so maxConcurrency is emitted as integer with minimum: 1, regenerated the schema, and added schema tests that accept 1 and reject 0 and 1.5.

Changed:

Addressed comments

  • No bot or reviewer comments were present in .workforce/context.json or the local .workforce metadata, so there were no external comments to validate or address.

Advisory Notes

  • None.

Validation

Passed locally:

  • corepack pnpm install --frozen-lockfile
  • corepack pnpm --filter @agentworkforce/persona-kit run emit:schema
  • corepack pnpm --filter @agentworkforce/persona-kit test
  • PATH="/tmp/corepack-bin:$PATH" pnpm -r run build
  • PATH="/tmp/corepack-bin:$PATH" pnpm run lint
  • PATH="/tmp/corepack-bin:$PATH" pnpm run typecheck
  • PATH="/tmp/corepack-bin:$PATH" pnpm run test

I did not print READY because GitHub-side check completion and mergeability were not available from the provided local metadata.

@khaliqgant

Copy link
Copy Markdown
Member Author

Implementation-complete handoff for clr-bp review at HEAD 866e65f:

  • PR1 implementation is final from my side.
  • Current head is green: GitHub CI check SUCCESS, CodeRabbit status SUCCESS, Cubic NEUTRAL/skipped.
  • Reviewer-requested follow-up is included: fresh-main provenance confirmed, intentional leniency comment added, absent maxConcurrency test added, match/where strict throw behavior asserted.
  • Local focused gates passed: pnpm --filter @agentworkforce/persona-kit test (277), pnpm --filter @agentworkforce/persona-kit build, git diff --check.
  • Report updated: /tmp/subs-fix/REPORT-followup-bp.md.

Relay CLI DM/channel posting is currently blocked for cdx-bp with Invalid agent token, so this PR comment is the durable handoff until relay auth is restored.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/persona-kit/scripts/emit-schema.mjs (1)

137-147: ⚡ Quick win

Add explanatory comment for consistency.

The two preceding post-processing blocks (workspace_service_account.name at lines 50-54, tags at lines 84-89) include comments explaining why the post-processing is necessary. Adding a similar comment here would maintain consistency and clarify for future maintainers why maxConcurrency requires integer+minimum constraints.

📝 Suggested comment structure
+// Post-process: tighten the PersonaIntegrationTrigger.maxConcurrency constraint
+// to match parseIntegrationTrigger (integer >= 1). The generator emits a bare
+// `{ "type": "number" }` because the constraint lives in the parser. Without this,
+// the schema accepts 0 or 1.5 which the parser then omits as invalid.
 const agentTrigger = agentSchema.definitions?.PersonaIntegrationTrigger;
🤖 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-kit/scripts/emit-schema.mjs` around lines 137 - 147, Add a
short explanatory comment above the post-processing block that modifies
agentSchema.definitions?.PersonaIntegrationTrigger.properties.maxConcurrency
explaining why we coerce type to 'integer' and add minimum: 1 (e.g., to enforce
whole-number concurrency and disallow non-positive values for runtime/validation
compatibility), matching the style of the earlier comments for
workspace_service_account.name and tags; place the comment immediately above the
agentTrigger modification so future maintainers see the intent for the
maxConcurrency integer+minimum constraint.
🤖 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.

Nitpick comments:
In `@packages/persona-kit/scripts/emit-schema.mjs`:
- Around line 137-147: Add a short explanatory comment above the post-processing
block that modifies
agentSchema.definitions?.PersonaIntegrationTrigger.properties.maxConcurrency
explaining why we coerce type to 'integer' and add minimum: 1 (e.g., to enforce
whole-number concurrency and disallow non-positive values for runtime/validation
compatibility), matching the style of the earlier comments for
workspace_service_account.name and tags; place the comment immediately above the
agentTrigger modification so future maintainers see the intent for the
maxConcurrency integer+minimum constraint.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f01c0ec9-b1a3-4868-af0d-4c8ad1ebcc99

📥 Commits

Reviewing files that changed from the base of the PR and between a7d3e6d and e2685af.

📒 Files selected for processing (5)
  • packages/persona-kit/schemas/agent.schema.json
  • packages/persona-kit/scripts/emit-schema.mjs
  • packages/persona-kit/src/emit-schema.test.ts
  • packages/persona-kit/src/parse.test.ts
  • packages/persona-kit/src/parse.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/persona-kit/schemas/agent.schema.json
  • packages/persona-kit/src/parse.ts

@khaliqgant

Copy link
Copy Markdown
Member Author

Merge triage: clr-bp impl signoff @ e2685af (independent clean-worktree verify, 277 persona-kit tests pass, RED-without-fix proof — reverting parse.ts maxConcurrency handling fails 2 tests). CI green, no actionable inline bot findings (gemini summary-only; cubic NEUTRAL). This is the durable declaration contract for cloud#2092's stopgap (cloud reads raw input.agent today). Merging.

@khaliqgant
khaliqgant merged commit 969e657 into main Jun 12, 2026
3 checks passed
@khaliqgant
khaliqgant deleted the fix/trigger-max-concurrency branch June 12, 2026 11:12
@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed and fixed the PR-scoped issue that appeared after the branch advanced: the agent schema now emits maxConcurrency as an integer with minimum: 1, matching parser behavior.

Local validation passed:

  • corepack pnpm install --frozen-lockfile
  • pnpm -r run build
  • pnpm run lint
  • pnpm run typecheck
  • pnpm run test

Remote status observed at final check: PR head e2685af4883903a0c1820f8b015b7618cb7373bb, mergeable true, mergeable state clean; Actions check success, CodeRabbit success, Cubic neutral/skipped.

Addressed comments

  • coderabbitai[bot] comment 4690383797: raised a rate-limit notice and generic docstring coverage warning, with no actionable code finding. Current trigger field docs remain at packages/persona-kit/src/types.ts:203, and schema docs at packages/persona-kit/schemas/agent.schema.json:52.
  • agent-relay-code[bot] comment 4690399242: review harness failed and posted no review. No code change: no actionable finding.
  • agent-relay-code[bot] comment 4690429183: duplicate harness failure. No code change: no actionable finding.
  • khaliqgant comment 4690432104: prior bot/CI audit only. No code change needed; later schema mismatch was separately fixed in packages/persona-kit/scripts/emit-schema.mjs:137.
  • khaliqgant comment 4690480451: prior current-head audit. No code change needed beyond preserving the parser/test behavior already present at packages/persona-kit/src/parse.ts:556 and packages/persona-kit/src/parse.test.ts:694.
  • khaliqgant comment 4690482415: same current-head audit, no new code finding. Confirmed existing parser leniency and strict match/where assertions at packages/persona-kit/src/parse.test.ts:733.
  • agent-relay-code[bot] comment 4690511735: stale no-change audit from an older head. Later schema finding is fixed in packages/persona-kit/schemas/agent.schema.json:52.
  • agent-relay-code[bot] comment 4690576686: raised schema allowing any number while parser only preserves positive integers. Fixed in packages/persona-kit/scripts/emit-schema.mjs:137, packages/persona-kit/schemas/agent.schema.json:52, and covered in packages/persona-kit/src/emit-schema.test.ts:141.
  • khaliqgant comment 4690615917: implementation handoff/status note. No additional code finding; final local validation passed after applying the schema constraint fix.
  • gemini-code-assist[bot] review 4484903341: summary review explicitly said there were no review comments. No code change needed.

Advisory Notes

None.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

persona-kit: preserve trigger maxConcurrency in defineAgent specs

1 participant