Skip to content

Architecture

C4 Level 1: System Context

The user interacts with Glean Search through Raycast. The extension delegates all search and authentication to the Glean CLI, which communicates with the Glean cloud API.

flowchart TB
    User["User<br/>Raycast user"]
    System["Glean Search<br/>Raycast Extension"]
    GleanAPI["Glean Cloud API<br/>Search + Auth endpoints"]
    CLI_Source["GitHub Releases<br/>glean-cli binary"]
    Browser["Browser<br/>OAuth provider"]
    Keychain["macOS Keychain<br/>Token storage"]

    User -->|"types query<br/>clicks sign in"| System
    System -->|"glean search<br/>glean auth"| GleanAPI
    System -->|"auto-downloads"| CLI_Source
    System -->|"opens OAuth URL"| Browser
    Browser -->|"OAuth callback"| System
    System -->|"stores/reads tokens"| Keychain

    style System fill:#5e81ac,stroke:#2e3440,color:#fff
    style User fill:#88c0d0,stroke:#2e3440,color:#2e3440
Element Description
User A person searching their company's knowledge base via Raycast
Glean Search The Raycast extension (this project). Auto-downloads CLI, manages auth, executes search
Glean Cloud API The Glean backend providing search and OAuth endpoints
GitHub Releases Source of the pre-built glean-cli binary, verified via SHA-256
Browser OAuth 2.0 + PKCE flow opened in the user's default browser
macOS Keychain Secure credential storage used by the Glean CLI

C4 Level 2: Container Diagram

The extension is a single Raycast command with four internal modules that orchestrate the Glean CLI.

flowchart TB
    subgraph Raycast["Raycast Runtime"]
        Command["search-glean.tsx<br/>React Component<br/>(UI + state)"]
    end

    subgraph Modules["Extension Modules"]
        Hook["glean.ts<br/>useGlean hook<br/>(orchestrator)"]
        Auth["auth.ts<br/>Auth manager<br/>(OAuth + status)"]
        CLI["cli.ts<br/>Binary manager<br/>(discovery + download)"]
        Types["types.ts<br/>Shared types<br/>(interfaces)"]
    end

    subgraph External["External Dependencies"]
        GleanCLI["glean CLI<br/>/usr/local/bin/glean<br/>or auto-downloaded"]
        GitHub["github.com/gleanwork<br/>glean-cli releases"]
        GleanAPI["Glean Cloud API"]
        Config["~/.glean/config.json<br/>Server URL cache"]
        Keychain["macOS Keychain<br/>OAuth tokens"]
    end

    Command -->|"useGlean()"| Hook
    Hook -->|"resolveGleanCli()"| CLI
    Hook -->|"checkGleanAuth()<br/>signInToGlean()"| Auth
    Hook -->|"search(query)"| GleanCLI
    CLI -->|"download"| GitHub
    CLI -->|"verify SHA-256"| GitHub
    Auth -->|"glean auth status"| GleanCLI
    Auth -->|"glean auth login"| GleanCLI
    GleanCLI -->|"HTTP"| GleanAPI
    GleanCLI -->|"read/write"| Config
    GleanCLI -->|"read/write"| Keychain

    style Raycast fill:#3b4252,stroke:#81a1c1,color:#e5e9f0
    style Modules fill:#434c5e,stroke:#88c0d0,color:#e5e9f0
    style External fill:#2e3440,stroke:#4c566a,color:#d8dee9
Container Technology Responsibility
search-glean.tsx React (Raycast SDK) Single command view. Renders search results, auth forms, error/loading states
glean.ts TypeScript + React hooks Orchestrates lifecycle: CLI discovery, auth checking, search execution
auth.ts TypeScript + child_process Reads config.json, runs glean auth status/login, parses output
cli.ts TypeScript + https + child_process Binary discovery chain, auto-download with SHA-256, caching
types.ts TypeScript GleanResult, GleanSearchResponse, AuthInfo, GleanSnippet, GleanDocument

C4 Level 3: Component Diagram

search-glean.tsx — UI States

stateDiagram-v2
    [*] --> Initializing: mount
    Initializing --> CLI_Not_Found: resolveGleanCli() fails
    Initializing --> Unauthenticated: CLI found, no session

    Unauthenticated --> Email_Form: needsEmail === true
    Unauthenticated --> Sign_In_Button: server URL known

    Email_Form --> Signing_In: submit email
    Sign_In_Button --> Signing_In: click sign in

    Signing_In --> Search_UI: OAuth success
    Signing_In --> Unauthenticated: failure (retryable)
    Signing_In --> Email_Form: needs email

    CLI_Not_Found --> Initializing: retryCliDiscovery()
    CLI_Not_Found --> Search_UI: auto-download succeeds

    Search_UI --> [*]: unmount

glean.ts — Hook Lifecycle

flowchart LR
    subgraph Mount["On Mount"]
        A["resolveGleanCli()"] --> B{"binary found?"}
        B -->|"yes"| C["checkGleanAuth()"]
        B -->|"no"| D["show CLI not found"]
        C --> E{"authed?"}
        E -->|"yes"| F["show search UI"]
        E -->|"no"| G{"needsEmail?"}
        G -->|"yes"| H["show email form"]
        G -->|"no"| I["show sign in button"]
    end

    subgraph SignIn["On Sign In"]
        J["signInToGlean(path, email?)"]
        J --> K{"GLEAN_SERVER_URL set?"}
        K -->|"yes"| L["spawn with stdin closed"]
        K -->|"no, email provided"| M["pipe email to stdin"]
        L --> N["extract OAuth URL from output"]
        M --> N
        N --> O["open() via Raycast API"]
        O --> P["wait for CLI exit code 0"]
        P -->|"success"| Q["recheckAuth()"]
        P -->|"failure: reading email"| R["toggle needsEmail"]
    end

    subgraph Search["On Search"]
        S["AbortController.abort() prev"]
        T["search(query, signal)"]
        T --> U["execFile(\"glean search\")"]
        U --> V["parse JSON response"]
        V --> W["setResults(items)"]
    end

cli.ts — Binary Discovery Chain

flowchart TB
    Start["resolveGleanCli()"] --> Cache["read cli-info.json"]
    Cache --> Cached{"path exists<br/>and executable?"}
    Cached -->|"yes"| Return["return cached path"]
    Cached -->|"no"| Download["check cached download"]
    Download --> Downloaded{"binary exists?"}
    Downloaded -->|"yes"| Return
    Downloaded -->|"no"| Homebrew["check /opt/homebrew/bin/glean<br/>/usr/local/bin/glean"]
    Homebrew --> BrewFound{"found?"}
    BrewFound -->|"yes"| Return
    BrewFound -->|"no"| Which["which glean"]
    Which --> WhichFound{"found?"}
    WhichFound -->|"yes"| Return
    WhichFound -->|"no"| GitHub["fetch latest release<br/>from GitHub API"]
    GitHub --> Checksum["fetch checksums.txt"]
    Checksum --> Verify["download + SHA-256 verify"]
    Verify --> Extract["extract tar.gz"]
    Extract --> Cache["write cli-info.json"]
    Cache --> Return
    Verify -->|"failure"| Fail["markDownloadFailed()"]
    Fail --> Path["check PATH again"]
    Path --> Return
    Return -->|"null"| UI["show CLI not found UI"]

    style Return fill:#1e3a2f,stroke:#2ecc71,color:#e0e0e0
    style Fail fill:#3a1e1e,stroke:#e74c3c,color:#e0e0e0

Data Flow

Search Sequence

sequenceDiagram
    participant User
    participant UI as search-glean.tsx
    participant Hook as useGlean
    participant CLI as glean CLI
    participant API as Glean API

    User->>UI: type query
    UI->>Hook: search(query, signal)
    Hook->>CLI: execFile("glean search", [query])
    CLI->>API: HTTP request
    API-->>CLI: JSON results
    CLI-->>Hook: stdout
    Hook-->>UI: GleanResult[]
    UI-->>User: render list

Authentication Sequence

sequenceDiagram
    participant User
    participant UI as search-glean.tsx
    participant Auth as auth.ts
    participant CLI as glean CLI
    participant Config as ~/.glean/config.json
    participant Browser
    participant Keychain

    alt Server URL cached
        Config-->>Auth: server_url found
        Auth->>CLI: spawn with GLEAN_SERVER_URL
        Note over CLI: skips email prompt
    else First time
        User-->>Auth: enter email
        Auth->>CLI: pipe email to stdin
        CLI->>Config: save server_url
    end

    CLI->>Browser: open OAuth URL
    User->>Browser: authenticate
    Browser-->>CLI: OAuth callback
    CLI->>Keychain: store token
    CLI-->>Auth: exit 0
    Auth-->>UI: authenticated

Design Decisions

Decision Rationale
CLI delegation over library integration Official Glean client -- reduced maintenance, guaranteed API compatibility
Auto-download over bundling Smaller package, independent version updates, SHA-256 verified
React hooks for state management Stable API surface via useCallback, no unnecessary re-renders
AbortController for search Prevents stale results on fast typing, clean cancellation
spawn over execFile for auth Real-time stdout capture for OAuth URL extraction, stdin control
Config file over preference ~/.glean/config.json persists across extension re-installs

Not affiliated with Glean. Glean is a trademark of Glean Technologies, Inc.