From 21193057900b26cac0a635d68947c4dc42e8020b Mon Sep 17 00:00:00 2001 From: "b.nishit420@gmail.com" Date: Sat, 17 Oct 2026 11:46:49 +0530 Subject: [PATCH 1/3] Prepare Machogs 1.4.3 with native app and website analytics --- README.md | 2 +- app/Info.plist | 4 ++-- app/build.sh | 5 +++-- docs/analytics-config.js | 8 ++++---- docs/analytics.js | 21 +++++++++------------ docs/analytics.md | 20 +++++--------------- docs/llms.txt | 2 +- docs/privacy.html | 2 +- 8 files changed, 26 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 235fae1..9a5cc7d 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ command arguments, scan contents, messages or cleanup receipts. |---|---|---| | App: Settings → Privacy → Share feature usage | App opens, onboarding, bounded feature scan counts and manual action outcomes, version and random install ID | Self-hosted Native Analytics | | CLI: explicitly set `MACHOGS_ANALYTICS=1` | Command category and success/failure, random install ID | Self-hosted Native Analytics | -| Website: allow on the privacy page | Landing-page visits and download clicks, unrelated ID per page load | PostHog | +| Website: allow on the privacy page | Landing-page visits and download clicks, unrelated ID per page load | Self-hosted Native Analytics | The native receiver stores the connection IP; native events expire after 90 days. App sharing requires a fresh choice when upgrading from the older basic usage diff --git a/app/Info.plist b/app/Info.plist index 24c892e..a6dd285 100644 --- a/app/Info.plist +++ b/app/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.2 + 1.4.3 CFBundleURLTypes @@ -28,7 +28,7 @@ CFBundleVersion - 14 + 15 LSMinimumSystemVersion 13.0 LSUIElement diff --git a/app/build.sh b/app/build.sh index 350ea3f..6255c26 100755 --- a/app/build.sh +++ b/app/build.sh @@ -42,8 +42,9 @@ esac BINARIES=() for arch in $ARCHS; do - swift build -c release --arch "$arch" - bin_dir=$(swift build -c release --arch "$arch" --show-bin-path) + scratch="$ROOT/.build/release-$arch" + swift build -c release --arch "$arch" --scratch-path "$scratch" + bin_dir=$(swift build -c release --arch "$arch" --scratch-path "$scratch" --show-bin-path) BINARIES+=("$bin_dir/MachogsApp") done diff --git a/docs/analytics-config.js b/docs/analytics-config.js index 535cd60..cab1e33 100644 --- a/docs/analytics-config.js +++ b/docs/analytics-config.js @@ -1,6 +1,6 @@ -// Public capture token only. Never put a personal/admin API key here. +// Public fixed-schema relay only. Never embed a producer or owner key here. window.machogsAnalyticsConfig = Object.freeze({ - token: 'phc_NKeUtSphlVzbxyDgYR58znBU0M0gAv6yjldCx65AOg4', - host: 'https://us.i.posthog.com', - version: '1.4.2' + host: 'https://native-analytics-production.up.railway.app', + project: 'machogs', + version: '1.4.3' }); diff --git a/docs/analytics.js b/docs/analytics.js index 403433c..01d487e 100644 --- a/docs/analytics.js +++ b/docs/analytics.js @@ -4,8 +4,8 @@ const config = window.machogsAnalyticsConfig; const test = new URLSearchParams(location.search).get('analytics_test') === '1'; const production = location.hostname === 'bnishit.github.io' && location.pathname.startsWith('/machogs/'); - const available = config?.token && ['https://us.i.posthog.com', 'https://eu.i.posthog.com'].includes(config.host) && (production || test); - const key = test ? 'machogs.analytics.test.choice' : 'machogs.analytics.choice'; + const available = config?.project === 'machogs' && config.host === 'https://native-analytics-production.up.railway.app' && (production || test); + const key = test ? 'machogs.native.analytics.test.choice' : 'machogs.native.analytics.choice'; const blocked = navigator.globalPrivacyControl === true || navigator.doNotTrack === '1'; let choice; try { choice = localStorage.getItem(key); } catch { /* Choice lasts for this page only. */ } @@ -17,18 +17,15 @@ if (!available || blocked || choice !== 'yes' || (!test && navigator.webdriver)) return; if (placement !== undefined && !['nav', 'hero', 'install'].includes(placement)) return; if (!crypto.randomUUID) return; - pageID ||= 'web_' + crypto.randomUUID(); + pageID ||= crypto.randomUUID(); const controller = new AbortController(); pending.add(controller); const payload = { - api_key: config.token, event, distinct_id: pageID, uuid: crypto.randomUUID(), - properties: { - product: 'machogs', platform: 'web', environment: test ? 'test' : 'production', - app_version: config.version, ...(placement ? {placement} : {}), - $process_person_profile: false, $geoip_disable: true, $ip: '0.0.0.0' - } + id: crypto.randomUUID(), install_id: pageID, consent: true, + event, feature: 'web', outcome: 'success', version: config.version, + ...(placement ? { placement } : {}) }; - fetch(config.host + '/i/v0/e/', { + fetch(config.host + '/v1/relay/' + config.project, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload), credentials: 'omit', referrerPolicy: 'no-referrer', keepalive: true, signal: controller.signal @@ -38,7 +35,7 @@ function visit() { if (landing && choice === 'yes' && !visited && document.visibilityState === 'visible') { visited = true; - capture('machogs_website_visit'); + capture('web.page_view'); } } @@ -69,7 +66,7 @@ }); }); document.querySelectorAll('a[data-download-placement]').forEach(link => { - link.addEventListener('click', () => capture('machogs_download_clicked', link.dataset.downloadPlacement)); + link.addEventListener('click', () => capture('web.download_clicked', link.dataset.downloadPlacement)); }); // Consent withdrawn in another tab applies here too. window.addEventListener('storage', event => { diff --git a/docs/analytics.md b/docs/analytics.md index 0e00cbb..0d89237 100644 --- a/docs/analytics.md +++ b/docs/analytics.md @@ -37,18 +37,8 @@ old-consent isolation, dev silence, payload limits, throttling, opt-out cancella and identity reset. A real launched-app check and signed/notarized release remain separate gates before public distribution. -## Website and previously released app - -Website collection remains separately optional in docs/analytics.js and -analytics-config.js, using shared PostHog project 39922. Do not change its global -settings. Events machogs_website_visit and machogs_download_clicked use unrelated -random IDs per page load. Person processing and GeoIP enrichment are disabled; -the payload uses the fixed IP placeholder 0.0.0.0. The network provider still sees -the connection IP. Honor Do Not Track and Global Privacy Control. - -Released app versions using the prior basic-usage implementation send -machogs_app_first_seen and machogs_app_active_week after consent, once per UTC ISO -week for foreground use. Those versions remain unchanged by this branch. -Dashboard: https://us.posthog.com/project/39922/dashboard/2116324. -Filter older data by product=machogs and environment=production; QA is test. -Download clicks and GitHub asset downloads do not prove installed active users. +## Website and previously released apps + +The website uses the same fixed-schema Native Analytics relay after a fresh, separate consent choice. It sends `web.page_view` and `web.download_clicked`, version, feature=web, optional nav/hero/install placement, and an unrelated UUID per page load. It stores no persistent visitor ID and never joins website activity with app IDs. The receiver retains the connection IP for 90 days. Global Privacy Control and Do Not Track disable collection; choosing no cancels pending sends. Only the exact GitHub Pages HTTPS origin is allowed by the relay's browser policy. No collector key is in browser code. + +Older released app versions can still send their previous first-use/weekly-use PostHog events until updated. No historical provider data is copied or deleted. Download clicks and GitHub asset downloads do not prove installed active users. diff --git a/docs/llms.txt b/docs/llms.txt index 0b6fa59..04c4f0f 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -126,7 +126,7 @@ actions use stable process identities and an execution-time recheck; stale targets never expand to other findings. The app targets macOS 13 or later and does not require an admin password, Full Disk Access, or Accessibility access. Optional usage analytics are off until the user opts in. They record -first opted-in use and weekly foreground use in released builds, never scan contents or file paths. The pending native-analytics update instead needs a fresh choice for feature counts and action outcomes; the self-hosted receiver stores connection IPs for 90 days. +first opted-in use and weekly foreground use in released builds, never scan contents or file paths. The native-analytics update needs a fresh choice for feature counts and action outcomes; the self-hosted receiver stores connection IPs for 90 days. See https://bnishit.github.io/machogs/privacy.html. Automatic cleanup is off by default. With explicit user opt-in, the native app diff --git a/docs/privacy.html b/docs/privacy.html index 957d396..e54c880 100644 --- a/docs/privacy.html +++ b/docs/privacy.html @@ -5,7 +5,7 @@ ← Back to Machogs

