Skip to content

feat(ai-bot): make bot account email configurable via AI_BOT_EMAIL env var#10672

Open
dnplkndll wants to merge 1 commit intohcengineering:developfrom
ledoent:feat/configurable-aibot-email
Open

feat(ai-bot): make bot account email configurable via AI_BOT_EMAIL env var#10672
dnplkndll wants to merge 1 commit intohcengineering:developfrom
ledoent:feat/configurable-aibot-email

Conversation

@dnplkndll
Copy link
Copy Markdown
Contributor

@dnplkndll dnplkndll commented Mar 23, 2026

Summary

Makes the AI bot account email configurable via AI_BOT_EMAIL env var using the platform Metadata pattern (per @aonnikov's review feedback), instead of mutable module state.

Resolves hcengineering/huly-selfhost#239

Motivation

The bot email huly.ai.bot@hc.engineering is an @hc.engineering address embedded in every self-hosted deployment's account system. Self-hosters have no control over this domain, and it can cause bounce-back noise if an external SMTP notification service attempts to email all workspace members.

Design

Uses platform Metadata — the same pattern as FrontVersion, EndpointURL, and other startup config values:

// Plugin definition (plugins/ai-bot/src/index.ts)
const aiBot = plugin(aiBotId, {
  metadata: {
    EndpointURL: '' as Metadata<string>,
    BotEmail: '' as Metadata<string>        // ← new
  }
})

// Startup (transactor + ai-bot service)
setMetadata(aiBot.metadata.BotEmail, process.env.AI_BOT_EMAIL)

// Consumers read via getter with default fallback
export function getAiBotAccountEmail (): string {
  return getMetadata(aiBot.metadata.BotEmail) ?? aiBotAccountEmail
}
  • No mutable module state (set/get function pairs)
  • Original aiBotAccountEmail and aiBotEmailSocialKey constants kept for client-side / default use
  • Empty-string guard on env var reads

Env vars

Service Var Default Required
ai-bot AI_BOT_EMAIL huly.ai.bot@hc.engineering No
transactor AI_BOT_EMAIL huly.ai.bot@hc.engineering No

Both must use the same value if set.

Changes (11 files)

File Change
plugins/ai-bot/src/index.ts Add BotEmail metadata key, getAiBotAccountEmail(), getAiBotEmailSocialKey()
pods/server/src/__start.ts Set metadata from AI_BOT_EMAIL env var
services/ai-bot/pod-ai-bot/src/start.ts Set metadata from AI_BOT_EMAIL env var
services/ai-bot/pod-ai-bot/src/utils/account.ts Use getter functions
services/ai-bot/pod-ai-bot/src/utils/platform.ts Use getter functions
foundations/server/packages/middleware/src/identity.ts Import from @hcengineering/ai-bot (was duplicate hardcoded string)
foundations/server/packages/middleware/src/pluginConfig.ts Use getter function
server-plugins/ai-bot-resources/src/index.ts Use getter function
**/package.json + pnpm-lock.yaml Add @hcengineering/ai-bot dependency

Not changed: plugins/ai-bot-resources/src/utils.ts (client-side, correctly uses constant — metadata is not available client-side).

Known limitation

Client-side code (aiBotSocialIdentityStore in Love/video meetings) queries by the static default social key. If a custom email is configured server-side, the client query won't match. This is acceptable for the current server-side scope — full client support would require pushing the configured email through workspace config.

Testing

Deployed to self-hosted K8s cluster with AI_BOT_EMAIL=aibot@ledoweb.com:

  • ai-bot: 0 restarts, registers new social identity in CockroachDB
  • Original identity preserved (backwards compat)
  • DM with Huly AI works — bot receives and responds
  • Default behavior (no env var) unchanged

DM with bot (custom email configured)

DM with Huly AI

Bot responding in Chunter

Bot response

🤖 Generated with Claude Code

@huly-github-staging
Copy link
Copy Markdown

Connected to Huly®: UBERF-16033

@dnplkndll
Copy link
Copy Markdown
Contributor Author

Alternative approach: Since no actual email is ever sent to or from this address (it's purely an account identity key), a simpler fix would be to just change the hardcoded default from huly.ai.bot@hc.engineering to something domain-neutral like ai-bot@huly — no env var needed.

The reason I went with the configurable approach is backwards compatibility: existing deployments already have the bot registered with huly.ai.bot@hc.engineering in their social_id table. Changing the constant would require a migration to update the social identity, otherwise the bot would create a duplicate account on next startup.

If a migration is acceptable, the simpler rename would be a ~5-line change. Happy to pivot to that approach if preferred.

setMetadata(serverNotification.metadata.MailAuthToken, config.mailAuthToken)
setMetadata(serverNotification.metadata.WebPushUrl, config.webPushUrl)
setMetadata(serverAiBot.metadata.EndpointURL, process.env.AI_BOT_URL)
if (process.env.AI_BOT_EMAIL !== undefined) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It is idiomaic to use metadata for such kind of configuration, i.e. something like:

setMetadata(serverAiBot.metadata.Email, process.env.AI_BOT_EMAIL)

and in the ai-bot plugin:

export function getAiBotEmailSocialKey (): string {
  return buildSocialIdString({
    type: SocialIdType.EMAIL,
    value:getMetadata(...) ?? aiBotAccountEmail
  })
}

Copy link
Copy Markdown
Member

@aonnikov aonnikov Mar 24, 2026

Choose a reason for hiding this comment

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

Honestly, I don't think it has to be a email, ideally that should be a separate SocialIdType, but this is something that requires larger refactoring.

@dnplkndll dnplkndll force-pushed the feat/configurable-aibot-email branch from 3c815d7 to b41a804 Compare March 24, 2026 20:03
@ArtyomSavchenko
Copy link
Copy Markdown
Member

@dnplkndll Looks like the following commit should be in a separate PR: feat(mobile): add Flutter iOS app with OAuth fix and Huly UX redesign .

@dnplkndll dnplkndll force-pushed the feat/configurable-aibot-email branch 2 times, most recently from 802aaed to dc2dcbd Compare March 25, 2026 12:30
Comment thread screenshots/08-dm-with-bot.png Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you explain why these screenshots are needed in the code base?

Comment thread pods/server/src/__start.ts
…v var

The AI bot email was hardcoded to huly.ai.bot@hc.engineering, causing
self-hosted deployments to send notifications to an unreachable address.

Add AI_BOT_EMAIL env var to the ai-bot service and transactor:
- ai-bot service: reads AI_BOT_EMAIL, calls setAiBotAccountEmail() on
  startup, uses it for signUp/assignWorkspace/identity lookups
- transactor: reads AI_BOT_EMAIL, calls setAiBotAccountEmail() so
  middleware recognizes the bot as a service account
- server plugin triggers: use getAiBotEmailSocialKey() for DB queries
- middleware: import from @hcengineering/ai-bot instead of duplicating
  the hardcoded string
- client plugin unchanged: queries by the default constant, which still
  works because the bot retains its original social identity

Defaults to huly.ai.bot@hc.engineering when unset (no behavior change).

Tested on self-hosted K8s: bot registers new social identity, DMs work,
0 restarts on both services.

Resolves hcengineering/huly-selfhost#239

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
@dnplkndll dnplkndll force-pushed the feat/configurable-aibot-email branch from dc2dcbd to f24b6fe Compare April 18, 2026 12:51
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.

Allow aibot email to be changed

3 participants