Safety-first, reproducible macOS setup and lifecycle automation for apps, permissions, preferences, and machine drift.
Current target version: 0.2.0 (shipped)
macomrade is a personal Codex Skill and repository-local Python CLI for making a new Mac ready to use from a reviewable configuration. It keeps reusable policy in Git while protecting secrets, private overlays, and machine-local observations.
- Inventories installed apps and their available installation-source evidence.
- Builds reviewable app plans for portable or expanded Mac storage profiles.
- Defines reusable permission and preference policy without copying protected grants or credentials.
- Detects configuration drift and records machine-local verification evidence.
- Routes scan, plan, apply, verify, drift, diagnostics, and migration workflows through one CLI.
Evaluate the public workflow without Homebrew, an Apple ID, administrator access, protected macOS permissions, or application changes:
git clone https://github.com/xxvk/macomrade.git
cd macomrade
export MACOMRADE_PUBLIC_ONLY=1
export INSTALL_MY_MACOS_APPS_STATE_DIR=/tmp/macomrade-public-quickstart
./bin/macomrade validate
./bin/macomrade scan apps
./bin/macomrade plan apps --profile autoRead the public onboarding guide for prerequisites, output review, limitations, private-overlay setup, and rollback guidance. The plan is advice, not authorization; macomrade never adds an apply flag on the user's behalf.
Current target version: 0.2.0 (shipped). The public source release is
available as the annotated v0.2.0 tag. No GitHub Release, packaged global
CLI, or completed genuine Clean-Mac acceptance run is implied.
VERSION is the version source of truth. The cumulative 0.2.0
shipped capability baseline, committed 0.3.0–0.9.0 scope, and
1.0 native macOS product vision are defined in
references/release-roadmap.md. Product-level
candidates are kept separately in
references/product-ideas.md.
The cumulative current-version behavior boundary is
references/release-acceptance-matrix.json;
validate it locally with python3 scripts/validate_release_contract.py.
The app catalog is only one part of the baseline. Tracked settings/ define
portable public policy. The local Private/ overlay is reserved for
user-approved personal configuration, remains synchronized through iCloud
Drive, and is ignored by Git. Sanitized templates live under
examples/private/. Runtime state now lives in machine-local Application Support storage;
the tracked state/ directory is only a compatibility locator. Privacy
grants, passwords, tokens, private keys, session material, and private document
contents are never copied as configuration; each new Mac must visibly
authorize protected access and then be verified.
See references/configuration-layers.md
for merge precedence, migration rules, and the boundary between local Private
configuration and secrets.
The registered versioned JSON contracts, Draft 2020-12 registry, validation-before-use
boundaries, and non-destructive migration procedure are documented in
references/schema-and-migration.md.
Support diagnostics use an allowlisted, bounded, preview-first ZIP workflow;
see
references/redacted-diagnostic-bundle.md.
Before opening an issue or sharing any artifact, follow the
public support and safety contract.
The stable 0.2.0 repository-local entry point is macomrade:
./bin/macomrade routes
./bin/macomrade scan apps
./bin/macomrade plan apps --profile auto
./bin/macomrade scan storage --mode quick
./bin/macomrade plan storage --target auto
./bin/macomrade verify schemas
./bin/macomrade verify release
./bin/macomrade diagnostics release-manifest
./bin/macomrade diagnostics public-cloneIt routes the supported workflow families—scan, review, plan, apply, verify,
history, drift, diagnostics, and migration—to the existing scripts without duplicating
their behavior. ./bin/macomrade --explain ... prints the exact compatibility
command without executing it. The dispatcher never adds --apply, so the
underlying dry-run, confirmation, verification, and rollback contract remains
authoritative.
The launcher stays repository-local for 0.2.0; no global symlink, Homebrew
formula, npm package, or packaged distribution is implied. See
references/macomrade-cli.md for the complete
route and compatibility contract and
references/cli-identity.json for the
point-in-time name-collision audit.
The shipped 0.2.0 storage implementation is
available through the same launcher. It separates logical, allocated,
estimated, staged, and measured bytes; remembers
reviewed decisions; imports Mole history as evidence only; surfaces bounded
read-only OS/Home/App handoff facts; and requires a frozen plan plus exact
confirmation for every storage mutation. See
references/storage-lifecycle.md.
All supported mutations are registered in
references/mutation-contracts.json and
validated through the shared
mutation transaction contract.
Tracked component guides are protected by the
component documentation state boundary;
detected versions, paths, timestamps, measurements, grants, and completion
results stay in machine-local state.
SKILL.md is the concise execution and safety entry point. Detailed procedures
are split into six directly linked domain references and loaded only when the
current task needs them. python3 scripts/validate_skill_structure.py enforces
the entry-point size limit, required routes, preserved domain sections, and
local-link integrity.
- macOS
- Python 3 (the scripts use the standard library only)
- Homebrew for automatic Homebrew cask/formula installs
- Codex Chrome extension only when managing an official website download in Chrome
This project is licensed under Apache License 2.0. Before contributing or reporting a problem, read the contribution guide, security policy, and code of conduct. Release-facing changes are summarized in the changelog; bundled third-party material and notice requirements are tracked in third-party notices.
The v0.2.0 tag publishes the reviewed source release. It does not imply a
GitHub Release, packaged CLI, notarized application, or broader platform
compatibility than the documented support boundary.
The 0.2.0 source release uses local macOS validation, not GitHub Actions, as its default quality gate:
python3 scripts/icloud_git_guard.py inspect --repo .
python3 scripts/schema_contract.py validate-tracked
python3 scripts/release_check.pyThe release check is hermetic by default and uses fixture responses for
Homebrew, App Store receipts, TCC, defaults, filesystem state, formal JSON
contracts/migrations, and macomrade route validation. Run
python3 scripts/release_check.py --include-live-smoke only when the current
Mac integration check is needed.
tests/smoke.sh validates the catalog and Python scripts, lints LaunchAgent
templates, and exercises read-only or dry-run paths against the current Mac.
It never authorizes an install, changes TCC permissions, or replaces a genuine
clean-Mac acceptance run. The previous automatically triggered
macos-latest workflow was removed because an ephemeral GitHub runner cannot
represent this repository's real application, account, hardware, permission,
Dock, or system-preference state and adds private-repository runner cost
without becoming release evidence.
Do not add a push, pull-request, or scheduled GitHub Actions workflow for this
skill unless the user explicitly changes this policy. See
references/testing-contract.md for the
hermetic/live boundary and required negative contracts.
This repository intentionally remains in iCloud Drive. Before git status,
git diff, git fsck, commit preparation, submodule operations, or other
Git-dependent work, run:
python3 scripts/icloud_git_guard.py inspect --repo .The command understands this skill's submodule .git pointer and stops before
Git opens an evicted object. If materialization is required, use the plan-first
workflow in
references/icloud-git-integrity.md.
Never interpret dataless as deletion or corruption, never repair Git before
materialization, and never relocate the repository as a workaround.
Keyboard settings are managed from the local, Git-ignored
Private/keyboard.yaml. The historical settings/keyboard.yaml path is a
compatibility locator. Start from the public
keyboard overlay example and
device profile example.
The active device-specific profile remains under Private/keyboards/ and is
never required by a public clone.
The current Logitech K240 Japanese-keyboard policy is:
| Key | Action |
|---|---|
| F1 | Open ChatGPT.app |
| F2 | Open Claude.app |
| F3 | Open Perplexity.app |
| F4 | Mission Control |
| F5 | Open YouTube.app (including PlayCover); otherwise Apple Music |
| F6 | Previous Track |
| F7 | Play/Pause |
| F8 | Next Track |
| F9 | Mute |
| F10 | Volume Down |
| F11 | Volume Up |
| F12 | Open macOS Screenshot.app toolbar |
The K240 is identified from the Logitech USB receiver (VID 0x046d,
PID 0xc534) plus physical confirmation of the K240 model and Japanese
layout. The receiver ID alone does not uniquely identify the paired keyboard.
-
Verify the receiver and keyboard layout:
hidutil list defaults read -g AppleSelectedInputSources -
Apply F6–F11 with native
hidutilusage mappings. These mappings are local to the current macOS session and may need to be reapplied after a restart or receiver reconnect. The portable mapping command is:hidutil property --set '{"UserKeyMapping":[ {"HIDKeyboardModifierMappingSrc":30064771135,"HIDKeyboardModifierMappingDst":3221225654}, {"HIDKeyboardModifierMappingSrc":30064771136,"HIDKeyboardModifierMappingDst":3221225677}, {"HIDKeyboardModifierMappingSrc":30064771137,"HIDKeyboardModifierMappingDst":3221225653}, {"HIDKeyboardModifierMappingSrc":30064771138,"HIDKeyboardModifierMappingDst":3221225698}, {"HIDKeyboardModifierMappingSrc":30064771139,"HIDKeyboardModifierMappingDst":3221225706}, {"HIDKeyboardModifierMappingSrc":30064771140,"HIDKeyboardModifierMappingDst":3221225705} ]}' hidutil property --get UserKeyMapping
-
F1–F3, F5, and F12 are handled by the native listener source at
scripts/keyboard-config-logi-k240.swift. It matches the Logitech receiver and the relevant HID usages (usage page 0x07): F10x3a, F20x3b, F30x3c, F50x3e, and F120x45. It opens ChatGPT.app, Claude.app, Perplexity.app, YouTube.app when present (including~/Applications/PlayCover/YouTube.app; otherwise Apple Music), or/System/Applications/Utilities/Screenshot.apprespectively. F4 is configured by the native macOS Mission Control shortcut (symbolic hotkey ID 32), not by Swift. F12 opens full screenshot toolbar, equivalent toCommand-Shift-5; it does not immediately force an area selection. -
Compile and run the listener in the foreground for a first test:
swiftc scripts/keyboard-config-logi-k240.swift -o /tmp/keyboard-config-logi-k240 /tmp/keyboard-config-logi-k240
Press F1 and F2 and confirm that ChatGPT and Claude open. Press F4 and confirm Mission Control opens through the macOS shortcut. Press F12 and confirm that the Screenshot toolbar appears. Press F5 and confirm that YouTube opens when installed, otherwise Apple Music opens. Test left Command twice in a text field to confirm that Dictation starts or stops. Stop the foreground process after testing. The listener writes diagnostics to
~/Library/Logs/install_my_macos_apps/keyboard-config-logi-k240.log. -
If a function key is captured in the log but its action does not appear, verify that the relevant system app exists. For F3, verify that
/Applications/Perplexity.appexists. For F12, verify that/System/Applications/Utilities/Screenshot.appexists and that macOS allows the Screenshot app to use the required Screen Recording capability. If the listener cannot open the receiver, grant the terminal or installed listener Privacy & Security → Input Monitoring permission and retry.
The listener can run automatically after login through the LaunchAgent template
templates/keyboard-config-logi-k240.launchagent.plist.
It is receiver-scoped, not a universal keyboard remapper: another brand or
another receiver will not match the Swift HID filter. The receiver identifier
does not uniquely prove that the paired physical keyboard is K240.
The installed user-level locations are:
Binary: ~/Library/Application Support/install_my_macos_apps/bin/keyboard-config-logi-k240
LaunchAgent: ~/Library/LaunchAgents/com.xvk.install-my-macos-apps.keyboard-config-logi-k240.plist
Logs: ~/Library/Logs/install_my_macos_apps/keyboard-config-logi-k240.log
The ~/Library directory is hidden in Finder. Locate the binary with:
open -R "$HOME/Library/Application Support/install_my_macos_apps/bin/keyboard-config-logi-k240"Input Monitoring is protected by macOS TCC. CLI can open the settings page but
cannot silently grant this permission; tccutil can reset it but cannot
authorize a new executable. Replacing or recompiling the binary may require
authorization again. Every time the binary is replaced, the skill must
automatically locate the new binary and open both Finder and the Input
Monitoring page before asking the user to enable it:
open -R "$HOME/Library/Application Support/install_my_macos_apps/bin/keyboard-config-logi-k240"
open 'x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_ListenEvent'After authorization, reload the agent with:
launchctl bootstrap gui/$(id -u) \
"$HOME/Library/LaunchAgents/com.xvk.install-my-macos-apps.keyboard-config-logi-k240.plist"F4 is intentionally excluded from the listener. Its Mission Control binding
is a native macOS shortcut (symbolic hotkey ID 32). F5 checks standard
/Applications/YouTube.app, then the PlayCover executable
~/Applications/PlayCover/YouTube.app/YouTube, and falls back to
/System/Applications/Music.app. PlayCover's flat bundle must be launched
through its inner executable, not with open -a. If the PlayCover YouTube
process is already running, the listener activates the existing instance
instead of starting another process. When that instance was minimized with the
yellow button, the listener also clears the window's minimized state before
activating it. This restoration uses macOS Accessibility window attributes;
grant the installed listener Accessibility permission if activation works but
the minimized window does not return.
The current PlayCover YouTube profile does not provide reliable login-session persistence: PlayTools must remain removed for startup compatibility, and enabling PlayChain did not preserve the tested YouTube login across a full quit and relaunch. The documented operating rule is therefore to log in again when YouTube is reopened. This is a known compatibility limitation, not an F5 or LaunchAgent failure.
The defaults entries for system shortcut IDs are not the authoritative
implementation for K240. They can be written successfully while having no
effect on an external keyboard, so the HID listener is the supported F1–F3,
F5, and F12 path. F4 is a native macOS shortcut and should not be duplicated
in the listener. Dictation remains a separate system shortcut: verify left
Command twice rather than treating F5 as a Dictation key.
These keyboard settings are machine-local. They are not treated as iCloud
synced configuration. Durable policy belongs in settings/; current device
facts and test logs belong in the resolved machine-local state directory or
the local log directory.
The K240 keyboard and M212 mouse share the Logitech receiver 046d:c534.
macOS's native HID and power commands do not expose their battery values.
Logi Options+ and OpenLogi may not recognize this legacy pairing. Solaar is the
optional next test; its macOS support is limited and its device-reported battery
values must be confirmed from each selected device's details pane. See
components/solaar.md for the GitHub-based installation
flow. Keep current readings in machine-local state, not in this durable README.
To see what macOS starts at login, including apps and helper components:
python3 scripts/macos_startup_items.py scanFor an interactive numbered selection:
python3 scripts/macos_startup_items.py reviewThe review flow asks for an explicit DISABLE confirmation. It only removes
selected user Login Items or disables user LaunchAgents. It preserves the
application and its data; system components and Background Task Management
records are reported for review rather than deleted automatically.
Run every command from this directory. These commands only inspect the Mac and
write records under the directory returned by
python3 scripts/state_paths.py path:
python3 scripts/macos_apps.py scan
python3 scripts/macos_apps.py plan --profile autoTo audit shared application data that may remain after an app is removed, run the read-only Group Container scan:
python3 scripts/scan_group_containers.py
python3 scripts/scan_group_containers.py --jsonThe scan reports container size, the metadata creator, whether a matching app
bundle is currently installed, and likely_orphan. That flag is only a review
signal: shared containers such as Microsoft Office's
UBF8T346G9.Office must not be deleted as a whole. Removal is a separate,
explicit, app-specific operation after reviewing what data is preserved.
To inspect and explicitly remove standalone OpenClaw leftovers:
python3 scripts/openclaw_cleanup.py inspect
python3 scripts/openclaw_cleanup.py remove --confirm "REMOVE OPENCLAW"This targets only ~/.openclaw and the known Kimi Desktop OpenClaw shim. It
preserves Hermes source/test files, Kimi Desktop, and unrelated application data.
The scan also records installation-source evidence. It recognizes an App Store
receipt, a matching installed Homebrew cask, or a system bundle; website/DMG/ZIP
installs are reported as manual_or_unknown. Review source_mismatches in the
plan before reinstalling. For example, Slack and Telegram must have an App Store
receipt; a mismatch only produces a prompt and never deletes the existing app.
Before applying an installation, validate
references/source-policy.md:
python3 scripts/supply_chain.py validate
python3 scripts/supply_chain.py inspectThe installer refuses mutable network-to-shell Homebrew bootstrap, unpinned npm globals, and third-party tap drift. Decrypted IPA sources require separate Private approval and per-file verification.
The 0.1.0 Clean-Mac harness is ready, but its real hardware run remains
blocked_external. Validate the harness on any Mac; initialize a session only
on unused or newly purchased hardware:
python3 scripts/clean_mac_acceptance.py validate
python3 scripts/clean_mac_acceptance.py statusSee
references/clean-mac-release-acceptance.md
for the 13-gate workflow. Previously configured Macs cannot satisfy CM-01.
portable applies below 512 GB; expanded applies at 512 GB or more. Review the generated plan before choosing one or two apps to install.
STATE_DIR="$(python3 scripts/state_paths.py path)"
python3 scripts/macos_apps.py install "$STATE_DIR/PLAN.json" --only "App Name"
python3 scripts/macos_apps.py install "$STATE_DIR/PLAN.json" --only "App Name" --applyThe first command is a dry run. --apply makes external changes and must be used only after explicit review. GUI apps must be opened and checked after installation.
Approved Homebrew CLI recommendations may be installed in batches of up to five. GUI apps and App Store/website installs remain one at a time so each can be opened, authenticated, and verified separately.
Merged catalog entries may include a minimum_version and a
preferred_account from Private/app-catalog-overlay.json. The plan reports
versions below the recorded floor as version_issues; account values are
prompts only and never include passwords, tokens, or recovery codes.
GUI installation and CLI installation are tracked separately. When a GUI app
has a CLI, the skill verifies command -v and the declared version, and only
creates a documented link after explicit confirmation. It never guesses a
symlink from an app bundle.
Every Core component guide keeps only planning estimates and reusable
installation know-how; size_gb in the catalog is only a planning estimate.
Measured download_bytes and installed_bytes belong in machine-local install
records. Run python3 scripts/audit_core_catalog.py and
python3 scripts/audit_component_frontmatter.py to find missing guides,
metadata, or state-boundary violations.
LM Studio Bionic is the desired Core application. Classic LM Studio
is retired because both applications use the same llmster daemon and cannot
run their local backends concurrently. Keep shared ~/.lmstudio model data
until Bionic has been verified; retirement does not imply deleting that data.
For entries with an app_store_url, sign in to the same Apple Account used on
the other Macs, verify that the listing supports macOS, and install from the
App Store or Purchased list. The user must click Get/Download and handle any
password, two-factor authentication, license, or permission prompts. Afterward,
the skill verifies the App Store receipt during the next scan. Apple Configurator
is reserved for iPhone, iPad, and Apple TV preparation; it is not used to deploy
Mac apps. The skill opens the matching App Store page and pauses immediately
before Get/Download/Redownload so the user can confirm the installation action.
Inspect Docker Desktop before removing it:
python3 scripts/docker_desktop_cleanup.py inspectInstall and verify OrbStack as the default local container backend on every developer Mac, including a new Mac with no Docker Desktop. If Docker Desktop is present, only remove it after OrbStack is verified. Removal permanently deletes Docker Desktop-local containers, images, volumes, build cache, Kubernetes data, and settings. It preserves OrbStack and ~/.docker.
python3 scripts/docker_desktop_cleanup.py remove --confirm "REMOVE DOCKER DESKTOP DATA"Runtime records are stored under
~/Library/Application Support/install-macos-apps/state/<hashed-machine-id>/.
Resolve the exact path with python3 scripts/state_paths.py path. The tracked
state/README.md and state/locator.json contain no machine observations.
See
references/machine-local-state.md for
override, migration, verification, and source-cleanup rules.
The expected Chrome Profile mapping belongs in the Git-ignored local
Private/chrome-profiles.json, initialized from the fictional
public Chrome profile example. A new
Mac can compare its local inventory with the user-approved account mapping
without publishing those identifiers. Never add passwords, tokens, recovery
codes, or Passkey data.
The historical config/chrome-profiles.json path is a compatibility locator
and remains accepted by scripts/chrome_profiles.py.
See SKILL.md for the complete Codex workflow and safety rules.