> ## Documentation Index
> Fetch the complete documentation index at: https://lunr-f6858e75.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Python API

> Complete Python API reference for HelixCommit

## GitRepository

Interface for working with Git repositories.

### Constructor

```python theme={}
GitRepository(path: Path, *, prefer_gitpython: bool = True)
```

<ParamField path="path" type="Path" required>
  Path to the Git repository directory.
</ParamField>

<ParamField path="prefer_gitpython" type="bool" default="true">
  Prefer using GitPython when available, with automatic fallback to the git CLI.
</ParamField>

### Methods

<ResponseField name="iter_commits" type="Iterator[CommitInfo]">
  Iterate over commits in a given range.

  ```python theme={}
  commits = repo.iter_commits(commit_range)
  for commit in commits:
      print(commit.subject)
  ```

  **Parameters:**

  * `commit_range: CommitRange` - Range of commits to fetch

  **Returns:** Iterator of `CommitInfo` objects
</ResponseField>

<ResponseField name="list_tags" type="List[TagInfo]">
  List all tags in the repository, sorted by date (newest first).

  ```python theme={}
  tags = repo.list_tags()
  latest_tag = tags[0] if tags else None
  ```

  **Returns:** List of `TagInfo` objects
</ResponseField>

<ResponseField name="get_github_slug" type="Optional[Tuple[str, str]]">
  Extract GitHub owner/repo from remote URL.

  ```python theme={}
  slug = repo.get_github_slug()
  if slug:
      owner, repo_name = slug
      print(f"{owner}/{repo_name}")
  ```

  **Returns:** Tuple of `(owner, repo)` or `None`
</ResponseField>

### Example

```python theme={}
from pathlib import Path
from helixcommit.git_client import GitRepository, CommitRange

# Initialize repository
repo = GitRepository(Path("."))

# Get commits
commits = list(repo.iter_commits(
    CommitRange(since="v1.0.0", until="v2.0.0")
))

# List tags
tags = repo.list_tags()
for tag in tags:
    print(f"{tag.name}: {tag.tagged_date}")
```

***

## CommitRange

Define a range of commits to process.

### Constructor

```python theme={}
CommitRange(
    since: Optional[str] = None,
    until: Optional[str] = None,
    include_merges: bool = True,
    max_count: Optional[int] = None
)
```

<ParamField path="since" type="str">
  Starting ref (tag, commit SHA, or branch). Commits after this ref are included.
</ParamField>

<ParamField path="until" type="str" default="HEAD">
  Ending ref. Commits up to and including this ref are included.
</ParamField>

<ParamField path="include_merges" type="bool" default="true">
  Whether to include merge commits in the output.
</ParamField>

<ParamField path="max_count" type="int">
  Maximum number of commits to process.
</ParamField>

### Example

```python theme={}
from helixcommit.git_client import CommitRange

# Between tags
range1 = CommitRange(since="v1.0.0", until="v2.0.0")

# Unreleased changes
range2 = CommitRange(since="v1.0.0", until="HEAD")

# With filtering
range3 = CommitRange(
    since="v1.0.0",
    until="HEAD",
    include_merges=False,
    max_count=100
)
```

***

## ChangelogBuilder

Build structured changelogs from commits.

### Constructor

```python theme={}
ChangelogBuilder(
    summarizer: Optional[BaseSummarizer] = None,
    section_order: Optional[Sequence[str]] = None,
    include_scopes: bool = True,
    dedupe_prs: bool = True,
    summary_body_limit: int = 1600,
)
```

<ParamField path="summarizer" type="BaseSummarizer">
  AI summarizer for generating enhanced descriptions. Pass `None` to disable AI.
</ParamField>

<ParamField path="section_order" type="List[str]">
  Custom order for changelog sections. Uses default order if not specified.
</ParamField>

<ParamField path="include_scopes" type="bool" default="true">
  Whether to include commit scopes in descriptions.
</ParamField>

<ParamField path="dedupe_prs" type="bool" default="true">
  Whether to deduplicate pull requests.
</ParamField>

### Methods

<ResponseField name="build" type="Changelog">
  Build a changelog from commits.

  ```python theme={}
  changelog = builder.build(
      version="v2.0.0",
      release_date=datetime.now(),
      commits=commits,
      commit_prs={},
      pr_index={},
  )
  ```

  **Parameters:**

  * `version: Optional[str]` - Version number
  * `release_date: datetime` - Release date
  * `commits: Sequence[CommitInfo]` - List of commits
  * `commit_prs: Dict[str, List[PullRequestInfo]]` - Commit to PRs mapping
  * `pr_index: Dict[int, PullRequestInfo]` - PR number to PR info mapping

  **Returns:** `Changelog` object
