Relationships
#376 Expose cel-js Environment to extensions for custom CEL evaluation
Opened by adam · 5/19/2026· Shipped 5/19/2026
Problem
Extensions cannot currently evaluate CEL expressions as part of their own implementation. CEL is used internally for workflow conditions, data queries, forEach expansion, and definition evaluation, but the evaluator is not reachable from extension code.
A concrete use case: an SSH factory model that defines a fleet up front and
exposes methods like exec. Users should be able to target hosts with
expressions like tags.contains("web") && region == "us-east-1" — predicates
the extension evaluates against fleet members at call time. More complex
extensions may want to register their own functions, types, or operators
scoped to their own evaluation context.
Proposed Solution
Expose cel-js Environment directly from src/libswamp/mod.ts via a factory
that returns a fresh, isolated environment seeded with swamp's baseline
registrations (bigint/double arithmetic overloads, namespace types).
Extensions construct their own environment, register whatever functions or
types they need, and call parse() / evaluate() themselves.
CEL should be CEL — no wrapper, no swamp-specific abstraction layer. The
cel-js Environment API already provides everything needed:
parse(expression)returns a reusable evaluation function — extensions decide compile-once-evaluate-many vs re-parse per callevaluate()is async and natively propagates Promises through registered functionsregisterFunction/registerType/registerOperator/clone— extensions shape their own environment without touching swamp's global one
This is per-extension, not global registration — no collision concerns, no shared state, no impact on swamp's internal CEL surface.
Scope of Changes
- New factory in
src/infrastructure/cel/cel_evaluator.ts(or a sibling file) that builds a freshEnvironmentwith the baseline registrations currently inCelEvaluator's constructor (lines 191–328) - Re-export
Environmentand the factory fromsrc/libswamp/mod.ts MethodContext(src/domain/models/model.ts:146) gets the factory available so model method extensions can call it- Documentation in the extension authoring docs covering registration and compile-once vs per-call parse patterns
Alternatives Considered
celFilter(items, predicate)helper onMethodContext— narrowest API, covers the SSH targeting case directly, but locks extensions out of anything beyond predicate filtering (custom functions, custom types, richer integrations).- Wrapped swamp-owned interface around
Environment— gives swamp control over the public contract, but means re-exporting a subset of cel-js and giving up features like.check()for type validation. Delays the cost of a future cel-js replacement without eliminating it. - Global CEL environment extension point — extensions register into the shared environment. Rejected: collision policy, lifecycle, and validation timing all become real design problems for no current need.
Direct `Environment` exposure is the simplest, most honest surface and matches the principle that CEL should be CEL.
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.