* feat: custom heartbeat prompt via YAML config or file
Wire up the existing but unused HeartbeatConfig.prompt field so users
can customize what the agent sees during heartbeats. Adds three ways
to set it: inline YAML (prompt), file-based (promptFile, re-read each
tick for live editing), and env var (HEARTBEAT_PROMPT). Also documents
the <no-reply/> opt-out behavior.
Fixes#232
Written by Cameron ◯ Letta Code
"The only way to do great work is to love what you do." -- Steve Jobs
* test: add coverage for heartbeat prompt resolution
Tests buildCustomHeartbeatPrompt and HeartbeatService prompt resolution:
- default prompt fallback
- inline prompt usage
- promptFile loading
- inline > promptFile precedence
- live reload (file re-read each tick)
- graceful fallback on missing file
- empty file falls back to default
Written by Cameron ◯ Letta Code
"The only way to do great work is to love what you do." -- Steve Jobs
* docs: add multi-agent configuration reference
Document the agents[] YAML config, per-agent options, migration path
from single to multi-agent, and known limitations (#219, #220, #221).
Written by Cameron ◯ Letta Code
"Documentation is a love letter that you write to your future self." -- Damian Conway
* docs: fix channels required claim and soften isolation wording
- channels is not strictly required per-agent (validation is global)
- isolation has known exceptions, don't claim "fully isolated"
Written by Cameron ◯ Letta Code
"Clear is kind." -- Brene Brown
- Document api.port/host/corsOrigin in configuration.md (example,
reference table, and env var mapping)
- Add "Long Messages" section to telegram-setup.md noting the
automatic 4096-char splitting behavior
Written by Cameron ◯ Letta Code
"The best time to plant a tree was 20 years ago. The second best time is now." - Chinese Proverb
Add a top-level `polling` section to lettabot.yaml for configuring
background polling (Gmail, etc.) instead of relying solely on env vars.
- Add `PollingYamlConfig` type with `enabled`, `intervalMs`, and `gmail` subsection
- Update `configToEnv()` to map new polling config to env vars
- Update `main.ts` to read from YAML config with env var fallback
- Maintain backward compat with `integrations.google` legacy path
- Document polling config in docs/configuration.md
Fixes#201
Co-authored-by: letta-code <248085862+letta-code@users.noreply.github.com>
Co-authored-by: Cameron <cpfiffer@users.noreply.github.com>
Users were confused why selfhosted mode still required an API key.
The validation check now properly skips the API key requirement when
server.mode is 'selfhosted'.
Also adds comprehensive selfhosted-setup.md guide covering:
- Letta Docker server setup
- Network configuration (Docker, remote servers)
- Troubleshooting (connection refused, stuck agent, tool approvals)
- Running as a service (systemd, launchd)
- Hardware requirements
Thanks to oculairthebear for the community guide that inspired this.
Written by Cameron and Letta Code
"I've learned that people will forget what you said, people will forget
what you did, but people will never forget how you made them feel."
- Maya Angelou
* docs: add TESTING.md guide
Comprehensive testing documentation covering:
- Unit test setup and patterns
- E2E test setup with Letta Cloud
- MockChannelAdapter usage
- CI/CD workflow
- Best practices
Written by Cameron ◯ Letta Code
* feat: add LETTABOT_CONFIG env var for config path
Addresses Discord feedback from fpl9000 who was confused about where
to put the config file after a global npm install.
Changes:
- Add LETTABOT_CONFIG env var that overrides the config search order
- Update error messages to show the env var option
- Document in docs/configuration.md
Now users doing global installs can either:
- Create ~/.lettabot/config.yaml, or
- Set LETTABOT_CONFIG=/path/to/config.yaml
Written by Cameron ◯ Letta Code
"Configuration should be explicit, not magic." - The Twelve-Factor App
Auto-detect RAILWAY_VOLUME_MOUNT_PATH and use it for all persistent data
(agent ID, cron jobs, logs). On local machines, data stays in project
directory. Template now includes volume by default.
- Add src/utils/paths.ts with getDataDir() and getWorkingDir() helpers
- Update Store, cron service, CLI tools to use data directory
- Log storage locations on startup for debugging
- Update deploy button URLs with UTM tracking
Written by Cameron ◯ Letta Code
"The best way to predict the future is to invent it." - Alan Kay
* feat: add Railway deployment support with agent auto-discovery
- Add railway.toml for build/deploy config with health checks
- Skip config file requirement when RAILWAY_ENVIRONMENT detected
- Auto-discover existing agent by name on container deploys
- Add findAgentByName() API function for agent lookup
- Add setAgentId() method to LettaBot class
- Add comprehensive Railway deployment docs
One-click deploy flow:
1. Set LETTA_API_KEY + channel tokens
2. LettaBot finds existing agent by AGENT_NAME (default: "LettaBot")
3. If not found, creates on first message
4. Subsequent deploys auto-reconnect to same agent
Written by Cameron ◯ Letta Code
"The best way to predict the future is to deploy it." - Railway, probably
* fix: specify Node 22 for Railway deployment
* fix: fail fast if LETTA_API_KEY is missing
* fix: don't await Telegram bot.start() - it never resolves
* fix: extract message from send_message tool call
* Revert "fix: extract message from send_message tool call"
This reverts commit 370306e49de3728434352d2df1b78c744e888833.
* fix: clear LETTA_AGENT_ID env var when agent doesn't exist
* docs: add Railway deploy button to README and docs
* fix: .nvmrc newline and correct MODEL default in docs
Baileys/libsignal logs "Closing open session in favor of incoming
prekey bundle" and similar messages that are normal Signal Protocol
key renegotiation - not errors.
Changes:
- Remove our own crypto error logging (line 810)
- Add console filter to suppress Baileys crypto patterns:
- prekey bundle messages
- session renegotiation
- bad mac errors
- ratchet/key details
These are harmless noise that confused users into thinking
something was wrong.
Addresses LET-7275
Written by Cameron ◯ Letta Code
"Silence is golden." - Thomas Carlyle
When user selects "dedicated bot number" mode (selfChatMode=false),
skip the dmPolicy question and default to allowlist. Prompt for
allowed phone numbers immediately.
This is simpler and safer than pairing mode, which sends codes to
whoever messages the bot.
Users who want pairing or open mode can edit lettabot.yaml manually.
Also updates docs to reflect the new defaults.
Written by Cameron ◯ Letta Code
"Simplicity is the ultimate sophistication." - Leonardo da Vinci
Fixes and updates:
- README.md: Remove duplicate heartbeat troubleshooting section
- docs/getting-started.md: Fix Node version (18→20), commands, repo URL
- docs/commands.md: Rewrite with accurate command list (/start, /status, /heartbeat)
- docs/README.md: New multi-channel architecture diagram
- docs/whatsapp-setup.md: Add selfChatMode safety docs, media support section
- docs/slack-setup.md: Fix broken links
New documentation:
- docs/configuration.md: Complete YAML config reference
- docs/cron-setup.md: Scheduling guide (cron jobs + heartbeats)
Written by Cameron ◯ Letta Code
"Documentation is a love letter that you write to your future self." - Damian Conway