Repository navigation
feat: self-hosted supabase data plane for enterprise edge (#231) - #240
Conversation
Add a fully self-hosted Supabase stack to the enterprise compose profile so the EnterpriseEdge box has zero external SaaS dependency. Tenant data, authentication tokens, and uploaded files never leave the customer machine. Services added (enterprise profile only): - supabase-db (pgvector/pgvector:pg16): Postgres 16 with the vector extension pre-installed. Required by RAG (#232). - supabase-auth (supabase/gotrue:v2.170.0): local JWT issuer. edge-api JWKS validation points at this service via SUPABASE_JWKS_URL. - supabase-rest (postgrest/postgrest:v12.2.3): auto REST API over the local Postgres, used by control-plane as SUPABASE_URL. - supabase-storage (supabase/storage-api:v1.11.13): S3-compatible object storage with a local filesystem backend (no MinIO, AGPL avoided). Replaces the hosted Supabase Storage S3 endpoint for the enterprise path. - supabase-init: one-shot curl container that creates the hive-files and hive-images buckets via the Storage API on first compose up. Other changes: - deploy/supabase/init/00-extensions.sql: Postgres init script that enables uuid-ossp, pgcrypto, and vector extensions and creates the auth, storage, graphql_public, and extensions schemas plus the anon, authenticated, service_role, and supabase_admin roles on first boot. - supabase/migrations/20260625_01_enable_pgvector.sql: idempotent CREATE EXTENSION IF NOT EXISTS vector migration. Safe to run on both the self-hosted and hosted Supabase instances. - .env.example: ENTERPRISE_* variable block with generation instructions and commented rewire block for SUPABASE_URL, SUPABASE_DB_URL, SUPABASE_JWKS_URL, S3_ENDPOINT, and related vars. - edge-api and control-plane services gain required:false depends_on entries for supabase-auth, supabase-storage, and supabase-db so the enterprise profile waits for local services before starting application containers. Profiles local, cloud, and chat are not changed and continue to use the hosted Supabase configuration as before. Closes #231
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 34282787 | Triggered | Generic Password | 46aaf7f | deploy/docker/docker-compose.yml | View secret |
| 34282788 | Triggered | Generic Password | 46aaf7f | .env.example | View secret |
| 34282788 | Triggered | Generic Password | 46aaf7f | deploy/docker/docker-compose.yml | View secret |
| 34282789 | Triggered | Generic Password | 46aaf7f | deploy/docker/docker-compose.yml | View secret |
| 34282788 | Triggered | Generic Password | 46aaf7f | deploy/docker/docker-compose.yml | View secret |
| 34282789 | Triggered | Generic Password | 46aaf7f | deploy/docker/docker-compose.yml | View secret |
| 34282880 | Triggered | Generic Password | d67aa62 | deploy/docker/docker-compose.enterprise.yml | View secret |
| 34282880 | Triggered | Generic Password | d67aa62 | deploy/docker/docker-compose.enterprise.yml | View secret |
| 34282880 | Triggered | Generic Password | d67aa62 | deploy/docker/docker-compose.enterprise.yml | View secret |
| 34282880 | Triggered | Generic Password | d67aa62 | deploy/docker/docker-compose.enterprise.yml | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
Warning Review limit reached
More reviews will be available in 42 minutes and 14 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR adds a local enterprise Supabase stack, updates startup instructions to use both compose files, bootstraps required Postgres objects, and enables the ChangesEnterprise self-hosted Supabase stack
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
B1 (missing hive_app role): add hive_app NOLOGIN role to the DO block in
deploy/supabase/init/00-extensions.sql. RLS policies in migration
20260529_01_rls_tenant_tables.sql grant full access to this role; without
it the control-plane connection would fail all policy checks on first boot.
Also grant hive_app USAGE on public and storage schemas.
B2 (empty JWT secret auth bypass): all ENTERPRISE_JWT_SECRET,
ENTERPRISE_DB_PASSWORD, ENTERPRISE_ANON_KEY, and ENTERPRISE_SERVICE_ROLE_KEY
vars now use :? guards so a missing value refuses startup with a clear message.
Docker Compose constraint fix: :? guards in enterprise-only services cause
config validation errors for --profile local and --profile cloud because
Compose interpolates all service envs regardless of active profile. Resolved
by extracting the five Supabase services into a dedicated override file
deploy/docker/docker-compose.enterprise.yml that is only parsed when
explicitly included. The base docker-compose.yml retains the comment block
explaining the two-file usage pattern. local and cloud profiles now validate
cleanly without any ENTERPRISE_* vars set.
Verification:
docker compose --profile local config: OK (no enterprise vars)
docker compose --profile cloud config: OK (no enterprise vars)
docker compose -f docker-compose.yml -f docker-compose.enterprise.yml
--profile enterprise config (with vars): OK
Same without vars: errors on ENTERPRISE_DB_PASSWORD as required
B3: scripts/install.sh used plain --profile enterprise on four invocations
(up, down, monitoring tip, logs tip). The self-hosted Supabase services live
in docker-compose.enterprise.yml which was never included, so supabase-db,
supabase-auth, supabase-rest, supabase-storage, and supabase-init never
started on an enterprise box, leaving the data plane silently absent.
All four install.sh invocations now pass both -f flags with absolute paths:
-f "$HIVE_HOME/deploy/docker/docker-compose.yml"
-f "$HIVE_HOME/deploy/docker/docker-compose.enterprise.yml"
CLAUDE.md Getting Started enterprise example updated to match.
GitGuardian false positive: the JWT payload JSON fragment in the
.env.example comment block (role/iss/iat keys) was triggering the scanner.
Replaced with a reference to the Supabase self-host key generator URL.
Classification: false positive, no real secret was committed, no rotation
needed.
Verified:
docker compose -f docker-compose.yml -f docker-compose.enterprise.yml
--profile enterprise config (with vars): OK
docker compose --profile local config: OK
docker compose --profile cloud config: OK
Bug 1: entrypoint used \${SERVICE_KEY} which Compose interpolates at parse
time from the host env (empty string). Changed to \$\${SERVICE_KEY} so the
container shell expands it at runtime from the injected environment.
Bug 2: curl -sf ... || true swallowed 401/500/network errors, making a
broken Storage API look healthy. Replaced with explicit HTTP status capture;
2xx and 409 (already exists) succeed, any other status exits 1 so the init
container fails visibly instead of silently.
Bug 3: edge-api and control-plane could start before supabase-init finished
creating buckets, causing startup S3 checks to fail. Added
supabase-init: { condition: service_completed_successfully } to the
depends_on of both services in the override file only, so --profile local
and --profile cloud are unaffected.
Bug 4: GOTRUE_JWT_ISSUER defaulted to http://localhost:9999. edge-api
validates the iss claim against SUPABASE_JWT_ISSUER (http://supabase-auth:9999
on the enterprise profile), so every minted JWT failed the issuer check.
Changed default to http://supabase-auth:9999 to match.
Verified: enterprise/local/cloud compose config all exit 0.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d67aa62a27
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- SUPABASE_URL comment corrected to point at GoTrue (supabase-auth:9999) not PostgREST; control-plane calls GET /auth/v1/user on this URL and PostgREST cannot serve auth/v1 routes. - SUPABASE_JWKS_URL comment documents the HTTPS enforcement in edge-api/cmd/server/main.go and explains the TLS proxy requirement for production; LAN/dev workaround noted inline. - S3_ENDPOINT path corrected from /object/s3 to /storage/v1/s3 to match the actual Supabase Storage S3-compatible endpoint path (confirmed from .env.example line 150 for hosted Supabase). - API_EXTERNAL_URL added to supabase-auth: GoTrue v2 requires this var at startup for email link generation; missing it causes GoTrue to refuse to start. - GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED + URI added to supabase-auth: without this flag GoTrue issues plain tokens with no tenant_id/role claims; every RLS policy and auth middleware check would fail. - PostgREST healthcheck changed from wget (absent from the minimal image) to a bash /dev/tcp TCP probe which works with only the shell available. Compose config: enterprise/local/cloud all exit 0.
…I fix) docker-compose.yml had required:false depends_on entries for supabase-auth, supabase-storage, and supabase-db. Docker Compose validates all depends_on references at parse time regardless of the required flag — if the named service does not exist in any loaded file the project fails with 'depends on undefined service'. The local+tools profile only loads docker-compose.yml so those enterprise-only services are undefined, breaking the gen-permissions codegen step and cascading to web-console type+unit+build failure. Fix: remove the three stubs. The enterprise ordering is fully handled inside docker-compose.enterprise.yml (supabase-init depends_on chain covers db, auth, rest, storage, init in order; edge-api and control-plane depend on supabase-init via the override).
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
.env.example (1)
253-253: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueQuote placeholder values to prevent dotenv parsing errors.
The placeholder values at these lines contain spaces and special characters (
<generate: openssl rand -base64 24>,<sign anon JWT with ENTERPRISE_JWT_SECRET>). While Docker Compose's env parser is lenient, standard dotenv tools and editors may truncate at the first space or flag syntax errors. Wrapping them in double quotes ensures they are treated as single values.-ENTERPRISE_DB_PASSWORD=<generate: openssl rand -base64 24> +ENTERPRISE_DB_PASSWORD="<generate: openssl rand -base64 24>" -ENTERPRISE_JWT_SECRET=<generate: openssl rand -base64 48> +ENTERPRISE_JWT_SECRET="<generate: openssl rand -base64 48>" -ENTERPRISE_ANON_KEY=<sign anon JWT with ENTERPRISE_JWT_SECRET> +ENTERPRISE_ANON_KEY="<sign anon JWT with ENTERPRISE_JWT_SECRET>" -ENTERPRISE_SERVICE_ROLE_KEY=<sign service_role JWT with ENTERPRISE_JWT_SECRET> +ENTERPRISE_SERVICE_ROLE_KEY="<sign service_role JWT with ENTERPRISE_JWT_SECRET>"Also applies to: 260-260, 265-266
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.env.example at line 253, The placeholder values in the env template are unquoted, which can break dotenv parsing when they contain spaces or special characters. Update the affected entries in the .env.example placeholders so they are wrapped in double quotes, including the ENTERPRISE_DB_PASSWORD and the JWT signing placeholders near the ENTERPRISE_JWT_SECRET-related values. Keep the changes localized to the placeholder lines so tools like dotenv, editors, and parsers treat each placeholder as a single value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.env.example:
- Around line 287-322: The S3 endpoint documentation is inconsistent between the
enterprise env example and the docker compose comment. Update the misleading
`/object/s3` reference in docker-compose.yml to match the correct Supabase
Storage S3 path `/storage/v1/s3`, and keep the wording aligned with the existing
`S3_ENDPOINT` guidance in `.env.example` so operators see the same endpoint in
both places.
In `@deploy/docker/docker-compose.enterprise.yml`:
- Around line 42-43: The GitGuardian failure is caused by the long operator
guidance embedded in the required env interpolation strings for the enterprise
compose file. Update the affected placeholders on the secret-bearing settings in
this docker-compose configuration to use neutral required markers like the
POSTGRES_PASSWORD entry, and move the explanatory setup text into comments or
the .env.example file instead. Apply the same cleanup to the other referenced
env blocks in this file so the runtime behavior stays the same while the scan no
longer flags the guidance strings.
In `@deploy/docker/docker-compose.yml`:
- Around line 175-194: The comments for SUPABASE_URL and S3_ENDPOINT in the
compose config are inconsistent with the documented enterprise endpoints. Update
the SUPABASE_URL guidance in the docker-compose enterprise environment block to
point to the GoTrue/auth service used by control-plane calls, and correct the
S3_ENDPOINT example to the Supabase Storage S3-compatible path. Use the existing
SUPABASE_URL, S3_ENDPOINT, and enterprise profile comment blocks to locate and
align the wording with .env.example.
In `@deploy/supabase/init/00-extensions.sql`:
- Around line 39-44: The bootstrap for hive_app creates a NOLOGIN role, but the
control-plane/edge-api connection contract expects this to be the actual
application DB role. Update the role setup in 00-extensions.sql so hive_app can
authenticate as intended, or change the downstream usage in the RLS migration
and related connection config to a separate login role consistently. Refer to
the hive_app role creation block and the RLS policy assumptions in the
tenant-tables migration when making the change.
---
Nitpick comments:
In @.env.example:
- Line 253: The placeholder values in the env template are unquoted, which can
break dotenv parsing when they contain spaces or special characters. Update the
affected entries in the .env.example placeholders so they are wrapped in double
quotes, including the ENTERPRISE_DB_PASSWORD and the JWT signing placeholders
near the ENTERPRISE_JWT_SECRET-related values. Keep the changes localized to the
placeholder lines so tools like dotenv, editors, and parsers treat each
placeholder as a single value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ade26b93-d469-44f0-b11b-b8891ed4ffbf
📒 Files selected for processing (7)
.env.exampleCLAUDE.mddeploy/docker/docker-compose.enterprise.ymldeploy/docker/docker-compose.ymldeploy/supabase/init/00-extensions.sqlscripts/install.shsupabase/migrations/20260625_01_enable_pgvector.sql
SUPABASE_URL comment: corrected from supabase-rest:3000 to supabase-auth:9999. S3_ENDPOINT comment: corrected path from /object/s3 to /storage/v1/s3. Both now match .env.example and docker-compose.enterprise.yml.
Summary
Closes #231. Ships a fully self-hosted Supabase stack inside the enterprise compose profile so the EnterpriseEdge box has zero external SaaS dependency. This is the blocking foundation that unblocks RAG (#232).
pgvector/pgvector:pg16): Postgres 16 with the vector extension pre-installed.CREATE EXTENSION IF NOT EXISTS vectormigration added so RAG (Carl.sh B: RAG — pgvector schema, local bge-m3 embeddings, /v1/rag/* endpoints #232) can run locally.supabase/gotrue:v2.170.0): local JWT issuer.SUPABASE_JWKS_URLandSUPABASE_JWT_ISSUERpoint at this service on the enterprise profile;apps/edge-api/internal/auth/jwt_supabase.govalidates JWTs against the local issuer without code changes.postgrest/postgrest:v12.2.3): auto REST API over local Postgres, used asSUPABASE_URLby control-plane.supabase/storage-api:v1.11.13): S3-compatible object storage with a local filesystem backend. No MinIO (AGPL avoided per repo policy).hive-filesandhive-imagesbuckets are created by a one-shotsupabase-initcontainer on firstcompose up.deploy/supabase/init/00-extensions.sql: Postgres init script enablinguuid-ossp,pgcrypto,vector; creatingauth,storage,graphql_public,extensionsschemas; and creating theanon,authenticated,service_role,supabase_adminroles required by GoTrue and PostgREST.supabase/migrations/20260625_01_enable_pgvector.sql: idempotentCREATE EXTENSION IF NOT EXISTS vector. Safe on both self-hosted and hosted Supabase..env.example:ENTERPRISE_*variable block with generation instructions and a commented rewire block forSUPABASE_URL,SUPABASE_DB_URL,SUPABASE_JWKS_URL,S3_ENDPOINT, and related vars.edge-apiandcontrol-planegainrequired: falsedepends_onentries for the new services so enterprise profile waits for local services before starting application containers.The
local,cloud, andchatprofiles are unchanged and continue to use hosted Supabase.Verification
docker compose --profile enterprise configexits 0 (YAML valid, no interpolation errors).docker compose --profile local configexits 0 (existing profile unaffected).docker compose --profile cloud configexits 0 (existing profile unaffected).:?replaced with:-) because Docker Compose evaluates all service envs regardless of active profile; empty-value failure is enforced at runtime by Postgres refusing to start with a blank password.SELECT extname FROM pg_extension WHERE extname='vector') was not run in this session due to image pull time and cost constraints. Thepgvector/pgvector:pg16image ships the extension pre-installed per the upstream README; the init SQL and migration are both idempotent.Test plan
docker compose --profile enterprise configand confirm exit 0.ENTERPRISE_DB_PASSWORD,ENTERPRISE_JWT_SECRET,ENTERPRISE_ANON_KEY,ENTERPRISE_SERVICE_ROLE_KEYand bring up the enterprise profile.supabase-dbhealthcheck passes andSELECT extname FROM pg_extension WHERE extname='vector'returns a row.supabase-authhealth endpoint responds athttp://localhost:9999/health.supabase-initexits 0 and bothhive-filesandhive-imagesbuckets exist.supabase/migrations/20260625_01_enable_pgvector.sqlagainst the local Postgres and confirm idempotency on re-run.localandcloudprofiles still start correctly with hosted Supabase credentials.Summary by CodeRabbit
New Features
Documentation
Greptile Summary
This PR ships a fully self-hosted Supabase data plane (Postgres/pgvector, GoTrue, PostgREST, Supabase Storage) inside a new
docker-compose.enterprise.ymloverride file, enabling the EnterpriseEdge profile to run without any external SaaS dependency and unblocking RAG (#232).supabase-db(pgvector:pg16),supabase-auth(GoTrue v2.170.0),supabase-rest(PostgREST v12.2.3),supabase-storage(v1.11.13), and a one-shotsupabase-initcontainer that creates thehive-files/hive-imagesbuckets via the Storage API.:?interpolation errors for operators running thelocal/cloudprofiles withoutENTERPRISE_*vars set;install.sh,CLAUDE.md, and operator docs are all updated to pass both-fflags.00-extensions.sqlbootstraps extensions, schemas, and roles on first Postgres start;20260625_01_enable_pgvector.sqladds the idempotent pgvector migration for both self-hosted and hosted Supabase.Confidence Score: 3/5
The core compose orchestration is sound, but two concrete runtime failures exist: Open WebUI OIDC login is broken for the enterprise profile, and the S3 endpoint path documented in the compose file comment contradicts the correct path in .env.example.
The OIDC discovery URL for Open WebUI is constructed by appending /auth/v1/.well-known/openid-configuration to SUPABASE_URL. For cloud deployments this is correct (Kong gateway routing), but for the enterprise profile SUPABASE_URL points directly at GoTrue which does not expose the /auth/v1/ prefix — every user login via Open WebUI returns an OIDC discovery error. Separately, the comment inside docker-compose.enterprise.yml documents the S3 endpoint as /object/s3 while the correct Supabase Storage S3-compatible path is /storage/v1/s3; an operator following only the compose file comment would configure a non-functional storage endpoint.
deploy/docker/docker-compose.yml (OPENID_PROVIDER_URL construction) and deploy/docker/docker-compose.enterprise.yml (S3 endpoint path comment).
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Op as Operator participant DB as supabase-db (pgvector:pg16) participant Auth as supabase-auth (GoTrue) participant Rest as supabase-rest (PostgREST) participant Stor as supabase-storage participant Init as supabase-init (one-shot) participant EA as edge-api participant CP as control-plane Op->>DB: compose up --profile enterprise DB-->>DB: run 00-extensions.sql (schemas, roles, vector) DB-->>Auth: service_healthy DB-->>Rest: service_healthy Auth-->>Auth: GoTrue internal DB migrations Rest-->>Stor: service_healthy DB-->>Stor: service_healthy Stor-->>Init: service_healthy Init->>Stor: POST /bucket hive-files (service_role JWT) Init->>Stor: POST /bucket hive-images (service_role JWT) Init-->>EA: service_completed_successfully Init-->>CP: service_completed_successfully EA-->>EA: start CP-->>CP: start%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Op as Operator participant DB as supabase-db (pgvector:pg16) participant Auth as supabase-auth (GoTrue) participant Rest as supabase-rest (PostgREST) participant Stor as supabase-storage participant Init as supabase-init (one-shot) participant EA as edge-api participant CP as control-plane Op->>DB: compose up --profile enterprise DB-->>DB: run 00-extensions.sql (schemas, roles, vector) DB-->>Auth: service_healthy DB-->>Rest: service_healthy Auth-->>Auth: GoTrue internal DB migrations Rest-->>Stor: service_healthy DB-->>Stor: service_healthy Stor-->>Init: service_healthy Init->>Stor: POST /bucket hive-files (service_role JWT) Init->>Stor: POST /bucket hive-images (service_role JWT) Init-->>EA: service_completed_successfully Init-->>CP: service_completed_successfully EA-->>EA: start CP-->>CP: startReviews (5): Last reviewed commit: "docs: fix two comment inconsistencies in..." | Re-trigger Greptile