Skip to main content

Python package for monitoring your pipeline & Model training status in real-time on Slack, Telegram and Microsoft Teams.

Project description

Introducing slackker! :fire:

slackker-logo.png

Python Version from PEP 621 TOML Tests Python Build Coverage Website

PyPI - Version

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 :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, TeamsClient prints 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

python-banner

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, or DiscordClient.

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 messages
  • get_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

keras-banner

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, or DiscordClient.

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

Use with Lightning

lightning-banner

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, or DiscordClient.

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 slackker amazing :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:

Static Badge

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slackker-2.0.0.tar.gz (553.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slackker-2.0.0-py3-none-any.whl (48.4 kB view details)

Uploaded Python 3

File details

Details for the file slackker-2.0.0.tar.gz.

File metadata

  • Download URL: slackker-2.0.0.tar.gz
  • Upload date:
  • Size: 553.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","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}

File hashes

Hashes for slackker-2.0.0.tar.gz
Algorithm Hash digest
SHA256 ff58cdc66b1f36dbb18e7f392b81f9e0cb9ea6e7c3e86b13febe0e60de69f1e2
MD5 3f3aef74639fe97059266e3fc8acc2d5
BLAKE2b-256 35adb8a5a55d07435c697853fe935d34e34f913709ab3952e9958b02252e8a8a

See more details on using hashes here.

File details

Details for the file slackker-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: slackker-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 48.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","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}

File hashes

Hashes for slackker-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 761b7aea75dbf8232c215f8df9ed37f206c6ca7c89ca587b86a3e502817b8cf7
MD5 28f05ce662b96264802bb59840cd6c69
BLAKE2b-256 b51d29977c9d1ad27f833c080e28544447802d1531a454afdbfdca9518f3c95b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page