agentsclimarketplace

Manage routes

Skill anoopsg/agent_rules/src/exclusive/skills/manage-routes

Behavioral blueprints for agents.

Install
npx -y skills add anoopsg/agent_rules --skill manage-routes

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when asked to add, update, or group routes using GoRouter, or manage redirection guards.

SKILL.md

5.6 KB, as published. Nobody here has run it

Routing Management Skill

This skill defines the process for adding, modifying, and guarding routes using GoRouter with the _AppRoute base class, Routes registry, and the priority-ordered GateGuard/RouteGuard guards.

1. Directory Structure

lib/src/routes/
├── router.dart            # GoRouter config & auth shells
├── router.g.dart          # Auto-generated (Riverpod)
├── router_listenable.dart # Auth-state refresh listener
└── routes.dart            # _AppRoute base + Routes registry

2. Route Architecture

_AppRoute Base Class

Every route extends the private _AppRoute class which holds path, name, and a build method. It also provides toGoRoute() for zero-boilerplate registration:

abstract class _AppRoute {
  const _AppRoute({required this.path, required this.name});
  final String path;
  final String name;

  Widget build(BuildContext context, GoRouterState state);

  GoRoute toGoRoute() => GoRoute(
    name: name,
    path: path,
    builder: build,
  );
}

Routes Registry

All routes are registered as static const fields in the Routes class for autocomplete-friendly discovery:

abstract final class Routes {
  static const home = _HomeRoute();
  static const login = _LoginRoute();
  // ...
}

3. Step 1 — Define a New Route

Add a final class extending _AppRoute at the bottom of routes.dart:

final class _SearchRoute extends _AppRoute {
  const _SearchRoute()
      : super(path: '/search', name: 'search');

  @override
  Widget build(_, _) => const SearchPage();
}

For routes with path parameters, extract them from GoRouterState:

final class _DetailRoute extends _AppRoute {
  const _DetailRoute()
      : super(path: '/detail/:id', name: 'detail');

  @override
  Widget build(_, GoRouterState state) {
    final id = state.pathParameters['id']!;
    return DetailPage(id: id);
  }
}

If the route should be gated by a capability rather than just login state, pass requiredPermission:

final class _SettingsRoute extends _AppRoute {
  const _SettingsRoute()
      : super(
          path: '/settings',
          name: 'settings',
          requiredPermission: Permission.settingsView,
        );

  @override
  Widget build(_, _) => const SettingsPage();
}

See manage-permissions for the full RBAC model.

4. Step 2 — Register in Routes

Add a static const entry in the Routes class inside routes.dart:

abstract final class Routes {
  // ... existing routes
  static const search = _SearchRoute();
}

5. Step 3 — Add to the Router

Add the route to the appropriate shell in router.dart using toGoRoute():

Routes.search.toGoRoute(),

Authentication Shells

ShellAccessRedirect
openRoutesAny user, platform-gatedNone
unauthenticatedRoutesLogged-out only/ if logged in
authenticatedRoutesLogged-in only/login if logged out

Route Guards

Cross-cutting gates that don't belong to a single shell come in two shapes (lib/src/routes/guards/route_guard.dart):

  • GateGuard — owns one exclusive full-screen route (path) and just answers whether it's currently active (isActive(AppState app)), with no knowledge of the current location. The router consults gateGuards in priority order and acts on only the first active one per redirect pass — never comparing multiple gates against the path itself — so two gates can't fight over the screen.
  • RouteGuard — a per-route access check, redirect(AppState app, GoRouterState state), evaluated only once every gate has resolved. PermissionGuard is the only one today.
PriorityGuardShapeGate
0MaintenanceGuardGateGuardWeb-only maintenance mode
10SplashGuardGateGuardMobile splash-complete (never actively claims it — see its doc comment)
20UpdateGuardGateGuardMobile forced update
30OnboardingGuardGateGuardOnboarding completion
40PermissionGuardRouteGuardPer-route permission

To add a new full-screen gate, add a file implementing GateGuard and one entry in the gateGuards list in router.dart — existing guards never need to change, and the router's stale-gate fallback (bounce home once no gate is active) picks it up automatically since it derives from gateGuards itself, not a separate path list. To add a new per-route access check, implement RouteGuard instead and add it to accessGuards. See ADR-0008 for the original guard design and ADR-0016 for why gates are arbitrated this way — this skill only covers the mechanics.

_landingRoute() & Platform Routing

The _landingRoute() function handles platform-specific layouts. On mobile the landing page uses a StatefulShellRoute.indexedStack with bottom nav branches (home, explore, notifications, profile). On web it returns a single Routes.home.toGoRoute().

To add a new bottom-nav tab, add the route to the branches list inside _landingRoute().

6. Step 4 — Re-generate

The appRouter provider is annotated with @Riverpod. After any change, regenerate the .g.dart file:

melos run generate

7. Navigation in Code

context.go(Routes.settings.path);
context.push(Routes.settings.path);
context.goNamed(Routes.settings.name);

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.