Skip to content

Architecture ​

High Level Architecture ​

LazyTeams follows a Clean Architecture design with SRP enforcement. Packages are isolated and interact only via dependency injection. The UI layer uses Elm Architecture (Model-Update-View) via Bubble Tea.

Package Structure ​

lazyteams/
├── main.go                          # Entry point
├── cmd/
│   └── auth-helper/                 # Playwright auth helper (captures tokens & cookies)
│       ├── main.go                  # Capture/renew logic + CLI flags
│       ├── console_windows.go       # ANSI/VT + UTF-8 setup on Windows
│       └── console_other.go         # No-op console setup on Linux/macOS
└── internal/
    ├── auth/                        # Tokens (reading + JWT parsing)
    │   └── auth.go                  # GetTokens(), loadTokensFile(), ParseUserNameFromToken()
    ├── graph/                       # HTTP client for Microsoft Graph API
    │   ├── client.go                # Client, doReq(), cleanHTML()
    │   ├── urls.go                  # Microsoft host allowlist (token exfiltration guard)
    │   ├── teams_api.go             # Teams and channels
    │   ├── chats_api.go             # Chats, auto-discovery self-chat
    │   ├── messages_api.go          # Read/write messages (ChatSvc)
    │   ├── files_api.go             # Drive browser, remote items
    │   ├── upload_api.go            # File uploading chunked sessions
    │   ├── download_api.go          # File downloads
    │   ├── ams_api.go               # Azure Media Services (Inline image pasting)
    │   ├── presence_api.go          # Get/Set/Clear presence
    │   ├── assignments_api.go       # Education Assignments (blocked by WAF)
    │   ├── activity_api.go          # Notifications via ChatSvc
    │   ├── auth_check.go            # Lightweight token health checks
    │   └── debug_api.go             # Debug endpoints
    ├── helpers/                     # Shared cross-domain helpers
    │   └── fs.go                    # ConfigDir(), HomeDir(), Process management
    ├── teams/teams.go               # Attachment aggregation, file icons
    ├── version/                     # Version string + GitHub update check
    │   ├── version.go               # Version string & comparison
    │   ├── update.go                # API client for GitHub releases + SHA-256 verification
    │   ├── replace_unix.go          # Atomic executable replacement for POSIX
    │   └── replace_windows.go       # Detached executable replacement for Windows
    └── ui/                          # TUI (Elm Architecture with Bubble Tea)
        ├── components/              # Reusable sub-components
        │   └── directorypicker/     # Interactive filesystem browser
        ├── clipboard.go             # Native OS clipboard image extraction
        ├── commands.go              # tea.Cmd constructors (API calls)
        ├── format.go                # Message formatting logic
        ├── helpers.go               # Pure utility functions
        ├── help.go                  # Cheat sheet renderer
        ├── model.go                 # Application state
        ├── prefs.go                 # Persistent preferences on disk
        ├── styles.go                # Lipgloss styles
        ├── symbols.go               # UI unicode symbols and icons
        ├── types.go                 # Shared type definitions
        ├── update.go                # Main state machine
        ├── update_data.go           # Network/API response handling
        ├── update_insert.go         # Textarea input logic
        ├── update_keys.go           # Keybinding routing
        ├── update_popups.go         # Floating windows logic
        └── view.go                  # Rendering logic (Layouts, Panels)

Design Principles ​

Clean Architecture ​

The ui package never makes HTTP calls. All network requests pass through graph and teams via tea.Cmd (async commands). This enforces a strict separation of concerns.

Elm Architecture (Model-Update-View) ​

Every UI component follows the Elm pattern:

  1. Model: Holds the entire application state
  2. Update: Pure function that handles events and returns new state + commands
  3. View: Pure function that renders the current state to the terminal

4 Workspaces ​

The application is organized into 4 workspaces, each with a left panel (list) and right panel (detail):

Auth Helper — How It Works ​

The helper uses Playwright with Firefox to capture tokens automatically:

  1. Persistent session (~/.config/lazyteams/browser-session/): after the first login, subsequent runs skip credentials.
  2. Request interceptor (context.On("request")): captures every Bearer token Teams sends, discriminating by aud (JWT claim).
  3. Automatic navigation: the helper navigates through Teams to trigger requests containing the required tokens.
  4. Graph Explorer: at the end of the loop, if MS_GRAPH_TOKEN is missing, opens Graph Explorer and captures the token from the interceptor or DOM.

Key Discoveries During Development ​

  • Teams v2 uses substrate.office.com as a Graph proxy — it does not make direct requests to graph.microsoft.com
  • The aud for Microsoft Graph is the GUID 00000003-0000-0000-c000-000000000000, not the string graph.microsoft.com
  • TEAMS_NOTIF_TOKEN and TEAMS_WEB_TOKEN are the same token (interchangeable)
  • MSAL does not persist refresh tokens in IndexedDB — tokens live only in JS memory