> ## 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.

# Configuration

> Customize HelixCommit for your workflow

## Overview

HelixCommit offers flexible configuration through configuration files, command-line flags, and environment variables. You can customize how commits are processed, what gets included in release notes, and how output is formatted.

## Configuration methods

<CardGroup cols={3}>
  <Card title="Configuration files" icon="file-code">
    Store project defaults in `.helixcommit.toml` or `.helixcommit.yaml`. Best for team-wide settings.
  </Card>

  <Card title="Command-line flags" icon="terminal">
    Pass options directly when running commands. Best for one-off customizations and testing.
  </Card>

  <Card title="Environment variables" icon="file-lines">
    Set variables in your shell or CI/CD environment. Ideal for credentials and secrets.
  </Card>
</CardGroup>

## Configuration precedence

When the same option is set in multiple places, HelixCommit uses this precedence (highest to lowest):

1. **Command-line flags** - Always take priority
2. **Configuration file** - Project defaults from `.helixcommit.toml` or `.helixcommit.yaml`
3. **Built-in defaults** - Fallback values

## Configuration files

HelixCommit looks for configuration files in your repository root in this order:

1. `.helixcommit.toml` (TOML format)
2. `.helixcommit.yaml` (YAML format)

The first file found is used. Configuration files are optional - HelixCommit works without them.

### Custom config file location

Use the `--config` flag to specify a custom config file location instead of the default discovery:

```bash theme={}
# Use a specific config file
helixcommit generate --config /path/to/my-config.toml

# Use project-specific configs
helixcommit generate --config configs/release.yaml

# Use environment-specific configs
helixcommit generate --config ~/.helixcommit/production.toml
```

<Info>
  The `--config` flag is available on both `generate` and `generate-commit` commands.
</Info>

<AccordionGroup>
  <Accordion title="Example: Multiple project configurations">
    Maintain different configurations for different release types:

    ```bash theme={}
    # configs/major-release.toml
    helixcommit generate --config configs/major-release.toml --unreleased

    # configs/patch-release.toml
    helixcommit generate --config configs/patch-release.toml --unreleased
    ```
  </Accordion>

  <Accordion title="Example: Shared team configuration">
    Store team-wide settings in a central location:

    ```bash theme={}
    # Use shared config from home directory
    helixcommit generate --config ~/.helixcommit/team-config.yaml

    # Or from a network location
    helixcommit generate --config /shared/configs/helixcommit.toml
    ```
  </Accordion>

  <Accordion title="Example: CI/CD with custom configs">
    Use different configs per CI environment:

    ```yaml theme={}
    # GitHub Actions example
    - name: Generate release notes (staging)
      run: helixcommit generate --config .ci/staging-config.toml --unreleased

    - name: Generate release notes (production)
      run: helixcommit generate --config .ci/production-config.toml --unreleased
    ```
  </Accordion>
</AccordionGroup>

<Tip>
  Template paths in custom config files are resolved relative to the config file's location, not the repository root.
</Tip>

