Skip to content

chore: extract apps/mac + apps/chrome to lobu-ai/owletto#784

Merged
buremba merged 9 commits into
mainfrom
feat/owletto-extraction
May 17, 2026
Merged

chore: extract apps/mac + apps/chrome to lobu-ai/owletto#784
buremba merged 9 commits into
mainfrom
feat/owletto-extraction

Conversation

@buremba
Copy link
Copy Markdown
Member

@buremba buremba commented May 17, 2026

Summary

Owletto becomes its own private repo. This PR is the plumbing pivot — no product code changes.

  • apps/mac/ and apps/chrome/ move to lobu-ai/owletto (renamed from lobu-ai/owletto-web). Full commit history preserved via git filter-repo + merge into owletto/main with --allow-unrelated-histories (merge commit on owletto side: 551ac9f).
  • packages/web submodule now points at lobu-ai/owletto.git (URL change in .gitmodules); pinned SHA bumped to the merge commit on owletto/main.
  • mac-release.yml stays in lobu, sources via the submodule path packages/web/apps/mac/. Owletto is private, so its GitHub Releases would require auth to download — releases ship from this public repo so releases/latest/download/Lobu.dmg and lobu-ai.github.io/lobu/appcast.xml stay reachable to anonymous users and existing installed apps. (The first commit on this branch incorrectly deleted the workflow; the second commit restores it with submodule paths.)
  • Submodule drift check, setup-submodule action, CI comments updated to reference owletto instead of owletto-web.
  • Code comments (packages/core/src/capabilities.ts, packages/connectors/src/chrome_tabs.ts) and the personal-mode-auth plan updated to use cross-repo path references (lobu-ai/owletto: apps/mac/…).
  • Strategic plan landed at docs/plans/owletto.md.

Old deprecated lobu-ai/owletto (memory-server work) was renamed to lobu-ai/owletto-archive separately, freeing the name.

What stays in lobu

  • Engine: gateway, agent-worker, core, CLI, SDK.
  • Server-side connectors (including chrome_tabs which still defines the platform string).
  • mac-release.yml — Mac DMG release pipeline, now sourcing through the submodule.
  • All Lobu engine + ops infrastructure.

What's now in owletto

  • apps/mac/ — SwiftUI menubar app source.
  • apps/chrome/ — MV3 Chrome extension source.
  • The existing React SPA (unchanged at root).

Follow-ups in owletto repo (out of scope here)

  • Update K8s deploy YAMLs inside deploy/ that still reference the old owletto-web URL.
  • M1: make cloud signin optional in apps/mac/Lobu/OAuthClient.swift + AppState.swift.

Follow-ups in lobu (out of scope here)

  • M0: LOBU_MODE=local, local-CLI executor, PGlite production path, lobu pull --local.
  • Eventually: rename submodule mount packages/webpackages/owletto for accuracy (touches every workflow + tsconfig reference; bundle with internal owletto-side package renames).

