# Membrane Config

> 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.

- Skill: `membrane/membrane-config` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add membrane/membrane-config`
- Raw SKILL.md: https://api.skillmd.com/api/skills/membrane/membrane-config/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: membrane (https://skillmd.com/u/membrane)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/membrane/membrane-config

---


# 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

1. **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.

2. **Find a close example.** Skim [references/cheatsheet.md](references/cheatsheet.md)
   for the matching pattern, then look at the real tutorial for the live version:
   ```bash
   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.

3. **Confirm exact attributes against the schema** for every non-trivial element.
   Guessing attribute names is the main way these configs go wrong:
   ```bash
   python3 scripts/describe_element.py rateLimiter   # attributes + enums + children
   python3 scripts/describe_element.py --grep auth   # discover element names
   python3 scripts/describe_element.py --list        # all element ids
   ```

4. **For any expression, template, or built-in function**, read
   [references/expressions.md](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.

5. **Write the config** following the conventions below.

6. **Validate** (YAML only) — always, before presenting:
   ```bash
   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](references/cheatsheet.md). `validate_config.py` does
not check XML, so lean harder on matching an existing example.

