chubin/wttr.in
64.7
Adequate · 24 September 2026
9.9k
lines of production code
Go
primary language
5
measurements over time
What this system is
This system is a high-performance, Go-based weather information service that serves console-friendly and web-compatible weather reports via HTTP. It processes location and IP queries to fetch and cache data from upstream providers, then renders the results into multiple formats including ANSI terminal output, HTML, PNG images, and JSON. The service supports extensive internationalization, multi-language localization, and various display modes, while managing infrastructure concerns like SSL termination, structured logging, and deployment via Docker and systemd.
How it got here
2015–2022 — Go-based server rewrite
12 changes.
The project underwent a comprehensive rewrite from Python to Go, establishing a new internal package structure, YAML-based configuration, and structured logging. This period also introduced expanded location alias support, dark-themed static assets, and a Salt Stack deployment configuration to support the new architecture.
2024–2026 — Architecture modernization and rendering expansion
27 changes.
The project underwent a significant architectural overhaul, introducing a modular internal structure with dedicated packages for domain models, caching, and query validation. This refactoring enabled the addition of diverse output formats, including rich v2 terminal renderers, HTML, PNG images, and Prometheus metrics, alongside robust multi-language localization support.
Features
Add pyphoon-lolcat wrapper script
A new executable wrapper script has been added at share/wrappers/pyphoon-lolcat that integrates the pyphoon tool with lolcat for colored output. The script ensures lolcat is installed, extracts location and language settings from environment variables (WTTR\_OPTION\_LOCATION and WTTR\_OPTION\_LANG), and pipes pyphoon's output through lolcat with UTF-8 locale support.
share/wrappers · high confidence
Add systemd service unit and installation instructions for wttr.in
Users can now run wttr.in as a persistent background service using systemd. A new service unit file (wttrin.service) is provided in the share/systemd directory, configured to execute the wttrin.sh script and manage a tmux session, along with a README detailing the steps to install, enable, and start the service for both user and system-level management.
share/systemd · high confidence
Added presentation materials for the 2026 curl up talk
Added a new directory under doc/talks/2026-curlup/ containing a README.md slide deck and a build script. The slide deck covers the history, core concepts, usage examples, and ecosystem integration of the wttr.in console weather service, while the build script allows generating a PDF from the Markdown source using Pandoc.
doc/talks · high confidence
Added utility scripts for emoji extraction, log monitoring, and firewall configuration
Three new Bash scripts have been added to the share/scripts directory to support operational and asset tasks. The extract-emoji.sh script uses ImageMagick to render a predefined set of weather-related emojis (such as sun, clouds, and rain) into PNG images in the share/emoji directory. The log-space.sh script monitors disk usage for the /wttr.in directory and appends the available space to a log file. The setup-iptables.sh script configures firewall rules to allow traffic on ports 80, 443, and 22024, while rejecting other incoming TCP connections on the eth0 interface.
share/scripts · high confidence
Expanded location aliases and request filtering
The application now supports a significantly larger set of location aliases, allowing users to search using alternative city names, common misspellings, and international variants (e.g., 'Msk' for Moscow, 'sanjose' for San Jose, 'YYZ' for Toronto Pearson Airport). Additionally, a new blacklist prevents the system from processing requests for non-location assets like 'apple-touch-icon.png' or 'NOT\_FOUND', improving response accuracy.
share · high confidence
Initial Salt Stack deployment configuration for wttr.in
Added an opinionated Salt Stack state to deploy the wttr.in weather service. This includes an init.sls state that manages dependencies (Go, Python libraries), clones the repository, configures the wego weather client via pillar-based API keys, and sets up a systemd service to run the application on port 80 using authbind. A README provides setup instructions and caveats regarding the required directory structure and current compatibility status.
share/salt · high confidence
Initial release of the Go-based wttr.in server implementation
The project has been rewritten in Go, replacing the previous Python-based implementation. This change introduces a new build system using a Makefile and build.sh script, a multi-stage Dockerfile targeting Go 1.26 and Alpine 3.23, and a new internal package structure for configuration, caching, rendering, and localization. The server binary (srv) now supports multiple renderer views (v1, v2, v2d, v2n) and output formats (ANSI, HTML, PNG, JSON, Prometheus, one-line) via a unified configuration loaded from YAML.
(repo-wide) · high confidence
Initial translation bundle implementation with embedded resource loading
The internal translation system now uses a \Bundle\ struct that embeds translation files directly into the binary via Go's \embed\ package. This change introduces the core logic for loading and serving localized content, including general messages, weather conditions (by code and English name), and raw text files. The implementation preloads all available languages from the \embed/share/translations\ directory at startup, distinguishing between full and partial translations based on metadata, and provides fallback to English for missing keys or unsupported languages.
internal/translate · high confidence
Introduce GeoIP2 support and SQLite-based IP cache
The internal IP geolocation service now supports MaxMind GeoIP2/GeoLite2 City databases as a lookup source, in addition to the existing file-based cache. A new SQLite-backed cache implementation is available for storing and retrieving IP location data, with a migration tool to convert existing file-based cache entries into the new database format. The cache operations are now protected by a mutex to ensure thread safety.
internal/ip · high confidence
Introduce multi-layer cache configuration with disk and LRU backends
The internal cache system has been restructured to support distinct, independently configurable cache layers for different data types. A new configuration schema (internal/cache/config.go) defines separate sections for response caching (rendered output) and weather data caching (raw upstream API responses), allowing each layer to specify its own backend type, TTL, and size limits. The implementation now includes a disk-backed cache (internal/cache/disk.go) for persistent storage of weather data and an LRU-based in-memory cache (internal/cache/lru.go) for fast response caching, both implementing a unified Cacher interface with support for in-progress markers to prevent thundering herd problems. A no-op cache implementation (internal/cache/noop.go) is provided for disabled layers.
internal/cache · high confidence
Introduce uplink proxy for backend request routing
The internal/uplink package now handles incoming requests by proxying them to configured backend uplink servers. It routes traffic to different backend addresses based on the request type (e.g., PNG images, v2 views, or standard views) and enriches forwarded requests with location and parsed options as JSON headers to optimize backend rendering. Responses are cached with randomized expiration times to prevent thundering herd issues.
internal/uplink · high confidence
Introduce v2 rich-panel terminal weather renderer
A new v2 renderer has been added to the internal terminal output, replacing the previous single-line view with a multi-block, framed panel. This view features a color-coded Braille temperature diagram with min/max labels, a rain sparkline with probability coloring, hourly weather emojis, and a wind block with direction arrows and speed-based coloring. It also includes an astronomical timeline (dawn/sunrise/sunset/dusk/moon phase), a date header, and a localized textual information footer. The implementation uses cubic spline interpolation for smoother plots and supports dumb-mode fallbacks for non-Unicode terminals.
internal/renderer/v2 · high confidence
Introduction of internal error types and Cadre struct
A new internal types package has been added, defining standard error variables (ErrNotFound, ErrUnknownLocationService, ErrUpstream, ErrInvalidCacheEntry) and a Cadre struct containing a byte slice body. This provides a centralized location for shared error handling and data structures used within the internal types module.
internal/types · high confidence
New ANSI-to-PNG image formatter with multi-script support
The \internal/formatter/ansitopng\ package introduces a new capability to render terminal output as PNG images. This formatter supports a wide range of character sets, including Cyrillic, Greek, Arabic, Hebrew, Han, Hiragana, Katakana, Hangul, Braille, Devanagari, Bengali, and Gurmukhi, by loading specific fonts per script category. It handles 256-color ANSI palettes, emoji rendering, and configurable options such as background color, transparency, and inverted colors. The implementation fixes high-concurrency corruption by loading fresh font faces per render and corrects vertical position computation and color support for accurate visual output.
internal/formatter/ansitopng · high confidence
New HTML and PNG output formats for weather reports
The application now supports generating weather reports as HTML pages and PNG images in addition to the existing text and JSON formats. The new HTML formatter converts ANSI terminal output into a styled web page using the buildkite terminal-to-html library, while the PNG formatter renders the terminal output as an image. These new capabilities are implemented in the internal formatter package alongside the existing text and JSON formatters.
internal/formatter · high confidence
New HTML output templates for weather reports
Added new HTML templates for the weather report formatter. The default template provides a simple, dark-mode-friendly view with monospace font support, while the Buildkite-specific template offers a styled terminal-like appearance with social sharing buttons for GitHub and Twitter.
share/templates · high confidence
New internal location cache with SQLite storage and geocoding providers
The internal/location package now provides a geocoding cache that stores resolved locations in a SQLite database (with an LRU in-memory layer) instead of the previous file-based approach. It supports batched writes to improve performance and integrates with external geocoding services (LocationIQ and OpenCage) via a configurable provider interface. The cache also enriches location data with timezone information using an embedded timezone database, and exposes a response handler for resolving location queries.
internal/location · high confidence
New internal package for accessing embedded project assets
A new internal package, internal/assets, has been introduced to provide a centralized way to access static files embedded directly into the application binary. This package exposes an embed.FS instance containing files from the 'embed' directory and offers helper functions like GetFile and MustGetFile, allowing other parts of the codebase to read these assets by path without relying on the filesystem at runtime.
internal/assets · high confidence
New internal utility functions for file, HTTP, string, and YAML operations
The internal/util package now provides several helper functions: RemoveFileIfExists safely deletes a file only if it exists; ReadUserIP extracts the client's IP address from an HTTP request by checking X-Real-Ip, X-Forwarded-For, and falling back to RemoteAddr; InSlice and HasPrefixInSlice check for string presence in slices, with the latter supporting prefix matching; and YamlUnmarshalStrict parses YAML data, returning an error if unknown fields are encountered. These utilities support internal logic for file management, request handling, data validation, and configuration parsing.
internal/util · high confidence
New renderer package with J1, J2, Prometheus, and Page renderers
The internal renderer logic has been moved to a dedicated package, introducing several new output formats. The J1 renderer now returns raw weather data as JSON, while the J2 renderer provides a minified JSON output with hourly forecast entries removed for a more compact representation. A Prometheus renderer has been added to expose weather metrics (such as temperature, humidity, and wind speed) in Prometheus exposition format, including support for current conditions and a 3-day forecast. Additionally, an embedded page renderer now serves static text pages (like help and about) with full multilanguage support via the localization system, falling back to English assets if a localized version is unavailable.
internal/renderer · high confidence
New subprocess-based renderer for external weather rendering
A new renderer implementation has been added that delegates weather rendering to external subprocesses. This renderer uses a routing configuration (SubprocessRoute) to match requests based on location and other query options, then executes a specified external program. Data from the query (options, location, IP data, client data, and raw weather data) is passed to the subprocess via environment variables prefixed with WTTR\_. This allows external tools or scripts to generate weather content while integrating with the existing localization and query systems.
internal/renderer/subprocess · high confidence
New teansi package for ANSI rendering and text manipulation
A new internal package, teansi, has been added to provide ANSI serialization and color manipulation capabilities for the go-te terminal engine. This addition introduces a ToANSI function that converts screen buffers into colored ANSI strings, helper functions for setting cell and line colors (including true-color and 256-color support), and a WriteText function to render text with optional styling at specific screen coordinates.
internal/renderer/teansi · high confidence
New terminal utility for ANSI removal and truecolor conversion
The internal/util/termutil package has been introduced to centralize terminal text processing. It provides a RemoveANSI function to strip ANSI escape codes from text and a TruecolorTo256 function that converts 24-bit truecolor ANSI sequences into the closest 256-color equivalents, ensuring compatibility with terminals that do not support truecolor.
internal/util/termutil · high confidence
Server now supports multiple SSL/TLS certificates via SNI
The server configuration and runtime have been updated to support serving multiple SSL/TLS certificates for different domains or wildcards using Server Name Indication (SNI). Administrators can now define a list of certificates in the configuration file, each mapped to a specific domain or wildcard pattern, while maintaining backward compatibility with the legacy single-certificate setup. This allows the server to correctly present the appropriate certificate for each requested domain, improving security and flexibility for multi-domain deployments.
internal/server · high confidence
Behavioural changes
Add supervisord configuration for multi-process container management
The Docker environment now uses supervisord to manage multiple application processes within the container. A new configuration file defines three managed services: the main server (srv), a proxy service, and a geoproxy service, ensuring they are all started and monitored by a single process manager rather than relying on a single entrypoint.
share/docker · high confidence
Code generator for query options now includes map conversion and default application logic
The code generator in internal/generate has been updated to produce Options structs that include new methods for converting between the struct and map\[string\]string representations (ToMap, ApplyParsedMap) and generating query strings (ToQueryString). This change ensures that generated options correctly handle default values when parsing maps and only include non-zero/non-default values when serializing back to maps or query strings, improving consistency in how query parameters are processed and reconstructed.
internal/generate · high confidence
Dark-themed static assets and error page for share view
The share/static area now provides a dark-themed user experience by default. A new malformed-response.html page displays a user-friendly error message when the service is overloaded, including links to the project's GitHub repository and Twitter updates. The styling is handled by new style.css and terminal.css files: style.css sets a black background with light text and defines a robust monospace font stack for preformatted content, while terminal.css introduces comprehensive CSS classes for rendering terminal output, including support for xterm-256 colors, text attributes (bold, italic, underline, blink), and background colors.
share/static · high confidence
Introduce central domain models for weather data and caching
The application now defines its core business entities and data transfer objects in a new \internal/domain\ package. This includes structured types for weather responses (current conditions, forecasts, hourly data, and astronomy), location details, and client information. Additionally, the \CacheEntry\ type has been extended with metadata fields (\CachedAt\, \TTL\, \Key\, \Source\) to support better observability and multi-source caching, providing users with more robust and debuggable caching behavior.
internal/domain · high confidence
Introduce new weather service pipeline with request coalescing and caching
The internal weather handling has been replaced with a new pipeline architecture that includes request coalescing and time-based caching. This change limits parallel upstream connections to World Weather Online to prevent overload, caches weather data for up to 45 minutes to reduce latency, and coalesces concurrent requests for the same location so only one upstream call is made. It also adds support for CamelCase location names and logs unknown locations to a file for debugging.
internal/weather · high confidence
Introduction of YAML-based configuration management
The application now supports loading its entire configuration from a YAML file, replacing the previous method of configuration. This change introduces a structured configuration system that manages settings for geolocation, IP parsing, weather data sources, caching, logging, upstream uplinks, the HTTP server, and the renderer subprocess. Users can now define these settings in a single external file, which is parsed using strict unmarshalling to ensure validity.
internal/config · high confidence
Localized weather data now includes per-language keys alongside generic language keys
The localization system has been refactored to support both generic \lang\_xx\ keys and specific per-language keys (e.g., \lang\_de\) in weather responses. A new \internal/localization\ package introduces an \L10n\ wrapper that binds language-specific functions to reduce boilerplate, and a \TranslateWeather\ function that processes weather JSON to inject these translated condition strings. This change ensures that clients can access localized weather descriptions using either the standard ISO language code or the specific language identifier, improving flexibility for international users.
internal/localization · high confidence
New structured request logging with suppression and localhost filtering
The application now includes a dedicated logging subsystem that aggregates HTTP request metrics (protocol, IP, URI, user-agent) and writes them to a configurable file at set intervals. This new behavior automatically filters out localhost traffic (127.0.0.1 and ::1) to reduce noise from health checks, and provides a log suppressor mechanism to filter specific log lines based on configured prefixes. Configuration for access logs, error logs, and flush intervals is now centralized in a dedicated config structure.
internal/logging · high confidence
Oneline renderer refactored with new emoji profiles and USCS support
The oneline renderer has been restructured into a modular package with a new centralized emoji profile system (unicode, narrow, nerd, plain) accessible via the ?emoji= option, replacing the previous hardcoded symbol logic. It now supports USCS (United States Customary Units) via the UseUscs option, ensuring precipitation and temperature fields render in inches and Fahrenheit respectively, matching the existing imperial behavior. The rendering pipeline is now driven by a registry of placeholder functions (e.g., %c, %t, %p) mapped in oneline.go, with dedicated files for emoji, moon, solar, and data parsing logic, improving maintainability and extensibility.
internal/renderer/oneline · high confidence
Refactor options package and add configurable emoji profile
The internal options handling has been reorganized into a dedicated \internal/options\ package, consolidating the structure for weather query parameters. This change introduces a new \Emoji\ option that allows users to select an emoji profile or symbol set, which affects both the visual appearance and terminal alignment of the output. Additionally, the options structure now explicitly supports various display modes (such as current weather, forecasts for multiple days), unit systems (metric, imperial, USCS), and formatting controls (like transparency, padding, and ANSI force modes), providing a more granular and configurable experience for generating weather reports.
internal/options · high confidence
Strict, configuration-driven query parsing and validation
The query handling logic has been replaced with a new \internal/query\ package that enforces strict validation of HTTP request parameters based on a YAML specification. This change means that previously accepted malformed or undocumented query parameters are now rejected with specific error codes, and boolean flags are handled more rigorously (e.g., rejecting unknown short flags). The system now supports bundled short options (like \?0pq\), validates parameter types and ranges against the spec, and applies automatic fixes for view/output format defaults based on the user agent. This ensures that only valid, active options defined in the configuration are processed, improving reliability and security for API consumers.
internal/query · high confidence
V1 renderer rewritten with new translation and layout support
The v1 terminal weather renderer has been partially rewritten to support internationalized weather descriptions (using localized language codes with English fallback), right-to-left text rendering for languages like Hebrew and Arabic, and a new structured layout system that formats forecast days into morning, noon, evening, and night slots. The change also introduces a 'dumb' mode for terminals without color support, updates the wind direction icons, and adds support for Punjabi.
internal/renderer/v1 · high confidence
Test coverage
Added smoke tests for wttr.in API endpoints; Added v1 renderer golden test fixtures and automation.
Dependencies
Initial Go dependency manifest for wttr.in
The project introduces a new Go module definition (go.mod) and lock file (go.sum) for the wttr.in service, establishing the foundational library dependencies required for its operation. This includes libraries for terminal-to-HTML conversion, Unicode text width handling, emoji rendering, geographic location services (GeoIP2, timezone mapping), astronomical calculations (sunrise/sunset, twilight), and database access (SQLite via go-sqlite3).
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.
Score
- CAI 63 → 65 (+1.3)
- Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 76 → 84 (+8.4)
- Architecture 100 → 99 (-1.4)
- Maturity 60 → 60 (-0.0)
- Readiness 64 → 68 (+3.2)
- Security 81 → 82 (+0.4)
- Domain Modelling 64 → 70 (+6.1)
- Accessibility 64 → 64 (+0.0)
Resolved (29)
- Coverage not included — suite not readable by the collector
- Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
- Duplicated block (13 lines × 2) (internal/localization/weatherer_translate.go)
- Duplicated block (13 lines × 2) (internal/renderer/oneline/render_solar.go)
- Duplicated block (13 lines × 2) (internal/renderer/v1/format.go)
- Duplicated block (15 lines × 2) (internal/renderer/v2/block_temperature.go)
- Duplicated block (5 lines × 2) (internal/util/termutil/termutil.go)
- Duplicated block (7 lines × 2) (internal/renderer/oneline/render_solar.go)
- Duplicated block (7 lines × 2) (internal/renderer/v1/converter.go)
- High CVE: [GHSA redacted] (go.mod)
- High: security finding (details withheld)
- High: security finding (details withheld)
- Hotspot: internal/formatter/ansitopng/ansitopng.go (internal/formatter/ansitopng/ansitopng.go)
- Hotspot: internal/formatter/ansitopng/fonts.go (internal/formatter/ansitopng/fonts.go)
- Hotspot: internal/localization/weatherer_translate.go (internal/localization/weatherer_translate.go)
- Hotspot: internal/query/fromrequest.go (internal/query/fromrequest.go)
- Hotspot: internal/renderer/renderer_p1.go (internal/renderer/renderer_p1.go)
- Hotspot: internal/renderer/subprocess/subprocess.go (internal/renderer/subprocess/subprocess.go)
- Hotspot: internal/renderer/v1/renderer.go (internal/renderer/v1/renderer.go)
- Hotspot: internal/weather/weather.go (internal/weather/weather.go)
- …and 9 more
New (40)
- Dependency pinned to a stale untagged commit: github.com/cnkei/gospline
- Dependency pinned to a stale untagged commit: github.com/goastro/twilight
- Documentation: no installation or build instructions (README.md)
- Documentation: no usage examples (README.md)
- Duplicated block (12 lines × 2) (internal/location/convert.go)
- Duplicated block (15–16 lines × 2) (internal/renderer/oneline/render_solar.go)
- Duplicated block (23 lines × 2) (internal/localization/weatherer_translate.go)
- Duplicated block (26–27 lines × 2) (internal/renderer/v2/block_temperature.go)
- Duplicated block (45–46 lines × 2) (internal/renderer/v1/format.go)
- Duplicated block (6 lines × 2) (internal/util/termutil/termutil.go)
- Duplicated block (7 lines × 2) (internal/renderer/v1/converter.go)
- Duplicated block (7–10 lines × 2) (internal/renderer/oneline/render_solar.go)
- High CVE: [GHSA redacted] (go.mod)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- Medium CVE: [GHSA redacted] (go.mod)
- Medium CVE: GO-2026-5024 (go.mod)
- Medium CVE: GO-2026-5970 (go.mod)
- …and 20 more
Changes since last survey
- 1 commits — 1 feature/other, 0 fixes
By area
- (root) — 1 commit
Notable commits
- change: docs: Update OpenCage acknowledgment for geolocation data
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
chubin/wttr.in was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 24 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit c369bc45df4b140e8a9092c57b49e980b3a5c35e — the exact code this score is about.
- Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-5f8d0eb43fd7.