Skip to content

Commit eee2245

Browse files
committed
docs: add AGENTS.md coding standards and architecture guide
1 parent 787cb44 commit eee2245

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# AGENTS.md — Thermal Coding Standards & Architecture Guide
2+
3+
This document defines the architectural conventions, coding standards, loader requirements, build quirks, and historical lessons for **Thermal** (`github.com/jadmadi/thermal`). Any AI coding assistant (Claude Code, Gemini CLI, Devin, OpenCode, Cursor, etc.) working on this repository MUST read and adhere to these standards.
4+
5+
---
6+
7+
## 1. Project Purpose & Architecture
8+
9+
Thermal (`thermal`) is a high-performance, zero-allocation terminal contribution heatmap and leaderboard tool for AI coding assistants. It scans local databases and session transcripts across multiple AI tools, calculates activity and token metrics, and renders beautiful terminal heatmaps.
10+
11+
### Directory Structure
12+
13+
```
14+
thermal/
15+
├── cmd/thermal/ # Main CLI entrypoint (main.go, upgrade.go for self-update mechanism)
16+
├── internal/loaders/ # Tool-specific ingestion engines and incremental delta-cache
17+
├── internal/thermal/ # Heatmap algorithms, streak calculation, and time parsing
18+
├── internal/render/ # Terminal formatting, color palettes, dashboard & leaderboard UI
19+
├── internal/version/ # SemVer constants and ldflag injection targets
20+
├── build.sh # Local multi-target build and UPX compression script
21+
└── .goreleaser.yml # Automated GitHub Actions release configuration
22+
```
23+
24+
---
25+
26+
## 2. Core Coding & Architectural Standards
27+
28+
### A. Read-Only Data Ingestion (`internal/loaders/`)
29+
1. **Never Modify User Data**: All SQLite connections MUST open in strictly read-only mode using URI parameters:
30+
```go
31+
db, err := sql.Open("sqlite", "file:"+dbPath+"?mode=ro")
32+
```
33+
2. **Memory-Mapped I/O**: Immediately after opening any SQLite database, execute `PRAGMA mmap_size` to enable memory mapping for instant scanning of multi-gigabyte files:
34+
```go
35+
db.Exec("PRAGMA mmap_size=268435456") // 256MB mmap window
36+
```
37+
3. **Robust Time Parsing (`parseSessionTime`)**: AI tool timestamps vary wildly across tools and versions (RFC3339 strings, Unix seconds, milliseconds, microseconds, SQLite strings). Always use robust multi-format parsing or `time_test.go` utilities. Never assume a single fixed format.
38+
4. **Incremental Delta Caching (`cache.go`)**: For large databases (`Devin`, `OpenCode`, `MiMoCode`, `Codex`) and multi-file scanners (`command-code`, `Agy`), use the `LoadOrScanWithCache` mechanism (`~/.cache/thermal/<tool>.json`). Store exact file modification times (`mod_time`), sizes (`size`), or max seen transaction IDs so subsequent invocations take under `10ms`.
39+
5. **Concurrency Safety**: Multi-file, directory, and JSONL log scanners (`command-code`, `Codex` rollout logs, `Agy` overview logs) must use bounded worker pools (`sync.WaitGroup` or semaphore channels capped at ~16 workers) with thread-safe aggregation (`sync.Mutex`). Never spawn unbounded goroutines over thousands of files.
40+
41+
### B. Tool-Specific Loader Quirks
42+
* **Devin (`devin.go`)**: Queries the SQLite DB joining `message_nodes` against `sessions`. Always check `metadata.metrics` for true input/output/cache token counts (`input_tokens`, `output_tokens`, `cache_creation_tokens`, `cache_read_tokens`). Check `prompt_history` (`updated_at` fallback to `created_at`) for accurate streak calculations across sessions without messages.
43+
* **OpenCode / MiMoCode (`opencode.go`, `mimocode.go`)**: Read pre-aggregated `session_summary` or `sessions` tables containing token counts, costs, and diff lines.
44+
* **Codex (`codex.go`)**: Reads `state_5.sqlite` (`threads.tokens_used`, reasoning effort, source/model breakdown) as the primary source. Supplements with rollout JSONL logs (`~/.codex/sessions/**/*.jsonl`) for granular token breakdowns when available.
45+
* **codewhale (`codewhale.go`)**: Reads `~/.codewhale/sessions/*.json` files for `metadata.total_tokens` and `metadata.cost.session_cost_usd`.
46+
* **command-code (`commandcode.go`)**: Scans `~/.commandcode/sessions/*/transcript.jsonl` for message activity and `.meta.json` sidecars for model distributions.
47+
* **Agy (`agy.go`)**: Scans `~/.gemini/antigravity-cli/brain/*/overview.txt` (`Step <id>:` step count activity) and `.system_generated/logs/transcript.jsonl` (`MODEL` step entries) for model distribution.
48+
49+
---
50+
51+
## 3. Terminal Rendering & CLI (`internal/render/`)
52+
53+
1. **Leaderboard Categories**:
54+
* **Token Warriors**: Tools reporting token usage (`Devin`, `OpenCode`, `MiMoCode`, `Codex`, `codewhale`).
55+
* **Activity Hunters**: Tools reporting actions/messages/steps instead of tokens (`command-code`, `Agy`).
56+
2. **Compact Number Formatting**: Always format large numbers concisely via `CompactNumber()`: `57.2B tok`, `44.0M tok`, `22.7K tok`, `304 step`.
57+
3. **Color & Verbosity Flags**:
58+
* `--no-color`: Strips all ANSI escape sequences. Always check `colorEnabled` before emitting color codes.
59+
* `--verbose`: Outputs non-fatal loader diagnostic warnings (`database locked`, `missing directory`) exclusively to `os.Stderr`. Never pollute `os.Stdout` or JSON output (`--json`) with warnings.
60+
61+
---
62+
63+
## 4. Build, Versioning & Release Guidelines
64+
65+
### A. `.gitignore` Path Rules
66+
* **IMPORTANT**: Never put bare binary names like `thermal` directly in `.gitignore`. Because `cmd/thermal/` and `internal/thermal/` share the name `thermal`, a bare `thermal` rule will silently ignore source files inside those directories (`e.g., cmd/thermal/upgrade.go`)!
67+
* **Rule**: Always use root-anchored paths for build artifacts: `/thermal`, `/dist/`, `*.exe`.
68+
69+
### B. GoReleaser Configuration (`.goreleaser.yml`)
70+
1. **Template Variables**: GoReleaser v2 strictly enforces `{{ .ShortCommit }}`. Never use `.Short_commit` (causes fatal build errors).
71+
2. **UPX Compression**:
72+
```yaml
73+
upx:
74+
- enabled: true
75+
compress: "9"
76+
goos:
77+
- linux
78+
- windows
79+
```
80+
* **Rule**: Enable UPX compression **ONLY** for `linux` and `windows` binaries.
81+
* **Do NOT compress `darwin` (macOS) binaries with UPX**: Stripped `darwin/amd64` and `darwin/arm64` binaries must remain uncompressed so macOS Gatekeeper, code signing, and binary format verifiers do not reject the executable.
82+
83+
### C. Automated Release Pipeline (`release-please` + `goreleaser`)
84+
1. **Conventional Commits**: All commit messages MUST follow Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`, `refactor:`, `test:`).
85+
* `release-please` (`googleapis/release-please-action@v5`) parses commits since the last release tag (`vx.y.z`) to calculate SemVer bumps and automatically generate PRs updating `CHANGELOG.md` and `.release-please-manifest.json`.
86+
2. **Release Execution Flow**:
87+
* When the automated `release-please` PR (`chore(master): release x.y.z`) is merged into `main`, `release-please` tags the commit (`vx.y.z`) and creates the GitHub Release entry.
88+
* The `.github/workflows/release.yml` workflow triggers on `push: tags: ["v*"]`. It installs `upx` (`sudo apt-get install -y upx`) and runs GoReleaser (`goreleaser/goreleaser-action@v6`) to cross-compile across 5 OS/Arch targets, apply UPX compression to Linux/Windows binaries, and upload `.tar.gz` / `.zip` assets directly to the GitHub Release.
89+
90+
---
91+
92+
## 5. Testing & Verification Checklist
93+
94+
Before committing or submitting a pull request, run the verification suite:
95+
96+
```bash
97+
# 1. Run all unit tests with race detection and verbose output
98+
go test -v ./...
99+
100+
# 2. Verify compilation of the CLI binary
101+
go build -o /tmp/thermal-test ./cmd/thermal
102+
103+
# 3. Test alias resolution and heatmap output locally
104+
/tmp/thermal-test --tool auto
105+
/tmp/thermal-test --tool devin
106+
/tmp/thermal-test --tool agy --verbose
107+
```
108+
109+
When modifying loaders, ensure unit tests inside `internal/loaders/*_test.go` cover edge cases (missing databases, corrupted files, zero-token sessions, timestamp variations, and schema differences) using mock temporary files or SQLite in-memory databases.

0 commit comments

Comments
 (0)