<Tabs>
  <Tab title="TOML format">
    Create a `.helixcommit.toml` file in your repository root:

    ```toml theme={}
    # .helixcommit.toml - HelixCommit configuration

    [generate]
    format = "markdown"           # Output format: markdown, html, text, json
    include_scopes = true         # Show commit scopes in output
    no_merge_commits = false      # Exclude merge commits
    no_prs = false                # Skip PR/MR lookups
    fail_on_empty = false         # Exit with error if no commits found

    # Advanced filtering (v1.2+)
    include_types = []            # Only include these commit types (e.g., ["feat", "fix"])
    exclude_scopes = []           # Exclude commits with these scopes (e.g., ["deps", "ci"])
    author_filter = ""            # Regex to filter by author name or email

    [ai]
    enabled = false               # Enable AI-powered summaries (--use-llm)
    provider = "openrouter"       # AI provider: openai or openrouter
    openai_model = "gpt-4o-mini"
    openrouter_model = "x-ai/grok-4.1-fast:free"
    include_diffs = false         # Include diffs for better AI context
    domain_scope = "software release notes"
    expert_roles = ["Product Manager", "Tech Lead", "QA Engineer"]
    rag_backend = "simple"        # RAG backend: simple or chroma
    ```
  </Tab>

  <Tab title="YAML format">
    Create a `.helixcommit.yaml` file in your repository root:

    ```yaml theme={}
    # .helixcommit.yaml - HelixCommit configuration

    generate:
      format: markdown            # Output format: markdown, html, text, json
      include_scopes: true        # Show commit scopes in output
      no_merge_commits: false     # Exclude merge commits
      no_prs: false               # Skip PR/MR lookups
      fail_on_empty: false        # Exit with error if no commits found

      # Advanced filtering (v1.2+)
      include_types: []           # Only include these commit types
      exclude_scopes: []          # Exclude commits with these scopes
      author_filter: ""           # Regex to filter by author name or email

    ai:
      enabled: false              # Enable AI-powered summaries (--use-llm)
      provider: openrouter        # AI provider: openai or openrouter
      openai_model: gpt-4o-mini
      openrouter_model: x-ai/grok-4.1-fast:free
      include_diffs: false        # Include diffs for better AI context
      domain_scope: software release notes
      expert_roles:
        - Product Manager
        - Tech Lead
        - QA Engineer
      rag_backend: simple         # RAG backend: simple or chroma
    ```
  </Tab>
</Tabs>

<Warning>
  **Never store API keys or tokens in configuration files.** Use environment variables for sensitive credentials like `OPENAI_API_KEY`, `GITHUB_TOKEN`, etc.
</Warning>

### Environment variable expansion

Configuration files support environment variable expansion using the `${VAR}` syntax. This allows you to reference environment variables directly in your config files, making configurations more portable across different environments.

<Tabs>
  <Tab title="Basic syntax">
    Use `${VAR_NAME}` to reference an environment variable:

    ```toml theme={}
    # .helixcommit.toml
    [ai]
    enabled = true
    openai_model = "${AI_MODEL}"
    domain_scope = "${PROJECT_DOMAIN}"
    ```

    ```yaml theme={}
    # .helixcommit.yaml
    ai:
      enabled: true
      openai_model: "${AI_MODEL}"
      domain_scope: "${PROJECT_DOMAIN}"
    ```

    Set the variables before running:

    ```bash theme={}
    export AI_MODEL=gpt-4o
    export PROJECT_DOMAIN=e-commerce
    helixcommit generate --unreleased
    ```
  </Tab>

  <Tab title="Default values">
    Use `${VAR:-default}` to provide a fallback value when the variable is not set:

    ```toml theme={}
    # .helixcommit.toml
    [ai]
    enabled = true
    openai_model = "${AI_MODEL:-gpt-4o-mini}"
    domain_scope = "${PROJECT_DOMAIN:-software release notes}"
    ```

    ```yaml theme={}
    # .helixcommit.yaml
    ai:
      enabled: true
      openai_model: "${AI_MODEL:-gpt-4o-mini}"
      domain_scope: "${PROJECT_DOMAIN:-software release notes}"
    ```

    If `AI_MODEL` is not set, `gpt-4o-mini` will be used instead.
  </Tab>
</Tabs>

<AccordionGroup>
  <Accordion title="Example: Environment-specific configurations">
    Use environment variables to switch between development and production settings:

    ```toml theme={}
    # .helixcommit.toml
    [generate]
    format = "${OUTPUT_FORMAT:-markdown}"

    [ai]
    enabled = true
    provider = "${AI_PROVIDER:-openrouter}"
    openai_model = "${OPENAI_MODEL:-gpt-4o-mini}"
    openrouter_model = "${OPENROUTER_MODEL:-x-ai/grok-4.1-fast:free}"
    domain_scope = "${DOMAIN_SCOPE:-software release notes}"
    ```

    Then configure per environment:

    ```bash theme={}
    # Development
    export AI_PROVIDER=openrouter
    export OPENROUTER_MODEL=x-ai/grok-4.1-fast:free

    # Production
    export AI_PROVIDER=openai
    export OPENAI_MODEL=gpt-4o
    ```
  </Accordion>

  <Accordion title="Example: Dynamic template paths">
    Reference template directories via environment variables:

    ```toml theme={}
    # .helixcommit.toml
    [templates]
    markdown = "${TEMPLATE_DIR:-templates}/changelog.md.j2"
    html = "${TEMPLATE_DIR:-templates}/changelog.html.j2"
    ```
  </Accordion>

  <Accordion title="Example: Team-specific roles">
    Configure expert roles per team member or CI environment:

    ```toml theme={}
    # .helixcommit.toml
    [ai]
    enabled = true
    expert_roles = ["${PRIMARY_ROLE:-Product Manager}", "${SECONDARY_ROLE:-Tech Lead}"]
    ```
  </Accordion>
