Phase 1 is pure reach: the code to copy a single Foundation layer already exists, it is just unreachable from the surfaces where layers are actually listed. One reusable menu fragment, attached in five places. Phase 2 is a deletion: the menu bar tray goes, and so does the notification queue, the git polling timer, and the five services that fed them — because leaving those running with no surface would be write-only dead code.
The problem
Phase 1. Copying one layer’s content to the clipboard is only
reachable from inside that layer’s own edit/preview page
(LayerExportMenu / CompactExportButton). From the surfaces where
layers are listed — dashboard widget, Foundation hub, Foundation Review —
the only clipboard action is the full-foundation export, or a file-writing
“Export as Markdown”. There is no right-click → copy this one layer.
Phase 2. The tray icon had stopped earning its place, but it was not
just an icon: it hosted a whole notification center
(MenuBarNotificationQueue, persisted to Application Support) fed by five
services, plus a five-minute git polling timer.
Approach
One menu fragment, five attachment points
FoundationExportService.shared.export(layer:manager:format:projectName:)
already returns markdown, a short overview, or JSON for any single layer. Only the UI
entry points are missing — so the work is one reusable
FoundationLayerCopyMenuItems plus a
.foundationLayerCopyMenu(…) View extension, attached to every layer row
rather than five bespoke menus that drift apart.
Full removal, not a hidden icon
Hiding the tray would leave the queue, the timer, and five posting services running
with nothing to display. The plan verified each signal still has an in-app surface before
deleting: the five standup sites all set reachedNaturalEnd + save, which
drives the in-meeting banner, and MockupDeliveryService also calls
NotificationService.notify.
Normalized JSON, consistent with the rest of the app
.json re-encodes the in-memory Codable model, not the raw
.claude/context/<layer>.json file. For layers whose decoders drop unknown
fields this is a normalized view rather than a byte-copy of disk. That matches existing
“Copy as JSON” behavior elsewhere, so the plan keeps it rather than making one
menu special.
Decisions made for you
The commit nudge goes away entirely
Every other tray signal — mockup-ready, mockup-delivered, meeting-pending-response, guide tips — was confirmed to have another in-app surface. The commit nudge had none, and it is cut rather than rehomed. That is the intended trade, not an oversight.
Session Bar Show/Hide relocated to General Settings
The tray popover held the only Show/Hide control for the Session Identity Bar. Settings has an enable toggle, but once the bar was user-dismissed only the tray could bring it back — so removing the tray would have stranded it. A Show/Hide control moves into General Settings in the same phase.
The work
Phase 1 — Right-click copy for a single Foundation layer
5 tasks Additive; independent of Phase 2.- Add
Code Raven/Views/Foundation/FoundationLayerCopyMenu.swiftwithFoundationLayerCopyMenuItems(Copy as Markdown / Copy Summary / Copy as JSON) and a.foundationLayerCopyMenu(...)View extension - Attach copy items to the existing per-layer context menu in
CompactFoundationWidget.compactLayerCell - Add a context menu to
LayerConfigCard(Foundation hub rows) when the layer has data - Add a context menu to
LayerReviewSectionheader and fold JSON into its inline Share menu (FoundationReviewView) - Add a context menu to the
LayerPreviewFullPageheader title so the Features layer — which has no export button — is covered too
Phase 2 — Remove the macOS menu bar tray icon
9 tasks Deletions land together; the build gate is the last task.- Delete
MenuBarController.swift,MenuBarNotificationQueue.swift,MenuBarCommitNudgeMonitor.swift,MenuBarDeepLinkRouter.swift,Models/MenuBarNotification.swift,Views/MenuBar/MenuBarNotificationPopover.swift - Move
Notification.Name.navigateToProjectTabtoExtensions/NotificationNames.swift(theAppMainViewlistener stays; it now has no poster) - Remove
menuBarControllerandMenuBarCommitNudgeMonitorstart/stop fromCode_RavenApp.swift - Remove the five
MenuBarNotificationQueue.postsites inStandupMeetingService.swift - Remove the post sites in
MockupAIService.swift,MockupDeliveryService.swift,LivingGuideStore.swift - Remove
markViewedByTypecalls inLivingGuideView,StandupMeetingView,MockupStudioContainerView - Remove the “Menu bar notifications” toggle from
GeneralSettingsViewand add a Session Bar Show/Hide control - Delete the
MenuBarIcon.imagesetasset xcodebuild -scheme "Code Raven" -destination 'platform=macOS' buildgreen
Manual testing
5 tasks Yours — excluded from progress.- Right-click a layer in the dashboard Foundation widget → Copy as Markdown / JSON, paste and confirm content is that layer onlyyou
- Right-click a layer row in the Foundation hub and in Foundation Review → sameyou
- Right-click the Features layer header in its preview page → copy works there tooyou
- Confirm no Code Raven icon appears in the macOS menu bar after relaunchyou
- Dismiss the Session Bar, then re-show it from General Settingsyou
Risks & edge cases
Normalized JSON is not a byte-copy
If you copy a layer as JSON expecting to paste it back over
.claude/context/<layer>.json, any field the decoder does not know about
is silently gone. Fine for reading and for handing to another model; wrong for
round-tripping a file.
Phase 2 is not reversible in place
Six files are deleted outright. Restoring the tray later means restoring the queue, the persistence, the deep-link router, and the five post sites — recoverable from git, but not a toggle.
A listener with no poster
navigateToProjectTab survives the deletion and moves to
NotificationNames.swift, but nothing posts it any more. It is harmless and
may well be wanted again — it is also exactly the kind of thing that reads as live
wiring six months from now.
Final review
The two halves are well matched to their own logic. Phase 1 resists the obvious shortcut — five separate context menus — in favor of one fragment attached five times, which is the difference between a change that stays consistent and one that drifts. Phase 2’s strength is that it did the surface audit before deleting rather than discovering the gap afterward, and it caught the Session Bar regression, which is the non-obvious casualty of removing the tray.
Where it is weakest: batching two unrelated tasks into one plan means the Chronicle
record and any checkin summary describe a change with no single theme, and the Manual
Testing section mixes verification for both. That is a legibility cost, not a correctness
one. The stranded navigateToProjectTab listener is the one loose thread worth
a comment in the file.
High on approach: the shared-fragment choice and the pre-deletion surface audit are both the right calls, and the accepted losses are named rather than hidden. Held back from higher by the batching, which makes the plan harder to review as one thing than either half would have been alone.