# Group Terminal > Terminal-based group chat system for testing AI agent integrations Group Terminal is a minimalistic, terminal-based group chat system designed for testing and prototyping AI service integrations. It provides a zero-configuration WebSocket-based chat server and Rich-powered terminal clients that eliminate authentication, databases, and user management complexity. Build and test server-side message handlers that respond to group chat messages with immediate visual feedback. Unix-specific (uses termios, will not work on Windows). # User Guide # Overview Group Terminal is a minimalistic, terminal-based group chat system designed for testing and prototyping AI service integrations. Most group chat systems require authentication, databases, and user management before you can test a single message handler or prototype collaboration of user groups with AI. Group Terminal eliminates this complexity by providing a minimal WebSocket-based chat server and [Rich](https://github.com/Textualize/rich)-powered terminal clients that let you focus on testing your integration logic rather than infrastructure setup. Note Group Terminal uses [termios](https://docs.python.org/3/library/termios.html) for terminal control and is Unix-specific. It will not work on Windows systems. ## Installation ``` pip install group-terminal ``` ## Quickstart The included example demonstrates how to launch a chat server and register a message handler. The handler echoes back each received message with the pattern "I received '{message}' from {username}". This showcases a basic service integration pattern. Here's the essential code: examples/app.py ``` import asyncio from group_terminal.server import ChatServer class ChatApp: def __init__(self, host: str, port: int): self._server = ChatServer(host=host, port=port) self._server.add_handler(self._handle_message) @property def server(self): return self._server async def _process_message(self, content: str, username: str): # potentially long-running operation ... response = f"I received '{content}' from {username}" # send response to chat clients await self._server.send_message(response, sender="agent", agent=True) async def _handle_message(self, content: str, username: str): # Handles messages generated by chat clients i.e. users. A # handler is called sequentially in message arrival order. # This is the same order as seen in the chat client. # Operations that require preserving message arrival order # (adding to a queue, ...) should be done here. Long-running # message processing should be done asynchronously to prevent # blocking the message receiver loop. asyncio.create_task(self._process_message(content, username)) app = ChatApp(host="0.0.0.0", port=8723) await app.server.start() await app.server.join() ``` See the [complete example](https://github.com/gradion-ai/group-terminal/blob/main/examples/app.py) for full implementation details. Start the server: ``` python examples/app.py ``` In separate terminals, launch two clients with different usernames: ``` python -m group_terminal.client --username alice python -m group_terminal.client --username bob ``` The screenshots below show a conversation where `alice` sends "Hey everyone! How's it going?" and `bob` replies "Pretty good!". Notice the color coding: your own messages appear in orange, messages from other users in cyan, and agent responses in green. The message handler echoes each message back to all connected clients. `alice`'s view: `bob`'s view: # API Documentation ## group_terminal.server.ChatServer ``` ChatServer(host: str = 'localhost', port: int = 8723) ``` WebSocket-based group chat server for testing and demonstration purposes. Manages client connections, message broadcasting, and custom message handlers. Supports multiple clients connecting with distinct usernames to participate in a shared chat session. Multiple connections with the same username are not allowed. Example Basic server with a message handler:: ``` async def handle_message(content: str, username: str): print(f"Received '{content}' from {username}") server = ChatServer(host="0.0.0.0", port=8723) server.add_handler(handle_message) await server.start() await server.join() ``` Initialize the chat server. Parameters: | Name | Type | Description | Default | | ------ | ----- | ----------------------------------------------------------------------------------------------------------------- | ------------- | | `host` | `str` | The hostname or IP address to bind the server to. Use "0.0.0.0" to accept connections from any network interface. | `'localhost'` | | `port` | `int` | The port number to listen on for WebSocket connections. | `8723` | ### add_handler ``` add_handler(handler: MessageHandler) ``` Register a callback to handle incoming chat messages. Handlers are called sequentially in the order that messages arrive from clients. This is the same order that messages appear in chat clients. For operations that preserve message arrival order (such as adding to a queue), perform them directly in the handler. For long-running message processing, delegate to background tasks to avoid blocking the message receiver loop. Parameters: | Name | Type | Description | Default | | --------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | | `handler` | `MessageHandler` | Callback function that receives message content and username. Multiple handlers can be registered and will be called in registration order for each message. | *required* | ### start ``` start() ``` Start the chat server asynchronously. Returns immediately after launching the server task. The server runs in the background and begins accepting WebSocket connections. ### stop ``` stop() ``` Stop the server gracefully. Signals the server to shut down and waits for the server task to complete. ### join ``` join() ``` Wait for the server to complete. Blocks until stop is called from another task. If you have other means to keep your main coroutine alive, calling join is not necessary. ## group_terminal.server.MessageHandler ``` MessageHandler = Callable[[str, str], Awaitable[None]] ``` Callback function for handling incoming chat messages. Handlers receive messages in the order they arrive and are called sequentially. For long-running operations, implementations should delegate work to background tasks to avoid blocking the message receiver loop. Parameters: | Name | Type | Description | Default | | ---------- | ----- | --------------------------------------------- | ---------- | | `content` | `str` | The message content sent by a user | *required* | | `username` | `str` | The username of the user who sent the message | *required* | ## group_terminal.client.ChatClient ``` ChatClient(username: str, host: str = 'localhost', port: int = 8723, **terminal_kwargs) ``` Bases: `MessageSender` Terminal-based chat client for testing and demonstration purposes. Provides a [Rich](https://github.com/Textualize/rich)-based terminal interface for interacting with a group of users and services connected to a ChatServer instance. Intended for testing and demonstration only, not for production use in applications. The client is typically started from the command line using: `python -m group_terminal.client --username `. Note This client uses [termios](https://docs.python.org/3/library/termios.html) for terminal control and is Unix-specific. It will not work on Windows systems. Initialize the chat client. Parameters: | Name | Type | Description | Default | | ---------- | ----- | ---------------------------------------------- | ------------- | | `username` | `str` | The name of the this client's user. | *required* | | `host` | `str` | The hostname or IP address of the chat server. | `'localhost'` | | `port` | `int` | The port number of the chat server. | `8723` | ### connect ``` connect() -> bool ``` Connect to the chat server. ### join ``` join() ``` Join a connected client until disconnected.