</AccordionGroup>

<Info>
  If an environment variable is not set and no default is provided, the reference (e.g., `${UNDEFINED_VAR}`) is kept as-is in the config value.
</Info>

<Warning>
  Environment variable expansion is for non-sensitive configuration values like model names, domains, and paths. **Never use this feature for API keys or tokens** - those should always be set as environment variables directly and accessed by the application.
</Warning>

### Configuration reference

<AccordionGroup>
  <Accordion title="[generate] section">
    | Option             | Type      | Default      | Description                                                   |
    | ------------------ | --------- | ------------ | ------------------------------------------------------------- |
    | `format`           | string    | `"markdown"` | Output format: `markdown`, `html`, `text`, or `json`          |
    | `include_scopes`   | boolean   | `true`       | Show commit scopes (e.g., `feat(api)`)                        |
    | `no_merge_commits` | boolean   | `false`      | Exclude merge commits from output                             |
    | `no_prs`           | boolean   | `false`      | Skip GitHub/GitLab/Bitbucket PR lookups                       |
    | `fail_on_empty`    | boolean   | `false`      | Exit with code 1 if no commits found                          |
    | `include_types`    | string\[] | `[]`         | Only include commits of these types (e.g., `["feat", "fix"]`) |
    | `exclude_scopes`   | string\[] | `[]`         | Exclude commits with these scopes (e.g., `["deps", "ci"]`)    |
    | `author_filter`    | string    | `null`       | Regex pattern to filter commits by author name or email       |
  </Accordion>

  <Accordion title="[ai] section">
    | Option             | Type      | Default                     | Description                                 |
    | ------------------ | --------- | --------------------------- | ------------------------------------------- |
    | `enabled`          | boolean   | `false`                     | Enable AI-powered summaries                 |
    | `provider`         | string    | `"openrouter"`              | AI provider: `openai` or `openrouter`       |
    | `openai_model`     | string    | `"gpt-4o-mini"`             | OpenAI model to use                         |
    | `openrouter_model` | string    | `"x-ai/grok-4.1-fast:free"` | OpenRouter model to use                     |
    | `include_diffs`    | boolean   | `false`                     | Include commit diffs for AI context         |
    | `domain_scope`     | string    | `null`                      | Domain context for AI prompts               |
    | `expert_roles`     | string\[] | `[]`                        | Expert roles for multi-perspective analysis |
    | `rag_backend`      | string    | `"simple"`                  | RAG backend: `simple` or `chroma`           |
  </Accordion>
</AccordionGroup>

### Example configurations

