Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
343857d
docs(specs): analyze repository and define spec for ai tool plugin sy…
arielshad Apr 13, 2026
2a7ba14
docs(specs): define requirements and product questions for ai tool pl…
arielshad Apr 13, 2026
4b9dca7
docs(specs): research technical decisions for ai tool plugin system
arielshad Apr 13, 2026
aae62ff
docs(specs): create implementation plan and task breakdown for ai too…
arielshad Apr 13, 2026
3c1182e
feat(tsp): add plugin domain models and enums for ai tool plugin system
arielshad Apr 13, 2026
83eabba
feat(domain): add plugin persistence layer with migrations, mapper, a…
arielshad Apr 13, 2026
48bd7bc
feat(domain): add plugin port interfaces, catalog, and use cases
arielshad Apr 13, 2026
0e2dfe3
feat(domain): add plugin health checker service and check health use …
arielshad Apr 13, 2026
fb224fb
feat(domain): register plugin services and use cases in di container
arielshad Apr 13, 2026
2a6b06d
feat(domain): implement mcp server manager service with process lifec…
arielshad Apr 13, 2026
ba3061c
feat(domain): add mcpconfigpath to agent execution options interface
arielshad Apr 13, 2026
4d8bfb2
feat(domain): inject mcp-config flag in claude code executor
arielshad Apr 13, 2026
b63e531
feat(agents): add mcpconfigpath to feature agent state and executor o…
arielshad Apr 13, 2026
8301907
feat(agents): integrate plugin mcp server lifecycle into feature agen…
arielshad Apr 13, 2026
d353f7a
feat(cli): add plugin command group with 8 subcommands
arielshad Apr 13, 2026
72c26a2
test(cli): add plugin command group unit tests
arielshad Apr 13, 2026
d024a88
feat(web): add plugin management ui with catalog browser and per-feat…
arielshad Apr 14, 2026
7f328ef
chore(specs): capture evidence for ai tool plugin system feature
arielshad Apr 14, 2026
ec2da4f
chore(specs): recapture evidence screenshots for ai tool plugin system
arielshad Apr 14, 2026
063d195
chore(specs): recapture evidence for ai tool plugin system
arielshad Apr 14, 2026
ada3e8a
chore(specs): add feature tracking yaml for ai tool plugin system
arielshad Apr 14, 2026
6b67604
fix(ci): attempt 1/10 — add gitleaks ignore for mock tokens
arielshad Apr 14, 2026
ce5384b
fix(ci): attempt 2/10 — shorten commit subject exceeding 72 char limit
arielshad Apr 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ d05e96264388c5293b05819845dd77053b97e477:src/presentation/web/components/feature
d05e96264388c5293b05819845dd77053b97e477:src/presentation/web/components/features/settings/agent-settings-section.stories.tsx:generic-api-key:78
f2099f97e4e447aac7f141b14a2eb38a39df56f7:src/presentation/web/components/features/settings/agent-settings-section.stories.tsx:generic-api-key:68
f2099f97e4e447aac7f141b14a2eb38a39df56f7:src/presentation/web/components/features/settings/agent-settings-section.stories.tsx:generic-api-key:78
d05e96264388c5293b05819845dd77053b97e477:src/presentation/web/components/features/settings/agent-settings-section.stories.tsx:generic-api-key:68
d05e96264388c5293b05819845dd77053b97e477:src/presentation/web/components/features/settings/agent-settings-section.stories.tsx:generic-api-key:78
3 changes: 3 additions & 0 deletions apis/json-schema/Feature.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ properties:
worktreePath:
type: string
description: Absolute path to the git worktree for this feature
activePlugins:
$ref: RecordBoolean.yaml
description: Per-feature plugin activation overrides mapping plugin names to enabled state (JSON-serialized in DB)
pr:
$ref: PullRequest.yaml
description: Pull request data (null until PR created)
Expand Down
86 changes: 86 additions & 0 deletions apis/json-schema/Plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
$schema: https://json-schema.org/draft/2020-12/schema
$id: Plugin.yaml
type: object
properties:
name:
type: string
description: Unique plugin name used as identifier (e.g., 'mempalace', 'ruflo')
displayName:
type: string
description: Human-readable display name for UI presentation
type:
$ref: PluginType.yaml
description: Integration type determining how the plugin connects to Shep workflows
version:
type: string
description: Installed version of the plugin package
installSource:
type: string
description: "Installation source: 'catalog' for curated plugins, 'custom' for user-added"
transport:
$ref: PluginTransport.yaml
description: MCP transport protocol (only for Mcp type plugins)
serverCommand:
type: string
description: Command to start the MCP server process (only for Mcp type plugins)
serverArgs:
type: array
items:
type: string
description: Arguments passed to the MCP server command (only for Mcp type plugins)
requiredEnvVars:
type: array
items:
type: string
description: Environment variable names required by this plugin (names only, never values)
toolGroups:
type: array
items:
$ref: ToolGroup.yaml
description: Available tool groups defined by this plugin for selective activation
activeToolGroups:
type: array
items:
type: string
description: Names of currently enabled tool groups from the available set
enabled:
type: boolean
default: true
description: Whether this plugin is globally enabled for use in features
healthStatus:
$ref: PluginHealthStatus.yaml
default: Unknown
description: Current operational health status based on multi-tier health checks
healthMessage:
type: string
description: Human-readable details from the most recent health check
hookType:
type: string
description: Hook event type for lifecycle integration (only for Hook type plugins)
scriptPath:
type: string
description: Path to the hook script file (only for Hook type plugins)
binaryCommand:
type: string
description: Executable command for CLI tool invocation (only for Cli type plugins)
runtimeType:
type: string
description: "Required runtime environment: 'python' or 'node'"
runtimeMinVersion:
type: string
description: Minimum required version of the runtime (e.g., '3.9' for Python, '20' for Node.js)
homepageUrl:
type: string
description: Plugin homepage or repository URL for reference
description:
type: string
description: Brief description of what this plugin provides
required:
- name
- displayName
- type
- enabled
- healthStatus
allOf:
- $ref: BaseEntity.yaml
description: External AI-native tool registered in Shep's plugin system
9 changes: 9 additions & 0 deletions apis/json-schema/PluginHealthStatus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
$schema: https://json-schema.org/draft/2020-12/schema
$id: PluginHealthStatus.yaml
type: string
enum:
- Healthy
- Degraded
- Unavailable
- Unknown
description: Operational health status of a plugin based on multi-tier health checks
7 changes: 7 additions & 0 deletions apis/json-schema/PluginTransport.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
$schema: https://json-schema.org/draft/2020-12/schema
$id: PluginTransport.yaml
type: string
enum:
- Stdio
- Http
description: Transport protocol for MCP server communication
8 changes: 8 additions & 0 deletions apis/json-schema/PluginType.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$schema: https://json-schema.org/draft/2020-12/schema
$id: PluginType.yaml
type: string
enum:
- Mcp
- Hook
- Cli
description: Integration type determining how a plugin connects to Shep workflows
6 changes: 6 additions & 0 deletions apis/json-schema/RecordBoolean.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
$schema: https://json-schema.org/draft/2020-12/schema
$id: RecordBoolean.yaml
type: object
properties: {}
additionalProperties:
type: boolean
18 changes: 18 additions & 0 deletions apis/json-schema/ToolGroup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
$schema: https://json-schema.org/draft/2020-12/schema
$id: ToolGroup.yaml
type: object
properties:
name:
type: string
description: Group identifier used for activation and filtering
description:
type: string
description: Human-readable description of what this tool group provides
tools:
type: array
items:
type: string
description: List of individual tool names belonging to this group
required:
- name
description: Logical grouping of MCP tools within a plugin for selective activation
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ export interface AgentExecutionOptions {
disableMcp?: boolean;
/** Restrict available built-in tools via --tools flag */
tools?: string[];
/**
* Path to a per-feature .mcp.json temp file containing MCP server definitions
* for plugin-provided tools. When set, the executor passes this to the agent
* (e.g., Claude Code --mcp-config <path>) so plugin MCP servers are available.
* Generated by McpServerManagerService.generateMcpConfigPath().
*/
mcpConfigPath?: string;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export type { IRepositoryRepository } from './repository-repository.interface.js
export type { IInteractiveSessionRepository } from './interactive-session-repository.interface.js';
export type { IInteractiveMessageRepository } from './interactive-message-repository.interface.js';
export type { IApplicationRepository } from './application-repository.interface.js';
export type { IPluginRepository } from './plugin-repository.interface.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Plugin Repository Interface
*
* Output port for Plugin persistence operations.
* Implementations handle database-specific logic (SQLite, etc.).
*
* Following Clean Architecture:
* - Domain and Application layers depend on this interface
* - Infrastructure layer provides concrete implementations
*/

import type { Plugin } from '../../../../domain/generated/output.js';

/**
* Repository interface for Plugin entity persistence.
*
* Implementations must:
* - Handle database connection management
* - Provide thread-safe operations
* - Enforce unique plugin names
*/
export interface IPluginRepository {
/**
* Create a new plugin record.
*
* @param plugin - The plugin to persist
*/
create(plugin: Plugin): Promise<void>;

/**
* Find a plugin by its unique ID.
*
* @param id - The plugin ID
* @returns The plugin or null if not found
*/
findById(id: string): Promise<Plugin | null>;

/**
* Find a plugin by its unique name.
*
* @param name - The plugin name (e.g., 'mempalace', 'ruflo')
* @returns The plugin or null if not found
*/
findByName(name: string): Promise<Plugin | null>;

/**
* List all plugins ordered by name.
*
* @returns Array of all plugins
*/
list(): Promise<Plugin[]>;

/**
* Update an existing plugin.
*
* @param plugin - The plugin with updated fields
*/
update(plugin: Plugin): Promise<void>;

/**
* Delete a plugin by ID (hard delete).
*
* @param id - The plugin ID to delete
*/
delete(id: string): Promise<void>;
}
5 changes: 5 additions & 0 deletions packages/core/src/application/ports/output/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,8 @@ export type {
TerminalOutputListener,
TerminalExitListener,
} from './terminal-session-service.interface.js';
export type { IMcpServerManager, ActiveMcpServer } from './mcp-server-manager.interface.js';
export type {
IPluginHealthChecker,
PluginHealthResult,
} from './plugin-health-checker.interface.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* MCP Server Manager Interface
*
* Output port for managing MCP server process lifecycle.
* Handles spawning, stopping, and reference counting of MCP server
* processes used by plugins during feature execution.
*
* Following Clean Architecture:
* - Application layer depends on this interface
* - Infrastructure layer provides concrete implementation (child_process.spawn)
*/

import type { Plugin } from '../../../../domain/generated/output.js';

/**
* Information about a running MCP server process.
*/
export interface ActiveMcpServer {
/** Plugin name this server belongs to */
pluginName: string;
/** Process ID of the running server */
pid: number;
/** Number of features currently using this server */
referenceCount: number;
}

/**
* Service interface for managing MCP server process lifecycle.
*
* Implementations must:
* - Spawn MCP server processes for enabled plugins
* - Track reference counts for concurrent feature access
* - Clean up processes on feature stop or unexpected exit
* - Generate per-feature MCP config files for agent executors
*/
export interface IMcpServerManager {
/**
* Start MCP servers for all provided plugins for a given feature.
* Increments reference counts for already-running shared servers.
*
* @param featureId - The feature requesting the servers
* @param plugins - MCP-type plugins to start servers for
*/
startServersForFeature(featureId: string, plugins: Plugin[]): Promise<void>;

/**
* Stop MCP servers for a feature and decrement reference counts.
* Kills server processes when reference count reaches zero.
* Also cleans up the per-feature MCP config temp file.
*
* @param featureId - The feature releasing the servers
*/
stopServersForFeature(featureId: string): Promise<void>;

/**
* Get information about all MCP servers active for a feature.
*
* @param featureId - The feature to query
* @returns Array of active server info, empty if none
*/
getActiveServers(featureId: string): ActiveMcpServer[];

/**
* Generate a temporary .mcp.json config file for a feature's active plugins.
* The file path can be passed to agent executors via --mcp-config flag.
*
* @param featureId - The feature to generate config for
* @returns Absolute path to the generated temp config file, or null if no active servers
*/
generateMcpConfigPath(featureId: string): Promise<string | null>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Plugin Health Checker Interface
*
* Output port for verifying plugin operational health.
* Implements multi-tier health checks: runtime detection,
* package verification, env var validation, and optional server probe.
*
* Following Clean Architecture:
* - Application layer depends on this interface
* - Infrastructure layer provides concrete implementation
*/

import type { Plugin, PluginHealthStatus } from '../../../../domain/generated/output.js';

/**
* Result of a health check on a single plugin.
*/
export interface PluginHealthResult {
/** The plugin name that was checked */
pluginName: string;
/** Overall health status */
status: PluginHealthStatus;
/** Human-readable details about the health check result */
message: string;
}

/**
* Service interface for plugin health verification.
*
* Implementations must:
* - Check runtime availability (python3/node on PATH)
* - Verify package installation where applicable
* - Validate required environment variables are set
* - Optionally probe MCP server startup for deep checks
*/
export interface IPluginHealthChecker {
/**
* Run a multi-tier health check on a single plugin.
*
* @param plugin - The plugin to check
* @returns Health check result with status and message
*/
checkHealth(plugin: Plugin): Promise<PluginHealthResult>;

/**
* Run health checks on all provided plugins.
*
* @param plugins - Plugins to check
* @returns Array of health results, one per plugin
*/
checkAllHealth(plugins: Plugin[]): Promise<PluginHealthResult[]>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ export class CreateFeatureUseCase {
enableEvidence: input.enableEvidence ?? false,
injectSkills: input.injectSkills ?? false,
commitEvidence: input.commitEvidence ?? false,
...(input.activePlugins && Object.keys(input.activePlugins).length > 0
? { activePlugins: input.activePlugins }
: {}),
approvalGates: input.approvalGates ?? {
allowPrd: false,
allowPlan: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export interface CreateFeatureInput {
rebaseBeforeBranch?: boolean;
/** Inject curated skills into the worktree (overrides settings.workflow.skillInjection.enabled). */
injectSkills?: boolean;
/** Per-feature plugin activation overrides (plugin name -> enabled/disabled). */
activePlugins?: Record<string, boolean>;
}

export interface CreateFeatureResult {
Expand Down
Loading
Loading