use claude_agent_sdk::{
ClaudeAgentOptions, ContentBlock, Message, PermissionMode, SdkPluginConfig, query,
};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
println!("=== Example 21: Custom Plugins ===\n");
println!("--- Example 1: Single Plugin ---\n");
let _single_plugin_options = ClaudeAgentOptions::builder()
.plugins(vec![SdkPluginConfig::local("./my-plugin")])
.permission_mode(PermissionMode::BypassPermissions)
.max_turns(3)
.build();
println!("Configured with single plugin:");
println!(" Plugin: ./my-plugin\n");
println!("✓ Single plugin configuration created\n");
println!("--- Example 2: Multiple Plugins ---\n");
let _multi_plugin_options = ClaudeAgentOptions::builder()
.plugins(vec![
SdkPluginConfig::local("./plugins/database-tools"),
SdkPluginConfig::local("./plugins/api-integration"),
SdkPluginConfig::local("~/.claude/plugins/company-tools"),
])
.permission_mode(PermissionMode::BypassPermissions)
.max_turns(5)
.build();
println!("Configured with multiple plugins:");
println!(" 1. ./plugins/database-tools");
println!(" 2. ./plugins/api-integration");
println!(" 3. ~/.claude/plugins/company-tools\n");
println!("✓ Multiple plugin configuration created\n");
println!("--- Example 3: Using Test Plugin ---\n");
let test_plugin_path = "./fixtures/test-plugin";
if std::path::Path::new(test_plugin_path).exists() {
println!("Test plugin found at: {}", test_plugin_path);
let options = ClaudeAgentOptions::builder()
.plugins(vec![SdkPluginConfig::local(test_plugin_path)])
.permission_mode(PermissionMode::BypassPermissions)
.max_turns(3)
.build();
println!("\nAttempting to use test plugin...");
match query("Hello, check if plugins are loaded", Some(options)).await {
Ok(messages) => {
println!("\n✓ Successfully queried with plugin loaded!\n");
let mut found_plugin_info = false;
for message in &messages {
match message {
Message::System(sys) if sys.subtype == "init" => {
if let Some(plugins) = sys.data.get("plugins") {
println!("Plugins loaded: {:?}", plugins);
found_plugin_info = true;
}
},
Message::Assistant(msg) => {
for block in &msg.message.content {
if let ContentBlock::Text(text) = block {
println!("Claude: {}", text.text);
}
}
},
Message::Result(result) => {
println!("\nResult:");
println!(" Duration: {}ms", result.duration_ms);
println!(" Turns: {}", result.num_turns);
if let Some(cost) = result.total_cost_usd {
println!(" Cost: ${:.4}", cost);
}
},
_ => {},
}
}
if !found_plugin_info {
println!("Note: Plugin info not in system message (this is OK)");
}
},
Err(e) => {
println!("\n⚠ Plugin query failed: {}", e);
println!("Note: The SDK correctly passes --plugin-dir to Claude CLI.");
println!("Plugin support requires Claude CLI with plugin features enabled.");
},
}
} else {
println!("⚠ Test plugin not found at: {}", test_plugin_path);
println!("This is expected in a fresh checkout.");
}
println!("\n--- Example 4: Plugin Path Patterns ---\n");
println!("Supported plugin path patterns:");
println!(" • Relative paths: ./plugins/my-plugin");
println!(" • Absolute paths: /usr/local/plugins/my-plugin");
println!(" • Home directory: ~/.claude/plugins/my-plugin");
println!(" • Project relative: ./my-app-plugins/special-tools");
let path_examples = [
SdkPluginConfig::local("./plugins/local-plugin"),
SdkPluginConfig::local("/opt/company-plugins/tool-suite"),
SdkPluginConfig::local("~/.claude/plugins/personal-tools"),
];
println!("\nExample configurations:");
for (i, plugin) in path_examples.iter().enumerate() {
println!(" {}. {:?}", i + 1, plugin.path().unwrap());
}
println!("\n=== Plugin Development Guide ===\n");
println!("To create a custom plugin:");
println!("1. Create a plugin directory with proper structure");
println!("2. Define plugin metadata (name, version, description)");
println!("3. Implement custom tools and functionality");
println!("4. Test the plugin with Claude CLI");
println!("5. Load it via SdkPluginConfig in your Rust code");
println!("\n=== Plugin Configuration Tips ===\n");
println!("• Plugins extend Claude's capabilities with custom tools");
println!("• Multiple plugins can be loaded simultaneously");
println!("• Plugin order may affect tool resolution");
println!("• Use absolute paths for production deployments");
println!("• Use relative paths for project-specific plugins");
println!("• Home directory paths (~) work for user-specific plugins");
println!("\n=== Security Considerations ===\n");
println!("⚠ Important security notes:");
println!("• Only load plugins from trusted sources");
println!("• Review plugin code before deployment");
println!("• Be cautious with plugins that access sensitive data");
println!("• Use permission modes to control plugin capabilities");
println!("• Test plugins in isolated environments first");
Ok(())
}