<AccordionGroup>
  <Accordion title="Minimal AI-enabled setup">
    ```toml theme={}
    # .helixcommit.toml
    [ai]
    enabled = true
    provider = "openrouter"
    ```

    Then set your API key:

    ```bash theme={}
    export OPENROUTER_API_KEY=sk-or-...
    helixcommit generate --unreleased
    ```
  </Accordion>

  <Accordion title="CI/CD optimized">
    ```toml theme={}
    # .helixcommit.toml
    [generate]
    format = "markdown"
    no_merge_commits = true
    fail_on_empty = true
    ```
  </Accordion>

  <Accordion title="Full-featured with AI">
    ```toml theme={}
    # .helixcommit.toml
    [generate]
    format = "markdown"
    include_scopes = true
    no_merge_commits = true

    [ai]
    enabled = true
    provider = "openai"
    openai_model = "gpt-4o-mini"
    include_diffs = true
    domain_scope = "software release notes"
    expert_roles = ["Product Manager", "Tech Lead", "Security Engineer"]
    ```
  </Accordion>

  <Accordion title="With advanced filtering">
    ```toml theme={}
    # .helixcommit.toml
    [generate]
    format = "markdown"
    no_merge_commits = true

    # Only include features, fixes, and performance improvements
    include_types = ["feat", "fix", "perf"]

    # Exclude dependency updates and CI changes
    exclude_scopes = ["deps", "ci"]

    # Only include commits from team members
    author_filter = ".*@mycompany\\.com"
    ```

    ```yaml theme={}
    # .helixcommit.yaml equivalent
    generate:
      format: markdown
      no_merge_commits: true
      include_types:
        - feat
        - fix
        - perf
      exclude_scopes:
        - deps
        - ci
      author_filter: ".*@mycompany\\.com"
    ```
  </Accordion>
</AccordionGroup>

## Core configuration areas

### Commit range selection

Control which commits are included in your release notes.

<Tabs>
  <Tab title="Tag-based ranges">
    Use semantic version tags to define ranges:

    ```bash theme={}
    # Between two specific tags
    helixcommit generate \
      --since-tag v1.2.0 \
      --until-tag v1.2.1

    # From tag to HEAD (unreleased)
    helixcommit generate \
      --since-tag v1.2.1 \
      --until HEAD
    ```

    <Tip>
      The `--unreleased` flag automatically uses the latest tag as the starting point.
    </Tip>
  </Tab>

  <Tab title="Commit-based ranges">
    Use commit SHAs or branch names:

    ```bash theme={}
    # Specific commit range
    gitreleasegen generate \
      --since abc123def \
      --until 456ghi789

    # From branch to another
    gitreleasegen generate \
      --since main \
      --until feature-branch
    ```
  </Tab>

  <Tab title="Date-based ranges">
    Use date expressions:

    ```bash theme={}
    # Changes in the last week
    gitreleasegen generate \
      --since "7 days ago"

    # Changes since specific date
    gitreleasegen generate \
      --since "2024-01-01" \
      --until "2024-06-30"
    ```

    <Info>
      Date expressions use Git's date parsing, which supports relative dates like "1 week ago" and absolute dates like "2024-01-01".
    </Info>
  </Tab>
</Tabs>

### Output formatting

Customize how release notes are formatted and where they're saved.

<ParamField path="format" type="string" default="markdown">
  Choose the output format that fits your publishing workflow.

  **Markdown** - Perfect for GitHub releases and documentation sites

  ```bash theme={}
  helixcommit generate --format markdown --out RELEASE_NOTES.md
  ```

  **HTML** - Ready for embedding in websites

  ```bash theme={}
  helixcommit generate --format html --out changelog.html
  ```

  **Text** - Plain text for email notifications or chat

  ```bash theme={}
  helixcommit generate --format text --out changes.txt
  ```

  **JSON** - Machine-readable for programmatic use

  ```bash theme={}
  helixcommit generate --format json --out changelog.json
  ```
</ParamField>

<ParamField path="output destination" type="string">
  Control where output is written.

  **Standard output** (default)

  ```bash theme={}
  gitreleasegen generate --format markdown
  ```

  **File output**

  ```bash theme={}
  gitreleasegen generate --out /path/to/output.md
  ```

  <Check>
    Parent directories are created automatically if they don't exist.
  </Check>
</ParamField>

### Filtering commits

Fine-tune which commits appear in your release notes.

