diff --git a/docs/PUBLIC_RELEASE_AUDIT.md b/docs/PUBLIC_RELEASE_AUDIT.md index 6ff839d..13b9e8b 100644 --- a/docs/PUBLIC_RELEASE_AUDIT.md +++ b/docs/PUBLIC_RELEASE_AUDIT.md @@ -30,7 +30,7 @@ GitHub secret scanning, push protection, and private vulnerability reporting are `Package.swift` declares no third-party package dependencies. Corewise uses Swift, SwiftUI, AppKit/macOS frameworks, and repository-owned source only. There is no third-party notices bundle required for the current app. -The application icon is repository-owned and reproducibly generated by `script/generate_app_icon.swift`. `Sources/Corewise/Resources/Corewise.icns` is the packaged icon and `docs/assets/corewise-app-icon.png` is its public preview. Public screenshots are captured from Corewise itself and contain no third-party artwork. The repository social preview is composed from those repository-owned screenshots by `script/generate_social_preview.swift`; it introduces no external font, stock image, or generated-art dependency. +The application icon is repository-owned and reproducibly generated by `script/generate_app_icon.swift`. `Sources/Corewise/Resources/Corewise.icns` is the packaged icon and `docs/assets/corewise-app-icon.png` is its public preview. Public screenshots are captured from Corewise itself and contain no third-party artwork. The repository social preview is composed from those repository-owned screenshots by `script/generate_social_preview.swift`; it introduces no external font, stock image, or generated-art dependency. The coordinated public-beta launch images under `docs/launch/assets/` are likewise composed from the same Corewise screenshots by `script/generate_launch_assets.swift` and use only system typography and programmatic shapes. Contributor Covenant text is adapted from version 2.1 with attribution in `CODE_OF_CONDUCT.md`. diff --git a/docs/launch/PUBLIC_BETA_LAUNCH_KIT.md b/docs/launch/PUBLIC_BETA_LAUNCH_KIT.md new file mode 100644 index 0000000..158db13 --- /dev/null +++ b/docs/launch/PUBLIC_BETA_LAUNCH_KIT.md @@ -0,0 +1,232 @@ + + +# Corewise public beta launch kit + +## Launch posture + +This is a small builder-led beta launch, not a general-availability campaign. The goal is to reach a first group of macOS and local-AI users, earn useful feedback, and turn concrete problems into GitHub Issues. + +- Primary destination: **[corewise.dev](https://corewise.dev)** +- Direct beta: **[Corewise 0.1.0 beta 2](https://github.com/roccodaffuso/Corewise/releases/tag/v0.1.0-beta.2)** +- Feedback: **[GitHub Issues](https://github.com/roccodaffuso/Corewise/issues/new/choose)** + +## Canonical message + +### One line + +> Corewise is a free, open-source Mac signal console that explains local performance, storage, and AI workloads without uploading diagnostic data. + +### Three proof points + +1. **AI Workloads** observes supported local tools such as Codex, Claude, Cursor, and Ollama, separating the app footprint from related local work and shared hosts. +2. **Local by design** means no account, telemetry, or backend. Corewise does not read prompts, projects, process arguments, or working directories. +3. **Open source** means the code is public under MPL-2.0, while the official beta is signed, notarized, and available for macOS 14 or later. + +### Language boundaries + +Say: + +- “observed local processes”; +- “attributable app footprint”; +- “related local work”; +- “no urgent live signals detected”; +- “free and open source.” + +Do not say: + +- “active agents” or “agent count”; +- “Corewise sees cloud usage”; +- “your Mac is healthy”; +- “Corewise diagnoses or fixes your Mac”; +- “100% private” without explaining the local-data boundary. + +## Recommended launch sequence + +1. Publish the X post from `@rodabuilds` with the Overview image. Put links in the first reply. +2. Publish the LinkedIn post with the AI Workloads image and the website link in the body or first comment. +3. The next day, share the transparent Reddit post in a relevant macOS community with the Privacy/Open Source image. Check each community's self-promotion rules first. +4. Reply to every substantive question and convert reproducible defects or requests into GitHub Issues. +5. Two or three days later, publish a short builder follow-up about what early users noticed. Do not invent adoption numbers or testimonials. + +## X / Twitter launch post + +Use `corewise-launch-overview.jpg`. + +```text +Activity Monitor can show what is using your Mac. + +I wanted something that also explains what matters — without a fake health score or an aggressive “clean now” button. + +So I built Corewise: a local-first signal console for macOS. + +It covers performance, storage, thermal signals, startup activity, recurring app issues, and local AI workloads. + +Free. Open source. Public beta. +``` + +First reply: + +```text +Corewise runs locally, has no account or telemetry, and the official macOS 14+ beta is signed and notarized. + +Try it: https://corewise.dev +Source + issues: https://github.com/roccodaffuso/Corewise +``` + +Optional second post with `corewise-launch-ai-workloads.jpg`: + +```text +The part I wanted most: AI Workloads. + +Corewise can show the local CPU and memory footprint attributable to supported tools such as Codex, Claude, Cursor, and Ollama. + +App footprint, related local work, and shared hosts stay separate. Cloud activity and “agent counts” are deliberately outside coverage. +``` + +## LinkedIn launch post + +Use `corewise-launch-ai-workloads.jpg`. + +```text +I have released the public beta of Corewise, a free and open-source macOS diagnostic utility. + +I built it around a simple frustration: system monitors expose a lot of numbers, but they rarely help explain which signals matter or what a safe next step looks like. + +Corewise brings performance, storage, battery, thermal state, startup activity, and recurring app issues into one local signal console. Its most distinctive view is AI Workloads: it observes supported local tools such as Codex, Claude, Cursor, and Ollama, while keeping directly attributable app footprint, related local work, and shared hosts explicitly separate. + +The privacy boundary is intentionally narrow: +• no account, telemetry, or backend; +• no prompt or project inspection; +• no process arguments or working-directory collection; +• no automatic cleanup or destructive action. + +The source is available under MPL-2.0. The macOS 14+ beta is universal, signed, and notarized. + +I am looking for practical feedback from people who use a Mac for development, creative work, or local AI tools — especially confusing results, missing context, and rough edges. + +Website and beta: https://corewise.dev +Source and issues: https://github.com/roccodaffuso/Corewise +``` + +## LinkedIn Italian alternative + +Use `corewise-launch-ai-workloads.jpg`. + +```text +Ho pubblicato la beta di Corewise, un'app macOS gratuita e open source per capire meglio cosa sta usando le risorse del Mac. + +L'idea nasce da un limite che sentivo usando i normali monitor di sistema: mostrano molti numeri, ma spesso non spiegano quali segnali contano davvero e quale sia il prossimo controllo sensato. + +Corewise riunisce performance, storage, batteria, stato termico, elementi di avvio e problemi ricorrenti delle app. La parte più particolare è AI Workloads: osserva i processi locali attribuibili a strumenti supportati come Codex, Claude, Cursor e Ollama, separando footprint dell'app, lavoro locale correlato e host condivisi. + +Tutto resta locale: niente account, telemetria o backend; niente lettura di prompt, progetti, argomenti dei processi o cartelle di lavoro; nessuna pulizia automatica. + +Il codice è pubblico con licenza MPL-2.0. La beta per macOS 14+ è universale, firmata e notarizzata. + +Cerco feedback concreto, soprattutto su risultati poco chiari, contesto mancante e problemi reali di utilizzo. + +Sito e beta: https://corewise.dev +Codice e issue: https://github.com/roccodaffuso/Corewise +``` + +## Reddit post + +Use `corewise-launch-privacy-open-source.jpg`. + +Title: + +```text +I built Corewise, an open-source local-first Mac signal console with AI workload attribution +``` + +Body: + +```text +Hi — I am the developer of Corewise, and I have just published its first public beta. + +Corewise is a macOS 14+ utility for understanding performance, storage, battery, thermal state, startup activity, and recurring app issues without reducing everything to a “health score” or offering automatic cleanup. + +One view I could not find elsewhere in the form I wanted is AI Workloads. Corewise observes supported local tools such as Codex, Claude, Cursor, and Ollama and separates directly attributable app footprint from related local work and ambiguous shared hosts. It does not claim to count agents, and cloud activity is outside its coverage. + +The app has no account, backend, telemetry, or network collector. It does not inspect prompts, projects, process arguments, environments, or working directories. Storage analysis is read-only and any broader access is optional. + +Corewise is open source under MPL-2.0. The public beta is a signed and notarized universal build: + +https://corewise.dev + +Source: https://github.com/roccodaffuso/Corewise + +I would especially value feedback about confusing language, incorrect attribution, accessibility, and cases where the app fails to explain what you are seeing. Bugs and feature requests can go directly into GitHub Issues. +``` + +## Short variants + +### Mastodon / Bluesky + +Use `corewise-launch-overview.jpg`. + +```text +Corewise is now in public beta: a free, open-source Mac signal console for performance, storage, and supported local AI workloads. + +No account, telemetry, backend, prompt inspection, or automatic cleanup. The macOS 14+ build is signed and notarized. + +https://corewise.dev +``` + +### GitHub profile or pinned note + +```text +Building Corewise — a local-first, open-source macOS signal console with explicit AI workload attribution. Public beta: https://corewise.dev +``` + +## Coordinated images + +All assets are 1200×675 JPEGs designed for X, LinkedIn, Reddit, Mastodon, and Bluesky. They use only Corewise-owned screenshots and the existing signal-field visual language. + +| Asset | Purpose | +| --- | --- | +| `assets/corewise-launch-overview.jpg` | Main product announcement and general link sharing. | +| `assets/corewise-launch-ai-workloads.jpg` | AI Workloads explanation and developer-focused posts. | +| `assets/corewise-launch-privacy-open-source.jpg` | Privacy, open-source, and trust-oriented posts. | + +Regenerate them with: + +```sh +swift script/generate_launch_assets.swift \ + docs/assets/corewise-overview.png \ + docs/assets/corewise-ai-workloads.png \ + docs/assets/corewise-storage.png \ + docs/launch/assets +``` + +## Reply bank + +### “Does it monitor my prompts or projects?” + +No. AI Workloads uses local process identity and topology. Corewise does not read prompts, project contents, process arguments, environments, or working directories. + +### “Can it see cloud agents or token usage?” + +No. Cloud activity is outside local process observation. Corewise intentionally reports supported local tools, not logical or cloud-agent counts. + +### “Why does Storage ask for access?” + +Startup-volume capacity needs no folder access. Detailed file analysis is read-only and requires explicit optional permission because macOS protects personal data. + +### “Why MPL-2.0?” + +MPL-2.0 keeps distributed modifications to existing Corewise source files public while allowing separate files and integrations to use compatible terms. The project name and logo remain outside the code license. + +### “Is it safe to install?” + +The official beta is a universal Developer ID build signed and notarized by Apple. The release page includes its SHA-256 checksum and the source is public for inspection. + +## Small-launch success signals + +Do not add telemetry for the launch. Use only public or volunteered signals: + +- confirmed external installations; +- relevant GitHub stars or forks; +- actionable Issues rather than raw issue count; +- questions that reveal unclear messaging; +- one or more users who can complete install, first launch, AI Workloads, and optional Storage analysis. diff --git a/docs/launch/assets/corewise-launch-ai-workloads.jpg b/docs/launch/assets/corewise-launch-ai-workloads.jpg new file mode 100644 index 0000000..987baed Binary files /dev/null and b/docs/launch/assets/corewise-launch-ai-workloads.jpg differ diff --git a/docs/launch/assets/corewise-launch-overview.jpg b/docs/launch/assets/corewise-launch-overview.jpg new file mode 100644 index 0000000..e92dd17 Binary files /dev/null and b/docs/launch/assets/corewise-launch-overview.jpg differ diff --git a/docs/launch/assets/corewise-launch-privacy-open-source.jpg b/docs/launch/assets/corewise-launch-privacy-open-source.jpg new file mode 100644 index 0000000..1dad592 Binary files /dev/null and b/docs/launch/assets/corewise-launch-privacy-open-source.jpg differ diff --git a/script/generate_launch_assets.swift b/script/generate_launch_assets.swift new file mode 100644 index 0000000..c2bbabf --- /dev/null +++ b/script/generate_launch_assets.swift @@ -0,0 +1,289 @@ +#!/usr/bin/env swift +// SPDX-License-Identifier: MPL-2.0 + +import AppKit + +private let canvasSize = NSSize(width: 1_200, height: 675) + +private struct LaunchCard { + let filename: String + let eyebrow: String + let headline: String + let body: String + let chips: [String] + let screenshot: NSImage +} + +private func color(_ hex: UInt32, alpha: CGFloat = 1) -> NSColor { + NSColor( + red: CGFloat((hex >> 16) & 0xff) / 255, + green: CGFloat((hex >> 8) & 0xff) / 255, + blue: CGFloat(hex & 0xff) / 255, + alpha: alpha + ) +} + +private func drawText( + _ text: String, + in rect: NSRect, + font: NSFont, + color: NSColor, + lineHeight: CGFloat? = nil +) { + let paragraph = NSMutableParagraphStyle() + paragraph.lineBreakMode = .byWordWrapping + if let lineHeight { + paragraph.minimumLineHeight = lineHeight + paragraph.maximumLineHeight = lineHeight + } + + text.draw( + in: rect, + withAttributes: [ + .font: font, + .foregroundColor: color, + .paragraphStyle: paragraph, + ] + ) +} + +private func drawSignalField(accentY: CGFloat) { + for index in 0..<7 { + let path = NSBezierPath() + path.lineWidth = index == 3 ? 1.8 : 1 + let baseY = CGFloat(58 + index * 92) + path.move(to: NSPoint(x: 0, y: baseY)) + + for x in stride(from: CGFloat(0), through: canvasSize.width, by: 14) { + let wave = sin((x / 74) + CGFloat(index) * 0.9) * CGFloat(7 + index) + let pulse = exp(-pow((x - 420) / 128, 2)) * sin(x / 12) * 24 + path.line(to: NSPoint(x: x, y: baseY + wave + pulse)) + } + + color(0x55D6D9, alpha: index == 3 ? 0.14 : 0.045).setStroke() + path.stroke() + } + + let guide = NSBezierPath() + guide.lineWidth = 1 + guide.setLineDash([3, 7], count: 2, phase: 0) + guide.move(to: NSPoint(x: 52, y: accentY)) + guide.line(to: NSPoint(x: canvasSize.width - 52, y: accentY)) + color(0x86E7E4, alpha: 0.13).setStroke() + guide.stroke() +} + +private func sourceRect(for image: NSImage, target: NSRect) -> NSRect { + let sourceRatio = image.size.width / image.size.height + let targetRatio = target.width / target.height + + if sourceRatio > targetRatio { + let width = image.size.height * targetRatio + return NSRect( + x: (image.size.width - width) / 2, + y: 0, + width: width, + height: image.size.height + ) + } + + let height = image.size.width / targetRatio + return NSRect( + x: 0, + y: (image.size.height - height) / 2, + width: image.size.width, + height: height + ) +} + +private func drawScreenshot(_ screenshot: NSImage) { + let frameRect = NSRect(x: 560, y: 72, width: 710, height: 525) + let frame = NSBezierPath(roundedRect: frameRect, xRadius: 24, yRadius: 24) + + NSGraphicsContext.saveGraphicsState() + let shadow = NSShadow() + shadow.shadowColor = color(0x000000, alpha: 0.72) + shadow.shadowBlurRadius = 34 + shadow.shadowOffset = NSSize(width: -8, height: -12) + shadow.set() + color(0x050B0C).setFill() + frame.fill() + NSGraphicsContext.restoreGraphicsState() + + NSGraphicsContext.saveGraphicsState() + frame.addClip() + screenshot.draw( + in: frameRect, + from: sourceRect(for: screenshot, target: frameRect), + operation: .sourceOver, + fraction: 1, + respectFlipped: true, + hints: [.interpolation: NSImageInterpolation.high] + ) + NSGraphicsContext.restoreGraphicsState() + + color(0x79E2E0, alpha: 0.28).setStroke() + frame.lineWidth = 1 + frame.stroke() +} + +private func chipWidth(for text: String) -> CGFloat { + let attributes: [NSAttributedString.Key: Any] = [ + .font: NSFont.systemFont(ofSize: 14, weight: .semibold), + ] + return ceil((text as NSString).size(withAttributes: attributes).width) + 30 +} + +private func drawChips(_ chips: [String]) { + var x: CGFloat = 62 + + for chip in chips { + let width = chipWidth(for: chip) + let rect = NSRect(x: x, y: 68, width: width, height: 38) + let shape = NSBezierPath(roundedRect: rect, xRadius: 11, yRadius: 11) + color(0x55D6D9, alpha: 0.085).setFill() + shape.fill() + color(0x55D6D9, alpha: 0.23).setStroke() + shape.lineWidth = 1 + shape.stroke() + + drawText( + chip, + in: NSRect(x: x + 15, y: 77, width: width - 30, height: 20), + font: .systemFont(ofSize: 14, weight: .semibold), + color: color(0xB2CECC) + ) + x += width + 10 + } +} + +private func render(_ card: LaunchCard, to outputURL: URL) throws { + guard + let bitmap = NSBitmapImageRep( + bitmapDataPlanes: nil, + pixelsWide: Int(canvasSize.width), + pixelsHigh: Int(canvasSize.height), + bitsPerSample: 8, + samplesPerPixel: 4, + hasAlpha: true, + isPlanar: false, + colorSpaceName: .deviceRGB, + bytesPerRow: 0, + bitsPerPixel: 0 + ), + let context = NSGraphicsContext(bitmapImageRep: bitmap) + else { + throw CocoaError(.fileWriteUnknown) + } + + NSGraphicsContext.saveGraphicsState() + NSGraphicsContext.current = context + context.imageInterpolation = .high + + NSGradient( + starting: color(0x050D0E), + ending: color(0x132625) + )?.draw(in: NSRect(origin: .zero, size: canvasSize), angle: 0) + + drawSignalField(accentY: 132) + + let glow = NSBezierPath(ovalIn: NSRect(x: 390, y: 84, width: 670, height: 670)) + color(0x55D6D9, alpha: 0.045).setFill() + glow.fill() + + drawScreenshot(card.screenshot) + + let accentLine = NSBezierPath() + accentLine.lineWidth = 3 + accentLine.move(to: NSPoint(x: 62, y: 597)) + accentLine.line(to: NSPoint(x: 132, y: 597)) + color(0x55D6D9).setStroke() + accentLine.stroke() + + drawText( + card.eyebrow, + in: NSRect(x: 62, y: 555, width: 460, height: 25), + font: .systemFont(ofSize: 15, weight: .bold), + color: color(0x7DDEDC) + ) + + drawText( + card.headline, + in: NSRect(x: 58, y: 302, width: 475, height: 225), + font: .systemFont(ofSize: 54, weight: .semibold), + color: color(0xF3F7F6), + lineHeight: 59 + ) + + drawText( + card.body, + in: NSRect(x: 62, y: 146, width: 430, height: 125), + font: .systemFont(ofSize: 20, weight: .regular), + color: color(0xA9B9B8), + lineHeight: 28 + ) + + drawChips(card.chips) + + NSGraphicsContext.restoreGraphicsState() + + guard let data = bitmap.representation(using: .jpeg, properties: [.compressionFactor: 0.9]) else { + throw CocoaError(.fileWriteUnknown) + } + try data.write(to: outputURL, options: .atomic) +} + +let arguments = CommandLine.arguments +guard arguments.count == 5 else { + FileHandle.standardError.write( + Data("Usage: swift script/generate_launch_assets.swift \n".utf8) + ) + exit(64) +} + +guard + let overview = NSImage(contentsOfFile: arguments[1]), + let aiWorkloads = NSImage(contentsOfFile: arguments[2]), + let storage = NSImage(contentsOfFile: arguments[3]) +else { + FileHandle.standardError.write(Data("Unable to read one or more Corewise screenshots.\n".utf8)) + exit(66) +} + +private let cards = [ + LaunchCard( + filename: "corewise-launch-overview.jpg", + eyebrow: "COREWISE / PUBLIC BETA", + headline: "Your Mac, explained locally.", + body: "Understand performance, storage, thermal signals, startup activity, and recurring app issues without a fake health score.", + chips: ["macOS 14+", "Signed + notarized", "Open source"], + screenshot: overview + ), + LaunchCard( + filename: "corewise-launch-ai-workloads.jpg", + eyebrow: "COREWISE / AI WORKLOADS", + headline: "See what local AI tools use.", + body: "Observe Codex, Claude, Cursor, and Ollama while keeping app footprint, related work, and shared hosts separate.", + chips: ["Local processes", "No agent count", "Cloud excluded"], + screenshot: aiWorkloads + ), + LaunchCard( + filename: "corewise-launch-privacy-open-source.jpg", + eyebrow: "COREWISE / LOCAL BY DESIGN", + headline: "Your diagnostics stay on your Mac.", + body: "No account, telemetry, or backend. Corewise never reads prompts, projects, process arguments, or working directories.", + chips: ["Read-only", "No telemetry", "MPL-2.0"], + screenshot: storage + ), +] + +let outputDirectory = URL(fileURLWithPath: arguments[4], isDirectory: true) +do { + try FileManager.default.createDirectory(at: outputDirectory, withIntermediateDirectories: true) + for card in cards { + try render(card, to: outputDirectory.appendingPathComponent(card.filename)) + } +} catch { + FileHandle.standardError.write(Data("Unable to generate launch assets: \(error)\n".utf8)) + exit(74) +}