</ResponseField>

### Example

```python theme={}
from datetime import datetime
from helixcommit.changelog import ChangelogBuilder

# Basic usage
builder = ChangelogBuilder(include_scopes=True)
changelog = builder.build(
    version="v2.0.0",
    release_date=datetime.now(),
    commits=commits,
    commit_prs={},
    pr_index={},
)

# With AI summarization
from helixcommit.summarizer import PromptEngineeredSummarizer

summarizer = PromptEngineeredSummarizer(
    api_key="sk-...",
    model="gpt-4o-mini",
)
builder = ChangelogBuilder(summarizer=summarizer)
changelog = builder.build(
    version="v2.0.0",
    release_date=datetime.now(),
    commits=commits,
    commit_prs={},
    pr_index={},
)
```

***

## Formatters

Render changelogs in different formats.

### Markdown

```python theme={}
from helixcommit.formatters.markdown import render_markdown

markdown_output = render_markdown(changelog)
Path("RELEASE_NOTES.md").write_text(markdown_output)
```

### HTML

```python theme={}
from helixcommit.formatters.html import render_html

html_output = render_html(changelog)
Path("changelog.html").write_text(html_output)
```

### Text

```python theme={}
from helixcommit.formatters.text import render_text

text_output = render_text(changelog)
print(text_output)
```

***

## GitHubClient

Interface with GitHub's API.

### Constructor

```python theme={}
GitHubClient(settings: GitHubSettings)
```

<ParamField path="settings" type="GitHubSettings" required>
  GitHub configuration including owner, repo, and token.
</ParamField>

### Methods

<ResponseField name="get_pull_request" type="Optional[PullRequestInfo]">
  Fetch pull request by number.

  ```python theme={}
  pr = client.get_pull_request(123)
  if pr:
      print(f"PR #{pr.number}: {pr.title}")
  ```

  **Parameters:**

  * `number: int` - Pull request number

  **Returns:** `PullRequestInfo` or `None`
</ResponseField>

<ResponseField name="find_pull_requests_by_commit" type="List[PullRequestInfo]">
  Find pull requests associated with a commit.

  ```python theme={}
  prs = client.find_pull_requests_by_commit("abc123def")
  for pr in prs:
      print(f"PR #{pr.number}")
  ```

  **Parameters:**

  * `sha: str` - Commit SHA

  **Returns:** List of `PullRequestInfo`
</ResponseField>

<ResponseField name="close" type="None">
  Close the GitHub client and release resources.

  ```python theme={}
  client.close()
  ```
</ResponseField>

### Example

```python theme={}
from helixcommit.github_client import GitHubClient, GitHubSettings

# Initialize client
settings = GitHubSettings(
    owner="username",
    repo="repository",
    token="ghp_..."  # Optional
)
client = GitHubClient(settings)

try:
    # Fetch PR
    pr = client.get_pull_request(123)
    
    # Find PRs by commit
    prs = client.find_pull_requests_by_commit("abc123")
finally:
    client.close()
```

***

## PromptEngineeredSummarizer

AI-powered summarization of commits.

### Constructor

```python theme={}
PromptEngineeredSummarizer(
    api_key: str,
    model: str = "gpt-4o-mini",
    base_url: Optional[str] = None,
    cache_path: Optional[Path] = None,
    domain_scope: Optional[str] = None,
    expert_roles: Optional[List[str]] = None,
    rag_backend: str = "simple"
)
```

<ParamField path="api_key" type="str" required>
  OpenAI or OpenRouter API key.
</ParamField>

<ParamField path="model" type="str" default="gpt-4o-mini">
  AI model to use for summarization.
</ParamField>

<ParamField path="base_url" type="str">
  Custom API base URL (for OpenRouter: `https://openrouter.ai/api/v1`).
</ParamField>

<ParamField path="cache_path" type="Path">
  Path to cache file for storing summaries.
</ParamField>

<ParamField path="domain_scope" type="str">
  Domain context for the AI (e.g., "software release notes").
</ParamField>

<ParamField path="expert_roles" type="List[str]">
  Expert perspectives to consider (e.g., \["Product Manager", "Tech Lead"]).
</ParamField>

<ParamField path="rag_backend" type="str" default="simple">
  RAG backend: "simple" (keyword) or "chroma" (vector).
</ParamField>

### Example

