| name | membrane-config |
| description | Generate a Membrane API Gateway configuration example or snippet — an apis.yaml (default) or, when explicitly asked, a legacy proxies.xml. Use this whenever the user wants a config, example, or snippet for Membrane: routing a port to a backend, a flow with plugins (setHeader, rateLimiter, basicAuthentication, openapi, choose/if, static/return, template, validator, oauth2, llmGateway, ...), TLS termination, SOAP/REST transformation, or "how do I configure X in Membrane". Also trigger for phrases like "membrane config", "apis.yaml example", "proxies.xml", "add a plugin to my gateway config", or "show me the YAML for ...". Grounds output in the project's real tutorials and verifies it against membrane.schema.json. |
Membrane configuration generator
Membrane is configured declaratively. The modern format is apis.yaml; a legacy
Spring proxies.xml format also exists. This skill produces correct, idiomatic
config by doing what a careful engineer does: copy the shape from a real working
example, confirm exact attribute names against the schema, and validate before
handing it over.
Two sources of truth, and they play different roles:
distribution/tutorials/**/*.yaml — idiom and style. Heavily commented,
curated, and the best examples in the repo. Treat these as gold.
distribution/examples/** adds more (including proxies.xml).
membrane.schema.json — what's actually allowed: every element, its exact
attribute names, enum values, and nesting. The model's main failure mode is
inventing plausible-but-wrong attribute names; the schema is how you avoid that.
Don't generate config from memory alone. The element set is large (~255
elements) and evolves; ground every snippet.
Workflow
-
Clarify intent only if needed. What should the gateway do? Default to one
api on port 2000 forwarding to a target.url unless the request implies
otherwise. Don't over-ask — most requests map cleanly onto a known pattern.
-
Find a close example. Skim references/cheatsheet.md
for the matching pattern, then look at the real tutorial for the live version:
grep -rl "rateLimiter:" distribution/tutorials distribution/examples
Reading the closest tutorial is the single highest-leverage step — it carries
ordering, nesting, and conventions you'd otherwise guess at.
-
Confirm exact attributes against the schema for every non-trivial element.
Guessing attribute names is the main way these configs go wrong:
python3 scripts/describe_element.py rateLimiter
python3 scripts/describe_element.py --grep auth
python3 scripts/describe_element.py --list
-
For any expression, template, or built-in function, read
references/expressions.md before writing it. The
schema does not cover this, and it's the easiest place to be confidently
wrong: which engine evaluates a string (template is Groovy, setBody/if
default to SpEL), how you call a function (${user()} in SpEL vs.
${fn.user()} in a Groovy template), which variables are in scope, and the
full built-in catalog (user(), base64Encode, hasScope, env, …). These
bugs surface as a runtime 500, not a schema error — validate_config.py won't
catch them.
-
Write the config following the conventions below.
-
Validate (YAML only) — always, before presenting:
python3 scripts/validate_config.py path/to/apis.yaml
Fix every reported problem and re-run until it passes. If you only produced a
snippet, drop it into a minimal api: skeleton in a temp file and validate
that, so you're confident the snippet is structurally sound.
The scripts find the schema automatically: they prefer the locally built
core/target/classes/com/predic8/membrane/core/config/json/membrane.schema.json
and fall back to downloading the published v7.4.0.json (cached). They
bootstrap their own dependencies on first run, so just call them.
Conventions
Match the tutorials so generated config looks native:
- Schema header. Start full files with
# yaml-language-server: $schema=https://www.membrane-api.io/<version>.json — it
gives editors autocompletion and validation. Pin <version> to whatever the
tutorials currently use (grep one: grep -m1 schema= distribution/tutorials/*/*.yaml),
not a hardcoded number here — it tracks the current release and goes stale otherwise.
- One top-level key per document. Each YAML document has exactly one root key
(
api, global, configuration, soapProxy, sslProxy). Separate multiple
definitions with a --- line.
- Default port 2000 (8443 for TLS), matching the tutorials.
- Comment with purpose. Tutorials briefly say what a block does and, where
useful, a
curl line to try it. Add short comments in that spirit — explain
intent, don't narrate syntax.
- Snippet vs. full file. If the user asked for a snippet to drop into an
existing config, return just the relevant
flow/plugin block at the right
indentation. If they asked for an example or a runnable config, return a
complete file with the header and a target or return.
Output
Present the config in a fenced code block with yaml or xml as its info string. Below it, add a line or
two on what it does and, when it makes the example concrete, how to run and test
it (e.g. ./membrane.sh -c apis.yaml then a curl). State that you validated it
against the schema. If a requested feature isn't in the schema (the local build
can lag the newest features — e.g. some AI plugins), say so and point to the
tutorial you based it on instead of forcing it through validation.
XML (proxies.xml)
Only when the user explicitly asks for XML / proxies.xml / the Spring format.
Same elements, camelCase tags, attributes instead of nested keys, wrapped in
<spring:beans>...<router>. Ground it in a real
distribution/examples/**/proxies.xml; see the XML section of
references/cheatsheet.md. validate_config.py does
not check XML, so lean harder on matching an existing example.