<!-- AUTO-GENERATED FROM agents/sources/packages/sdk.md; DO NOT EDIT DIRECTLY. -->
<!-- This file is maintained as both CLAUDE.md (Claude Code) and AGENTS.md (Codex).
     Keep them identical. If you edit one, copy the changes to the other. -->

# DalySDK — Python Client for the Daly Energy REST API

## What This Is
Synchronous Python SDK for the Daly Energy REST API, published to PyPI as `daly-energy`.
Provides a typed, resource-namespaced interface for all API endpoints.

## Tech Stack

| Layer | Technology |
|-------|-----------|
| Language | Python 3.11+ |
| HTTP client | httpx (synchronous) |
| Type hints | Pydantic v2 (type hints only, not runtime) |
| Build | hatchling |
| Linting | ruff |

## Directory Structure

```
packages/sdk/
├── dalysdk/              # Importable package
│   ├── __init__.py       # Public API: DalyClient + exceptions
│   ├── auth.py           # API key authentication
│   ├── client.py         # DalyClient — main entry point
│   ├── exceptions.py     # DalyAPIError hierarchy
│   ├── py.typed          # PEP 561 marker
│   └── resources/        # Resource namespaces
│       ├── __init__.py
│       ├── energy_models.py
│       ├── inverters.py
│       ├── locations.py
│       ├── modules.py
│       ├── projects.py
│       ├── shading_scenes.py
│       ├── tasks.py
│       ├── weather_data.py
│       ├── workflows.py
│       └── workspaces.py
└── pyproject.toml        # Test directory not present yet (known gap)
```

## How to Use

```python
from dalysdk import DalyClient

with DalyClient(workspace_api_key="wk_...", user_api_key="uk_...") as client:
    locations = client.locations.list()
    project = client.projects.create({"name": "My Project", "location_index": 1})
```

## How to Develop

```bash
# Install
pip install -e ".[dev,test]"

# Lint
ruff check . && ruff format --check .

# Type check
mypy dalysdk/
```

## Key Patterns

- **Resource namespaces**: Each API resource is a namespace on the client
  (`client.locations`, `client.projects`, etc.)
- **Returns raw dicts**: SDK returns parsed JSON dicts, not Pydantic models.
  Consumers handle their own deserialization.
- **No dalyapi dependency**: This package is fully independent. All internal imports
  use `from dalysdk.X import Y` (absolute).
- **Auth flow**: API key exchange for JWT, auto-refresh on expiry.

## Dependencies

- **Runtime**: httpx, pydantic (type hints only)
- **Depends on**: DalyAPI (HTTP, at runtime)
- **Depended on by**: External consumers, potentially Bubba

## Package-Specific Rules

1. Do NOT add imports from dalyapi, core.models, or daly_schema.
2. Do NOT return Pydantic model instances — return raw dicts.
3. All internal imports must use `from dalysdk.X import Y` (absolute).
4. Keep httpx as the only HTTP dependency.
