5.9 KiB
Volcanic Secretary
A personal assistant you talk to over Telegram. The agent engine is Pi embedded through its SDK. It lives in one workspace directory, runs tools without asking, remembers things in MEMORY.md, and can schedule reminders, prompts, and watcher scripts.
Setup (Windows or any host with Node 24)
On Windows the quickest path is run.bat, which creates .env on the first run, then installs, builds, and starts the bot on every later run. The step by step guide, including how to get the bot token and your user id, is in SETUP-WINDOWS.md.
- Create a bot with @BotFather and copy the token.
- Find your numeric Telegram user id (send
/startto @userinfobot). - Log in to a model provider once with
piso~/.pi/agent/auth.jsonexists, or plan to setPI_MODELplus a provider API key. - Copy
.env.exampleto.envand fill inTELEGRAM_BOT_TOKENandTELEGRAM_OWNER_ID. AddOPENAI_API_KEYif you want voice notes transcribed. npm install, thennpm run dev(development) ornpm run build && npm start.
The bot messages you π’ Online. when it is ready. Only your user id is accepted; everyone else is ignored.
Talking to it
Send text, photos, voice notes, or files. Photos go to the model as images. Voice notes are transcribed with OpenAI and echoed back as π€ .... Files are saved to workspace/inbox/ and the agent is told the path.
While the agent works you see one βοΈ Workingβ¦ message that updates with tool activity, then the answer. Send another message while it works and it is queued for the current run (you get a π reaction).
Commands: /status, /new, /stop, /jobs, /cancel <id>, /compact.
Scheduling
Ask in plain language:
- "Remind me at 9 tomorrow to call the dentist" (one-off, sent directly)
- "Every weekday at 8, summarize what's in my inbox folder" (recurring prompt through the agent)
- "Write a script that checks the price on this page every 10 minutes and tell me only if it drops below 50" (watcher script)
Watcher scripts follow one rule: print nothing and exit 0 to stay silent, print a message to trigger delivery, exit non-zero on a real error. Failures are reported once and stay quiet while the same failure repeats.
Jobs live in workspace/.secretary/jobs.json.
Workspace
workspace/
AGENTS.md persona and standing instructions (edit freely)
MEMORY.md facts the assistant keeps; it edits this itself
scripts/ scripts for scheduled jobs
inbox/ files you sent
.secretary/ runtime state
The agent's edits to MEMORY.md are local runtime data. Leave them uncommitted, or run git update-index --assume-unchanged workspace/MEMORY.md.
Environment variables
| Variable | Required | Default | Purpose |
|---|---|---|---|
TELEGRAM_BOT_TOKEN |
yes | Bot token | |
TELEGRAM_OWNER_ID |
yes | Your numeric user id | |
WORKSPACE_DIR |
no | ./workspace |
Workspace directory |
OPENAI_API_KEY |
no | Enables voice transcription | |
STT_MODEL |
no | gpt-4o-transcribe |
OpenAI transcription model |
PI_MODEL |
no | first model with credentials | provider/model or provider/model:thinking, for example pi-claude-code-provider/opus with the Claude Code subscription package; pi --list-models shows every id |
PI_CODING_AGENT_DIR |
no | ~/.pi/agent |
Pi config directory (auth, settings, packages) |
SECRETARY_TIMEZONE |
no | system | IANA timezone for cron and time display |
SECRETARY_SHELL |
no | Git Bash / bash | Shell used for scheduled scripts |
LOG_LEVEL |
no | info |
debug, info, warn, error |
Keeping it running on Windows
Use Task Scheduler (run node dist/main.js at logon, restart on failure) or npm i -g pm2 then pm2 start dist/main.js --name secretary. If Git is installed per-user or somewhere else entirely, set SECRETARY_SHELL to the full path of bash.exe.
Docker / Coolify
docker compose up -d --build runs it with two named volumes: /workspace and /pi-agent. Provide the environment through Coolify. For model auth either copy a Pi agent directory containing auth.json into the /pi-agent volume, or set ANTHROPIC_API_KEY and PI_MODEL=anthropic/claude-opus-4-7 (an id from Pi's built-in Anthropic provider, which is what an API key unlocks). The image includes bash, git, ripgrep, and Python 3 so watcher scripts work the same as on Windows.
Tests
npm test runs the unit tests. SECRETARY_SMOKE=1 npx vitest run src/agent/pi-backend.smoke.test.ts runs one real model call through Pi.
Manual end-to-end checklist
Run npm run dev with a real bot and walk through every line:
hiβ progress message appears then disappears, reply arrives as formatted text.- Long answer (
explain git rebase in detail with code examples) β multiple messages, code blocks render, no HTML shows raw. - Photo with caption
what is thisβ reply describes the image. - Voice note β
π€ <transcript>then a reply. WithoutOPENAI_API_KEYβ the not-configured note. - Document (a small
.csv) with captionsummarize thisβ file appears inworkspace/inbox/with date prefix, reply uses it. - Send a message while a long run is in progress β π reaction, and the agent picks it up in the same run.
/stopduring a run βStopped.and no final answer message.remind me in 2 minutes to stretchβ confirmation with the fire time; two minutes later<job name>: <message>arrives directly.every minute run scripts/ping.py and tell me if it prints somethingwhereping.pyprints on even minutes β messages arrive only on even minutes;/jobslists it;/cancel <id>removes it.- Ask it to remember a fact (
remember that my dog is called Rex), then/new, thenwhat is my dog calledβ answer comes fromMEMORY.md. - Stop the daemon, start it again β conversation continues (
what did we just talk about). /compactβ reply with token counts.