Skip to main content

Messaging connectors giving AI agents authenticated, normalized access to email and chat platforms

Project description

appif -- Application Interfaces

A Python library that gives AI agents authenticated, normalized access to external platforms -- email, chat, and work tracking systems.

Purpose

Agents need information that lives behind logins: email threads, Slack messages, Jira tickets. This library provides connectors and adapters that authenticate as you and return clean, structured domain objects suitable for agent reasoning -- platform-specific APIs are fully encapsulated behind shared protocols.

Two domains are supported:

  • Messaging -- Gmail, Outlook, Slack. Unified MessageEvent objects via the Connector protocol.
  • Work Tracking -- Jira. Unified WorkItem objects via the WorkTracker protocol. Multi-instance support with YAML config.

For the complete usage guide -- the unified model, per-connector mapping tables, code examples, and environment variable reference -- see docs/usage.md.

Quick Start

Messaging (Gmail, Outlook, Slack)

pip install appif
from appif.adapters.gmail import GmailConnector
from appif.domain.messaging.models import MessageEvent, MessageContent

class MyListener:
    def on_message(self, event: MessageEvent) -> None:
        print(f"[{event.connector}] {event.author.display_name}: {event.content.text}")

connector = GmailConnector()
connector.connect()
connector.register_listener(MyListener())

All three messaging connectors (Gmail, Outlook, Slack) follow this same pattern. The full model, per-connector setup, and examples are in docs/usage.md.

Work Tracking (Jira)

from appif.domain.work_tracking.service import WorkTrackingService
from appif.domain.work_tracking.models import CreateItemRequest, SearchCriteria

service = WorkTrackingService()  # Loads from ~/.config/appif/jira/config.yaml

# Create a ticket
item = service.create_item(CreateItemRequest(
    project="MYPROJECT",
    title="Fix login bug",
    item_type="Bug",
    description="Users cannot log in after password reset",
))
print(f"Created: {item.key}")

# Search
results = service.search(SearchCriteria(project="MYPROJECT", status="To Do"))
for item in results.items:
    print(f"  {item.key}: {item.title}")

See docs/design/work_tracking/setup.md for configuration.

Supported Platforms

Messaging Connectors

Service Connector Inbound Method Status
Gmail Google API (OAuth 2.0) history.list polling Active
Outlook / Microsoft 365 Microsoft Graph API Delta-query polling Active
Slack Slack API (Bolt + Socket Mode) Real-time Socket Mode Active

Work Tracking Adapters

Service Library Auth Method Status
Jira Cloud atlassian-python-api API token (YAML config) Active

CLI

The Slack adapter includes a command-line interface:

# Install makes the CLI available
pip install appif

# List channels, send messages, monitor in real-time
appif-slack channels
appif-slack send --channel general "Hello from CLI"
appif-slack monitor --channel general

Installation

For development

uv venv .venv
source .venv/bin/activate
uv pip install -e ".[dev]"

As a library dependency

pip install appif

Prerequisites

  • Python 3.13.x
  • uv (for development)

Configuration

Messaging (environment variables)

Credentials are stored in ~/.env and loaded at runtime:

cp .env.example ~/.env
Variable Service Required
APPIF_GMAIL_CLIENT_ID Gmail Yes -- Google Cloud OAuth client ID
APPIF_GMAIL_CLIENT_SECRET Gmail Yes -- Google Cloud OAuth client secret
APPIF_GMAIL_ACCOUNT Gmail Yes -- Account email address
APPIF_OUTLOOK_CLIENT_ID Outlook Yes -- Azure AD app (client) ID
APPIF_OUTLOOK_TENANT_ID Outlook Optional -- Azure AD tenant (default: common)
APPIF_SLACK_BOT_OAUTH_TOKEN Slack Yes -- Bot user OAuth token (xoxb-...)
APPIF_SLACK_BOT_APP_LEVEL_TOKEN Slack Yes -- App-level token for Socket Mode (xapp-...)

See .env.example for the full template with all optional variables.

Work Tracking (YAML config)

Jira uses a YAML config file at ~/.config/appif/jira/config.yaml:

instances:
  personal:
    jira:
      url: https://your-domain.atlassian.net
      username: your-email@example.com
      api_token: your-api-token

default: personal

Override the config path with APPIF_JIRA_CONFIG env var. Multiple instances supported.

See docs/design/work_tracking/setup.md for the full setup guide.

Project Structure

