Skip to content

Stabilize GUI project API polling#264

Merged
TraderSamwise merged 7 commits into
masterfrom
chore/gui-smoke-next-8
Jun 28, 2026
Merged

Stabilize GUI project API polling#264
TraderSamwise merged 7 commits into
masterfrom
chore/gui-smoke-next-8

Conversation

@TraderSamwise

@TraderSamwise TraderSamwise commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • add URL-scoped app project reads and the /inbox alias uncovered by GUI smoke testing
  • keep route project reconciliation stable to avoid unnecessary chat/event reconnects
  • make daemon /projects polling use registered project snapshots and project-id endpoint reads instead of repeated topology/git scans
  • keep restart dashboard reloads scoped by known project roots so stale dashboard owner metadata does not block repair

Verification

Summary by CodeRabbit

  • New Features
    • Added an Inbox entry point that redirects to Notifications and preserves relevant filters.
  • Bug Fixes
    • Improved project/endpoint context consistency across the Dashboard, Graveyard, Plans, Threads, Coordination, Library, Topology, Project, and related screens—especially when a project is present in the URL.
    • Reduced redundant updates and added service liveness caching to make project listing and refresh behavior more stable.
  • Tests
    • Expanded automated coverage for project reconciliation, daemon routing, service liveness caching behavior, and post-restart verification.

@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 28, 2026 9:54pm

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@TraderSamwise, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 11 minutes and 28 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5d2b8f38-6928-4553-af23-9832e1bd23aa

📥 Commits

Reviewing files that changed from the base of the PR and between 3510a5f and 7536fd8.

📒 Files selected for processing (12)
  • app/app/(main)/(tabs)/(threads)/threads.tsx
  • app/app/(main)/(tabs)/coordination/index.tsx
  • app/app/(main)/(tabs)/library/index.tsx
  • app/app/(main)/(tabs)/project/index.tsx
  • app/app/(main)/(tabs)/topology/index.tsx
  • app/components/WorktreeDashboard.tsx
  • app/components/screens/AgentChatScreen.tsx
  • app/components/screens/ServiceDetailScreen.tsx
  • app/stores/projects.test.ts
  • app/stores/projects.ts
  • src/project-scanner.test.ts
  • src/project-scanner.ts
📝 Walkthrough

Walkthrough

Adds a route-based project resolver, migrates screens and shared components to it, introduces an inbox redirect route, preserves project list identity during reconciliation, and updates daemon project listing to use cached liveness and metadata lookup. It also changes restart verification for dashboard ownership and caches the tmux session prefix.

Changes

App: useRouteProject hook, screen migration, inbox alias, and project reconciliation

Layer / File(s) Summary
useRouteProject hook contract and implementation
app/lib/use-route-project.ts
Defines RouteProject and useRouteProject(), which reads the route project param, looks up the project in projectsAtom, falls back to selectedProjectAtom, computes endpoint, and returns a memoized result object.
reconcileProjectList optimization and tests
app/stores/projects.ts, app/stores/projects.test.ts
Adds reconcileProjectList that returns the previous array reference when project snapshots are identical; updates reconcileProjectsAtom to use it and to write atoms only when values change; adds tests for reference preservation and sorted replacement.
Screens migrated from Jotai atoms to useRouteProject
app/app/(main)/(tabs)/(dashboard)/graveyard.tsx, app/app/(main)/(tabs)/(dashboard)/plans/[sessionId].tsx, app/app/(main)/(tabs)/(threads)/threads.tsx, app/app/(main)/(tabs)/(coordination)/index.tsx, app/app/(main)/(tabs)/(library)/index.tsx, app/app/(main)/(tabs)/(project)/index.tsx, app/app/(main)/(tabs)/(topology)/index.tsx, app/app/(main)/(tabs)/(inbox)/notifications/index.tsx, app/components/WorktreeDashboard.tsx, app/components/screens/AgentChatScreen.tsx, app/components/screens/ServiceDetailScreen.tsx
Replaces selectedProjectAtom, selectedProjectEndpointAtom, and getProjectServiceEndpoint with useRouteProject() across screens and shared components, shifting project and endpoint resolution to the route hook.
Inbox alias route and dashboard index search param
app/app/inbox.tsx, app/app/_layout.tsx, app/app/(main)/(tabs)/(dashboard)/index.tsx
Adds InboxAlias redirecting /inbox to /notifications with forwarded project and lens params; registers the inbox stack screen with headerShown: false; updates DashboardIndex to read the project search param and incorporate it into the redirect target.

Daemon: project scanner, metadata store, liveness/route caching, runtime-restart, tmux prefix

