feat(agents): parameterized agent selection via agentName#349
Conversation
Add full protocol support for entry-point-specific agent selection. **Flow:** 1. Client passes agentName in send message options 2. Server sets MITZO_AGENT_NAME env var 3. Harness hook reads env var and requests agent-specific boot context 4. ContexGin compiles context per agent definition **Changes:** - packages/protocol/src/ws-schemas-v2.ts — add agentName to V2SendMessage - server/ws-handler-v2.ts — pass agentName to startChat() - server/chat.ts — set MITZO_AGENT_NAME env var, use in recipe lookup - packages/harness/src/session-registry.ts — add agentName to ManagedSession - packages/client/src/store.ts — add agentName to SendMessageOptions/PendingSession - frontend/src/pages/ChatView.tsx — forward agentName from pending session Defaults to 'mitzo-conversational' when not specified. Enables future UI entry points (Telos, calendar) to request specialized agents. Companion PR: mgmt#<number> Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Wire TodoView to pass agentName: 'mitzo-telos' when starting a session from a Telos task. This triggers the specialized Telos agent with task-specific context blocks and governance. Calendar integration not yet implemented (CalendarView is read-only). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
dimakis
left a comment
There was a problem hiding this comment.
Centaur Review
Found 5 issue(s) (1 critical) (3 warning).
server/chat.ts
The core plumbing is clean and follows the established telosTaskId pattern, but the user-controlled agentName is used in file path construction (join(cwd, '.agents', agentName + '.yaml')) without any validation — this is a path traversal vulnerability that needs a format constraint at the protocol schema level.
- 🔴 unsafe_assumptions (L781): Path traversal vulnerability:
agentNameoriginates from unauthenticated WebSocket input (z.string().optional()— no format constraint) and is interpolated directly into a file path:join(cwd, '.agents', \${agentName}.yaml`). A malicious client can sendagentName: '../../etc/passwd'to read arbitrary YAML-parseable files. The try-catch silences failures butloadAgentDefinitionmay still parse and return data from out-of-bounds paths. Add a Zod regex constraint (e.g.,z.string().regex(/^[a-zA-Z0-9_-]+$/)) inws-schemas-v2.tsor validate withpath.basename()before constructingrecipePath.[fixable]` - 🟡 unsafe_assumptions (L729):
agentNameis also injected into the process environment asMITZO_AGENT_NAMEwithout sanitization. While less dangerous than the path traversal, an attacker-controlled env var value containing special characters could affect downstream shell commands or child processes that read this variable.[fixable] - 🟡 missing_tests (L781): No test coverage for the
agentNameparameter. The existingws-handler-v2.test.ts(2745 lines) has noagentNametests. At minimum: (1) verifyagentNameis forwarded from WS message tostartChat, (2) verify the default fallback tomitzo-conversational, (3) verify path traversal attempts are rejected.[fixable] - 🔵 style (L728): The default agent name
'mitzo-conversational'is a magic string. Consider extracting it toconstants.ts(where other server-wide defaults live) since it appears in an env var assignment and a file path construction — a single source of truth prevents drift.[fixable]
packages/harness/src/session-registry.ts
The core plumbing is clean and follows the established telosTaskId pattern, but the user-controlled agentName is used in file path construction (join(cwd, '.agents', agentName + '.yaml')) without any validation — this is a path traversal vulnerability that needs a format constraint at the protocol schema level.
- 🟡 regressions (L50):
agentNameis added to theManagedSessioninterface and stored at registration (chat.ts:682), but is never read back anywhere in the codebase (session.agentNamehas zero grep hits). This is dead metadata — either it should be consumed (e.g., for session restore, reattach, or auditing) or removed from the interface to avoid confusion.[fixable]
| try { | ||
| if (compileModule.loadAgentDefinition) { | ||
| const recipePath = join(cwd, '.agents', 'mitzo-conversational.yaml'); | ||
| const recipePath = join(cwd, '.agents', `${agentName}.yaml`); |
There was a problem hiding this comment.
🔴 unsafe_assumptions: Path traversal vulnerability: agentName originates from unauthenticated WebSocket input (z.string().optional() — no format constraint) and is interpolated directly into a file path: join(cwd, '.agents', \${agentName}.yaml`). A malicious client can send agentName: '../../etc/passwd'to read arbitrary YAML-parseable files. The try-catch silences failures butloadAgentDefinitionmay still parse and return data from out-of-bounds paths. Add a Zod regex constraint (e.g.,z.string().regex(/^[a-zA-Z0-9_-]+$/)) in ws-schemas-v2.tsor validate withpath.basename()before constructingrecipePath. [fixable]`
| const sessionEnv = sdkEnv(); | ||
| sessionEnv.MITZO_SESSION_ID = wtId; | ||
| const agentName = options.agentName || 'mitzo-conversational'; | ||
| sessionEnv.MITZO_AGENT_NAME = agentName; |
There was a problem hiding this comment.
🟡 unsafe_assumptions: agentName is also injected into the process environment as MITZO_AGENT_NAME without sanitization. While less dangerous than the path traversal, an attacker-controlled env var value containing special characters could affect downstream shell commands or child processes that read this variable. [fixable]
| try { | ||
| if (compileModule.loadAgentDefinition) { | ||
| const recipePath = join(cwd, '.agents', 'mitzo-conversational.yaml'); | ||
| const recipePath = join(cwd, '.agents', `${agentName}.yaml`); |
There was a problem hiding this comment.
🟡 missing_tests: No test coverage for the agentName parameter. The existing ws-handler-v2.test.ts (2745 lines) has no agentName tests. At minimum: (1) verify agentName is forwarded from WS message to startChat, (2) verify the default fallback to mitzo-conversational, (3) verify path traversal attempts are rejected. [fixable]
| // Build session env with worktree paths for the agent (all repos including primary) | ||
| const sessionEnv = sdkEnv(); | ||
| sessionEnv.MITZO_SESSION_ID = wtId; | ||
| const agentName = options.agentName || 'mitzo-conversational'; |
There was a problem hiding this comment.
🔵 style: The default agent name 'mitzo-conversational' is a magic string. Consider extracting it to constants.ts (where other server-wide defaults live) since it appears in an env var assignment and a file path construction — a single source of truth prevents drift. [fixable]
| /** Active subagent task IDs — task_id → tool_use_id (parent_tool_use_id). */ | ||
| activeTaskIds: Map<string, string>; | ||
| /** Agent definition name for ContexGin boot context (e.g., mitzo-conversational, mitzo-telos). */ | ||
| agentName?: string; |
There was a problem hiding this comment.
🟡 regressions: agentName is added to the ManagedSession interface and stored at registration (chat.ts:682), but is never read back anywhere in the codebase (session.agentName has zero grep hits). This is dead metadata — either it should be consumed (e.g., for session restore, reattach, or auditing) or removed from the interface to avoid confusion. [fixable]
Add "Prep for this meeting" button to calendar event cards. Clicking initiates a session with the mitzo-calendar agent and pre-populated meeting context. **Changes:** - EventCard.tsx — add prep button + navigation handler - calendar-utils.ts — prompt and context builders for meeting prep - calendar.css — styles for action button **Flow:** 1. User taps event to expand 2. Clicks "Prep for this meeting" 3. Session starts with mitzo-calendar agent 4. Context includes attendees, time, doc links Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Summary
Add full protocol support for entry-point-specific agent selection, plus UI integration for Telos and Calendar entry points.
Flow:
agentNamein send message optionsMITZO_AGENT_NAMEenv varChanges
Protocol:
packages/protocol/src/ws-schemas-v2.ts— addagentNametoV2SendMessageServer:
server/ws-handler-v2.ts— passagentNametostartChat()server/chat.ts— setMITZO_AGENT_NAMEenv var, use in recipe lookuppackages/harness/src/session-registry.ts— addagentNametoManagedSessionClient:
packages/client/src/store.ts— addagentNametoSendMessageOptionsandPendingSessionfrontend/src/pages/ChatView.tsx— forwardagentNamefrom pending sessionUI Integration:
frontend/src/pages/TodoView.tsx— Telos tasks usemitzo-telosagent ✅frontend/src/components/EventCard.tsx— "Prep for this meeting" button ✅frontend/src/lib/calendar-utils.ts— meeting prep prompt and context builders ✅frontend/src/styles/calendar.css— action button styles ✅Behavior
'mitzo-conversational'when not specifiedmitzo-telosagentmitzo-calendaragentNext Steps
mitzo-pr-review,mitzo-email)Companion PR: dimakis/mgmt#127
Test Plan
mitzo-conversationalagentName: 'mitzo-telos'agentName: 'mitzo-calendar'🤖 Generated with Claude Code