Skip to content

Development

This page describes the development workflow for Buddy, including source preservation, documentation comments, logging integration, validation, and MkDocs build practices.

Buddy combines a Streamlit application, provider wrapper modules, local storage utilities, and source-driven documentation. Changes should be made conservatively because UI state, provider request construction, and document workflows depend on shared session-state keys and provider-specific wrapper contracts.

๐Ÿงญ Purpose

The development process has four objectives:

  1. Preserve existing application behavior.
  2. Keep provider wrappers isolated and predictable.
  3. Maintain MkDocs-compatible Google-style docstrings.
  4. Validate source files before building or publishing documentation.

Buddy documentation is built from source files, so source comments are part of the product. A documentation change should not introduce runtime changes unless the behavior change is intentional and tested.

๐Ÿงฑ Source Layout

The core project files are organized around the Streamlit application and provider wrappers.

File Role
app.py Main Streamlit application, mode routing, session-state initialization, local database utilities, data-management workflows, prompt handling, document workflows, and export logic.
gpt.py OpenAI wrapper for chat, images, text-to-speech, transcription, translation, embeddings, files, and vector stores.
gemini.py Gemini wrapper for chat, image workflows, embeddings, speech, transcription, translation, files, file search, and cloud buckets.
grok.py xAI Grok wrapper for chat, text-to-speech, transcription, translation, images, files, and collection-style retrieval workflows.
config.py Application configuration, API keys, constants, paths, logos, provider defaults, and UI settings.
requirements.txt Runtime and documentation dependencies.
mkdocs.yml MkDocs configuration for the generated documentation site.
docs/ Markdown documentation pages, assets, API pages, and generated diagrams.

๐Ÿงฌ Development Principles

Buddy development should follow a preservation-first model.

Principle Rule
Preserve behavior Do not change control flow, provider calls, session-state keys, or return behavior during documentation-only work.
Preserve signatures Do not change function, method, or constructor signatures unless a feature requires it.
Preserve layout Do not move Streamlit widgets, columns, tabs, expanders, or state writes unless a UI change is requested.
Keep providers isolated Provider-specific API logic belongs in gpt.py, gemini.py, or grok.py, not in unrelated UI code.
Validate early Compile and inspect files before running MkDocs.
Treat warnings as defects Griffe and MkDocs warnings usually indicate malformed docstrings, missing nav entries, or broken links.

๐Ÿ“ Google-Style Docstring Standard

Buddy uses Google-style docstrings because the API reference is generated by mkdocstrings and parsed by griffe.

Use this section order when applicable:

Purpose:
Args:
Attributes:
Returns:
Raises:
Notes:
Examples:

Do not use underline-style headings such as:

Parameters:
-----------
Returns:
--------
Purpose:
--------

Do not document self or cls.

Do not add a Returns: section to __init__.

Do not add Returns: None to constructors or procedures that only mutate state.

Function Example

def build_input(self, prompt: str, context: list[dict[str, str]] | None = None) -> list[dict[str, object]]:
    """Build a provider input payload.

    Purpose:
        Creates the provider request input structure from the current prompt and optional
        prior conversation context while preserving the message roles expected by the API.

    Args:
        prompt: User prompt submitted to the provider.
        context: Optional prior user, assistant, system, or developer messages.

    Returns:
        list[dict[str, object]]: Provider-ready message payload.

    Raises:
        Error: Raised when validation or payload construction fails.
    """

Property Example

@property
def model_options(self) -> list[str]:
    """Return supported model names.

    Purpose:
        Provides model names used by the Streamlit selector for the current provider mode.

    Returns:
        list[str]: Supported model option names.
    """

๐Ÿšจ Logging and Exception Handling

Buddy wraps provider and workflow exceptions with the project Error object. Where existing exception handlers catch and re-raise wrapped errors, they should also write to the project logger.

Recommended pattern:

except Exception as e:
    exception = Error(e)
    exception.module = 'gpt'
    exception.cause = 'Chat'
    exception.method = 'generate_text( self, prompt: str ) -> str | None'
    Logger().write(exception)
    raise exception

The exception.method value should be a stable signature string. It must not include:

  • API keys.
  • User prompts.
  • File contents.
  • DataFrame contents.
  • Full local file paths.
  • Tokens.
  • Provider responses.
  • Object memory addresses.
  • Other sensitive or volatile runtime values.

๐Ÿ” Configuration Practices

Provider credentials and runtime defaults should come from configuration or environment variables. Do not hard-code secrets in source files.

Common environment variables include:

Variable Purpose
OPENAI_API_KEY OpenAI provider access.
GOOGLE_API_KEY Google Gemini access.
GEMINI_API_KEY Gemini-specific provider access where separately configured.
XAI_API_KEY xAI Grok access.
GOOGLE_CSE_ID Search-related workflows where enabled.
GOOGLEMAPS_API_KEY Maps-related workflows where enabled.
GEOCODING_API_KEY Geocoding workflows where enabled.

๐Ÿงช Local Development Setup

Create a clean virtual environment and install dependencies.

python -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

Run the Streamlit application:

streamlit run app.py

Run from the repository root so imports, configuration paths, and SQLite paths resolve consistently.

โœ… Source Validation

Before building documentation, validate the Python files.

python -m py_compile .\app.py
python -m py_compile .\gpt.py
python -m py_compile .\gemini.py
python -m py_compile .\grok.py

