Skip to content

[feat][RCP] Helm chart changes for RetoolOS - #385

Merged
njdelima merged 6 commits into
mainfrom
njdelima/retoolos-worker-slack-helm
Sep 30, 2026
Merged

njdelima merged 6 commits into
mainfrom
njdelima/retoolos-worker-slack-helm

Conversation

@njdelima

@njdelima njdelima commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Description

Makes RetoolOS an opt-in, single-toggle feature for self-hosted deployments:

retoolos:
  enabled: true

Enabling it creates one new backend-image worker (retoolos_temporal_worker). It's a monolithic worker that handles everything 'asynchronous' - i.e. everything that does not happen live in the context of a backend endpoint:

  • running the agent loop
  • triggering scheduled Jobs
  • ingress from/egress to Slack and GChat
  • background search embedding and indexing

The core idea is that if the deployment that already has R² configured, then there are no new infra changes needed:

  • All you have to do is enable via retoolos.enabled: true
  • And ensure that the Postgres server in use has pgvector available for install. If using managed Postgres in any of the 3 cloud providers (AWS/GCS/Azure), this should already be true

Blob storage

RetoolOS reuses the existing rr.blobStorage configuration. The chart supplies the same RR_BLOB_STORAGE_PROVIDER and RR_DEFAULT_<PROVIDER>_* values to the backend and RetoolOS worker, even when Git Server itself is disabled.

RetoolOS stores its objects under the retoolos/ prefix, so they can safely share the R² bucket or container.

The application still supports explicit RETOOLOS_<PROVIDER>_* configuration for deployments that want a separate store. Those values take precedence over the RR defaults.

Slack

Self-hosted deployments default to Socket Mode, which uses an outbound connection and does not require public Slack event or interaction endpoints.

Customers can configure the Slack app through one of three paths:

  1. Configure it in Retool Settings → RetoolOS → Messaging. The credentials are stored encrypted in Postgres.
  2. Provide RETOOLOS_SLACK_* through the chart’s generic environment variables
  3. Set retoolos.slack.secretName to an existing Kubernetes Secret containing:
    • client-id
    • client-secret
    • signing-secret
    • app-token when using Socket Mode

The Kubernetes Secret and explicit environment-variable paths (2 and 3) cannot be combined because they both describe the same deployment-managed Slack app.

For a customer that wants HTTP ingress instead of Socket mode, that can be configured via:

retoolos:
  enabled: true
  slack:
    mode: http

Search

Search is enabled automatically on the backend, Jobs Runner, and RetoolOS worker when RetoolOS is enabled.

Operators can disable search without disabling the rest of RetoolOS:

retoolos:
  enabled: true

env:
  RETOOLOS_SEARCH_ENABLED: false

The Postgres server must have pgvector 0.7 or newer available, and the migration user must be able to create or update the vector extension.


retoolos_self_hosted_no_rr.md: preserving an old version of this PR description, as it might contain useful info for customers that do not have R² configured.

Test Plan

In a file somewhere, e.g. ./values.njdelima-retoolos.local.yaml:

retoolos:
  enabled: true

postgresql:
  image:
    repository: pgvector/pgvector
    tag: 0.8.6-pg15-bookworm

config:
  licenseKeySecretName: njdelima-retoolos-license
  licenseKeySecretKey: licenseKey

image:
  repository: 753800337063.dkr.ecr.us-west-2.amazonaws.com/onprem
  tag: pr-4.67.0-ceb4fa1

codeExecutor:
  image:
    repository: 753800337063.dkr.ecr.us-west-2.amazonaws.com/code-executor-service
    tag: pr-4.67.0-ceb4fa1

rr:
  jsExecutor:
    enabled: true
    image:
      repository: 753800337063.dkr.ecr.us-west-2.amazonaws.com/js-executor-service
      tag: pr-4.67.0-ceb4fa1
  blobStorage:
    s3:
      bucket: retool-rr-app-git-storage-internal-tools
      region: us-west-2
      secretAccessKeySecretName: rr-git-storage-s3-secret
      secretAccessKeySecretKey: secret-access-key

