Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# AGENTS.md

Guidance for AI coding agents working on TeslaMate.

Human contributors: see [Development and Contributing](https://docs.teslamate.org/docs/development/) and `CONTRIBUTING`.

## Project map

| Path | Role |
|------|------|
| `lib/`, `test/` | Elixir / Phoenix app |
| `priv/repo/` | Migrations and SQL helpers (`convert_celsius`, `convert_km`, …) |
| `grafana/dashboards/` | Provisioned Grafana dashboards |
| `website/` | Documentation (Docusaurus) |
| `nix/`, `flake.nix` | Dev environment / packaging |
| `.github/workflows/` | CI |

Prefer small, reviewable changes. Do not expand scope unprompted.

## Setup and checks

Use versions from the development docs when you have a local environment:

```bash
mix setup
MIX_ENV=test mix ecto.setup
mix ci
treefmt # or: nix run .#lint
```

Not every contributor has a full local Elixir/Postgres/Grafana stack. **It is fine to rely on GitHub Actions CI** on the PR for format checks, tests, and related workflows. Run what you can locally; fix CI failures the PR introduces before asking for merge.

Run `mix gettext.extract --merge` only if user-facing strings changed and you can run Mix.

## Change rules

- Match neighboring style; no drive-by refactors.
- Smallest diff that solves the stated problem.
- Add or update tests for behavior changes.
- Do not commit secrets, tokens, cookies, or vehicle credentials.
- Do not change dashboard **UIDs** unless explicitly requested.

## Grafana dashboards

Canonical query and dashboard craft (timestamps, `positions`/streaming, `EXPLAIN ANALYZE`, `pg_stat_statements`) lives in the [Development and Contributing](https://docs.teslamate.org/docs/development/) docs under **Making Changes to Grafana Dashboards** and **Best Practices**. Follow that. Short rules for agents:

- Use `teslamate/grafana:edge` for local edits. Export as code with **Model: Classic** (not **V2 Resource**); keep the JSON as exported.
- Copy variable/link patterns from a similar existing dashboard (e.g. Overview, Efficiency).
- Common variables: `car_id`, `base_url`, and when relevant `length_unit`, `temp_unit`, `preferred_range`.
- Header links: TeslaMate → `${base_url:raw}` + Dashboards dropdown (tag `tesla`).
- Temperature: `convert_celsius(col, '$temp_unit')` — never hardcode °C-only when settings exist.
- Distance: `convert_km(..., '$length_unit')`.
- Prefer `$__timeFilter` / `$__timeGroup`. If using `DATE_TRUNC`, follow the docs pattern with `TIMEZONE('UTC', …)` and `'$__timezone'`.
- Query `positions` only when needed. If ~15s resolution is enough, prefer `ideal_battery_range_km IS NOT NULL` (and `car_id = $car_id`) to skip dense streaming rows — see docs.
- `positions` is denser while driving than when parked; sample counts are not “time spent.” Prefer time-bucketing for distributions.
- History charts: aggregate where samples exist; use Connect null values **Threshold** (not Always) for long offline gaps.
- Larger UX changes: update screenshots under `website/static/screenshots/` (see docs).
- Keep dashboard domain focus; do not merge unrelated concerns unprompted.

## GitHub

- Do not push, open PRs, merge, or post reviews/comments unless the user explicitly asks.
- PR descriptions: what/why, tradeoffs, how tested; `Closes #…` when applicable.

## AI assistance disclosure

Disclose material AI help on **PR descriptions** and **substantive review comments**.

Use this footer (include the robot icon and the **exact model name**):

```markdown
---

🤖 Assisted by <Exact model name> (<Vendor>) via <Tool> (<what it helped with>).
```

Examples:

```markdown
---

🤖 Assisted by Claude Opus 5 (Anthropic) via Claude Code (implementation, tests).
```

```markdown
---

🤖 Assisted by Grok 4.5 (xAI) via Grok Build (planning, code edits, PR description).
```

Rules:

- Always state the **exact model name** (e.g. `Grok 4.5`, not only “Grok” or “AI”).
- Name vendor, tool, and a short role list.
- Do not paste chain-of-thought or tool logs into the PR.
- The **human** opening the PR or posting the review remains fully responsible for correctness, security, and licensing (AGPL-3.0).

## Security

- Never exfiltrate `.env`, tokens, or database dumps.
- Do not add telemetry or phone-home behavior.
- Treat vehicle location and identity as sensitive.
4 changes: 3 additions & 1 deletion CONTRIBUTING
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Contributing Guidelines

see [Development and Contributing](https://docs.teslamate.org/docs/development/)
See [Development and Contributing](https://docs.teslamate.org/docs/development/).

AI coding agents: see [`AGENTS.md`](./AGENTS.md).
72 changes: 65 additions & 7 deletions website/docs/development.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,12 @@ grafana:

## Making Changes to Grafana Dashboards

To update dashboards you need Grafana running locally. The following _docker-compose.yml_ can be used for this purpose:
Use **`teslamate/grafana:edge`** for local dashboard work. Export JSON as Grafana saves it into `./grafana/dashboards/`.

```yml
services:
grafana:
image: teslamate/grafana:latest
image: teslamate/grafana:edge
environment:
- DATABASE_USER=postgres
- DATABASE_PASS=postgres
Expand All @@ -132,18 +132,39 @@ volumes:
grafana-data:
```

_(on Linux use the actual IP address of the host as `DATABASE_HOST`instead of `host.docker.internal`)_
_(on Linux use the actual IP address of the host as `DATABASE_HOST` instead of `host.docker.internal`)_

Then build the image with `make grafana` and run the container via `docker compose up grafana`.

Access the Grafana at [http://localhost:3000](http://localhost:3000) and sign in with the default user `admin` and password `admin`.
```bash
docker compose up grafana
```

Then edit the respective dashboard(s) locally. To export a dashboard hit the 'Save' button and select `Save JSON to file`. The final JSON file belongs in the directory `./grafana/dashboards/`. To apply the changes rebuild the image and start the container.
Open [http://localhost:3000](http://localhost:3000) (`admin` / `admin`), edit the dashboard, then **Export** → **Export as code**. Under **Advanced options**, set **Model** to **Classic** (not **V2 Resource**), then **Download file** into `./grafana/dashboards/`.

When making larger changes to Grafana Dashboards please include updated screenshots (1920x1080 @ x2, Grafana running in Kiosk mode) in `./website/static/screenshots`. Ensure to blur sensitive information.

## Best Practices

### Dashboard variables and units

Most dashboards follow a shared shell. Prefer copying variable and link blocks from a similar existing dashboard (e.g. Overview or Efficiency) rather than inventing new shapes.

Common template variables:

| Variable | Typical source | When |
|----------|----------------|------|
| `car_id` | `cars` | Almost always |
| `base_url` | `settings.base_url` | Header link to TeslaMate |
| `length_unit` | `settings.unit_of_length` | Distance / speed |
| `temp_unit` | `settings.unit_of_temperature` | Temperature |
| `preferred_range` | `settings.preferred_range` | Ideal vs rated range |

Typical header links: **TeslaMate** → `${base_url:raw}`, plus a **Dashboards** dropdown on tag `tesla`.

Use the database helpers so user settings apply:

- Temperature: `convert_celsius(column, '$temp_unit')` — do not hardcode Celsius-only units, axis labels, or thresholds when `temp_unit` exists
- Distance / speed: `convert_km(column, '$length_unit')`

### Queries involving timestamp columns

Datetime values are currently stored in columns of type `timestamp`. [This is NOT recommended](https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_timestamp_.28without_time_zone.29_to_store_UTC_times).
Expand All @@ -165,6 +186,8 @@ When Streaming API is enabled roughly 1 GB of data is gathered per car and 30 00
- only query positions table when really needed
- if data in 15 second intervals is sufficient consider excluding streaming data by adding `ideal_battery_range_km IS NOT NULL and car_id = $car_id` as WHERE conditions

Logging is much denser while driving than when parked or asleep. **Sample counts are not “time spent.”** For frequency distributions, heatmaps, or percentiles over ambient conditions, time-bucket or otherwise debiased aggregates first; do not treat raw row counts as a fair distribution.

Before opening pull requests please diagnose index usage & query performance by making use of `EXPLAIN ANALYZE`.

### Enable _pg_stat_statements_ to collect query statistics
Expand Down Expand Up @@ -227,6 +250,41 @@ Before we can merge your first Pull Request, you must sign our **Fiduciary Licen
- **How?** When you open a PR, our `@cla-assistant` bot will post a comment with a link to sign the agreement using your GitHub account. It only takes a few seconds.
- **More Info:** You can find the full text and further details in our [Legal Repository](https://github.com/teslamate-org/legal).

### 3. AI-assisted contributions

**Use of AI tools is welcome** for planning, implementation, tests, docs, and review drafting.

You remain fully in charge of what you submit or post:

- You must understand the change and be able to explain it.
- You are responsible for correctness, security, performance, and license compliance (AGPL-3.0 / CLA).
- Review comments or replies drafted with AI are still **your** review: read and agree with every request before posting.
- Do not let an agent push, merge, or speak on GitHub on your behalf without your explicit direction and review.

For **material** AI assistance, disclose it at the end of the PR description and of substantive review comments. Include the robot icon and the **exact model name** (not only a product family):

```markdown
---

🤖 Assisted by <Exact model name> (<Vendor>) via <Tool> (<what it helped with>).
```

Examples:

```markdown
---

🤖 Assisted by Claude Opus 5 (Anthropic) via Claude Code (implementation, tests).
```

```markdown
---

🤖 Assisted by Grok 4.5 (xAI) via Grok Build (planning, code edits, PR description).
```

Trivial edits (typos, rebases) need no footer. Agent-oriented project rules (commands, Grafana conventions, scope) live in [`AGENTS.md`](https://github.com/teslamate-org/teslamate/blob/main/AGENTS.md) at the repository root.

## Pre-Merge Checks for Dependency Updates

When reviewing a pull request that updates dependencies, it's crucial to verify that the changes are correct and don't break the Nix-based development environment. After checking out the branch of the PR, run the following commands:
Expand Down
Loading