Layer / File(s) Summary
Project scanner refactoring and metadata-store ID-based lookup
src/project-scanner.ts, src/metadata-store.ts
Adds listRegisteredDesktopProjects() using shared hide-rule and tmux-prefix helpers; updates listDesktopProjects() to precompute temp dirs; adds loadMetadataEndpointByProjectId() for project-ID-based endpoint file resolution.
Daemon liveness cache and /projects route cache
src/daemon.ts, src/daemon.test.ts
Adds per-project liveness caching and routes /projects through a helper that builds project entries from registered desktop projects, cached liveness, and metadata-loaded service endpoints; invalidates cached state on spawn, exit, replace, stop, and shutdown; updates GET /projects to return the helper output.
Runtime-restart: remove ownership-aware dashboard repair logic
src/runtime-restart.ts, src/runtime-restart.test.ts
Removes expectedRuntimeOwner from projectNeedsCurrentRuntimeRepair, changes dashboard selection to rely on dashboard presence, updates the post-restart verification call site, and expands tests for foreign-owned dashboard reload and stale-dashboard failure.
TmuxRuntimeManager: memoize session prefix
src/tmux/runtime-manager.ts
Adds sessionPrefixCache, refactors getProjectSession() to use getSessionPrefix(), and memoizes the tmux prefix with an aimux fallback on error.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • TraderSamwise/aimux#42: Overlaps with the topology screen routing changes, since both alter how route state determines the active project and endpoint.
  • TraderSamwise/aimux#255: Overlaps with the runtime-restart verification flow in src/runtime-restart.ts, especially dashboard repair and post-restart coherence behavior.

Poem

🐇 I hop by routes and cache the trail,
The inbox turns without a fail.
New project paths align just so,
While daemon winds and tmux winds know.
A carrot toast to hooks that steer —
The burrow’s tidy now, my dear! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the main theme of stabilizing GUI project polling and project-scoped routing changes.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/gui-smoke-next-8

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

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 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 `@app/app/`(main)/(tabs)/project/index.tsx:
- Line 214: The routed project query is being dropped when section links are
rebuilt because this screen only reads project from useRouteProject(), so a
pending URL project= can be lost before the list resolves. Update the project
screen to also use the stable projectPath exposed by useRouteProject(), and make
the link-building logic preserve that path instead of reconstructing /project
from the selected project fallback. Focus on the useRouteProject() destructuring
and the section-link builder that currently rebuilds the URL.

In `@app/app/inbox.tsx`:
- Around line 5-7: The browserSearchValue() helper is using
window.location.search in a shared route, which is not safe for native
rendering. Update inbox.tsx to read project and lens from
useGlobalSearchParams() instead, then pass those values through
cleanSearchValue() so the route works consistently without relying on window.

In `@app/components/screens/AgentChatScreen.tsx`:
- Around line 72-75: The plans navigation from AgentChatScreen is only carrying
sessionId, so it can lose the route-resolved project context. Update the
push/navigation call in AgentChatScreen to forward projectPath alongside
sessionId, using the projectPath obtained from useRouteProject(), so the plans
screen stays scoped to the same project even when the stored selection differs.

In `@app/components/screens/ServiceDetailScreen.tsx`:
- Around line 49-52: `goBack()` in `ServiceDetailScreen` should use the
route-stable `projectPath` instead of `project?.path` so back navigation stays
tied to the current route. Update the navigation logic in `goBack` to read from
`useRouteProject()`’s `projectPath` (with the existing fallback behavior if
needed) and ensure the query param is preserved when the project record in
`projectsAtom` has not loaded yet.

In `@app/components/WorktreeDashboard.tsx`:
- Around line 581-585: The dashboard detail navigation handlers in
WorktreeDashboard should use the routed projectPath consistently instead of
project?.path, since the atom state is already keyed by projectPath and the
unresolved-route case can lose the project query param. Update the route changes
in the detail handlers (the ones that navigate to the next screen) to pass
projectPath from useRouteProject() so the destination stays bound to the current
routed project rather than falling back to selection.

In `@app/stores/projects.ts`:
- Around line 82-90: The reconcileProjectList() sort is not deterministic when
multiple DaemonProject entries share the same name, causing unstable ordering
and unnecessary snapshot churn. Update the sorting logic in
reconcileProjectList() to use a stable tie-breaker after name (for example, a
unique project identifier or other deterministic field available on
DaemonProject) so duplicate names always sort the same way. Keep the comparison
logic in sameProjectSnapshot() and the index-by-index reconciliation behavior
unchanged, but ensure the sorted array order is fully deterministic before
comparing previous and incoming lists.

In `@src/project-scanner.ts`:
- Around line 52-55: The tmux prefix is being computed once from the daemon’s
current cwd instead of per project, which makes `dashboardSessionName` incorrect
for repos with different local config. Update `getConfiguredTmuxSessionPrefix`
to take a project root (or repo root) and pass that through to `loadConfig()`,
then have `listDesktopProjects()` and any other callers derive the session
prefix from each `entry.repoRoot` so the published dashboard session matches the
project’s own config.
- Around line 43-49: The path check in shouldHideDesktopProject is too broad
because projectPath.startsWith(tmpDir) can match sibling directories like
/tmp-foo; update the temp-project detection to use a path-boundary-aware
comparison, such as relative path logic or a separator-aware prefix check. Keep
the existing basename and aimux- prefix behavior, but ensure only projects
actually under the hidden temp dirs are filtered.
🪄 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

Run ID: c6bfb631-45c2-4ddb-bfaf-4025ee531c67

