we (web engine): Experimental web browser project to understand the limits of Claude
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add signed .app bundle build for /Applications, modelled after mct/build.sh #217

open opened by pierrelf.com

Right now cargo run -p we-browser is the only way to launch the browser. There is no .app bundle, no icon, no code-signing, no Launch Services registration, and no way to associate the app with http:///https:// URLs or .html files. Mirror what ~/misc/mct/build.sh does for MCT and produce a real macOS app.

Reference#

Look at ~/misc/mct/build.sh (and ~/misc/mct/.env for the signing identity convention). The full mct script is the working template — adapt it for a Rust/Cargo build.

Scope#

Add a build.sh at the repo root that, in this order:

  1. Load ./.env (gitignored) if present, exporting CERT_NAME. If missing, fall through to ad-hoc signing (codesign --sign -) so the script still works for contributors without the Apple Developer cert.

  2. Compile release binary:

    cargo build --release -p we-browser --target aarch64-apple-darwin
    
  3. Lay out the bundle at build/we.app/:

    we.app/
      Contents/
        Info.plist
        PkgInfo                   # \"APPL????\"
        MacOS/we                  # copied from target/aarch64-apple-darwin/release/browser
        Resources/AppIcon.icns
    
  4. Generate the icon in pure Rust. We have we-image with a PNG encoder — write a tiny tools/generate_icon binary (in this repo, not an external swiftc script) that emits a 1024x1024 PNG to a path, then slice and pack it via sips + iconutil exactly as mct does:

    sips -z 16 16 ... ; sips -z 32 32 ... ; ... iconutil --convert icns ...
    

    Cache the .icns under build/icon/ so we don't regenerate every build.

    The icon design can be simple — a stylised we wordmark on a rounded-rect gradient background. Keep it placeholder-quality; the point is to have a real icon slot, not to ship final branding.

  5. Write the Info.plist. Browser-specific keys (in addition to the mct boilerplate):

    • CFBundleIdentifier = com.we.browser
    • CFBundleName = we
    • CFBundleDisplayName = we
    • CFBundleShortVersionString = read from crates/browser/Cargo.toml [package].version
    • CFBundleVersion = same
    • CFBundleExecutable = we
    • CFBundleIconFile = AppIcon
    • CFBundlePackageType = APPL
    • LSMinimumSystemVersion = 14.0
    • LSApplicationCategoryType = public.app-category.web-browser
    • CFBundleURLTypes — register http and https schemes so open https://... and OS-wide "set default browser" can target we:
      <key>CFBundleURLTypes</key>
      <array>
        <dict>
          <key>CFBundleURLName</key><string>HTTP</string>
          <key>CFBundleURLSchemes</key><array><string>http</string></array>
        </dict>
        <dict>
          <key>CFBundleURLName</key><string>HTTPS</string>
          <key>CFBundleURLSchemes</key><array><string>https</string></array>
        </dict>
      </array>
      
    • CFBundleDocumentTypes — register .html, .htm, .xhtml so double-clicking opens in we.
    • NSAppTransportSecurity with NSAllowsArbitraryLoads=true for now (we need plain HTTP until issue 3mm2gmpx46624 ships proper TLS).

    The browser binary will need a tiny extra: handle the application:openURL: AppKit callback (or read argv on launch when LaunchServices passes the file). Existing argv handling already covers the file-path case; the URL-scheme case ("Get URL" Apple Event) is a future ticket — register the schemes now so the OS knows the app is willing.

  6. PkgInfo = literal APPL???? (8 bytes).

  7. Code-sign:

    codesign --force --options runtime --sign \"$CERT_NAME\" build/we.app
    

    (Or --sign - if CERT_NAME is empty.) --options runtime enables the hardened runtime, required for Developer ID notarization. Add an entitlements plist tools/we.entitlements granting com.apple.security.network.client (otherwise the sandbox blocks outbound sockets). Pass it via --entitlements.

  8. Install to /Applications/we.app:

    pkill -x we 2>/dev/null || true
    rm -rf /Applications/we.app
    cp -R build/we.app /Applications/we.app
    codesign --force --options runtime --sign \"$CERT_NAME\" /Applications/we.app
    
  9. Refresh Launch Services so Finder/launchd see the new bundle:

    /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f /Applications/we.app
    
  10. open /Applications/we.app and report success.

.gitignore#

Add build/ and .env to .gitignore so the bundle output and signing identity stay out of git.

Documentation#

  • Update CLAUDE.md Commands section with a ./build.sh entry that says "produce signed we.app and install to /Applications".
  • Mention the optional .env with CERT_NAME=<Developer ID Application: …> and that omitting it falls back to ad-hoc signing.

Acceptance#

  • ./build.sh exits 0 with no signing identity present, producing /Applications/we.app that launches and shows the browser window.
  • With a CERT_NAME set in ./.env, codesign --verify --deep --strict /Applications/we.app passes, and spctl --assess /Applications/we.app succeeds (or returns the expected "unnotarized" message for a Developer ID build — explicit notarization is out of scope here, separate ticket).
  • mdls /Applications/we.app shows the bundle as a Web Browser category app.
  • Right-clicking an .html file in Finder lists we under "Open With".
  • defaults read /Applications/we.app/Contents/Info.plist CFBundleURLTypes lists http and https.
  • The Dock shows the generated app icon on launch.

Out of scope (separate tickets)#

  • Apple notarization (xcrun notarytool).
  • Universal binary (x86_64 + arm64). For now arm64-only matches the project's stated platform.
  • Sparkle/auto-update.
  • Handling "Get URL" Apple Events for live URL-scheme dispatch (currently we just declare the schemes so the OS will list we as an option).
  • DMG packaging / public release artefact.
sign up or login to add to the discussion
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:meotu43t6usg4qdwzenk4s2t/sh.tangled.repo.issue/3mm2gsgkspt2e