Your Mac.
Your choice.

Machogs checks your Mac locally. Optional analytics help us understand whether people find the app and keep using it. You can say no and use every feature.

Website analytics

Website analytics are off until you allow them.

What the website shares

Only after you allow analytics: a landing-page visit, a click on a Mac download button, the button’s position, the advertised app version, and an event time and random identifier. A new identifier is made for each page load. We do not join it to your app activity.

There are no analytics cookies, persistent visitor identifiers, session recordings, or automatic capture of what you type. Your choice is stored in this browser’s local storage. We honor Global Privacy Control and Do Not Track. Query strings, referral URLs, and browsing history are not sent in our events.

-

What the updated app shares

The next app build replaces basic usage tracking with “Share feature usage”, off by default, in Settings → Privacy. It requires a fresh choice even if you allowed the older analytics. If enabled, it sends app opens, onboarding completion, feature scan counts and manual action outcomes, app version and a random installation ID. Scan events can include background checks; they do not measure active people.

No process names, paths, command arguments, scan contents, messages or cleanup receipts are sent. Turning sharing off cancels pending sends and resets the local identifier. It does not erase events already received. Existing released apps retain their earlier first-use and weekly-use measurement until you install an updated build.

CLI sharing

The CLI sends nothing unless you explicitly set MACHOGS_ANALYTICS=1. It then sends the command category and success/failure with a random installation ID. Unset that variable to stop sharing. The app's bundled engine does not send separate CLI events.