Then, I re-used my existing njdelima balloon instance, using the local chart defined here in my branch, and the values override above:

# from the retool-helm repo root, on this branch
helm upgrade --install njdelima ./charts/retool --namespace default \
# this is just the usual balloon instance startup values for `njdelima` balloon instance
   -f /Users/njdelima/retool/retool-k8s/helm/internal-tools/internal-onprem/onprem-instances/values.base.yaml \
   -f /Users/njdelima/retool/retool-k8s/helm/internal-tools/internal-onprem/onprem-instances/values.njdelima.retool.dev.yaml \
# This is the override yaml from above
   -f ./values.njdelima-retoolos.local.yaml \
   --wait --timeout 30m

I think an actual customer might do something close to this:

   helm dependency update ./charts/retool
   helm upgrade --install <release> ./charts/retool -n <namespace> \
     -f <base-values.yaml> -f <retoolos-values.yaml> --wait --timeout 30m

Install and verify Slack. After the above, I was able to visit my balloon instance https://njdelima.retool.dev/ and verify RetoolOS works, I can chat with the agent etc. In Retool Settings → RetoolOS → Configure → Messaging, select Add to Slack and finish OAuth as an administrator. DM the bot from a Slack user whose email matches an enabled Retool user and confirm a reply.

@greptile-apps

greptile-apps Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[High risk] Adds RetoolOS worker deployment to Helm chart infrastructure.

The PR appears safe to merge based on this review.

Reviews (3) · Last reviewed commit: "Remove RetoolOS Slack setup guide from c..."

Comment thread charts/retool/templates/_helpers.tpl
Comment thread charts/retool/values.yaml
@njdelima

Copy link
Copy Markdown
Contributor Author

@greptile

@njdelima
njdelima marked this pull request as ready for review September 25, 2026 05:24
@njdelima

njdelima commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor Author

Feedback:

1
Try to re-use the bucket that R2 already requires vs making customers create a new bucket for retoolos
DONE

We already prefix with retoolos/.... so should be possible
backend/src/server/modules/blobStorage/blobStoreFactory.ts
Can chat with ibork/erin who have context
ENV VARS
plan: keep the RETOOLOS_S3_... around so customers can set them if they want, but IF THEY DONT we should fall back (in retool development) to the RR_DEFAULT_ ones.

2 "Configure Slack"
DONE

The env vars approach makes sense for cloud, but too much pain for on-prem. We basically need these fields

CLIENT_ID
CLIENT_SECRET
SIGNING_SECRET
(optional) websocket app token

So can keep the env var path but additionally allow customers to type these into a text box in app and we store it encrypted in postgres.

3
RETOOLOS_SEARCH_ENABLED is good as a kill switch but maybe default it to on so it "just works" out of the box
DONE

retoolos:
  enabled: true <-- also creates RETOOLOS_SEARCH_ENABLED: true on backend & jobs-runner containers

env:
  RETOOLOS_SEARCH_ENABLED: false <-- default true so can be left absent, but can be set to false as kill switch

4
After merging this, someone (ask ra or infra) to run the script to publish the new version of the helm chart

@njdelima njdelima changed the title [feat][RCP] Add RetoolOS worker and Slack setup to Helm [feat][RCP] Helm chart changes for RetoolOS Sep 28, 2026
…ker-slack-helm

# Conflicts:
#	charts/retool/Chart.yaml
Comment thread values.yaml
secretName: ""

# RetoolOS worker configuration
config: {}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is very ambiguous. what would even go here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a specific bag of 3 possible values that the generic worker template recognizes. I've updated with a commented out example.

Comment thread values.yaml Outdated
Comment on lines +1613 to +1617
# Labels for RetoolOS worker pods
labels: {}

