pub trait MartyPlugin {
// Required methods
fn name(&self) -> &str;
fn key(&self) -> &str;
fn workspace_provider(&self) -> &dyn WorkspaceProvider;
// Provided method
fn configuration_options(&self) -> Option<Value> { ... }
}Expand description
The main plugin interface that defines plugin metadata and behavior.
This trait provides Marty with essential information about your plugin and
connects it to the workspace scanning logic via WorkspaceProvider.
§Implementation Requirements
Your plugin struct must also implement:
Defaultor provide anew()constructor for theexport_plugin!macro- Be
Send + Syncfor thread safety (automatically satisfied for most structs)
§Example
use marty_plugin_protocol::{MartyPlugin, WorkspaceProvider};
use serde_json::{json, Value};
pub struct MyPlugin;
impl MyPlugin {
pub const fn new() -> Self { Self }
}
impl Default for MyPlugin {
fn default() -> Self { Self::new() }
}
impl MartyPlugin for MyPlugin {
fn name(&self) -> &str {
"My Awesome Framework Plugin" // User-friendly display name
}
fn key(&self) -> &str {
"my-framework" // Unique identifier (no spaces!)
}
fn workspace_provider(&self) -> &dyn WorkspaceProvider {
&MyWorkspaceProvider // Your detection logic
}
fn configuration_options(&self) -> Option<Value> {
Some(json!({
"type": "object",
"properties": {
"version": {
"type": "string",
"description": "Target framework version",
"default": "latest"
}
},
"additionalProperties": false
}))
}
}Required Methods§
Sourcefn name(&self) -> &str
fn name(&self) -> &str
Return the human-readable name of this plugin.
Purpose: Displayed to users in logs, error messages, and plugin listings. Should be descriptive and professional.
Guidelines:
- Use proper capitalization and spacing
- Include the technology/framework name
- Keep it concise but descriptive
- Avoid technical jargon that users might not understand
§Examples
fn name(&self) -> &str {
"Cargo Workspace Plugin" // ✅ Clear, professional
// Other good examples:
// "TypeScript Project Plugin" - Technology-specific
// "Python Requirements Plugin" - Describes functionality
// ❌ Avoid these patterns:
// "cargo-plugin" - Too technical
// "My Super Awesome Plugin!!!" - Unprofessional
// "Plugin" - Too generic
}Sourcefn key(&self) -> &str
fn key(&self) -> &str
Return the unique identifier for this plugin.
Purpose: Used internally by Marty for:
- Plugin registration and loading
- Configuration file sections (
[plugins.your-key]) - Dependency resolution and caching
- The
discovered_byfield inInferredProject
Requirements:
- Must be unique across all plugins
- No whitespace characters (spaces, tabs, newlines)
- Use kebab-case for consistency
- Should be stable across plugin versions
Naming Convention:
- Use the primary technology name:
"cargo","typescript","python" - For sub-technologies, use hyphens:
"next-js","create-react-app" - Avoid version numbers or vendor names in the key
§Examples
fn key(&self) -> &str {
"cargo" // ✅ Rust Cargo projects
// Other good examples:
// "typescript" - TypeScript projects
// "python" - Python projects
// "next-js" - Next.js frameworks
// "docker-compose" - Docker Compose files
// ❌ Avoid these patterns:
// "cargo plugin" - Contains space
// "typescript-v2" - Version in key
// "my company-ts" - Vendor name + space
}Sourcefn workspace_provider(&self) -> &dyn WorkspaceProvider
fn workspace_provider(&self) -> &dyn WorkspaceProvider
Return the workspace provider implementation for this plugin.
Purpose: Connects your plugin to the workspace scanning and project detection logic. This is where the actual work happens.
Implementation Pattern: Most plugins create a separate struct for the workspace provider and return a reference to a static instance.
§Example
fn workspace_provider(&self) -> &dyn WorkspaceProvider {
// Pattern 1: Static instance (most common)
&MyWorkspaceProvider
// Pattern 2: If you need state, use a field
// &self.workspace_provider
}Provided Methods§
Sourcefn configuration_options(&self) -> Option<Value>
fn configuration_options(&self) -> Option<Value>
Return JSON Schema configuration options for this plugin.
Purpose: Allow users to customize plugin behavior through configuration files. The schema is used for validation and IDE autocomplete in Marty config files.
When to Provide Configuration:
- Plugin has configurable behavior (build commands, versions, paths)
- Users need to specify framework-specific options
- Different projects might need different settings
Schema Requirements:
- Must be valid JSON Schema (draft 7 recommended)
- Should have a root
"type": "object" - Include
"description"for all properties - Provide sensible
"default"values - Use
"additionalProperties": falsefor strict validation
§Example: Comprehensive Configuration Schema
fn configuration_options(&self) -> Option<Value> {
Some(json!({
"type": "object",
"description": "Configuration for My Framework Plugin",
"properties": {
// String configurations
"build_command": {
"type": "string",
"description": "Command to build projects",
"default": "build",
"examples": ["build", "compile", "make"]
},
"target_version": {
"type": "string",
"description": "Framework version to target",
"default": "latest",
"enum": ["1.0", "2.0", "latest"]
},
// Boolean flags
"enable_optimization": {
"type": "boolean",
"description": "Enable build optimizations",
"default": true
},
"strict_mode": {
"type": "boolean",
"description": "Enable strict validation rules",
"default": false
},
// Array configurations
"additional_includes": {
"type": "array",
"description": "Extra glob patterns to include",
"items": { "type": "string" },
"default": [],
"examples": [["**/*.config.js", "**/*.env"]]
},
// Nested object configurations
"build_settings": {
"type": "object",
"description": "Advanced build configuration",
"properties": {
"output_dir": {
"type": "string",
"description": "Build output directory",
"default": "dist"
},
"minify": {
"type": "boolean",
"description": "Minify output files",
"default": true
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
"required": [] // Specify required fields if any
}))
}For Simple Plugins: Return None if your plugin doesn’t need configuration.
fn configuration_options(&self) -> Option<Value> {
None // No configuration needed for this plugin
}