Skip to content

feat: Add plugin support for label-based routing (CYPACK-782)#832

Open
cyrusagent wants to merge 18 commits intomainfrom
cypack-782
Open

feat: Add plugin support for label-based routing (CYPACK-782)#832
cyrusagent wants to merge 18 commits intomainfrom
cypack-782

Conversation

@cyrusagent
Copy link
Contributor

@cyrusagent cyrusagent commented Feb 5, 2026

Summary

Implements plugin infrastructure that allows installing and loading Claude SDK plugins based on issue labels, enabling custom extensions to enhance Cyrus capabilities for specific workflows.

Key Changes

  • Plugin installation endpoint (POST /api/plugins/install) - Accepts zip content or URL for plugin archives
  • Plugin storage - Plugins stored in ~/.cyrus/plugins/ directory with proper validation
  • Config schema updates - Added pluginRouting and plugins fields to repository config
  • Label-based routing - Plugins automatically loaded based on issue labels (case-insensitive matching)
  • Claude SDK integration - Resolved plugins passed to SDK query() function

Implementation Details

New Files

  • packages/edge-worker/src/PluginService.ts - Full plugin management service
  • packages/edge-worker/test/PluginService.test.ts - Comprehensive test suite (29 tests)

Modified Files

  • packages/claude-runner/src/types.ts - Added plugins field to ClaudeRunnerConfig
  • packages/claude-runner/src/ClaudeRunner.ts - Pass plugins to SDK query options
  • packages/core/src/config-schemas.ts - Added PluginConfigSchema and PluginRoutingSchema
  • packages/edge-worker/src/EdgeWorker.ts - Plugin endpoint registration and label-based resolution
  • apps/cli/src/Application.ts - Added "plugins" directory initialization

Plugin Structure

Plugins must contain .claude-plugin/plugin.json manifest with at minimum a name field.

Config Example

pluginRouting:
  my-plugin: ["feature", "enhancement"]
plugins:
  - name: my-plugin
    path: /path/to/plugin
    labels: ["feature"]
    isActive: true

Testing

  • 29 new unit tests for PluginService covering:
    • Plugin validation (valid/invalid structures)
    • Installation from zip and URL
    • Plugin listing and deletion
    • Label-based resolution (case-insensitive, multiple labels, inactive plugins)
  • All 484 tests passing
  • Build clean, typecheck clean, lint clean

Breaking Changes

None - this is an additive feature.

Linear Issue

CYPACK-782


🤖 Generated with Claude Code

cyrusagent and others added 18 commits January 26, 2026 13:37
Summary subroutines (concise-summary, verbose-summary, question-answer,
plan-summary, etc.) have disallowAllTools: true, but MCP tools like
Linear's create_comment were still accessible because MCP config was
always provided regardless of this setting.

This change conditionally disables mcpConfig and mcpConfigPath when
disallowAllTools is true, ensuring the agent truly has no tool access
during summary subroutines.

Closes CYPACK-760

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…YPACK-725)

Implements Phase 1 of CYPACK-724 architectural refactor. Creates new
GlobalSessionRegistry class that centralizes session storage across all
repositories, enabling cross-repository session lookups for orchestrator
workflows.

Key features:
- Session CRUD operations (create, get, update, delete, getAll)
- Entry management (add, get, update entries)
- Parent-child session mapping for orchestrator workflows
- EventEmitter with lifecycle events (sessionCreated, sessionUpdated, sessionCompleted)
- Serialization/deserialization (v3.0 format)
- Cleanup method for removing old sessions
- Comprehensive unit tests (45 tests)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add changelog entry for GlobalSessionRegistry implementation with PR link.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix TypeScript error in updateEntry method by ensuring type and content
fields are never undefined when applying partial updates.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…tation (CYPACK-726)

- Create IActivitySink interface for decoupling activity posting
- Implement LinearActivitySink wrapping IIssueTrackerService
- Add comprehensive unit tests (20 tests, all passing)
- Export from edge-worker package

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…726)

Add changelog entry documenting the extraction of IActivitySink interface
and LinearActivitySink implementation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add GlobalSessionRegistry instance to EdgeWorker
- Replace childToParentAgentSession Map calls with GlobalSessionRegistry methods
- Pass GlobalSessionRegistry to AgentSessionManager for future migration
- All session lookups for cross-repo parent resume now use GlobalSessionRegistry

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…(CYPACK-728)

- Rename linearAgentActivitySessionId to id for clarity
- Add optional externalSessionId for tracker-specific IDs (e.g., Linear's AgentSession ID)
- Add optional issueContext object with trackerId, issueId, issueIdentifier
- Make issue and issueId optional for standalone sessions
- Update PersistenceManager to v3.0 with automatic migration from v2.0
- Update all field references in GlobalSessionRegistry, AgentSessionManager, EdgeWorker
- Add 7 new tests for persistence migration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…PACK-728)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix missed linearAgentActivitySessionId → id rename in EdgeWorker.ts:1639
  (code added in main after the Phase 4 schema changes)
- Fix unused variable lint warning in GlobalSessionRegistry.ts:264

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update getAgentRunnersForIssue, getSessionsByIssueId, and
getActiveSessionsByIssueId to resolve issue ID from issueContext first,
falling back to deprecated issueId field. This ensures future standalone
sessions that only populate issueContext will be found correctly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…gentSession (CYPACK-724)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ding max-turns. Now, when the result message of a single-turn sub-routine is an error, the result text from the previous sub-routine is emitted to Linear as a result message.
Implement plugin infrastructure that allows installing and loading plugins
based on issue labels:

- Add plugin installation endpoint (POST /api/plugins/install) that accepts
  zip content or URL
- Store plugins in ~/.cyrus/plugins/ directory with validation
- Add PluginConfigSchema and PluginRoutingSchema to config schemas
- Add pluginRouting and plugins fields to repository config
- Create PluginService for installation, validation, and label-based resolution
- Pass resolved plugins to Claude SDK query() function
- Add comprehensive test suite (29 tests)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@cyrusagent cyrusagent marked this pull request as ready for review February 5, 2026 02:18
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.

2 participants