Extending Mycel¶
When built-in features aren't enough, Mycel can be extended with custom logic via WebAssembly (WASM). Three extension points are available: validators, custom functions, and plugins.
Validators¶
Custom validators add field-level validation rules to type definitions. Three types are supported: regex, cel, and wasm.
Regex Validator¶
validator "cuit" {
type = "regex"
pattern = "^[0-9]{2}-[0-9]{8}-[0-9]$"
message = "Must be a valid CUIT (XX-XXXXXXXX-X)"
}
CEL Validator¶
validator "company_email" {
type = "cel"
expr = "value.endsWith('@company.com')"
message = "Must use a company email address"
}
CEL validators receive value (the field value) and must return a boolean.
WASM Validator¶
For complex validation logic that can't be expressed in CEL:
validator "luhn_check" {
type = "wasm"
wasm = "./wasm/validators.wasm"
entrypoint = "validate_credit_card"
message = "Invalid credit card number"
}
Using Validators in Types¶
type "invoice" {
number = string { validate = "luhn_check" }
supplier_tax = string { validate = "cuit" }
contact = string { validate = "company_email" }
}
Custom Functions (WASM)¶
WASM functions extend the CEL transform engine with custom logic. Write in Rust, Go/TinyGo, C, C++, AssemblyScript, or Zig.
functions "pricing" {
wasm = "./wasm/pricing.wasm"
exports = ["calculate_price", "apply_discount"]
}
Then use in any transform:
transform {
total = "calculate_price(input.items)"
adjusted = "apply_discount(output.total, input.coupon_code)"
}
WASM Interface¶
Functions must implement the standard Mycel WASM interface:
Memory management (required by host):
Function exports:
# Input/output via shared memory: host writes JSON input at ptr, reads JSON result
function_name(ptr: i32, len: i32) -> i32 # returns result pointer
See WASM Documentation for complete interface spec and language-specific examples.
Mocks¶
Mocks provide test data without connecting to real services. Place JSON files in mocks/ following the naming convention, then enable with CLI flags.
Directory Structure¶
mocks/
├── db/
│ ├── users.json # Mock for connector "db", target "users"
│ └── products.json
└── external_api/
├── GET_users.json # Mock for GET /users
└── POST_orders.json # Mock for POST /orders
Mock Data Format¶
[
{
"id": "mock-id-1",
"email": "alice@example.com",
"name": "Alice"
},
{
"id": "mock-id-2",
"email": "bob@example.com",
"name": "Bob"
}
]
Enabling Mocks¶
# Mock all connectors
mycel start --config ./my-service
# Mock specific connectors only
mycel start --mock=db --mock=external_api
# Mock all except specific connectors
mycel start --no-mock=stripe
How Mocks Work¶
When a mock is enabled for a connector, all reads from that connector return mock data. Writes are silently discarded. This lets you test transforms and flow logic without real database or API access.
Plugins¶
Plugins add new connector types to Mycel via WASM modules. Useful for integrating systems not natively supported.
After declaring the plugin, use its connector like any built-in connector:
connector "sf" {
type = "salesforce"
instance_url = env("SF_INSTANCE_URL")
token = env("SF_TOKEN")
}
flow "sync_contacts" {
from {
connector = "api"
operation = "POST /sync"
}
to {
connector = "sf"
operation = "upsert_contact"
}
}
Plugin Sources¶
| Format | Example |
|---|---|
| GitHub | github.com/org/repo |
| GitLab | gitlab.com/org/repo |
| Local path | ./plugins/my-plugin |
| Any git URL | https://git.internal.com/repo |
Version Constraints¶
| Constraint | Meaning |
|---|---|
"^1.0" |
Compatible with 1.x (>= 1.0, < 2.0) |
"~2.0" |
Patch-level updates (>= 2.0, < 2.1) |
">= 1.0, < 3.0" |
Explicit range |
"latest" |
Latest release |
Plugin Management¶
mycel plugin install # Install all plugins from config
mycel plugin list # Show installed plugins
mycel plugin remove salesforce # Remove a plugin
mycel plugin update # Update all plugins
Plugins are cached in mycel_plugins/ (add to .gitignore). Reproducible builds via plugins.lock.
Plugin Manifest¶
Plugin authors create a plugin.mycel file:
plugin {
name = "salesforce"
version = "1.0.0"
}
provides {
connector "salesforce" {
wasm = "connector.wasm"
}
validator "sf_id" {
wasm = "validators.wasm"
entrypoint = "validate_sf_id"
message = "Invalid Salesforce ID"
}
sanitizer "pii_filter" {
wasm = "sanitizers.wasm"
entrypoint = "filter_pii"
apply_to = ["flows/api/*"]
fields = ["email", "phone"]
}
}
Aspects¶
Aspects (cross-cutting concerns applied across flows by pattern matching) are a core concept, not a runtime extension — they're fully declarative, with no WASM or external code involved. Their documentation now lives in Core Concepts → Aspects.
See Also¶
- WASM Documentation — complete WASM interface and language examples
- Plugins example
- Validators example
- Aspects example
- Mocks example