```python theme={}
from pathlib import Path
from helixcommit.summarizer import PromptEngineeredSummarizer

# OpenAI
summarizer = PromptEngineeredSummarizer(
    api_key="sk-...",
    model="gpt-4o-mini",
    cache_path=Path(".cache/summaries.json"),
    domain_scope="software release notes",
    expert_roles=["Product Manager", "Tech Lead", "QA Engineer"]
)

# OpenRouter
summarizer = PromptEngineeredSummarizer(
    api_key="sk-or-...",
    model="meta-llama/llama-3.1-8b-instruct:free",
    base_url="https://openrouter.ai/api/v1",
    cache_path=Path(".cache/summaries.json")
)

# Use with ChangelogBuilder
builder = ChangelogBuilder(summarizer=summarizer)
```

***

## Data models

### CommitInfo

```python theme={}
@dataclass
class CommitInfo:
    sha: str
    subject: str
    body: str
    author_name: str
    author_email: str
    authored_date: datetime
    committed_date: datetime
    is_merge: bool = False
    pr_number: Optional[int] = None
    labels: List[str] = field(default_factory=list)
    diff: Optional[str] = None

    @property
    def message(self) -> str: ...
```

### Changelog

```python theme={}
@dataclass
class Changelog:
    version: Optional[str]
    date: Optional[datetime]
    sections: List[ChangelogSection]
    metadata: Dict[str, Any]
```

### ChangelogSection

```python theme={}
@dataclass
class ChangelogSection:
    title: str
    items: List[ChangeItem] = field(default_factory=list)

    def extend(self, changes: Iterable[ChangeItem]) -> None: ...
```

### PullRequestInfo

```python theme={}
@dataclass
class PullRequestInfo:
    number: int
    title: str
    url: str
    author: Optional[str]
    merged_at: Optional[datetime]
    body: Optional[str] = None
    labels: List[str] = field(default_factory=list)
    assignees: List[str] = field(default_factory=list)
```

***

## Complete example

```python theme={}
from datetime import datetime
from pathlib import Path
from typing import Optional

from helixcommit.changelog import ChangelogBuilder
from helixcommit.formatters.markdown import render_markdown
from helixcommit.formatters.html import render_html
from helixcommit.git_client import CommitRange, GitRepository
from helixcommit.github_client import GitHubClient, GitHubSettings
from helixcommit.summarizer import PromptEngineeredSummarizer

def generate_release_notes(
    repo_path: Path,
    since: str,
    until: str,
    github_token: Optional[str] = None,
    openai_key: Optional[str] = None
) -> str:
    """Generate comprehensive release notes."""
    
    # Initialize repository
    repo = GitRepository(repo_path)
    
    # Get commits
    commit_range = CommitRange(since=since, until=until, include_merges=False)
    commits = list(repo.iter_commits(commit_range))
    
    # GitHub enrichment
    pr_index = {}
    commit_prs = {}
    if github_token:
        slug = repo.get_github_slug()
        if slug:
            settings = GitHubSettings(
                owner=slug[0],
                repo=slug[1],
                token=github_token
            )
            client = GitHubClient(settings)
            try:
                for commit in commits:
                    if commit.pr_number:
                        pr = client.get_pull_request(commit.pr_number)
                        if pr:
                            pr_index[commit.pr_number] = pr
            finally:
                client.close()
    
    # AI summarization
    summarizer = None
    if openai_key:
        summarizer = PromptEngineeredSummarizer(
            api_key=openai_key,
            model="gpt-4o-mini",
            cache_path=repo_path / ".cache" / "summaries.json"
        )
    
    # Build changelog
    builder = ChangelogBuilder(
        summarizer=summarizer,
        include_scopes=True,
        dedupe_prs=True,
    )
    
    changelog = builder.build(
        version=until,
        release_date=datetime.now(),
        commits=commits,
        commit_prs=commit_prs,
        pr_index=pr_index,
    )
    
    # Render output
    markdown = render_markdown(changelog)
    html = render_html(changelog)
    
    # Save files
    (repo_path / "RELEASE_NOTES.md").write_text(markdown)
    (repo_path / "release.html").write_text(html)
    
    return markdown

# Usage
if __name__ == "__main__":
    notes = generate_release_notes(
        repo_path=Path("."),
        since="v1.0.0",
        until="v2.0.0",
        github_token="ghp_...",
        openai_key="sk-..."
    )
    print(notes)
```

***

## Next steps

<CardGroup cols={2}>
  <Card title="Git client" icon="code-branch" href="/api-reference/git-client" color="#0A6ACB">
    Detailed Git client documentation
  </Card>

  <Card title="Changelog builder" icon="list" href="/api-reference/changelog" color="#F26419">
    Changelog building API
  </Card>

  <Card title="Formatters" icon="file-export" href="/api-reference/formatters" color="#F6A02D">
    Output formatting reference
  </Card>

  <Card title="Examples" icon="code" href="/examples" color="#0A6ACB">
    See Python API in action
  </Card>
</CardGroup>