Naming notes (intentionally deferred)

  • Secret name OWLETTO_WEB_DEPLOY_KEY is unchanged. Functionally fine (it's just a label, the key itself works for the renamed repo). Cosmetic rename can happen later.
  • Submodule mount path is still packages/web even though the submodule now contains the Mac app + Chrome extension. Renaming the mount is a much bigger ripple (workflows, tsconfig, scripts) and is best paired with renaming @lobu/web inside the owletto repo. Out of scope here.

Test plan

  • bun install clean
  • make build-packages passes
  • make typecheck passes (strict, matches Dockerfile)
  • packages/web submodule resolves at the new lobu-ai/owletto.git URL
  • No stray apps/mac / apps/chrome references outside intentional cross-repo paths
  • No stray owletto-web references outside CHANGELOG (historic)
  • Pre-commit (biome + tsc) clean
  • CI green
  • Submodule drift check green (pin matches new owletto/main)
  • mac-release.yml smoke test (manual workflow_dispatch with a test version, optional — secrets unchanged so structurally same as before)

Summary by CodeRabbit

  • Chores

    • Reorganized repository structure by moving Mac app and Chrome extension code to a separate lobu-ai/owletto repository
    • Updated CI/CD workflows and submodule configurations to reference new repository layout
    • Updated internal documentation paths and repository references
  • Documentation

    • Added comprehensive product plan documenting Owletto architecture, scope, and roadmap
    • Updated planning documents to reflect new repository organization

Review Change Stack

Owletto becomes a separate private repo (renamed from lobu-ai/owletto-web).
Mac app and Chrome extension history preserved via git-filter-repo into the
new repo; lobu engine + connectors stay here.

- Rename submodule URL packages/web → lobu-ai/owletto
- Bump submodule pointer to owletto/main HEAD that includes the import merge
- Drop apps/mac/, apps/chrome/, .github/workflows/mac-release.yml
- Update submodule drift check, setup-submodule action, and CI comments
- Update cross-repo references in code comments and personal-mode-auth plan
- Land strategic plan at docs/plans/owletto.md
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates the macOS and Chrome extension implementations from the main lobu repository to a private lobu-ai/owletto repository. It updates submodule configuration and CI workflows to reference the external source, removes in-repo source files, and introduces comprehensive Owletto product planning documentation with cross-repo path clarifications.

Changes

Submodule, CI, and workflow infrastructure

Layer / File(s) Summary
Submodule configuration and git URLs
.gitmodules, .github/actions/setup-submodule/action.yml, packages/web
.gitmodules URL updated from lobu-ai/owletto-web to lobu-ai/owletto; deploy-key action description and SSH rewrite configuration updated to reference the new repository URL; packages/web commit SHA bumped.
Frontend CI job updates
.github/workflows/ci.yml
Frontend job comments and step labels changed from owletto-web to owletto to match submodule naming; build/test invocation logic unchanged.
Submodule drift check messaging
.github/workflows/submodule-drift.yml
Drift-check step name, error messages, success output, and suggested fix commit command updated to reference owletto/main instead of owletto-web/main; underlying validation logic unchanged.
macOS release workflow submodule integration
.github/workflows/mac-release.yml
Adds submodule setup step with OWLETTO_WEB_DEPLOY_KEY and contract verification; switches Xcode project paths to packages/web/apps/mac/Lobu.xcodeproj; updates Sparkle script path to scripts/sparkle/update-appcast.py; adds validation for submodule origin and required release artifacts.
Developer documentation updates
AGENTS.md
References updated to point packages/web instructions to lobu-ai/owletto repository.

Source code migration and removals

Layer / File(s) Summary
Xcode project configuration removals
apps/mac/Lobu.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved, apps/mac/Lobu/Assets.xcassets/*
SwiftPM lockfile with Sparkle dependency pinning and asset catalog metadata removed.
Chrome extension source code removal
apps/chrome/{background.js, bridge.js, config.js, manifest.json, pairing.*, permissions.*, sidepanel.*, README.md, SCOPE.md}
Entire MV3 extension implementation deleted, including service worker, RPC bridge, configuration, manifest, pairing flow, permissions UI, and sidepanel.

Product planning and cross-repo documentation

Layer / File(s) Summary
Owletto product and engineering plan
docs/plans/owletto.md
Comprehensive new document defining local-first macOS menubar + Chrome extension product, v1 scope and out-of-scope features, embedded Lobu gateway architecture with PGlite, local CLI executor worker integration, filesystem sync semantics (~/lobu/ DB mirroring), repository structure and migration from in-repo apps/mac/Lobu/, brand/positioning/moat analysis, marketing channels, M0–M5 milestones, resolved decisions, and open questions.
Authentication docs and code comment updates
docs/plans/personal-mode-auth.md, packages/connectors/src/chrome_tabs.ts, packages/core/src/capabilities.ts
Updated personal-mode-auth documentation to clarify Mac app and extension are in lobu-ai/owletto repo; adjusted code documentation comments to cite cross-repo paths using lobu-ai/owletto: prefix.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • lobu-ai/lobu#773: The main PR removes the entire Chrome extension MV3 source files that this PR adds for the native-messaging pairing and bridge flow.
  • lobu-ai/lobu#774: Both PRs touch the Mac menu-bar app's Swift implementations (AppState, MenuBarContent, BrowserProfilesView, ObsidianVaultManager, LobuUpdater) with the main PR deleting them while the retrieved PR modifies their logic.
  • lobu-ai/lobu#732: The main PR removes macOS Photos-related implementations (PhotosSyncService, AppState photos logic, Info.plist entitlements) that the retrieved PR adds for apple.photos support.

Suggested labels

skip-size-check

Poem

🐰 A rabbit hops from repo to repo,
Moving code across the veil—
Owletto spreads its wings, local-only,
While Chrome files pack their mail. 📦
New plans bloom in markdown—
The future forks, and we set sail! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: extracting apps/mac and apps/chrome to a separate repository (lobu-ai/owletto). It reflects the primary objective without unnecessary detail.
Description check ✅ Passed The PR description provides comprehensive context covering the extraction, submodule updates, what stays/moves, test results, and follow-ups. It includes a Summary section, detailed Test plan checklist (with most items marked complete), and extensive Notes. All required template sections are present and substantively completed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/owletto-extraction

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/plans/owletto.md`:
- Around line 113-144: Add explicit language identifiers ("text") to the two
fenced code blocks: the ASCII diagram block that begins with
"┌────────────────────────────────────────────────────────────────┐" and the
directory tree block that begins with "owletto/"; replace the opening triple
backticks (```) with "```text" for each fenced block so markdownlint stops
complaining (leave the closing ``` as-is).
- Around line 191-201: The docs contain a contradiction: the "Proactive
precision: the 'should this interrupt' gate" section introduces an LLM interrupt
gate as a first-class v1 feature while the v1 scope elsewhere explicitly states
"No LLM interrupt gate"; resolve by reconciling the contract—either remove or
move the LLM gate content (the paragraph titled "Proactive precision: the
'should this interrupt' gate") out of the v1 plan and mark it as a future
v2/experimental feature, or adjust the v1 scope language to explicitly include a
lightweight/local LLM gate (e.g., "small + cheap" gate) and update the v1 scope
lines to match; ensure the edited sections reference the same concept name
("interrupt gate" / "LLM gate") so there is a single authoritative v1 contract.
- Line 1: Add a single-sentence memory entry to CLAUDE.md summarizing the
Owletto plan change: state that the Owletto repo is being split and adopting a
local-first architecture (e.g., "Owletto repo split and moving to a local-first
plan"). Edit the CLAUDE.md file to append this one-line sentence in the memory
section so it matches the guideline for "*.md" files.

In `@docs/plans/personal-mode-auth.md`:
- Around line 3-5: Replace the placeholder "`#TBD`" in the top-level note of
docs/plans/personal-mode-auth.md with a concrete migration reference: either the
exact migration date (e.g., "2026-06-01") or a specific PR/commit identifier
(e.g., "PR `#1234`" or commit SHA) that documents when the Mac app + Chrome
extension moved to lobu-ai/owletto; update the sentence so it reads clearly
(e.g., "as of PR `#1234` (2026-06-01)"), ensuring the change targets the note
containing the string "`#TBD`".

In `@packages/web`:
- Line 1: The submodule pointer for packages/web is currently pinned to a commit
not reachable from the owletto/main branch, causing the Submodule Drift gate to
fail; update the submodule reference for packages/web to a commit SHA that
exists on owletto/main (i.e., repin the gitlink in the repository metadata where
packages/web is referenced), commit that updated submodule SHA, and push and
rerun the drift/CI checks so the reachability check succeeds before merging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d927f571-6b52-4f09-a408-49279089682b

📥 Commits

Reviewing files that changed from the base of the PR and between 5226d99 and 8ca00d0.

⛔ Files ignored due to path filters (11)
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_128x128.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_16x16.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_256x256.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_32x32.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_512x512.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png is excluded by !**/*.png
  • apps/mac/Lobu/Assets.xcassets/MenuBarIcon.imageset/lobster-mark.svg is excluded by !**/*.svg
📒 Files selected for processing (52)
  • .github/actions/setup-submodule/action.yml
  • .github/workflows/ci.yml
  • .github/workflows/mac-release.yml
  • .github/workflows/submodule-drift.yml
  • .gitmodules
  • AGENTS.md
  • apps/chrome/README.md
  • apps/chrome/SCOPE.md
  • apps/chrome/background.js
  • apps/chrome/bridge.js
  • apps/chrome/config.js
  • apps/chrome/manifest.json
  • apps/chrome/pairing.html
  • apps/chrome/pairing.js
  • apps/chrome/permissions.html
  • apps/chrome/permissions.js
  • apps/chrome/sidepanel.html
  • apps/chrome/sidepanel.js
  • apps/mac/Lobu.xcodeproj/project.pbxproj
  • apps/mac/Lobu.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  • apps/mac/Lobu.xcodeproj/xcshareddata/xcschemes/Lobu.xcscheme
  • apps/mac/Lobu/AppState.swift
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/Contents.json
  • apps/mac/Lobu/Assets.xcassets/Contents.json
  • apps/mac/Lobu/Assets.xcassets/MenuBarIcon.imageset/Contents.json
  • apps/mac/Lobu/BrowserProfileManager.swift
  • apps/mac/Lobu/BrowserProfilesView.swift
  • apps/mac/Lobu/ChromeBridgeHost.swift
  • apps/mac/Lobu/HealthKitSyncService.swift
  • apps/mac/Lobu/Info.plist
  • apps/mac/Lobu/KeychainTokenStore.swift
  • apps/mac/Lobu/KnowledgeKitReader.swift
  • apps/mac/Lobu/Lobu.entitlements
  • apps/mac/Lobu/LobuApp.swift
  • apps/mac/Lobu/LobuClient.swift
  • apps/mac/Lobu/LobuUpdater.swift
  • apps/mac/Lobu/LocalDirectorySyncService.swift
  • apps/mac/Lobu/LocalLobuRunner.swift
  • apps/mac/Lobu/MenuBarContent.swift
  • apps/mac/Lobu/OAuthClient.swift
  • apps/mac/Lobu/ObsidianVaultManager.swift
  • apps/mac/Lobu/PhotosSyncService.swift
  • apps/mac/Lobu/ScreenTimeSyncService.swift
  • apps/mac/Lobu/WhatsAppLocalSyncService.swift
  • apps/mac/sparkle/.gitignore
  • apps/mac/sparkle/README.md
  • apps/mac/sparkle/update-appcast.py
  • docs/plans/owletto.md
  • docs/plans/personal-mode-auth.md
  • packages/connectors/src/chrome_tabs.ts
  • packages/core/src/capabilities.ts
  • packages/web
💤 Files with no reviewable changes (42)
  • apps/mac/Lobu/Assets.xcassets/MenuBarIcon.imageset/Contents.json
  • apps/mac/Lobu/Lobu.entitlements
  • apps/mac/Lobu/Assets.xcassets/Contents.json
  • apps/mac/Lobu.xcodeproj/project.pbxproj
  • apps/mac/Lobu/BrowserProfileManager.swift
  • apps/chrome/SCOPE.md
  • apps/chrome/permissions.html
  • apps/chrome/bridge.js
  • apps/chrome/background.js
  • apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/Contents.json
  • apps/mac/Lobu/LobuApp.swift
  • apps/chrome/manifest.json
  • apps/mac/Lobu/Info.plist
  • apps/chrome/pairing.html
  • apps/mac/Lobu.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  • apps/mac/sparkle/.gitignore
  • apps/chrome/permissions.js
  • apps/chrome/config.js
  • apps/mac/Lobu/ObsidianVaultManager.swift
  • apps/mac/sparkle/update-appcast.py
  • .github/workflows/mac-release.yml
  • apps/chrome/README.md
  • apps/chrome/pairing.js
  • apps/mac/Lobu/KeychainTokenStore.swift
  • apps/mac/sparkle/README.md
  • apps/mac/Lobu.xcodeproj/xcshareddata/xcschemes/Lobu.xcscheme
  • apps/mac/Lobu/WhatsAppLocalSyncService.swift
  • apps/mac/Lobu/BrowserProfilesView.swift
  • apps/mac/Lobu/LocalLobuRunner.swift
  • apps/mac/Lobu/ChromeBridgeHost.swift
  • apps/mac/Lobu/PhotosSyncService.swift
  • apps/mac/Lobu/KnowledgeKitReader.swift
  • apps/mac/Lobu/AppState.swift
  • apps/chrome/sidepanel.js
  • apps/mac/Lobu/HealthKitSyncService.swift
  • apps/mac/Lobu/MenuBarContent.swift
  • apps/mac/Lobu/LobuUpdater.swift
  • apps/mac/Lobu/ScreenTimeSyncService.swift
  • apps/mac/Lobu/LocalDirectorySyncService.swift
  • apps/mac/Lobu/OAuthClient.swift
  • apps/mac/Lobu/LobuClient.swift
  • apps/chrome/sidepanel.html

Comment thread docs/plans/owletto.md Outdated
@@ -0,0 +1,506 @@
# Owletto
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Record this plan change in CLAUDE.md memory as a single sentence.

Please add a one-line memory entry capturing the Owletto repo split/local-first plan context.

As per coding guidelines "**/*.md: Add memory to CLAUDE.md as a single sentence when documenting important context`."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/owletto.md` at line 1, Add a single-sentence memory entry to
CLAUDE.md summarizing the Owletto plan change: state that the Owletto repo is
being split and adopting a local-first architecture (e.g., "Owletto repo split
and moving to a local-first plan"). Edit the CLAUDE.md file to append this
one-line sentence in the memory section so it matches the guideline for "*.md"
files.

Comment thread docs/plans/owletto.md Outdated
Comment thread docs/plans/owletto.md Outdated
Comment on lines +3 to +5
> **Note:** The Mac app + Chrome extension live in `lobu-ai/owletto` as of
> #TBD. Mac-side changes specified in this plan happen in that repo;
> server/gateway/auth changes (the majority of this plan) still happen here
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace #TBD with a concrete migration date or PR reference.

The top-level note currently leaves repo-move timing unresolved, which weakens this doc as an implementation reference.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/personal-mode-auth.md` around lines 3 - 5, Replace the placeholder
"`#TBD`" in the top-level note of docs/plans/personal-mode-auth.md with a concrete
migration reference: either the exact migration date (e.g., "2026-06-01") or a
specific PR/commit identifier (e.g., "PR `#1234`" or commit SHA) that documents
when the Mac app + Chrome extension moved to lobu-ai/owletto; update the
sentence so it reads clearly (e.g., "as of PR `#1234` (2026-06-01)"), ensuring the
change targets the note containing the string "`#TBD`".

Comment thread packages/web Outdated
The previous commit incorrectly deleted mac-release.yml under the assumption
that Mac releases would move to owletto. They can't: owletto is private, so
its GitHub Releases require auth to download, breaking the
releases/latest/download/Lobu.dmg pattern and the Sparkle appcast URL that
existing installed apps hardcode in Info.plist.

Keep mac-release.yml here (public) and reach the Mac source via the owletto
submodule:
  - Add the existing setup-submodule action so the deploy key clones owletto.
  - Update xcodebuild -project paths from apps/mac/Lobu.xcodeproj to
    packages/web/apps/mac/Lobu.xcodeproj.
  - Update the Sparkle update-appcast.py path similarly.
  - Header comment now documents the private-source-public-release split.

No secret migration needed — the workflow already runs in lobu where all the
Apple signing + Sparkle secrets live.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/mac-release.yml:
- Line 102: The workflow references the non-existent Xcode project
"Lobu.xcodeproj" in the mac-release.yml xcodebuild steps, which will cause the
job to fail; either ensure the mac submodule is initialized and contains the
expected Lobu.xcodeproj or update the mac-release.yml xcodebuild invocations to
point to the correct Xcode project/target in this repo (or skip the mac build
when the project is absent). Locate the xcodebuild command lines that reference
"Lobu.xcodeproj" and replace them with the actual project path/target used in
this repository, or add a pre-check step that verifies the project exists (and
exits with a clear message) before running xcodebuild so the workflow fails fast
and clearly if the submodule/project is missing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ba308462-3820-49e0-bd5c-e5fdbfe96e07

📥 Commits

Reviewing files that changed from the base of the PR and between 8ca00d0 and c1cdb94.

📒 Files selected for processing (1)
  • .github/workflows/mac-release.yml

Comment thread .github/workflows/mac-release.yml
@buremba
Copy link
Copy Markdown
Member Author

buremba commented May 17, 2026

Post-extraction verification

CodeQL Swift orphan

Disabled `swift` in the repo's CodeQL default-setup language list via API (now: `actions, javascript, javascript-typescript, python, typescript`). The `Analyze (swift)` CI job will no longer run.

Owletto brand mark

Shipped in `lobu-ai/owletto@f759d61` — `<··>` owl in the existing Lobu orange gradient (`#ff4b00` → `#ff8a1a`) for "Powered by Lobu" family kinship. The two-dot motif between the brackets is what makes it read as an owl face.

Files updated in owletto repo:

  • `apps/mac/Lobu/Assets.xcassets/AppIcon.appiconset/` — all 10 PNG sizes (16→1024).
  • `apps/chrome/icons/` — new dir with 16/32/48/128. `manifest.json` now declares `icons` and `action.default_icon`.
  • `public/favicon.svg`, `favicon.ico`, `apple-touch-icon.png`, `icon-192.png`, `icon-512.png`.
  • `public/site.webmanifest` — name + description rebranded to Owletto.

`lobu-og.png` (Open Graph share image, 1200×630) intentionally untouched — needs separate layout work for a wider format.

This PR's submodule pointer is bumped accordingly to include the brand-mark commit.

Mac release smoke test (workflow_dispatch on this branch, version=0.0.0-smoke)

Verified end-to-end that the path migration works:

Step Result
`setup-submodule` (deploy key clones renamed owletto repo)
`xcodebuild` from `packages/web/apps/mac/Lobu.xcodeproj`
Build DMG
Attach DMG to release
Sign update with Sparkle and publish appcast ❌ pre-existing on `main`

The Sparkle step failed identically on the most recent `main` run (May 14, run 25841148752 — same step, same ~1.5s timeout). Not introduced by this PR; a separate follow-up.

Draft release `lobu-v0.0.0-smoke` + tag deleted post-test.

Remaining truly out-of-scope follow-ups

  • Fix the Sparkle `Sign update` step (set +e debugging needed to find the real cause; appears upstream of my changes).
  • Update K8s deploy YAMLs inside `packages/web/deploy/` (in owletto repo) that still reference the old `owletto-web` URL.
  • M1 in owletto: make cloud signin optional in `apps/mac/Lobu/OAuthClient.swift`.
  • M0 in lobu: `LOBU_MODE=local`, local-CLI executor, PGlite production path.
  • Owletto-side Open Graph share image (`lobu-og.png` → `owletto-og.png` with new layout).

buremba added 2 commits May 17, 2026 02:47
Addresses pi review findings on PR #784:

1. Fail fast on stubbed submodule. setup-submodule writes a stub
   package.json when OWLETTO_WEB_DEPLOY_KEY is missing — fine for fork
   CI, catastrophic for a release. Make it fatal.
2. Assert packages/web origin URL resolves to lobu-ai/owletto. If
   .gitmodules drifts or the submodule URL changes, surface it before
   we publish an artifact from the wrong codebase.
3. Assert the Mac project + Info.plist paths actually exist at the
   pinned SHA. A silent rename inside owletto (lobster-mark.svg →
   owletto-mark.svg style) would otherwise only surface inside
   xcodebuild or sign_update.
4. Move scripts/sparkle/update-appcast.py back into lobu. Release
   infrastructure for a public-repo release pipeline shouldn't live
   in a private submodule where an owletto-side cleanup could silently
   delete it.
5. Update docs/plans/owletto.md to reflect the actual posture: owletto
   product (Mac app + Chrome extension + web SPA) is closed-source +
   private; Lobu engine stays Apache-2.0 OSS. The earlier "OSS / public
   repo" framing was from before we settled on closed product surface.
@buremba
Copy link
Copy Markdown
Member Author

buremba commented May 17, 2026

Pi review — applied + deferred

Ran `pi -p` on the PR. Triaged the 8 findings:

Fixed in this PR (commit `5ab5555`)

Pi #2 — fail fast on stubbed submodule. Mac release now hard-fails when `OWLETTO_WEB_DEPLOY_KEY` is missing/invalid, when `packages/web` origin doesn't resolve to `lobu-ai/owletto`, and when expected Mac paths don't exist at the pinned SHA. See `Verify release contract` step in `.github/workflows/mac-release.yml`.

Pi #3 — release infra in private submodule was fragile. Moved `update-appcast.py` to `scripts/sparkle/update-appcast.py` in this public repo. Owletto-side cleanup can no longer silently delete the release pipeline's script.

Pi #5 + #6 — submodule URL drift not asserted. The new `Verify release contract` step asserts `git -C packages/web config remote.origin.url` resolves to `lobu-ai/owletto.git` before any build step runs.

Pi #8 — plan doc contradicted reality. `docs/plans/owletto.md` now correctly says owletto product (Mac/extension/SPA) is closed-source + private, Lobu engine stays Apache-2.0 OSS. The earlier "new public OSS repo" framing was pre-decision.

Pi #4 — Sparkle smoke test was already done

Smoke test ran earlier on this branch (`gh workflow run` against the pinned SHA, version=0.0.0-smoke). Result: setup-submodule + xcodebuild + DMG + release-attach all ✅. Sparkle step failed identically to the May 14 run on `main` — pre-existing, not introduced by this PR. Documented in the post-extraction verification comment above.

Deferred (filed as follow-ups, not merge-blocking)

Pi #1 — `packages/web` submodule mount is mis-named now that it contains Mac + Chrome source. Renaming the mount path is its own ~50-file PR (every workflow, tsconfig exclude, script reference) and is best bundled with renaming `@lobu/web` inside the owletto repo. Tracked separately. The release-contract path checks now serve as the guardrail Pi suggested in the interim.

Pi #7 — owletto branch protection. Public lobu release pipeline now depends on a private repo never force-pushing or deleting `main`. Need to enable: no force-push on `main`, no branch deletion, and ideally a Mac-build CI job inside owletto on every PR. That's a GitHub settings change on the private repo, separate from this PR.

Net

The PR now hard-fails before doing anything destructive (or producing a wrong/empty release artifact) when the submodule contract drifts. Release infra is back in the public repo. Plan doc matches reality.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
docs/plans/owletto.md (3)

272-272: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifier to code block.

The directory tree code block is missing a language identifier. Add text after the opening backticks.

-```
+```text
 owletto/                   # private; renamed from owletto-web
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/owletto.md` at line 272, The markdown code block in
docs/plans/owletto.md is missing a language identifier; update the opening
triple-backtick for the directory tree to include the language tag "text" (i.e.,
change the backtick-only fence that precedes the line "owletto/                 
# private; renamed from owletto-web" to "```text") so the block is explicitly
marked as plain text.

114-114: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifier to code block.

The fenced code block is missing a language identifier, which violates markdown lint rules. Add text after the opening backticks.

-```
+```text
 ┌────────────────────────────────────────────────────────────────┐
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/owletto.md` at line 114, The fenced code block that begins with
``` before the ASCII box needs a language identifier to satisfy markdown
linting: change the opening fence from ``` to ```text so the block becomes a
text-code block (i.e., replace the opening triple-backticks for the ASCII-art
block with ```text).

192-202: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resolve the v1 LLM interrupt gate contradiction.

This section describes the LLM interrupt gate as a "first-class step, not a heuristic" that runs between watcher-fire and surface events. However, the v1 scope explicitly states "No LLM interrupt gate in v1" (Line 64), the v1.1 out-of-scope section says "Add the gate in v1.1 if precision is still bad" (Lines 90-92), and the resolved decisions confirm "No LLM interrupt gate in v1" (Line 483).

The contradiction creates ambiguity about:

  • Whether v1 implementation must include this gate
  • What "per-watcher cooldowns + daily interrupt budget" (Line 64) means if the gate is also present
  • Timeline and scope boundaries for M3-M5 milestones

Either remove this section entirely and move it to a "V2 Architecture" heading, or reconcile the v1 scope to explicitly include a lightweight local LLM gate and update Lines 64, 90-92, and 483 accordingly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/owletto.md` around lines 192 - 202, The "Proactive precision: the
'should this interrupt' gate" section conflicts with stated v1 scope; either
remove/move this section to a V2 Architecture chapter or reconcile the v1 scope
to include a lightweight local LLM gate. If you choose removal: delete this
section and add a brief pointer in v2 architecture that describes the gate. If
you choose reconciliation: update the "v1 scope" paragraph, the "v1.1
out-of-scope" note, and the "resolved decisions" entry to explicitly state a
lightweight local LLM gate will run before surfacing (describe it as
Haiku-tier/local-only, used only for interrupt filtering alongside per-watcher
cooldowns and daily interrupt budget), and clarify timeline/milestone placement
for M3–M5.
🧹 Nitpick comments (1)
docs/plans/owletto.md (1)

313-313: 💤 Low value

Consider clearer phrasing for signin work.

The term "unmandatory-signin work" is awkward. Consider "make-signin-optional work" or "optional-signin work" for clarity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/owletto.md` at line 313, Replace the awkward phrase
"unmandatory-signin" with a clearer term like "optional-signin" (or
"make-signin-optional") throughout the plan text; search for the exact token
"unmandatory-signin" and update occurrences in the docs/plans/owletto.md content
and branch instructions so the intent reads clearly (e.g., "Cut a branch in this
repo that completes the optional-signin work").
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/plans/owletto.md`:
- Around line 159-165: The text is ambiguous about where the LocalSurface
adapter should live and how it integrates with gateway routing; update the doc
to state that LocalSurface is a distinct adapter placed in a new sibling
directory (e.g., packages/server/src/gateway/surfaces/) rather than inside
packages/server/src/gateway/connections/, and describe that it implements a
separate interface (LocalSurface) that the gateway recognizes alongside
Connection types; explain that the gateway's event router should treat
LocalSurface events by matching on a surface identity field (e.g., surfaceId)
and applying surface-specific filters (rather than channel/reply/history
semantics) so routing logic in the gateway checks event.source.type === 'local'
or event.surfaceId to dispatch to LocalSurface handlers without inheriting
chat-platform assumptions.

---

Duplicate comments:
In `@docs/plans/owletto.md`:
- Line 272: The markdown code block in docs/plans/owletto.md is missing a
language identifier; update the opening triple-backtick for the directory tree
to include the language tag "text" (i.e., change the backtick-only fence that
precedes the line "owletto/                   # private; renamed from
owletto-web" to "```text") so the block is explicitly marked as plain text.
- Line 114: The fenced code block that begins with ``` before the ASCII box
needs a language identifier to satisfy markdown linting: change the opening
fence from ``` to ```text so the block becomes a text-code block (i.e., replace
the opening triple-backticks for the ASCII-art block with ```text).
- Around line 192-202: The "Proactive precision: the 'should this interrupt'
gate" section conflicts with stated v1 scope; either remove/move this section to
a V2 Architecture chapter or reconcile the v1 scope to include a lightweight
local LLM gate. If you choose removal: delete this section and add a brief
pointer in v2 architecture that describes the gate. If you choose
reconciliation: update the "v1 scope" paragraph, the "v1.1 out-of-scope" note,
and the "resolved decisions" entry to explicitly state a lightweight local LLM
gate will run before surfacing (describe it as Haiku-tier/local-only, used only
for interrupt filtering alongside per-watcher cooldowns and daily interrupt
budget), and clarify timeline/milestone placement for M3–M5.

---

Nitpick comments:
In `@docs/plans/owletto.md`:
- Line 313: Replace the awkward phrase "unmandatory-signin" with a clearer term
like "optional-signin" (or "make-signin-optional") throughout the plan text;
search for the exact token "unmandatory-signin" and update occurrences in the
docs/plans/owletto.md content and branch instructions so the intent reads
clearly (e.g., "Cut a branch in this repo that completes the optional-signin
work").
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4fbe1390-13c8-4ba4-86ce-128402a685ce

📥 Commits

Reviewing files that changed from the base of the PR and between 5146d48 and 5ab5555.

📒 Files selected for processing (3)
  • .github/workflows/mac-release.yml
  • docs/plans/owletto.md
  • scripts/sparkle/update-appcast.py

Comment thread docs/plans/owletto.md Outdated
Comment on lines +159 to +165
3. **`LocalSurface` adapter (not a chat-platform connection).** Mac
canvas + native notifications are an event/UI bus, not a chat
transport. Forcing them through the existing chat-platform connection
abstraction would leak chat assumptions (channels, replies,
histories) into the surface. Define a parallel `LocalSurface`
adapter alongside `packages/server/src/gateway/connections/` —
filters on its own surface identity, no chat-shaped contract.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Clarify LocalSurface adapter placement and integration.

The phrasing "alongside packages/server/src/gateway/connections/" is ambiguous when the text also states it's NOT a chat-platform connection. Should LocalSurface live:

  • Inside packages/server/src/gateway/connections/ as a parallel adapter type?
  • In a sibling directory like packages/server/src/gateway/surfaces/?
  • Somewhere else entirely?

Additionally, specify how "filters on its own surface identity" integrates with the existing gateway event routing without inheriting chat-platform assumptions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/owletto.md` around lines 159 - 165, The text is ambiguous about
where the LocalSurface adapter should live and how it integrates with gateway
routing; update the doc to state that LocalSurface is a distinct adapter placed
in a new sibling directory (e.g., packages/server/src/gateway/surfaces/) rather
than inside packages/server/src/gateway/connections/, and describe that it
implements a separate interface (LocalSurface) that the gateway recognizes
alongside Connection types; explain that the gateway's event router should treat
LocalSurface events by matching on a surface identity field (e.g., surfaceId)
and applying surface-specific filters (rather than channel/reply/history
semantics) so routing logic in the gateway checks event.source.type === 'local'
or event.surfaceId to dispatch to LocalSurface handlers without inheriting
chat-platform assumptions.

buremba added 2 commits May 17, 2026 03:17
Plan was an owletto product/strategy doc, not a Lobu engine plan.
Moved to lobu-ai/owletto:docs/owletto-plan.md so it lives next to the
code it describes (private, matches the rest of owletto's posture).

Also bumps submodule pointer to pick up the relocated doc commit.
buremba added 2 commits May 17, 2026 03:29
Pi second-pass found that 'set -x' at the top of the Sparkle step traces
through the SPARKLE_ED_PRIVATE_KEY file write + sign_update invocation
+ the gh-pages clone URL containing GITHUB_TOKEN. GitHub Actions masks
known secret strings in logs but we shouldn't rely on that masking for
release correctness.

Toggle xtrace selectively: on around curl/tar/sign_update path checks
and around the python appcast script invocation; off around the key-file
write, the sign_update execution, and the token-bearing git clone.
@buremba
Copy link
Copy Markdown
Member Author

buremba commented May 17, 2026

Final state — ready to merge

Pi second-pass review

Found one new issue: `set -x` traced through SPARKLE_ED_PRIVATE_KEY handling + GITHUB_TOKEN-bearing git clone URL. Fixed in commit `87a517f` — xtrace now toggles off around the key file write, sign_update invocation, and gh-pages clone.

All commits on this branch

  1. `8ca00d0` — chore: extract apps/mac + apps/chrome to lobu-ai/owletto
  2. `c1cdb94` — ci(mac-release): keep workflow in lobu, source via submodule
  3. `5146d48` — chore(submodule): bump owletto for rebrand commits
  4. `5ab5555` — ci(mac-release): release contract checks; move appcast script in-repo
  5. `20f8002` — docs: drop owletto plan; lives in owletto repo now
  6. `cd4e6d6` — ci(mac-release): set -x in Sparkle step for diagnostics
  7. `9896f6f` — chore(submodule): bump owletto for single-instance fix
  8. `87a517f` — ci(mac-release): keep xtrace off around secret handling

Deferred items — all filed as issues

Owletto repo follow-ups landed in tandem

  • Brand mark (`<·>` owl, orange gradient) shipped to `lobu-ai/owletto`: AppIcon (10 sizes), Chrome extension icons, web favicon, site.webmanifest, index.html.
  • Full Mac app string rebrand: CFBundleName + CFBundleDisplayName → "Owletto", three NS*UsageDescription permission prompts, all user-facing copy in MenuBarContent/LobuApp/AppState/KnowledgeKitReader/WhatsAppLocalSyncService/LocalLobuRunner/OAuthClient. Engine/keychain/env-var contracts intentionally untouched.
  • Single-instance enforcement in LobuApp.init — fixes the duplicate-launch "signed out" UX bug.
  • Strategy plan moved to `lobu-ai/owletto:docs/owletto-plan.md`.

CI

All substantive checks green: typecheck, unit, frontend, build-test, check-drift, format-lint, Security tests (bun + vitest), Static security guards, CodeQL, Analyze (actions/js-ts/python), CodeRabbit, pr-title. Three red checks (integration, migrations, pr-size) are pre-existing on `main` and tracked separately.

Smoke test

`mac-release.yml` triggered against the pinned SHA: submodule init ✅, xcodebuild from `packages/web/apps/mac/` ✅, DMG build ✅, release attach ✅. Sparkle step fails for the unrelated credential reason in #788.

Merging with `--squash --admin` per the established workflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants