Guide for contributors: local setup, running the bot, and releasing.
- Node.js 18+
- ffmpeg — required for voice messages (
brew install ffmpegon macOS) - At least one supported AI coding CLI installed and authenticated — see Engines
- A Telegram bot token and your user ID — see Telegram
npm install
npm startThe start script runs the bot with --config examples, so HAL uses the config and env from the examples/ folder. You must create your own .env there before it will work, and you should not commit that file.
The examples/ folder contains a sample config (hal.config.yaml) that uses ${VAR_NAME} placeholders for secrets (bot tokens, user IDs, etc.). HAL loads env from the config directory at boot:
examples/.envexamples/.env.local(optional override forexamples/.env; both are gitignored)
Create examples/.env with the variables referenced in examples/hal.config.yaml. Do not commit it. For example:
# examples/.env
# Your Telegram user ID (required for access)
USER_MARCO_IPHONE_ID=123456789
# Bot tokens for each project in hal.config.yaml
OBSIDIAN_TELEGRAM_TOKEN=7123456789:AAHActual-token-here
TIMETRACKER_TELEGRAM_TOKEN=7123456789:AAHAnother-token-hereReplace the placeholder names and values with your own. See Telegram for creating a bot and finding your user ID. The config structure is in Configuration. If you need an extra local override layer, you can also add examples/.env.local.
Releases use release-it with conventional commits. The flow is split: version and changelog stay local until you run the push step; publish runs in your terminal so the browser/OTP flow works with 2FA.
| Script | What it does |
|---|---|
| release:patch | Lint → build (fails if either fails) → bump patch → update CHANGELOG.md → commit → tag. Does not push or publish. |
| release:minor | Same as above with minor bump. |
| release:major | Same as above with major bump. |
| release:push | Pushes the release commit and tag to the remote, then runs npm publish --access public. |
| release | Interactive: release-it prompts for version bump and options. |
| deploy | Alias for release:patch. |
prepare runs on npm install (sets up husky). prepublishOnly runs automatically before publish (runs build).
- Clean tree — Commit or stash all changes. release-it will refuse to run if the working directory is dirty.
- Version + changelog (local only) — Run one of:
npm run release:patchnpm run release:minornpm run release:majorEach runs lint and build first; if either fails, the script stops. Then it bumps the version, updatesCHANGELOG.md, commits, and creates the tag. Nothing is pushed.
- Push and publish — When ready:
npm run release:push. This pushes the commit and tag, then runsnpm publish --access public.
If your npm account uses 2FA, you can use an automation token so you don't need to enter OTP each time:
-
Create the token — On npmjs.com: Account → Access Tokens → Generate New Token → Automation.
-
Store it in the project root — Create a gitignored
.envin the project root (not inexamples/):# .env (project root, gitignored) export NPM_TOKEN=npm_xxxxxxxxxxxxxxxx
Replace with your actual token. The
exportis required so child processes receive the variable. -
Configure npm — The project
.npmrcalready contains://registry.npmjs.org/:_authToken=${NPM_TOKEN}npm reads
NPM_TOKENfrom the environment. -
Run publish — Before
release:push, load the env:source .env npm run release:pushOr in one line:
source .env && npm run release:push.
| Step | Command |
|---|---|
| Version + changelog | npm run release:patch (or minor/major) |
| Publish (with token) | source .env && npm run release:push |
| Publish (with 2FA) | npm run release:push (npm will prompt for OTP in browser when you have 2FA) |
Config: .release-it.json (conventional-commits preset, CHANGELOG.md at repo root).