Skip to content

Search these docs from your AI tool

  • Antigravity
    {
      "mcpServers": {
        "edisyl-docs": {
          "serverUrl": "https://docs.edisyl.com/mcp"
        }
      }
    }
  • Claude CodeCLI
    claude mcp add edisyl-docs https://docs.edisyl.com/mcp --transport http --scope user
  • CodexCLI
    codex mcp add --url https://docs.edisyl.com/mcp edisyl-docs
  • Cursor
    {
      "mcpServers": {
        "edisyl-docs": {
          "type": "http",
          "url": "https://docs.edisyl.com/mcp"
        }
      }
    }
  • Gemini CLI
    gemini mcp add --transport http edisyl-docs https://docs.edisyl.com/mcp
  • Goose
    {
      "extensions": {
        "edisyl-docs": {
          "enabled": true,
          "name": "edisyl-docs",
          "type": "streamable_http",
          "uri": "https://docs.edisyl.com/mcp",
          "envs": {},
          "env_keys": [],
          "headers": {},
          "description": "",
          "timeout": 300,
          "bundled": null,
          "available_tools": []
        }
      }
    }
  • JetBrains AI Assistant
    {
      "mcpServers": {
        "edisyl-docs": {
          "type": "http",
          "url": "https://docs.edisyl.com/mcp"
        }
      }
    }

    Paste into Settings → Tools → AI Assistant → Model Context Protocol → Add → As JSON. Direct file writing isn’t supported — JetBrains stores this per-version as XML.

  • Junie (JetBrains)
    {
      "mcpServers": {
        "edisyl-docs": {
          "url": "https://docs.edisyl.com/mcp"
        }
      }
    }
  • OpenCode
    {
      "mcp": {
        "edisyl-docs": {
          "type": "remote",
          "url": "https://docs.edisyl.com/mcp"
        }
      }
    }
  • VS CodeCLI
    code --add-mcp '{"name":"edisyl-docs","type":"http","url":"https://docs.edisyl.com/mcp"}'
  • Windsurf
    {
      "mcpServers": {
        "edisyl-docs": {
          "serverUrl": "https://docs.edisyl.com/mcp"
        }
      }
    }

    Supports both stdio and native HTTP connections.

Using your own infrastructure

The chart bundles everything the platform needs, so an install on hardware you own works with no external dependencies. On a cloud you probably already run managed equivalents — and would rather the platform used those than keep a database alive inside the cluster.

Every bundled dependency is optional. Each has an enabled flag and a documented external path, and nothing is duplicated in forked templates: the two postures differ in values only. The configurator asks the database, Redis and object storage choices and writes the values below for you.

Bundled Turn it off with Replace it with
PostgreSQL (CloudNativePG) cnpg.enabled: false database.source, plus a Secret for each other database (below)
Redis redis.enabled: false config.redis* + secrets.managed.edisyl-redis
Object storage (MinIO) minio.enabled: false config.objectStorage* + secrets.managed.edisyl-object-storage
Inngest inngest.enabled: false config.inngestBaseUrl + secrets.managed.edisyl-inngest

Addresses and other settings are values under config.*; only credentials go in a secrets.managed group. A setting left in a managed Secret fails the render and names the config.* key it moved to — see Configuration.

Where the chart can tell that a replacement is missing, it fails the render and names the value — a Helm error rather than a CrashLoopBackOff twenty minutes later. That covers the connection URLs, DATABASE_URL, the Redis host, port, user and password, and the object store’s bucket and URL, but not everything a server needs: pgvector, the Redis modules and a reachable endpoint surface at boot instead. Treat the checks as a safety net, not a specification.

With your own Postgres, each of the three or four databases (see Prerequisites) needs a database, a role that owns it, and a Secret the chart reads its connection from. The chart creates none of them unless the bundled clusters run.

Database Values Secret the chart reads
services database.source managed: chart-managed edisyl-database, key DATABASE_URL. existing-secret: database.existingSecret.name, key database.existingSecret.key (default uri)
auth edisyl.auth.database.secretName, secretKey default mono-auth-db, key uri
inngest inngest.database.source: existing-secret edisyl-inngest-db, key uri (fixed)
bifrost bifrost.database.source: existing-secret bifrost.database.existingSecret.name, keys host, port, username, password, dbname

