Claude-skill-registry extension-developer
Use this skill when the user needs help building, testing, or deploying custom LimaCharlie extensions.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/extension-developer" ~/.claude/skills/majiayu000-claude-skill-registry-extension-developer && rm -rf "$T"
skills/data/extension-developer/SKILL.mdLimaCharlie Extension Developer
This skill helps you build custom LimaCharlie extensions. Use this when users ask for help creating extensions, understanding the extension architecture, building UI components, or debugging extension issues.
What are LimaCharlie Extensions?
LimaCharlie Extensions are small HTTPS services that receive webhooks from the LimaCharlie cloud, enabling you to expand and customize security environments by integrating third-party tools, automating workflows, and adding new capabilities.
Key Benefits
- Multi-tenancy: LC organizations can subscribe to your extension and replicate features across tenants
- Credentials handling: No need to store credentials - every callback includes an authenticated LimaCharlie SDK with requested permissions
- Configuration: LC provides a configuration JSON object stored in Hive with validation callbacks
- Auto-generated UI: Extensions define a schema that LimaCharlie interprets to generate custom user interfaces
Public vs Private Extensions
- Private Extensions: Require
andbilling.ctrl
permissions to subscribe an organizationuser.ctrl - Public Extensions: Visible and subscribable by everyone (contact answers@limacharlie.io to make an extension public)
Extension Architecture
High-Level Structure
Extensions are HTTPS services that:
- Receive webhooks from LimaCharlie cloud
- Process requests using the LimaCharlie SDK (provided in callbacks)
- Return responses in JSON format
- Can be hosted on Google Cloud Run, AWS Lambda, or custom infrastructure
Request/Response Model
User/D&R Rule → LimaCharlie Cloud → Extension (via webhook) ↓ Process with LC SDK ↓ Return JSON Response
Each webhook includes:
- Request data: Action name and parameters
- Authenticated SDK: Pre-configured with org-specific permissions
- Organization context: Relevant to the callback
- Signature: Shared secret for authenticity verification
Quick Start
Step 1: Choose Framework
Golang (recommended for stricter typing):
https://github.com/refractionPOINT/lc-extension
Python:
https://github.com/refractionPOINT/lc-extension/tree/master/python
Step 2: Create Extension Definition
Navigate to: https://app.limacharlie.io/add-ons/published
Required fields:
- Destination URL: HTTPS endpoint for your extension
- Required Extensions: List of other extensions your extension depends on
- Shared Secret: Random string (32+ characters) for webhook signature verification
- Extension Flairs:
: Isolates resources (extension can only see/modify what it created)segment
: Increases API quota for extensions making many API callsbulk
- Permissions: List of required permissions (use least privilege)
Step 3: Define Schema
Create a basic schema with configuration and actions:
{ "config_schema": { "fields": { "api_key": { "data_type": "secret", "description": "API key for external service", "label": "API Key" } }, "requirements": [["api_key"]] }, "request_schema": { "scan": { "is_impersonated": false, "is_user_facing": true, "short_description": "Scan a sensor", "parameters": { "fields": { "sid": { "data_type": "sid", "description": "Sensor ID to scan", "label": "Sensor" } }, "requirements": [["sid"]] } } }, "required_events": ["subscribe", "unsubscribe"] }
Step 4: Implement Callbacks
e.OnRequest("scan", func(ctx *ext.Context) (interface{}, error) { sid := ctx.Params["sid"].(string) results := performScan(ctx.SDK, sid) return map[string]interface{}{"status": "completed", "findings": results}, nil }) e.OnEvent("subscribe", func(ctx *ext.Context) error { log.Printf("New subscription: %s", ctx.OID) return nil })
Step 5: Deploy and Test
- Deploy to Cloud Run, Lambda, or custom infrastructure
- Update extension with destination URL
- Test locally with ngrok for debugging
- Subscribe a test organization
- Invoke actions from UI or D&R rules
Extension Schema Basics
Schema Structure
{ "config_schema": { "fields": { /* configuration fields */ }, "requirements": [ /* required fields */ ] }, "request_schema": { "action_name": { "is_impersonated": false, "is_user_facing": true, "short_description": "Brief description", "long_description": "Detailed description", "parameters": { "fields": { /* action parameters */ }, "requirements": [ /* required parameters */ ] }, "response": { "fields": { /* response structure */ } } } }, "required_events": ["subscribe", "unsubscribe", "update"] }
Field Structure
Every field follows this minimal structure:
{ "field_name": { "data_type": "string", "description": "Field description", "label": "Human Readable Label", "placeholder": "Example value", "display_index": 1, "default_value": "default" } }
Requirements Array
The
requirements field defines which fields are required:
// Both fields required "requirements": [["denominator"], ["numerator"]] // denominator AND (numerator OR default) required "requirements": [["denominator"], ["numerator", "default"]]
- First array joins with AND
- Nested arrays join with OR
Common Data Types
| Type | Description | Example |
|---|---|---|
| Text value | Any text |
| Number | 42 |
| Boolean | true/false |
| Selection from list | Requires |
| Sensor ID | UUID format |
| Secret from secrets manager | Encrypted value |
| JSON data | Any JSON object |
| YAML data | YAML content |
| Nested fields | Complex structures |
For complete data type reference, see REFERENCE.md.
Request Handling
Actions are defined in
request_schema with parameters:
- is_impersonated: Uses user's authentication context
- is_user_facing: Shows in UI (false = API/D&R only)
- parameters: Input fields for the action
- response: Expected output structure
e.OnRequest("action_name", func(ctx *ext.Context) (interface{}, error) { param := ctx.Params["param_name"].(string) config, _ := ctx.SDK.Hive().Get("extension_configuration", "my-ext") sensor, _ := ctx.SDK.Sensor(param).Get() return map[string]interface{}{"status": "success", "data": sensor}, nil }) e.OnEvent("subscribe", func(ctx *ext.Context) error { return ctx.SDK.Rules().Add("my-rule", ruleContent) })
UI Development Basics
Auto-Generated UI
LimaCharlie automatically generates UI from your schema. The UI adapts based on data types and layout configuration.
Layout Types
Specify layout in schema's top-level
layout field:
- auto (default): Automatically selects appropriate layout
- config: Prioritizes configuration display
- editor: For large code blocks (YAML/JSON editing)
- action: Prioritizes specific actions with in-page forms
- description: Description-focused layout
Multiple Layouts (Tabs)
{ "views": [ { "name": "Configuration", "layout": "config" }, { "name": "Actions", "layout": "action", "default_action": "scan" }, { "name": "Documentation", "layout": "description" } ] }
Tables with Object Lists
Use
is_list: true with object data type to create table UI:
{ "rules": { "data_type": "object", "is_list": true, "description": "Detection rules", "object": { "fields": { "name": { "data_type": "string", "description": "Rule name" }, "severity": { "data_type": "enum", "enum_values": ["low", "medium", "high"] } } } } }
Using Extensions
From D&R Rules
detect: event: NEW_PROCESS op: is path: event/FILE_PATH value: /usr/bin/suspicious respond: - action: extension request extension name: my-scanner extension action: scan extension request: sid: '{{ .routing.sid }}'
From CLI
limacharlie extension request \ --name my-scanner \ --action scan \ --data '{"sid": "sensor-id"}'
From API
curl -X POST "https://api.limacharlie.io/v1/ext/my-scanner/request" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"oid": "org-id", "action": "scan", "params": {"sid": "sensor-id"}}'
Best Practices
Security: Always verify webhook signatures, use least privilege permissions, validate all input, secure secrets in environment variables, use segment flair for resource isolation.
Performance: Use async operations for long tasks, cache configurations, use bulk flair for high API usage, implement timeouts.
Error Handling: Return meaningful errors, handle partial failures gracefully, maintain comprehensive logs.
Simplified Frameworks
D&R Framework: Package D&R rules for distribution using
lc-extension/simplified/dr
Lookup Framework: Package threat intelligence lookups using
lc-extension/simplified/lookup
CLI Framework: Integrate external CLI tools using
lc-extension/simplified/cli
See EXAMPLES.md for complete implementations.
Navigation
- REFERENCE.md: Complete extension architecture, all data types, field options, request/response formats
- EXAMPLES.md: Complete extension examples with full code (alerting, scanning, etc.)
- TROUBLESHOOTING.md: Testing strategies, deployment guides, debugging tips
Quick Reference
Extension Definition: Destination URL (HTTPS endpoint), Shared Secret (32+ chars), Permissions array, Extension Flairs (
segment, bulk)
Schema Fields:
config_schema (configuration), request_schema (actions), required_events (subscribe/unsubscribe/update), layout (UI type), views (tabs)
Callbacks: Request (handle actions), Event (handle subscribe/unsubscribe/update), Config Validation (validate changes)
Common Permissions:
sensor.get/task, dr.get/set, hive.get/set, artifact.get, outputs.get/set
Additional Resources
Code: Golang Framework | Python Framework
API Docs: Extension API | Schema API
Support: Community Slack | answers@limacharlie.io
Key Reminders
Always verify webhook signatures, use least privilege permissions, validate input, test with test organizations first, use segment flair for isolation, implement proper error handling, cache configurations, use simplified frameworks for common patterns, test locally with ngrok before deploying.