Then run a project-wide compile check:

python -m compileall .

If a compile check fails, fix source syntax first. Do not troubleshoot MkDocs until the source files compile.

๐Ÿ“š MkDocs Build Workflow

Build the documentation locally:

mkdocs build

Serve the documentation locally:

mkdocs serve

Then open the local site in a browser and verify:

  • The home page renders.
  • The user guide pages are listed in navigation.
  • API reference pages render with source-driven content.
  • Search works.
  • Dark-mode styling loads.
  • Tables are readable.
  • No broken local links appear.
  • No missing image or asset warnings appear.

๐Ÿงพ MkDocs Configuration Checklist

The mkdocs.yml file should include only pages and assets that exist.

Required sections:

theme:
  name: material

plugins:
  - search
  - mkdocstrings:
      handlers:
        python:
          paths:
            - .
          options:
            docstring_style: google

If CSS or JavaScript assets are added, confirm the files exist before referencing them:

extra_css:
  - assets/css/buddy.css

extra_javascript:
  - assets/js/buddy.js

๐Ÿงฉ API Reference Pattern

API pages should be simple and source-driven.

Example docs/api/gpt.md:

# GPT API

::: gpt

Example docs/api/gemini.md:

# Gemini API

::: gemini

Example docs/api/grok.md:

# Grok API

::: grok

Example docs/api/app.md:

# Application API

::: app

Manual prose should stay in user-guide and architecture pages. API pages should rely on the Python docstrings.

๐Ÿงญ Session-State Discipline

app.py uses session-state keys to coordinate modes. When changing UI or mode logic:

  1. Ensure keys are written before they are read.
  2. Do not reuse unrelated keys across modes.
  3. Do not clear upstream state unless the reset action is explicit.
  4. Keep reset functions scoped to their mode.
  5. Preserve compatibility aliases where existing workflows expect them.

Mode-state functions should remain defensive because widgets may render in different orders after reruns.

๐Ÿ—„๏ธ Data and Storage Practices

Buddy uses SQLite-backed workflows for prompts, history, embeddings, and data-management utilities.

Development rules:

  • Validate table and column names before dynamic SQL.
  • Quote SQLite identifiers where needed.
  • Avoid destructive operations unless explicitly requested.
  • Keep user-uploaded data separate from prompt and history storage.
  • Preserve export paths and generated artifact behavior.
  • Keep retrieval data traceable to the active document or vector-store source.

๐Ÿ”Ž Retrieval and Grounding Practices

Retrieval workflows should keep answer generation close to source material.

Recommended pattern:

  1. Load or upload source material.
  2. Extract text.
  3. Normalize and chunk text.
  4. Generate embeddings or provider file references.
  5. Retrieve relevant chunks or sources.
  6. Submit grounded prompt context.
  7. Display answer and source information.
  8. Export results when needed.

Source attribution should remain visible when the provider or local workflow exposes it.

๐Ÿ› ๏ธ Provider Wrapper Practices

Provider wrappers should expose similar high-level workflows even when provider APIs differ.

Wrapper Development Rule
gpt.py Keep OpenAI Responses, Files, Images, Audio, Embeddings, and Vector Stores logic inside OpenAI wrapper classes.
gemini.py Keep Gemini SDK, file search, cloud bucket, safety, grounding, and multimodal request logic inside Gemini wrapper classes.
grok.py Keep xAI model, image, audio, file, and collection-style retrieval logic inside Grok wrapper classes.

The UI should ask wrappers for available options through properties such as model_options, tool_options, format_options, and related option lists.

๐Ÿšฆ Pull Request Review Checklist

Use this checklist before merging changes.

Check Required
Python files compile Yes
MkDocs builds Yes
No avoidable griffe warnings Yes
No broken docs links Yes
No missing assets referenced by mkdocs.yml Yes
Public docstrings use Google style Yes
Constructors do not include Returns: Yes
Logging handlers avoid sensitive runtime values Yes
Session-state keys are preserved Yes
Provider behavior is preserved Yes
UI layout changes are intentional Yes

๐Ÿงฏ Common Issues

Issue Likely Cause Fix
No type or annotation for returned value 'None' Constructor or procedure has malformed Returns: section. Remove Returns: from __init__ and avoid Returns: None.
API page is empty Module path is wrong or source file fails import. Confirm paths: - . and run py_compile.
Page exists but is not in nav Markdown file was created but not listed in mkdocs.yml. Add the file to nav or remove it.
CSS/JS warning Asset referenced but missing. Create the asset or remove the reference.
Broken image link Image path is incorrect or image was not copied into docs/images/. Fix the relative path or copy the image.
Streamlit key error Session-state key is read before initialization. Add or repair the relevant ensure_*_mode_state function.

โœ… Release Build Sequence

Use this sequence for a clean documentation release:

python -m compileall .
mkdocs build
mkdocs serve

After visual review, commit source and documentation changes together.

Recommended commit groups:

  1. Source docstring and logging updates.
  2. Documentation Markdown pages.
  3. CSS and JavaScript assets.
  4. Diagrams and images.
  5. MkDocs configuration.

โš ๏ธ Review Standard

Buddy supports analysis and documentation workflows, but AI-generated outputs still require professional review. Treat generated responses, extracted summaries, and exported reports as draft analytical products until validated against authoritative source material.