<AccordionGroup>
  <Accordion title="Include or exclude merge commits">
    ```bash theme={}
    # Exclude merge commits (cleaner output)
    gitreleasegen generate --no-merge-commits

    # Include merge commits (default)
    gitreleasegen generate
    ```

    Merge commits often duplicate information. Excluding them typically produces cleaner release notes.
  </Accordion>

  <Accordion title="Limit commit count">
    ```bash theme={}
    # Process only the last 50 commits
    gitreleasegen generate --max-items 50
    ```

    Useful for testing or when you only need recent changes.
  </Accordion>

  <Accordion title="Show or hide commit scopes">
    ```bash theme={}
    # With scopes (default)
    gitreleasegen generate --include-scopes
    # Output: "**api**: Add authentication endpoint"

    # Without scopes
    gitreleasegen generate --no-include-scopes
    # Output: "Add authentication endpoint"
    ```

    <Info>
      Scopes are extracted from Conventional Commits format: `feat(api): message`
    </Info>
  </Accordion>
</AccordionGroup>

## GitHub integration

Configure how GitReleaseGen interacts with GitHub's API.

### Authentication

<Steps>
  <Step title="Create a GitHub token">
    Visit [github.com/settings/tokens](https://github.com/settings/tokens) and create a personal access token.

    **For public repositories:** No special permissions needed

    **For private repositories:** Select the `repo` scope
  </Step>

  <Step title="Set the token">
    <CodeGroup>
      ```bash Environment variable (recommended) theme={}
      export GITHUB_TOKEN=ghp_your_token_here

      # Use in commands
      gitreleasegen generate --unreleased
      ```

      ```bash Command-line flag theme={}
      gitreleasegen generate \
        --unreleased \
        --github-token ghp_your_token_here
      ```

      ```bash CI/CD (GitHub Actions) theme={}
      - name: Generate release notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gitreleasegen generate --unreleased --out RELEASE_NOTES.md
      ```
    </CodeGroup>

    <Warning>
      Never commit tokens to version control. Use environment variables or CI/CD secrets.
    </Warning>
  </Step>
</Steps>

### Rate limiting and retries

GitReleaseGen handles GitHub API rate limits automatically with exponential backoff.

<ResponseField name="GITRELEASEGEN_GH_MAX_RETRIES" type="integer" default="3">
  Maximum number of retry attempts for failed requests.

  ```bash theme={}
  export GITRELEASEGEN_GH_MAX_RETRIES=5
  ```
</ResponseField>

<ResponseField name="GITRELEASEGEN_GH_BACKOFF_BASE_SEC" type="float" default="0.5">
  Initial delay between retries in seconds.

  ```bash theme={}
  export GITRELEASEGEN_GH_BACKOFF_BASE_SEC=1.0
  ```
</ResponseField>

<ResponseField name="GITRELEASEGEN_GH_BACKOFF_CAP_SEC" type="float" default="8">
  Maximum delay between retries in seconds.

  ```bash theme={}
  export GITRELEASEGEN_GH_BACKOFF_CAP_SEC=16
  ```
</ResponseField>

### Caching

Reduce API calls and improve performance with caching.

<ResponseField name="GITRELEASEGEN_GH_CACHE" type="boolean" default="false">
  Enable persistent caching of GitHub API responses.

  ```bash theme={}
  export GITRELEASEGEN_GH_CACHE=1
  gitreleasegen generate --unreleased
  ```

  Valid values: `1`, `true`, `yes`, `on`
</ResponseField>

<ResponseField name="GITRELEASEGEN_GH_CACHE_DIR" type="path" default=".gitreleasegen-cache/github">
  Directory where cache files are stored.

  ```bash theme={}
  export GITRELEASEGEN_GH_CACHE_DIR=.cache/gh-api
  ```
</ResponseField>

<ResponseField name="GITRELEASEGEN_GH_CACHE_TTL_MINUTES" type="integer" default="10">
  How long cache entries remain valid in minutes.

  ```bash theme={}
  export GITRELEASEGEN_GH_CACHE_TTL_MINUTES=30
  ```
</ResponseField>

<Tip>
  Enable caching in CI/CD environments to speed up repeated runs and reduce API usage.
</Tip>

### Skip GitHub integration

Work offline or skip PR lookups:

```bash theme={}
helixcommit generate --unreleased --no-prs
```

<Info>
  Using `--no-prs` means no GitHub API calls are made. Perfect for offline work or when PR metadata isn't needed.
</Info>

## GitLab integration

HelixCommit automatically detects GitLab repositories (including self-hosted instances) and enriches release notes with merge request data.

### Authentication

```bash theme={}
export GITLAB_TOKEN=glpat-your_token_here

helixcommit generate --unreleased
```

**Required permissions:** `read_api` and `read_repository` for private projects.

<Info>
  For more details, see the [GitLab integration guide](/gitlab-integration).
</Info>

## Bitbucket integration

HelixCommit automatically detects Bitbucket Cloud repositories and enriches release notes with pull request data.

### Authentication

```bash theme={}
export BITBUCKET_TOKEN=your_app_password_here

helixcommit generate --unreleased
```

**Required permissions:** Repositories: Read, Pull requests: Read

<Info>
  For more details, see the [Bitbucket integration guide](/bitbucket-integration).
</Info>

## AI configuration

Configure AI-powered summarization features.

### Provider selection

<Tabs>
  <Tab title="OpenAI">
    ```bash theme={}
    export OPENAI_API_KEY=sk-...

    gitreleasegen generate \
      --unreleased \
      --use-llm \
      --openai-model gpt-4o-mini
    ```

    **Recommended models:**

    * `gpt-4o-mini` - Fast and cost-effective (recommended)
    * `gpt-4o` - Most capable
    * `gpt-3.5-turbo` - Budget option

    Get your API key at [platform.openai.com/api-keys](https://platform.openai.com/api-keys)
  </Tab>

  <Tab title="OpenRouter">
    ```bash theme={}
    export OPENROUTER_API_KEY=sk-or-...

    gitreleasegen generate \
      --unreleased \
      --use-llm \
      --llm-provider openrouter \
      --openrouter-model meta-llama/llama-3.1-8b-instruct:free
    ```

    **Popular models:**

    * `meta-llama/llama-3.1-8b-instruct:free` - Free tier
    * `anthropic/claude-3-haiku` - Fast and capable
    * `google/gemini-pro` - Good balance

    Get your API key at [openrouter.ai](https://openrouter.ai)

    <Info>
      OpenRouter provides access to many AI models with a single API key, including free options.
    </Info>
  </Tab>
</Tabs>

### Summary caching

AI summaries are cached to minimize token usage and costs.

```bash theme={}
# Use custom cache location
gitreleasegen generate \
  --use-llm \
  --summary-cache .cache/ai-summaries.json

# Default cache location
# .gitreleasegen-cache/summaries.json
```

<Tip>
  Delete the cache file to regenerate all summaries with updated prompts or settings.
</Tip>

### Prompt engineering

Customize AI behavior with advanced options:

<ParamField path="domain-scope" type="string">
  Set the domain context for better AI summaries.

  ```bash theme={}
  gitreleasegen generate \
    --use-llm \
    --domain-scope "software release notes"
  ```

  Examples: `"conservation"`, `"healthcare"`, `"finance"`, `"e-commerce"`
</ParamField>

<ParamField path="expert-role" type="string[]">
  Define expert roles for multi-perspective analysis.

  ```bash theme={}
  gitreleasegen generate \
    --use-llm \
    --expert-role "Product Manager" \
    --expert-role "Tech Lead" \
    --expert-role "Security Engineer"
  ```

  <Info>
    Default roles: Product Manager, Tech Lead, QA Engineer
  </Info>
</ParamField>

<ParamField path="rag-backend" type="string" default="simple">
  Choose the retrieval backend for context.

  ```bash theme={}
  # Simple keyword matching (default)
  gitreleasegen generate --use-llm --rag-backend simple

  # Vector-based retrieval (requires chromadb)
  pip install chromadb
  gitreleasegen generate --use-llm --rag-backend chroma
  ```
</ParamField>

## Example configurations

<AccordionGroup>
  <Accordion title="Minimal offline setup">
    Generate release notes with no external dependencies:

    ```bash theme={}
    gitreleasegen generate \
      --unreleased \
      --no-prs \
      --no-merge-commits \
      --format markdown \
      --out RELEASE_NOTES.md
    ```

    Perfect for local development or air-gapped environments.
  </Accordion>

  <Accordion title="Full-featured with AI">
    Maximum enrichment with AI summaries and GitHub integration:

    ```bash theme={}
    export GITHUB_TOKEN=ghp_...
    export OPENAI_API_KEY=sk-...
    export GITRELEASEGEN_GH_CACHE=1

    gitreleasegen generate \
      --unreleased \
      --use-llm \
      --openai-model gpt-4o-mini \
      --domain-scope "software release notes" \
      --format markdown \
      --out RELEASE_NOTES.md
    ```
  </Accordion>

  <Accordion title="CI/CD optimized">
    Fast generation for automated pipelines:

    ```bash theme={}
    #!/bin/bash
    export GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
    export GITRELEASEGEN_GH_CACHE=1
    export GITRELEASEGEN_GH_CACHE_TTL_MINUTES=60

    gitreleasegen generate \
      --since-tag $PREVIOUS_TAG \
      --until-tag $CURRENT_TAG \
      --no-merge-commits \
      --format markdown \
      --out RELEASE_NOTES.md \
      --fail-on-empty
    ```
  </Accordion>

  <Accordion title="Team workflow">
    Balanced configuration for team use:

    ```bash theme={}
    # .env file
    export GITHUB_TOKEN=ghp_...
    export GITRELEASEGEN_GH_CACHE=1
    export GITRELEASEGEN_GH_MAX_RETRIES=5

    # Generate command
    gitreleasegen generate \
      --unreleased \
      --include-scopes \
      --format markdown
    ```
  </Accordion>
</AccordionGroup>

## Custom templates

GitReleaseGen uses formatters to render output. You can customize the look and feel by modifying templates.

### Template locations

Templates are located in the GitReleaseGen package:

```
gitreleasegen/formatters/
├── markdown.py    # Markdown formatter
├── html.py        # HTML formatter
└── text.py        # Text formatter
```

### Creating custom formatters

<Steps>
  <Step title="Copy an existing formatter">
    ```bash theme={}
    cp src/gitreleasegen/formatters/markdown.py my_formatter.py
    ```
  </Step>

  <Step title="Modify the template">
    Edit the rendering logic to match your needs. Formatters use Jinja2 templates for rendering.
  </Step>

  <Step title="Use programmatically">
    ```python theme={}
    from gitreleasegen.changelog import ChangelogBuilder
    import my_formatter

    builder = ChangelogBuilder()
    changelog = builder.build(...)
    output = my_formatter.render(changelog)
    ```
  </Step>
</Steps>

<Info>
  For more details on programmatic usage, see the [Python API reference](/api-reference/python-api).
</Info>

## Environment file

Create a `.env` file to store configuration:

```bash .env theme={}
# GitHub configuration
GITHUB_TOKEN=ghp_your_token_here
GITRELEASEGEN_GH_CACHE=1
GITRELEASEGEN_GH_CACHE_TTL_MINUTES=30

# AI configuration
OPENAI_API_KEY=sk-...
# or
OPENROUTER_API_KEY=sk-or-...

# Rate limiting
GITRELEASEGEN_GH_MAX_RETRIES=5
GITRELEASEGEN_GH_BACKOFF_CAP_SEC=16
```

Load it before running commands:

```bash theme={}
source .env
gitreleasegen generate --unreleased
```

<Warning>
  Add `.env` to your `.gitignore` to avoid committing secrets.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="CLI reference" icon="terminal" href="/cli-reference" color="#0A6ACB">
    Complete list of all CLI options
  </Card>

  <Card title="AI features" icon="sparkles" href="/ai-features" color="#F26419">
    Learn about AI-powered summarization
  </Card>

  <Card title="Examples" icon="lightbulb" href="/examples" color="#F6A02D">
    See configuration in action
  </Card>

  <Card title="GitHub integration" icon="github" href="/github-integration" color="#0A6ACB">
    Deep dive into GitHub API features
  </Card>
</CardGroup>