Where the data goes

The updated app and CLI use self-hosted Native Analytics. The receiver stores the connection IP and keeps events for 90 days. No producer secret is embedded. Sending is best-effort; offline events are not replayed. The website keeps its separate PostHog choice and per-page IDs. Previously released apps also use PostHog. App and website IDs are not joined.

The site and downloads are hosted by GitHub. The landing page also requests fonts from Google Fonts. Those services handle ordinary web requests under their own privacy policies, independently of the optional analytics choice.

+

What the updated app shares

The updated app replaces basic usage tracking with “Share feature usage”, off by default, in Settings → Privacy. It requires a fresh choice even if you allowed the older analytics. If enabled, it sends app opens, onboarding completion, feature scan counts and manual action outcomes, app version and a random installation ID. Scan events can include background checks; they do not measure active people.

No process names, paths, command arguments, scan contents, messages or cleanup receipts are sent. Turning sharing off cancels pending sends and resets the local identifier. It does not erase events already received. Existing released apps retain their earlier first-use and weekly-use measurement until you install an updated build.

CLI sharing

The CLI sends nothing unless you explicitly set MACHOGS_ANALYTICS=1. It then sends the command category and success/failure with a random installation ID. Unset that variable to stop sharing. The app's bundled engine does not send separate CLI events.

Where the data goes

The updated app and CLI use self-hosted Native Analytics. The receiver stores the connection IP and keeps events for 90 days. No producer secret is embedded. Sending is best-effort; offline events are not replayed. The website uses the same self-hosted receiver after a fresh opt-in choice, with a separate per-page ID. Its connection IP is retained for 90 days. Older released apps may still use PostHog until updated. App and website IDs are not joined.

The site and downloads are hosted by GitHub. The landing page also requests fonts from Google Fonts. Those services handle ordinary web requests under their own privacy policies, independently of the optional analytics choice.

What the numbers mean

