Homepage · npm · Plugin Guide · CLI Reference
AI-powered Telegram personal assistant built on the GitHub Copilot SDK.
Chat with state-of-the-art AI models (GPT-5, Claude Sonnet 4, o3, and more) directly from Telegram. Extend it with plugins for Gmail, Google Calendar, or build your own.
| Requirement | How to get it |
|---|---|
| Node.js 20+ | nodejs.org |
| Telegram Bot Token | Message @BotFather → /newbot → copy the token |
| Telegram User ID | Message @userinfobot → copy the numeric ID |
| GitHub Token | github.com/settings/tokens — create a token with Copilot access |
Install globally from npm:
npm install -g @hmawla/co-assistantCo-Assistant needs a working directory to store your configuration, plugins, and data:
mkdir my-assistant && cd my-assistantRun the interactive setup wizard — it walks you through every credential and preference:
co-assistant setupThe wizard creates your .env file and config.json. Re-run it anytime to update settings.
co-assistant startOpen Telegram, find your bot, and send a message. That's it.
Verbose mode (shows messages and debug logs in the terminal):
co-assistant start -vWorks on Linux, macOS, and Windows:
npm install -g @hmawla/co-assistantAfter install, the co-assistant command is available everywhere. Create a directory for your instance and run co-assistant setup inside it.
Windows note: If
co-assistantis not found after install, ensure your npm global bin directory is in yourPATH. Runnpm config get prefixand add the resulting path +/bin(or\binon Windows) to your system PATH.
Try it out without a global install:
npx @hmawla/co-assistant setup
npx @hmawla/co-assistant startFor development or customisation:
git clone https://github.com/hmawla/co-assistant.git
cd co-assistant
npm installRun commands via tsx during development:
npx tsx src/cli/index.ts setup
npx tsx src/cli/index.ts start -vOr build first, then run the compiled output:
npm run build
node dist/cli/index.js startTwo markdown files control how the AI behaves and who it knows you are:
| File | Purpose | Included in package? |
|---|---|---|
personality.md |
Defines the assistant's tone, style, and behaviour | ✅ Yes — edit to customise |
user.md |
Your personal profile (name, role, timezone, preferences) | Template only (user.md.example) |
Set up your user profile:
cp user.md.example user.md
# Edit user.md with your detailsBoth files are read fresh on each message — edit them anytime without restarting. If the files don't exist in your working directory, the assistant works fine without them.
For running Co-Assistant permanently on a server (VPS, Raspberry Pi, etc.).
# Install globally on the server
npm install -g @hmawla/co-assistant
# Create a dedicated directory
sudo mkdir -p /opt/co-assistant
sudo chown $USER:$USER /opt/co-assistant
cd /opt/co-assistant
# Set up credentials
co-assistant setupCreate a systemd service:
sudo nano /etc/systemd/system/co-assistant.service[Unit]
Description=Co-Assistant Telegram Bot
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=your-username
WorkingDirectory=/opt/co-assistant
ExecStart=/usr/bin/co-assistant start
Restart=always
RestartSec=10
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetTip: Run
which co-assistantto find the exact path forExecStartif it differs.
sudo systemctl daemon-reload
sudo systemctl enable co-assistant
sudo systemctl start co-assistantUseful commands:
sudo systemctl status co-assistant # Check if running
sudo journalctl -u co-assistant -f # Live logs
sudo systemctl restart co-assistant # Restart after config changesnpm install -g @hmawla/co-assistant
mkdir -p ~/co-assistant && cd ~/co-assistant
co-assistant setupCreate a launch agent:
nano ~/Library/LaunchAgents/com.co-assistant.plist<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.co-assistant</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/co-assistant</string>
<string>start</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/your-username/co-assistant</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/your-username/co-assistant/co-assistant.log</string>
<key>StandardErrorPath</key>
<string>/Users/your-username/co-assistant/co-assistant.log</string>
</dict>
</plist>Tip: Run
which co-assistantand replace/usr/local/bin/co-assistantwith the actual path.
launchctl load ~/Library/LaunchAgents/com.co-assistant.plistOption A: PM2 (cross-platform, recommended for Windows)
npm install -g @hmawla/co-assistant pm2
mkdir C:\co-assistant
cd C:\co-assistant
co-assistant setup
pm2 start co-assistant -- start
pm2 save
pm2-startup install # auto-start on bootOption B: Task Scheduler
- Open Task Scheduler → Create Basic Task
- Set trigger to "When the computer starts"
- Action: Start a program
- Program:
co-assistant(or full path fromwhere co-assistant) - Arguments:
start - Start in:
C:\co-assistant
- Program:
- Check "Run whether user is logged on or not"
PM2 works the same way on Linux, macOS, and Windows:
npm install -g @hmawla/co-assistant pm2
mkdir my-assistant && cd my-assistant
co-assistant setup
pm2 start co-assistant -- start
pm2 save
pm2 startup # generates command to auto-start on bootFROM node:20-slim
WORKDIR /app
RUN npm install -g @hmawla/co-assistant
COPY .env config.json personality.md ./
COPY plugins/ plugins/
COPY heartbeats/ heartbeats/
# Optional — only if you created a user.md:
# COPY user.md ./
CMD ["co-assistant", "start"]docker build -t co-assistant .
docker run -d --restart=always --name co-assistant co-assistantAll configured via .env (the setup wizard handles this):
| Variable | Required | Default | Description |
|---|---|---|---|
TELEGRAM_BOT_TOKEN |
✅ | — | Bot token from @BotFather |
TELEGRAM_USER_ID |
✅ | — | Your Telegram numeric user ID |
GITHUB_TOKEN |
✅ | — | GitHub token with Copilot access |
DEFAULT_MODEL |
— | gpt-4.1 |
AI model to use on startup |
LOG_LEVEL |
— | info |
Logging level (debug, info, warn, error) |
HEARTBEAT_INTERVAL_MINUTES |
— | 0 |
Scheduled heartbeat interval (0 = disabled) |
AI_SESSION_POOL_SIZE |
— | 3 |
Number of parallel AI sessions |
| Command | Description |
|---|---|
co-assistant setup |
Interactive setup wizard |
co-assistant start |
Start the bot |
co-assistant start -v |
Start with verbose logging |
co-assistant model |
Show current AI model |
co-assistant model <name> |
Switch AI model |
co-assistant plugin list |
List discovered plugins in local plugins/ |
co-assistant plugin available |
List bundled first-party plugins |
co-assistant plugin install <id> |
Install a bundled plugin into plugins/ |
co-assistant plugin install --all |
Install all bundled plugins |
co-assistant plugin enable <name> |
Enable a plugin |
co-assistant plugin disable <name> |
Disable a plugin |
co-assistant plugin configure <name> |
Set up plugin credentials |
co-assistant heartbeat list |
List heartbeat events |
co-assistant heartbeat add |
Create a new heartbeat event |
co-assistant heartbeat remove <name> |
Delete a heartbeat event |
co-assistant heartbeat run [name] |
Test heartbeat(s) on demand |
co-assistant status |
Show bot and system status |
| Command | Description |
|---|---|
/start |
Welcome message |
/help |
List available commands |
/model [name] |
View or change the AI model |
/plugins |
List plugins and their status |
/enable <plugin> |
Enable a plugin |
/disable <plugin> |
Disable a plugin |
/clear |
Clear conversation and reset AI context |
/update |
Check for updates — tap "Update Now" to self-update |
/status |
Show bot status |
/heartbeat [name] |
Run heartbeat event(s) on demand |
/hb [name] |
Shorthand for /heartbeat |
Anything else you type is a conversation with the AI.
Models are grouped by rate consumption (requests per prompt):
| Tier | Models | Rate |
|---|---|---|
| Premium | gpt-5, o3, claude-opus-4 |
3× |
| Standard | gpt-4.1, gpt-4o, o4-mini, claude-sonnet-4 |
1× |
| Low | gpt-4o-mini, gpt-4.1-mini, gpt-5-mini, o3-mini, claude-haiku-4.5 |
0.33× |
| Free | gpt-4.1-nano |
0× |
Switch anytime: co-assistant model claude-sonnet-4
Defines the assistant's identity, tone, formatting rules, and boundaries. Shipped with a sensible default. Edit it to change the assistant's style — changes apply on the next message.
Your personal details (name, title, timezone, role, preferences) so the AI can address you correctly and understand your context. Copy user.md.example to get started.
Both files are injected as system-level context on every message:
- Personality — how the assistant should behave
- User profile — who it's talking to
- Your message — the actual prompt
| Plugin | Tools provided |
|---|---|
| Gmail | Search threads, get thread, search emails, read email, send email |
| Google Calendar | List events, create event, update event, delete event |
Co-Assistant ships with first-party plugins (Gmail, Google Calendar). If you installed via npm, they aren't in your working directory yet — install them with:
# See what's available
co-assistant plugin available
# Install a specific plugin
co-assistant plugin install gmail
# Install all bundled plugins at once
co-assistant plugin install --all
# Overwrite an existing plugin (e.g. after an update)
co-assistant plugin install gmail --forceco-assistant plugin enable gmail
co-assistant plugin configure gmailThe configure command walks you through setting up OAuth credentials. For Google plugins, it includes an automated local OAuth flow to obtain refresh tokens.
Create a directory under plugins/ in your working directory:
plugins/my-plugin/
├── plugin.json # Manifest (id, name, version, credentials)
└── index.ts # Entry point exporting createPlugin()
plugin.json:
{
"id": "my-plugin",
"name": "My Plugin",
"version": "1.0.0",
"description": "What it does",
"requiredCredentials": [
{ "key": "API_KEY", "description": "API key for the service" }
]
}index.ts:
import type { CoAssistantPlugin, PluginContext } from "../../src/plugins/types.js";
export default function createPlugin(): CoAssistantPlugin {
return {
id: "my-plugin",
name: "My Plugin",
version: "1.0.0",
description: "What it does",
requiredCredentials: [{ key: "API_KEY", description: "API key" }],
async initialize(context: PluginContext) {
// Set up connections, validate credentials
},
getTools() {
return [{
name: "do_something",
description: "Does something useful",
parameters: {
type: "object",
properties: {
input: { type: "string", description: "The input" },
},
required: ["input"],
},
handler: async (args: Record<string, unknown>) => {
return `Result for: ${args.input}`;
},
}];
},
async destroy() {},
async healthCheck() { return true; },
};
}Tool names are automatically prefixed with the plugin ID (e.g., my-plugin_do_something) to prevent collisions. Plugins run in a sandbox — failures are isolated and auto-disabled after 5 consecutive errors.
📖 See docs/plugin-development.md for the full guide.
Heartbeats are scheduled AI prompts that run every N minutes. Use them for periodic checks like "do I have unread emails that need a reply?"
- Set the interval in
.env:HEARTBEAT_INTERVAL_MINUTES=5 - Add a heartbeat event:
co-assistant heartbeat add - Or trigger manually via Telegram:
/heartbeat
Heartbeat prompts are stored as .heartbeat.md files in the heartbeats/ directory. They support deduplication via {{DEDUP_STATE}} placeholders and <!-- PROCESSED: id1, id2 --> markers.
your-project/ # Your working directory
├── .env # Credentials (auto-created by setup)
├── config.json # Plugin & runtime config (auto-created)
├── personality.md # AI personality instructions
├── user.md # Your personal profile
├── plugins/ # Your plugins (gmail, google-calendar, custom)
│ ├── gmail/
│ └── google-calendar/
├── heartbeats/ # Heartbeat prompt files
├── data/ # SQLite database (auto-created)
└── node_modules/ # If installed locally
When installed globally, the package provides the co-assistant binary. All runtime files (config, data, plugins, heartbeats) live in whichever directory you run the command from.
Key internals:
- Session pool — Multiple parallel AI sessions so messages don't queue behind each other
- System context —
personality.md+user.mdinjected into every AI prompt as system instructions - Plugin sandbox — Every plugin call wrapped in try/catch with auto-disable after 5 failures
- Plugin loader — Uses
tsx/esm/apito dynamically import TypeScript plugins fromplugins/ - Garbage collector — Prunes old conversations (30 days) and health records (7 days); logs memory stats
- Heartbeat deduplication — State files track processed item IDs to avoid duplicate notifications
- Reply threading — Each AI response threads back to the user's original Telegram message
npm update -g @hmawla/co-assistantYour .env, config.json, user.md, plugins, and heartbeats are unaffected — they live in your working directory, not in the package.
npm uninstall -g @hmawla/co-assistantYour working directory and data are preserved. Delete it manually if no longer needed.
MIT