@hailer/mcp 1.2.1 → 1.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/agent-hailer-helper.md +118 -0
- package/.claude/commands/debug-squad.md +13 -290
- package/.claude/commands/publish.md +2 -2
- package/.claude/commands/review-squad.md +17 -139
- package/.claude/skills/create-and-publish-app/SKILL.md +133 -143
- package/.claude/skills/hailer-app-builder/SKILL.md +29 -2
- package/.claude/skills/hailer-ui-guide/SKILL.md +265 -0
- package/.env.example +50 -1
- package/CLAUDE.md +141 -10
- package/dist/app-prep.d.ts +27 -0
- package/dist/app-prep.d.ts.map +1 -0
- package/dist/app-prep.js +94 -0
- package/dist/app-prep.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +3 -0
- package/dist/app.js.map +1 -1
- package/dist/bot/bot-manager.d.ts +9 -6
- package/dist/bot/bot-manager.d.ts.map +1 -1
- package/dist/bot/bot-manager.js +142 -31
- package/dist/bot/bot-manager.js.map +1 -1
- package/dist/bot/bot.d.ts +61 -16
- package/dist/bot/bot.d.ts.map +1 -1
- package/dist/bot/bot.js +927 -151
- package/dist/bot/bot.js.map +1 -1
- package/dist/bot/operation-logger.d.ts.map +1 -1
- package/dist/bot/operation-logger.js +24 -12
- package/dist/bot/operation-logger.js.map +1 -1
- package/dist/bot/services/bot-permissions.d.ts +37 -5
- package/dist/bot/services/bot-permissions.d.ts.map +1 -1
- package/dist/bot/services/bot-permissions.js +159 -35
- package/dist/bot/services/bot-permissions.js.map +1 -1
- package/dist/bot/services/conversation-manager.d.ts +23 -23
- package/dist/bot/services/conversation-manager.d.ts.map +1 -1
- package/dist/bot/services/conversation-manager.js +52 -49
- package/dist/bot/services/conversation-manager.js.map +1 -1
- package/dist/bot/services/helper-prompt.d.ts +8 -0
- package/dist/bot/services/helper-prompt.d.ts.map +1 -0
- package/dist/bot/services/helper-prompt.js +177 -0
- package/dist/bot/services/helper-prompt.js.map +1 -0
- package/dist/bot/services/message-classifier.d.ts +16 -16
- package/dist/bot/services/message-classifier.d.ts.map +1 -1
- package/dist/bot/services/message-classifier.js +55 -49
- package/dist/bot/services/message-classifier.js.map +1 -1
- package/dist/bot/services/message-formatter.d.ts +47 -38
- package/dist/bot/services/message-formatter.d.ts.map +1 -1
- package/dist/bot/services/message-formatter.js +99 -80
- package/dist/bot/services/message-formatter.js.map +1 -1
- package/dist/bot/services/permission-guard.d.ts.map +1 -1
- package/dist/bot/services/permission-guard.js +20 -10
- package/dist/bot/services/permission-guard.js.map +1 -1
- package/dist/bot/services/signal-router.d.ts.map +1 -1
- package/dist/bot/services/signal-router.js +11 -6
- package/dist/bot/services/signal-router.js.map +1 -1
- package/dist/bot/services/system-prompt.d.ts +14 -0
- package/dist/bot/services/system-prompt.d.ts.map +1 -1
- package/dist/bot/services/system-prompt.js +181 -4
- package/dist/bot/services/system-prompt.js.map +1 -1
- package/dist/bot/services/token-billing.d.ts +23 -23
- package/dist/bot/services/token-billing.d.ts.map +1 -1
- package/dist/bot/services/token-billing.js +51 -36
- package/dist/bot/services/token-billing.js.map +1 -1
- package/dist/bot/services/types.d.ts +3 -1
- package/dist/bot/services/types.d.ts.map +1 -1
- package/dist/bot/services/typing-indicator.d.ts +8 -8
- package/dist/bot/services/typing-indicator.d.ts.map +1 -1
- package/dist/bot/services/typing-indicator.js +12 -10
- package/dist/bot/services/typing-indicator.js.map +1 -1
- package/dist/bot/services/workspace-refresh.d.ts +3 -3
- package/dist/bot/services/workspace-refresh.d.ts.map +1 -1
- package/dist/bot/services/workspace-refresh.js +23 -13
- package/dist/bot/services/workspace-refresh.js.map +1 -1
- package/dist/bot/tool-executor.d.ts +10 -6
- package/dist/bot/tool-executor.d.ts.map +1 -1
- package/dist/bot/tool-executor.js +12 -6
- package/dist/bot/tool-executor.js.map +1 -1
- package/dist/bot/workspace-overview.d.ts.map +1 -1
- package/dist/bot/workspace-overview.js +6 -3
- package/dist/bot/workspace-overview.js.map +1 -1
- package/dist/bot-config/activity-error.d.ts +47 -0
- package/dist/bot-config/activity-error.d.ts.map +1 -0
- package/dist/bot-config/activity-error.js +67 -0
- package/dist/bot-config/activity-error.js.map +1 -0
- package/dist/bot-config/context.d.ts +4 -4
- package/dist/bot-config/context.d.ts.map +1 -1
- package/dist/bot-config/context.js +18 -14
- package/dist/bot-config/context.js.map +1 -1
- package/dist/bot-config/events.d.ts +45 -0
- package/dist/bot-config/events.d.ts.map +1 -0
- package/dist/bot-config/events.js +51 -0
- package/dist/bot-config/events.js.map +1 -0
- package/dist/bot-config/index.d.ts +3 -0
- package/dist/bot-config/index.d.ts.map +1 -1
- package/dist/bot-config/index.js +8 -1
- package/dist/bot-config/index.js.map +1 -1
- package/dist/bot-config/loader.d.ts +3 -0
- package/dist/bot-config/loader.d.ts.map +1 -1
- package/dist/bot-config/loader.js +45 -20
- package/dist/bot-config/loader.js.map +1 -1
- package/dist/bot-config/persistence.js.map +1 -1
- package/dist/bot-config/reconciler.d.ts +11 -0
- package/dist/bot-config/reconciler.d.ts.map +1 -0
- package/dist/bot-config/reconciler.js +121 -0
- package/dist/bot-config/reconciler.js.map +1 -0
- package/dist/bot-config/state.d.ts.map +1 -1
- package/dist/bot-config/state.js.map +1 -1
- package/dist/bot-config/types.d.ts +32 -0
- package/dist/bot-config/types.d.ts.map +1 -1
- package/dist/bot-config/webhooks.d.ts.map +1 -1
- package/dist/bot-config/webhooks.js.map +1 -1
- package/dist/bot-config/workflow-installer.d.ts +37 -0
- package/dist/bot-config/workflow-installer.d.ts.map +1 -0
- package/dist/bot-config/workflow-installer.js +346 -0
- package/dist/bot-config/workflow-installer.js.map +1 -0
- package/dist/cli.d.ts +4 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +92 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +23 -19
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +65 -27
- package/dist/config.js.map +1 -1
- package/dist/core.d.ts +6 -4
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +11 -16
- package/dist/core.js.map +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +7 -4
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/request-logger.d.ts +19 -19
- package/dist/lib/request-logger.d.ts.map +1 -1
- package/dist/lib/request-logger.js +19 -19
- package/dist/lib/request-logger.js.map +1 -1
- package/dist/mcp/UserContextCache.d.ts +28 -22
- package/dist/mcp/UserContextCache.d.ts.map +1 -1
- package/dist/mcp/UserContextCache.js +23 -23
- package/dist/mcp/UserContextCache.js.map +1 -1
- package/dist/mcp/auth.js.map +1 -1
- package/dist/mcp/hailer-clients.d.ts +5 -4
- package/dist/mcp/hailer-clients.d.ts.map +1 -1
- package/dist/mcp/hailer-clients.js +83 -34
- package/dist/mcp/hailer-clients.js.map +1 -1
- package/dist/mcp/hailer-rpc.d.ts +40 -0
- package/dist/mcp/hailer-rpc.d.ts.map +1 -0
- package/dist/mcp/hailer-rpc.js +43 -0
- package/dist/mcp/hailer-rpc.js.map +1 -0
- package/dist/mcp/publish-auth-injector.d.ts +22 -0
- package/dist/mcp/publish-auth-injector.d.ts.map +1 -0
- package/dist/mcp/publish-auth-injector.js +100 -0
- package/dist/mcp/publish-auth-injector.js.map +1 -0
- package/dist/mcp/session-store.d.ts +16 -16
- package/dist/mcp/session-store.d.ts.map +1 -1
- package/dist/mcp/session-store.js +16 -16
- package/dist/mcp/session-store.js.map +1 -1
- package/dist/mcp/tool-profiles.d.ts +69 -0
- package/dist/mcp/tool-profiles.d.ts.map +1 -0
- package/dist/mcp/tool-profiles.js +184 -0
- package/dist/mcp/tool-profiles.js.map +1 -0
- package/dist/mcp/tool-registry.d.ts +16 -0
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +91 -39
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/mcp/tools/activity.d.ts +2 -0
- package/dist/mcp/tools/activity.d.ts.map +1 -1
- package/dist/mcp/tools/activity.js +575 -218
- package/dist/mcp/tools/activity.js.map +1 -1
- package/dist/mcp/tools/aliases.d.ts +11 -0
- package/dist/mcp/tools/aliases.d.ts.map +1 -0
- package/dist/mcp/tools/aliases.js +182 -0
- package/dist/mcp/tools/aliases.js.map +1 -0
- package/dist/mcp/tools/app-core.d.ts +6 -8
- package/dist/mcp/tools/app-core.d.ts.map +1 -1
- package/dist/mcp/tools/app-core.js +355 -254
- package/dist/mcp/tools/app-core.js.map +1 -1
- package/dist/mcp/tools/app-marketplace.d.ts +12 -16
- package/dist/mcp/tools/app-marketplace.d.ts.map +1 -1
- package/dist/mcp/tools/app-marketplace.js +748 -856
- package/dist/mcp/tools/app-marketplace.js.map +1 -1
- package/dist/mcp/tools/app.d.ts +4 -7
- package/dist/mcp/tools/app.d.ts.map +1 -1
- package/dist/mcp/tools/app.js +4 -7
- package/dist/mcp/tools/app.js.map +1 -1
- package/dist/mcp/tools/bot-self.d.ts +21 -0
- package/dist/mcp/tools/bot-self.d.ts.map +1 -0
- package/dist/mcp/tools/bot-self.js +174 -0
- package/dist/mcp/tools/bot-self.js.map +1 -0
- package/dist/mcp/tools/calendar.d.ts +21 -0
- package/dist/mcp/tools/calendar.d.ts.map +1 -0
- package/dist/mcp/tools/calendar.js +741 -0
- package/dist/mcp/tools/calendar.js.map +1 -0
- package/dist/mcp/tools/company.d.ts.map +1 -1
- package/dist/mcp/tools/company.js +2 -1
- package/dist/mcp/tools/company.js.map +1 -1
- package/dist/mcp/tools/date.js.map +1 -1
- package/dist/mcp/tools/discussion.d.ts +29 -3
- package/dist/mcp/tools/discussion.d.ts.map +1 -1
- package/dist/mcp/tools/discussion.js +419 -534
- package/dist/mcp/tools/discussion.js.map +1 -1
- package/dist/mcp/tools/file.d.ts.map +1 -1
- package/dist/mcp/tools/file.js +18 -16
- package/dist/mcp/tools/file.js.map +1 -1
- package/dist/mcp/tools/index.js +4 -4
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/insight.d.ts +24 -5
- package/dist/mcp/tools/insight.d.ts.map +1 -1
- package/dist/mcp/tools/insight.js +513 -480
- package/dist/mcp/tools/insight.js.map +1 -1
- package/dist/mcp/tools/user.d.ts.map +1 -1
- package/dist/mcp/tools/user.js +15 -13
- package/dist/mcp/tools/user.js.map +1 -1
- package/dist/mcp/tools/workflow-permissions.d.ts +2 -4
- package/dist/mcp/tools/workflow-permissions.d.ts.map +1 -1
- package/dist/mcp/tools/workflow-permissions.js +88 -97
- package/dist/mcp/tools/workflow-permissions.js.map +1 -1
- package/dist/mcp/tools/workflow.d.ts +9 -7
- package/dist/mcp/tools/workflow.d.ts.map +1 -1
- package/dist/mcp/tools/workflow.js +852 -860
- package/dist/mcp/tools/workflow.js.map +1 -1
- package/dist/mcp/utils/api-errors.d.ts.map +1 -1
- package/dist/mcp/utils/api-errors.js +2 -2
- package/dist/mcp/utils/api-errors.js.map +1 -1
- package/dist/mcp/utils/data-transformers.d.ts +0 -3
- package/dist/mcp/utils/data-transformers.d.ts.map +1 -1
- package/dist/mcp/utils/data-transformers.js +32 -5
- package/dist/mcp/utils/data-transformers.js.map +1 -1
- package/dist/mcp/utils/file-upload.d.ts.map +1 -1
- package/dist/mcp/utils/file-upload.js +1 -1
- package/dist/mcp/utils/file-upload.js.map +1 -1
- package/dist/mcp/utils/hailer-api-client.d.ts +81 -81
- package/dist/mcp/utils/hailer-api-client.d.ts.map +1 -1
- package/dist/mcp/utils/hailer-api-client.js +113 -103
- package/dist/mcp/utils/hailer-api-client.js.map +1 -1
- package/dist/mcp/utils/index.d.ts.map +1 -1
- package/dist/mcp/utils/index.js.map +1 -1
- package/dist/mcp/utils/logger.d.ts.map +1 -1
- package/dist/mcp/utils/logger.js.map +1 -1
- package/dist/mcp/utils/response-builder.d.ts.map +1 -1
- package/dist/mcp/utils/response-builder.js +8 -4
- package/dist/mcp/utils/response-builder.js.map +1 -1
- package/dist/mcp/utils/role-utils.d.ts.map +1 -1
- package/dist/mcp/utils/role-utils.js +6 -3
- package/dist/mcp/utils/role-utils.js.map +1 -1
- package/dist/mcp/utils/tool-helpers.d.ts.map +1 -1
- package/dist/mcp/utils/tool-helpers.js +2 -2
- package/dist/mcp/utils/tool-helpers.js.map +1 -1
- package/dist/mcp/utils/types.d.ts +2 -1
- package/dist/mcp/utils/types.d.ts.map +1 -1
- package/dist/mcp/utils/types.js.map +1 -1
- package/dist/mcp/webhook-handler.d.ts +43 -8
- package/dist/mcp/webhook-handler.d.ts.map +1 -1
- package/dist/mcp/webhook-handler.js +861 -116
- package/dist/mcp/webhook-handler.js.map +1 -1
- package/dist/mcp/workspace-admin-store.d.ts +49 -0
- package/dist/mcp/workspace-admin-store.d.ts.map +1 -0
- package/dist/mcp/workspace-admin-store.js +168 -0
- package/dist/mcp/workspace-admin-store.js.map +1 -0
- package/dist/mcp/workspace-cache.d.ts +2 -2
- package/dist/mcp/workspace-cache.d.ts.map +1 -1
- package/dist/mcp/workspace-cache.js +9 -5
- package/dist/mcp/workspace-cache.js.map +1 -1
- package/dist/mcp-server.d.ts +26 -11
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +367 -48
- package/dist/mcp-server.js.map +1 -1
- package/dist/plugins/vipunen/client.d.ts +41 -41
- package/dist/plugins/vipunen/client.d.ts.map +1 -1
- package/dist/plugins/vipunen/client.js +53 -48
- package/dist/plugins/vipunen/client.js.map +1 -1
- package/dist/plugins/vipunen/index.js.map +1 -1
- package/dist/plugins/vipunen/tools.d.ts.map +1 -1
- package/dist/plugins/vipunen/tools.js +6 -3
- package/dist/plugins/vipunen/tools.js.map +1 -1
- package/dist/public-chat/graduate.d.ts +29 -0
- package/dist/public-chat/graduate.d.ts.map +1 -0
- package/dist/public-chat/graduate.js +593 -0
- package/dist/public-chat/graduate.js.map +1 -0
- package/dist/public-chat/handler.d.ts +12 -0
- package/dist/public-chat/handler.d.ts.map +1 -0
- package/dist/public-chat/handler.js +183 -0
- package/dist/public-chat/handler.js.map +1 -0
- package/dist/public-chat/index.d.ts +16 -0
- package/dist/public-chat/index.d.ts.map +1 -0
- package/dist/public-chat/index.js +74 -0
- package/dist/public-chat/index.js.map +1 -0
- package/dist/public-chat/knowledge.d.ts +3 -0
- package/dist/public-chat/knowledge.d.ts.map +1 -0
- package/dist/public-chat/knowledge.js +1340 -0
- package/dist/public-chat/knowledge.js.map +1 -0
- package/dist/public-chat/rate-limit.d.ts +16 -0
- package/dist/public-chat/rate-limit.d.ts.map +1 -0
- package/dist/public-chat/rate-limit.js +51 -0
- package/dist/public-chat/rate-limit.js.map +1 -0
- package/dist/public-chat/session-store.d.ts +41 -0
- package/dist/public-chat/session-store.d.ts.map +1 -0
- package/dist/public-chat/session-store.js +95 -0
- package/dist/public-chat/session-store.js.map +1 -0
- package/dist/public-chat/studio-prewarm.d.ts +61 -0
- package/dist/public-chat/studio-prewarm.d.ts.map +1 -0
- package/dist/public-chat/studio-prewarm.js +162 -0
- package/dist/public-chat/studio-prewarm.js.map +1 -0
- package/dist/public-chat/system-prompt.d.ts +22 -0
- package/dist/public-chat/system-prompt.d.ts.map +1 -0
- package/dist/public-chat/system-prompt.js +435 -0
- package/dist/public-chat/system-prompt.js.map +1 -0
- package/package.json +13 -7
- package/scripts/build-public-chat-knowledge.py +101 -0
- package/scripts/smoke-public-chat-live.ts +148 -0
- package/scripts/smoke-public-chat.ts +110 -0
- package/.claude/CLAUDE.md +0 -126
- package/.claude/commands/app-squad.md +0 -131
- package/.claude/commands/audit-squad.md +0 -158
- package/.claude/commands/cleanup-squad.md +0 -98
- package/.claude/commands/config-squad.md +0 -106
- package/.claude/commands/crud-squad.md +0 -87
- package/.claude/commands/data-squad.md +0 -97
- package/.claude/commands/doc-squad.md +0 -65
- package/.claude/commands/help.md +0 -29
- package/.claude/commands/help:agents.md +0 -182
- package/.claude/commands/help:commands.md +0 -78
- package/.claude/commands/help:faq.md +0 -79
- package/.claude/commands/help:plugins.md +0 -50
- package/.claude/commands/help:skills.md +0 -87
- package/.claude/commands/help:tools.md +0 -75
- package/.claude/commands/hotfix-squad.md +0 -112
- package/.claude/commands/integration-squad.md +0 -82
- package/.claude/commands/janitor-squad.md +0 -167
- package/.claude/commands/onboard-squad.md +0 -130
- package/.claude/commands/swarm.md +0 -210
- package/.claude/commands/tool-builder.md +0 -39
- package/.claude/skills/publish-hailer-app/SKILL.md +0 -280
- package/dist/CLAUDE.md +0 -370
- package/dist/agents/bot-manager.d.ts +0 -48
- package/dist/agents/bot-manager.d.ts.map +0 -1
- package/dist/agents/bot-manager.js +0 -254
- package/dist/agents/bot-manager.js.map +0 -1
- package/dist/agents/bug-fixer/ai.d.ts +0 -80
- package/dist/agents/bug-fixer/ai.d.ts.map +0 -1
- package/dist/agents/bug-fixer/ai.js +0 -466
- package/dist/agents/bug-fixer/ai.js.map +0 -1
- package/dist/agents/bug-fixer/bot.d.ts +0 -92
- package/dist/agents/bug-fixer/bot.d.ts.map +0 -1
- package/dist/agents/bug-fixer/bot.js +0 -687
- package/dist/agents/bug-fixer/bot.js.map +0 -1
- package/dist/agents/bug-fixer/config.d.ts +0 -21
- package/dist/agents/bug-fixer/config.d.ts.map +0 -1
- package/dist/agents/bug-fixer/config.js +0 -218
- package/dist/agents/bug-fixer/config.js.map +0 -1
- package/dist/agents/bug-fixer/files.d.ts +0 -67
- package/dist/agents/bug-fixer/files.d.ts.map +0 -1
- package/dist/agents/bug-fixer/files.js +0 -386
- package/dist/agents/bug-fixer/files.js.map +0 -1
- package/dist/agents/bug-fixer/git.d.ts +0 -48
- package/dist/agents/bug-fixer/git.d.ts.map +0 -1
- package/dist/agents/bug-fixer/git.js +0 -298
- package/dist/agents/bug-fixer/git.js.map +0 -1
- package/dist/agents/bug-fixer/index.d.ts +0 -103
- package/dist/agents/bug-fixer/index.d.ts.map +0 -1
- package/dist/agents/bug-fixer/index.js +0 -262
- package/dist/agents/bug-fixer/index.js.map +0 -1
- package/dist/agents/bug-fixer/lsp.d.ts +0 -113
- package/dist/agents/bug-fixer/lsp.d.ts.map +0 -1
- package/dist/agents/bug-fixer/lsp.js +0 -485
- package/dist/agents/bug-fixer/lsp.js.map +0 -1
- package/dist/agents/bug-fixer/monitor.d.ts +0 -123
- package/dist/agents/bug-fixer/monitor.d.ts.map +0 -1
- package/dist/agents/bug-fixer/monitor.js +0 -629
- package/dist/agents/bug-fixer/monitor.js.map +0 -1
- package/dist/agents/bug-fixer/prompt.d.ts +0 -5
- package/dist/agents/bug-fixer/prompt.d.ts.map +0 -1
- package/dist/agents/bug-fixer/prompt.js +0 -94
- package/dist/agents/bug-fixer/prompt.js.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-classification.d.ts +0 -28
- package/dist/agents/bug-fixer/registries/pending-classification.d.ts.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-classification.js +0 -50
- package/dist/agents/bug-fixer/registries/pending-classification.js.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-fix.d.ts +0 -33
- package/dist/agents/bug-fixer/registries/pending-fix.d.ts.map +0 -1
- package/dist/agents/bug-fixer/registries/pending-fix.js +0 -64
- package/dist/agents/bug-fixer/registries/pending-fix.js.map +0 -1
- package/dist/agents/bug-fixer/registries/pending.d.ts +0 -27
- package/dist/agents/bug-fixer/registries/pending.d.ts.map +0 -1
- package/dist/agents/bug-fixer/registries/pending.js +0 -49
- package/dist/agents/bug-fixer/registries/pending.js.map +0 -1
- package/dist/agents/bug-fixer/specialist-daemon.d.ts +0 -88
- package/dist/agents/bug-fixer/specialist-daemon.d.ts.map +0 -1
- package/dist/agents/bug-fixer/specialist-daemon.js +0 -431
- package/dist/agents/bug-fixer/specialist-daemon.js.map +0 -1
- package/dist/agents/bug-fixer/specialist.d.ts +0 -47
- package/dist/agents/bug-fixer/specialist.d.ts.map +0 -1
- package/dist/agents/bug-fixer/specialist.js +0 -327
- package/dist/agents/bug-fixer/specialist.js.map +0 -1
- package/dist/agents/bug-fixer/types.d.ts +0 -123
- package/dist/agents/bug-fixer/types.d.ts.map +0 -1
- package/dist/agents/bug-fixer/types.js +0 -9
- package/dist/agents/bug-fixer/types.js.map +0 -1
- package/dist/agents/factory.d.ts +0 -172
- package/dist/agents/factory.d.ts.map +0 -1
- package/dist/agents/factory.js +0 -706
- package/dist/agents/factory.js.map +0 -1
- package/dist/agents/hailer-expert/index.d.ts +0 -8
- package/dist/agents/hailer-expert/index.d.ts.map +0 -1
- package/dist/agents/hailer-expert/index.js +0 -14
- package/dist/agents/hailer-expert/index.js.map +0 -1
- package/dist/agents/hal/daemon.d.ts +0 -174
- package/dist/agents/hal/daemon.d.ts.map +0 -1
- package/dist/agents/hal/daemon.js +0 -1385
- package/dist/agents/hal/daemon.js.map +0 -1
- package/dist/agents/hal/definitions.d.ts +0 -42
- package/dist/agents/hal/definitions.d.ts.map +0 -1
- package/dist/agents/hal/definitions.js +0 -300
- package/dist/agents/hal/definitions.js.map +0 -1
- package/dist/agents/hal/index.d.ts +0 -3
- package/dist/agents/hal/index.d.ts.map +0 -1
- package/dist/agents/hal/index.js +0 -8
- package/dist/agents/hal/index.js.map +0 -1
- package/dist/agents/index.d.ts +0 -18
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/index.js +0 -48
- package/dist/agents/index.js.map +0 -1
- package/dist/agents/shared/base.d.ts +0 -253
- package/dist/agents/shared/base.d.ts.map +0 -1
- package/dist/agents/shared/base.js +0 -1122
- package/dist/agents/shared/base.js.map +0 -1
- package/dist/agents/shared/schemas/action-schema.d.ts +0 -62
- package/dist/agents/shared/schemas/action-schema.d.ts.map +0 -1
- package/dist/agents/shared/schemas/action-schema.js +0 -483
- package/dist/agents/shared/schemas/action-schema.js.map +0 -1
- package/dist/agents/shared/services/agent-registry.d.ts +0 -108
- package/dist/agents/shared/services/agent-registry.d.ts.map +0 -1
- package/dist/agents/shared/services/agent-registry.js +0 -469
- package/dist/agents/shared/services/agent-registry.js.map +0 -1
- package/dist/agents/shared/services/conversation-manager.d.ts +0 -57
- package/dist/agents/shared/services/conversation-manager.d.ts.map +0 -1
- package/dist/agents/shared/services/conversation-manager.js +0 -168
- package/dist/agents/shared/services/conversation-manager.js.map +0 -1
- package/dist/agents/shared/services/mcp-client.d.ts +0 -56
- package/dist/agents/shared/services/mcp-client.d.ts.map +0 -1
- package/dist/agents/shared/services/mcp-client.js +0 -124
- package/dist/agents/shared/services/mcp-client.js.map +0 -1
- package/dist/agents/shared/services/message-classifier.d.ts +0 -37
- package/dist/agents/shared/services/message-classifier.d.ts.map +0 -1
- package/dist/agents/shared/services/message-classifier.js +0 -203
- package/dist/agents/shared/services/message-classifier.js.map +0 -1
- package/dist/agents/shared/services/message-formatter.d.ts +0 -89
- package/dist/agents/shared/services/message-formatter.d.ts.map +0 -1
- package/dist/agents/shared/services/message-formatter.js +0 -390
- package/dist/agents/shared/services/message-formatter.js.map +0 -1
- package/dist/agents/shared/services/session-logger.d.ts +0 -162
- package/dist/agents/shared/services/session-logger.d.ts.map +0 -1
- package/dist/agents/shared/services/session-logger.js +0 -724
- package/dist/agents/shared/services/session-logger.js.map +0 -1
- package/dist/agents/shared/services/structured-output-executor.d.ts +0 -88
- package/dist/agents/shared/services/structured-output-executor.d.ts.map +0 -1
- package/dist/agents/shared/services/structured-output-executor.js +0 -296
- package/dist/agents/shared/services/structured-output-executor.js.map +0 -1
- package/dist/agents/shared/services/token-billing.d.ts +0 -72
- package/dist/agents/shared/services/token-billing.d.ts.map +0 -1
- package/dist/agents/shared/services/token-billing.js +0 -198
- package/dist/agents/shared/services/token-billing.js.map +0 -1
- package/dist/agents/shared/services/tool-executor.d.ts +0 -43
- package/dist/agents/shared/services/tool-executor.d.ts.map +0 -1
- package/dist/agents/shared/services/tool-executor.js +0 -175
- package/dist/agents/shared/services/tool-executor.js.map +0 -1
- package/dist/agents/shared/services/typing-indicator.d.ts +0 -24
- package/dist/agents/shared/services/typing-indicator.d.ts.map +0 -1
- package/dist/agents/shared/services/typing-indicator.js +0 -54
- package/dist/agents/shared/services/typing-indicator.js.map +0 -1
- package/dist/agents/shared/services/workspace-schema-cache.d.ts +0 -122
- package/dist/agents/shared/services/workspace-schema-cache.d.ts.map +0 -1
- package/dist/agents/shared/services/workspace-schema-cache.js +0 -507
- package/dist/agents/shared/services/workspace-schema-cache.js.map +0 -1
- package/dist/agents/shared/specialist.d.ts +0 -91
- package/dist/agents/shared/specialist.d.ts.map +0 -1
- package/dist/agents/shared/specialist.js +0 -399
- package/dist/agents/shared/specialist.js.map +0 -1
- package/dist/agents/shared/tool-schema-loader.d.ts +0 -65
- package/dist/agents/shared/tool-schema-loader.d.ts.map +0 -1
- package/dist/agents/shared/tool-schema-loader.js +0 -238
- package/dist/agents/shared/tool-schema-loader.js.map +0 -1
- package/dist/agents/shared/types.d.ts +0 -190
- package/dist/agents/shared/types.d.ts.map +0 -1
- package/dist/agents/shared/types.js +0 -13
- package/dist/agents/shared/types.js.map +0 -1
- package/dist/bot/bot-config.d.ts +0 -37
- package/dist/bot/bot-config.d.ts.map +0 -1
- package/dist/bot/bot-config.js +0 -219
- package/dist/bot/bot-config.js.map +0 -1
- package/dist/bot/services/__tests__/permission-guard.test.d.ts +0 -2
- package/dist/bot/services/__tests__/permission-guard.test.d.ts.map +0 -1
- package/dist/bot/services/__tests__/permission-guard.test.js +0 -357
- package/dist/bot/services/__tests__/permission-guard.test.js.map +0 -1
- package/dist/bot/services/session-logger.d.ts +0 -162
- package/dist/bot/services/session-logger.d.ts.map +0 -1
- package/dist/bot/services/session-logger.js +0 -724
- package/dist/bot/services/session-logger.js.map +0 -1
- package/dist/bot/services/workspace-schema-cache.d.ts +0 -122
- package/dist/bot/services/workspace-schema-cache.d.ts.map +0 -1
- package/dist/bot/services/workspace-schema-cache.js +0 -506
- package/dist/bot/services/workspace-schema-cache.js.map +0 -1
- package/dist/bot-config/tools.d.ts +0 -28
- package/dist/bot-config/tools.d.ts.map +0 -1
- package/dist/bot-config/tools.js +0 -279
- package/dist/bot-config/tools.js.map +0 -1
- package/dist/client/agents/base.d.ts +0 -207
- package/dist/client/agents/base.d.ts.map +0 -1
- package/dist/client/agents/base.js +0 -744
- package/dist/client/agents/base.js.map +0 -1
- package/dist/client/agents/definitions.d.ts +0 -53
- package/dist/client/agents/definitions.d.ts.map +0 -1
- package/dist/client/agents/definitions.js +0 -263
- package/dist/client/agents/definitions.js.map +0 -1
- package/dist/client/agents/orchestrator.d.ts +0 -141
- package/dist/client/agents/orchestrator.d.ts.map +0 -1
- package/dist/client/agents/orchestrator.js +0 -1062
- package/dist/client/agents/orchestrator.js.map +0 -1
- package/dist/client/agents/specialist.d.ts +0 -86
- package/dist/client/agents/specialist.d.ts.map +0 -1
- package/dist/client/agents/specialist.js +0 -340
- package/dist/client/agents/specialist.js.map +0 -1
- package/dist/client/bot-entrypoint.d.ts +0 -7
- package/dist/client/bot-entrypoint.d.ts.map +0 -1
- package/dist/client/bot-entrypoint.js +0 -103
- package/dist/client/bot-entrypoint.js.map +0 -1
- package/dist/client/bot-manager.d.ts +0 -44
- package/dist/client/bot-manager.d.ts.map +0 -1
- package/dist/client/bot-manager.js +0 -173
- package/dist/client/bot-manager.js.map +0 -1
- package/dist/client/bot-runner.d.ts +0 -35
- package/dist/client/bot-runner.d.ts.map +0 -1
- package/dist/client/bot-runner.js +0 -188
- package/dist/client/bot-runner.js.map +0 -1
- package/dist/client/chat-agent-daemon.d.ts +0 -464
- package/dist/client/chat-agent-daemon.d.ts.map +0 -1
- package/dist/client/chat-agent-daemon.js +0 -1774
- package/dist/client/chat-agent-daemon.js.map +0 -1
- package/dist/client/daemon-factory.d.ts +0 -106
- package/dist/client/daemon-factory.d.ts.map +0 -1
- package/dist/client/daemon-factory.js +0 -301
- package/dist/client/daemon-factory.js.map +0 -1
- package/dist/client/factory.d.ts +0 -111
- package/dist/client/factory.d.ts.map +0 -1
- package/dist/client/factory.js +0 -314
- package/dist/client/factory.js.map +0 -1
- package/dist/client/index.d.ts +0 -17
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -38
- package/dist/client/index.js.map +0 -1
- package/dist/client/multi-bot-manager.d.ts +0 -42
- package/dist/client/multi-bot-manager.d.ts.map +0 -1
- package/dist/client/multi-bot-manager.js +0 -161
- package/dist/client/multi-bot-manager.js.map +0 -1
- package/dist/client/orchestrator-daemon.d.ts +0 -87
- package/dist/client/orchestrator-daemon.d.ts.map +0 -1
- package/dist/client/orchestrator-daemon.js +0 -444
- package/dist/client/orchestrator-daemon.js.map +0 -1
- package/dist/client/server.d.ts +0 -8
- package/dist/client/server.d.ts.map +0 -1
- package/dist/client/server.js +0 -251
- package/dist/client/server.js.map +0 -1
- package/dist/client/services/agent-registry.d.ts +0 -108
- package/dist/client/services/agent-registry.d.ts.map +0 -1
- package/dist/client/services/agent-registry.js +0 -630
- package/dist/client/services/agent-registry.js.map +0 -1
- package/dist/client/services/conversation-manager.d.ts +0 -50
- package/dist/client/services/conversation-manager.d.ts.map +0 -1
- package/dist/client/services/conversation-manager.js +0 -136
- package/dist/client/services/conversation-manager.js.map +0 -1
- package/dist/client/services/mcp-client.d.ts +0 -48
- package/dist/client/services/mcp-client.d.ts.map +0 -1
- package/dist/client/services/mcp-client.js +0 -105
- package/dist/client/services/mcp-client.js.map +0 -1
- package/dist/client/services/message-classifier.d.ts +0 -37
- package/dist/client/services/message-classifier.d.ts.map +0 -1
- package/dist/client/services/message-classifier.js +0 -187
- package/dist/client/services/message-classifier.js.map +0 -1
- package/dist/client/services/message-formatter.d.ts +0 -84
- package/dist/client/services/message-formatter.d.ts.map +0 -1
- package/dist/client/services/message-formatter.js +0 -353
- package/dist/client/services/message-formatter.js.map +0 -1
- package/dist/client/services/session-logger.d.ts +0 -106
- package/dist/client/services/session-logger.d.ts.map +0 -1
- package/dist/client/services/session-logger.js +0 -446
- package/dist/client/services/session-logger.js.map +0 -1
- package/dist/client/services/tool-executor.d.ts +0 -41
- package/dist/client/services/tool-executor.d.ts.map +0 -1
- package/dist/client/services/tool-executor.js +0 -169
- package/dist/client/services/tool-executor.js.map +0 -1
- package/dist/client/services/workspace-schema-cache.d.ts +0 -149
- package/dist/client/services/workspace-schema-cache.d.ts.map +0 -1
- package/dist/client/services/workspace-schema-cache.js +0 -732
- package/dist/client/services/workspace-schema-cache.js.map +0 -1
- package/dist/client/specialist-daemon.d.ts +0 -77
- package/dist/client/specialist-daemon.d.ts.map +0 -1
- package/dist/client/specialist-daemon.js +0 -197
- package/dist/client/specialist-daemon.js.map +0 -1
- package/dist/client/specialists.d.ts +0 -53
- package/dist/client/specialists.d.ts.map +0 -1
- package/dist/client/specialists.js +0 -178
- package/dist/client/specialists.js.map +0 -1
- package/dist/client/tool-schema-loader.d.ts +0 -62
- package/dist/client/tool-schema-loader.d.ts.map +0 -1
- package/dist/client/tool-schema-loader.js +0 -232
- package/dist/client/tool-schema-loader.js.map +0 -1
- package/dist/client/types.d.ts +0 -327
- package/dist/client/types.d.ts.map +0 -1
- package/dist/client/types.js +0 -121
- package/dist/client/types.js.map +0 -1
- package/dist/commands/seed-config.d.ts +0 -9
- package/dist/commands/seed-config.d.ts.map +0 -1
- package/dist/commands/seed-config.js +0 -377
- package/dist/commands/seed-config.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -11
- package/dist/commands/setup.d.ts.map +0 -1
- package/dist/commands/setup.js +0 -320
- package/dist/commands/setup.js.map +0 -1
- package/dist/lib/discussion-lock.d.ts +0 -42
- package/dist/lib/discussion-lock.d.ts.map +0 -1
- package/dist/lib/discussion-lock.js +0 -110
- package/dist/lib/discussion-lock.js.map +0 -1
- package/dist/mcp/signal-handler.d.ts +0 -82
- package/dist/mcp/signal-handler.d.ts.map +0 -1
- package/dist/mcp/signal-handler.js +0 -406
- package/dist/mcp/signal-handler.js.map +0 -1
- package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts +0 -2
- package/dist/mcp/tools/__tests__/discussion-forward.test.d.ts.map +0 -1
- package/dist/mcp/tools/__tests__/discussion-forward.test.js +0 -218
- package/dist/mcp/tools/__tests__/discussion-forward.test.js.map +0 -1
- package/dist/mcp/tools/app-member.d.ts +0 -14
- package/dist/mcp/tools/app-member.d.ts.map +0 -1
- package/dist/mcp/tools/app-member.js +0 -195
- package/dist/mcp/tools/app-member.js.map +0 -1
- package/dist/mcp/tools/app-scaffold.d.ts +0 -14
- package/dist/mcp/tools/app-scaffold.d.ts.map +0 -1
- package/dist/mcp/tools/app-scaffold.js +0 -581
- package/dist/mcp/tools/app-scaffold.js.map +0 -1
- package/dist/mcp/tools/bot-config/constants.d.ts +0 -23
- package/dist/mcp/tools/bot-config/constants.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/constants.js +0 -94
- package/dist/mcp/tools/bot-config/constants.js.map +0 -1
- package/dist/mcp/tools/bot-config/core.d.ts +0 -253
- package/dist/mcp/tools/bot-config/core.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/core.js +0 -2456
- package/dist/mcp/tools/bot-config/core.js.map +0 -1
- package/dist/mcp/tools/bot-config/index.d.ts +0 -10
- package/dist/mcp/tools/bot-config/index.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/index.js +0 -59
- package/dist/mcp/tools/bot-config/index.js.map +0 -1
- package/dist/mcp/tools/bot-config/tools.d.ts +0 -7
- package/dist/mcp/tools/bot-config/tools.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/tools.js +0 -15
- package/dist/mcp/tools/bot-config/tools.js.map +0 -1
- package/dist/mcp/tools/bot-config/types.d.ts +0 -50
- package/dist/mcp/tools/bot-config/types.d.ts.map +0 -1
- package/dist/mcp/tools/bot-config/types.js +0 -6
- package/dist/mcp/tools/bot-config/types.js.map +0 -1
- package/dist/mcp/tools/bug-fixer-tools.d.ts +0 -45
- package/dist/mcp/tools/bug-fixer-tools.d.ts.map +0 -1
- package/dist/mcp/tools/bug-fixer-tools.js +0 -1096
- package/dist/mcp/tools/bug-fixer-tools.js.map +0 -1
- package/dist/mcp/tools/document.d.ts +0 -11
- package/dist/mcp/tools/document.d.ts.map +0 -1
- package/dist/mcp/tools/document.js +0 -741
- package/dist/mcp/tools/document.js.map +0 -1
- package/dist/mcp/tools/investigate.d.ts +0 -9
- package/dist/mcp/tools/investigate.d.ts.map +0 -1
- package/dist/mcp/tools/investigate.js +0 -254
- package/dist/mcp/tools/investigate.js.map +0 -1
- package/dist/mcp/utils/pagination.d.ts +0 -40
- package/dist/mcp/utils/pagination.d.ts.map +0 -1
- package/dist/mcp/utils/pagination.js +0 -55
- package/dist/mcp/utils/pagination.js.map +0 -1
- package/dist/modules/bug-reports/bug-config.d.ts +0 -25
- package/dist/modules/bug-reports/bug-config.d.ts.map +0 -1
- package/dist/modules/bug-reports/bug-config.js +0 -187
- package/dist/modules/bug-reports/bug-config.js.map +0 -1
- package/dist/modules/bug-reports/bug-monitor.d.ts +0 -108
- package/dist/modules/bug-reports/bug-monitor.d.ts.map +0 -1
- package/dist/modules/bug-reports/bug-monitor.js +0 -510
- package/dist/modules/bug-reports/bug-monitor.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-agent.d.ts +0 -58
- package/dist/modules/bug-reports/giuseppe-agent.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-agent.js +0 -467
- package/dist/modules/bug-reports/giuseppe-agent.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-ai.d.ts +0 -83
- package/dist/modules/bug-reports/giuseppe-ai.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-ai.js +0 -466
- package/dist/modules/bug-reports/giuseppe-ai.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-bot.d.ts +0 -110
- package/dist/modules/bug-reports/giuseppe-bot.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-bot.js +0 -804
- package/dist/modules/bug-reports/giuseppe-bot.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-daemon.d.ts +0 -80
- package/dist/modules/bug-reports/giuseppe-daemon.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-daemon.js +0 -617
- package/dist/modules/bug-reports/giuseppe-daemon.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-files.d.ts +0 -64
- package/dist/modules/bug-reports/giuseppe-files.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-files.js +0 -375
- package/dist/modules/bug-reports/giuseppe-files.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-git.d.ts +0 -48
- package/dist/modules/bug-reports/giuseppe-git.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-git.js +0 -298
- package/dist/modules/bug-reports/giuseppe-git.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-lsp.d.ts +0 -113
- package/dist/modules/bug-reports/giuseppe-lsp.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-lsp.js +0 -485
- package/dist/modules/bug-reports/giuseppe-lsp.js.map +0 -1
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts +0 -5
- package/dist/modules/bug-reports/giuseppe-prompt.d.ts.map +0 -1
- package/dist/modules/bug-reports/giuseppe-prompt.js +0 -94
- package/dist/modules/bug-reports/giuseppe-prompt.js.map +0 -1
- package/dist/modules/bug-reports/index.d.ts +0 -77
- package/dist/modules/bug-reports/index.d.ts.map +0 -1
- package/dist/modules/bug-reports/index.js +0 -215
- package/dist/modules/bug-reports/index.js.map +0 -1
- package/dist/modules/bug-reports/pending-classification-registry.d.ts +0 -28
- package/dist/modules/bug-reports/pending-classification-registry.d.ts.map +0 -1
- package/dist/modules/bug-reports/pending-classification-registry.js +0 -50
- package/dist/modules/bug-reports/pending-classification-registry.js.map +0 -1
- package/dist/modules/bug-reports/pending-fix-registry.d.ts +0 -30
- package/dist/modules/bug-reports/pending-fix-registry.d.ts.map +0 -1
- package/dist/modules/bug-reports/pending-fix-registry.js +0 -42
- package/dist/modules/bug-reports/pending-fix-registry.js.map +0 -1
- package/dist/modules/bug-reports/pending-registry.d.ts +0 -27
- package/dist/modules/bug-reports/pending-registry.d.ts.map +0 -1
- package/dist/modules/bug-reports/pending-registry.js +0 -49
- package/dist/modules/bug-reports/pending-registry.js.map +0 -1
- package/dist/modules/bug-reports/types.d.ts +0 -123
- package/dist/modules/bug-reports/types.d.ts.map +0 -1
- package/dist/modules/bug-reports/types.js +0 -9
- package/dist/modules/bug-reports/types.js.map +0 -1
- package/dist/plugins/bug-fixer/index.d.ts +0 -2
- package/dist/plugins/bug-fixer/index.d.ts.map +0 -1
- package/dist/plugins/bug-fixer/index.js +0 -18
- package/dist/plugins/bug-fixer/index.js.map +0 -1
- package/dist/plugins/bug-fixer/tools.d.ts +0 -45
- package/dist/plugins/bug-fixer/tools.d.ts.map +0 -1
- package/dist/plugins/bug-fixer/tools.js +0 -1096
- package/dist/plugins/bug-fixer/tools.js.map +0 -1
- package/dist/plugins/vipunen/__tests__/tools.test.d.ts +0 -10
- package/dist/plugins/vipunen/__tests__/tools.test.d.ts.map +0 -1
- package/dist/plugins/vipunen/__tests__/tools.test.js +0 -646
- package/dist/plugins/vipunen/__tests__/tools.test.js.map +0 -1
- package/dist/routes/agents.d.ts +0 -44
- package/dist/routes/agents.d.ts.map +0 -1
- package/dist/routes/agents.js +0 -311
- package/dist/routes/agents.js.map +0 -1
- package/dist/services/agent-credential-store.d.ts +0 -73
- package/dist/services/agent-credential-store.d.ts.map +0 -1
- package/dist/services/agent-credential-store.js +0 -212
- package/dist/services/agent-credential-store.js.map +0 -1
- package/dist/stdio-server.d.ts +0 -14
- package/dist/stdio-server.d.ts.map +0 -1
- package/dist/stdio-server.js +0 -101
- package/dist/stdio-server.js.map +0 -1
- package/dist/workspace/context.d.ts +0 -148
- package/dist/workspace/context.d.ts.map +0 -1
- package/dist/workspace/context.js +0 -339
- package/dist/workspace/context.js.map +0 -1
- package/dist/workspace/credentials.d.ts +0 -55
- package/dist/workspace/credentials.d.ts.map +0 -1
- package/dist/workspace/credentials.js +0 -239
- package/dist/workspace/credentials.js.map +0 -1
- package/dist/workspace/index.d.ts +0 -21
- package/dist/workspace/index.d.ts.map +0 -1
- package/dist/workspace/index.js +0 -45
- package/dist/workspace/index.js.map +0 -1
- package/dist/workspace/loader.d.ts +0 -27
- package/dist/workspace/loader.d.ts.map +0 -1
- package/dist/workspace/loader.js +0 -222
- package/dist/workspace/loader.js.map +0 -1
- package/dist/workspace/schema.d.ts +0 -37
- package/dist/workspace/schema.d.ts.map +0 -1
- package/dist/workspace/schema.js +0 -192
- package/dist/workspace/schema.js.map +0 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Express handler for POST /api/public-chat.
|
|
4
|
+
*
|
|
5
|
+
* Anonymous endpoint (no Hailer auth). The handler:
|
|
6
|
+
* 1. Rate-limits by client IP.
|
|
7
|
+
* 2. Validates the request payload (turns + new user message).
|
|
8
|
+
* 3. Calls Claude Haiku 4.5 with a cached system prompt.
|
|
9
|
+
* 4. Streams text deltas back to the client as Server-Sent Events.
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.createPublicChatHandler = createPublicChatHandler;
|
|
16
|
+
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
17
|
+
const zod_1 = require("zod");
|
|
18
|
+
const logger_1 = require("../lib/logger");
|
|
19
|
+
const system_prompt_1 = require("./system-prompt");
|
|
20
|
+
const rate_limit_1 = require("./rate-limit");
|
|
21
|
+
const session_store_1 = require("./session-store");
|
|
22
|
+
const logger = (0, logger_1.createLogger)({ component: 'public-chat' });
|
|
23
|
+
// Match the model the rest of the project standardizes on.
|
|
24
|
+
const MODEL = 'claude-haiku-4-5';
|
|
25
|
+
// Cost backstop, NOT the brevity mechanism — prose length is enforced by the
|
|
26
|
+
// system prompt's hard length rule. Sized so the largest legitimate reply (a
|
|
27
|
+
// full guided tour, ~21 <bot-action> tags ≈ 950 tokens) NEVER truncates:
|
|
28
|
+
// a mid-tag cut would feed the frontend tag parser a malformed fragment.
|
|
29
|
+
const MAX_TOKENS = 1600;
|
|
30
|
+
const MAX_HISTORY_TURNS = 12; // user + assistant turns kept from the client
|
|
31
|
+
const MAX_USER_MESSAGE_CHARS = 2000; // hard cap on a single message
|
|
32
|
+
const messageSchema = zod_1.z.object({
|
|
33
|
+
role: zod_1.z.enum(['user', 'assistant']),
|
|
34
|
+
content: zod_1.z.string().min(1).max(8000),
|
|
35
|
+
});
|
|
36
|
+
const requestSchema = zod_1.z.object({
|
|
37
|
+
// Prior turns (oldest first). The server doesn't trust this — it caps and
|
|
38
|
+
// sanitizes it — but accepting it lets the prototype work without a session
|
|
39
|
+
// store. A future iteration can move the history server-side.
|
|
40
|
+
history: zod_1.z.array(messageSchema).max(MAX_HISTORY_TURNS).default([]),
|
|
41
|
+
message: zod_1.z.string().min(1).max(MAX_USER_MESSAGE_CHARS),
|
|
42
|
+
// Client-generated UUID for the demo chat session. Stored by the frontend
|
|
43
|
+
// in localStorage so a visitor who reloads (or later registers and signs in)
|
|
44
|
+
// can resume the same conversation. The server just logs it for now;
|
|
45
|
+
// future analytics or server-side persistence can correlate by this key.
|
|
46
|
+
sessionId: zod_1.z.string().uuid().optional(),
|
|
47
|
+
});
|
|
48
|
+
function writeSseEvent(res, event, data) {
|
|
49
|
+
res.write(`event: ${event}\n`);
|
|
50
|
+
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
51
|
+
}
|
|
52
|
+
function createPublicChatHandler(anthropicApiKey) {
|
|
53
|
+
const anthropic = new sdk_1.default({ apiKey: anthropicApiKey });
|
|
54
|
+
return async (req, res) => {
|
|
55
|
+
// req.ip is the real client IP because mcp-server sets 'trust proxy'.
|
|
56
|
+
const ip = req.ip ?? 'unknown';
|
|
57
|
+
const rate = (0, rate_limit_1.checkRate)(ip);
|
|
58
|
+
if (!rate.ok) {
|
|
59
|
+
res.setHeader('Retry-After', String(rate.retryAfterSec ?? 60));
|
|
60
|
+
res.status(429).json({
|
|
61
|
+
error: 'rate_limited',
|
|
62
|
+
message: 'Too many requests. Please slow down.',
|
|
63
|
+
retryAfterSec: rate.retryAfterSec,
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const parsed = requestSchema.safeParse(req.body);
|
|
68
|
+
if (!parsed.success) {
|
|
69
|
+
logger.warn('public-chat validation failed', { issues: parsed.error.issues });
|
|
70
|
+
res.status(400).json({
|
|
71
|
+
error: 'invalid_request',
|
|
72
|
+
message: 'Request body did not match schema.',
|
|
73
|
+
issues: parsed.error.issues,
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const { history, message, sessionId } = parsed.data;
|
|
78
|
+
// Set up SSE response.
|
|
79
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
80
|
+
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
81
|
+
res.setHeader('Connection', 'keep-alive');
|
|
82
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
83
|
+
res.flushHeaders?.();
|
|
84
|
+
// Disable Node's per-socket idle timeout so the connection isn't
|
|
85
|
+
// killed during the natural ~500ms gap between message_start and the
|
|
86
|
+
// first content delta from Anthropic.
|
|
87
|
+
res.socket?.setTimeout(0);
|
|
88
|
+
req.socket?.setTimeout(0);
|
|
89
|
+
// Initial SSE comment so the response body has bytes immediately.
|
|
90
|
+
res.write(': open\n\n');
|
|
91
|
+
// Heartbeat every 15s — belt-and-suspenders against proxy/browser timeouts
|
|
92
|
+
// during longer model responses.
|
|
93
|
+
const heartbeat = setInterval(() => {
|
|
94
|
+
if (!res.writableEnded) {
|
|
95
|
+
res.write(': heartbeat\n\n');
|
|
96
|
+
}
|
|
97
|
+
}, 15_000);
|
|
98
|
+
let aborted = false;
|
|
99
|
+
// Use res.on('close') — `req.on('close')` fires as soon as the request body
|
|
100
|
+
// is fully consumed by express.json(), not when the client actually
|
|
101
|
+
// disconnects. We only treat the response closing *before* we've ended it
|
|
102
|
+
// ourselves as a real abort.
|
|
103
|
+
res.on('close', () => {
|
|
104
|
+
if (!res.writableEnded) {
|
|
105
|
+
aborted = true;
|
|
106
|
+
clearInterval(heartbeat);
|
|
107
|
+
logger.info('public-chat client disconnected mid-stream');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
try {
|
|
111
|
+
const messages = [
|
|
112
|
+
...history.map((m) => ({ role: m.role, content: m.content })),
|
|
113
|
+
{ role: 'user', content: message },
|
|
114
|
+
];
|
|
115
|
+
// Use the lower-level streaming API — returns a Stream<RawMessageStreamEvent>
|
|
116
|
+
// that's a direct async iterator over the SSE response from Anthropic.
|
|
117
|
+
const stream = await anthropic.messages.create({
|
|
118
|
+
model: MODEL,
|
|
119
|
+
max_tokens: MAX_TOKENS,
|
|
120
|
+
system: (0, system_prompt_1.buildPublicChatSystem)(),
|
|
121
|
+
messages,
|
|
122
|
+
stream: true,
|
|
123
|
+
});
|
|
124
|
+
let finalUsage;
|
|
125
|
+
let finalStopReason = null;
|
|
126
|
+
// Buffer the assistant's text as it streams so we can persist the
|
|
127
|
+
// completed turn to the session store at the end. Includes the
|
|
128
|
+
// <bot-action> tags; the frontend strips them for display.
|
|
129
|
+
let assistantText = '';
|
|
130
|
+
for await (const event of stream) {
|
|
131
|
+
if (aborted)
|
|
132
|
+
break;
|
|
133
|
+
if (event.type === 'content_block_delta' &&
|
|
134
|
+
event.delta.type === 'text_delta') {
|
|
135
|
+
assistantText += event.delta.text;
|
|
136
|
+
writeSseEvent(res, 'delta', { text: event.delta.text });
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (event.type !== 'message_delta')
|
|
140
|
+
continue;
|
|
141
|
+
if (event.usage) {
|
|
142
|
+
finalUsage = event.usage;
|
|
143
|
+
}
|
|
144
|
+
if (event.delta.stop_reason) {
|
|
145
|
+
finalStopReason = event.delta.stop_reason;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
clearInterval(heartbeat);
|
|
149
|
+
if (aborted)
|
|
150
|
+
return;
|
|
151
|
+
writeSseEvent(res, 'done', {
|
|
152
|
+
stopReason: finalStopReason,
|
|
153
|
+
usage: finalUsage,
|
|
154
|
+
});
|
|
155
|
+
res.end();
|
|
156
|
+
// Persist the completed turn — only when we have a sessionId AND
|
|
157
|
+
// the model actually produced output AND the stop reason indicates
|
|
158
|
+
// a clean finish.
|
|
159
|
+
if (sessionId && assistantText.length > 0) {
|
|
160
|
+
session_store_1.publicChatSessionStore.append(sessionId, message, assistantText);
|
|
161
|
+
}
|
|
162
|
+
logger.info('public-chat completed', {
|
|
163
|
+
sessionId,
|
|
164
|
+
stopReason: finalStopReason,
|
|
165
|
+
inputTokens: finalUsage?.input_tokens,
|
|
166
|
+
outputTokens: finalUsage?.output_tokens,
|
|
167
|
+
storedTurns: sessionId ? session_store_1.publicChatSessionStore.get(sessionId)?.length : undefined,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
clearInterval(heartbeat);
|
|
172
|
+
logger.error('public-chat stream failed', err);
|
|
173
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
174
|
+
if (!res.headersSent) {
|
|
175
|
+
res.status(500).json({ error: 'internal_error', message: errMessage });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
writeSseEvent(res, 'error', { message: errMessage });
|
|
179
|
+
res.end();
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/public-chat/handler.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;AA6CH,0DA6IC;AAvLD,4DAA0C;AAC1C,6BAAwB;AACxB,0CAA6C;AAC7C,mDAAwD;AACxD,6CAAyC;AACzC,mDAAyD;AAEzD,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;AAE1D,2DAA2D;AAC3D,MAAM,KAAK,GAAG,kBAAkB,CAAC;AACjC,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,yEAAyE;AACzE,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,iBAAiB,GAAG,EAAE,CAAC,CAAQ,8CAA8C;AACnF,MAAM,sBAAsB,GAAG,IAAI,CAAC,CAAC,+BAA+B;AAEpE,MAAM,aAAa,GAAG,OAAC,CAAC,MAAM,CAAC;IAC7B,IAAI,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACnC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,OAAC,CAAC,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,4EAA4E;IAC5E,8DAA8D;IAC9D,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAClE,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,sBAAsB,CAAC;IACtD,0EAA0E;IAC1E,6EAA6E;IAC7E,qEAAqE;IACrE,yEAAyE;IACzE,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC;AAEH,SAAS,aAAa,CAAC,GAAqB,EAAE,KAAa,EAAE,IAAa;IACxE,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;IAC/B,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AAED,SAAgB,uBAAuB,CAAC,eAAuB;IAC7D,MAAM,SAAS,GAAG,IAAI,aAAS,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;IAE7D,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACxB,sEAAsE;QACtE,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAA,sBAAS,EAAC,EAAE,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,GAAG,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;YAC/D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,cAAc;gBACrB,OAAO,EAAE,sCAAsC;gBAC/C,aAAa,EAAE,IAAI,CAAC,aAAa;aAClC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9E,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,KAAK,EAAE,iBAAiB;gBACxB,OAAO,EAAE,oCAAoC;gBAC7C,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;aAC5B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;QAEpD,uBAAuB;QACvB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;QACnD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,wBAAwB,CAAC,CAAC;QACzD,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC1C,GAAG,CAAC,SAAS,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;QACzC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;QAErB,iEAAiE;QACjE,qEAAqE;QACrE,sCAAsC;QACtC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;QAE1B,kEAAkE;QAClE,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAExB,2EAA2E;QAC3E,iCAAiC;QACjC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC,EAAE,MAAM,CAAC,CAAC;QAEX,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,4EAA4E;QAC5E,oEAAoE;QACpE,0EAA0E;QAC1E,6BAA6B;QAC7B,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,OAAO,GAAG,IAAI,CAAC;gBACf,aAAa,CAAC,SAAS,CAAC,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG;gBACf,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7D,EAAE,IAAI,EAAE,MAAe,EAAE,OAAO,EAAE,OAAO,EAAE;aAC5C,CAAC;YAEF,8EAA8E;YAC9E,uEAAuE;YACvE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC7C,KAAK,EAAE,KAAK;gBACZ,UAAU,EAAE,UAAU;gBACtB,MAAM,EAAE,IAAA,qCAAqB,GAAE;gBAC/B,QAAQ;gBACR,MAAM,EAAE,IAAI;aACb,CAAC,CAAC;YAEH,IAAI,UAAyE,CAAC;YAC9E,IAAI,eAAe,GAAkB,IAAI,CAAC;YAC1C,kEAAkE;YAClE,+DAA+D;YAC/D,2DAA2D;YAC3D,IAAI,aAAa,GAAG,EAAE,CAAC;YACvB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBACjC,IAAI,OAAO;oBAAE,MAAM;gBACnB,IACE,KAAK,CAAC,IAAI,KAAK,qBAAqB;oBACpC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,EACjC,CAAC;oBACD,aAAa,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;oBAClC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oBACxD,SAAS;gBACX,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe;oBAAE,SAAS;gBAC7C,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAChB,UAAU,GAAG,KAAK,CAAC,KAA0D,CAAC;gBAChF,CAAC;gBACD,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;oBAC5B,eAAe,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;gBAC5C,CAAC;YACH,CAAC;YAED,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,IAAI,OAAO;gBAAE,OAAO;YAEpB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE;gBACzB,UAAU,EAAE,eAAe;gBAC3B,KAAK,EAAE,UAAU;aAClB,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,iEAAiE;YACjE,mEAAmE;YACnE,kBAAkB;YAClB,IAAI,SAAS,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1C,sCAAsB,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE;gBACnC,SAAS;gBACT,UAAU,EAAE,eAAe;gBAC3B,WAAW,EAAE,UAAU,EAAE,YAAY;gBACrC,YAAY,EAAE,UAAU,EAAE,aAAa;gBACvC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,sCAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS;aACnF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAC;YAC/C,MAAM,UAAU,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACpE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;gBACvE,OAAO;YACT,CAAC;YACD,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;YACrD,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public chat module — anonymous chatbot for Hailer's login page.
|
|
3
|
+
*
|
|
4
|
+
* Wires public-chat routes into the Express app. Returns `false` and registers
|
|
5
|
+
* nothing if ANTHROPIC_API_KEY is missing, so the rest of the server keeps
|
|
6
|
+
* working even without the key configured.
|
|
7
|
+
*/
|
|
8
|
+
import express from 'express';
|
|
9
|
+
import { PUBLIC_CHAT_AUTHORIZE_ROUTE } from './graduate';
|
|
10
|
+
export declare const PUBLIC_CHAT_ROUTE = "/api/public-chat";
|
|
11
|
+
export declare const PUBLIC_CHAT_HISTORY_ROUTE = "/api/public-chat/history";
|
|
12
|
+
export { PUBLIC_CHAT_AUTHORIZE_ROUTE };
|
|
13
|
+
export declare function registerPublicChatRoutes(app: express.Express, opts: {
|
|
14
|
+
anthropicApiKey: string | undefined;
|
|
15
|
+
}): boolean;
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/public-chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAM9B,OAAO,EAAoC,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAI3F,eAAO,MAAM,iBAAiB,qBAAqB,CAAC;AACpD,eAAO,MAAM,yBAAyB,6BAA6B,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,CAAC;AAKvC,wBAAgB,wBAAwB,CACpC,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,IAAI,EAAE;IAAE,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAC9C,OAAO,CAuDT"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Public chat module — anonymous chatbot for Hailer's login page.
|
|
4
|
+
*
|
|
5
|
+
* Wires public-chat routes into the Express app. Returns `false` and registers
|
|
6
|
+
* nothing if ANTHROPIC_API_KEY is missing, so the rest of the server keeps
|
|
7
|
+
* working even without the key configured.
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.PUBLIC_CHAT_AUTHORIZE_ROUTE = exports.PUBLIC_CHAT_HISTORY_ROUTE = exports.PUBLIC_CHAT_ROUTE = void 0;
|
|
14
|
+
exports.registerPublicChatRoutes = registerPublicChatRoutes;
|
|
15
|
+
const express_1 = __importDefault(require("express"));
|
|
16
|
+
const logger_1 = require("../lib/logger");
|
|
17
|
+
const handler_1 = require("./handler");
|
|
18
|
+
const system_prompt_1 = require("./system-prompt");
|
|
19
|
+
const session_store_1 = require("./session-store");
|
|
20
|
+
const rate_limit_1 = require("./rate-limit");
|
|
21
|
+
const graduate_1 = require("./graduate");
|
|
22
|
+
Object.defineProperty(exports, "PUBLIC_CHAT_AUTHORIZE_ROUTE", { enumerable: true, get: function () { return graduate_1.PUBLIC_CHAT_AUTHORIZE_ROUTE; } });
|
|
23
|
+
const logger = (0, logger_1.createLogger)({ component: 'public-chat' });
|
|
24
|
+
exports.PUBLIC_CHAT_ROUTE = '/api/public-chat';
|
|
25
|
+
exports.PUBLIC_CHAT_HISTORY_ROUTE = '/api/public-chat/history';
|
|
26
|
+
// RFC 4122-ish UUID; we just want to reject malformed input quickly.
|
|
27
|
+
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
28
|
+
function registerPublicChatRoutes(app, opts) {
|
|
29
|
+
if (!opts.anthropicApiKey) {
|
|
30
|
+
logger.warn(`${exports.PUBLIC_CHAT_ROUTE} disabled — ANTHROPIC_API_KEY not set in environment`);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
app.post(exports.PUBLIC_CHAT_ROUTE, (0, handler_1.createPublicChatHandler)(opts.anthropicApiKey));
|
|
34
|
+
// GET history for a session. Anonymous endpoint — only the sessionId acts
|
|
35
|
+
// as a (unguessable) auth token. UUID v4 has ~122 bits of entropy, so a
|
|
36
|
+
// brute-force lookup of someone else's session is infeasible.
|
|
37
|
+
//
|
|
38
|
+
// This route is the only consumer of the session store, and it exists for
|
|
39
|
+
// client convenience (resume after reload). The chat handler does NOT use
|
|
40
|
+
// the store as a source of truth for prompting — the request body's
|
|
41
|
+
// `history` field is what shapes the model context. See session-store.ts.
|
|
42
|
+
app.get(exports.PUBLIC_CHAT_HISTORY_ROUTE, (req, res) => {
|
|
43
|
+
// req.ip is the real client IP because mcp-server sets 'trust proxy'.
|
|
44
|
+
const rate = (0, rate_limit_1.checkRate)(req.ip ?? 'unknown');
|
|
45
|
+
if (!rate.ok) {
|
|
46
|
+
res.setHeader('Retry-After', String(rate.retryAfterSec ?? 60));
|
|
47
|
+
res.status(429).json({ error: 'rate_limited' });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const sessionId = typeof req.query.sessionId === 'string' ? req.query.sessionId : '';
|
|
51
|
+
if (!UUID_REGEX.test(sessionId)) {
|
|
52
|
+
res.status(400).json({ error: 'invalid_session_id' });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const turns = session_store_1.publicChatSessionStore.get(sessionId);
|
|
56
|
+
if (!turns) {
|
|
57
|
+
res.status(404).json({ error: 'session_not_found' });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
res.json({ sessionId, messages: turns });
|
|
61
|
+
});
|
|
62
|
+
// Graduation endpoint — POST from Hailer's `/authorize/user-api-key`
|
|
63
|
+
// popup, body is form-encoded (apiKey=...). The same urlencoded parser
|
|
64
|
+
// pattern as /admin-authorize so the popup's content-type is accepted.
|
|
65
|
+
app.post(graduate_1.PUBLIC_CHAT_AUTHORIZE_ROUTE, express_1.default.urlencoded({ extended: true }), (0, graduate_1.createPublicChatAuthorizeHandler)());
|
|
66
|
+
logger.info('Public chat routes registered', {
|
|
67
|
+
chat: exports.PUBLIC_CHAT_ROUTE,
|
|
68
|
+
history: exports.PUBLIC_CHAT_HISTORY_ROUTE,
|
|
69
|
+
authorize: graduate_1.PUBLIC_CHAT_AUTHORIZE_ROUTE,
|
|
70
|
+
knowledgeBytes: system_prompt_1.KNOWLEDGE_BYTES,
|
|
71
|
+
});
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/public-chat/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;AAmBH,4DA0DC;AA3ED,sDAA8B;AAC9B,0CAA6C;AAC7C,uCAAoD;AACpD,mDAAkD;AAClD,mDAAyD;AACzD,6CAAyC;AACzC,yCAA2F;AAMlF,4GANkC,sCAA2B,OAMlC;AAJpC,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;AAE7C,QAAA,iBAAiB,GAAG,kBAAkB,CAAC;AACvC,QAAA,yBAAyB,GAAG,0BAA0B,CAAC;AAGpE,qEAAqE;AACrE,MAAM,UAAU,GAAG,4EAA4E,CAAC;AAEhG,SAAgB,wBAAwB,CACpC,GAAoB,EACpB,IAA6C;IAE7C,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CACP,GAAG,yBAAiB,sDAAsD,CAC7E,CAAC;QACF,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,yBAAiB,EAAE,IAAA,iCAAuB,EAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;IAE3E,0EAA0E;IAC1E,wEAAwE;IACxE,8DAA8D;IAC9D,EAAE;IACF,0EAA0E;IAC1E,0EAA0E;IAC1E,oEAAoE;IACpE,0EAA0E;IAC1E,GAAG,CAAC,GAAG,CAAC,iCAAyB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC5C,sEAAsE;QACtE,MAAM,IAAI,GAAG,IAAA,sBAAS,EAAC,GAAG,CAAC,EAAE,IAAI,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACX,GAAG,CAAC,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,CAAC;YAC/D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YAChD,OAAO;QACX,CAAC;QACD,MAAM,SAAS,GAAG,OAAO,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;YACtD,OAAO;QACX,CAAC;QACD,MAAM,KAAK,GAAG,sCAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACrD,OAAO;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,qEAAqE;IACrE,uEAAuE;IACvE,uEAAuE;IACvE,GAAG,CAAC,IAAI,CACJ,sCAA2B,EAC3B,iBAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EACtC,IAAA,2CAAgC,GAAE,CACrC,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE;QACzC,IAAI,EAAE,yBAAiB;QACvB,OAAO,EAAE,iCAAyB;QAClC,SAAS,EAAE,sCAA2B;QACtC,cAAc,EAAE,+BAAe;KAClC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const HAILER_KNOWLEDGE_CORPUS = "# Hailer Knowledge Base\n\nThis is the curated, public-safe knowledge corpus that the public chatbot uses to answer questions about Hailer. It covers product concepts, the user interface, the MCP server, app development, and getting started.\n\n## Developer & MCP\n\n### Apps & Marketplace\n\n#### What Hailer apps are and how they relate to the MCP server\n\nHailer apps are custom web applications that run inside Hailer workspaces. They are full frontend applications \u2014 React, Svelte, vanilla JS \u2014 that use Hailer's API for data and are embedded inside the Hailer UI.\n\nThe Hailer MCP server itself does not contain apps. It provides the tools to create, manage, and publish them. Each app lives in its own project directory.\n\nThe lifecycle is: Scaffold (about a minute) \u2192 Develop (locally) \u2192 Publish (to CDN) \u2192 Share (control access).\n\nThe app lifecycle is script-driven: scaffold with npx @hailer/create-app, develop with cd app && npm run dev, publish with cd app && npm run publish-production -- --force, and register/share with manage_app (action add_member) or by editing workspace/apps.ts then running npx hailer-sdk ws-config apps push --force. There are no MCP tools for scaffolding or publishing apps \u2014 those steps are script-only.\n\n#### Scaffolding a new Hailer app with npx @hailer/create-app\n\nScaffold a new app in one step with npx @hailer/create-app \u2014 there is no MCP tool for scaffolding. Ask Claude Code something like 'Create a task dashboard app' and the command will:\n\n1. Create a Vite + React-TS project (or another template).\n2. Install @hailer/app-sdk and Chakra UI.\n3. Generate an app icon (gradient SVG).\n4. Create a dev app entry in Hailer pointing to localhost:3000.\n5. Configure CORS in vite.config.ts.\n6. Share the app with the workspace.\n7. Create a manifest.json with the assigned appId.\n8. Start the dev server.\n\nThe scaffolded structure:\n```\nmy-app/\n\u251C\u2500\u2500 public/manifest.json # App metadata (appId, name, version)\n\u251C\u2500\u2500 src/\n\u2502 \u251C\u2500\u2500 main.tsx # React entry point\n\u2502 \u251C\u2500\u2500 App.tsx # Main component\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 package.json\n\u251C\u2500\u2500 vite.config.ts # Build config with CORS\n\u2514\u2500\u2500 tsconfig.json\n```\n\nThe key rule: always scaffold fresh with npx @hailer/create-app to create new apps. Never copy an existing app \u2014 the create-app command handles app registration, icon generation, CORS config, manifest creation, and sharing in one step.\n\n#### Available app templates\n\nThe scaffold command (npx @hailer/create-app) supports multiple frontend stacks. Pick the one that matches the team's preferences:\n\n- react-ts (default) \u2014 React + TypeScript + Chakra UI.\n- react \u2014 React + JavaScript.\n- preact-ts \u2014 Preact + TypeScript.\n- preact \u2014 Preact + JavaScript.\n- svelte-ts \u2014 Svelte + TypeScript.\n- svelte \u2014 Svelte + JavaScript.\n- vanilla-ts \u2014 Vanilla + TypeScript.\n- vanilla \u2014 Vanilla JavaScript.\n\nReact-TS is the most heavily documented and is what the design-system skill targets. Other templates work but get less first-party support around components, hooks, and example code.\n\n#### Developing a Hailer app locally and connecting to Hailer data\n\nAfter scaffolding, run the app locally:\n\n```bash\ncd my-app\nnpm run dev # starts Vite on port 3000\n```\n\nThe dev app entry inside Hailer points at http://localhost:3000, so changes appear live in the workspace.\n\nApps use the Hailer API client to fetch and modify data through the @hailer/app-sdk hook:\n\n```typescript\nimport { useHailer } from '@hailer/app-sdk';\n\nfunction TaskList() {\n const hailer = useHailer();\n const [tasks, setTasks] = useState([]);\n\n useEffect(() => {\n const fetch = async () => {\n const result = await hailer.request('v3.activity.list', [\n workflowId,\n { phase: activePhaseId, limit: 50 },\n ]);\n setTasks(result.activities);\n };\n fetch();\n }, []);\n\n return <TaskTable data={tasks} />;\n}\n```\n\nThe default React-TS template also includes Hailer's Chakra UI v2 theme: brand colors, a custom icon set, pre-configured components, responsive grid patterns, and consistent typography. See the hailer-design-system skill for the full reference.\n\n#### Publishing a Hailer app with npm run publish-production\n\nWhen an app is ready for production, run cd app && npm run publish-production -- --force. This is the only publishing path \u2014 there is no MCP tool for publishing apps. The --force flag is required: without it the publish stops at an interactive 'Overwrite the app? (Y/n)' prompt that hangs automated runs. It handles:\n\n1. Runs npm run build (Vite production build).\n2. Packages dist/ together with manifest.json as a tar archive.\n3. Uploads the tar to the Hailer CDN.\n4. Creates a published app entry with an auto-generated URL.\n5. Updates the app's URL from localhost to the production CDN URL.\n\nApp entries inside Hailer come in two shapes:\n\nDevelopment app:\n```json\n{ \"name\": \"Task Dashboard\", \"description\": \"View and manage tasks\", \"url\": \"http://localhost:3000\", \"image\": \"<fileId>\", \"config\": {} }\n```\n\nPublished app:\n```json\n{ \"name\": \"Task Dashboard\", \"description\": \"View and manage tasks\", \"url\": \"\", \"image\": \"<fileId>\" }\n```\nA published app uses an empty url, which causes Hailer to serve from the auto-generated CDN URL.\n\n#### Sharing apps with workspace members, teams, users, and groups\n\nOnce an app is scaffolded or published, control who can use it with the manage_app MCP tool (action add_member), or by editing workspace/apps.ts and running npx hailer-sdk ws-config apps push --force. Recipients are addressed by typed identifier:\n\n- Workspace-wide: pass network_<workspaceId>.\n- Team: pass team_<teamId>.\n- User: pass user_<userId>.\n- Group: pass group_<groupId>.\n\nThis matches Hailer's broader sharing model \u2014 the same id-prefix convention is used wherever you grant access. By scaffold time, the create-app command has already shared the dev app with the current workspace, so no manual sharing is needed for the developer's own use.\n\n#### Marketplace: templates and apps you can distribute across workspaces\n\nThe marketplace lets you distribute apps and templates across workspaces.\n\nTemplates are reusable workspace configurations \u2014 workflow definitions, field setups, and optionally apps. The relevant tools:\n- publish_marketplace \u2014 publish a template (type:'template') or app (type:'app') to the marketplace.\n- browse_marketplace \u2014 browse listings, get listing details, and read an app's manifest.\n- install_marketplace \u2014 install a marketplace template or app into a workspace.\n\nFor a new marketplace app listing, the versionId/targetId comes from npm run publish-production -- --market --force (it is saved to public/manifest.json); then call publish_marketplace with type:'app' to list it.\n\nMarketplace submissions must include a complete metadata bundle (title, description, version, version description, publisher, icon file ID); a publish guard hook enforces this before anything is sent.\n\n#### Marketplace publishing requirements and recommended skills\n\nMarketplace submissions must include the following metadata. The publish guard hook validates each field before submission:\n\n- title \u2014 required, max 64 characters.\n- description \u2014 required, max 4096 characters.\n- version \u2014 semantic version (for example, '1.0.0').\n- versionDescription \u2014 release notes.\n- publisher \u2014 company or person name.\n- iconFileId \u2014 24-character file ID for the app icon.\n\nWhen building apps, sub-agents should load the relevant skills for context:\n\n- hailer-app-builder \u2014 React patterns, @hailer/app-sdk hooks, component patterns.\n- hailer-design-system \u2014 Chakra UI theme, colors, icons, layout, responsive design.\n- hailer-apps-pictures \u2014 fetching and displaying images stored in Hailer.\n- create-and-publish-app \u2014 CLI-based scaffold and publish via the @hailer/create-app npm package.\n\n### Getting Started\n\n#### Installing and running @hailer/mcp\n\nHailer MCP is published on the public npm registry as @hailer/mcp. There are two common ways to use it:\n\nInstall and run as a global CLI:\n```bash\nnpm install @hailer/mcp\nnpx @hailer/mcp\n```\n\nOr run directly with npx without a global install:\n```bash\nnpx @hailer/mcp --port 3030\n```\n\nBy default the server starts on http://localhost:3030. The default port can be overridden with the PORT environment variable or the --port flag.\n\nBefore the server can talk to Hailer it needs at least one configured account. Provide a CLIENT_CONFIGS environment variable that maps an API key (used by your MCP client) to a Hailer account (used to call Hailer). One CLIENT_CONFIGS entry covers a single account; you can list more than one to support multiple accounts on the same server.\n\n#### Connecting Hailer MCP to Claude Code\n\nOnce the server is running locally on http://localhost:3030 you can attach it to Claude Code with the claude CLI:\n\n```bash\nclaude mcp add hailer npx mcp-remote \"http://localhost:3030/api/mcp?apiKey=your-api-key\"\n```\n\nThe apiKey query parameter must match a key you defined in CLIENT_CONFIGS \u2014 the server uses it to look up which Hailer account to authenticate as.\n\nAfter this, Claude Code will see all 71 Hailer MCP tools (activity, workflow, discussion, insight, app management) the next time it lists tools. Common tools include list_activities, create_activity, describe_workflows, add_discussion_message, and the SQL-style insight tools.\n\nIf you use Claude Desktop instead of Claude Code, prefer the OAuth flow at /api/cowork/oauth/* \u2014 it logs you into your real Hailer account rather than reusing a service-account key.\n\n#### Tools you get out of the box\n\nAfter connecting Hailer MCP to your AI client, the available tools are grouped by domain:\n\n- Activity tools \u2014 create, read, update, list activities. Bulk operations are supported. Phase transitions go through update with the new phase ID.\n- Workflow tools \u2014 manage workflows, fields, phases, and inspect workflow schemas. These are how you discover what fields exist on a workflow before you start writing data.\n- Discussion tools \u2014 chat and messaging within activities. Read messages, send messages, join or leave discussions, invite users.\n- Insight tools \u2014 SQL-like reporting over workflow data. You can preview a query, save it as an insight, and read the results.\n- App tools \u2014 Hailer app sharing (manage_app) and marketplace operations (publish_marketplace, browse_marketplace, install_marketplace). Scaffolding and publishing are script-only (npx @hailer/create-app and npm run publish-production -- --force) \u2014 there are no MCP tools for those.\n- Workspace tools \u2014 initialize workspace data once per session, search users, manage teams and groups.\n\nNot every tool is available to every account \u2014 the tool registry filters tools by the access groups granted to the API key in use.\n\n### hailer-studio\n\n#### What Hailer Studio is \u2014 the SDK workspace experience in the cloud\n\nHailer Studio is the cloud-hosted version of the Hailer SDK workspace-configuration experience. To understand it, start with the SDK.\n\nThe Hailer SDK (@hailer/sdk on npm) lets you initialise a Hailer workspace as a code project. Instead of clicking through the website UI to create workflows, fields, and phases, you define the workspace configuration in code, then push changes with CLI commands. The workspace is shaped from code rather than from the UI \u2014 'workspace as code', which you can version, diff, and review.\n\nHailer Studio takes that exact experience and puts it in the cloud, so there is no local setup. When a user starts a Studio session, they get:\n- An initialised Hailer SDK project, already set up in the cloud \u2014 no npm install, no local toolchain.\n- An AI agent, already initialised, that the user talks to through Hailer's chat. The agent comes pre-loaded with instructions on how to manipulate the configuration code and run the CLI commands that push changes to the workspace.\n\nTwo ways to edit your workspace configuration in Studio:\n1. The built-in code editor in the Studio frontend \u2014 edit the SDK project's configuration files directly, like an IDE in the browser.\n2. The AI agent \u2014 describe the change in chat ('add a priority dropdown to the support workflow', 'split the Done phase into Resolved and Archived'), and the agent edits the code and runs the CLI command to apply it.\n\nHow Studio relates to the other surfaces:\n- vs the in-workspace Hailer Helper bot: the Helper makes runtime changes through the MCP tools (create a workflow, add a field, create activities) against a live workspace. Studio is the config-as-code path \u2014 you edit the SDK project and push, closer to how a developer evolves a system. The Helper operates inside a workspace; Studio shapes the workspace's structure as code.\n- vs the local SDK flow: Studio is the same SDK project model, just hosted in the cloud with a browser code editor and a chat-driven AI agent instead of a local terminal. A developer who prefers their own machine can still use @hailer/sdk locally; Studio is for people who want the code-based workflow without local setup.\n- vs Hailer Apps: Apps are custom React / Svelte / vanilla applications that run inside Hailer. Studio is about workspace configuration (workflows, fields, phases), not about building front-end applications. Do NOT describe Studio as an 'app builder' \u2014 that conflates it with the Apps SDK, which is a different surface.\n\nWho it is for: workspace admins and developers who want code-based, reviewable, AI-assisted control over their workspace structure \u2014 without installing the SDK toolchain locally. It suits technical users and teams who treat their workspace as something to version and evolve deliberately, rather than click together ad hoc.\n\nOne-liner pitch: Hailer Studio is the Hailer SDK experience in the cloud \u2014 a code-configured workspace plus an AI agent that edits the config and runs the CLI for you, no local setup required.\n\nGraduation-flow note: the 'Continue in Hailer' pathway pre-warms a Studio session for the new user, so they can land in a ready-to-go cloud SDK project with the AI agent already initialised. This is why a visitor who graduates may encounter Studio as well as the in-workspace Helper.\n\n### MCP Server\n\n#### What the Model Context Protocol (MCP) is\n\nThe Model Context Protocol (MCP) is an open standard that lets AI assistants call tools on external systems. Instead of the AI guessing or asking the user to copy-paste data, it can directly query databases, create records, and perform actions through a structured tool interface.\n\nThe Hailer MCP server implements MCP over HTTP using JSON-RPC 2.0, making Hailer's full API accessible to any MCP-compatible client (Claude Code, Claude Desktop, and others). The server is an Express.js application; the main entry point is the MCPServerService class.\n\n#### MCP server endpoints and what each is for\n\nThe Hailer MCP server exposes these HTTP endpoints:\n\n- /api/mcp \u2014 main MCP endpoint for direct API key access.\n- /api/cowork/mcp \u2014 MCP endpoint for OAuth-authenticated sessions (used by Claude Desktop's native connector).\n- /api/vipunen \u2014 Vipunen RAG tools (no Hailer auth required).\n- /health \u2014 health check.\n- /.well-known/oauth-authorization-server \u2014 OAuth 2.0 metadata (RFC 8414).\n- /.well-known/oauth-protected-resource \u2014 OAuth Protected Resource Metadata.\n- POST /api/cowork/oauth/register \u2014 Dynamic Client Registration (RFC 7591).\n- /api/cowork/oauth/* \u2014 OAuth flow (authorize, token, callback).\n- POST /api/cowork/auth/register \u2014 register a Hailer API key session, called by the frontend after login.\n- POST /:apiKey \u2014 alternative API key as path parameter.\n\nMost integrations only need /api/mcp (direct API key) or the OAuth endpoints under /api/cowork.\n\n#### JSON-RPC 2.0 protocol used for tool discovery and execution\n\nAll MCP tool communication uses JSON-RPC 2.0. There are two main calls:\n\nTool discovery (tools/list):\n```json\n{ \"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"tools/list\" }\n```\nThe response returns an array of tools, each with a name, description, and JSON Schema for its arguments.\n\nTool execution (tools/call):\n```json\n{\n \"jsonrpc\": \"2.0\", \"id\": 2, \"method\": \"tools/call\",\n \"params\": {\n \"name\": \"list_activities\",\n \"arguments\": { \"workflowId\": \"<id>\", \"limit\": 10 }\n }\n}\n```\n\nResponses follow MCP's content-array format:\n```json\n{ \"jsonrpc\": \"2.0\", \"id\": 2, \"result\": { \"content\": [{ \"type\": \"text\", \"text\": \"...\" }] } }\n```\nThis is what every Hailer MCP tool returns.\n\n#### Authentication: direct API key, OAuth 2.0 with PKCE, pre-configured accounts\n\nThe Hailer MCP server supports three authentication methods:\n\n1. Direct API key (simplest) \u2014 pass the Hailer API key as a query parameter, e.g. POST /api/mcp?apiKey=your-hailer-api-key. Used by Claude Code via the mcp-remote bridge.\n\n2. OAuth 2.0 with PKCE \u2014 for Claude Desktop and other MCP clients that support OAuth. The flow:\n - Client discovers OAuth metadata at /.well-known/oauth-authorization-server.\n - Client redirects the user to /api/cowork/oauth/authorize.\n - User logs into Hailer and selects a workspace.\n - Hailer redirects back with an authorization code.\n - Client exchanges the code for an access_token at /api/cowork/oauth/token.\n - Client sends the access_token in an Authorization: Bearer header.\nThe real Hailer API key stays server-side in the session store; the client only ever sees a key_id.\n\n3. Pre-configured accounts (CLIENT_CONFIGS) \u2014 service accounts defined in the environment as a JSON map of API key \u2192 account credentials. This is the most common setup for development and production deployments.\n\n#### Session management: max TTL, inactivity TTL, cleanup\n\nOAuth sessions in the MCP server have two expiry rules running in parallel:\n\n- Max TTL: 24 hours absolute lifetime. After this the session is gone regardless of activity.\n- Inactivity TTL: 30 minutes; resets on each use.\n\nA session record stores: { apiKey, workspaceId, createdAt, lastAccessedAt }. A cleanup job runs every 5 minutes to remove expired sessions.\n\nThis dual-TTL design means active users stay logged in for the full 24 hours but abandoned tabs lose their session quickly \u2014 which is the right trade-off for a tool with backend write access. The implementation lives in src/mcp/session-store.ts.\n\n#### User context: what every authenticated request gets\n\nEvery authenticated MCP request gets a UserContext object containing the data tools need:\n\n- client: HailerClient \u2014 socket/REST connection.\n- init: full workspace data (workflows with fields and phases, all workspace users, team and group definitions, workspace metadata).\n- workspaceCache: structured lookups for fast access.\n- hailer: API call wrapper.\n- apiKey: identifier.\n- createdAt: session creation timestamp.\n- email, password: credentials for session renewal.\n- workspaceRoles: a per-workspace role map.\n- currentWorkspaceId: the active workspace.\n- allowedGroups: tool access groups for this session.\n\nThe init data is fetched once via v2.core.init and cached for 15 minutes per API key, so subsequent tool calls are fast \u2014 they read from cache instead of calling Hailer again. This is implemented in src/mcp/UserContextCache.ts.\n\n#### Tool registry, tool definition pattern, and tool lifecycle\n\nThe tool registry manages MCP tool lifecycle in three stages:\n\n- Registration (startup): app.ts imports allTools and registers each with Core, which passes them to the ToolRegistry.\n- Discovery (tools/list): the registry returns tool names, descriptions, and JSON schemas. Nuclear (destructive) tools are excluded unless ENABLE_NUCLEAR_TOOLS=true.\n- Execution (tools/call): the registry looks up the tool by name, validates arguments with the Zod schema, pre-transforms common LLM mistakes (e.g., converting an array into the expected object), then calls tool.execute(validatedArgs, userContext) and returns the MCP response.\n\nEvery tool follows this pattern:\n```typescript\nexport const myTool: Tool = {\n name: 'my_tool_name',\n group: ToolGroup.READ,\n contextType: 'hailer',\n description: 'What this tool does',\n schema: z.object({\n requiredParam: z.string().describe('What this param is'),\n }),\n async execute(args, context: UserContext) {\n const result = await context.hailer.request('v3.some.method', [args.requiredParam]);\n return { content: [{ type: 'text', text: `Result: ${JSON.stringify(result)}` }] };\n },\n};\n```\n\n#### MCP server error handling and configuration\n\nThe server handles errors at multiple levels: schema validation (Zod catches invalid inputs before execution), pre-transformation (fixes common LLM formatting mistakes), tool-level try/catch, response builder (standardized error formatting with isError: true), and request-logger HTTP-level error tracking.\n\nError responses include helpful context so the AI can self-correct, for example:\n```json\n{ \"content\": [{ \"type\": \"text\", \"text\": \"Error: workflowId is required. Available workflows: ...\" }], \"isError\": true }\n```\n\nAll server configuration flows through a single Zod-validated config: environment variables \u2192 Zod validation \u2192 ApplicationConfig instance. Key settings:\n\n- PORT \u2014 server port (default 3030).\n- NODE_ENV \u2014 environment mode (default development).\n- CLIENT_CONFIGS \u2014 required JSON map of API key \u2192 account credentials.\n- CORS_ORIGINS \u2014 allowed origins; an empty array means allow all.\n- ENABLE_NUCLEAR_TOOLS \u2014 show destructive tools (default false).\n- DISABLE_MCP_SERVER \u2014 skip server startup (default false).\n- WORKSPACE_CONFIG_PATH \u2014 path to local workspace files (optional).\n- DEV_APPS_PATH \u2014 path for scaffolded apps (optional).\n\n### rest-api-and-webhooks\n\n#### REST API surface: auth, field types, webhooks, iCal feed, and Excel import\n\nHailer exposes a REST API for programmatic access. This chunk is the developer-archetype reference. The MCP server (covered in its own chunks) is a higher-level surface that wraps these REST calls for AI agents; this chunk is for engineers who want to call Hailer directly.\n\nAPI entry point:\n- Base URL: `https://api.hailer.com/api/` (substitute the right host for self-hosted or staging deployments).\n- Operator pattern: every endpoint is `/api/<operator>` where the operator is a versioned dotted name, e.g. `v3.activity.list`, `v3.activity.create`, `v2.forms.process.get`. The operator name lives in the URL path, not as a JSON-RPC method body.\n- Methods: GET for reads (args URL-decoded from the query string), POST for writes (JSON body). Max request body size is 20 MB.\n- API versioning: most modern endpoints are v3; some legacy endpoints are still v2. There is no v1 surface to worry about.\n\nAuthentication:\n- User API keys are the primary auth for programmatic access. A workspace admin generates a key in account settings; the key is bcrypt-hashed server-side.\n- Send keys either as `Authorization: Bearer <key>` or as the `hlrkey` header \u2014 both are accepted.\n- Per-key IP whitelisting is supported: when a key has an IP whitelist set, requests from any other IP are rejected. Useful for hardening server-to-server integrations.\n- Session cookies are also accepted (the regular login session) for browser callers.\n\nWebhooks (outbound):\n- Webhooks are configured per workflow phase, not per workspace. On the workflow's phase settings, an admin sets `webhooksEnabled: true` and a `webhookUrl` (multiple URLs by regex match are supported in one phase).\n- They fire when an activity is created in that phase or moves into that phase. Hailer POSTs an activity-state payload to the configured URL(s). Failed sends are queued and retried.\n- This is the integration path most Hailer customers use today for outbound notifications and downstream automations.\n\nField type catalog (what kinds of fields workflows can have):\n- Text: `text`, `textarea`, `textunit` (text with a unit suffix), `textpredefinedoptions` (dropdown).\n- Numbers: `numeric`, `numericunit`.\n- Time: `date`, `datetime`, `time`, `daterange`, `timerange`, `datetimerange`.\n- People: `users`, `teams`.\n- Geographic: `country`.\n- Cross-workflow: `activitylink` (reference activities in another workflow), `linkedfrom` (backlink \u2014 automatically populated from activitylinks pointing at this activity; valid only in the process schema, not as a user-set value).\n- Structural: `subheader` (groups fields visually; not user-data; valid only in the process schema).\n- Calculated: any field type above can be turned into a calculated/function field by setting `function` (JavaScript code) and `functionEnabled: true`. The function runs server-side in an isolated VM.\n\nExcel/CSV import:\n- Activity bulk-import endpoint: `v3.activity.import`. Hailer expects an XLSX file with workflow ID, phase ID, and column headers in specific cells (documented in Hailer's help center). The endpoint returns the count of created activities and any per-row errors. A separate bulk-user-invite Excel flow lives in workspace settings.\n\niCal calendar feed:\n- Personal iCal subscription URL: `https://api.hailer.com/ical/{subscribe_code}` (subscribe code is a per-user token generated in calendar settings). Output is RFC 5545 compliant \u2014 paste the URL into Gmail/Outlook/Apple Calendar and Hailer events show up.\n\nWhat Hailer does NOT have (be honest):\n- No first-party GraphQL or OData. REST + webhooks is the surface.\n- No public rate-limit table; if a visitor needs a hard SLO commitment, recommend they talk to the Hailer team.\n- No Postman collection shipped publicly; describe operators by name and point at the help center.\n- Zapier integration exists, but it's a Zapier-side app that calls this REST API \u2014 not a separate backend feature inside hailer-api.\n\n## Legal & Privacy\n\n### demo-chat-privacy\n\n#### What happens to your demo conversation\n\nIf a visitor asks 'where does this chat go?', 'is this conversation kept?', 'do you train on this?', or anything in that family \u2014 the answer is in this section. This is a plain-English summary of the demo-chat handling, in addition to (not instead of) Hailer's formal Privacy Policy.\n\nThe demo chat on the Hailer login page:\n- Is anonymous. We do not collect the visitor's name, email, or contact info during the chat. There is no signup gate to begin chatting.\n- Is stored server-side under an anonymous session ID generated in the browser. This session ID is the only identifier tied to the conversation; the visitor can clear it by clearing their browser's localStorage.\n- Is used in one of two ways: (a) to let the bot answer follow-up questions in the same conversation, and (b) if the visitor clicks 'Continue in Hailer' and creates a Hailer workspace, to give the new Hailer Helper bot in that workspace context about what was discussed (the 'seed context'). Without 'Continue in Hailer', the chat is never linked to a Hailer account.\n- Is sent to Anthropic's Claude API in order to generate the bot's replies. Anthropic processes the conversation under their published data-use terms; Anthropic does not train on API content by default.\n- Is not used to train Hailer's own models. We do not have first-party AI models \u2014 the chat is processed by Anthropic for replies and stored locally for handoff. We do not sell or share the conversation contents with third parties.\n- Has a server-side retention limit. The in-memory store the demo uses is cleared when the server restarts; a longer-lived store, if introduced later, will retain conversations for a short window (3 days planned) before purging.\n\nIf the visitor wants their demo chat deleted before retention expires, or wants a copy of the data, they can contact privacy@hailer.com with the session ID (visible in the browser's localStorage as `hailerPublicChatSessionId`).\n\n### Privacy Policy\n\n#### Privacy Policy overview, data controller, and structure\n\nHailer's Privacy Policy covers what information Hailer collects when you use the products or services or otherwise interact with the company (for example by attending events or communicating with Hailer staff), unless a different policy is displayed.\n\nData controller: Hailer Oy, business ID 2772571-4, Rihkamatori 2, Porvoo, Finland. All inquiries regarding the Privacy Policy should be directed to privacy@hailer.com.\n\nIf you do not agree with the policy, you should not access or use Hailer services or interact with any other aspect of the business.\n\nThe policy is split into two sections: (1) how the Hailer Application collects and processes your data, and (2) how the Hailer website and social-media channels collect and process your data. The full policy is published at https://app.hailer.com/#/privacy-policy.\n\n#### Hailer Application \u2014 what data is collected\n\nSection 1 of the Privacy Policy covers the Hailer Application, which means any of: (1) the web client at app.hailer.com, (2) the Hailer Android app, (3) the Hailer iOS app, and (4) Hailer API users.\n\nWhat data is collected:\n\n- To use the service and identify the user, certain data has to be collected for the service to be functional. This data includes (but is not limited to) email address, full name, and any other data inserted into the application.\n- Payment and billing information is collected when you register for certain paid services \u2014 for example, payment card details, which are collected via secure payment processing services.\n- Some information is collected automatically, including (but not limited to) the type of mobile device you use, your mobile device's unique device ID, the IP address of your mobile device, your mobile operating system, the type of mobile internet browser you use, and information about how you use the Application.\n\n#### Hailer Application \u2014 how the data is used; end-user note\n\nHow Hailer uses the data it collects (Application section):\n\nHailer uses data and collective learnings (including feedback) about how people use the application to troubleshoot, identify trends, usage and activity patterns, find areas for integration and product improvement, and develop new products, features, and technologies that benefit users.\n\nImportant note for end users of organization workspaces:\n\nMany Hailer products are intended for use by organizations. When the services are made available to you through an organization (for example, your employer), that organization is the administrator of the workspace and is responsible for it. In these cases, direct your data-privacy questions to your administrator \u2014 your use of the services is subject to that organization's policies. Hailer is not responsible for the privacy or security practices of an administrator's organization, which may differ from Hailer's policy.\n\n#### Hailer subprocessors \u2014 infrastructure and third-party services\n\nHailer uses Amazon Web Services (AWS) infrastructure for providing the Hailer cloud service. The server infrastructure is located in the EU and AWS is committed to handle all data traffic compliant with EU data protection legislation (see the AWS GDPR DPA at https://d1.awsstatic.com/legal/aws-gdpr/AWS_GDPR_DPA.pdf).\n\nData residency specifics: all Hailer infrastructure runs in the AWS eu-west-1 region, located in Ireland. The MongoDB database is hosted in the same region. Every workspace's data resides there \u2014 there is currently no option to choose a different region or to pin a workspace to another location. So data residency is EU (Ireland) for all customers by default, but customer-selectable region / data residency is not offered today.\n\nFull list of Hailer subprocessors:\n\n- Amazon Web Services (AWS) \u2014 server infrastructure; all Hailer data.\n- MongoDB Atlas (MongoDB Inc.) \u2014 databases; all Hailer data.\n- Mailgun (Mailgun Technologies, Inc.) \u2014 sending email from Hailer; email address, name, password reset and invitation links.\n- Splunk (Splunk Inc.) \u2014 server log management; infrastructure logs.\n- Apple Push Notification Service / APN (Apple) \u2014 sending push notifications; push notification content and metadata to Apple devices.\n- Firebase Cloud Messaging / FCM (Alphabet Inc.) \u2014 sending web push notifications; push notification metadata and content to web clients.\n- Stripe \u2014 online payments; client payment information.\n- Creamailer (Creamailer Oy) \u2014 newsletters; email address and name.\n\n#### Hailer website and social media \u2014 data collection and use\n\nSection 2 of the Privacy Policy covers Hailer's website and social-media channels.\n\nWhat data is collected:\n\nHailer collects information you input into the website, social-media accounts, or provide directly through other communications. Website visitors are the primary source of personal, company, and technical information \u2014 including registration data, contact information, and anything else provided through Hailer's digital assets. Some information also comes from third-party platforms (advertising platforms, content on third-party sites, social networks).\n\nHow the data is used:\n\nProcessing is based on Hailer's legitimate interest to ensure the functionality and security of the website and to provide information and services to data subjects visiting Hailer's digital assets. Personal data is also processed to develop and customize the website content for people interested in Hailer's products and services.\n\nContact details collected through web forms include: name, email address, telephone number, interest in the system, and the company you work for.\n\n#### Your rights, data disclosure cases, and policy changes\n\nDisclosure of user information may happen in these specific cases:\n\n- As required by law (for example, to comply with a subpoena or similar legal process).\n- When Hailer believes in good faith that disclosure is necessary to protect its rights, protect your safety or the safety of others, investigate fraud, or respond to a government request.\n- With trusted service providers acting on Hailer's behalf. These providers don't have independent use of the information and have agreed to follow the rules in the privacy statement.\n- If Hailer is involved in a merger, acquisition, or sale of all or part of its assets, users will be notified by email and/or a prominent notice on the website about ownership changes or new uses of the information, and any choices users have.\n\nYour rights:\n\nYou have the right to request a copy of your information, object to its use (including for marketing), request deletion or restriction of your data, or request your information in a structured electronic format. Submit requests to privacy@hailer.com.\n\nHailer may decline requests that are unreasonably repetitive, systematic, technically disproportionate, conflict with others' privacy, are extremely impractical, or where access is not legally required. Some data may be retained as needed to comply with legal obligations, resolve disputes, or in backups. For website-form data you can opt out manually at any time.\n\nPolicy changes:\n\nHailer can update the privacy policy when the methods or purposes of processing change. New versions are posted on the privacy-policy page and users are informed by email.\n\n## Product & UI\n\n### customer-stories\n\n#### Customer story \u2014 Viestint\u00E4 Ruuti (communications agency, Lahti, Finland)\n\nViestint\u00E4 Ruuti Oy is a content-marketing and communications agency in Lahti, Finland. The story below is summarised from the published customer reference at hailerreferences.com/tarinat/viestinta-ruuti.html (Finnish-language original; quotes translated). Use it when a visitor's situation resembles theirs.\n\nThe company:\n- Founded by CEO Riina Kruut.\n- Grew from a one-person operation to a five-person core team plus a freelancer network over roughly five years.\n- Services include social-media management, expert branding, training, and strategic communications planning.\n- Multi-client agency model \u2014 each client comes with its own scope, billing structure, and stakeholders.\n\nThe pain before Hailer:\n- Client information was scattered across Excel spreadsheets, PowerPoint slides, Word documents, and sticky notes.\n- Hour tracking was difficult because each client had its own billing structure \u2014 different rates, different recurring/one-off arrangements, different reporting expectations.\n- As the team grew from one person to five, the founder could no longer hold all the client context in her head, and the existing tools didn't give her a clean way to verify what work had been done before invoicing.\n- Quote (translated): 'Various client relationships and billing structures caused challenges in keeping up with hour tracking.'\n\nHow they use Hailer today:\n- One central place for all client data \u2014 contact details, billing arrangements, account credentials, project notes.\n- Hour and project tracking \u2014 team members log hours per client and project monthly; the founder can verify exactly what work was done before sending invoices.\n- Internal communication tied to the work \u2014 conversation threads attach to the relevant client or project record, alongside notes, billing changes, and responsibility assignments.\n- Project documentation lives on the record, so the founder no longer has to chase teammates for status updates.\n\nConcrete outcomes:\n- Visibility she trusts: 'If I didn't have clarity on who worked where and how much, I couldn't manage billing responsibly.' Hailer gave her that clarity.\n- Less management overhead \u2014 instead of asking team members what they did, the founder can see the logs and confirm work was done.\n- Cleaner billing \u2014 the agency and its clients both benefit from documented deliverables and hours, reducing back-and-forth at invoicing time.\n- Scalability foundation \u2014 growing from one person to five with multiple complex billing structures only worked because client info, hours, and conversations all lived in one place.\n- Quote (translated): 'All client-related matters are always found in one place.'\n\nWhen this story is the right one to reach for:\n- Visitor is running an agency, consultancy, or any client-services business with multiple clients and per-client billing variation.\n- Visitor mentions time tracking, hour logs, billing accuracy, or invoicing as a pain.\n- Visitor describes information scattered across spreadsheets, slide decks, docs, sticky notes, or email threads.\n- Visitor is at the 'I can't hold it all in my head anymore' moment \u2014 typically 3\u201310 people, growing.\n- Visitor mentions freelancers or contractors alongside core team \u2014 the agency context resonates.\n\nHow to use it in the chat:\n- Don't read the case study back as a brochure. Pull the one or two threads that match what the visitor just told you and connect those to their situation.\n- Lead with the pain the visitor named ('scattered info', 'never sure what was actually done before billing'), then mention that a Finnish agency hit the same wall growing from one person to five, and tell them what Hailer changed for that agency.\n- Reference is publicly published, so naming Viestint\u00E4 Ruuti and Riina Kruut is fine. Don't fabricate detail beyond what's in this chunk \u2014 the original story is short, and embellishment is the fastest way to lose credibility.\n- If a visitor asks for more customer stories from other industries, be honest: this is the one with a published reference today; more are coming.\n\n### demo-apps-page\n\n#### What the demo's Apps page shows \u2014 and what's real vs. illustrative\n\nThe interactive Hailer demo at /demo has an Apps page (reached via the left nav 'Apps' button). It mocks the Hailer apps surface \u2014 two sections, 'Installed' and 'Marketplace' \u2014 with six tiles. The tiles are visually rich and clickable, but the demo is read-only and the page is a mock-up, NOT a real apps catalogue. Some tiles correspond to real Hailer surfaces; others are illustrative examples invented to make the marketplace concept tangible.\n\nWhen a visitor asks 'what does X do?' for one of these tiles, answer honestly using the table below. Do NOT promise that the illustrative ones ship today.\n\nInstalled tiles:\n- AI Hub \u2014 REAL. Hailer ships an AI Hub surface in every workspace for managing AI agents (bots), their system prompts, the people they can talk to, and token usage. The in-workspace Hailer Helper bot is one such agent. After 'Continue in Hailer' the visitor can find AI Hub in their real workspace.\n- Document Templates \u2014 REAL feature, packaged as an app for demo clarity. Hailer's PDF/document generator turns activity data into offers, invoices, certificates, and other structured documents using the same function-field engine that powers calculated fields. The 'Document Templates' name is the demo's framing; in production this lives inside the workspace's template configuration rather than as a standalone marketplace app.\n\nMarketplace tiles (all ILLUSTRATIVE \u2014 none of these ship as named apps today, but each represents a pattern Hailer supports):\n- Customer Portal \u2014 ILLUSTRATIVE. Hailer does support public web forms that create activities in a workflow (the publicForm feature). Branding it as a 'Customer Portal' app is the demo's shorthand for that capability.\n- Equipment Inventory \u2014 ILLUSTRATIVE. Represents the dataset pattern (a single-phase or Active/Archived workflow used as a reference list). A user could build this themselves; it's not a one-click install.\n- Slack Bridge \u2014 ILLUSTRATIVE. Hailer's first-party Slack story is the Zapier integration (Zapier triggers Slack messages from Hailer events). There is no purpose-built 'Slack Bridge' app today.\n- Stripe Receipts \u2014 ILLUSTRATIVE. Combines automation (phase-change triggers) and document generation patterns Hailer does support, but there's no shipping Stripe-specific app.\n\nHow to answer typical questions:\n- 'Can I install Slack Bridge?' \u2014 'That tile is illustrative. Hailer's Slack story today is the Zapier integration, which can post Slack messages from Hailer events.'\n- 'What's AI Hub?' \u2014 'AI Hub is the real surface where you manage your workspace's AI agents \u2014 including the Hailer Helper bot that gets provisioned when you Continue in Hailer.'\n- 'Can I build my own apps like these?' \u2014 'Yes. Apps are built with the Hailer Apps SDK (React, Svelte, vanilla, etc.) or scaffolded by an AI agent via the @hailer/mcp tools. The marketplace lets you publish them to other workspaces.'\n- 'How do I get an app for my [specific use case]?' \u2014 Recommend the route honestly: 'For something custom, scaffold a Hailer App with the SDK or ask the in-workspace Helper to scaffold one. For a configuration-only solution (workflow + fields + a function field generating documents), describe it to the in-workspace Helper after you Continue in Hailer.'\n\nKey rule: if the visitor seems to assume these are all shippable apps they can install today, gently correct that \u2014 Hailer apps are mostly something teams build (or commission), not a fully populated marketplace. The deck's Apps & Studio slide ('apps-studio' slide id) explains this in the broader story.\n\n### Frequently Asked Questions\n\n#### Trial, integrations, and data import/export\n\nFrequently asked questions from the Hailer help site:\n\nCan I test Hailer for free?\nYes. Every new Hailer workspace starts with full Hailer functionality and a starter AI token grant for trying the AI features. Token consumption applies only to AI-driven operations \u2014 chats with the in-workspace Hailer Helper, AI Hub bots, and MCP-driven AI sessions. Creating activities, using kanban, the calendar, discussions, and everything else in the regular Hailer UI does not consume from this budget. When the AI token balance runs low, the workspace owner can top up via the billing area. For the current grant size and rough estimates of what it covers, see the 'How Hailer's free AI token grant works' chunk \u2014 that chunk is the single source of truth for the grant figure; do not quote a number from this FAQ.\n\nWhat integrations does Hailer have?\nHailer currently offers a Zapier integration and a REST API. Through a Zapier workflow you can create a new Hailer activity or update an existing one, create a new calendar event, upload files, or create a new wall post on the feed.\n\nCan I import data from old systems to Hailer? What about export?\nYes. You can do an Excel import in a few minutes, or export your data out the same way.\n\n#### Calendar sync, custom workflows, and public forms\n\nMore frequently asked questions from the Hailer help site:\n\nCan I sync Hailer events to Gmail or another calendar?\nYes. You can sync Hailer events to your Gmail or Office account using an iCal link.\n\nCan I create a custom workflow for my business?\nYes. You can create any type of workflow or process in Hailer. A few ready-made templates are available, and if none fit your needs you can easily build a custom workflow from scratch.\n\nI want to collect data from external persons \u2014 is that possible?\nYes. Workspace admins can enable a public form on any workflow or dataset. This produces a web form whose link you can embed in a webpage or share wherever you need to gather data from people outside the workspace.\n\n### free-tier-tokens\n\n#### How Hailer's free AI token grant works\n\nMAINTAINER NOTE \u2014 this chunk is the single source of truth for the AI token grant figure. The faq.json and graduation.json chunks deliberately do NOT quote the number; they cross-reference here. When the backend changes the grant, update ONLY this chunk and the corpus stays coherent.\n\nEvery new Hailer workspace gets an AI token grant at signup. The current grant is 1500 tokens \u2014 this number is set on Hailer's backend and may change in the future, so always describe it as 'the current signup grant' rather than a permanent figure.\n\nWhat tokens are spent on:\n- Conversations with the in-workspace Hailer Helper bot.\n- AI Hub bots running on behalf of the workspace.\n- MCP-driven AI sessions (e.g. Claude Code connected to the workspace).\n- Function-field execution \u2014 calculated fields run sandboxed JavaScript, and each execution draws from the same token bucket. Function fields evaluated at scale (long lists, frequent re-calculation, heavy data) can therefore consume meaningful tokens on their own.\n\nWhat does NOT spend tokens:\n- Creating, updating, or moving activities through the regular Hailer UI.\n- Sending discussion messages to other humans.\n- Calendar entries, feed posts, file uploads.\n- Reading existing activity data that doesn't trigger a function-field recompute.\n\nHow the meter works:\n- Tokens are 'output-normalized' \u2014 Hailer converts every kind of AI usage to an equivalent number of model-output tokens before deducting. The default underlying model is Claude Haiku 4.5.\n- A typical single bot turn (the user asks something, the bot reads context and replies) costs roughly 500 to 1000 normalized tokens depending on how long the user's question and the bot's reply are. A modest reply costs around 700 tokens.\n- Turns that involve tool use (the bot creating a workflow, adding fields, creating activities, fetching data) can cost more per turn because the bot does more work inside one response.\n\nWhat 1500 tokens covers, roughly, at the current rate:\n- About two substantive back-and-forth chats with the Hailer Helper. Enough for a 'set up my workspace' conversation or a couple of follow-up questions.\n- Or one moderately complex workflow-creation request that involves multiple tool calls in a single turn.\n- Or a handful of short prompts like 'add an activity for Acme Deal' if the bot's replies stay brief.\n\nThese estimates are approximate and depend heavily on prompt length, model choice, and how much tool use the bot does. A workspace running heavier AI features (Sonnet instead of Haiku, very long prompts, deep multi-turn tool chains) will burn through 1500 tokens faster.\n\nWhen the balance runs low:\n- Below 100 tokens, the system flags the workspace as 'LOW'. The bot continues to respond and function fields continue to run.\n- At zero or negative, two things pause: (a) AI features stop generating responses (Helper bot, AI Hub bots, MCP-driven AI sessions) and (b) function-field execution halts \u2014 calculated fields stop recomputing until the workspace tops up.\n- The rest of manual Hailer use keeps working \u2014 creating and moving activities through the UI, posting discussion messages to other humans, calendar entries, feed posts, file uploads. Only AI features and function-field execution are gated by the token balance.\n\nTo top up, the workspace owner uses the billing area of Hailer. Top-ups work on an on-use / pay-as-you-go basis \u2014 purchase additional tokens as needed rather than committing to a fixed monthly bucket. The 1500-token grant is a starter allotment, not a permanent free quota.\n\n### graduation\n\n#### What the 'Continue in Hailer' button does\n\nOn the Hailer login page, the 'Continue in Hailer' button (also shown as 'I've verified \u2014 finish setup' after a fresh signup confirms their email) signs the visitor up for a free Hailer workspace and provisions a Hailer Helper bot inside it before the user even lands in Hailer.\n\nThe flow:\n1. The visitor clicks 'Continue in Hailer'.\n2. They sign up (or sign in if returning) and confirm their email.\n3. A free workspace is created for them \u2014 full Hailer functionality, plus the standard signup AI token grant for trying out the AI features. See the 'How Hailer's free AI token grant works' chunk for the current grant figure; that chunk is the single source of truth \u2014 do not quote a number from here.\n4. An 'Agent Directory' workflow is installed in that workspace if it isn't already.\n5. A bot activity is created in the Deployed phase \u2014 this becomes the workspace's Hailer Helper.\n6. The bot's Hailer account is auto-provisioned with admin permissions in the workspace.\n7. The conversation the visitor had with the demo bot on the login page is carried forward as context \u2014 the new Helper's first message references what they discussed.\n8. The visitor lands directly inside the Helper's discussion in Hailer, with the welcome message already posted.\n\nThe whole flow typically completes in a few seconds. The visitor never has to paste an API key or configure anything \u2014 the authorize step is one click. The Helper's first replies will use a small portion of the workspace's AI token grant; see 'How Hailer's free AI token grant works' for the math.\n\n#### What the post-signup Hailer Helper bot does in a workspace\n\nThe Hailer Helper bot that gets provisioned by the 'Continue in Hailer' flow is the user's starter assistant in their brand-new workspace. It has admin-level permissions and inherits the demo conversation as context.\n\nWhat it can do today:\n- Read and understand the workspace's structure (workflows, phases, fields, teams, users) using the standard Hailer MCP toolset.\n- Create workflows tailored to what the user described in the demo chat \u2014 sales pipelines, project trackers, support queues, recruiting funnels, anything the conversation pointed at.\n- Add and modify fields and phases on existing workflows.\n- Invite team members to the workspace (admin permission allows this).\n- Create activities, follow discussions, and post messages.\n- Answer follow-up questions about Hailer using the same knowledge base the demo bot used, but now grounded in the user's real workspace state.\n- Build dashboards (insights) using Hailer's SQL-based query layer.\n\nWhat it does NOT do (don't promise these):\n- Write production code outside Hailer.\n- Integrate third-party services (Salesforce, HubSpot, etc.) on its own \u2014 those are separate Hailer integrations the user sets up via Zapier or the REST API.\n- Replace a human developer building custom Hailer Apps with the SDK.\n- Operate independently in the background \u2014 it responds to messages in its own discussion, not autonomously.\n\nThe bot is a separate Hailer user account in the workspace; the visitor can chat with it, rename it, or disable it from AI Hub at any time.\n\n#### Continuity between the demo chat and the post-signup workspace\n\nWhen a visitor clicks 'Continue in Hailer', the conversation they had on the login page does not disappear \u2014 it carries forward as seed context for the bot that greets them in their new workspace.\n\nHow continuity works:\n- The demo chat stores each user message and bot reply server-side under a session ID that the demo page generates and keeps in the browser.\n- That session ID is included in the authorize popup URL when the visitor clicks 'Continue in Hailer'.\n- When the workspace is provisioned, the demo turns are passed to the new Hailer Helper bot as `seedContext` \u2014 a structured record of the conversation.\n- The new bot's first message in its own discussion references what the visitor talked about ('I see you were thinking about a sales pipeline for your team \u2014 here's what I'd suggest').\n- Without seed context (e.g., a visitor signs up without chatting first, or the server restarted and lost the in-memory store), the new bot falls back to a generic introduction. The workspace and Hailer Helper still work; only the personalised opener differs.\n\nWhat the visitor sees:\n- The same conversation thread does NOT continue verbatim in the new workspace \u2014 it's a fresh discussion with a separate bot, but that bot already knows the context. Think of it as the demo bot briefing the workspace bot before handing the visitor over.\n- More demo turns before clicking 'Continue in Hailer' = a more specific, personalised welcome in the workspace. Four to eight back-and-forth turns is the sweet spot.\n\n### helper-capabilities\n\n#### Hailer Helper bot capabilities \u2014 the in-workspace toolset\n\nAfter a visitor clicks 'Continue in Hailer' and lands in their new workspace, the in-workspace Hailer Helper bot has access to a rich set of tools backed by the Hailer MCP server. The bot is a workspace admin, so its permissions cover everything in this list inside the visitor's workspace. This is what the bot can actually do once the visitor is in Hailer.\n\nWorkflow and dataset setup:\n- List existing workflows and datasets in the workspace and read their schemas (fields, phases, permissions).\n- Install new workflows from templates or scratch \u2014 sales pipelines, project trackers, support queues, recruiting funnels, anything with a lifecycle of stages.\n- Install datasets for reference data \u2014 customer lists, product catalogs, equipment registers, vendor lists. Datasets are modelled as workflows with a single phase (or two, like Active/Archived) so items live in categories rather than moving through stages.\n- The Helper should pick the right shape (workflow vs dataset) based on the use case: lifecycle \u2192 workflow, reference list \u2192 dataset. When the user's intent is ambiguous, the Helper should ask once before building rather than default to a multi-phase workflow.\n- Create and update fields on a workflow or dataset (text, dropdown, date, calculated/function fields, file fields, user fields, etc.).\n- Create and update phases on a workflow, including transitions between them.\n- Grant or revoke per-workflow permissions for users and teams.\n- Remove workflows or datasets when they're no longer needed.\n\nActivities (the work records inside workflows):\n- Create activities in any workflow, with field values populated from a description.\n- List, search, count, and show activity details.\n- Update activity fields and move activities between phases.\n- Read an activity's linked discussion to follow the conversation context.\n\nDiscussions and messaging:\n- List the bot's own discussions.\n- Fetch messages from a discussion (recent and historical).\n- Post messages into a discussion.\n- Invite users into a discussion or join/leave existing ones.\n- Look up which activity is linked to a given discussion.\n\nCalendar and events:\n- List the workspace's calendars and their upcoming events.\n- Create new calendar events.\n\nFiles:\n- Upload files to the workspace.\n- Download existing files.\n\nReporting and insights:\n- List existing insights (saved SQL queries) and run them to fetch data.\n- Create new SQL-based insights to summarise and aggregate workflow data.\n- Update or remove existing insights.\n- Preview an insight before saving it.\n\nUsers, teams, and permissions:\n- Search the workspace's users.\n- Set a user's role (admin, user) in the workspace.\n- Check a specific user's permissions on a workflow.\n\nHailer Apps (custom React applications inside Hailer):\n- Scaffold a brand-new Hailer app project (React + Vite) and configure it.\n- Publish an existing app so other users can install it.\n- List installed apps and read their manifests.\n- Add or remove members from an app's allowlist.\n- Install marketplace apps and templates published by others.\n\nTemplates and the marketplace:\n- List, get, install, create, and publish workflow templates so configurations can be reused or shared across workspaces.\n\nSelf-management:\n- Read and update its own system prompt (so the visitor can personalise how the Helper behaves).\n- Set its own profile picture.\n- Check the workspace's AI token balance.\n\nUtilities:\n- Resolve relative dates ('next Friday', 'end of quarter') into concrete timestamps.\n\nWhat the Helper cannot do:\n- Run code in the visitor's local environment, terminal, or developer tools \u2014 that's the Hailer Studio surface, not the workspace Helper.\n- Talk to third-party services (Salesforce, HubSpot, Slack, etc.) on its own. The user can wire those up via Zapier or the REST API, but the Helper doesn't have those credentials.\n- Send email or SMS from the workspace's domain.\n- Modify another workspace it isn't a member of.\n- Replace a human developer building a fully custom Hailer App with the SDK \u2014 it can scaffold and publish apps, but production-quality app code typically needs a developer.\n\nThe overall pattern: anything that lives inside a Hailer workspace's data model \u2014 workflows, activities, fields, phases, discussions, files, calendars, insights, apps, templates, user roles \u2014 the Helper can read, create, and modify on the visitor's behalf. Anything that crosses the boundary into the outside world (third-party APIs, the visitor's own machine, email systems) is outside its toolset.\n\nProactive setup offer on first contact:\n- The Helper's very first message in its discussion scans the demo conversation for concrete workspace-setup intent (a process the user described, records they want to manage, fields they need, stages an item moves through).\n- If the demo gave enough detail to start building, the Helper offers to set it up immediately \u2014 naming the phases or dataset shape, naming the key fields \u2014 and asks 'want me to go ahead?' rather than building unilaterally.\n- If the demo is too vague to act on, the Helper asks one or two specific clarifying questions instead of generic 'what do you want to track?' prompts.\n- This proactive offer only fires on the first message, when the seed context is fresh. Subsequent turns behave normally.\n\n### mobile-and-localization\n\n#### Mobile apps, push notifications, video calls, and supported languages\n\nHailer ships native iOS and Android apps (built on Capacitor, packaging the same Hailer web UI) alongside the web app. Anything below is shipping; don't promise features that aren't listed.\n\nMobile apps:\n- iOS and Android both have native apps. They share the web UI under the hood, so feature parity is high \u2014 workflows, kanban, activities, discussions, calendar, feed, settings all work.\n- Native push notifications: the apps receive push for incoming discussion messages, mentions, and ball-passing events (when an activity moves to a user). Notification taps deep-link into the relevant discussion or activity.\n- Video calls: the apps handle incoming Hailer video calls natively with accept/decline actions on the lock screen and from notifications. The video call surface is wired into the discussion thread it belongs to.\n- Workspace admins can require biometric unlock on every launch (Force local auth \u2014 see the SSO and admin controls chunk).\n\nOffline support:\n- The apps work online primarily; substantial offline editing isn't a documented feature. If a visitor explicitly asks about offline-first usage, say honestly that Hailer is online-first and recommend they reach out to Hailer if offline support is critical.\n\nLanguages:\n- The Hailer UI ships in English, Finnish, and Swedish. Visitors will see their browser's language by default if it's one of the three; otherwise English. There's no per-workspace language pin \u2014 each user sees their own preference, set in their account.\n- Activity content (the things users create \u2014 workflow names, field labels, discussion messages) is whatever the user typed; Hailer doesn't translate user content.\n- If a visitor asks about other languages (German, French, Spanish), be honest: only en/fi/sv are supported today.\n\nNotifications model overview (not exhaustive):\n- Native push (iOS/Android apps) \u2014 the primary channel for time-sensitive events.\n- In-app notifications \u2014 visible inside the Hailer UI on web and mobile.\n- Email \u2014 used for invites, password resets, and certain admin-configured workflow events; granular per-user email controls aren't a documented public feature beyond standard unsubscribe.\n- If a visitor asks 'will this spam me?', the honest answer is: push and in-app notifications follow the events that involve them (mentions, balls passed, etc.); email is used sparingly for transactional things.\n\nTone guidance: don't oversell offline. Don't promise translations beyond en/fi/sv. Don't claim email-frequency settings exist unless the visitor mentions them \u2014 if they do, recommend they ask the Hailer team directly.\n\n### Overview\n\n#### What Hailer MCP is and what it does\n\nHailer MCP Server (@hailer/mcp) is a Node.js application that bridges AI assistants with Hailer \u2014 a workspace and CRM platform for managing workflows, activities, teams, and apps. It implements the Model Context Protocol (MCP), an open standard that lets AI models (Claude, ChatGPT) call tools on external systems. Think of it as a universal adapter: an AI assistant asks 'list all activities in the Sales pipeline', and the server translates that into the right Hailer API calls and returns structured results.\n\nThe server exposes 71 tools to any MCP-compatible AI client. Tools cover everything you can do in Hailer: create activities, manage workflows, query data, build apps, and control permissions. The flow is: AI client \u2192 HTTP \u2192 MCP Server \u2192 Socket/REST \u2192 Hailer API.\n\n#### MCP Server, Bot Client, and Plugin System capabilities\n\nHailer MCP provides three things:\n\n1. MCP Server (Primary) \u2014 An HTTP server that exposes 71 tools to any MCP-compatible AI client. Tools cover the full surface of Hailer: creating activities, managing workflows, querying data, building apps, and controlling permissions.\n\n2. Bot Client (Optional) \u2014 Automated AI agents that live inside Hailer discussions. When someone @mentions the bot, it reads the conversation, uses the same 71 tools to gather context, and responds with AI-generated answers.\n\n3. Plugin System \u2014 Extensible architecture for additional capabilities. Currently includes Vipunen, a Weaviate-based RAG (Retrieval-Augmented Generation) plugin for semantic search over documentation.\n\n#### Hailer ecosystem core concepts: workflows, activities, phases, fields\n\nTo understand Hailer you need to know its key concepts. A Workspace contains everything else:\n\n- Workflows \u2014 like database tables: 'Projects', 'Tasks', 'Invoices'.\n - Fields \u2014 columns on a workflow: 'Title', 'Due Date', 'Assignee'.\n - Phases \u2014 stages an activity moves through: 'New' \u2192 'In Progress' \u2192 'Done'.\n - Activities \u2014 rows in the workflow: individual records or items.\n- Discussions \u2014 chat threads, can be attached to activities.\n- Teams & Groups \u2014 organizational units used for permissions.\n- Apps \u2014 custom web applications embedded in Hailer.\n- Insights \u2014 SQL-like queries for reporting.\n- Users \u2014 workspace members with roles.\n\nDefinitions:\n- Workflow = a structured process (like a Kanban board or database table).\n- Activity = a single item in a workflow (like a task, project, or invoice).\n- Phase = a stage in the workflow lifecycle (like 'Draft' \u2192 'Review' \u2192 'Published').\n- Field = a data point on an activity (like 'Title', 'Due Date', 'Assigned To').\n\n#### Hailer MCP technology stack and package\n\nHailer MCP is built with these technologies:\n\n- Language: TypeScript 5 (strict mode) for type-safe server code\n- Runtime: Node.js 20\n- HTTP: Express.js\n- Protocol: JSON-RPC 2.0 over Server-Sent Events (SSE) for MCP communication\n- Validation: Zod for input schema validation\n- Hailer API: @hailer/cli (socket.io) for backend communication\n- AI: Anthropic Claude SDK and OpenAI SDK for the bot client\n- RAG: Weaviate for vector search via the Vipunen plugin\n- Build: TypeScript compiler (tsc)\n- Deploy: Docker (multi-platform images)\n\nThe package is published to the public npm registry as @hailer/mcp. Install or run it with:\n\nnpx @hailer/mcp --port 3030\n\nIt also installs as a global CLI command 'hailer-mcp'.\n\n### overview-presentation\n\n#### The Hailer overview presentation \u2014 what the in-demo slide deck covers\n\nThe Hailer demo page (the interactive mock workspace at /demo) ships with a spatial slide presentation that introduces Hailer's story. It opens as a fullscreen overlay above the mock UI \u2014 launched by clicking the 'Tour' button in the top-right of the demo topbar, or by the bot emitting a <bot-action type=\"presentation\" target=\"open\" /> tag. ESC closes it; arrow keys / Space / PgUp / PgDn step through slides; mouse wheel zooms; click-drag pans; 0\u20139 jumps to a percentage of the deck.\n\nThe deck has 15 slides arranged in three rows on a Prezi-style canvas \u2014 the camera flies between them. It is NOT the interactive demo (clickable kanban, table, discussions, etc.). The presentation is a narrative; the demo is a sandbox. Offer the presentation when the visitor wants the conceptual map; offer the demo tour (navigate + point chain) when they want to see the product in use.\n\nSlides \u2014 each line is `slide-id \u2014 title \u2014 what it covers`. Bot can reference any slide inline via <bot-action type=\"slide\" target=\"{slide-id}\" />, which renders a clickable chip in the chat that opens the deck on that exact slide:\n- `title` \u2014 'Hailer / Where work flows' \u2014 the opening cover.\n- `what` \u2014 Hailer is a workspace platform for structured work + team chat in one.\n- `problem` \u2014 Trackers and chat live apart; context dies in translation.\n- `core-label` \u2014 section divider: Core concepts.\n- `workspaces` \u2014 Multi-tenant homes; SSO; per-workspace AI agents.\n- `workflows` \u2014 Phases, fields, automations, permissions \u2014 the configurable process.\n- `activities` \u2014 Work items moving through phases; ball tracking; audit history.\n- `discussions` \u2014 Built-in chat per activity; real-time; bots and AI participants.\n- `build-label` \u2014 section divider: Build & extend.\n- `apps-studio` \u2014 Hailer Studio (cloud SDK editor for workspace config, with an AI agent) + apps marketplace. (Studio shapes workspace configuration as code; it is NOT an app builder \u2014 the Apps SDK and marketplace cover app-building. See the hailer-studio chunk.)\n- `sdk` \u2014 Workspace config as code; @hailer/sdk on npm.\n- `sdk-code` \u2014 TypeScript workflow definition example (fields + phases + automation).\n- `mcp` \u2014 Model Context Protocol surface; @hailer/mcp on npm.\n- `insights` \u2014 Saved chart/table queries + phase-change automations.\n- `closer` \u2014 One platform: system of record + team chat under one roof.\n\nWhen to recommend the presentation: visitor asks 'what is Hailer?', 'show me the overview', 'the elevator pitch', 'give me the slides', 'I want to understand the whole thing'. Don't open it on detail questions ('how do permissions work?', 'is there a free trial?') \u2014 those get a direct prose answer.\n\nWhen to embed a slide chip inline: the visitor's question maps cleanly to one slide's topic. Answer in prose, drop the chip mid-paragraph where it makes sense, move on. One or two chips per reply max. Don't substitute chips for prose \u2014 they're a side door, not the answer.\n\nWhen NOT to use either: as a substitute for the live demo tour. The two surfaces are complementary. The demo tour shows HOW Hailer feels in daily use. The presentation tells the STORY of what Hailer is and how the pieces fit together.\n\n### Product Description\n\n#### What Hailer is \u2014 the cloud platform overview\n\nHailer is a cloud platform designed for process-driven business management and communication. The largest organizational unit in Hailer is the workspace, and there is typically one workspace per customer.\n\nA workspace contains the structures the team works in: workflows and datasets that organize activities, discussions for messaging, a feed for company-wide updates, calendars for events, files, users, and teams. Hailer is built around the idea that day-to-day work \u2014 sales cases, tasks, projects, support tickets \u2014 moves through a structured process the team can configure rather than a fixed product taxonomy.\n\n#### Activities, workflows, and datasets\n\nActivities form the core of Hailer. They model the structured organizational work \u2014 sales cases, tasks, projects \u2014 that progresses through a defined process.\n\nActivities live inside two related structures:\n\n- Workflows are configurable processes. The process owner defines which steps (phases) the workflow consists of, plus what data is collected within the workflow. Activities move from phase to phase as the work progresses.\n\n- Datasets share most properties with workflows but disable phase transitions between categories \u2014 they're more like a labeled list than a stage-by-stage process. Datasets are useful for reference data (customers, products, equipment) where items don't move between stages.\n\nA single workspace can have many workflows and datasets side by side.\n\n#### Available field types and advanced field features\n\nEach workflow defines what data is captured on its activities. Hailer supports a wide range of field types:\n\n- Text, Predefined Options, Text Area\n- Numeric, Numeric with Unit\n- Date, Date Range, Time, Time Range, Date & Time, Date & Time Range\n- Country\n- Activity links, User links, Team links, Linked activities\n- Subheader fields (visual grouping)\n\nActivities can also carry location data with coordinates and file attachments.\n\nAdvanced field capabilities:\n\n- All field types can be turned into function fields \u2014 calculated fields whose values come from JavaScript-based rules running in sandboxed virtual environments.\n- Fields can be marked mandatory.\n- Phase-specific visibility lets a field show only in certain phases.\n- User- and team-level access restrictions hide fields from users without permission.\n- A PDF document generator produces offers, invoices, packing lists, confirmations, certificates, and reports from activity data.\n\n#### Discussions, feed, and calendar\n\nHailer has three communication surfaces:\n\nDiscussions come in four flavors:\n- Private discussions \u2014 direct messages between users who share a workspace.\n- Group discussions \u2014 multi-participant chats.\n- Activity discussions \u2014 chats linked to a specific activity (task/project/case).\n- Event discussions \u2014 chats linked to a calendar event.\n\nFeed: every Hailer workspace comes with a feed available to all workspace members, used for organization-wide updates. Hailer also automatically posts to the feed when notable workflow events happen, so the team sees milestones without anyone having to broadcast them manually.\n\nCalendar: workspaces support multiple calendars with restricted visibility (per user or team). Each event can have its own discussion thread, so conversation around an event lives next to the event itself.\n\n#### Hailer Apps (Beta) and Insights\n\nHailer Apps (Beta) are customized applications that use Hailer as their infrastructure. Apps are built on top of the platform's data model and authentication. New apps are currently available through development inquiry \u2014 Hailer's team works with customers to scope and build them.\n\nInsights is built on top of Apps. It provides:\n- A SQL query builder for assembling reports from workflow data\n- Pivot tables\n- Visual charts\n- Plain data tables, with the ability to drill into the underlying activities\n\nInsights is how teams turn the structured data inside their workflows into dashboards, KPIs, and management reporting.\n\n#### Users, teams, and files\n\nUsers: Hailer accounts are global \u2014 once a user has a profile they can participate in multiple workspaces with the same identity. Each workspace has its own attributes for the user (role, team membership, etc.) so a person can be an admin in one workspace and a regular member in another.\n\nTeams: workspaces use teams to group users. Team membership drives content visibility \u2014 fields, phases, and activities can be restricted to specific teams so members only see what's relevant to their role.\n\nFiles: Hailer has an inbuilt file management system to make it easy to store, track, find, and share files. Files can be attached to activities, posted in discussions, or uploaded to the feed, and they're searchable across the workspace.\n\n#### API, platform support, and technology stack\n\nAPI: Hailer exposes an HTTP REST API. Requests use JSON, and authentication is via username/password credentials.\n\nPlatform support: the fully responsive Hailer web application is supported on Chrome, Firefox, Safari, and Edge. Native iOS (13+) and Android applications are also available. The iOS app includes additional field-operations capabilities for users working off-site.\n\nTechnology stack:\n- Frontend: Angular\n- iOS: Swift (native)\n- Android: web-based wrapper\n- Backend: Node.js\n- Database: MongoDB\n- Language: TypeScript across the stack\n- Infrastructure: AWS\n\n### sso-and-admin-controls\n\n#### SSO, login methods, and workspace-admin controls (audit, biometric, bulk invite)\n\nHailer supports the following login methods and admin controls. Anything below is shipping today; describe them honestly, don't add features that aren't here.\n\nSingle sign-on:\n- Microsoft Entra ID (Azure AD) login is supported via a dedicated route: `/#/entralogin/{clientId}/{tenantId}`. The workspace's IT admin provides the Entra app's client and tenant IDs; users authenticate against Microsoft and are then signed into Hailer. This is the SSO answer for organisations on the Microsoft stack.\n- Username + password is the default login.\n- There is NO first-party SAML or generic OIDC provider beyond Entra at this time. If a visitor asks about Okta, OneLogin, Auth0, or 'plain SAML', be honest: the supported enterprise SSO today is Microsoft Entra. The Hailer team can be contacted for other identity provider questions.\n\nBiometric / local-auth lock:\n- Workspace admins can enable a 'Force local auth' setting that requires users on iOS/Android to unlock the app with their device biometrics (Face ID, Touch ID, fingerprint) or PIN on every launch. Useful for shared devices or high-security workflows.\n\nAudit log:\n- Workspace admins have access to an audit log in workspace settings that records operations with the user, timestamp, IP address, request/response details, and success/failure status. Use it for compliance reviews or to investigate unexpected changes.\n\nBulk user invitation via Excel:\n- Admins can invite many users at once by uploading an Excel file from workspace settings. The template supports user details, team assignment, role, and a notes column. This is separate from the per-activity Excel import (`v3.activity.import`); both surfaces exist but they import different things.\n\nData residency / hosting location:\n- All Hailer infrastructure runs in AWS region eu-west-1, located in Ireland. The MongoDB database is in the same region. Every workspace's data resides in the EU (Ireland) by default.\n- There is currently NO option to choose a different region or pin a workspace to another location \u2014 it's eu-west-1 for all customers. If a visitor needs US, APAC, or in-country hosting, be honest: that isn't offered today, and they should contact the Hailer team to discuss requirements.\n- This is good news for EU/GDPR data-residency questions: 'your data stays in the EU \u2014 specifically AWS in Ireland.' It's a limitation for anyone who requires data to live outside the EU.\n\nWhat to tell different visitors:\n- IT / admin asking about SSO: 'Microsoft Entra ID is the supported SSO today. The login URL pattern is `/#/entralogin/{clientId}/{tenantId}`. SAML / Okta / other IdPs aren't first-party today \u2014 reach out to Hailer if that's a requirement.'\n- IT asking about audit + access reviews: 'Yes, workspace admins have an audit log under settings; it records user actions with IP and timestamp.'\n- IT / admin asking about data residency or 'where is our data hosted?': 'Everything runs on AWS in the EU \u2014 region eu-west-1, in Ireland \u2014 including the database. There's no region-selection option today; all workspaces are hosted there. If you need hosting outside the EU, that's a conversation with the Hailer team.'\n- Operations / decision-maker asking about onboarding many users: 'You can invite users one at a time or upload an Excel of users in settings.'\n- End user asking about device security: 'On mobile, your workspace admin may require Face ID/Touch ID to open the app \u2014 that's the Force-local-auth setting.'\n\n### UI Guide\n\n#### Hailer main layout: three-column structure with left nav, content, and sidenav\n\nHailer uses a three-column layout. On desktop screens (wider than 600px) the layout is:\n\n- Left sidebar: a 56-pixel vertical icon menu, always visible.\n- Main content: fills the remaining horizontal space; this is where workflow boards, lists, and pages render via the Angular router-outlet.\n- Right sidenav: a 400-pixel panel that opens when you click an activity or discussion to show its details.\n\nOn mobile (600px and below) the layout collapses:\n- A top toolbar appears.\n- The sidenav becomes full screen (100vw) when opened.\n- A bottom navigation bar replaces the left sidebar.\n\nThis structure stays consistent across the entire application \u2014 once a user understands it, they can navigate any section.\n\n#### Left navigation menu \u2014 icons and what each section does\n\nThe left navigation is a vertical icon menu always visible on desktop. From top to bottom:\n\n1. Discussions \u2014 chat and team discussions.\n2. Feed \u2014 activity feed and updates.\n3. Calendar \u2014 events and schedules.\n4. Activities \u2014 workflows and kanban boards.\n5. Apps \u2014 custom applications.\n6. People \u2014 user directory.\n\nAt the bottom:\n- Settings \u2014 workspace settings (admins only; regular users do not see this).\n- User profile \u2014 opens a menu with profile settings, language selection, dark/light mode toggle, and logout.\n\nWhen guiding someone, refer to icons by position. Example phrasing: 'Click the Activities icon in the left menu \u2014 it's the 4th icon from the top, and looks like a kanban board.'\n\n#### Activities section: workflow list, kanban view, view modes, and actions\n\nWhen the user navigates to /activities they see the workflow list view: every workflow they have access to appears as a card with a name and an icon. Clicking a card opens that workflow.\n\nThe default workflow view is Kanban (URL pattern: /activities/{workflowId}). Phases are columns, activities are cards inside columns. View modes can be toggled in the top-right:\n- Kanban \u2014 cards in columns by phase (default).\n- Table \u2014 list view with sortable columns.\n- Calendar \u2014 timeline/calendar view.\n- Map \u2014 location-based view (only when enabled for the workflow).\n\nPrimary actions in the workflow view:\n- Create activity: click the [+ Add] button in the top-right, or click empty space inside any phase column.\n- Open activity: click any card \u2014 it opens the activity detail in the right sidenav.\n- Move activity: drag a card to another phase column, OR open the card and use the phase selector in the header.\n- Filter: use the search bar or filter controls at the top.\n\n#### Activity sidenav: tabs, modes, and control buttons in the right panel\n\nThe activity sidenav opens when you click an activity card. It is 400 pixels wide on desktop and full-screen on mobile.\n\nHeader section shows: activity name (large text), workspace badge (colored tag), workflow badge (clickable \u2014 navigates to the workflow), a copy-tag button (mentions the activity in discussions), and a call button when video calls are enabled.\n\nA tab bar of icons sits below the header:\n1. Detail \u2014 main fields and info.\n2. Participants \u2014 followers, with a badge count.\n3. Discussion \u2014 activity chat with an unread count badge.\n4. Files \u2014 attachments with a count badge.\n5. Location \u2014 map view (when enabled).\n6. Linked \u2014 related activities with a count.\n7. Options \u2014 activity settings (when permitted).\n\nThree modes determine what the user sees:\n- View mode: read-only display.\n- Edit mode: fields become editable; Cancel and Save buttons appear at the bottom.\n- Create mode: empty form for a new activity.\n\nThe control buttons at the bottom (visible in edit and create modes) are Cancel (discard changes) and Save (with checkmark icon).\n\n#### How to move activities between phases\n\nActivities can move between phases two ways:\n\nMethod 1 \u2014 Drag and Drop in Kanban view:\nDrag the card from its current phase column and drop it in the target phase column. Best for quick rearrangements when you can see both columns.\n\nMethod 2 \u2014 Phase selector in the activity sidenav:\nOpen the activity to expose the phase dropdown near the top of the sidenav, then select the target phase. Best when phases are off-screen, you're already inside the activity, or many fields need to change at once.\n\nPhases are displayed left-to-right in the order defined by the workflow. The first phase is the leftmost column (typically 'New' or 'Draft'). The last phase is the rightmost column (typically 'Done' or 'Archived').\n\n#### Discussions section: list, threads, and activity-linked chats\n\nThe Discussions section is at /discussions.\n\nDiscussion list view shows every discussion the user is part of. Unread message counts appear as badges on each item. A search bar at the top lets users filter by name or content.\n\nDiscussion view layout:\n- Message list shown chronologically.\n- Input field at the bottom for typing messages.\n- File attachment button (paperclip icon).\n- Emoji picker.\n- @mention support \u2014 typing @ surfaces a user picker.\n\nActivity discussions are a special case: an activity can have its own attached discussion. To access it, open the activity sidenav and click the Discussion tab (3rd tab, speech-bubble icon). Users must Join the discussion before they can see and post messages \u2014 this is by design so people don't auto-subscribe to every activity's chat.\n\n#### Common Hailer UI patterns: buttons, cards, badges, tooltips, colors\n\nCommon patterns repeat across Hailer's interface:\n\nButtons:\n- Primary action: blue filled button (e.g., Save, Create).\n- Secondary action: outlined button (e.g., Cancel).\n- Icon buttons: small circular buttons with icons.\n\nCards:\n- White background in light mode, dark gray in dark mode.\n- Rounded corners with a subtle shadow.\n- Click to select or open.\n\nBadges:\n- Small colored pills showing counts or status.\n- Red badge: requires attention.\n- Gray badge: informational.\n\nTooltips:\n- Hover over an icon button to see its label. This is the fastest way to understand an unclear icon.\n\nColor coding:\n- Phases have assigned colors (visible as the column accent in kanban).\n- Workflow badges use the workflow's own color.\n- Workspace badges use the workspace's color.\n\n#### Common Hailer user issues and how to resolve them\n\nCommon issues and what they usually mean:\n\n'I can't see the workflow' \u2014 the user probably lacks permission to that workflow. An admin needs to grant access in the workflow's permissions settings.\n\n'I can't edit this activity' \u2014 the user does not have edit permission for this phase. Some phases are read-only for certain roles.\n\n'I can't move the card' \u2014 phase transitions may be restricted by the workflow's configuration. Check the workflow settings to see which transitions are allowed.\n\n'Where are my discussions?' \u2014 the user must be a member of a discussion to see it. Check the Discussions section in the left menu. For activity-linked discussions, the user must Join the discussion first via the activity's Discussion tab.\n\n'I can't see Settings' \u2014 Settings is admin-only. Regular (non-admin) users do not see this menu item; this is by design.\n\n### use-case-contract-management\n\n#### Use case \u2014 contract management on Hailer with e-signature integration\n\nContract management is a common use case Hailer is well-shaped for. A legal team handles many contracts every week \u2014 NDAs, supplier agreements, employment contracts, letters of representation, partnership agreements. Without a system, these tend to live across Word documents, email threads, shared folders, and tracking spreadsheets. Versions get lost, the wrong draft gets signed, and nobody knows what's pending or about to expire. The Hailer pattern below addresses that.\n\nThe pattern \u2014 a 'Contracts' workflow with four phases:\n- Draft \u2014 the lawyer is writing the contract or revising it after counterparty feedback.\n- Negotiation \u2014 the draft has been shared with the counterparty and they're proposing changes (back and forth as needed).\n- Ready to sign \u2014 both sides have agreed on the final version; awaiting signatures.\n- Signed \u2014 fully executed; the signed PDF and metadata are stored on the activity.\n\nFields commonly added to the contract activity:\n- Contract type (NDA, supplier agreement, employment, etc.) as a dropdown.\n- Counterparty name and country (a link to a 'Companies' dataset if the team tracks counterparties).\n- Effective date and expiry date \u2014 drives the calendar view and the 'expiring soon' alerts.\n- Owner \u2014 the responsible lawyer.\n- Version number \u2014 incremented each time the draft is revised.\n- The current draft (file attachment) and, once executed, the signed PDF.\n- Notes / risk flags as a text-area field.\n\nE-signature integration \u2014 the editing/signing separation:\n- Editing and signing are two separate stages. Hailer hosts the editing and negotiation; an external e-signature service handles the final signing.\n- All draft revisions happen inside Hailer in the Draft or Negotiation phase. The counterparty's comments come in by email or via a shared Hailer discussion; the lawyer brings the changes into the next version. Each version is saved on the activity, so the negotiation has a full audit trail.\n- Only the final, agreed PDF is sent for signature. The activity moves to 'Ready to sign' when the lawyer clicks the equivalent of 'send for signing'.\n- When signatures complete, the signed PDF is returned to Hailer automatically and the activity advances to 'Signed'.\n- Hailer can integrate with e-signature services through its REST API, webhooks, and Zapier integration. The supported services depend on what's available in the customer's region \u2014 in particular, e-signature providers vary by country because of differing legal-validity rules (e.g. providers that work with national bank IDs). For specific integrations the in-workspace Helper or the Hailer team can confirm the current options.\n- Counterparties do not need a Hailer account to participate. They receive a signing link by email, click 'Sign' in their browser, and the signature flows back into Hailer. No account creation, no software install on their side.\n\nThe old way vs the new way:\n- OLD: Lawyer writes the contract in Word \u2192 emails it to the other party \u2192 the other party prints, signs, scans, emails back \u2192 someone saves it in a folder \u2192 someone updates a spreadsheet \u2192 next month nobody remembers where it is or when it expires.\n- NEW (Hailer + e-signature integration): Lawyer drafts the contract inside Hailer \u2192 revises through the Draft/Negotiation phases as needed \u2192 clicks 'Send for signing' when both sides agree \u2192 signing happens online, signed PDF returns to Hailer automatically \u2192 status is always visible (Draft, Negotiation, Ready to sign, Signed, Expiring soon) \u2192 calendar and feed surface upcoming expiries automatically.\n\nWhat the customer gets:\n- Time saved per contract \u2014 no printing, no scanning, no chasing people for wet signatures.\n- One place for every contract \u2014 nothing gets lost in email threads or shared folders.\n- Always-visible status \u2014 who has signed, who hasn't, what's overdue, what expires soon.\n- Cross-border signing \u2014 counterparties without a national e-ID can still sign through e-signature providers that support international flows.\n- Legal proof \u2014 every signature is timestamped, and the negotiation history lives on the contract activity for audit purposes.\n- Automatic reminders \u2014 Hailer can trigger feed posts or calendar alerts when a contract is about to expire or has been waiting for a signature too long.\n\nWho this pattern fits:\n- Companies handling many legal contracts (10+ per month is a useful threshold).\n- Small legal teams spending disproportionate time on administrative tracking.\n- Organisations working with international partners where signatures cross borders.\n- Industries with heavy contract volume \u2014 law firms, construction and real estate, HR-heavy organisations (employment contracts, NDAs), consulting firms, property management, manufacturers with supplier networks, any business with a mix of domestic and foreign partners.\n- Teams that need a clear audit trail for compliance reviews.\n\nWhen a visitor describes contract chaos \u2014 'we lose versions', 'I never know what's pending', 'half my week is chasing signatures' \u2014 translate this pattern back into their words. Lead with the pain ('versions getting lost', 'signatures across countries', 'no audit trail') and describe how the Hailer + e-signature flow addresses it before naming Hailer terms like phase, activity, dataset.\n\nIf a visitor wants advanced collaborative editing inside Hailer (track-changes, real-time co-editing of the contract document itself), be honest: today the pattern relies on revising the draft activity-by-activity in the Draft phase, with the document attached as a file. For organisations that do very heavy in-document negotiation, that's a future-roadmap conversation rather than a shipped feature today.\n\n### value-propositions\n\n#### Why Hailer \u2014 the seven benefits to translate from\n\nWhen a visitor describes their current setup and the pain points in it, these are the seven angles Hailer's value tends to land on. Use them as the translation targets when answering 'how would this work for us?' \u2014 pick the one or two that match their pain, never all seven.\n\nModular \u2014 building blocks, not a fixed product.\n- Workflows, datasets, fields, phases, discussions, calendars, and apps are independent pieces a team assembles.\n- A 'CRM' is just a sales-pipeline workflow plus a customer dataset. A 'project tracker' is a project workflow plus a task workflow. A 'helpdesk' is a ticket workflow plus a customer dataset plus public forms.\n- You don't buy a CRM module and a PM module separately and bolt them together. You compose the pieces that fit, and you add more pieces as the team grows.\n- Translation example: someone running a small consultancy hears 'modular' as 'I'd have a deals pipeline, a project tracker, and a client list as three pieces that already know about each other \u2014 not three apps I have to reconcile'.\n\nCost saving \u2014 one platform replaces the stack of single-purpose tools.\n- The teams who get the most from Hailer were running 3\u20135 tools before: a CRM, a project tracker, a ticketing system, a chat app, maybe a doc generator on top.\n- Hailer is one subscription with one auth, one permission model, one data model, doing all of it. Total cost ends up lower than the per-seat sum of the individual tools, especially as headcount grows.\n- Translation example: 'instead of paying for HubSpot + Asana + Intercom + Slack + a PDF tool, your team works in one place and the bill is one line item.' (When talking to a visitor, name their pain \u2014 'the stack you're paying for today' \u2014 instead of naming the competitors.)\n\nTime saving \u2014 no re-keying, no swivel-chair, context-with-the-work.\n- Customer info lives once, as structured fields, and every related deal, project, ticket, or invoice references it.\n- Conversations attach to the record they're about, so handoffs don't lose context \u2014 sales-to-delivery, support-to-engineering, ops-to-finance.\n- Phase changes show up in the feed automatically; status updates write themselves.\n- The time savings come from removing seams, not from being faster at any one thing.\n- Translation example: 'when a deal moves to \"won\", everyone watching it sees the move and the conversation history is right there on the deal \u2014 nobody has to re-summarize the deal in the project channel.'\n\nCustomizable apps \u2014 every workspace can extend itself.\n- The Apps SDK (React, Svelte, vanilla JS) lets teams build their own surfaces on top of their data \u2014 dashboards, kiosks, customer portals, public forms, anything. (Hailer Studio is a separate surface \u2014 a cloud SDK editor for workspace configuration, not an app builder; don't conflate the two.)\n- The in-workspace Helper bot can scaffold an app on request, so non-engineers can describe what they need and get a starting point.\n- If the off-the-shelf workflow shape doesn't quite fit the team's process, the workspace grows new surfaces to match. The platform bends to the team, not the other way around.\n- Translation example: 'if your field techs need a phone-friendly intake form their customers can fill in, that's a public form on your job workflow \u2014 you don't go shop for a SaaS form builder.'\n\nStill just a chat \u2014 discussions are the spine.\n- Everything in Hailer ties back to a conversation. Activities have discussions. Calendar events have discussions. The AI Helper bot lives in a discussion.\n- Teams trying Hailer find the learning curve gentle because the dominant interaction is still 'send a message' \u2014 the structured-work side is where the chat output gets organized, not a separate paradigm.\n- This matters for adoption: the people on the team who only ever want to chat can stay in chat; the people who want to track structure see the structure; everyone is in the same workspace.\n- Translation example: 'for the half of your team that just wants to talk things through, Hailer feels like a chat app \u2014 the kanban board is for the other half, but they're both looking at the same deals.'\n\nWorks across the team and beyond it \u2014 not just one business function, and not strictly business at all.\n- Hailer's data model is flexible enough to hold a sales pipeline and a household maintenance log; a hobby club's event list and a freelancer's invoicing; a charity's volunteer roster and a school's parent-communications log.\n- Personal / hobby / non-commercial use of the free workspace is explicitly permitted by Hailer's TOS. A real example: a board-game club uses Hailer to maintain their internal documentation and a list of currently-active members. Other communities have used Hailer the same way for training programs, conference logistics, family-business operations, equipment registers, asset tracking.\n- The platform doesn't prescribe a business shape \u2014 it gives you the building blocks, and the same workspace can hold multiple unrelated workflows for the same team.\n- Translation example (mixed team): 'the same workspace your sales team lives in can also hold the engineering team's release calendar and HR's onboarding tracker \u2014 you're not buying separate tools for each function.'\n- Translation example (personal / community): 'if you're running a club or volunteer group, the same building blocks work \u2014 your member list is a dataset, your events are a workflow with phases like planned, confirmed, ran, retrospective. The free tier covers it for small groups; pay-as-you-go tokens only enter the picture if you start using AI features or heavy calculated fields.'\n\nYour system = your code \u2014 workspace as code via the SDK.\n- With @hailer/sdk on npm, a workspace's full configuration (workflows, fields, phases, teams, groups, insights, function fields) is just TypeScript files in a git repo.\n- Version it, diff it, code-review it, branch it, automate it. For engineering-led teams this turns workspace evolution from 'someone clicks around in settings' into a normal development loop with PRs and history.\n- Combined with @hailer/mcp it means AI assistants like Claude Code can read and modify workspace structure directly \u2014 describe a change in chat, the AI proposes the SDK edit, you review and push.\n- Translation example (developer-leaning visitor): 'when your ops manager asks for a new field on the deal workflow, that's a one-line edit in the workspace repo, code-reviewed and pushed like any other change. The workspace is configuration as code.'\n\nHow to use these in the chat:\n- After the visitor has described their current setup and pain points, pick ONE or TWO of these benefits that match what they said. Never list all seven; that's a brochure, not a conversation.\n- Translate the benefit into the visitor's words and concrete examples. If they named tools, name the seams between those tools; if they named a workflow ('our intake process'), name the Hailer shape ('a workflow with intake \u2192 review \u2192 action \u2192 done phases') in that language.\n- Lead with the benefit's effect ('you stop re-keying client info') before naming the underlying capability ('referenced fields between a deal workflow and a client dataset').\n- Don't oversell. If a visitor has a small simple need, 'modular building blocks' is overkill \u2014 just say 'you'd model it as one workflow with three phases' and move on. The benefits are a vocabulary for fit, not a checklist to recite.\n\n### workflow-vs-dataset\n\n#### Workflow vs Dataset \u2014 which one to use\n\nHailer has two related structures that both hold activities: workflows and datasets. They share most properties (fields, permissions, views, public forms, calendar entries) but differ in how phases work. Picking the right one is one of the first questions when modelling a use case.\n\nUse a WORKFLOW when:\n- The records have a lifecycle with stages \u2014 leads become qualified, qualified become proposals, proposals become won/lost.\n- The activity moves through ordered phases as the work progresses.\n- Phase changes are meaningful events (you want them in the feed, want to trigger automations, want reports of how long activities spent in each stage).\n- Examples: sales pipelines, recruitment funnels, project trackers, support tickets, onboarding processes, deal management, incident response, change-management approvals.\n\nUse a DATASET when:\n- The records are reference data or a catalog \u2014 they have categories but don't 'flow' through them.\n- An item doesn't progress from one state to another; it either stays in its category permanently or moves only as an admin correction.\n- Phase changes are not meaningful events on their own \u2014 categories function more like tags than stages.\n- Examples: customer lists, product catalogs, equipment registers, vendor lists, location lists, employee directories, contact lists, asset inventories, price lists, knowledge-base entries, FAQ items.\n\nDecision questions to ask when a user describes a use case:\n1. Does this thing have a beginning, middle, and end? (workflow if yes; dataset if no)\n2. Would the team expect to see a kanban view of these moving through stages? (workflow)\n3. Or do they mostly want a sortable, filterable list to look things up in? (dataset)\n4. Is the same item likely to stay in one state for months or years? (dataset)\n5. Is the same item likely to move between states within days or weeks? (workflow)\n\nMixed cases \u2014 when a user says 'customer list':\n- A pure customer list (names, contact info, segment) is a DATASET.\n- A list of customers with sales activity that progresses (active prospects, current customers, churned, won-back) is closer to a workflow with phases for those stages. Ask what they actually need before committing.\n\nMixed cases \u2014 when a user says 'projects':\n- Active projects that move from planning \u2192 execution \u2192 review \u2192 done are a WORKFLOW.\n- A reference list of completed projects for portfolio display is a DATASET.\n\nWhen unclear, default to a workflow with a small number of phases \u2014 it's the more general structure. Datasets can be thought of as 'workflows whose phases are categories, not stages'. You can later split a dataset off from a workflow if the use case clarifies.\n\nThe Helper bot inside a Hailer workspace should make this distinction explicitly when a user asks for something modelled. If the user says 'make a customer list', the Helper should reply 'I'll set this up as a dataset \u2014 a labelled list rather than a stage-by-stage process \u2014 does that match what you have in mind?' rather than silently building a phase-rich workflow.\n\nTechnical detail (developer-archetype question): in Hailer's data model, a dataset is a workflow with the boolean flag `enableUnlinkedMode` set to `true`. The same backing entity backs both \u2014 datasets are workflows in unlinked mode. Effects of setting the flag:\n- The item is listed under 'Datasets' in the UI instead of under 'Workflows'.\n- Phases on the workflow are not linked together \u2014 i.e. the ordered phase transitions that workflows support are disabled, and phases function as labels/categories rather than ordered stages.\n- Field, permission, public-form, and calendar capabilities work the same as on workflows.\n\nFor developers building against Hailer's API: see the hailer-api workflow schema for the full set of options that flip with the flag. When creating a workflow via @hailer/sdk or the REST API, set `enableUnlinkedMode: true` to make it a dataset from the start; flipping the flag on an existing workflow is also supported but changes how its phases behave.\n";
|
|
2
|
+
export declare const HAILER_KNOWLEDGE_BYTES: number;
|
|
3
|
+
//# sourceMappingURL=knowledge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge.d.ts","sourceRoot":"","sources":["../../src/public-chat/knowledge.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,uBAAuB,mksGAizCnC,CAAC;AAEF,eAAO,MAAM,sBAAsB,QAAiC,CAAC"}
|