Every URI is complete and percent-encodes its password. The commands below prompt for a password without echoing it, in bash or zsh, encode it with jq, and create nothing when it is empty; the configurator prints them with your hosts and names filled in. Create the Secrets in the release namespace before installing.

database.source is the switch for where DATABASE_URL comes from. A Secret you already have keeps the credential out of values entirely, which is the better option where something else provisions your database:

cnpg:
enabled: false
database:
source: existing-secret
existingSecret:
name: my-postgres-connection
key: uri

Or supply the URL as a credential:

database:
source: managed
secrets:
managed:
edisyl-database:
data:
DATABASE_URL: "postgresql://edisyl:password@db.example.com:5432/edisyl?sslmode=require"

The render fails if that value is blank. Under secrets.provider: external-secrets it comes from your store instead.

pgvector must be available. The first migration runs CREATE EXTENSION vector. Amazon RDS and Cloud SQL both offer it, but it is not enabled by default on either; check before you install.

The auth service never shares the application database. Its role owns the database and needs CREATEROLE: the install’s auth-prep-db job creates the auth service’s own roles in it.

Terminal window
trap 'stty echo' INT TERM EXIT; printf 'Password for mono_auth: '; stty -echo; IFS= read -r PW; stty echo; trap - INT TERM EXIT; printf '\n'
[ -n "$PW" ] && kubectl -n edisyl create secret generic mono-auth-db \
--from-literal="uri=postgresql://mono_auth:$(jq -rn --arg p "$PW" '$p|@uri')@db.example.com:5432/mono_auth?sslmode=require" \
|| echo 'mono-auth-db was not created.' >&2
unset PW

A different Secret name or key goes in edisyl.auth.database.secretName and secretKey. Setting edisyl.auth.database.create: true while cnpg.enabled is false fails the render: there is no bundled cluster to create it in.

The job runner keeps its run history in Postgres. With your own, set inngest.database.source: existing-secret and create Secret edisyl-inngest-db; the Inngest pod does not start until it exists.

inngest:
database:
source: existing-secret
Terminal window
trap 'stty echo' INT TERM EXIT; printf 'Password for inngest: '; stty -echo; IFS= read -r PW; stty echo; trap - INT TERM EXIT; printf '\n'
[ -n "$PW" ] && kubectl -n edisyl create secret generic edisyl-inngest-db \
--from-literal="uri=postgresql://inngest:$(jq -rn --arg p "$PW" '$p|@uri')@db.example.com:5432/inngest?sslmode=require" \
|| echo 'edisyl-inngest-db was not created.' >&2
unset PW

The name is fixed: the Inngest subchart’s environment is static values. To read another Secret, override inngest.inngest.extraEnv and keep an INNGEST_POSTGRES_URI entry; the render refuses a list without one. Keep it a secretKeyRef: the nightly pruning below reads the Secret it names. Helm replaces the list wholesale, so copy the chart’s other entries into yours too, EXPERIMENTAL_STEP_METADATA: "false" among them, or your override turns Inngest’s step metadata back on.

Since chart 0.63.0 a nightly CronJob deletes run history older than inngest.retention.days (seven by default) from this database, connecting with the same URI — see Inngest run history.

inngest.database.source: sqlite keeps the history on the pod’s scratch volume instead, and loses it on every restart. Use it for an evaluation only. Left unset, the source follows cnpg.enabled: the bundled cluster when it is on, SQLite when it is off.

The LLM gateway, when the chart runs it, owns and migrates its own schema in a database of its own. Its Secret holds discrete keys, not a URI, because Bifrost has no DSN input:

bifrost:
database:
source: existing-secret
existingSecret:
name: edisyl-bifrost-db
# The key names below are the defaults; change them only if your Secret
# uses different ones.
keys: { host: host, port: port, user: username, password: password, dbName: dbname }
sslMode: require
Terminal window
trap 'stty echo' INT TERM EXIT; printf 'Password for bifrost: '; stty -echo; IFS= read -r PW; stty echo; trap - INT TERM EXIT; printf '\n'
[ -n "$PW" ] && kubectl -n edisyl create secret generic edisyl-bifrost-db \
--from-literal="host=db.example.com" --from-literal="port=5432" \
--from-literal="username=bifrost" --from-literal="password=$PW" --from-literal="dbname=bifrost" \
|| echo 'edisyl-bifrost-db was not created.' >&2
unset PW

