Modore finds what AI tools and developer workflows left on your device, protects what matters, and safely reclaims the rest.
Today, the Mac app focuses on AI work continuity and storage recovery. The Windows edition provides maintained local PC diagnostics.
| Protect AI work | Understand storage | Reclaim safely |
|---|---|---|
| Find sessions and worktrees at risk, then create verified Claude and Codex backups. | Trace caches, developer runtimes, app residue, and storage drops to their source. | Preview exact targets, remeasure before execution, require approval, and record the result. |
Website · Install · Architecture · Security · Releases
Local by default. Core scans, judgments, backups, and cleanup run on the device. No account or LLM is required, and nothing is deleted automatically. The optional MCP interface exposes selected read-only results to the client that invokes it.
Status: source preview. No public installer is published yet; build the Mac or iPhone app from source, or wait for a signed release.
| Surface | What it provides |
|---|---|
| Mac app | Native SwiftUI views for storage, AI work, system evidence, activity history, settings, and approval-gated recovery. |
| iPhone preview | Shows device capacity, reviews photos and videos after Photo Library permission, and deletes only confirmed selections. Files cleanup is limited to files explicitly chosen through the document picker. Records before/after capacity locally; iOS does not expose other apps' caches or System Data. |
| AI work protection | Joins Claude, Codex, Gemini, and supported IDE sessions to repositories and worktrees; flags retention risk, missing workspaces, and unpushed sole copies. |
| CI incidents | Groups GitHub Actions failures with evidence, links local projects, tracks verified recovery, and optionally notifies on new issues or recovery while the app runs. CI workflow. |
| Verified backups | Creates and verifies original Claude and Codex session archives, then restores them only into a new safe directory. |
| Asset retirement | Select GitHub archive and local repository cleanup independently; preserve ignored data, override risk warnings, retry partial operations, and inspect separate mutation/verification/free-space results. Workflow. |
| Storage recovery | Explains caches, developer runtimes, apps, models, Simulator data, and project residue; safe batches require an exact preview and stop when the free-space goal is met. |
| Local audits | Reviews uninstall residue and trust roots, unused model caches, broken MCP registrations, session file access, and user corrections of AI agents. |
| Read-only MCP | Makes selected judgments available during an agent session without exposing cleanup, deletion, or scan execution. |
| System diagnosis | Connects process, network, autorun, security, and storage evidence with locale-aware explanations and optional hash-only VirusTotal lookup. |
| Windows edition | Maintained PowerShell scanner and offline report for Defender, Sysinternals, startup entries, networking, recent installs, and idle CPU. |
git clone https://github.com/heznpc/Modore.git
cd Modore
./run-mac-app.commandRequires macOS 13 or later and Swift 5.9 or later. Cleanup always shows an exact preview and requires explicit approval.
From a source checkout, you can link that checkout's bin/modore into your
PATH for a narrow terminal or agent entry point. The installed Mac app does
not currently install this command. It owns AI-session continuity and storage
recovery only; it does not route Git, PR, or multi-repository work.
modore sessions current
modore sessions --limit 50
printf '%s' 'exact phrase' | modore search --first
modore storage status
modore cleanup list
modore storage recoverysessions current resolves the calling Codex task from its process context and
validates the matching JSONL metadata. It does not search conversation bodies.
Codex rollout fragments with the same provider session ID are listed as one
logical session while their physical sources remain available for backup and
inspection.
search --first stops at the newest matching turn; ordinary search keeps its
full coverage contract for absence claims.
Currently implemented — turn test resources: opt-in Claude/Codex lifecycle
hooks connect a completed response to simulator runs started by
modore resources begin-test. Modore shuts down only its registered test run,
preserves devices and persistent data, and keeps resources with unresolved
consumers or an explicit preview hold. Hook setup requires host review where
applicable; disabled hooks and unregistered processes are outside this coverage.
This does not pause or terminate AI sessions. See the
command contract.
Clone the repository or download its source archive, then run scan.bat. See Installation for requirements and troubleshooting.
cd ios/Modore
xcodegen generate
open Modore.xcodeprojRequires iOS 17 or later. The generated project is committed, so XcodeGen is needed only after changing project.yml. Storage thresholds and capacity arithmetic come from shared/ModoreDomain, the same Swift package used by the Mac app.
See iPhone cleanup for selection, confirmation, receipt behavior and validation limits.
Technical and CLI reference
Modore connects local Claude Code, Claude Desktop Code, Codex, Gemini, and supported IDE session stores to their workspaces and repositories. It reports retention risk, missing workspaces, and worktrees or checkouts that hold unpushed work. The CLI entry point is:
python3 scripts/scree.py # join · retention forecast · orphans · sole-copy verdicts · lineage
python3 scripts/scree.py preserve <session-file> # masked conversation text, not an original backup
python3 scripts/scree.py bind <workspace> --deep # which AI sessions a delete would strand
python3 scripts/scree.py title <session-file> # one masked line: what that session was about- Cross-tool join — which tools touched which workspace/repository, when, across Claude Code, Claude Desktop Code conversation units, Codex, Gemini CLI, and VS Code-fork stores.
- Retention forecast — per-store rolling windows estimated from file ages, with D-day flags for sessions about to expire inside still-active projects. Deleting a conversation in the Claude desktop app rewrites only that app's index and leaves the transcript on disk, so those sessions are read from the desktop tombstones (filenames only), marked
owner_deleted, and sorted below the rest: a transcript outliving the delete that was meant to remove it is not a reason to urge its rescue. - Sole-copy judgment — agent worktrees and primary checkouts stranded off main: protected (dirty or unpushed commits) versus rebuildable, from read-only git evidence, every verdict preview-grade with an explicit revalidation duty.
- Orphans & lineage — sessions pointing at vanished workspaces (
orphan_basis: path_missing), and every remembered work path classified alive+git / alive+plain / vanished, with macOS case-variant ghosts merged. - Not a uniqueness claim about the primitive — an agent IDE that creates worktrees can and does compute the same unpushed-work verdict for the worktrees it manages (Orca's workspace cleanup runs the same
rev-list --not --remotescheck). scree's coverage is the difference: it sweeps every agent worktree on the machine regardless of which tool created it, plus primary checkouts stranded off main and registry entries whose directory is gone. - Contract — ordinary audits retain only metadata; nested transcripts are attributed by
stat()without being opened. Explicitpreserve,title,titles,inspect,search,evidence, andbind --deepcommands may read content as documented inscree.py. Raw backup operations below are a separate opt-in exception. None of these outputs grants deletion permission, and scans never create backups automatically.
In 작업, select a Claude Code, Claude Desktop Code, or Codex conversation and choose 원본 백업…. The separate 대화 내보내기… action still produces masked Markdown text; it does not preserve structured tool calls or results.
- Scope: one named session from a recognized local store. Claude Code includes its transcript plus existing session-scoped
subagents/,tool-results/,file-history/,image-cache/, anduploads/. Claude Desktop Code includes thelocal_*.jsonmetadata object and its same-stem conversation-unit directory, including transcript, audit, queue, output, subagent, upload, and owned sidecar entries; it never follows selected workspace folders or other external references. Codex contains the selected transcript only. Workspace code, shared project memory, other sessions, and externally referenced files are excluded. - Integrity: a ZIP with a versioned manifest, file sizes, and SHA-256 digests. Creation detects source changes, verifies the archive, and refuses to overwrite a destination. Limits are 10,000 files and 2 GiB of uncompressed data per session.
- Restore: 백업 확인·복원… opens an existing backup even when its original session is gone. All entries are checked before extraction; restore creates a new directory outside the live Claude/Codex session stores and verifies the extracted bytes. Existing directories, provider-store destinations, casing/symlink aliases of those stores, and unsafe archive paths are rejected. Claude Desktop-owned leaf sidecar symlinks are recorded and restored as links without being followed; symlinks are rejected in every other backup scope. Restore does not register or resume the session inside a provider app.
- Privacy: raw backups require acknowledgement. They are not masked or encrypted and can contain secrets already present in transcripts. ZIPs and restored files are owner-only (0600), restored directories 0700. No upload or model call occurs. Keep a separate protected copy off the source disk for disk-failure protection; do not publish raw backups in a public Git repository.
python3 scripts/scree.py backup <session-file> --out <new-backup.zip> --include-sensitive
python3 scripts/scree.py backup-verify <backup.zip>
python3 scripts/scree.py backup-restore <backup.zip> --out <new-directory>Design intent: inspect what matters, preserve original evidence, and test restoration before deciding how to manage local storage. Non-goals: automatic deletion, full machine backup, provider migration, or a guarantee that a provider can resume an archived session. A successful byte comparison is not a cleanup authorization.
The operator-friction audit reads the same session stores for a different question: where did the user stop or correct the agent? Its CLI entry point is:
python3 scripts/friction.py # 9-category pushback taxonomy · severity 1-3
python3 scripts/friction.py scan --json --source codex # structured output, one store- Nine categories — wrong-action, no-research-assertion, stalling-approval, rule-contamination, over-orchestration-token, stale-repetition, verbosity, tone-attitude, other-ai-friction, at severity 1 (mild correction) / 2 (clear irritation) / 3 (rage). Taxonomy and severity ladder are cited from a 2026-07 human audit of 2,630 user turns yielding 515 findings; they are not re-derived here.
- Four stores — Claude Code and Codex are discovered through scree's own collectors; Gemini CLI chats and Claude Desktop local-agent sessions are added on top, joined to a real workspace path where the store records one.
- Same judgment contract — keyword and tone matching only, no model anywhere in the path; a review aid that both under- and over-catches, so every verdict is tagged
evidence: preview. - Content contract — only turns authored by the user are examined; assistant text, tool calls, and nested subagent transcripts are never emitted. Quotes are capped at 200 characters and masked (email / JWT / API keys / private keys / home path) by default, with
--raw-quotesas the explicit opt-out. Nothing is written.
Removing an app does not remove everything it registered. Modore correlates macOS installer receipts with the system and user trust stores; the CLI entry point is:
python3 scripts/moraine.py # receipts · trusted roots · orphaned-root verdict
python3 scripts/moraine.py --json- Receipts — every package ever installed, with whether its payload still exists (
present/partial/vanished/no_payload) and when it was installed. macOS never forgets a receipt, so it outlives the files. - Trusted roots — every root in the admin and user trust domains, with self-signed / CA / key size / validity, and whether its trust is unconditional. An empty usage-constraint array means "trust as root for every policy", which reads like "nothing configured" and is exactly the opposite.
- The correlated verdict — a trusted root whose installing package has no payload left is a certificate still vouching for a vendor otherwise gone from the machine. Neither source produces that alone.
unattributedmeans no receipt claims the root: MDM profiles, enterprise Wi-Fi, and hand-imported roots are legitimately unattributed, so it is a statement about attribution, not legitimacy. - Prior art — AppCleaner is the reference for moraine hunting and its location list is genuinely vetted, but it is target-driven (you drop an app on it) and its binary contains no
SecTrust/SecCertificatesymbols at all; mole readspkgutilreceipts too, but only to locate app bundles in/usr/localand/opt, never to judge whether a payload survived. The trust store is the half neither reaches. - Deletes nothing. Removing a trust root is an admin act and stays a human decision.
The judgments above were terminal-only, which meant the agent doing the work could not ask them while working. Modore ships a zero-dependency MCP server so it can — before deleting a worktree, before assuming a session will still be there tomorrow, before repeating something the operator already objected to:
python3 scripts/mcp_server.py --tools # inspect the surface without speaking JSON-RPC at it{"mcpServers": {"modore": {"command": "python3", "args": ["<repo>/scripts/mcp_server.py"]}}}agent_state_report— the join, retention forecast, orphan/sole-copy/lineage judgment, by section, with every truncation reported.agent_session_list— newest-first local session metadata fromscree sessions; conversation bodies are not opened.agent_session_search— an explicit user-requested phrase search delegated toscree search; the query stays off argv and returned snippets remain masked.operator_friction_report— the pushback taxonomy, filterable by store, category, and minimum severity.model_residue_report— which models in the Hugging Face hub cache no project file names, and how many gigabytes those account for. Reportssearch_complete; when the search could not be exhaustive every model isunknown, neverunreferenced.mcp_hygiene— registered MCP servers that cannot start: dead command, missing script path, duplicate entry, or anenvblock worth a human look (reported as a key count, never as keys or values).agent_file_access— the reverse index: which sessions touched which paths, with reads/writes/shell counts. Agent rule surfaces first, because a silently editedCLAUDE.mdis the case it exists for.system_scan_summary— the storage and security scan result already on disk, with its age in seconds and an explicitstaleverdict by the app's own six-hour rule, because a stale result read as current is the failure mode here.uninstall_residue_report— installer receipts, trusted roots, and the orphaned-root verdict above.- A thin layer, not a second implementation — each tool runs one judgment script with
--jsonand forwards what it prints, so the CLI, the Mac app, and the MCP surface cannot disagree about what is true. - Read-only by contract, enforced at registration — a tool is reachable only if it is on an explicit allowlist and annotated read-only and non-destructive; one added without a deliberate edit fails closed. Cleanup, deletion, and scan execution are deliberately absent. Modore gates destruction on an approval a human grants on screen; an agent-reachable bypass would not be a feature, it would be the end of that guarantee. Every result is fenced as untrusted data.
- This surface can cross the local boundary — read-only is not the same as local-only. The server itself speaks stdio and makes no network request or LLM API call, and no judgment here is produced by a model, exactly as everywhere else in Modore. But a tool result exists to be read by whatever client invoked it: local metadata, directory and process names, and (from
operator_friction_report) masked, length-capped excerpts of turns you wrote become available to that client, and whether they then leave this machine depends on that client's and its model provider's data-handling policy — a wholly local client and model is a different answer than a hosted one. Two claims that sound alike and are not: no model produces Modore's verdicts is true on every surface; nothing Modore reads reaches a model is true of the app and script mode, and is not what connecting this server means. Several tools also read machine-wide session stores rather than only the current project, so register it per-project (--scope localin Claude Code) rather than globally until you want that breadth.
A fan that will not stop, CPU/GPU load while idle, an unknown process, a strange network connection, disk space vanishing overnight. Generic scanners detect but do not explain — and on a Korean banking/government PC they cry wolf over IPinside, nProtect, MagicLine and the rest of the mandated plugin set until users either panic-uninstall critical software or learn to ignore every warning. Modore is the second opinion: it joins process, network, autorun, security, and storage signals, checks miner-like runtime patterns, recognizes the Korean plugin set with a locale-aware whitelist, and explains every finding in plain Korean, English, or Japanese with a 🟢🟡🔴 verdict. Nothing is ever deleted automatically.
This diagnostic surface is maintained, not growing: bug and security fixes continue, but new Modore capability lands on the durable-state side above. Live monitoring that does not contribute to provenance, residue attribution, or a bounded cleanup decision is out of scope.
- Mac Edition Swift app — deepen project-manifest parsing for SDK/runtime version requirements and expand attributable app-residue mappings without weakening the local approval boundary.
- Windows Edition maintenance — Windows remains under the same Modore brand, but new Windows-only storage features wait for real-device validation.
- Additional report locales beyond en/ko/ja — community PRs welcome; the report i18n loader (
data/report_i18n/) already supports arbitrary codes.
Modore is the brand. The OS editions are separate products under that brand, not feature-parity promises.
| Edition | Artifact | Focus | Validation rule |
|---|---|---|---|
| Mac Edition | modore-v0.3.x-mac-source.zip, optional notarized Universal 2 DMG |
The scree AI-agent session/residue audit, plus macOS security context and decoding of the System Data / Developer / macOS storage bar into real paths and safe next actions | Mac-only features ship after local macOS validation |
| iPhone preview | Source project in ios/Modore |
Device capacity, confirmed photo/video and user-picked file deletion, and local cleanup receipts; no cross-app cache inspection | Public iOS APIs only; Simulator tests and real-device validation before distribution |
| Windows Edition | modore-v0.3.x-win.zip |
Korean banking/government security-plugin context, Defender, Sysinternals, autoruns, network, idle CPU monitor | Windows-only features ship only after real Windows-device validation |
Shared rules, whitelist data, i18n strings, and report vocabulary can be reused where they genuinely match. OS-specific collectors stay separate.
The boundary every new capability is judged against:
In scope — durable local state whose creator, owner, workspace, package, or original purpose may no longer be present or obvious, when Modore can establish useful provenance, survival, protection, or reclaimability evidence. Sessions, worktrees, uninstall residue, model and build caches, trust roots, agent environment registrations.
Out of scope — generic live system monitoring or threat detection that does not materially contribute to provenance, residue attribution, recovery, or a bounded cleanup decision. The existing diagnostic surface stays maintained; it does not grow.
"AI-builder Mac" is the audience this is built for, not a filter on what qualifies: an orphaned trust root from a removed banking plugin and an orphaned worktree from a removed agent workspace are the same problem, and both are in.
Windows stays scripts + HTML; Mac uses a native utility interface over the same readable runtime. This is the load-bearing choice:
| Concern | Windows Edition | Mac Edition |
|---|---|---|
| Primary UI | PowerShell launcher + offline HTML | Native SwiftUI app + offline HTML export |
| Runtime truth | Readable PowerShell and JSON rules | Readable Bash/JXA, JSON rules, and Swift source |
| Distribution | Source ZIP | Source ZIP; optional Developer ID/notarized standalone DMG |
| Network default | Local, except opt-in hash lookup/downloads | Local, except opt-in VirusTotal hash lookup |
The Mac app bundles only the allowlisted Bash/JXA/data/rule runtime it needs. A standalone build validates the app's sealed code-signature resources, captures every interpreter input between signature checks, and executes those bytes through anonymous file descriptors. Owner-controlled Application Support is used only for the non-executable runtime mirror, migration state, local configuration, and a separate results/ directory; app updates do not replace scan results or reports. It never executes the replaceable Application Support mirror and never depends on the developer's checkout path. User settings stay at ~/Library/Application Support/Modore/config.json; the tracked data/config.example.json contains no key.
Deterministic, metadata-only judgment is the product. Every verdict — the traffic-light scan result and the scree session/residue judgment alike — comes from declarative rules and read-only metadata, never from a generative model. The same input always produces the same output, the full judgment path is readable source, and adversarial data (a process name, a session file) cannot talk a probabilistic judge into a false verdict.
Cleanup is local and approval-gated. Modore remains the pause before deletion, but the Mac Edition can execute audited recipes for rebuildable caches, Claude VM bundles, Xcode DerivedData, stale Chrome clones, and the known INNORIX user module. Installed apps are re-resolved by bundle ID and moved with exactly attributable containers/caches/preferences to a per-run Trash folder; Xcode and app bundles containing developer SDK/toolchain payloads are blocked. Individual Shutdown Simulator devices can be removed by a normalized UUID revalidated through simctl; Booted devices and locally preserved UUIDs are checked again immediately before deletion. Preview produces a short-lived approval manifest binding canonical paths, tree size, process state, and filesystem identity; execution remeasures before and after the same-volume staged move. Normal app termination waits for an approved destructive transaction to reach its receipt boundary instead of abandoning a child process. SDKs, Simulator runtimes, Codex session JSONL, Claude local-agent workspaces, and Codex databases have no cleanup recipe.
The incident comes before cleanup. The Mac home screen is ordered as judgment → observed evidence → likely impact → recovery. A browser or developer-runtime process is never killed merely because it is old or large. A detached, long-running automation tree is labeled as a residue candidate, and the app preserves the local incident summary so a later scan can show what was observed at that time.
Privacy-first VirusTotal use. Hashes only, never file contents. VirusTotal calls live in scripts/vt-lookup.ps1 and scripts/scanner_helper.jxa.js; optional Sysinternals downloads live in scripts/sigcheck-helper.ps1 and scripts/autorunsc-helper.ps1. Grep for Invoke-RestMethod, Invoke-WebRequest, curl, and virustotal.com/api to audit outbound calls.
Mac local-only UX. The SwiftUI Mac frontend shows whether VirusTotal is enabled, labels the normal state as local-only, opens the user-owned Application Support config, and explains Full Disk Access when macOS privacy settings hide Mail, Messages, Safari, or app-container data. Status, storage, security, activity, and settings use native navigation and lists. Cleanup is never automatic: each supported row opens a scrollable preview with remeasured targets, process blockers, and rebuild cost before the user can approve it. The development workspace also reports browser-automation roots with PID, profile, elapsed time, controller clues, and estimated descendant RSS. An isolated browser or disposable temporary Chrome profile can receive an explicitly approved SIGTERM only after the PID, start time, real executable path, and command identity are revalidated; the normal default profile and persistent custom profiles are never eligible, and the app does not escalate to SIGKILL.
Mac storage scan speed. The SwiftUI quick scan caps each expensive du measurement so huge Simulator or SDK directories do not make the app feel stuck. Timed-out rows are shown as "measurement deferred" instead of a fake size. For an exact CLI pass, run PCH_STORAGE_DU_TIMEOUT=0 bash scripts/scanner.sh.
- Not a replacement for antivirus. Keep using Windows Defender, V3 Lite, Malwarebytes, etc. Recommended workflow:
- Windows Defender (or V3 Lite / Alyac) for real-time baseline protection.
- Malwarebytes Free or Emsisoft Emergency Kit for deep scans when suspicious.
- This tool to understand what's actually running and whether your banking plugins are normal.
- Not a cryptominer remover. It detects patterns and alerts you; removal is left to the user's AV.
- Not real-time protection. It's an on-demand scan that produces an HTML report.
- Not a Korean-only tool. English is the source language and the AI-agent session audit is locale-agnostic; the banking/government plugin whitelist is a Korean-specialized data layer, not the whole product.
- Specific external persons who contributed feedback or testing context are intentionally not named in this README.
- Any user-PC scan artifacts (
scan_result.json,monitor_result.json,raw_facts.json,검사결과*.html,vt-cache.json) are gitignored — they contain PC-identifying data and must not be committed.
- No public DMG is currently published. Clone the source, then right-click
run-mac-app.command→ Open. It builds and opensbuild/macos/Modore.app. - When a release includes a notarized Universal 2 DMG, verify its SHA-256 metadata, open it, and drag Modore to Applications. No Swift toolchain is required for that artifact.
- For script-only mode, right-click
scan.command→ Open. - Follow the menu or the SwiftUI app controls. Cleanup always requires an item preview and a second explicit approval.
- While the repository is in source-preview status, clone it or use GitHub's source archive.
- Once a verified release exists, prefer its
modore-v*-win.zipand compare the published SHA-256 metadata. - Extract anywhere (USB, Desktop, Downloads — no installer needed), then double-click
scan.bat.
- macOS script mode: Bash +
osascript(built into macOS). - macOS SwiftUI source mode: macOS 13 or later plus Swift tools 5.9 or later from the system-selected, root-owned Xcode under
/Applicationsor Command Line Tools under/Library/Developer/CommandLineTools. The explicitly nonpublishable local/CI packaging check may also use an ephemeral current-user-owned Xcode when it is not group/world writable; public distribution never receives that exception. A notarized DMG does not require the toolchain. - Source-checkout
bin/modorecommand: Python 3.9+ available as/usr/bin/python3. The installed Mac app does not require or install this command. - Windows: PowerShell 5.1+ (built into Windows 10/11).
- Development / tests only: Python 3.11+ for pytest, release-smoke packaging, and local docs preview.
- The precise Windows scan needs 5 quiet minutes. It includes an idle-CPU observation window; close video/game workloads and let the machine sit idle so it can catch "using CPU while doing nothing" processes.
- "This script cannot be run on this system" (Windows). Open PowerShell as the current user and run
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned. - A console window flashes and closes immediately (
scan.bat). Right-click → "Run as administrator". - macOS "developer cannot be verified" warning. Right-click the file → Open (only needed once).
- Fully portable. Copy the whole
modore/folder to a USB drive and run it from any Windows or Mac machine — no installer. - Not an antivirus replacement. Pair Windows Defender / macOS Gatekeeper (built in) with Malwarebytes Free for a second opinion when something looks wrong.
-
Sign up at virustotal.com — free.
-
Profile icon → API Key → copy.
-
Either:
Option A — environment variable (recommended for shared / CI / multi-user PCs):
# macOS / Linux export VT_API_KEY="your_key_here" # Windows PowerShell (current session) $env:VT_API_KEY = "your_key_here" # Windows PowerShell (persistent, current user) [System.Environment]::SetEnvironmentVariable('VT_API_KEY', 'your_key_here', 'User')
VT_API_KEYsupplies the secret without writing it into the project, but network lookup still requiresvirustotal.enabledto betruein the local user config. The macOS/Linuxexportand current-session PowerShell forms are process-session values and are not written by Modore. The persistent Windows form is stored in the current user's registry hive on disk; use it only on a trusted single-user account and remove it when no longer needed.Option B — ignored user config: the SwiftUI Mac app, including builds opened through
run-mac-app.command, uses~/Library/Application Support/Modore/config.json. Script-only source/archive mode may copydata/config.example.jsonto the ignoreddata/config.json. Windows can also use%LOCALAPPDATA%\Modore\config.json."virustotal": { "enabled": true, "apiKey": "YOUR_KEY_HERE" }
Lock the file so other users can't read it:
# macOS / Linux chmod 600 data/config.json chmod 600 "$HOME/Library/Application Support/Modore/config.json" # Windows (PowerShell, owner-only ACL) icacls data\config.json /inheritance:r /grant:r "$env:USERNAME:F" icacls "$env:LOCALAPPDATA\Modore\config.json" /inheritance:r /grant:r "$env:USERNAME:F"
-
Run the scan. File hashes will be cross-checked against 70+ antivirus engines.
Privacy note. Only the SHA-256 hash is sent. VirusTotal never receives file contents. If the hash is unknown, the tool reports "unknown" — it does not upload the file.
modore/
├── scan.bat Windows launcher (double-click)
├── scan.command macOS launcher (double-click)
├── run-mac-app.command macOS SwiftUI app builder/launcher
├── README.md This file
├── docs/
│ ├── index.html GitHub Pages landing (static, English)
│ └── style.css
├── data/
│ ├── whitelist.json Korean programs + miner blacklist DB
│ ├── explain.json Plain-language explanations per check
│ ├── config.example.json tracked safe defaults; copy to ignored config.json locally
│ └── report_i18n/ en / ko / ja Python development report strings
├── rules/ Declarative rule JSON
│ ├── autoruns.json
│ ├── defender.json
│ ├── installs.json
│ ├── network.json
│ └── process.json
├── scripts/
│ ├── scree.py AI-agent session & residue audit (metadata-only)
│ ├── friction.py operator-pushback scan over the same session stores
│ ├── moraine.py receipts + trust-store audit of what survived an uninstall
│ ├── hfscan.py Hugging Face hub cache: which models nothing here names
│ ├── mcpaudit.py MCP config hygiene: registered servers that cannot start
│ ├── fileaccess.py reverse index: which sessions touched which paths
│ ├── mcp_server.py read-only MCP surface (scree · friction · moraine · hfscan · mcpaudit · fileaccess · scan summary)
│ ├── menu.ps1 Windows interactive menu
│ ├── scanner.ps1 Windows scanner
│ ├── monitor.ps1 Windows 5-min idle monitor
│ ├── idle_cpu.sh Mac idle CPU observer with ancestor attribution
│ ├── report.ps1 Windows HTML generator
│ ├── rule_engine.ps1 Windows rule evaluator
│ ├── vt-lookup.ps1 VirusTotal wrapper
│ ├── sigcheck-helper.ps1 Sysinternals sigcheck wrapper
│ ├── autorunsc-helper.ps1 Sysinternals autorunsc wrapper
│ ├── scanner.sh macOS scanner
│ ├── cleanup.sh allowlisted macOS preview/execute harness
│ ├── storage_watch.sh free-space monitor + bounded drop-time path snapshot
│ ├── schedule.sh local LaunchAgent toggle harness
│ ├── scanner_helper.jxa.js macOS data aggregator + rule evaluator
│ ├── report.jxa.js macOS HTML generator
│ ├── build_macos_swift_app.sh SwiftUI app builder
│ ├── build_macos_icon.sh vector-to-ICNS builder
│ ├── package_macos_release.sh standalone DMG/sign/notarize harness
│ ├── artifact_audit.py secret/PII/symlink release gate
│ └── modules/macos/ macOS scanner sub-modules
├── macos/
│ └── Modore/ SwiftUI app, feature views, models, and Swift tests
└── tests/ pytest service and safety contracts
Run bash scripts/build_macos_swift_app.sh to build the native app with two
compiler jobs. Local builds use an available Developer ID Application identity,
or the explicit PCH_SIGNING_IDENTITY identity. Reusing the identity preserves
macOS privacy grants across updates; changing from an older ad-hoc build can
require granting access once to the newly signed app. For an intentionally
ad-hoc development build, set PCH_SIGNING_IDENTITY=- explicitly.
Deep storage scans are manual by default; enable automatic refresh in Settings if wanted. Live free-space readings continue independently. Recovery previews use two concurrent workers with a 30-second preview budget, retain verified candidates when another candidate fails, and allow retrying excluded candidates. Chrome clone cleanup checks individual clone directories for open files, keeping active or unverified clones while offering unused ones. Displayed clone size is not a promise of reclaimed space because APFS blocks can be shared.
CPU load alerts can be enabled in Modore Settings. While the app is running (including in the background), native process CPU counters are sampled every 10 seconds, supplemented by the system process reader for protected processes such as WindowServer. A minute of sustained high CPU usage or macOS thermal pressure produces a notification with the top three process names, PIDs, and recent CPU percentages. Bursts are ignored and notifications are at least ten minutes apart. The monitor allows system sleep, resets sustained-load evidence after long sampling gaps (including sleep), stores no process history, and stops when Modore quits.
The docs/ folder is the project landing page, designed for GitHub Pages. It is a static, script-free English page: two HTML/CSS files, no client-side i18n runtime.
To serve locally:
cd docs
python3 -m http.server 8000
# open http://localhost:8000python3 -I -B -m pytest tests/ -q
swift test --package-path macos/Modore \
-Xswiftc -warnings-as-errors \
-Xswiftc -strict-concurrency=completeCI runs rule-JSON validation, Python syntax checks, PowerShell parser checks, pytest, strict Swift release build/tests, and a full unsigned Universal 2 standalone DMG build/audit on pushes to main and pull requests targeting main.
Release zips are built from explicit allowlists so scan artifacts and caches cannot be included by accident:
python3 -I -B scripts/release_smoke.py
# writes clearly non-publishable smoke artifacts under dist/local/The smoke checks fail on scan output, a user config.json, cache files, unsafe ZIP paths, symlinks, non-executable macOS launchers, credential-shaped data, email addresses, or real local home paths.
For publication, provide the reviewed SSH signing public key and its expected OpenSSH SHA-256 fingerprint externally. The key must contain only its type and base64 data; the fixed allowed-signers principal is heznpc.
PCH_RELEASE_SIGNER_PUBLIC_KEY='ssh-ed25519 <reviewed-public-key-base64>' \
PCH_RELEASE_SIGNER_SHA256='SHA256:<reviewed-fingerprint>' \
python3 -I -B scripts/release_smoke.py --release --version <version>Publication additionally requires clean HEAD at the exact signed annotated v<version> tag with the pinned signer succeeding before and after the ZIP build, reads every payload byte with Git replace objects disabled from that immutable commit, and is the only mode that writes canonical ZIP names under dist/.
The local builder embeds an explicit allowlist of Bash/JXA/data/rule files in the app. Public DMG creation requires credentials to be supplied from Keychain/environment; the repository never stores them.
scripts/package_macos_release.sh --check
scripts/package_macos_release.sh --local
PCH_CODESIGN_IDENTITY="Developer ID Application: ..." \
PCH_CODESIGN_TEAM_ID="ABCDE12345" \
PCH_CODESIGN_CERT_SHA256="<reviewed-64-hex-leaf-certificate-fingerprint>" \
PCH_NOTARY_PROFILE="modore-notary" \
PCH_RELEASE_SIGNER_PUBLIC_KEY='ssh-ed25519 <reviewed-public-key-base64>' \
PCH_RELEASE_SIGNER_SHA256='SHA256:<reviewed-fingerprint>' \
scripts/package_macos_release.shDistribution mode only runs from a clean v<version> tag at HEAD verified by that pinned SSH signer. It builds from an isolated git archive snapshot with replace objects disabled, produces Universal 2 with a declared macOS 13 minimum, removes build-machine source prefixes and file metadata, audits the app/DMG, pins the Developer ID identity to an externally reviewed Team ID and leaf-certificate SHA-256, enables hardened runtime, signs, submits with notarytool --keychain-profile, staples, and runs Gatekeeper assessment. Only then does it publish the sidecar first and the DMG as the completion marker; metadata contains the commit, tag object ID, tag signer, Developer ID Team/certificate, architectures, minimum OS, trust state, audit state, and SHA-256. --local writes an unmistakably unsigned artifact under dist/local/ and refuses to overwrite any existing artifact.
- Trust is inspectable. Cleanup recipes accept IDs rather than arbitrary paths; contributors can audit every target, process blocker, and outbound network call.
- Local false positives need local knowledge. Whitelist, miner-pool, Korean banking-plugin, app attribution, and translation PRs improve the product without requiring access to anyone's scan history.
- Rules and UX can evolve independently. OS collectors remain separate while shared vocabulary, rules, tests, and explanations can be reviewed in small PRs.
- The project publishes its limits. It is a diagnostic second opinion, not antivirus, real-time protection, or an automatic optimizer.
| Tool | Platform | Target | Strength | vs. This project |
|---|---|---|---|---|
| SpecStory | Win/Mac | AI coding users | Saves and searches AI coding sessions | scree does not archive content; it judges retention risk, orphans, and sole-copy work, metadata-only |
| Agent Sessions | Mac | Claude Code / Codex users | Browses local session logs | scree adds the cross-tool join, expiry forecast, and worktree/checkout/lineage verdicts |
| Malwarebytes Free | Win/Mac | General users | Real detection | This = context. Use both. |
| Windows Defender | Win | Everyone | Real-time protection | Complementary |
| Sysinternals Autoruns | Win | Experts | Exhaustive autoruns | We wrap it and explain in plain language |
| Objective-See tools | Mac | Prosumer+ | Native UX | English only, fragmented across many tools |
| Hoax Eliminator / 구라제거기 | Win | Korean users | Removes unwanted Korean banking/security modules | This explains which entries are normal, noisy, or suspicious before removal |
| AppCleaner | Mac | Mac users | Removes an app and related files | This adds system/developer context and bundle-ID-verified Trash moves; AppCleaner may still discover app-name-based residue that cannot be attributed safely |
| Malware Zero (malzero.xyz) | Win | Korean users | PUP removal | Older UX, no per-finding explanations |
| HijackThis / FRST | Win | Tech-savvy | Log analysis | Not novice-friendly |
The gap this fills: on a Mac, a deterministic, metadata-only answer to "what did my AI agents leave behind?" — plus suspicion-to-evidence triage for "why is my PC this busy?", with plain-language explanations, locale-aware banking-software context, miner/runtime signals, storage context, and privacy-safe VT lookup.
- No telemetry. The tool never sends usage analytics or error reports.
- No file uploads. VirusTotal integration uses SHA-256 hashes only.
- Local cache only. VT response cache lives in
%LOCALAPPDATA%/PC건강검진/(Windows) or~/Library/Caches/PC건강검진/(macOS). - Local cleanup receipts. Mac cleanup receipts stay under
~/Library/Application Support/Modore/cleanup-receipts/; they contain local paths and are never uploaded. - Local maintenance state. Simulator keep UUIDs, bounded scan snapshots, and minute free-space samples stay under
~/Library/Application Support/Modore/with owner-only permissions. They are never uploaded and can contain local paths, so exported support material should not include them. - Auditable. VirusTotal calls are in
scripts/vt-lookup.ps1/scripts/scanner_helper.jxa.js; optional Sysinternals downloads are inscripts/sigcheck-helper.ps1/scripts/autorunsc-helper.ps1. Grep forInvoke-RestMethod,Invoke-WebRequest,curl, andvirustotal.com/api.
Whitelist contributions are especially welcome. See CONTRIBUTING.md for the full guide. Short version — if you recognize a legitimate local app missing from data/whitelist.json, open a PR with:
- Process name (lowercased, without extension)
- Vendor
- Short English/Korean/Japanese description
- Category (system / browser / korean_common / banking_security / dev_tools / hardware / cloud)
Vulnerability reports should go through GitHub's Private Vulnerability Reporting. Do not place vulnerability details in a public issue; see SECURITY.md for the full policy, scope, and response timeline.
This project verifies all Sysinternals binaries via Get-AuthenticodeSignature against a Microsoft signer subject on every invocation — not only at first download — before executing them. The cached .exe under %LOCALAPPDATA% is re-validated each run because that directory is user-writable and the threat model this tool exists in (other user-mode malware may be present) requires treating the cache as untrusted between runs. By default, Sysinternals download prompts for user confirmation; setting sysinternals.autoDownload to true enables quiet download with the same signature gate.
MIT. See LICENSE for details.
This project depends on — but does not redistribute — Microsoft Sysinternals tools (sigcheck.exe, autorunsc.exe). Per the Sysinternals license, those are downloaded from Microsoft's servers on first run with explicit user consent.
- Microsoft Sysinternals (Windows signature + autoruns coverage).
- The Objective-See Foundation (macOS security research informing the macOS scanner design).
- Korean community knowledge from Malware Zero (malzero.xyz) and the 바이러스 제로 시큐리티 community.
Version 0.3 · 2026
The 지금 이 Mac home screen observes disk availability, macOS memory pressure, swap, CPU and thermal pressure every ten seconds while Modore runs. It records up to 40 local incidents, links notifications back to the screen, and compares observations before and after an action. Recovery requires a complete minute below the warning thresholds; restarting or a monitoring gap never implies recovery. Notification permission does not gate observation. Process working directories connect to matching session metadata as candidates, not proof that a session owns a process. Conversation bodies are opened only through explicit session selection or search. The screen also exposes cleanup receipts and copying the current diagnostic context.
Cleanup previews report actual recovery unknown. Summed directory sizes may include shared APFS blocks and never establish goal completion. Candidate review includes remaining eligible recipes rather than stopping when their sizes add up to the requested gain. Execution still stops based on measured filesystem availability. A shortfall is explicitly reported after execution.
Design intent: preserve evidence from detection through action and observed outcome without making the user reconstruct it in a prompt.
Non-goals: automatic process termination, automatic deletion, inference of session ownership from an app name, or guaranteed recovery from directory size.