Give GitHub Copilot arms.
Open Tentacles is a GitHub-native AI agent framework for personal OSS maintainers. It turns GitHub Copilot from a chat tool you talk to in a browser tab into a partner that reaches out everywhere your open-source work happens — Discord, Telegram, and beyond.
One Copilot brain. Many tentacles.
📖 See
VISION.mdfor the full project vision and decision log.
v1 — early development. Solo-use, Discord-first, single bot-owner Copilot token.
Currently private while the framework hardens. Will be made public when v1 is ready.
GitHub Copilot is brilliant inside vscode and on the web — but the moment you leave the editor, it's gone. OSS maintenance doesn't only happen in vscode. It happens on Discord with contributors, on Telegram with collaborators, on your phone, mid-conversation. The full Copilot experience is boxed.
Open Tentacles unboxes it. It's the partner that shows up where you already are, remembers what you've worked on, and helps you maintain and build OSS — everywhere.
GitHub's mascot is the Octocat. Octocats have tentacles. So Open Tentacles gives Copilot its tentacles.
- 🧠 Brain: GitHub Copilot SDK (
@github/copilot-sdk) - 🐙 Tentacles: pluggable channels (Discord first, Telegram next, more later)
- 🔧 Hands: GitHub-native tools —
ghCLI, Octokit, MCP - 💾 Memory: central
bun:sqlitestore, channel-tagged, cross-channel recall - 🤝 Behavior: acts when certain, confirms when not. Goal = full autonomy.
- 🔒 Audit: every action leaves a receipt
- Not a multi-provider AI router — the brain is GitHub Copilot, by design
- Not a replacement for Copilot in vscode, on the web, or on mobile
- Not a generic agent SDK
- Not a hosted SaaS — self-host first
- Not a general AI assistant — OSS maintainers, specifically
- Bun ≥ 1.2
- A GitHub account with an active Copilot subscription
- A Discord bot application and token (for v1)
git clone https://github.com/warengonzaga/opententacles.git
cd opententacles
bun install
bun run setup # interactive wizard — sets bot token, owner ID, and preferences
bun run devSet the required environment variables in the Railway dashboard, then deploy the Docker image. No interactive setup needed — see Configuration below.
DM the bot. Conversation memory persists per user, across sessions, across channels.
Configuration is split by sensitivity:
- Secrets — stored encrypted via
@wgtechlabs/secrets-engine(set viabun run setuplocally) - Non-secret config — stored in SQLite via
@wgtechlabs/config-engine(also set viabun run setup) - Environment variables — take priority over stored values (ideal for Railway, Docker, CI)
| Variable | Required | Description |
|---|---|---|
DISCORD_BOT_TOKEN |
✅ Yes | Your Discord bot secret token |
DISCORD_OWNER_ID |
✅ Yes (required when DISCORD_BOT_TOKEN is set) |
Discord user ID of the bot owner. This is required to prevent the bot from accepting messages from anyone and burning your Copilot quota. |
GITHUB_NAMESPACES |
Optional | Comma-separated GitHub orgs/users you control (e.g. warengonzaga,wgtechlabs) — used to place cloned repos in first-party paths |
OPENTENTACLES_LOG_LEVEL |
Optional | debug | info | warn | error | silent (default: info) |
OPENTENTACLES_DATA_DIR |
Optional | Override the data directory (default: ~/.opententacles) |
For local dev, place these in a .env file — Bun loads it automatically. For Railway, set them in the Variables dashboard.
src/
├── cli.ts CLI entry point (setup | start | purge)
├── index.ts core start: load config → discover channels → start them
├── setup.ts interactive setup wizard
├── purge.ts wipe all persisted data
├── registry.ts auto-discovers channels from src/channels/*/index.ts
├── core/
│ ├── types.ts Channel + ChannelContext contracts
│ ├── config.ts config loader — SQLite + env var overrides, zod-validated
│ ├── copilot.ts per-user session cache over @github/copilot-sdk
│ ├── memory.ts channel-tagged sqlite memory
│ ├── db.ts bun:sqlite for persistent state
│ ├── gh.ts GitHub CLI token resolution
│ ├── paths.ts data/workspace/config dir resolution
│ └── logger.ts
└── channels/
├── discord/ v1 — DM-only Discord channel (long-running)
└── telegram/ v2 placeholder
export interface Channel {
readonly name: string;
start(ctx: ChannelContext): Promise<void>;
stop(): Promise<void>;
}
export interface ChannelContext {
copilot: CopilotOrchestrator; // send(userKey, prompt, { onDelta, onIdle, onError })
logger: Logger;
config: unknown; // this channel's slice of config.toml
http: HttpHost; // lazy — only boots if a channel registers a route
}The contract supports both shapes:
- Long-running channels (Discord, Telegram bot, IRC, Matrix) — open a connection in
start(), listen forever. Ignorectx.http. - Webhook channels (Slack, WhatsApp, future GitHub-App-style) — register routes via
ctx.http.post(...)instart(). The HTTP server boots on first registration.
A user running Discord-only never sees the HTTP server start. A user adding Slack later doesn't refactor anything.
Central bun:sqlite store with cross-channel recall:
| Table | Purpose |
|---|---|
identities |
links Discord/Telegram/etc. user IDs to one GitHub login |
conversations |
per identity, per channel, with channel tag |
facts |
per identity, channel-agnostic |
audit |
every action the agent took, with channel and receipt |
Ask the agent on Telegram "do you remember what we discussed?" and it can answer "yes — on Discord on Tuesday, you mentioned the rate-limiter bug in wgtechlabs/clean-commit."
- v1: acts on high-confidence tasks, confirms when uncertain
- Goal: full autonomy as tools and confidence harden
- Always: every action leaves a receipt in the audit log
- Create
src/channels/<name>/index.ts. - Default-export an object implementing
Channel. - Add
<name>tochannels.enabledinconfig.toml. - Add any channel-specific config under
[channels.<name>].
The registry will find it at startup. See src/channels/discord/ as a reference implementation for long-running channels. A webhook channel reference will land alongside the first webhook integration.
Official vs community channels:
- Official — built into this repo, maintained by me, ships with the Docker image (Discord, Telegram, …).
- Community — separate repo, installed as a plugin, community-maintained.
bun run setup # interactive setup wizard (local/self-hosted)
bun run dev # hot-reload dev server
bun run start # run once
bun test # unit tests
bun run typecheck # tsc --noEmit
bun run lint # biome check
bun run lint:fix # biome check --write (auto-fix)
bun run purge # wipe all persisted dataSelf-host first. Docker is the official deploy target. Railway is the recommended platform.
- Dockerfile (multi-stage, non-root, production-ready)
- Railway one-click deploy template (planned)
-
docker compose(planned)
For Railway: set the required env vars in the Variables dashboard, mount a persistent volume at OPENTENTACLES_DATA_DIR, and deploy the image. No interactive setup needed.
The roadmap is "which tentacle next," not "which feature next."
Phase 0 — Framework hardening
- Channel contract (long-running shape)
- Channel contract (webhook shape via lazy
HttpHost) - Heartware agent loop
- Channel-tagged memory + audit
Phase 1 — Official channels
- Discord DM
- Telegram DM (grammY)
- Slash commands:
/reset,/model,/status - File and image attachments
- Guild channel support (mentions, threads)
Phase 2 — Community channels (plugins)
- WhatsApp, Slack, Matrix, IRC, Mastodon, Bluesky — the framework makes channels cheap; the community provides the long tail.
Please report any issues and bugs by creating a new issue here, also make sure you're reporting an issue that doesn't exist. Any help to improve the project would be appreciated. Thanks! 🙏✨
Like this project? Leave a star! ⭐⭐⭐⭐⭐
Want to support my work and get some perks? Become a sponsor! 💖
Or, you just love what I do? Buy me a coffee! ☕
Recognized my open-source contributions? Nominate me as GitHub Star! 💫
Read the project's code of conduct.
This project is licensed under GNU General Public License v3.0.
Open Tentacles is a different flavor — GitHub-focused, OSS-maintainer-focused, Copilot-brained. Not an alternative to OpenClaw; a sibling with a different mission. See VISION.md for the full positioning.
This project is created by Waren Gonzaga, with the help of awesome contributors.
💻💖☕ by Waren Gonzaga | YHWH 🙏 - Without Him, none of this exists, even me.
