Skip to main content

Chattice

Chattice

Async, typed event framework for Google Chat apps — aiogram-quality DX, Google-native semantics.

Python License Status Discussions

from chattice import Dispatcher, F, Router
from chattice.events import MessageEvent

router = Router()


@router.message(F.text == "ping")
async def ping(message: MessageEvent) -> str:
    return "pong"  # synchronous interaction response (no auth, 30 s deadline)


dispatcher = Dispatcher()
dispatcher.include_router(router)

What this is

  • Google Chat-native. Space, Thread, Message, Command, Action, Card, Dialog, App Home, Workspace Events are first-class typed objects. No Telegram concepts leak into the domain model.
  • aiogram ergonomics. Routers, magic filters (F), middleware, dependency injection, FSM — the DX you know, without Telegram semantics.
  • Explicit response model. A handler RETURN is the synchronous interaction response (30 s deadline); outbound Bot calls are separate authenticated operations. Contextual message.reply() / thread.send() / space.send() methods are zero-fetch adapters over that same Bot, never a hidden second channel.
  • Secure by default. Incoming verification is fail-closed, push endpoints require a verifier, outbound privacy gates (private messages, notifications, preview features) fail closed before any network call.
  • Diagnosable in production. DEBUG routing logs identify the observer, handler, and result; Pub/Sub failures include safe delivery context, exception messages, and tracebacks without dumping raw event payloads.
  • Core is small. Core abstracts Google Chat platform primitives and technical boilerplate ONLY. Business scenarios (polls, approvals, tickets) are assembled from the primitives in your application code — never added to core.
  • Curated outbound facade. An operation registry is the single source of outbound auth truth; identity-bound resource clients (bot.app.* / bot.user.* for spaces, messages, memberships, reactions, and per-user state) and one executor path make every Google call explicit about who is calling.
  • Explicit identity. APP and USER are always chosen by the caller (bot.raw.app() / bot.raw.user()); the framework never switches silently. Direct messages are first-class: bot.user.spaces.get_or_setup_direct_message(...) returns the official Space with its clickable space_uri.
  • Diagnosable in production. Structured lifecycle stages (handler_started before invocation), stage-tagged error logs, Pub/Sub delivery identity/age, per-card update serialization, configurable RuntimeDiagnostics thresholds, and CI-verified operation registry against the Google discovery document.

What this is not

  • Not a Telegram framework. No chat_id, no CallbackQuery, no Update hierarchy, no Telegram-style long polling (see the aiogram comparison).
  • Not a Google product. Independent open-source project, not endorsed by Google.

Two ways to run

Chattice has two honest startup models (see the aiogram side-by-side):

# HTTP — Google calls your HTTPS endpoint; the handler RETURN is the
# synchronous response (Dialogs and App Home work here).
app.include_router(create_chat_router(dispatcher, GoogleTokenVerifier(audience=...)))
# python -m uvicorn app:app

# Pub/Sub streaming pull — a persistent subscriber process, visually
# like aiogram's start_polling, but it is NOT Telegram polling.
# No domain/TLS needed; no Dialogs, no App Home — answers go outbound
# through the authenticated Bot.
await dispatcher.run_pubsub(subscription, bot=bot)
# python app.py

Capabilities

Area Support
Events MESSAGE, CARD_CLICKED, APP_COMMAND (slash/quick/message actions), ADDED/REMOVED_FROM_SPACE, APP_HOME, SUBMIT_FORM, WIDGET_UPDATED
Routing Routers, observer-wide filters, magic filters, middleware, DI
Cards Typed facades, public/non-sensitive PNG/JPEG publication through an optional AssetPublisher, sync updates
Memberships APP-auth add/get/list/remove for human users; caller-member Space listing
Dialogs OPEN_DIALOG, submit/cancel observers, action status; capability-gated per transport
FSM State/StatesGroup, Memory + Redis record storage (compare-and-set)
Ingress HTTP (verified), Pub/Sub push (verified), Pub/Sub streaming pull, Workspace Events CloudEvents
Media Local-file attachments sent with USER auth end to end (media.upload → messages.create, sender = HUMAN); download USER/APP; metadata APP; 200 MB local preflight
Auth App (service account), user (OAuth refresh), incoming verification
Diagnostics DEBUG routing diagnostics, structured Pub/Sub failure logs, typed Chat API errors
Testing MockBot, EventFactory, assertions, fake transport

