Introducing slackker! :fire:
slackker sends real-time notifications, custom updates, and metric plots from any Python script directly to Slack, Telegram, Microsoft Teams, or Discord — so you can step away from the screen and still stay informed. :coffee:
https://github.com/user-attachments/assets/41ab1ee9-4d3c-44d0-82b2-3194acbf7727
Table of contents :notebook:
- Installation
- Quick Start
- Create a Client
- SimpleCallback — any Python function
- Interactive Pipeline
- MCP Server
- Universal MCP Configuration
- Keras
- Lightning
- Support
- Citation
- Maintainer
Installation :arrow_down:
Install slackker from UV (recommended) or pip. Requires Python >= 3.10.
uv add slackker
pip install slackker
Quick Start :rocket:
from slackker.core import TelegramClient
from slackker.callbacks.simple import SimpleCallback
client = TelegramClient(
token="1234567890:AAAAA_A111BBBBBCCC2DD3eEe44f5GGGgGG",
verbose=1,
)
notify = SimpleCallback(client)
@notify.notifier
def train_model():
# ... your training code ...
return {"accuracy": 0.94, "loss": 0.12}
train_model()
Refer to our website for platform setup instructions (Slack, Telegram, Teams, Discord).
Create a Client
All slackker callbacks use a client object. Create one for your platform and pass it to any callback.
from slackker.core import SlackClient, TelegramClient, TeamsClient, DiscordClient
# Slack
client = SlackClient(
token="xoxb-123234234235-123234234235-adedce74748c3844747aed",
channel_id="C04AAB77ABC",
verbose=0,
)
# Telegram
client = TelegramClient(
token="1234567890:AAAAA_A111BBBBBCCC2DD3eEe44f5GGGgGG",
verbose=0,
)
# Discord
client = DiscordClient(
token="your_bot_token_here",
channel_id="123456789012345678",
verbose=0,
)
# Microsoft Teams
client = TeamsClient(
app_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
tenant_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
chat_id="19:xxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxx@thread.v2",
verbose=0,
)
First-time Teams setup: On the first run,
TeamsClientprints a short URL and a code. Visit the URL, enter the code, and sign in. The token is then cached and silently refreshed on every subsequent run.
Client parameters
Shared parameters (Slack, Telegram, Discord):
| Parameter | Type | Default | Description |
|---|---|---|---|
token |
str |
required | Slack app / Telegram bot / Discord bot token |
channel_id |
str |
required (Slack & Discord only) | Slack or Discord channel ID |
chat_id |
str |
None (Telegram only) |
Telegram chat ID — auto-discovered if omitted |
verbose |
int |
0 |
0 = WARNING/ERROR, 1 = INFO, 2 = DEBUG |
Teams-specific parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
app_id |
str |
required | Azure AD application (client) ID |
tenant_id |
str |
"common" |
Azure AD tenant ID, or "common" for personal + org accounts |
chat_id |
str |
required | Teams chat ID (e.g. 19:..._...@thread.v2) — right-click a message → Copy link, extract from URL |
token_cache_path |
str |
~/.slackker/teams_<app_id[:8]>.json |
Path to cache the access/refresh token |
verbose |
int |
0 |
0 = WARNING/ERROR, 1 = INFO, 2 = DEBUG |
SimpleCallback — any Python function
from slackker.core import TelegramClient
from slackker.callbacks.simple import SimpleCallback
client = TelegramClient(
token="1234567890:AAAAA_A111BBBBBCCC2DD3eEe44f5GGGgGG",
verbose=1,
)
notify = SimpleCallback(client)
# Decorator — automatically sends function name, execution time, and return value
@notify.notifier
def train():
# ... your training code ...
return {"accuracy": 0.94, "loss": 0.12}
train()
# notify() — send a custom update anywhere, with optional file attachment
notify.notify(
event="training_complete",
attachment="./artifacts/model.ckpt",
best_val_loss=0.0123,
epoch=20,
)
Works with any client:
SlackClient,TelegramClient,TeamsClient, orDiscordClient.
Async: use await notify.async_notify(event="step_done", accuracy=0.95) in async contexts.
SimpleCallback parameters
Constructor:
| Parameter | Type | Description |
|---|---|---|
client |
BaseClient |
A slackker client instance |
notify() / async_notify() parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
event |
str |
None |
Label in the notification header; defaults to script filename |
attachment |
str |
None |
Path to a file to send alongside the notification |
**kwargs |
— | — | Any key-value pairs to include in the notification body |
ask() / async_ask() parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
question |
str |
required | Message sent to the platform asking for a reply |
timeout |
float |
60.0 |
Seconds to wait for a reply; auto-continues on timeout |
halt_on |
str |
"no" |
Reply text (case-insensitive) that halts the flow |
Returns True to continue, False to halt.
Interactive Pipeline
Use ask() to send a message and wait for the user's reply — ideal for checkpoints, confirmations, or human-in-the-loop pipelines:
from slackker.core import TelegramClient
from slackker.callbacks.simple import SimpleCallback
client = TelegramClient(
token="1234567890:AAAAA_A111BBBBBCCC2DD3eEe44f5GGGgGG",
verbose=1,
)
notifier = SimpleCallback(client)
def pipeline():
notifier.notify(event="preprocessing_done", samples=10000)
reply = notifier.ask("Preprocessing done. Start training? (yes/no)")
if reply.lower() != "yes":
return
# ... training ...
notifier.notify(event="training_complete", accuracy=0.94)
pipeline()
Async version: use await notifier.async_ask("...") in async contexts.
MCP Server
Use slackker as an MCP server so AI agents can call tools like a remote SimpleCallback:
notify→ send event notifications (optional attachment + metadata)ask→ human approval gate (continue/halt)get_messages→ fetch recent channel messagesget_status→ connection + listener status
Install MCP extras:
pip install "slackker[mcp]"
Start the server (stdio transport):
slackker-mcp
CLI run methods
If slackker-mcp is not on your shell PATH, use one of these:
# Run via uv in the current project environment
uv run slackker-mcp
# Run as a Python module (bypasses PATH lookup)
python -m slackker.mcp.server
You can also configure everything with CLI flags only:
slackker-mcp --platform slack --token xoxb-... --channel-id C04AAB77ABC
Or load config from a JSON file and still override via flags:
slackker-mcp --config ./slackker_mcp.json --poll-interval 1.0
Configuration is read from environment variables:
# Required for Slack / Telegram / Discord
SLACKKER_PLATFORM=slack # slack | telegram | discord | teams
SLACKKER_TOKEN=xoxb-... # required for slack/telegram/discord
# Platform-specific target
SLACKKER_CHANNEL_ID=C04AAB77ABC # Slack / Discord channel ID
SLACKKER_CHAT_ID=123456 # Telegram chat ID (optional if auto-discovery works)
# Teams-specific
SLACKKER_APP_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
SLACKKER_TENANT_ID=common
SLACKKER_CHAT_ID=19:...@thread.v2
# Optional runtime tuning
SLACKKER_POLL_INTERVAL=2.0
SLACKKER_VERBOSE=1
slackker-mcp automatically reads a local .env file from the current working directory.
If the same SLACKKER_* key is set in both places, the exported process environment value wins.
Universal MCP Configuration
slackker-mcp runs as a local stdio MCP server, so it works with MCP clients that can launch a local command.
Compatibility Matrix
| Client | Status | Config shape | Notes |
|---|---|---|---|
| VS Code | ✅ Verified | servers.<name> |
MCP extension config (.vscode/mcp.json) |
| Zed | ✅ Verified | context_servers.<name>.command |
Uses settings.json |
| Claude Desktop | ✅ Verified | mcpServers.<name> |
Uses claude_desktop_config.json |
| Claude Code (terminal) | ✅ Verified | claude mcp add ... or .mcp.json with mcpServers |
Native MCP management commands |
| OpenCode (terminal) | ✅ Verified | mcp.<name> with type: "local" |
Uses opencode.json |
| Roo Code | ✅ Verified | mcpServers.<name> |
Global/project MCP files |
| Cursor | 🟡 Common stdio pattern | mcpServers.<name> |
AI-native fork; follows Claude/MCP standard |
| Continue | 🟡 Common stdio pattern | mcpServers.<name> |
Confirm exact file path per plugin/version |
| Antigravity | 🟡 Common stdio pattern | mcpServers.<name> |
AI-native fork; follows Claude/MCP standard |
| Hermes / other terminal agents | 🟡 Stdio-compatible by design | Local stdio command + env | Works if host supports stdio MCP servers |
Snippets by client
Click to expand configuration snippets
VS Code (`.vscode/mcp.json`)
{
"servers": {
"slackker": {
"type": "stdio",
"command": "slackker-mcp",
"env": {
"SLACKKER_PLATFORM": "slack",
"SLACKKER_TOKEN": "xoxb-...",
"SLACKKER_CHANNEL_ID": "C04AAB77ABC"
}
}
}
}
Zed (`settings.json`)
{
"context_servers": {
"slackker": {
"command": {
"path": "slackker-mcp",
"env": {
"SLACKKER_PLATFORM": "slack",
"SLACKKER_TOKEN": "xoxb-...",
"SLACKKER_CHANNEL_ID": "C04AAB77ABC"
}
}
}
}
}
Claude Desktop (`claude_desktop_config.json`)
{
"mcpServers": {
"slackker": {
"command": "slackker-mcp",
"env": {
"SLACKKER_PLATFORM": "slack",
"SLACKKER_TOKEN": "xoxb-...",
"SLACKKER_CHANNEL_ID": "C04AAB77ABC"
}
}
}
}
Claude Code (terminal)
Add from CLI:
claude mcp add --transport stdio \
--env SLACKKER_PLATFORM=slack \
--env SLACKKER_TOKEN=xoxb-... \
--env SLACKKER_CHANNEL_ID=C04AAB77ABC \
slackker -- slackker-mcp
Or project config (.mcp.json):
{
"mcpServers": {
"slackker": {
"type": "stdio",
"command": "slackker-mcp",
"env": {
"SLACKKER_PLATFORM": "slack",
"SLACKKER_TOKEN": "xoxb-...",
"SLACKKER_CHANNEL_ID": "C04AAB77ABC"
}
}
}
}
OpenCode (`opencode.json`)
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"slackker": {
"type": "local",
"command": ["slackker-mcp"],
"enabled": true,
"environment": {
"SLACKKER_PLATFORM": "slack",
"SLACKKER_TOKEN": "xoxb-...",
"SLACKKER_CHANNEL_ID": "C04AAB77ABC"
}
}
}
}
File-based config variant:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"slackker": {
"type": "local",
"command": ["slackker-mcp", "--config", "/absolute/path/slackker_mcp.json"],
"enabled": true
}
}
}
Cursor / Continue / Roo / Antigravity (common stdio shape)
{
"mcpServers": {
"slackker": {
"command": "slackker-mcp",
"env": {
"SLACKKER_PLATFORM": "slack",
"SLACKKER_TOKEN": "xoxb-...",
"SLACKKER_CHANNEL_ID": "C04AAB77ABC"
}
}
}
}
File path and top-level key names can vary by client/plugin version.
Hermes / other terminal MCP hosts
Use whichever config file your host expects, with these required fields:
- transport: local/stdio
- command:
slackker-mcp - env:
SLACKKER_*(or args--config /path/to/slackker_mcp.json)
Minimal generic example:
{
"mcpServers": {
"slackker": {
"command": "slackker-mcp",
"env": {
"SLACKKER_PLATFORM": "slack",
"SLACKKER_TOKEN": "xoxb-...",
"SLACKKER_CHANNEL_ID": "C04AAB77ABC"
}
}
}
}
Use with Keras
from slackker.core import TelegramClient
from slackker.callbacks.keras import KerasCallback
client = TelegramClient(
token="1234567890:AAAAA_A111BBBBBCCC2DD3eEe44f5GGGgGG",
verbose=1,
)
slackker = KerasCallback(
client=client,
model_name="MyModel",
export="png",
send_plot=True,
)
history = model.fit(
x_train, y_train,
epochs=10,
batch_size=32,
validation_data=(x_val, y_val),
callbacks=[slackker],
)
Works with any client:
SlackClient,TelegramClient,TeamsClient, orDiscordClient.
KerasCallback parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
client |
BaseClient |
required | A slackker client instance |
model_name |
str |
required | Name used in messages and plot titles |
export |
str |
"png" |
Plot format (eps, jpeg, jpg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff) |
send_plot |
bool |
False |
Send training/validation plots when training ends |
track_logs |
dict[str, str] | None |
None |
Maps attribute names to Keras logs keys. Defaults to {"train_loss": "loss", "train_acc": "accuracy", "valid_loss": "val_loss", "valid_acc": "val_accuracy"}. Customise for non-standard metric names. |
monitor |
str |
"valid_loss" |
Attribute name from track_logs used to determine the best epoch. Loss-like metrics use argmin; others use argmax. |
Use with Lightning
Unlike Keras, Lightning requires you to explicitly log metrics using self.log() inside your LightningModule. Use on_epoch=True in training_step so slackker can read them at the end of each epoch.
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torchvision as tv
import torch.nn.functional as F
from lightning.pytorch import LightningModule, Trainer
from slackker.core import TelegramClient
from slackker.callbacks.lightning import LightningCallback
class LightningModel(LightningModule):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(28 * 28, 256)
self.fc2 = nn.Linear(256, 128)
self.out = nn.Linear(128, 10)
def forward(self, x):
batch_size, _, _, _ = x.size()
x = x.view(batch_size, -1)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
return self.out(x)
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=1e-3)
def training_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
loss = F.cross_entropy(y_hat, y)
accuracy = (torch.max(y_hat, 1)[1] == y).float().mean()
# log with on_epoch=True so slackker can read them at epoch end
self.log("train_loss", loss, on_epoch=True)
self.log("train_acc", accuracy, on_epoch=True)
return loss
def validation_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
loss = F.cross_entropy(y_hat, y)
accuracy = (torch.max(y_hat, 1)[1] == y).float().mean()
# on_epoch=True by default in validation_step
self.log("val_loss", loss)
self.log("val_acc", accuracy)
return loss
train_data = tv.datasets.MNIST(".", train=True, download=True, transform=tv.transforms.ToTensor())
val_data = tv.datasets.MNIST(".", train=False, download=True, transform=tv.transforms.ToTensor())
train_loader = DataLoader(train_data, batch_size=128)
val_loader = DataLoader(val_data, batch_size=128)
model = LightningModel()
client = TelegramClient(
token="1234567890:AAAAA_A111BBBBBCCC2DD3eEe44f5GGGgGG",
verbose=1,
)
slackker = LightningCallback(
client=client,
model_name="MyModel",
track_logs=["train_loss", "train_acc", "val_loss", "val_acc"],
monitor="val_loss",
export="png",
send_plot=True,
)
trainer = Trainer(max_epochs=10, callbacks=[slackker])
trainer.fit(model, train_loader, val_loader)
Works with any client:
SlackClient,TelegramClient,TeamsClient, orDiscordClient.
LightningCallback parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
client |
BaseClient |
required | A slackker client instance |
model_name |
str |
required | Name used in messages and plot titles |
track_logs |
list[str] |
required | Metrics to track and report each epoch |
monitor |
str |
None |
Metric used to determine the best epoch |
export |
str |
"png" |
Plot format (eps, jpeg, jpg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff) |
send_plot |
bool |
False |
Send training plots when training ends |
Support :sparkles:
If you get stuck, we’re here to help. The following are the best ways to get assistance working through your issue:
- Use our Github Issue Tracker for reporting bugs or requesting features.
Contribution are the best way to keep
slackkeramazing :muscle: - If you want to contribute please refer Contributor's Guide for how to contribute in a helpful and collaborative way :innocent:
Citation :page_facing_up:
Please cite slackker in your publications if this is useful for your project/research. Here is an example BibTeX entry:
@misc{siddheshgunjal2023slackker,
title={slackker},
author={Siddhesh Gunjal},
year={2023},
howpublished={\url{https://github.com/siddheshgunjal/slackker}},
}
Maintainer :sunglasses:
Metadata
Release files for slackker 2.0.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| slackker-2.0.4.tar.gz | 556.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| slackker-2.0.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 606.2 kB
Release files / slackker-2.0.4.tar.gz
| Download URL | slackker-2.0.4.tar.gz |
|---|---|
| Size | 556.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4afbcf149bbb267138864d0e9d10e3e6a0d64785dd3f064e3e3420b38471daae
|
|
BLAKE2b-256 checksum How to use checksums |
19aa898701ea937ac88412c328e61c961ce88f63d7a32531564ba72f149b5a78
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / slackker-2.0.4-py3-none-any.whl
| Download URL | slackker-2.0.4-py3-none-any.whl |
|---|---|
| Size | 49.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0741ed59a44cc5a76fb3047ff078c2770564fa08ea41ffc05cbe4055868d16ef
|
|
BLAKE2b-256 checksum How to use checksums |
a59e34be3061d8785ae303db8a441a273110493d4b9cb019c4eea5a00c3fdbba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|