# Annotations for RetoolOS worker pods
annotations: {}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a bit awkward for labels and annotations to exist under retoolos. but other pod-specific settings to live under retoolos.worker.. I'd vote to move both of these under retoolos.worker.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, and have updated it the way you describe.

I had originally done it this way because the shared worker template (used by a few workers like agents/agentEvals/r2/workflows etc) reads labels and annotations from the parent block, so this was the only way to do it without special casing retoolos.

Had to change the template to now continue reading parent metadata (for backwards compatibility) but additionally now merge in metadata from the worker block with the worker block winning on conflicting keys.

Comment thread values.yaml Outdated
Comment on lines +1621 to +1623
# socket uses an outbound Socket Mode connection and works without public
# ingress. Set http to receive Slack webhooks instead.
mode: socket

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be worth suggesting what kind of scenario a customer might choose webhooks over socket, if you have some idea.

Comment thread charts/retool/Chart.yaml
description: A Helm chart for Kubernetes
type: application
version: 6.11.34
version: 6.12.0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +280 to +281
{{- else if eq (include "retool.retoolos.enabled" .) "1" }}
{{- include "retool.blobStorage.envVars" . | nindent 10 }}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uhhh this branch looks like a fallthrough from the if eq (include "retool.gitServer.enabled" .) "1" conditional above? should probably make this its own thing, assuming not intentional.

actually, re-reading the helpers changes, I'm guessing this is a result of refactoring retool.gitServer.commonEnv to also embed retool.blobStorage.envVars, so now here if git is disabled but retoolos is enabled, we need to still include blob store env. I guess this is a smaller change from what was already here, but now that these are diverging I'd vote for actually totally isolating retool.gitServer.commonEnv from retool.blobStorage.envVars. I think the logic at call sites like here will be more intuitive that way for the future.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I believe I've implemented it now the way you describe and it does seem cleaner and more intuitive.

@ryanartecona ryanartecona left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great! just a couple comments on helper organization but this looks ready to ship to me

Comment on lines +558 to +568
{{/*
Set RetoolOS worker enabled
Usage: (include "retool.retoolos.enabled" .)
*/}}
{{- define "retool.retoolos.enabled" -}}
{{- $output := "" -}}
{{- if (eq (toString .Values.retoolos.enabled) "true") -}}
{{- $output = "1" -}}
{{- end -}}
{{- $output -}}
{{- end -}}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not hurting much, but unless we anticipate this conditional becoming more elaborate to check, this helper isn't simplifying anything as is. all it's doing is changing a call site likeif .Values.retoolos.enabled ...to instead be if (eq (include "retool.retoolos.enabled" .) "1") ... which IMO is slightly harder to read and more characters.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but I think we have to keep this helper.

The chart has a shared generic loop that renders all the workers (workflows, agents, ..., now retoolos). It makes you describe your worker like so:

  - parent: workflows
    type: workflow
  - parent: agents
    type: agent
  - parent: retoolos
    type: retoolos

and then dynamically constructs the helper it invokes:

  parent = "retoolos"
  helper name = "retool." + parent + ".enabled"
              = "retool.retoolos.enabled"

Again to avoid special casing retoolOS i'd rather just keep this

Comment on lines +343 to +351
Return "1" when a top-level env setting already owns a variable.

Chart-derived defaults use this helper to avoid emitting a duplicate EnvVar.
For example, `env.RETOOLOS_SEARCH_ENABLED: false` must override the chart's
RetoolOS default. Values supplied through envFrom cannot be inspected while the
chart renders; use env, environmentVariables, or environmentSecrets to override
a chart-derived default.

Usage: include "retool.envVarIsExplicit" (dict "root" . "name" "MY_VAR")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmm this is clever, I like this abstraction

@njdelima
njdelima merged commit ae70b82 into main Sep 30, 2026
13 checks passed
@njdelima
njdelima deleted the njdelima/retoolos-worker-slack-helm branch September 30, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants