airbyte_ops_mcp.cli.roster

CLI commands for internal team roster operations.

Commands:

airbyte-ops roster generate - Generate roster artifact from Slack and GitHub APIs airbyte-ops roster summary - Print a matching summary from a roster JSON artifact

CLI reference

The commands below are regenerated by poe docs-generate via cyclopts's programmatic docs API; see docs/generate_cli.py.

airbyte-ops roster COMMAND

Internal team roster operations.

Commands:

  • generate: Generate the internal team roster from Slack and GitHub APIs.
  • summary: Print a matching summary from a roster JSON artifact.

airbyte-ops roster generate

airbyte-ops roster generate OUTPUT

Generate the internal team roster from Slack and GitHub APIs.

Requires SLACK_HYDRA_BOT_TOKEN (or SLACK_AIRBYTE_TEAM_READ_USERS) and GITHUB_TOKEN environment variables.

Parameters:

  • OUTPUT, --output: Output file path for the roster JSON artifact. [required]

airbyte-ops roster summary

airbyte-ops roster summary INPUT

Print a matching summary from a roster JSON artifact.

Categorises roster members into matched, Slack-only, and GitHub-only groups and prints unmatched members for review.

Parameters:

  • INPUT, --input: Path to a roster JSON file (produced by the generate command). [required]
 1# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
 2"""CLI commands for internal team roster operations.
 3
 4Commands:
 5    airbyte-ops roster generate - Generate roster artifact from Slack and GitHub APIs
 6    airbyte-ops roster summary  - Print a matching summary from a roster JSON artifact
 7
 8## CLI reference
 9
10The commands below are regenerated by `poe docs-generate` via cyclopts's
11programmatic docs API; see `docs/generate_cli.py`.
12
13.. include:: ../../../docs/generated/cli/roster.md
14   :start-line: 2
15"""
16
17from __future__ import annotations
18
19# Hide Python-level members from the pdoc page for this module; the rendered
20# docs for this CLI group come entirely from the grafted `.. include::` in
21# the module docstring above.
22__all__: list[str] = []
23
24import os
25from pathlib import Path
26from typing import Annotated
27
28from cyclopts import Parameter
29
30from airbyte_ops_mcp.cli._base import App, app
31from airbyte_ops_mcp.cli._shared import console, exit_with_error, print_success
32from airbyte_ops_mcp.github_api import resolve_default_github_token
33from airbyte_ops_mcp.internal_team_roster import (
34    generate_roster_to_file,
35    summarize_roster,
36)
37
38# Create the roster sub-app
39roster_app = App(name="roster", help="Internal team roster operations.")
40app.command(roster_app)
41
42
43@roster_app.command(name="generate")
44def roster_generate(
45    output: Annotated[
46        str,
47        Parameter(help="Output file path for the roster JSON artifact."),
48    ],
49) -> None:
50    """Generate the internal team roster from Slack and GitHub APIs.
51
52    Requires SLACK_HYDRA_BOT_TOKEN (or SLACK_AIRBYTE_TEAM_READ_USERS) and
53    GITHUB_TOKEN environment variables.
54    """
55    slack_token = os.environ.get("SLACK_HYDRA_BOT_TOKEN") or os.environ.get(
56        "SLACK_AIRBYTE_TEAM_READ_USERS",
57    )
58    if not slack_token:
59        exit_with_error(
60            "SLACK_HYDRA_BOT_TOKEN or SLACK_AIRBYTE_TEAM_READ_USERS "
61            "environment variable is required."
62        )
63
64    github_token = os.environ.get("GITHUB_TOKEN")
65    if not github_token:
66        github_token = resolve_default_github_token()
67
68    count = generate_roster_to_file(
69        output_path=Path(output),
70        slack_token=slack_token,
71        github_token=github_token,
72    )
73    print_success(f"Roster generated: {count} members written to {output}")
74
75
76@roster_app.command(name="summary")
77def roster_summary(
78    input: Annotated[
79        str,
80        Parameter(
81            help="Path to a roster JSON file (produced by the generate command)."
82        ),
83    ],
84) -> None:
85    """Print a matching summary from a roster JSON artifact.
86
87    Categorises roster members into matched, Slack-only, and GitHub-only
88    groups and prints unmatched members for review.
89    """
90    path = Path(input)
91    if not path.exists():
92        exit_with_error(f"Roster file not found: {input}")
93
94    text = summarize_roster(path)
95    console.print(text)