📥 Commits

Reviewing files that changed from the base of the PR and between f09689f and 2071cda.

📒 Files selected for processing (24)
  • app/app/(main)/(tabs)/(dashboard)/graveyard.tsx
  • app/app/(main)/(tabs)/(dashboard)/index.tsx
  • app/app/(main)/(tabs)/(dashboard)/plans/[sessionId].tsx
  • app/app/(main)/(tabs)/(inbox)/notifications/index.tsx
  • app/app/(main)/(tabs)/(threads)/threads.tsx
  • app/app/(main)/(tabs)/coordination/index.tsx
  • app/app/(main)/(tabs)/library/index.tsx
  • app/app/(main)/(tabs)/project/index.tsx
  • app/app/(main)/(tabs)/topology/index.tsx
  • app/app/_layout.tsx
  • app/app/inbox.tsx
  • app/components/WorktreeDashboard.tsx
  • app/components/screens/AgentChatScreen.tsx
  • app/components/screens/ServiceDetailScreen.tsx
  • app/lib/use-route-project.ts
  • app/stores/projects.test.ts
  • app/stores/projects.ts
  • src/daemon.test.ts
  • src/daemon.ts
  • src/metadata-store.ts
  • src/project-scanner.ts
  • src/runtime-restart.test.ts
  • src/runtime-restart.ts
  • src/tmux/runtime-manager.ts

Comment thread app/app/(main)/(tabs)/project/index.tsx Outdated
Comment thread app/app/inbox.tsx Outdated
Comment thread app/components/screens/AgentChatScreen.tsx
Comment thread app/components/screens/ServiceDetailScreen.tsx Outdated
Comment thread app/components/WorktreeDashboard.tsx Outdated
Comment thread app/stores/projects.ts
Comment thread src/project-scanner.ts
Comment thread src/project-scanner.ts Outdated
@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/daemon.ts (1)

723-730: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Only expose endpoints that match the live service.

loadMetadataEndpointByProjectId(project.id) can return a stale metadata file for an old pid while serviceAlive is computed from the current ProjectServiceState. That can make /projects advertise a live/current service with an endpoint for a different or dead process. Gate the endpoint by the live service pid and null it when the service is not alive.

Proposed fix
     return listRegisteredDesktopProjects().map((project) => {
       const service = servicesById[project.id] ?? null;
       const serviceAlive = service ? this.isProjectServiceLive(service) : false;
+      const metadataEndpoint = service && serviceAlive ? loadMetadataEndpointByProjectId(project.id) : null;
       return {
         ...project,
         service: serviceAlive ? service : null,
         serviceAlive,
-        serviceEndpoint: loadMetadataEndpointByProjectId(project.id),
+        serviceEndpoint: metadataEndpoint?.pid === service?.pid ? metadataEndpoint : null,
       };
     });
🤖 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 `@src/daemon.ts` around lines 723 - 730, The `/projects` response is exposing a
metadata endpoint even when it may belong to a stale or dead process; update the
project mapping in `src/daemon.ts` so the `serviceEndpoint` is only returned
when it matches the currently live `ProjectServiceState` for that project. Use
the existing `service`, `serviceAlive`, and `loadMetadataEndpointByProjectId`
logic in the same return object, and add a pid/liveness check so the endpoint is
nulled whenever the live service is absent or does not match the current pid.
🤖 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.

Outside diff comments:
In `@src/daemon.ts`:
- Around line 723-730: The `/projects` response is exposing a metadata endpoint
even when it may belong to a stale or dead process; update the project mapping
in `src/daemon.ts` so the `serviceEndpoint` is only returned when it matches the
currently live `ProjectServiceState` for that project. Use the existing
`service`, `serviceAlive`, and `loadMetadataEndpointByProjectId` logic in the
same return object, and add a pid/liveness check so the endpoint is nulled
whenever the live service is absent or does not match the current pid.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 834646d2-0c0e-4fb7-a78f-9fc8a03172ff

📥 Commits

Reviewing files that changed from the base of the PR and between 2071cda and 3510a5f.

📒 Files selected for processing (3)
  • app/app/inbox.tsx
  • src/daemon.test.ts
  • src/daemon.ts

@TraderSamwise

Copy link
Copy Markdown
Owner Author

Independent reviewer finding triage: app/lib/use-route-project.ts invalid project= query handling.

By design. projectPath intentionally preserves the routed path even before projectsAtom has resolved, so deep links do not silently jump to the currently selected project. If a route points at a truly unknown project, showing no endpoint/no selected project is safer than mutating operations onto another project.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

Independent reviewer finding triage: src/daemon.ts retained service liveness cache and theoretical PID reuse.

By design for this PR. Cached true entries still call isPidAlive() on every /projects read and are scoped to the same pid for only 30s; re-running full command-line identity checks on every GUI poll would bring back the latency this PR removes. Daemon-owned child services remain verified by child tracking, and stale retained services are revalidated after the short cache window.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise
TraderSamwise merged commit 9ae5df6 into master Jun 28, 2026
3 checks passed
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.

1 participant