bifrost.database.source defaults to cnpg, so with cnpg.enabled: false a render that does not set it fails, for the same reason the auth database does. With an external gateway (bifrost.enabled: false) there is no Bifrost/LLM database.

redis:
enabled: false
config:
redisHost: redis.example.internal
redisPort: "6379"
redisUser: default
redisTls: "true" # optional
secrets:
managed:
edisyl-redis:
data:
REDIS_PASSWORD: "password"
edisyl-redis-inngest:
data:
INNGEST_REDIS_URI: "rediss://default:password@redis.example.internal:6379/2"

The host, port, user and TLS setting are configuration, under config.redis*; edisyl-redis holds the password and nothing else. With bundled Redis off, the render fails if any of config.redisHost, config.redisPort, config.redisUser or REDIS_PASSWORD is unset, and INNGEST_REDIS_URI too while the bundled job runner is on. A REDIS_URL, or a host, port, user or TLS key left in edisyl-redis, is refused.

The password is required. The chart never generates one for your Redis — it must be your server’s — and the API refuses to start on a blank one, so a passwordless Redis needs a password before you install.

ElastiCache and Memorystore both work, provided they offer RediSearch and RedisJSON. Use rediss:// and config.redisTls: "true" where the service requires TLS.

ElastiCache IAM authentication is not supported. The API reads a static REDIS_PASSWORD, and Inngest takes a static INNGEST_REDIS_URI; neither can mint the short-lived IAM tokens. Create an ElastiCache user with a password (RBAC user groups) and use it for both, or run the bundled Redis.

For a Redis behind Sentinel with no proxy in front — the configurator’s “Redis Sentinel” choice, with its “Sentinel addresses” and “Master name” — set the Sentinels and the master set name instead of a host and port. The API asks the Sentinels for the primary and follows it through a failover, giving them the same user, password and TLS setting as the data nodes:

redis:
enabled: false
config:
redisSentinels: "redis-sentinel-0.redis:26379,redis-sentinel-1.redis:26379"
redisSentinelMaster: mymaster
redisUser: default
secrets:
managed:
edisyl-redis:
data:
REDIS_PASSWORD: "password"
edisyl-redis-inngest:
data:
# One address that follows the primary — see below.
INNGEST_REDIS_URI: "redis://default:password@redis-primary.redis:6379"

