Repository navigation
Give the buddy a map of the app: get_app_guide - #301
Conversation
The backend's new get_app_guide tool answers "where do I…" questions about the app itself. Two things make its answers usable here: - streamMessage sends the pathname the dock is floating over as currentPage, so "what can I do on this page?" has a "this page". - Root-relative links in a buddy reply navigate in place instead of reloading the app in a new tab (same change as on the 311 branch, so the two merge cleanly). Plus a status label for the tool while it runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The buddy's map of the app (get_app_guide) lives in the backend's AppGuide.kt. appGuideRoutes.ts mirrors its route list, and a test fails when accessPolicy.ts has a route that is neither described there nor excluded on purpose — so a new page trips CI in the repo it was added in. accessPolicy.ts exports APP_ROUTES for it; AGENTS.md says to keep the guide in step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The buddy links to /admin?tab=projects in place. The tab parameter was only read on mount, so somebody already on the page kept their tab while the parameter sat in the URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wledge # Conflicts: # AGENTS.md # src/auth/accessPolicy.ts # src/pages/AdminPage.tsx
…wledge # Conflicts: # src/pages/AdminPage.tsx # tests/unit/pages/AdminPage.test.tsx
kiranfin
left a comment
There was a problem hiding this comment.
Review
The change is small and well scoped: currentPage is read at send time rather than through useLocation, APP_ROUTES replaces the duplicated Object.keys(...), and the omit-if-absent request body is covered by a service test. I also checked the parts that live in the other repo. APP_GUIDE_ROUTES mirrors the page order of AppGuide.kt, and the tab/view labels the guide quotes exist in the frontend. The deep links the guide emits (/team-management?tab=roles, /hire-setup?tab=arrival|starter, /insights/knowledge-requests?view=answered) already derive their state live from the URL, so AdminPage was indeed the only page that needed to follow ?tab= in place. I ran appGuideRoutes, buddyService and AdminPage tests against the branch and they pass. The remaining concerns are a UI inconsistency in the new tab-follow path and a blind spot in the new coverage tripwire.
🟡 Worth a look
-
A
?tab=link followed while the page is open bypasseshandleTabChange, so an open drawer stays on top of the new tab —src/pages/AdminPage.tsx:111-120,src/pages/AdminPage.tsx:699-707
The render-phase adjustment callssetActiveTab(requestedTab)directly. Every user-driven switch goes throughhandleTabChange, which first clearsopenUserMenuIdand closes an open drawer (closeDetails()). The drawers are rendered fromselectedUser/selectedProject/selectedSkill, independent ofactiveTab. The buddy dock is non-modal, so this is reachable: open a user on Users, then click a buddy link to/admin?tab=projects. The tab changes underneath, but the user drawer (and its backdrop) stays open over Projects. I reproduced this with a throwaway test: after the tab followed, "John Details" was still rendered.closeDetailsschedules a timeout, so it cannot simply be called from the render-phase block; handle the close in the effect (or route the URL-driven change through the same function ashandleTabChange) and add a regression test with a drawer open. -
The coverage tripwire cannot see routes that are not in
routePermissions—src/features/buddy/appGuideRoutes.ts:80-105,src/router/AppRouter.tsx
appGuideRoutes.test.tscompares the guide againstAPP_ROUTES, i.e.Object.keys(routePermissions).AppRouteralso registers/skill-wizard, which has noroutePermissionsentry. A new page added the same way would pass CI with no decision about the guide, which is exactly what the PR title ("Fail CI when a page is added without a decision") promises to prevent./skill-wizardis currently the example the backend tests use for "a page this guide does not describe", so nothing records that decision on this side.APP_GUIDE_EXCLUDED_ROUTESis typedPartial<Record<AppRoute, string>>, so it cannot hold such a route either. Either widen the check to the router's actual paths or state the limitation in the test and inFRONTEND_ARCHITECTURE.md§4.3 (which currently reads as full coverage).
🟢 Nits / cleanup
- The new test only covers Users → Projects with no drawer open. Missing cases: a drawer open while the link arrives (finding 1), the same link followed twice (the render-phase comment says this is why
handledTabexists), and?tab=skillsfollowed by a non-ADMIN (the existing test only covers it on mount). - Nothing asserts that
useBuddyConversationactually passeswindow.location.pathname. The newbuddyServicetest callsstreamMessagedirectly, andBuddyComposerIsolationonly readsmock.calls[0][0]. Dropping the new argument in the hook would not fail any test. - Stale doc comments in
AdminPage.tsx: the component docblock (~line 69) still says?tab=projects"opens the page on that tab once", and the?tab=comment still says it "seeds the tab once and is then stripped". Both now contradict the added paragraph. ?projectId=/?userId=are still handed off only on mount. With/admin?tab=projects&projectId=p1followed while open, the tab switches butprojectIdstays in the URL and the drawer does not open (and a reload would then open it). That matches the comment, but the existing test name "without leaving anything in the URL" is only true on mount.
Overall this is a clean, low-risk PR. I would fix finding 1 before merge, since it is cheap and the buddy dock makes it easy to hit. Finding 2 can be fixed here or accepted as a documented limitation.
…wledge # Conflicts: # src/services/buddyService.ts
Short summary
Frontend half of the buddy's app guide (
get_app_guidein the backend): the buddy learns which page the user is on, and the app guide's coverage is guarded from this repo.currentPage: every buddy message sendswindow.location.pathname, so "what can I do here?" is answered for the page the dock floats over. Read at send time, not viauseLocation, so navigation doesn't re-render the conversation.get_app_guide.accessPolicy.tsexportsAPP_ROUTES;features/buddy/appGuideRoutes.tslists the routes the backend'sAppGuide.ktdescribes plus deliberate exclusions, andappGuideRoutes.test.tsfails when a new route is in neither.AdminPage:?tab=is now followed while the page is already open. Before, a buddy link like/admin?tab=projectsclicked on/adminkept the current tab and left the parameter in the URL. Respects the admin-only Skills tab (visibleAdminTabs).docs/FRONTEND_ARCHITECTURE.md§4.3, with a pointer inAGENTS.md.Checks
Additional notes
Part of a three-repo change; each PR works on its own, but the feature needs all three:
devis merged in as of today. Not yet tried end to end with a real model.🤖 Generated with Claude Code