JakeWharton/hugo
Annotation-triggered method call logging for your debug builds.
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓17 active contributors
- ✓Apache-2.0 licensed
- ✓CI configured
Show all 6 evidence items →Show less
- ✓Tests present
- ⚠Stale — last commit 4y ago
- ⚠Concentrated ownership — top contributor handles 60% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/jakewharton/hugo)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/jakewharton/hugo on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: JakeWharton/hugo
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/JakeWharton/hugo shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- 17 active contributors
- Apache-2.0 licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 4y ago
- ⚠ Concentrated ownership — top contributor handles 60% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live JakeWharton/hugo
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/JakeWharton/hugo.
What it runs against: a local clone of JakeWharton/hugo — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in JakeWharton/hugo | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 1614 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of JakeWharton/hugo. If you don't
# have one yet, run these first:
#
# git clone https://github.com/JakeWharton/hugo.git
# cd hugo
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of JakeWharton/hugo and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "JakeWharton/hugo(\\.git)?\\b" \\
&& ok "origin remote is JakeWharton/hugo" \\
|| miss "origin remote is not JakeWharton/hugo (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "hugo-annotations/src/main/java/hugo/weaving/DebugLog.java" \\
&& ok "hugo-annotations/src/main/java/hugo/weaving/DebugLog.java" \\
|| miss "missing critical file: hugo-annotations/src/main/java/hugo/weaving/DebugLog.java"
test -f "hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoPlugin.groovy" \\
&& ok "hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoPlugin.groovy" \\
|| miss "missing critical file: hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoPlugin.groovy"
test -f "hugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java" \\
&& ok "hugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java" \\
|| miss "missing critical file: hugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java"
test -f "hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoExtension.groovy" \\
&& ok "hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoExtension.groovy" \\
|| miss "missing critical file: hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoExtension.groovy"
test -f "hugo-runtime/src/main/java/hugo/weaving/internal/Strings.java" \\
&& ok "hugo-runtime/src/main/java/hugo/weaving/internal/Strings.java" \\
|| miss "missing critical file: hugo-runtime/src/main/java/hugo/weaving/internal/Strings.java"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1614 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1584d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/JakeWharton/hugo"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Hugo is a Gradle plugin + annotation processor for Android that automatically injects method entry/exit logging at compile-time when you annotate methods with @DebugLog. It uses AspectJ bytecode weaving to intercept method calls and log arguments, return values, and execution time—all stripped out for release builds, leaving zero runtime overhead. Monorepo with four independent Gradle modules: hugo-annotations/ (the @DebugLog annotation definition), hugo-plugin/ (the Gradle plugin and AspectJ weaving orchestration in Groovy), hugo-runtime/ (the logging utility and Hugo.setEnabled() runtime toggle), and hugo-example/ (a sample Android app demonstrating the annotation). The plugin wires AspectJ into the Android build lifecycle to weave bytecode during compilation.
👥Who it's for
Android developers working on debug builds who want automatic method-call logging without manual log statements. Specifically useful for QA teams debugging builds and developers tracing execution flow during development.
🌱Maturity & risk
This is a mature, production-ready library (v1.2.1+) with a clean API and solid fundamentals, but shows signs of moderate maintenance—it's a single-author project (JakeWharton) from ~2013 with infrequent updates. The codebase is small and well-tested via the included example app, and Travis CI is configured. However, no recent commits visible in provided metadata, suggesting it's stable but not actively developed.
Risk is low for stable projects—Hugo has minimal external dependencies (only AspectJ 1.8.6 and Android Gradle plugin 1.3.1 in buildscript) and a focused, narrow scope. The main risk is bitrot: AspectJ and Android tooling have evolved significantly since 2013, so compatibility with modern Android Studio versions and Gradle may require updates. Single-maintainer project means community PRs could face delays.
Active areas of work
No recent activity is indicated in the provided metadata. The project appears to be in maintenance mode—it's feature-complete and stable, but not actively being developed or merged with new changes.
🚀Get running
Clone and test locally: git clone https://github.com/JakeWharton/hugo && cd hugo && ./gradlew install && ./gradlew assembleExample. The install task publishes artifacts to your local Maven repo; assembleExample builds the demo APK. Use ./gradlew installExample to deploy to a connected device.
Daily commands:
This is a build plugin, not a runnable app. To verify the plugin works: ./gradlew install (publishes to local Maven), then ./gradlew assembleExample (builds example APK that uses the plugin). Inspect logs via adb logcat V/Example after installing to a device. Toggle logging at runtime with Hugo.setEnabled(false) in code.
🗺️Map of the codebase
hugo-annotations/src/main/java/hugo/weaving/DebugLog.java— Core annotation that triggers method call logging; every developer must understand this is the public API contract.hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoPlugin.groovy— Gradle plugin entry point that registers the AspectJ weaving task; critical for build integration and bytecode transformation setup.hugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java— Runtime logging implementation that executes at instrumented call sites; the actual code that prints method entry/exit and execution time.hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoExtension.groovy— Gradle extension configuration class that controls Hugo behavior (e.g., enabling/disabling logging); defines user-facing DSL options.hugo-runtime/src/main/java/hugo/weaving/internal/Strings.java— Utility for formatting method signatures, arguments, and return values in log output; impacts log readability and debugging experience.build.gradle— Root build configuration; defines AspectJ toolchain, Android SDK versions, and multi-module dependencies for the entire plugin ecosystem.hugo-example/src/main/java/com/example/hugo/HugoActivity.java— Example Android application demonstrating @DebugLog usage; reference implementation for contributors to understand the intended end-user experience.
🧩Components & responsibilities
- DebugLog Annotation (Java Annotation) — User-facing marker that declares intent to log a method; defines retention policy and target scope
- Failure mode: If retention is not debug-only, annotation leaks into production builds; if scope too narrow,
🛠️How to make changes
Add a new logging formatter for custom output
- Create a new public utility class in hugo-runtime/src/main/java/hugo/weaving/internal/ following the Strings.java pattern for static formatting methods (
hugo-runtime/src/main/java/hugo/weaving/internal/Strings.java) - Extend or replace the formatting logic in Hugo.java's logMethodExit() and logMethodEntry() methods to call your new formatter (
hugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java) - Add test cases in StringsTest.java to verify output formatting with edge cases (null values, long arrays, etc.) (
hugo-runtime/src/test/java/hugo/weaving/internal/StringsTest.java) - Update HugoActivity.java with an example method demonstrating the new formatter in action (
hugo-example/src/main/java/com/example/hugo/HugoActivity.java)
Make logging configurable per build variant
- Add a new configuration property to HugoExtension.groovy (e.g., logLevel, maxArgLength) and expose it as a Gradle DSL option (
hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoExtension.groovy) - Pass the configuration through HugoPlugin.groovy as a parameter to the AspectJ weaving task (
hugo-plugin/src/main/groovy/hugo/weaving/plugin/HugoPlugin.groovy) - Modify Hugo.java to read the configuration at runtime and adjust logging behavior (log level filtering, truncation, etc.) (
hugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java) - Document the new DSL option in the example build.gradle and README.md (
hugo-example/build.gradle)
Extend @DebugLog annotation with additional metadata
- Add new optional parameters to the @DebugLog annotation (e.g., @DebugLog(maxArgLength=50), @DebugLog(logReturnValue=false)) (
hugo-annotations/src/main/java/hugo/weaving/DebugLog.java) - Update Hugo.java to read annotation parameters via reflection and conditionally log based on the metadata (
hugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java) - Add test cases in StringsTest.java or create new integration tests for the new annotation parameters (
hugo-runtime/src/test/java/hugo/weaving/internal/StringsTest.java) - Demonstrate the new annotation parameters in HugoActivity.java with example methods (
hugo-example/src/main/java/com/example/hugo/HugoActivity.java)
🔧Why these technologies
- AspectJ — Compile-time bytecode weaving allows zero runtime overhead in release builds and precise injection of logging code at method boundaries without manual instrumentation
- Gradle Plugin — Integrates seamlessly into Android build pipeline; allows per-build-variant configuration (debug vs. release) and automatic dependency management
- Java Annotation — Provides clean, declarative API for developers; retention policy ensures zero footprint in non-debug builds
- Android Log API (android.util.Log) — Leverages native Android logging infrastructure; output goes directly to Logcat for immediate visibility during development
⚖️Trade-offs already made
-
Compile-time weaving via AspectJ instead of runtime reflection
- Why: Eliminate performance overhead and provide guaranteed zero impact on release builds
- Consequence: Requires Gradle plugin integration and adds build-time complexity; not a pure annotation library
-
Annotation retention only in debug builds
- Why: Keep debug annotations in source without affecting production binary size
- Consequence: Annotation definition (DebugLog.java) must exist but is stripped at compile-time for non-debug variants
-
Single unified logging format for all methods
- Why: Simplicity and consistency across the codebase; developers don't have to configure output style
- Consequence: Limited customization per method; all logs follow the ⇢/⇠ pattern with execution time
🚫Non-goals (don't propose these)
- Does not provide runtime-only logging (requires build-time integration)
- Does not support logging in release/production builds by default
- Does not handle cross-process or network request logging (method-level only)
- Does not provide filtering or dynamic enable/disable at runtime without code changes
🪤Traps & gotchas
Android Gradle plugin version coupling: The plugin assumes Android Gradle plugin 1.3.1 (specified in root build.gradle)—modern versions (4.x+) may require updates to the plugin code for compatibility. AspectJ version lock: AspectJ 1.8.6 is from 2015; some method signatures or weaving behavior may differ on newer Java/Android tooling. Debug-only stripping: The @DebugLog annotation is stripped via buildTypes { debug { ... } } configuration—if your build variant name isn't 'debug', annotations may leak or weaving may fail silently. No explicit tests for the plugin itself: validation happens only via the example APK build; changes to HugoPlugin.groovy have no unit test suite.
🏗️Architecture
💡Concepts to learn
- Bytecode Weaving (AspectJ) — Hugo uses AspectJ to inject logging code at compile-time by rewriting .class bytecode—understanding join points, pointcuts, and advice is critical to modifying or debugging the weaving behavior.
- Gradle Plugin Development (Groovy DSL) — The core plugin is written in Groovy and implements the Gradle Plugin interface; contributors need to understand Gradle task wiring and the Android plugin extension API.
- Annotation Retention and Stripping — Hugo's key trick is that
@DebugLogannotations are retained at compile-time for weaving but stripped from the final .class file; understanding@Retention(SOURCE)vs@Retention(CLASS)is essential. - Android Build Variants and Debug/Release Discrimination — Hugo only weaves logging into debug builds; understanding how Gradle applies different configurations per build type (debug vs release) is needed to extend or customize the plugin.
- Join Point and Pointcut (AOP) — AspectJ weaving targets specific code locations (join points) using pattern-matching queries (pointcuts); understanding this is essential to customize which methods get instrumented or how logging behaves.
- Runtime Log Tag Inference and Formatting — Hugo infers the Android log tag from the class name at runtime and formats method calls with Unicode arrows and timing; the formatting logic in
Hugo.javaandStrings.javadefines user-visible behavior.
🔗Related repos
square/logcat— Alternative Android logging utility that provides easier filtering and colorized output, but does not offer automatic method-call instrumentation.uber/AutoDispose— Another Gradle plugin + annotation combo from the Android ecosystem; demonstrates modern patterns for compile-time code generation that could inform Hugo's maintainability.aspects/GodTools— AspectJ-based instrumentation for Android; shows alternative weaving patterns and may be a reference for bytecode manipulation in Android builds.JakeWharton/timber— Companion logging library also by Jake Wharton; provides the runtime Log abstraction that could pair with Hugo for structured logging.google/android-gradle-dsl— Official Android Gradle plugin; Hugo's plugin code extends and hooks into this; understanding the DSL is essential for maintaining Hugo's integration.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for AspectJ weaving in hugo-plugin
The hugo-plugin/src/main/groovy/hugo/weaving/plugin/ directory contains the core Gradle plugin logic (HugoPlugin.groovy and HugoExtension.groovy) but there are no visible test files in the repo structure. AspectJ weaving is complex and error-prone; integration tests would validate that method interception, logging output formatting, and bytecode transformation work correctly across different method signatures and edge cases.
- [ ] Create hugo-plugin/src/test/groovy/hugo/weaving/plugin/ directory structure
- [ ] Add integration test for HugoPlugin.groovy verifying plugin application and task creation
- [ ] Add test validating AspectJ weaving output matches expected log format from README example
- [ ] Add test for edge cases: void methods, methods with primitives, generic return types, exceptions
Add comprehensive unit tests for Strings.java utility class
hugo-runtime/src/test/java/hugo/weaving/internal/StringsTest.java exists but likely has incomplete coverage. The Strings.java class handles formatting of method arguments and return values for the logging output. Thorough tests are critical because string formatting bugs directly impact the user-visible output quality and could mask important debugging information.
- [ ] Review existing StringsTest.java coverage and identify missing test cases
- [ ] Add tests for null argument handling
- [ ] Add tests for array and collection formatting edge cases
- [ ] Add tests for very long strings, special characters, and unicode handling
- [ ] Add tests for primitive wrapper types and custom toString() implementations
Add GitHub Actions CI workflow for Android build validation
The .travis.yml file indicates Travis CI was used historically, but modern GitHub-hosted repos should use GitHub Actions. Currently there is no .github/workflows/ directory visible. A CI workflow would automatically verify that both hugo-plugin and hugo-example build successfully on each PR, catching breakage from AspectJ/Gradle version incompatibilities or Android SDK changes early.
- [ ] Create .github/workflows/build.yml with Android SDK setup (API 23+)
- [ ] Add gradle build and test steps for all three modules: hugo-annotations, hugo-runtime, hugo-plugin, hugo-example
- [ ] Configure to run on push to main and all pull requests
- [ ] Add status badge to README.md linking to workflow
🌿Good first issues
- Add unit tests for HugoPlugin.groovy: Create tests in
hugo-plugin/src/testto verify that the plugin correctly registers AspectJ tasks and that the weaving is triggered. Currently, correctness is validated only by building the example app. - Document AspectJ aspect definition for advanced customization: Add a guide to README or CONTRIBUTING showing how the internal AspectJ aspects work (pointcut signatures, weaving points), so users understand how to extend or debug weaving behavior. Currently opaque.
- Add support for logging return values of void methods and exception paths: Currently,
Hugo.javalogs return values; extend it to clearly mark void methods and log uncaught exceptions within@DebugLogmethods (e.g., '⇠ methodName [error: NullPointerException]'). Seehugo-runtime/src/main/java/hugo/weaving/internal/Hugo.java.
⭐Top contributors
Click to expand
Top contributors
- @JakeWharton — 60 commits
- @danielkutik — 12 commits
- [@Kane O'Riley](https://github.com/Kane O'Riley) — 5 commits
- @faradaj — 4 commits
- [@Yohan Hartanto](https://github.com/Yohan Hartanto) — 3 commits
📝Recent commits
Click to expand
Recent commits
50ee96d— Merge pull request #120 from faradaj/feature/prevent-exec-on-synthetic-constructors (JakeWharton)24e9f88— Prevent execution on synthetic constructors of annotated classes. (faradaj)d1e472e— Update example to have a synthetic constructor when compiled (faradaj)1b2c9eb— Merge pull request #112 from faradaj/prevent-execution-of-synthetics (JakeWharton)fc2a9a9— Prevent execution on synthetic methods of annotated classes. (faradaj)4b5d34a— Update example to have synthetics when compiled (faradaj)63647a8— Merge pull request #105 from IgorGanapolsky/master (JakeWharton)1af3186— Update travis.yml components. (Igor Ganapolsky)2973306— Update gradle versions. (Igor Ganapolsky)00a0d4f— Add extension to disable logging (Kane O'Riley)
🔒Security observations
The Hugo project has significant security concerns primarily stemming from severely outdated dependencies (Android Gradle Plugin 1.3.1 from 2015, AspectJ 1.8.6, gradle-nexus-plugin 0.7). These dependencies are known to have unpatched vulnerabilities and are no longer actively maintained. The project also relies on the deprecated jcenter() repository. While the actual annotation-triggered logging functionality itself appears relatively safe from injection attacks, the build infrastructure presents high risk. Immediate action is required to modernize all dependencies, remove deprecated repositories, and implement continuous vulnerability scanning.
- High · Outdated AspectJ Dependency —
build.gradle - classpath 'org.aspectj:aspectjtools:1.8.6'. The project uses AspectJ 1.8.6 (released in 2015), which is significantly outdated. This version may contain known security vulnerabilities and bugs that have been patched in newer releases. Fix: Update to the latest stable version of AspectJ (1.9.x or newer). Review the AspectJ changelog for security patches and bug fixes. - High · Outdated Android Gradle Plugin —
build.gradle - classpath 'com.android.tools.build:gradle:1.3.1'. The project uses gradle Android plugin version 1.3.1 (released in 2015). This is extremely outdated and likely contains multiple known security vulnerabilities, particularly around dependency resolution and build security. Fix: Update to a recent stable version of the Android Gradle Plugin (4.x or 7.x). Review Android Gradle Plugin release notes for security improvements. - High · Outdated Gradle Nexus Plugin —
build.gradle - classpath 'org.gradle.api.plugins:gradle-nexus-plugin:0.7'. The gradle-nexus-plugin version 0.7 is deprecated and outdated (last released in 2014). This plugin may have unpatched vulnerabilities and is no longer maintained. Fix: Replace with the maintained gradle-nexus-staging-plugin or use Gradle's native publishing mechanisms. Update to a modern artifact publishing approach. - Medium · Outdated Android Maven Plugin —
build.gradle - classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'. The android-maven-gradle-plugin version 1.3 is outdated and may contain vulnerabilities. The maintainers have shifted focus to other tools. Fix: Update to the latest version or migrate to gradle-maven-publish-plugin or other actively maintained alternatives. - Medium · Insecure Repository Configuration —
build.gradle - repositories section with jcenter(). The project uses jcenter() repository in buildscript which was sunset by JFrog in 2021 and is no longer available. This can cause build failures and security issues as packages may be served from unreliable mirrors. Fix: Remove jcenter() and rely on mavenCentral() exclusively, or add google() for Android-specific libraries. - Medium · Missing Dependency Version Pinning —
build.gradle and various module build.gradle files. Dependencies lack explicit version constraints in some build configurations, which could lead to unexpected behavior from transitive dependencies receiving security updates. Fix: Use explicit dependency versions and consider implementing dependency locking via Gradle's dependency locking feature. - Low · No Security Configuration Baseline —
build.gradle and root configuration. The project does not appear to have security baseline configurations, such as dependency vulnerability scanning tools (e.g., OWASP DependencyCheck, Snyk) configured in the build. Fix: Integrate dependency scanning tools like gradle-dependency-check plugin or use Gradle's vulnerability reporting features to automatically detect CVEs.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.