Both Sentinel values or neither; the addresses are comma-separated host:port pairs. config.redisHost and config.redisPort are then optional and ignored. The rest of the constraints:

  • The job runner cannot authenticate to Sentinels. Inngest’s client dials the Sentinels with no password and no TLS, so its Sentinel form (redis://<user>:<password>@<sentinel-0>:26379?master_set=<set>&addr=<sentinel-1>:26379) works only with Sentinels that require neither. Otherwise point INNGEST_REDIS_URI at one address that follows the primary, such as an operator’s master Service; Inngest then reconnects after a failover rather than following it.
  • Bundled Redis has no Sentinel. It is one node, and the render refuses the Sentinel values with redis.enabled: true.
  • Announce hostnames. Have the Sentinels announce hostnames (resolve-hostnames yes, announce-hostnames yes), so a restarted pod’s new IP does not break the clients.
  • It needs current images. Sentinel mode needs API images that read REDIS_SENTINELS; an older API ignores it and needs config.redisHost.
minio:
enabled: false
config:
objectStorageProvider: s3
objectStorageBucket: my-edisyl-files
objectStorageRegion: us-east-1
objectStorageUrl: ""
objectStorageForcePathStyle: ""
secrets:
managed:
edisyl-object-storage:
data:
OBJECT_STORAGE_ACCESS_KEY_ID: ""
OBJECT_STORAGE_SECRET_ACCESS_KEY: ""

The provider, bucket, region and URL are configuration, under config.objectStorage*; edisyl-object-storage holds the two keys and nothing else. config.objectStorageProvider takes s3 or s3compatible, and the distinction is load-bearing:

  • s3 means real AWS S3. Leave objectStorageUrl and objectStorageForcePathStyle empty, set the region and bucket, and either supply the two keys or leave them blank and use a pod IAM role.
  • s3compatible is for MinIO you run yourself, Ceph, Cloudflare R2, or any store reached through an explicit endpoint. It needs objectStorageUrl and both keys. objectStorageForcePathStyle picks the addressing: "true" for path-style (endpoint/bucket/key), which MinIO and Ceph need and R2 and Wasabi accept, or "false" for virtual-hosted (bucket.endpoint/key), only when the store requires it and its DNS resolves every bucket name.

Choosing s3compatible while pointing at AWS — or s3 with a URL — is the silent misconfiguration to avoid: storage that looks wired up and writes nowhere. The chart refuses s3 with a URL and s3compatible without one.

Leave OBJECT_STORAGE_ACCESS_KEY_ID and OBJECT_STORAGE_SECRET_ACCESS_KEY blank to use a pod IAM role (IRSA on EKS, Workload Identity on GKE), which is the better option where your cluster supports it.

R2 is an s3compatible store reached through its S3 endpoint, with an R2 API token’s access key pair. The provider value r2 and the CLOUDFLARE_R2_* keys were removed in chart 0.42.0, and r2 is refused:

config:
objectStorageProvider: s3compatible
objectStorageBucket: my-edisyl-files
objectStorageRegion: auto
objectStorageUrl: https://<account-id>.r2.cloudflarestorage.com
secrets:
managed:
edisyl-object-storage:
data:
OBJECT_STORAGE_ACCESS_KEY_ID: "<r2 access key id>"
OBJECT_STORAGE_SECRET_ACCESS_KEY: "<r2 secret access key>"
inngest:
enabled: false
config:
inngestBaseUrl: "https://api.inngest.com"
secrets:
managed:
edisyl-inngest:
data:
INNGEST_EVENT_KEY: "<event key>"
INNGEST_SIGNING_KEY: "<signing key>"

With Inngest off there is no Inngest database to provide. Keep the bundled job runner and its run history lives in Postgres: see The Inngest database.

Everything external, nothing bundled:

cnpg: { enabled: false }
redis: { enabled: false }
minio: { enabled: false }
inngest: { enabled: false }
database:
source: existing-secret
existingSecret: { name: my-postgres-connection, key: uri }
config:
domain: example.com
inngestBaseUrl: "https://api.inngest.com"
emailFrom: platform@example.com
redisHost: redis.example.internal
redisPort: "6379"
redisUser: default
redisTls: "true"
objectStorageProvider: s3
objectStorageBucket: my-edisyl-files
objectStorageRegion: us-east-1
bootstrap:
adminEmails: ["admin@example.com"]
organization: { name: Example Corp, slug: example-corp }
deploymentIdp:
metadataUrl: "https://idp.example.com/app/saml/metadata"
domains: [example.com]
edisyl:
auth:
database: { secretName: my-auth-db-connection, secretKey: uri }
# The bundled gateway needs a database of its own. Inngest Cloud keeps its
# own history, so there is no Inngest database here.
bifrost:
database:
source: existing-secret
existingSecret: { name: edisyl-bifrost-db }
secrets:
provider: k8s-native
managed:
edisyl-redis:
data:
REDIS_PASSWORD: "password"
edisyl-inngest:
data:
INNGEST_EVENT_KEY: "<event key>"
INNGEST_SIGNING_KEY: "<signing key>"
# Pod IAM role for S3, so the two object-storage keys stay blank. The auth
# signing material comes from the minted file — see Secrets and signing
# keys.

That runs the first-party services against your own datastores: no bundled database, cache, object store or job runner, and no CloudNativePG operator — that is only needed when cnpg.enabled is true.

Two things still run in the cluster beyond the applications: the auth service and the LLM gateway, both deployments of this chart rather than bundled third-party charts, each against its own database on your Postgres: three databases in all, with the application’s. The pods also mount small volumes — emptyDir scratch space for the applications, and a volume for the gateway’s request logs — so “nothing bundled” means no bundled infrastructure, not no volumes at all.

Everything above puts credentials in a values file. For anything beyond a trial, use secrets.provider: external-secrets instead and let the chart read them from your secret manager — AWS Secrets Manager, Doppler, Vault or any other backend the External Secrets Operator supports. The chart then generates nothing, and every key must exist in the store up front. See Secrets and signing keys.

Report incorrect code

Please provide a detailed description of the incorrect code.