application_interfaces/
├── src/
│   └── appif/                       # Top-level package (PyPI: appif)
│       ├── __init__.py              # Version via importlib.metadata
│       ├── domain/
│       │   ├── messaging/           # Connector protocol, canonical models, errors
│       │   └── work_tracking/       # WorkTracker protocol, models, service
│       ├── adapters/
│       │   ├── gmail/               # Gmail messaging connector
│       │   ├── outlook/             # Outlook messaging connector
│       │   ├── slack/               # Slack messaging connector
│       │   └── jira/                # Jira work tracking adapter
│       ├── cli/                     # CLI entry points (Slack)
│       └── infrastructure/          # Credential loading
├── tests/
│   ├── unit/                        # 241 unit tests
│   ├── integration/                 # Live API tests (Slack, Jira)
│   └── e2e/
├── scripts/                         # OAuth consent flows, cleanup utilities
├── docs/design/                     # Design documents per adapter
├── pyproject.toml
├── ADAPTERS.md                      # Detailed adapter documentation
├── .env.example
└── readme.md

Development

# Set up dev environment
uv venv .venv
source .venv/bin/activate
uv pip install -e ".[dev]"

# Run all unit tests (241 tests)
pytest tests/unit -v

# Run adapter-specific tests
pytest tests/unit/test_gmail_*.py -v
pytest tests/unit/test_outlook_*.py -v

# Run integration tests (requires live credentials)
pytest tests/integration/test_jira_integration.py -v
pytest tests/integration/test_slack_integration.py -v

# Clean up Jira test tickets
python scripts/jira_cleanup.py

# Lint and format
ruff check src/ tests/
ruff format src/ tests/

# Type check
mypy src/

Architecture

Messaging: Connector Protocol

All messaging connectors implement a shared Connector protocol (appif.domain.messaging.ports.Connector) -- a transport adapter that:

  • Connects to an external system and manages authentication
  • Emits normalized MessageEvent objects to registered listeners
  • Delivers outbound messages via send(target, content)
  • Supports historical backfill alongside realtime event ingestion
  • Advertises capabilities so upstream logic branches on what the connector supports, not which platform it is

All connectors produce identical canonical types (MessageEvent, ConversationRef, SendReceipt). Platform-specific SDK code is fully encapsulated -- zero Slack/Outlook/Gmail types leak through the public interface.

Work Tracking: WorkTracker Protocol

The Jira adapter implements the WorkTracker protocol (appif.domain.work_tracking.ports.WorkTracker):

  • CRUD operations: get, create, comment, transition, link, search
  • Multi-instance support via InstanceRegistry protocol
  • WorkTrackingService routes operations to the correct adapter instance
  • Domain types (WorkItem, CreateItemRequest, SearchCriteria) are platform-agnostic

Internal Module Pattern

Each messaging adapter follows the same decomposition:

src/appif/adapters/<platform>/
├── __init__.py          # Public exports
├── connector.py         # Connector protocol implementation
├── _auth.py             # Authentication (protocol + implementation)
├── _normalizer.py       # Platform message -> MessageEvent
├── _message_builder.py  # MessageContent -> platform request (email adapters)
├── _poller.py           # Inbound message detection (email adapters)
└── _rate_limiter.py     # Retry + platform error -> domain error mapping

The Jira adapter uses a similar pattern with adapter.py (operations), _auth.py (YAML config + client), and _normalizer.py (API dicts to domain types).

Credential Setup

Adapter Auth Method Setup Guide
Gmail OAuth 2.0 (python scripts/gmail_consent.py <account>) docs/design/gmail/setup.md
Outlook OAuth 2.0 (python scripts/outlook_consent.py <account>) docs/design/outlook/setup.md
Slack Bot + App tokens from Slack app config docs/design/slack/setup.md
Jira API token in YAML config docs/design/work_tracking/setup.md

Documentation

Document Description
ADAPTERS.md Detailed adapter documentation (all platforms)
docs/usage.md Unified messaging model and code examples
docs/design/gmail/ Gmail design, technical design, setup
docs/design/outlook/ Outlook design, technical design, setup
docs/design/slack/ Slack design, setup, CLI checklist
docs/design/work_tracking/ Jira requirements, design, technical design, setup

License

MIT -- see LICENSE.

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

appif-0.3.1.tar.gz (172.6 kB view details)

Uploaded Source

Built Distribution

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

appif-0.3.1-py3-none-any.whl (68.6 kB view details)

Uploaded Python 3

File details

Details for the file appif-0.3.1.tar.gz.

File metadata

  • Download URL: appif-0.3.1.tar.gz
  • Upload date:
  • Size: 172.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","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 appif-0.3.1.tar.gz
Algorithm Hash digest
SHA256 64ab07980ddcaeebe25831b0ed1bf769b40fabb6dee96cbcb031a789759f5c9e
MD5 08b5c8f5c50f0be9027622fc37437ed2
BLAKE2b-256 f8775e6f9df15ccb7eda90b0439af42dd1551c378e24c298c42cbe28ee1482ae

See more details on using hashes here.

File details

Details for the file appif-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: appif-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 68.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","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 appif-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ace45daf7da2b86def88a2f7d9936ea7b3afbfd71881af29c589dcaba59ae266
MD5 2ae2baeebb034fe20c078613ed13e6bd
BLAKE2b-256 6f196039e702d0e50336006ff69f19d08ca0685961a739bafb4196bb9485e5cb

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