+
+## Overview
+
+Apple apps, from your terminal. `apple` brings Notes, Reminders, Calendar, Mail, Photos and other
+Apple app and system targets to one macOS command, with structured JSON output and an optional MCP
+server for local agents.
-# apple-cli
+- **Script everyday workflows.** Search Notes, organize Reminders, inspect calendars, query
+ Photos and work with local files.
+- **Use predictable output.** JSON results, stable error codes and bounded reads make commands
+ usable in scripts.
+- **Connect your agent.** The MCP server exposes the same CLI capabilities through stdio or
+ Streamable HTTP.
-Apple apps, from your terminal. `apple-cli` brings 19 Apple app and system
-targets to one macOS command, with structured JSON output and an optional MCP
-server for local agents.
+> **Alpha preview · macOS arm64.** Feature availability depends on the target, OS, account and
+> permissions. See the [Release Guide](Documentation/Reference/ReleaseGuide.md) for the tested
+> build environment and installation details.
-[Install](#install) · [Quick start](#quick-start) · [Targets](#targets) ·
-[MCP](#mcp) · [Documentation](#documentation)
+## Quick look
-> **Alpha preview · macOS arm64.** Feature availability depends on the target,
-> OS, account and permissions. See the [Release Guide](Documentation/Reference/ReleaseGuide.md)
-> for the tested build environment and installation details.
+
+
+
+
-- **Script everyday workflows.** Search Notes, organize Reminders, inspect
- calendars, query Photos and work with local files.
-- **Use predictable output.** JSON results, stable error codes and bounded
- reads make commands usable in scripts.
-- **Connect your agent.** The MCP server exposes the same CLI capabilities
- through stdio or Streamable HTTP.
+Every command follows one shape:
~~~text
apple [options]
@@ -29,55 +56,49 @@ apple [options]
## Install
-### Homebrew
+### Build from source
-On macOS arm64, install from the organization tap:
+Use macOS with an Xcode toolchain providing Swift 6.3 or newer and the Notes private frameworks
+required by the package. From the repository root:
~~~bash
-brew install computer-mcp/tap/apple-cli
-apple --version
+scripts/bootstrap
+xcrun swift build --force-resolved-versions
+.build/debug/apple --help
~~~
-The [Homebrew tap](https://github.com/computer-mcp/homebrew-tap) installs both
-executables and their runtime libraries from the accepted GitHub release.
-Its formula declares the tested macOS requirement.
+Rerun `scripts/bootstrap` after changing Xcode or the SDK. The declared macOS 13 deployment floor
+is a build setting; runtime support requires validation on the intended OS and architecture.
-### Release archive
+### Releases
-Download the macOS arm64 archive and its checksum from
-[GitHub Releases](https://github.com/computer-mcp/apple-cli/releases).
-Release archives are built, tested and published by GitHub Actions.
+No release has been published yet. From the first release, two channels install it on macOS
+arm64.
-Run these commands in the download directory, replacing `VERSION` with the
-version you downloaded:
+**Homebrew**, from the organization tap, which installs both executables and their runtime
+libraries from the accepted GitHub release and declares the tested macOS requirement:
~~~bash
-shasum -a 256 -c apple-cli-VERSION-macos-arm64.tar.gz.sha256
-tar -xzf apple-cli-VERSION-macos-arm64.tar.gz
-export PATH="$PWD/apple-cli-VERSION-macos-arm64/bin:$PATH"
+brew install computer-mcp/tap/apple-cli
apple --version
~~~
-Keep the complete `bin` directory together: `apple`, `apple-cli-mcp` and any
-bundled Swift runtime libraries. The [Release Guide](Documentation/Reference/ReleaseGuide.md#install-the-archive)
-covers relocation, signatures and compatibility.
-
-### Build from source
-
-Use macOS with an Xcode toolchain providing Swift 6.3 or newer and the Notes
-private frameworks required by the package. From the repository root:
+**Release archive**, built, tested and published by GitHub Actions on
+[GitHub Releases](https://github.com/computer-mcp/apple-cli/releases). In the download directory,
+replacing `VERSION`:
~~~bash
-Scripts/bootstrap
-xcrun swift build --force-resolved-versions
-.build/debug/apple --help
+shasum -a 256 -c apple-cli-VERSION-macos-arm64.tar.gz.sha256
+tar -xzf apple-cli-VERSION-macos-arm64.tar.gz
+export PATH="$PWD/apple-cli-VERSION-macos-arm64/bin:$PATH"
+apple --version
~~~
-Rerun `Scripts/bootstrap` after changing Xcode or the SDK. The declared
-macOS 13 deployment floor is a build setting; runtime support requires
-validation on the intended OS and architecture.
+Keep the complete `bin` directory together: `apple`, `apple-cli-mcp` and any bundled Swift runtime
+libraries. The [Release Guide](Documentation/Reference/ReleaseGuide.md#install-the-archive) covers
+relocation, signatures and compatibility.
-## Quick start
+## Usage
Discover a target and check its readiness:
@@ -114,31 +135,19 @@ apple reminders create --list Today --title "Follow up" --json
### Structured output
-`--json` returns an envelope with `ok` and `data`. Errors use `ok: false` and a
-stable `error.code`. Add `--pretty` for readable formatting.
+`--json` returns an envelope with `ok` and `data`. Errors use `ok: false` and a stable
+`error.code`. Add `--pretty` for readable formatting. The Quick look's notification preview works
+without accessing app data or sending a notification.
-This preview works without accessing app data or sending a notification:
+### Permissions and writes
-~~~bash
-apple notifications preview --title Build --body Done --json --pretty
-~~~
+Start with `apple doctor --json` when a target cannot access an app or its data. Some
+workflows need macOS permissions or app automation approval.
-~~~json
-{
- "data": {
- "externalAction": false,
- "notification": {
- "body": "Done",
- "title": "Build"
- }
- },
- "meta": {
- "target": "notifications"
- },
- "ok": true,
- "warnings": []
-}
-~~~
+Use `--dry-run` to inspect a proposed mutation. External dispatch, destructive selections and
+system operations require the specific `--allow-*` flag named by the command. `--json` controls
+output; authorization comes from the requested operation and its gates. See
+[Safety Gates](Documentation/Reference/SafetyGates.md) for the full contract.
## Targets
@@ -152,36 +161,32 @@ Choose a target to open its user guide:
| Documents | [`pages`](Documentation/Reference/Pages/UserGuide.md) · [`numbers`](Documentation/Reference/Numbers/UserGuide.md) · [`keynote`](Documentation/Reference/Keynote/UserGuide.md) |
| System utilities | [`print`](Documentation/Reference/Print/UserGuide.md) · [`clipboard`](Documentation/Reference/Clipboard/UserGuide.md) · [`notifications`](Documentation/Reference/Notifications/UserGuide.md) · [`intelligence`](Documentation/Reference/Intelligence/UserGuide.md) · [`tcc`](Documentation/Reference/TCC/UserGuide.md) |
-Coverage varies by target. Pages focuses on metadata and export; Keynote
-supports native slide reads and PDF export alongside cached previews. Numbers
-supports reads, exports and single-cell writes. Safari Tab Group
-mutations and some Notes media workflows return an explicit unsupported result.
-Read the [Capability List](Documentation/Architecture/CapabilityList.md) for
-the supported scope of each target.
+Coverage varies by target. Pages focuses on metadata and export; Keynote supports native slide
+reads and PDF export alongside cached previews. Numbers supports reads, exports and single-cell
+writes. Safari Tab Group mutations and some Notes media workflows return an explicit unsupported
+result. Read the [Capability List](Documentation/Architecture/CapabilityList.md) for the supported
+scope of each target.
## MCP
-`apple-cli-mcp` connects local MCP clients to the `apple` CLI. Configure your
-client with the full path to the installed executable and `stdio` as its
-argument:
+`apple-cli-mcp` connects local MCP clients to the `apple` CLI. Configure your client with the full
+path to the executable and `stdio` as its argument:
| Client setting | Value |
| --- | --- |
| Command | `/path/to/extracted-release/bin/apple-cli-mcp` |
| Arguments | `stdio` |
-For Homebrew, get the full command path with
-`echo "$(brew --prefix)/bin/apple-cli-mcp"`.
-
-To start the server directly:
+For Homebrew, get the full command path with `echo "$(brew --prefix)/bin/apple-cli-mcp"`. To start
+the server directly:
~~~bash
apple-cli-mcp stdio
~~~
-The adapter finds `apple` beside its own executable. Keep both programs and
-the bundled runtime libraries together. For a separate CLI directory, set
-`APPLE_CLI_BIN_DIR` to the directory containing `apple`.
+The adapter finds `apple` beside its own executable. Keep both programs and the bundled runtime
+libraries together. For a separate CLI directory, set `APPLE_CLI_BIN_DIR` to the directory
+containing `apple`.
Streamable HTTP is also available on loopback:
@@ -190,53 +195,46 @@ apple-cli-mcp serve http --host 127.0.0.1 --port 8765 --path /mcp
~~~
The same target permissions and mutation gates apply through MCP. See
-[MCP setup](Documentation/Reference/AppleCLIUserGuide.md#mcp-setup) for discovery,
-remote access and authentication.
-
-The source tree also includes a [Reminder Creator skill](skills/reminder-creator/SKILL.md)
-for modeling reminder content, lists, sections and shopping workflows.
-See its [shopping reference](skills/reminder-creator/references/shopping-list.md)
-for scenario guidance.
-
-## Permissions and writes
-
-Start with `apple doctor --json` when a target cannot access an app
-or its data. Some workflows need macOS permissions or app automation approval.
+[MCP setup](Documentation/Reference/AppleCLIUserGuide.md#mcp-setup) for discovery, remote access and
+authentication.
-Use `--dry-run` to inspect a proposed mutation. External dispatch, destructive
-selections and system operations require the specific `--allow-*` flag named
-by the command. `--json` controls output; authorization comes from the requested
-operation and its gates. See [Safety Gates](Documentation/Reference/SafetyGates.md)
-for the full contract.
+The source tree also includes a [Reminder Creator skill](skills/reminder-creator/SKILL.md) for
+modeling reminder content, lists, sections and shopping workflows. See its
+[shopping reference](skills/reminder-creator/references/shopping-list.md) for scenario guidance.
-## Development
+## Requirements
-~~~bash
-Scripts/bootstrap
-xcrun swift test --force-resolved-versions
-Scripts/validate-public-content
-~~~
-
-The default suite uses fixtures and controlled backends. Real app behavior,
-accounts and OS compatibility need separate validation; the
-[Release Guide](Documentation/Reference/ReleaseGuide.md#build-from-source)
-describes the available integration checks.
+- macOS on arm64, the tested runtime; see the [Release Guide](Documentation/Reference/ReleaseGuide.md).
+- To build: an Xcode toolchain with Swift 6.3 or newer and the Notes private frameworks the
+ package requires.
+- Per target: the macOS permissions or app automation approval its workflows need.
## Documentation
| Start here | What it covers |
| --- | --- |
| [User guide](Documentation/Reference/AppleCLIUserGuide.md) | Discovery, output, permissions, MCP and workflow safety |
-| [Target guides](Documentation/README.md#target-guides) | User and developer documentation for all 19 targets |
+| [Target guides](Documentation/README.md#target-guides) | User and developer documentation for every target |
| [Release guide](Documentation/Reference/ReleaseGuide.md) | Installation, source builds and runtime requirements |
| [Release reference](Documentation/Reference/Release.md) | Version sources, candidate acceptance, CI publication and evidence |
| [Version rules](VERSIONING.md) | Organization version rules and repository acceptance requirements |
| [Architecture](Documentation/Architecture/README.md) | CLI ownership, implementation mechanisms and MCP boundaries |
-| [Contributing](CONTRIBUTING.md) | Repository conventions and validation |
| [Security](SECURITY.md) | Vulnerability reporting |
+## Contributing
+
+~~~bash
+scripts/bootstrap
+xcrun swift test --force-resolved-versions
+scripts/validate-public-content
+~~~
+
+The default suite uses fixtures and controlled backends. Real app behavior, accounts and OS
+compatibility need separate validation; the
+[Release Guide](Documentation/Reference/ReleaseGuide.md#build-from-source) describes the available
+integration checks. See the [contributor guide](CONTRIBUTING.md) for repository conventions.
+
## License
-Copyright (c) 2026 Xudong Xu. Licensed under the [Apache License 2.0](LICENSE).
-Third-party components retain their own licenses; see
-[Third-Party Notices](THIRD_PARTY_NOTICES.md).
+Copyright (c) 2026 Xudong Xu. Licensed under the [Apache License 2.0](LICENSE). Third-party
+components retain their own licenses; see [Third-Party Notices](THIRD_PARTY_NOTICES.md).
diff --git a/Tests/AppleCLITests/FrameworkNormalizationTests.swift b/Tests/AppleCLITests/FrameworkNormalizationTests.swift
index 4f41fd7..5c022c8 100644
--- a/Tests/AppleCLITests/FrameworkNormalizationTests.swift
+++ b/Tests/AppleCLITests/FrameworkNormalizationTests.swift
@@ -450,7 +450,7 @@ struct NormalizationFixture {
.deletingLastPathComponent().deletingLastPathComponent()
return try CLISubprocess.run(
.path("/usr/bin/xcrun"),
- arguments: ["swift", repository.appendingPathComponent("Scripts/\(profile.script)").path,
+ arguments: ["swift", repository.appendingPathComponent("scripts/\(profile.script)").path,
"--sources-root", (sourcesRoot ?? output).path] + (inputManifest.map { ["--input-manifest", $0.path] } ?? ["--dump-root", dump.path]) + extra,
timeoutSeconds: 90)
}
diff --git a/Tests/ReleaseTools/test_archive_documents.py b/Tests/ReleaseTools/test_archive_documents.py
index d65d5c8..22af13e 100644
--- a/Tests/ReleaseTools/test_archive_documents.py
+++ b/Tests/ReleaseTools/test_archive_documents.py
@@ -11,7 +11,7 @@
SOURCE = Path(__file__).resolve().parents[2]
-checker = runpy.run_path(str(SOURCE / "Scripts/verify-release"))
+checker = runpy.run_path(str(SOURCE / "scripts/verify-release"))
VALIDATION_DOCUMENTS = [
"Documentation/Reference/Release.md",
"VERSIONING.md",
diff --git a/Tests/ReleaseTools/test_public_content.py b/Tests/ReleaseTools/test_public_content.py
index 9211102..9e33d2f 100644
--- a/Tests/ReleaseTools/test_public_content.py
+++ b/Tests/ReleaseTools/test_public_content.py
@@ -17,9 +17,9 @@ def setUp(self):
self.root = Path(temporary.name) / "repository"
self.outside = Path(temporary.name) / "artifacts"
self.outside.mkdir()
- script = self.root / "Scripts/validate-public-content"
+ script = self.root / "scripts/validate-public-content"
script.parent.mkdir(parents=True)
- shutil.copy2(SOURCE / "Scripts/validate-public-content", script)
+ shutil.copy2(SOURCE / "scripts/validate-public-content", script)
self.write("README.md", "[Guide](Documentation/Guide.md)\n")
self.write("Documentation/Guide.md", "Run `apple --help`.\n")
subprocess.run(["git", "init", "--quiet"], cwd=self.root, check=True)
@@ -31,7 +31,7 @@ def write(self, name, text):
def scan(self, *arguments):
return subprocess.run(
- ["swift", str(self.root / "Scripts/validate-public-content"), *arguments],
+ ["swift", str(self.root / "scripts/validate-public-content"), *arguments],
cwd=self.root, capture_output=True, text=True, timeout=600,
)
@@ -45,7 +45,7 @@ def test_reports_every_finding(self):
# Assembled at runtime so this file does not match the credential scan.
token = "gh" + "p_" + "A" * 36
self.write("Documentation/Setup.md", "Run from /Users/jane/project.\n\n[Missing](Missing.md)\n")
- self.write("Scripts/configure", "TOKEN=" + token + "\n")
+ self.write("scripts/configure", "TOKEN=" + token + "\n")
self.write("Sources/Version.swift", 'let version = "0.0.0-dev"\n')
artifact = self.outside / "release-notes.txt"
artifact.write_text("Built in /Users/jane/build.\n")
@@ -54,8 +54,8 @@ def test_reports_every_finding(self):
self.assertEqual(result.stderr.splitlines(), [
"Documentation/Setup.md: machine-local absolute path",
"Documentation/Setup.md: missing local link Missing.md",
- "Scripts/configure: credential pattern requires review",
"Sources/Version.swift: development version bypasses the canonical version",
+ "scripts/configure: credential pattern requires review",
"release-notes.txt: release artifact contains a machine-local path",
])
diff --git a/Tests/ReleaseTools/test_publication.py b/Tests/ReleaseTools/test_publication.py
index 4f088d4..10ff151 100644
--- a/Tests/ReleaseTools/test_publication.py
+++ b/Tests/ReleaseTools/test_publication.py
@@ -9,7 +9,7 @@
ROOT = Path(__file__).resolve().parents[2]
-LOADER = importlib.machinery.SourceFileLoader("release_publication", str(ROOT / "Scripts/publish-release"))
+LOADER = importlib.machinery.SourceFileLoader("release_publication", str(ROOT / "scripts/publish-release"))
SPEC = importlib.util.spec_from_loader(LOADER.name, LOADER)
publisher = importlib.util.module_from_spec(SPEC)
LOADER.exec_module(publisher)
diff --git a/Tests/ReleaseTools/test_version_inputs.py b/Tests/ReleaseTools/test_version_inputs.py
index 6ff0031..0c3fcee 100644
--- a/Tests/ReleaseTools/test_version_inputs.py
+++ b/Tests/ReleaseTools/test_version_inputs.py
@@ -10,7 +10,7 @@
SOURCE = Path(__file__).resolve().parents[2]
-checker = runpy.run_path(str(SOURCE / "Scripts/verify-release"))
+checker = runpy.run_path(str(SOURCE / "scripts/verify-release"))
validate = checker["validate_version_inputs"]
@@ -162,7 +162,7 @@ def test_rejects_tag_on_another_commit(self):
def test_cli_returns_metadata_without_modifying_source(self):
before = {path: path.read_bytes() for path in [self.version_file, self.changelog]}
result = subprocess.run(
- [sys.executable, str(SOURCE / "Scripts/validate-version"), "--source", str(self.source), "--json"],
+ [sys.executable, str(SOURCE / "scripts/validate-version"), "--source", str(self.source), "--json"],
check=True, text=True, capture_output=True,
)
self.assertEqual(json.loads(result.stdout), {
@@ -175,7 +175,7 @@ def test_cli_fails_without_repairing_invalid_inputs(self):
self.write_source("0.1.0-alpha.01")
before = self.version_file.read_bytes()
result = subprocess.run(
- [sys.executable, str(SOURCE / "Scripts/validate-version"), "--source", str(self.source)],
+ [sys.executable, str(SOURCE / "scripts/validate-version"), "--source", str(self.source)],
text=True, capture_output=True,
)
self.assertEqual(result.returncode, 1)
@@ -189,7 +189,7 @@ def test_publisher_uses_the_same_notes_entry_as_preflight(self):
"[Guide](Documentation/Reference/ReleaseGuide.md)\n\n## 0.0.1\n\nOld changes.\n",
)
self.assertEqual(validate(self.source), "0.1.0-alpha.1")
- publisher = runpy.run_path(str(SOURCE / "Scripts/publish-release"))
+ publisher = runpy.run_path(str(SOURCE / "scripts/publish-release"))
notes = publisher["release_notes"]
notes.__globals__["SOURCE"] = self.source
body = notes({
diff --git a/Scripts/bootstrap b/scripts/bootstrap
similarity index 91%
rename from Scripts/bootstrap
rename to scripts/bootstrap
index 3c9b25f..d90ca35 100755
--- a/Scripts/bootstrap
+++ b/scripts/bootstrap
@@ -12,5 +12,5 @@ fi
task_sdk=$(/usr/bin/xcrun --sdk macosx --show-sdk-path)
task_output=${APPLE_CLI_NOTES_PRIVATE_FRAMEWORK_STUBS:-"$task_root/.build/notes-private-framework-link-stubs/current"}
cd "$task_root"
-/usr/bin/xcrun swift Scripts/notes-private-framework-generate-link-stubs \
+/usr/bin/xcrun swift scripts/notes-private-framework-generate-link-stubs \
--sdk-root "$task_sdk" --output-root "$task_output"
diff --git a/Scripts/framework-normalize-full-dump b/scripts/framework-normalize-full-dump
similarity index 100%
rename from Scripts/framework-normalize-full-dump
rename to scripts/framework-normalize-full-dump
diff --git a/Scripts/notes-private-framework-generate-link-stubs b/scripts/notes-private-framework-generate-link-stubs
similarity index 98%
rename from Scripts/notes-private-framework-generate-link-stubs
rename to scripts/notes-private-framework-generate-link-stubs
index 6f193e9..975e840 100755
--- a/Scripts/notes-private-framework-generate-link-stubs
+++ b/scripts/notes-private-framework-generate-link-stubs
@@ -18,7 +18,7 @@ struct StubError: LocalizedError {
func usage() {
print("""
Usage:
- Scripts/notes-private-framework-generate-link-stubs [--sdk-root ] [--output-root ] [--framework ]...
+ scripts/notes-private-framework-generate-link-stubs [--sdk-root ] [--output-root ] [--framework ]...
Generates local Notes link inputs from the selected macOS SDK, preserving
system install names and removing allowed/allowable-client restrictions.
@@ -76,7 +76,7 @@ func sourceTBD(_ framework: String, sdk: URL) throws -> URL {
let candidate = root.appendingPathComponent(suffix)
if FileManager.default.fileExists(atPath: candidate.path) { return candidate }
}
- throw StubError("Selected SDK \(sdk.path) is missing \(framework).tbd. Select an SDK containing all six Notes frameworks, then rerun Scripts/bootstrap.")
+ throw StubError("Selected SDK \(sdk.path) is missing \(framework).tbd. Select an SDK containing all six Notes frameworks, then rerun scripts/bootstrap.")
}
func removingAllowedClients(_ text: String) -> (text: String, removed: Int) {
diff --git a/Scripts/notes-private-framework-normalize-full-dump b/scripts/notes-private-framework-normalize-full-dump
similarity index 100%
rename from Scripts/notes-private-framework-normalize-full-dump
rename to scripts/notes-private-framework-normalize-full-dump
diff --git a/Scripts/package-release b/scripts/package-release
similarity index 98%
rename from Scripts/package-release
rename to scripts/package-release
index f74f35a..577f1c4 100755
--- a/Scripts/package-release
+++ b/scripts/package-release
@@ -138,7 +138,7 @@ func main() throws {
if option == "--help" || option == "-h" {
message(
"""
- Usage: Scripts/package-release [--output DIRECTORY] [--tag TAG] [--jobs COUNT]
+ Usage: scripts/package-release [--output DIRECTORY] [--tag TAG] [--jobs COUNT]
Build and test a clean, committed source candidate and create a
macOS arm64 archive, SHA-256 checksum, and provenance manifest.
--tag verifies an existing tag at HEAD against the source version.
@@ -174,7 +174,7 @@ func main() throws {
throw ReleaseError.invalid("Missing release input: \(file).")
}
}
- var versionArguments = ["python3", root.appendingPathComponent("Scripts/validate-version").path]
+ var versionArguments = ["python3", root.appendingPathComponent("scripts/validate-version").path]
if let tag { versionArguments += ["--tag", tag] }
let version = try run("/usr/bin/env", versionArguments)
let architecture = try run("/usr/bin/uname", ["-m"])
@@ -213,7 +213,7 @@ func main() throws {
validation.append(["check": label, "result": "passed", "log_sha256": try digest(log)])
}
message("Bootstrap selected SDK inputs")
- try run(root.appendingPathComponent("Scripts/bootstrap").path, [])
+ try run(root.appendingPathComponent("scripts/bootstrap").path, [])
var testEnvironment = ProcessInfo.processInfo.environment
testEnvironment.removeValue(forKey: "APPLE_CLI_RUN_NOTES_INTEGRATION_TESTS")
testEnvironment.removeValue(forKey: "APPLE_CLI_BIN")
@@ -310,7 +310,7 @@ func main() throws {
}
try validate(
"installed-release-content",
- ["swift", root.appendingPathComponent("Scripts/validate-public-content").path]
+ ["swift", root.appendingPathComponent("scripts/validate-public-content").path]
+ (["apple", "apple-cli-mcp"] + runtimeNames.sorted()).flatMap {
["--artifact", bin.appendingPathComponent($0).path]
}, environment: testEnvironment)
diff --git a/Scripts/publish-release b/scripts/publish-release
similarity index 99%
rename from Scripts/publish-release
rename to scripts/publish-release
index 69e97fe..e581267 100755
--- a/Scripts/publish-release
+++ b/scripts/publish-release
@@ -14,7 +14,7 @@ from urllib.parse import quote
SOURCE = Path(__file__).resolve().parents[1]
-checker = runpy.run_path(str(SOURCE / "Scripts/verify-release"))
+checker = runpy.run_path(str(SOURCE / "scripts/verify-release"))
require = checker["require"]
digest = checker["digest"]
diff --git a/Scripts/reminderkit-normalize-full-dump b/scripts/reminderkit-normalize-full-dump
similarity index 100%
rename from Scripts/reminderkit-normalize-full-dump
rename to scripts/reminderkit-normalize-full-dump
diff --git a/Scripts/validate-public-content b/scripts/validate-public-content
similarity index 98%
rename from Scripts/validate-public-content
rename to scripts/validate-public-content
index bf2560b..7b7782c 100755
--- a/Scripts/validate-public-content
+++ b/scripts/validate-public-content
@@ -10,7 +10,7 @@ do {
var arguments = CommandLine.arguments.dropFirst().makeIterator()
while let option = arguments.next() {
if option == "--help" || option == "-h" {
- print("Usage: Scripts/validate-public-content [--artifact FILE ...]")
+ print("Usage: scripts/validate-public-content [--artifact FILE ...]")
print("Check public source files for credential/path patterns and local links; scan optional release artifacts for machine-local paths.")
exit(0)
}
diff --git a/Scripts/validate-version b/scripts/validate-version
similarity index 94%
rename from Scripts/validate-version
rename to scripts/validate-version
index 6ee7d80..99c2329 100755
--- a/Scripts/validate-version
+++ b/scripts/validate-version
@@ -10,7 +10,7 @@ import sys
SOURCE = Path(__file__).resolve().parents[1]
-checker = runpy.run_path(str(SOURCE / "Scripts/verify-release"))
+checker = runpy.run_path(str(SOURCE / "scripts/verify-release"))
def main():
diff --git a/Scripts/verify-release b/scripts/verify-release
similarity index 99%
rename from Scripts/verify-release
rename to scripts/verify-release
index 7780792..b35c880 100755
--- a/Scripts/verify-release
+++ b/scripts/verify-release
@@ -172,7 +172,7 @@ def verify(directory, source, tag=None, require_verification=False):
require(receipt["archive"] == {"filename": archive.name, "sha256": archive_hash}, "Verification archive digest mismatch")
require(receipt["provenance"] == {"filename": manifest_path.name, "sha256": digest(manifest_path)}, "Verification provenance digest mismatch")
require(receipt["checksum"] == {"filename": checksum.name, "sha256": digest(checksum)}, "Verification checksum digest mismatch")
- require(receipt["checker"] == {"path": "Scripts/verify-release", "sha256": digest(Path(__file__))}, "Archive checker identity mismatch")
+ require(receipt["checker"] == {"path": "scripts/verify-release", "sha256": digest(Path(__file__))}, "Archive checker identity mismatch")
checks_passed(receipt["validation"], ARCHIVE_CHECKS)
require(receipt["artifact_content"] == {"files_scanned": files_scanned, "machine_local_path_matches": 0}, "Archive content receipt mismatch")
test = next(item for item in receipt["validation"] if item["check"] == "unpacked-cli-and-mcp")
@@ -217,7 +217,7 @@ def accept_executables(source, manifest, archive, manifest_path, checksum, verif
"archive": {"filename": archive.name, "sha256": digest(archive)},
"provenance": {"filename": manifest_path.name, "sha256": digest(manifest_path)},
"checksum": {"filename": checksum.name, "sha256": digest(checksum)},
- "checker": {"path": "Scripts/verify-release", "sha256": digest(Path(__file__))},
+ "checker": {"path": "scripts/verify-release", "sha256": digest(Path(__file__))},
"artifact_content": {"files_scanned": files_scanned, "machine_local_path_matches": 0},
"tested_macos": subprocess.check_output(["sw_vers", "-productVersion"], text=True).strip(),
"architecture": platform.machine(),