Install

Python 3.11+ (3.11–3.13 tested). MIT-licensed.

pip install "chattice[fastapi,pubsub,redis]"  # core + all integrations

# or pick only what you need:
#   pip install chattice            core
#   pip install "chattice[fastapi]" FastAPI integration
#   pip install "chattice[redis]"   Redis FSM/idempotency storage
#   pip install "chattice[pubsub]"  Pub/Sub push + streaming pull
#   pip install "chattice[media]"   Media/attachment uploads (Google API client)
#   pip install "chattice[gcs]"     Local Card image publication through GCS
#   pip install "chattice[gemini]"  Experimental Gemini agent bridge

# using uv
uv add "chattice[fastapi,pubsub,redis]"

Quickstart

  1. Parse a documented interaction payload:
from chattice.adapters.google_chat import parse_interaction

event = parse_interaction(payload)
result = await dispatcher.feed_update(event)
  1. Serve HTTP interactions (FastAPI):
from fastapi import FastAPI
from chattice.integrations.fastapi import create_chat_router
from chattice.transports.http import GoogleTokenVerifier

app = FastAPI()
app.include_router(create_chat_router(dispatcher, GoogleTokenVerifier(audience="...")))
  1. Send messages:
from chattice.client import Bot

bot = Bot(credentials=...)
await bot.app.messages.create("spaces/AAA", text="hello")

Inside an interaction handler, configure the same Bot once and use the known Google context without extra fetches:

dispatcher = Dispatcher(bot=bot)


@router.message()
async def reply(message: MessageEvent) -> None:
    await message.reply("hello in this thread")

Docs

Start with Installation, the 5-minute Quickstart, and the Space → Thread → Message mental model. The public API reference, Google mapping, the debugging guide, and aiogram comparison are linked from the docs site. Runnable examples live in examples/; machine-readable documentation is available in llms.txt.

Status

Pre-1.0 public release (current version 0.3.0) — see CHANGELOG. The documented public surface is the compatibility baseline: pre-1.0 work may add APIs but does not incompatibly rename, remove, or change existing contracts. chattice.experimental has no compatibility promise. bot.raw.app() / bot.raw.user() and raw event payloads follow Google's SDK and wire schema rather than the stable facade promise. Not an official Google product — independent open-source software, not endorsed by Google. MIT License, see LICENSE.

Metadata

Release files for chattice 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chattice 0.3.0
File Size Uploaded
chattice-0.3.0.tar.gz 2.8 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for chattice 0.3.0
File Interpreter ABI Platform
chattice-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 3.0 MB

Release files / chattice-0.3.0.tar.gz

Download URL chattice-0.3.0.tar.gz
Size 2.8 MB
Tags Source
SHA-256 checksum
How to use checksums
d78ea2e79a51792799d67bca20f5a1804fe63b501bfd1c225796a777563e07cc
BLAKE2b-256 checksum
How to use checksums
398b9c32e77ab0bcce72905b32139dd943d3438eaa51eeed98c811932091b555
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","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 / chattice-0.3.0-py3-none-any.whl

Download URL chattice-0.3.0-py3-none-any.whl
Size 170.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ed856e4d80013369beb7b200ce49ab85b873f57b227c7c99ac59a046bb1eec1b
BLAKE2b-256 checksum
How to use checksums
b571f295bd78d8d7fb1311167dbb35959820d214c2c0d02ced9c798f337a456b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","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 history Release notifications | RSS feed

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page