DEV Community

Masumi Kawasaki 💭
Masumi Kawasaki 💭

Posted on

Explaining Mac system metrics with Gemma in MenuPulse

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2 Side Hustle.

What I Built

When my Mac shows 30% CPU usage, I still have to decide what to check next. Memory readings take a little more interpretation: usage, compression, swap, and memory pressure each tell me something different.

I added an explanation feature to MenuPulse, a macOS menu bar app I was already developing. It captures a snapshot of system metrics and asks Gemma or ChatGPT for a short explanation. My work this week was adding that feature to the existing monitor and getting it working on my own Mac.

MenuPulse shows CPU, GPU, memory, SSD, and other system information from the menu bar. The new feature organizes its explanation into three parts: what was observed, what it might mean, and what to check next.

I have individuals and freelancers who work on Macs in mind. When something feels slow, they have work to get back to. I want to shorten the time they spend interpreting numbers and deciding where to look.

If this becomes a tool people would pay for, I think its value will come from making that everyday check easier. That is still a hypothesis. Getting it to work on my Mac and finding someone willing to pay for it are two things I need to test separately.

Demo

The interaction is short:

  1. Open “今の状態を説明” (“Explain the current state”) from the menu.

  2. Review the captured measurement time and the data that will be sent.

  3. Choose a local LLM or ChatGPT.

  4. Press the button to request an explanation.

Opening the window does not start an AI request. There is no repeated automatic inference. The user decides what to do after reading the explanation; MenuPulse does not terminate processes or delete files.

In my own testing, I signed in to ChatGPT and received an explanation. After fixing the local request handling described below, I also received a complete Gemma explanation in the app.

How I Built It

MenuPulse targets Apple Silicon Macs running macOS 14 or later. It uses Swift 6 and Apple's system frameworks. I added no external library dependencies to the application's Swift package; LM Studio runs the local model separately.

I used Codex during development, with automated tests for request handling, metric aggregation, cancellation, and other behavior. Testing with the actual model and app then exposed a problem the automated tests had missed.

Capture the metrics before inference

A local model uses CPU, GPU, and memory while explaining the Mac's condition. I capture the input before starting inference so that this generation's workload does not become part of the data being explained. Memory already occupied by a loaded model is still part of the Mac's system readings.

The input is limited to aggregate values such as CPU and GPU usage, total and used memory, compressed memory, memory pressure, swap, and disk capacity. CPU and memory also include a short summary covering up to the previous 120 seconds.

Calendar events, process names, IP addresses, and device names are excluded. That also limits the explanation: it does not have the information needed to identify which application caused a problem. Missing measurements remain unknown instead of becoming zero.

Keeping the input small makes it easier to inspect what was sent and check which measurements support the answer.

Fix the Gemma timeout

In the first test with the actual app, ChatGPT returned an explanation, but Gemma timed out.

The LM Studio logs showed that the request had arrived. Gemma spent about 34 seconds reasoning, then continued generating the explanation. Around 46 seconds after the request began, the client disconnected. MenuPulse had a 45-second request timeout and was waiting to receive the response all at once.

The generation budget was tight too. Reasoning alone used 764 tokens out of a 1,000-token limit.

I changed the local request to receive a stream, increased the timeout to 120 seconds, and raised the generation limit to 2,048 tokens, including reasoning. The parser keeps reasoning text out of the displayed explanation and requires both normal completion and the stream's end marker before accepting the answer.

A test using the production request and parsing code, with synthetic aggregate input, completed against the actual Gemma model in 55.88 seconds. A mock server that waited 47 seconds before sending its first response also completed successfully. After that, the app displayed Gemma's full explanation.

I only found this problem when I tried the real model. During a wait that looked unproductive from the client side, the model was still working.

Keep measuring MenuPulse itself

MenuPulse runs in the background, so its own CPU, memory, and disk usage are product requirements. Each release build is followed by a 60-second measurement of the collection process and a check against existing budgets. I also set up a daily five-minute measurement of the running app.

The performance measurement code needed a correction of its own. On this M1, one part of the process CPU-time calculation was not converting Mach time units correctly, so older reports understated CPU usage. The conversion is now fixed, and those older CPU readings are excluded from baseline comparisons.

After the request-handling fix, the release build's collection process was measured for about 60 seconds following a 10-second warm-up:

Measurement Result
Mean CPU usage 0.869%
Peak memory footprint 5.91 MiB
Disk reads and writes 0 B
App bundle size 1.80 MiB

These figures cover the collection process. They exclude AI inference, GUI rendering, and the external model's resource use. The app bundle size also excludes LM Studio and Gemma's model files.

CPU, memory, and I/O were within their limits, but the overall performance gate still failed: the app bundle exceeded the existing comparison limit by about 203 KiB. I have kept that limit unchanged and left the size increase as a decision to resolve.

All 203 Swift tests passed. Waiting time and the readability of the answer still needed testing with the real model and interface.

Check the explanation as well as the connection

Once the full answer appeared, there were still wording problems to examine.

Gemma described CPU and GPU readings in language that suggested a continuing trend, and called the available disk space “sufficient.” A short observation summary cannot establish every trend, and the amount of disk space someone needs depends on their work. Ordinary free space also needs to stay distinct from space that includes reclaimable storage.

I want the wording to stay close to what the data supports: the value at the captured time, or the amount of available space including reclaimable storage. Improving that precision is still work ahead.

Why Does Open Innovation Matter

For local inference, I used LM Studio's OpenAI-compatible chat completions API. The model I actually ran was google/gemma-4-e2b.

With the model prepared and LM Studio running on the same Mac, MenuPulse can request an explanation without sending the metrics to a cloud inference service. For a tool used on a work computer, being able to choose where those measurements go matters.

The model is not bundled into MenuPulse. Users prepare a compatible model and select it themselves. Gemma's open weights make this local path possible, while the API connection lets the application work with compatible models separately from its own release cycle.

Local inference still has costs. It takes setup, uses memory, and can make you wait. The connection test took about 56 seconds.

I also added a ChatGPT option. In that mode, the user signs in and authorizes the connection, and the aggregate metrics are sent to OpenAI. It uses the official Sign in with ChatGPT route for open-source and local applications. Using that route in a paid application would require a separate review of the offering's access conditions.

For someone working on a Mac, I think the useful outcome is being able to choose the next check more easily. My next step is to have other people try it: did the explanation help them decide what to inspect, and were the setup and waiting time acceptable?

Prize Categories

Best Use of Gemma — I ran google/gemma-4-e2b locally through LM Studio to explain captured Mac system metrics.

Top comments (0)