These are counts of people who choose to share, not a count of every install. Downloads can include repeats and testing. An existing user opting in is separate from a new setup. Clearing preferences or opting out and back in can create a new installation identifier. Website and app identities are kept separate, so we cannot attribute an app install to a particular visitor or ad.

Questions

Contact the maintainer through the Machogs repository. Do not post private scan details in a public issue.

Updated 20 September 2026.

From ee59ea7c950b1b4f84eb74e6c186bd7bdf29238a Mon Sep 17 00:00:00 2001 From: "b.nishit420@gmail.com" Date: Sat, 17 Oct 2026 11:49:57 +0530 Subject: [PATCH 2/3] Point release pages to the verified 1.4.3 artifact --- README.md | 6 +++--- docs/index.html | 10 +++++----- docs/llms.txt | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9a5cc7d..602bf4c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Finds the hog. Names the app. Leaves live sessions alone.** -**[Download the Mac app](https://github.com/bnishit/machogs/releases/download/v1.4.2/Machogs-1.4.2.dmg)** · **[Website](https://bnishit.github.io/machogs/)** · free · macOS 13+ · Apple silicon + Intel +**[Download the Mac app](https://github.com/bnishit/machogs/releases/download/v1.4.3/Machogs-1.4.3.dmg)** · **[Website](https://bnishit.github.io/machogs/)** · free · macOS 13+ · Apple silicon + Intel ## The Mac app @@ -14,7 +14,7 @@ is opt-in and limited to disconnected abandoned helpers. **New in 1.4:** optional usage sharing, off by default. Say “No thanks” and use every feature, or change your choice later in **Settings → Privacy**. -[Release notes](https://github.com/bnishit/machogs/releases/tag/v1.4.2) · +[Release notes](https://github.com/bnishit/machogs/releases/tag/v1.4.3) · [Privacy details](https://bnishit.github.io/machogs/privacy.html) The app needs macOS 13 or later. No admin password, Full Disk Access, or @@ -189,7 +189,7 @@ belonging to a live Claude Code session — it tells you to quit it there. ## Install the Mac app -[Download Machogs 1.4.2](https://github.com/bnishit/machogs/releases/download/v1.4.2/Machogs-1.4.2.dmg), open the DMG, and drag Machogs to Applications. +[Download Machogs 1.4.3](https://github.com/bnishit/machogs/releases/download/v1.4.3/Machogs-1.4.3.dmg), open the DMG, and drag Machogs to Applications. The app is signed with Developer ID, notarized by Apple, and includes both Apple silicon and Intel code. The first scan only looks. To uninstall: turn off diff --git a/docs/index.html b/docs/index.html index 7dca36d..28e113b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -8,7 +8,7 @@ - + - +
-
Meet Machogs 1.4.2

Find the hog.
Keep your flow.

A little pig with a nose for background work. Find what’s making your Mac slow, hot, or loud — and decide what goes.

Download for Mac

Free & open source · macOS 13+
Apple silicon + Intel · Signed & notarized

A little pink ceramic pig, ready to sniff out resource hogs
Small pig. Serious detective.
First scan only looksYou choose what closesLive coding sessions protected
+
Meet Machogs 1.4.3

Find the hog.
Keep your flow.

A little pig with a nose for background work. Find what’s making your Mac slow, hot, or loud — and decide what goes.

Download for Mac

Free & open source · macOS 13+
Apple silicon + Intel · Signed & notarized

A little pink ceramic pig, ready to sniff out resource hogs
Small pig. Serious detective.
First scan only looksYou choose what closesLive coding sessions protected
Less detective work. More doing.

One clear next step.

See what needs your attention, what was left alone, and when your Mac was last checked.

Machogs 1.3.0 running on a Mac: memory needs attention, zero items to review, and 44 protected items left alone
THE REAL APP · VERSION 1.3.0 · Captured on a working Mac.Your findings will depend on your Mac.
Your work stays yours

Curious by default.
Careful by design.

A finding is a reason to take a look. You get the context before you make the call.

01 /

Find what got left behind.

Stuck background jobs. Stranded browsers. Helpers still running after their app is gone. Machogs checks who owns them and what they’re doing.

02 /

Get the story.

See which app left it, how long it has been there, and what it has cost. Plain words make the next step easier to judge.

03 /

Review. Then decide.

Automatic cleanup is off by default. Turn it on in Settings to close only confirmed abandoned, disconnected helpers after five minutes. Live Codex and Claude Code sessions stay protected.

Sometimes, the answer is a restart.When memory pressure calls for it, Machogs says so. A cleanup isn’t a cure for everything.
A few more things to sniff out

Meet the usual suspects.

01 · Storage

Where did the space go?

See common caches and storage hotspots. Rebuildable caches are separate from your own files, with a review before clearing.

02 · Ports

Who’s on port 3000?

Find the app holding a port. Protected work and managed services are called out, so you know what can stay and what needs a different fix.

03 · Receipts

What actually changed?

Look back at what was closed and which apps keep leaving work behind. A record of the cleanup, with the cost in plain sight.

-

Put a pig
on the case.

Download. Drag to Applications. Check your Mac.
No account. No subscription.

Get Machogs — it’s free

Version 1.4.2 · macOS 13 or later

Prefer the terminal?
brew install bnishit/tap/machogs

Then run machogs for a read-only check.
Other ways to install ↗

-

Good questions.

Does it close or delete anything on its own?

By default, no. You can enable automatic cleanup in Settings for confirmed abandoned automation helpers. They must remain disconnected and idle for five minutes, with no live parent, child processes, terminal, or open work connections. Machogs checks again before a normal quit request and never force-kills them. Other cleanup stays under your control; personal files are never automatically deleted.

What about my live coding sessions?

Machogs protects running Codex and Claude Code sessions, macOS system processes, and known productive work. The command-line safety check, machogs --check, lists protections without closing anything.

Will it work on my Mac?

The app supports macOS 13 Ventura or later, on Apple silicon and Intel. Version 1.4.2 is Developer ID signed and Apple-notarized. Open the download and drag Machogs to Applications.

Does it need special permissions?

No admin password, Full Disk Access, or Accessibility access is required. Notifications and Start at Login are optional.

Really free?

Yes. Both the Mac app and the command-line tool are free and open source under the MIT license. Read the code on GitHub.

+

Put a pig
on the case.

Download. Drag to Applications. Check your Mac.
No account. No subscription.

Get Machogs — it’s free

Version 1.4.3 · macOS 13 or later

Prefer the terminal?
brew install bnishit/tap/machogs

Then run machogs for a read-only check.
Other ways to install ↗

+

Good questions.

Does it close or delete anything on its own?

By default, no. You can enable automatic cleanup in Settings for confirmed abandoned automation helpers. They must remain disconnected and idle for five minutes, with no live parent, child processes, terminal, or open work connections. Machogs checks again before a normal quit request and never force-kills them. Other cleanup stays under your control; personal files are never automatically deleted.

What about my live coding sessions?

Machogs protects running Codex and Claude Code sessions, macOS system processes, and known productive work. The command-line safety check, machogs --check, lists protections without closing anything.

Will it work on my Mac?

The app supports macOS 13 Ventura or later, on Apple silicon and Intel. Version 1.4.3 is Developer ID signed and Apple-notarized. Open the download and drag Machogs to Applications.

Does it need special permissions?

No admin password, Full Disk Access, or Accessibility access is required. Notifications and Start at Login are optional.

Really free?

Yes. Both the Mac app and the command-line tool are free and open source under the MIT license. Read the code on GitHub.

diff --git a/docs/llms.txt b/docs/llms.txt index 04c4f0f..99133b7 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -8,9 +8,9 @@ ## Install the native Mac app -Download Machogs 1.4.2: +Download Machogs 1.4.3: - https://github.com/bnishit/machogs/releases/download/v1.4.2/Machogs-1.4.2.dmg + https://github.com/bnishit/machogs/releases/download/v1.4.3/Machogs-1.4.3.dmg Open the DMG and drag Machogs to Applications. The app supports Apple silicon and Intel. Its first scan is read-only. One-tap Close actions re-verify every target @@ -118,7 +118,7 @@ findings are not counted unless `--dupes` is present. Always read `findings`. ## Native app status -Machogs 1.4.2 is the public native app release. Its Developer ID-signed +Machogs 1.4.3 is the public native app release. Its Developer ID-signed universal DMG is linked above. The app has a normal window, menu-bar Hogs, Storage and Ports views, Receipts, and Settings. Verified native behavior: manual process and port actions re-verify targets before acting; From e154a360591ed663dda18a758e8e373f2b9970d6 Mon Sep 17 00:00:00 2001 From: "b.nishit420@gmail.com" Date: Sat, 17 Oct 2026 11:51:06 +0530 Subject: [PATCH 3/3] Verify website consent and privacy signals in release checks --- .github/workflows/mac-checks.yml | 1 + tests/test_website_analytics.mjs | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/test_website_analytics.mjs diff --git a/.github/workflows/mac-checks.yml b/.github/workflows/mac-checks.yml index 1beb915..5bd822d 100644 --- a/.github/workflows/mac-checks.yml +++ b/.github/workflows/mac-checks.yml @@ -15,6 +15,7 @@ jobs: run: | bash -n machogs python3 -m unittest discover -s tests + node --test tests/test_website_analytics.mjs plutil -lint app/PrivacyInfo.xcprivacy - name: Test Mac core run: swift test --package-path app diff --git a/tests/test_website_analytics.mjs b/tests/test_website_analytics.mjs new file mode 100644 index 0000000..6187973 --- /dev/null +++ b/tests/test_website_analytics.mjs @@ -0,0 +1,33 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import vm from 'node:vm'; +import fs from 'node:fs'; +import {randomUUID} from 'node:crypto'; +const source=fs.readFileSync(new URL('../docs/analytics.js',import.meta.url),'utf8'); +function site(blocked=false){ + const requests=[];const controls={}; + const button=choice=>({dataset:{analyticsConsent:choice},addEventListener:(type,fn)=>{controls[choice]=fn;}}); + const yes=button('yes'),no=button('no');const link={dataset:{downloadPlacement:'hero'},addEventListener:(type,fn)=>{controls.download=fn;}}; + const context={window:{machogsAnalyticsConfig:{host:'https://native-analytics-production.up.railway.app',project:'machogs',version:'1.4.3'},addEventListener(){}}, + location:{search:'',hostname:'bnishit.github.io',pathname:'/machogs/'},navigator:{globalPrivacyControl:blocked}, + document:{visibilityState:'visible',addEventListener(){},querySelectorAll(selector){ + if(selector==='[data-analytics-consent]')return [yes,no]; + if(selector==='[data-analytics-consent="yes"]')return [yes]; + if(selector==='a[data-download-placement]')return [link];return []; + }},localStorage:{getItem:()=>null,setItem(){}},crypto:{randomUUID},URLSearchParams,AbortController, + fetch:(url,options)=>{requests.push({url,body:JSON.parse(options.body),options});return Promise.resolve({ok:true});},Set}; + vm.runInNewContext(source,context);return {requests,controls,yes}; +} +test('website needs fresh consent and sends fixed native events without keys',()=>{ + const {requests,controls}=site();assert.equal(requests.length,0); + controls.yes();controls.download();assert.equal(requests.length,2); + assert.equal(requests[0].url,'https://native-analytics-production.up.railway.app/v1/relay/machogs'); + assert.equal(requests[0].body.event,'web.page_view');assert.equal(requests[1].body.event,'web.download_clicked'); + assert.equal(requests[1].body.placement,'hero');assert.equal(requests[0].body.install_id,requests[1].body.install_id); + assert.deepEqual(Object.keys(requests[0].body).sort(),['consent','event','feature','id','install_id','outcome','version']); + assert.equal(requests[0].options.credentials,'omit');assert.equal(requests[0].options.referrerPolicy,'no-referrer'); + controls.no();controls.download();assert.equal(requests.length,2); +}); +test('browser privacy signal always blocks collection',()=>{ + const {requests,controls,yes}=site(true);controls.yes();controls.download();assert.equal(requests.length,0);assert.equal(yes.disabled,true); +});