diff --git a/experimental/linting_tool/lib/app.dart b/experimental/linting_tool/lib/app.dart
new file mode 100644
index 000000000..b2e24ddcb
--- /dev/null
+++ b/experimental/linting_tool/lib/app.dart
@@ -0,0 +1,40 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:linting_tool/theme/app_theme.dart';
+import 'package:linting_tool/widgets/adaptive_nav.dart';
+import 'package:linting_tool/routes.dart' as routes;
+
+class LintingTool extends StatefulWidget {
+  const LintingTool({Key? key}) : super(key: key);
+
+  static const String homeRoute = routes.homeRoute;
+
+  @override
+  _LintingToolState createState() => _LintingToolState();
+}
+
+class _LintingToolState extends State<LintingTool> {
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: 'Flutter Linting Tool',
+      theme: AppTheme.buildReplyLightTheme(context),
+      darkTheme: AppTheme.buildReplyDarkTheme(context),
+      themeMode: ThemeMode.light,
+      initialRoute: LintingTool.homeRoute,
+      onGenerateRoute: (settings) {
+        switch (settings.name) {
+          case LintingTool.homeRoute:
+            return MaterialPageRoute<void>(
+              builder: (context) => const AdaptiveNav(),
+              settings: settings,
+            );
+        }
+        return null;
+      },
+    );
+  }
+}
diff --git a/experimental/linting_tool/lib/layout/adaptive.dart b/experimental/linting_tool/lib/layout/adaptive.dart
new file mode 100644
index 000000000..c0d14dbff
--- /dev/null
+++ b/experimental/linting_tool/lib/layout/adaptive.dart
@@ -0,0 +1,23 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:adaptive_breakpoints/adaptive_breakpoints.dart';
+import 'package:flutter/material.dart';
+
+/// Returns a boolean value whether the window is considered medium or large size.
+/// Used to build adaptive and responsive layouts.
+bool isDisplayLarge(BuildContext context) =>
+    getWindowType(context) >= AdaptiveWindowType.medium;
+
+/// Returns boolean value whether the window is considered medium size.
+/// Used to build adaptive and responsive layouts.
+bool isDisplayMedium(BuildContext context) {
+  return getWindowType(context) == AdaptiveWindowType.medium;
+}
+
+/// Returns boolean value whether the window is considered small size.
+/// Used to build adaptive and responsive layouts.
+bool isDisplaySmall(BuildContext context) {
+  return getWindowType(context) <= AdaptiveWindowType.small;
+}
diff --git a/experimental/linting_tool/lib/main.dart b/experimental/linting_tool/lib/main.dart
index e22de4739..84c7024e2 100644
--- a/experimental/linting_tool/lib/main.dart
+++ b/experimental/linting_tool/lib/main.dart
@@ -3,67 +3,8 @@
 // found in the LICENSE file.
 
 import 'package:flutter/material.dart';
+import 'package:linting_tool/app.dart';
 
 void main() {
-  runApp(MyApp());
-}
-
-class MyApp extends StatelessWidget {
-  @override
-  Widget build(BuildContext context) {
-    return MaterialApp(
-      title: 'Flutter Linting Tool',
-      theme: ThemeData(
-        primarySwatch: Colors.blue,
-      ),
-      home: const MyHomePage(title: 'Flutter Linting Tool'),
-    );
-  }
-}
-
-class MyHomePage extends StatefulWidget {
-  const MyHomePage({Key? key, required this.title}) : super(key: key);
-
-  final String title;
-
-  @override
-  _MyHomePageState createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State<MyHomePage> {
-  int _counter = 0;
-
-  void _incrementCounter() {
-    setState(() {
-      _counter++;
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        title: Text(widget.title),
-      ),
-      body: Center(
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            const Text(
-              'You have pushed the button this many times:',
-            ),
-            Text(
-              '$_counter',
-              style: Theme.of(context).textTheme.headline4,
-            ),
-          ],
-        ),
-      ),
-      floatingActionButton: FloatingActionButton(
-        onPressed: _incrementCounter,
-        tooltip: 'Increment',
-        child: const Icon(Icons.add),
-      ),
-    );
-  }
+  runApp(const LintingTool());
 }
diff --git a/experimental/linting_tool/lib/pages/default_lints_page.dart b/experimental/linting_tool/lib/pages/default_lints_page.dart
new file mode 100644
index 000000000..28d890330
--- /dev/null
+++ b/experimental/linting_tool/lib/pages/default_lints_page.dart
@@ -0,0 +1,15 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+class DefaultLintsPage extends StatelessWidget {
+  const DefaultLintsPage({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    // TODO(abd99): Implement DefaultLintsPage, showing a list of default lint rules.
+    return const Text('Default Profiles');
+  }
+}
diff --git a/experimental/linting_tool/lib/pages/home_page.dart b/experimental/linting_tool/lib/pages/home_page.dart
new file mode 100644
index 000000000..45b05ddd9
--- /dev/null
+++ b/experimental/linting_tool/lib/pages/home_page.dart
@@ -0,0 +1,15 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+class HomePage extends StatelessWidget {
+  const HomePage({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    // TODO(abd99): Implement HomePage, showing a list of supported lint rules.
+    return const Text('Home');
+  }
+}
diff --git a/experimental/linting_tool/lib/pages/saved_lints_page.dart b/experimental/linting_tool/lib/pages/saved_lints_page.dart
new file mode 100644
index 000000000..dd1d93ea5
--- /dev/null
+++ b/experimental/linting_tool/lib/pages/saved_lints_page.dart
@@ -0,0 +1,15 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+class SavedLintsPage extends StatelessWidget {
+  const SavedLintsPage({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    // TODO(abd99): Implement SavedLintsPage, showing a list of saved lint rules profiles.
+    return const Text('Saved Profiles');
+  }
+}
diff --git a/experimental/linting_tool/lib/routes.dart b/experimental/linting_tool/lib/routes.dart
new file mode 100644
index 000000000..184c9a694
--- /dev/null
+++ b/experimental/linting_tool/lib/routes.dart
@@ -0,0 +1,6 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const String homeRoute = '/home';
+// TODO(abd99): Add new routes.
diff --git a/experimental/linting_tool/lib/theme/app_theme.dart b/experimental/linting_tool/lib/theme/app_theme.dart
new file mode 100644
index 000000000..34051bf0c
--- /dev/null
+++ b/experimental/linting_tool/lib/theme/app_theme.dart
@@ -0,0 +1,208 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:linting_tool/theme/colors.dart';
+
+class AppTheme {
+  static ThemeData buildReplyLightTheme(BuildContext context) {
+    final base = ThemeData.light();
+    return base.copyWith(
+      bottomAppBarColor: AppColors.blue700,
+      bottomSheetTheme: BottomSheetThemeData(
+        backgroundColor: AppColors.blue700,
+        modalBackgroundColor: Colors.white.withOpacity(0.7),
+      ),
+      navigationRailTheme: NavigationRailThemeData(
+        backgroundColor: AppColors.blue700,
+        selectedIconTheme: const IconThemeData(color: AppColors.orange500),
+        selectedLabelTextStyle:
+            GoogleFonts.workSansTextTheme().headline5!.copyWith(
+                  color: AppColors.orange500,
+                ),
+        unselectedIconTheme: const IconThemeData(color: AppColors.blue200),
+        unselectedLabelTextStyle:
+            GoogleFonts.workSansTextTheme().headline5!.copyWith(
+                  color: AppColors.blue200,
+                ),
+      ),
+      canvasColor: AppColors.white50,
+      cardColor: AppColors.white50,
+      chipTheme: _buildChipTheme(
+        AppColors.blue700,
+        AppColors.lightChipBackground,
+        Brightness.light,
+      ),
+      colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blueGrey),
+      textTheme: _buildReplyLightTextTheme(base.textTheme),
+      scaffoldBackgroundColor: AppColors.blue50,
+    );
+  }
+
+  static ThemeData buildReplyDarkTheme(BuildContext context) {
+    final base = ThemeData.dark();
+    return base.copyWith(
+      bottomAppBarColor: AppColors.darkBottomAppBarBackground,
+      bottomSheetTheme: BottomSheetThemeData(
+        backgroundColor: AppColors.darkDrawerBackground,
+        modalBackgroundColor: Colors.black.withOpacity(0.7),
+      ),
+      navigationRailTheme: NavigationRailThemeData(
+        backgroundColor: AppColors.darkBottomAppBarBackground,
+        selectedIconTheme: const IconThemeData(color: AppColors.orange300),
+        selectedLabelTextStyle:
+            GoogleFonts.workSansTextTheme().headline5!.copyWith(
+                  color: AppColors.orange300,
+                ),
+        unselectedIconTheme: const IconThemeData(color: AppColors.greyLabel),
+        unselectedLabelTextStyle:
+            GoogleFonts.workSansTextTheme().headline5!.copyWith(
+                  color: AppColors.greyLabel,
+                ),
+      ),
+      canvasColor: AppColors.black900,
+      cardColor: AppColors.darkCardBackground,
+      chipTheme: _buildChipTheme(
+        AppColors.blue200,
+        AppColors.darkChipBackground,
+        Brightness.dark,
+      ),
+      colorScheme: const ColorScheme.dark(
+        primary: AppColors.blue200,
+        primaryVariant: AppColors.blue300,
+        secondary: AppColors.orange300,
+        secondaryVariant: AppColors.orange300,
+        surface: AppColors.black800,
+        error: AppColors.red200,
+        onPrimary: AppColors.black900,
+        onSecondary: AppColors.black900,
+        onBackground: AppColors.white50,
+        onSurface: AppColors.white50,
+        onError: AppColors.black900,
+        background: AppColors.black900Alpha087,
+      ),
+      textTheme: _buildReplyDarkTextTheme(base.textTheme),
+      scaffoldBackgroundColor: AppColors.black900,
+    );
+  }
+
+  static ChipThemeData _buildChipTheme(
+    Color primaryColor,
+    Color chipBackground,
+    Brightness brightness,
+  ) {
+    return ChipThemeData(
+      backgroundColor: primaryColor.withOpacity(0.12),
+      disabledColor: primaryColor.withOpacity(0.87),
+      selectedColor: primaryColor.withOpacity(0.05),
+      secondarySelectedColor: chipBackground,
+      padding: const EdgeInsets.all(4),
+      shape: const StadiumBorder(),
+      labelStyle: GoogleFonts.workSansTextTheme().bodyText2!.copyWith(
+            color: brightness == Brightness.dark
+                ? AppColors.white50
+                : AppColors.black900,
+          ),
+      secondaryLabelStyle: GoogleFonts.workSansTextTheme().bodyText2!,
+      brightness: brightness,
+    );
+  }
+
+  static TextTheme _buildReplyLightTextTheme(TextTheme base) {
+    return base.copyWith(
+      headline4: GoogleFonts.workSans(
+        fontWeight: FontWeight.w600,
+        fontSize: 34,
+        letterSpacing: 0.4,
+        height: 0.9,
+        color: AppColors.black900,
+      ),
+      headline5: GoogleFonts.workSans(
+        fontWeight: FontWeight.bold,
+        fontSize: 24,
+        letterSpacing: 0.27,
+        color: AppColors.black900,
+      ),
+      headline6: GoogleFonts.workSans(
+        fontWeight: FontWeight.w600,
+        fontSize: 20,
+        letterSpacing: 0.18,
+        color: AppColors.black900,
+      ),
+      subtitle2: GoogleFonts.workSans(
+        fontWeight: FontWeight.w600,
+        fontSize: 14,
+        letterSpacing: -0.04,
+        color: AppColors.black900,
+      ),
+      bodyText1: GoogleFonts.workSans(
+        fontWeight: FontWeight.normal,
+        fontSize: 18,
+        letterSpacing: 0.2,
+        color: AppColors.black900,
+      ),
+      bodyText2: GoogleFonts.workSans(
+        fontWeight: FontWeight.normal,
+        fontSize: 14,
+        letterSpacing: -0.05,
+        color: AppColors.black900,
+      ),
+      caption: GoogleFonts.workSans(
+        fontWeight: FontWeight.normal,
+        fontSize: 12,
+        letterSpacing: 0.2,
+        color: AppColors.black900,
+      ),
+    );
+  }
+
+  static TextTheme _buildReplyDarkTextTheme(TextTheme base) {
+    return base.copyWith(
+      headline4: GoogleFonts.workSans(
+        fontWeight: FontWeight.w600,
+        fontSize: 34,
+        letterSpacing: 0.4,
+        height: 0.9,
+        color: AppColors.white50,
+      ),
+      headline5: GoogleFonts.workSans(
+        fontWeight: FontWeight.bold,
+        fontSize: 24,
+        letterSpacing: 0.27,
+        color: AppColors.white50,
+      ),
+      headline6: GoogleFonts.workSans(
+        fontWeight: FontWeight.w600,
+        fontSize: 20,
+        letterSpacing: 0.18,
+        color: AppColors.white50,
+      ),
+      subtitle2: GoogleFonts.workSans(
+        fontWeight: FontWeight.w600,
+        fontSize: 14,
+        letterSpacing: -0.04,
+        color: AppColors.white50,
+      ),
+      bodyText1: GoogleFonts.workSans(
+        fontWeight: FontWeight.normal,
+        fontSize: 18,
+        letterSpacing: 0.2,
+        color: AppColors.white50,
+      ),
+      bodyText2: GoogleFonts.workSans(
+        fontWeight: FontWeight.normal,
+        fontSize: 14,
+        letterSpacing: -0.05,
+        color: AppColors.white50,
+      ),
+      caption: GoogleFonts.workSans(
+        fontWeight: FontWeight.normal,
+        fontSize: 12,
+        letterSpacing: 0.2,
+        color: AppColors.white50,
+      ),
+    );
+  }
+}
diff --git a/experimental/linting_tool/lib/theme/colors.dart b/experimental/linting_tool/lib/theme/colors.dart
new file mode 100644
index 000000000..9ffebb8e5
--- /dev/null
+++ b/experimental/linting_tool/lib/theme/colors.dart
@@ -0,0 +1,42 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+class AppColors {
+  static const Color white50 = Color(0xFFFFFFFF);
+
+  static const Color black800 = Color(0xFF121212);
+  static const Color black900 = Color(0xFF000000);
+
+  static const Color blue50 = Color(0xFFEEF0F2);
+  static const Color blue100 = Color(0xFFD2DBE0);
+  static const Color blue200 = Color(0xFFADBBC4);
+  static const Color blue300 = Color(0xFF8CA2AE);
+  static const Color blue600 = Color(0xFF4A6572);
+  static const Color blue700 = Color(0xFF344955);
+  static const Color blue800 = Color(0xFF232F34);
+
+  static const Color orange300 = Color(0xFFFBD790);
+  static const Color orange400 = Color(0xFFF9BE64);
+  static const Color orange500 = Color(0xFFF9AA33);
+
+  static const Color red200 = Color(0xFFCF7779);
+  static const Color red400 = Color(0xFFFF4C5D);
+
+  static const Color white50Alpha060 = Color(0x99FFFFFF);
+
+  static const Color blue50Alpha060 = Color(0x99EEF0F2);
+
+  static const Color black900Alpha020 = Color(0x33000000);
+  static const Color black900Alpha087 = Color(0xDE000000);
+  static const Color black900Alpha060 = Color(0x99000000);
+
+  static const Color greyLabel = Color(0xFFAEAEAE);
+  static const Color darkBottomAppBarBackground = Color(0xFF2D2D2D);
+  static const Color darkDrawerBackground = Color(0xFF353535);
+  static const Color darkCardBackground = Color(0xFF1E1E1E);
+  static const Color darkChipBackground = Color(0xFF2A2A2A);
+  static const Color lightChipBackground = Color(0xFFE5E5E5);
+}
diff --git a/experimental/linting_tool/lib/widgets/adaptive_nav.dart b/experimental/linting_tool/lib/widgets/adaptive_nav.dart
new file mode 100644
index 000000000..a143030e0
--- /dev/null
+++ b/experimental/linting_tool/lib/widgets/adaptive_nav.dart
@@ -0,0 +1,334 @@
+// Copyright 2021 The Flutter team. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:math' as math;
+import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
+import 'package:linting_tool/pages/default_lints_page.dart';
+import 'package:linting_tool/pages/home_page.dart';
+import 'package:linting_tool/pages/saved_lints_page.dart';
+import 'package:linting_tool/layout/adaptive.dart';
+import 'package:linting_tool/theme/colors.dart';
+
+final navKey = GlobalKey<NavigatorState>();
+
+class AdaptiveNav extends StatefulWidget {
+  const AdaptiveNav({Key? key}) : super(key: key);
+
+  @override
+  _AdaptiveNavState createState() => _AdaptiveNavState();
+}
+
+class _AdaptiveNavState extends State<AdaptiveNav> {
+  @override
+  Widget build(BuildContext context) {
+    final isDesktop = isDisplayLarge(context);
+    const _navigationDestinations = <_Destination>[
+      _Destination(
+        textLabel: 'Home',
+        icon: Icons.home_outlined,
+        selectedIcon: Icons.home,
+        destination: HomePage(),
+      ),
+      _Destination(
+        textLabel: 'Saved Profiles',
+        icon: Icons.save_outlined,
+        selectedIcon: Icons.save,
+        destination: SavedLintsPage(),
+      ),
+      _Destination(
+        textLabel: 'Default Profiles',
+        icon: Icons.featured_play_list_outlined,
+        selectedIcon: Icons.featured_play_list,
+        destination: DefaultLintsPage(),
+      ),
+    ];
+
+    final _trailing = <String, IconData>{
+      'About': Icons.info_outline,
+    };
+
+    return _NavView(
+      extended: isDesktop,
+      destinations: _navigationDestinations,
+      trailing: _trailing,
+    );
+  }
+}
+
+class _NavView extends StatefulWidget {
+  const _NavView({
+    Key? key,
+    required this.extended,
+    required this.destinations,
+    this.trailing,
+  }) : super(key: key);
+
+  final bool extended;
+  final List<_Destination> destinations;
+  final Map<String, IconData>? trailing;
+
+  @override
+  _NavViewState createState() => _NavViewState();
+}
+
+class _NavViewState extends State<_NavView> {
+  late ValueNotifier<bool?> _isExtended;
+  var _selectedIndex = 0;
+
+  @override
+  void initState() {
+    super.initState();
+    _isExtended = ValueNotifier<bool?>(widget.extended);
+  }
+
+  void _onDestinationSelected(int index) {
+    setState(() {
+      _selectedIndex = index;
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      body: Row(
+        children: [
+          LayoutBuilder(
+            builder: (context, constraints) {
+              return SingleChildScrollView(
+                clipBehavior: Clip.antiAlias,
+                child: ConstrainedBox(
+                  constraints: BoxConstraints(
+                    minHeight: constraints.maxHeight,
+                  ),
+                  child: IntrinsicHeight(
+                    child: ValueListenableBuilder<bool?>(
+                      valueListenable: _isExtended,
+                      builder: (context, value, child) {
+                        var isSmallDisplay = isDisplaySmall(context);
+                        return NavigationRail(
+                          destinations: [
+                            for (var destination in widget.destinations)
+                              NavigationRailDestination(
+                                icon: Icon(destination.icon),
+                                selectedIcon: destination.selectedIcon != null
+                                    ? Icon(destination.selectedIcon)
+                                    : null,
+                                label: Text(destination.textLabel),
+                              ),
+                          ],
+                          extended: _isExtended.value! && !isSmallDisplay,
+                          labelType: NavigationRailLabelType.none,
+                          leading: _NavigationRailHeader(
+                            extended: _isExtended,
+                          ),
+                          trailing: _NavigationRailTrailingSection(
+                            trailingDestinations: widget.trailing!,
+                          ),
+                          selectedIndex: _selectedIndex,
+                          onDestinationSelected: _onDestinationSelected,
+                        );
+                      },
+                    ),
+                  ),
+                ),
+              );
+            },
+          ),
+          const VerticalDivider(thickness: 1, width: 1),
+          Expanded(
+            child: Center(
+              child: ConstrainedBox(
+                constraints: const BoxConstraints(maxWidth: 1340),
+                child: AnimatedSwitcher(
+                  duration: const Duration(milliseconds: 300),
+                  switchOutCurve: Curves.easeOut,
+                  switchInCurve: Curves.easeIn,
+                  child: widget.destinations[_selectedIndex].destination,
+                ),
+              ),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}
+
+class _NavigationRailHeader extends StatelessWidget {
+  const _NavigationRailHeader({
+    required this.extended,
+  });
+
+  final ValueNotifier<bool?> extended;
+
+  @override
+  Widget build(BuildContext context) {
+    final textTheme = Theme.of(context).textTheme;
+    final animation = NavigationRail.extendedAnimation(context);
+
+    return AnimatedBuilder(
+      animation: animation,
+      builder: (context, child) {
+        return Align(
+          alignment: AlignmentDirectional.centerStart,
+          widthFactor: animation.value,
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              SizedBox(
+                height: 56,
+                child: Row(
+                  children: [
+                    const SizedBox(width: 6),
+                    InkWell(
+                      key: const ValueKey('ReplyLogo'),
+                      borderRadius: const BorderRadius.all(Radius.circular(16)),
+                      onTap: () {
+                        extended.value = !extended.value!;
+                      },
+                      child: Row(
+                        children: [
+                          Transform.rotate(
+                            angle: animation.value * math.pi,
+                            child: const Icon(
+                              Icons.arrow_left,
+                              color: AppColors.white50,
+                              size: 16,
+                            ),
+                          ),
+                          const FlutterLogo(),
+                          const SizedBox(width: 10),
+                          Align(
+                            alignment: AlignmentDirectional.centerStart,
+                            widthFactor: animation.value,
+                            child: Opacity(
+                              opacity: animation.value,
+                              child: Text(
+                                'Linting Tool',
+                                style: textTheme.bodyText1!.copyWith(
+                                  color: AppColors.white50,
+                                ),
+                              ),
+                            ),
+                          ),
+                          SizedBox(width: 18 * animation.value),
+                        ],
+                      ),
+                    ),
+                  ],
+                ),
+              ),
+              const SizedBox(height: 8),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}
+
+class _NavigationRailTrailingSection extends StatelessWidget {
+  const _NavigationRailTrailingSection({
+    required this.trailingDestinations,
+  });
+
+  final Map<String, IconData> trailingDestinations;
+
+  @override
+  Widget build(BuildContext context) {
+    final theme = Theme.of(context);
+    final textTheme = theme.textTheme;
+    final navigationRailTheme = theme.navigationRailTheme;
+    final animation = NavigationRail.extendedAnimation(context);
+
+    return AnimatedBuilder(
+      animation: animation,
+      builder: (context, child) {
+        return Visibility(
+          maintainAnimation: true,
+          maintainState: true,
+          visible: animation.value > 0,
+          child: Opacity(
+            opacity: animation.value,
+            child: Align(
+              widthFactor: animation.value,
+              alignment: AlignmentDirectional.centerStart,
+              child: SizedBox(
+                height: 485,
+                width: 256,
+                child: ListView(
+                  padding: const EdgeInsets.all(12),
+                  physics: const NeverScrollableScrollPhysics(),
+                  children: [
+                    const Divider(
+                      color: AppColors.blue200,
+                      thickness: 0.4,
+                      indent: 14,
+                      endIndent: 16,
+                    ),
+                    const SizedBox(height: 8),
+                    for (var item in trailingDestinations.keys)
+                      InkWell(
+                        borderRadius: const BorderRadius.all(
+                          Radius.circular(36),
+                        ),
+                        onTap: () => _onTapped(context, item),
+                        child: Column(
+                          children: [
+                            Row(
+                              children: [
+                                const SizedBox(width: 12),
+                                Icon(
+                                  trailingDestinations[item],
+                                  color: AppColors.blue300,
+                                ),
+                                const SizedBox(width: 24),
+                                Text(
+                                  item,
+                                  style: textTheme.bodyText1!.copyWith(
+                                    color: navigationRailTheme
+                                        .unselectedLabelTextStyle!.color,
+                                  ),
+                                ),
+                                const SizedBox(height: 72),
+                              ],
+                            ),
+                          ],
+                        ),
+                      ),
+                  ],
+                ),
+              ),
+            ),
+          ),
+        );
+      },
+    );
+  }
+
+  void _onTapped(BuildContext context, String key) {
+    switch (key) {
+      case 'About':
+        showAboutDialog(context: context);
+        break;
+      default:
+        break;
+    }
+  }
+}
+
+class _Destination {
+  const _Destination({
+    required this.destination,
+    required this.textLabel,
+    required this.icon,
+    this.selectedIcon,
+  });
+
+  final String textLabel;
+  final IconData icon;
+  final IconData? selectedIcon;
+  final Widget destination;
+}
diff --git a/experimental/linting_tool/macos/Flutter/Flutter-Debug.xcconfig b/experimental/linting_tool/macos/Flutter/Flutter-Debug.xcconfig
index c2efd0b60..4b81f9b2d 100644
--- a/experimental/linting_tool/macos/Flutter/Flutter-Debug.xcconfig
+++ b/experimental/linting_tool/macos/Flutter/Flutter-Debug.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
 #include "ephemeral/Flutter-Generated.xcconfig"
diff --git a/experimental/linting_tool/macos/Flutter/Flutter-Release.xcconfig b/experimental/linting_tool/macos/Flutter/Flutter-Release.xcconfig
index c2efd0b60..5caa9d157 100644
--- a/experimental/linting_tool/macos/Flutter/Flutter-Release.xcconfig
+++ b/experimental/linting_tool/macos/Flutter/Flutter-Release.xcconfig
@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
 #include "ephemeral/Flutter-Generated.xcconfig"
diff --git a/experimental/linting_tool/macos/Flutter/GeneratedPluginRegistrant.swift b/experimental/linting_tool/macos/Flutter/GeneratedPluginRegistrant.swift
index cccf817a5..0d56f519c 100644
--- a/experimental/linting_tool/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/experimental/linting_tool/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -5,6 +5,8 @@
 import FlutterMacOS
 import Foundation
 
+import path_provider_macos
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+  PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
 }
diff --git a/experimental/linting_tool/macos/Podfile b/experimental/linting_tool/macos/Podfile
new file mode 100644
index 000000000..dade8dfad
--- /dev/null
+++ b/experimental/linting_tool/macos/Podfile
@@ -0,0 +1,40 @@
+platform :osx, '10.11'
+
+# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
+ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+
+project 'Runner', {
+  'Debug' => :debug,
+  'Profile' => :release,
+  'Release' => :release,
+}
+
+def flutter_root
+  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
+  unless File.exist?(generated_xcode_build_settings_path)
+    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
+  end
+
+  File.foreach(generated_xcode_build_settings_path) do |line|
+    matches = line.match(/FLUTTER_ROOT\=(.*)/)
+    return matches[1].strip if matches
+  end
+  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
+end
+
+require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
+
+flutter_macos_podfile_setup
+
+target 'Runner' do
+  use_frameworks!
+  use_modular_headers!
+
+  flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
+end
+
+post_install do |installer|
+  installer.pods_project.targets.each do |target|
+    flutter_additional_macos_build_settings(target)
+  end
+end
diff --git a/experimental/linting_tool/macos/Podfile.lock b/experimental/linting_tool/macos/Podfile.lock
new file mode 100644
index 000000000..328ddd1ae
--- /dev/null
+++ b/experimental/linting_tool/macos/Podfile.lock
@@ -0,0 +1,22 @@
+PODS:
+  - FlutterMacOS (1.0.0)
+  - path_provider_macos (0.0.1):
+    - FlutterMacOS
+
+DEPENDENCIES:
+  - FlutterMacOS (from `Flutter/ephemeral`)
+  - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
+
+EXTERNAL SOURCES:
+  FlutterMacOS:
+    :path: Flutter/ephemeral
+  path_provider_macos:
+    :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
+
+SPEC CHECKSUMS:
+  FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
+  path_provider_macos: a0a3fd666cb7cd0448e936fb4abad4052961002b
+
+PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
+
+COCOAPODS: 1.10.1
diff --git a/experimental/linting_tool/macos/Runner.xcodeproj/project.pbxproj b/experimental/linting_tool/macos/Runner.xcodeproj/project.pbxproj
index 7ec458b9a..5eac5b098 100644
--- a/experimental/linting_tool/macos/Runner.xcodeproj/project.pbxproj
+++ b/experimental/linting_tool/macos/Runner.xcodeproj/project.pbxproj
@@ -21,6 +21,7 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+		263EC21EDDA79B90E36D3AF2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BA99C65F70358A600BD0DB9 /* Pods_Runner.framework */; };
 		335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
 		33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
 		33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
@@ -52,9 +53,10 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		1FF9829B1C25BAA5E9CFD6F7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
 		333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
 		335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
-		33CC10ED2044A3C60003C045 /* linting_tool.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "linting_tool.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		33CC10ED2044A3C60003C045 /* linting_tool.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = linting_tool.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 		33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
 		33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -66,7 +68,10 @@
 		33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
 		33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
 		33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
+		4BA99C65F70358A600BD0DB9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		66D130ED505BEFC4C780F92C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
+		7E301E068432A8A69757147C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -75,6 +80,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				263EC21EDDA79B90E36D3AF2 /* Pods_Runner.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -99,6 +105,7 @@
 				33CEB47122A05771004F2AC0 /* Flutter */,
 				33CC10EE2044A3C60003C045 /* Products */,
 				D73912EC22F37F3D000D13A0 /* Frameworks */,
+				51EE2FAB634AFBA8448DB770 /* Pods */,
 			);
 			sourceTree = "<group>";
 		};
@@ -145,9 +152,21 @@
 			path = Runner;
 			sourceTree = "<group>";
 		};
+		51EE2FAB634AFBA8448DB770 /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				66D130ED505BEFC4C780F92C /* Pods-Runner.debug.xcconfig */,
+				1FF9829B1C25BAA5E9CFD6F7 /* Pods-Runner.release.xcconfig */,
+				7E301E068432A8A69757147C /* Pods-Runner.profile.xcconfig */,
+			);
+			name = Pods;
+			path = Pods;
+			sourceTree = "<group>";
+		};
 		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				4BA99C65F70358A600BD0DB9 /* Pods_Runner.framework */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -159,11 +178,13 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
 			buildPhases = (
+				FA1FF96E71045A62F03992DA /* [CP] Check Pods Manifest.lock */,
 				33CC10E92044A3C60003C045 /* Sources */,
 				33CC10EA2044A3C60003C045 /* Frameworks */,
 				33CC10EB2044A3C60003C045 /* Resources */,
 				33CC110E2044A8840003C045 /* Bundle Framework */,
 				3399D490228B24CF009A79C7 /* ShellScript */,
+				A7CF0EFBD867541ADB9884D5 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -270,6 +291,45 @@
 			shellPath = /bin/sh;
 			shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
 		};
+		A7CF0EFBD867541ADB9884D5 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		FA1FF96E71045A62F03992DA /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
diff --git a/experimental/linting_tool/macos/Runner.xcworkspace/contents.xcworkspacedata b/experimental/linting_tool/macos/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a16e..21a3cc14c 100644
--- a/experimental/linting_tool/macos/Runner.xcworkspace/contents.xcworkspacedata
+++ b/experimental/linting_tool/macos/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
    <FileRef
       location = "group:Runner.xcodeproj">
    </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
 </Workspace>
diff --git a/experimental/linting_tool/macos/Runner/DebugProfile.entitlements b/experimental/linting_tool/macos/Runner/DebugProfile.entitlements
index dddb8a30c..3ba6c1266 100644
--- a/experimental/linting_tool/macos/Runner/DebugProfile.entitlements
+++ b/experimental/linting_tool/macos/Runner/DebugProfile.entitlements
@@ -6,6 +6,8 @@
 	<true/>
 	<key>com.apple.security.cs.allow-jit</key>
 	<true/>
+	<key>com.apple.security.network.client</key>
+	<true/>
 	<key>com.apple.security.network.server</key>
 	<true/>
 </dict>
diff --git a/experimental/linting_tool/macos/Runner/Info.plist b/experimental/linting_tool/macos/Runner/Info.plist
index 4789daa6a..485f6f479 100644
--- a/experimental/linting_tool/macos/Runner/Info.plist
+++ b/experimental/linting_tool/macos/Runner/Info.plist
@@ -13,7 +13,7 @@
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
+	<string>Flutter Linting Tool</string>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
diff --git a/experimental/linting_tool/pubspec.lock b/experimental/linting_tool/pubspec.lock
index 29526b6b5..9b9d9436a 100644
--- a/experimental/linting_tool/pubspec.lock
+++ b/experimental/linting_tool/pubspec.lock
@@ -1,6 +1,13 @@
 # Generated by pub
 # See https://dart.dev/tools/pub/glossary#lockfile
 packages:
+  adaptive_breakpoints:
+    dependency: "direct main"
+    description:
+      name: adaptive_breakpoints
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.0.4"
   async:
     dependency: transitive
     description:
@@ -43,6 +50,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.15.0"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.0.1"
   cupertino_icons:
     dependency: "direct main"
     description:
@@ -57,6 +71,20 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.2.0"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.1.2"
+  file:
+    dependency: transitive
+    description:
+      name: file
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "6.1.2"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -74,6 +102,27 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  google_fonts:
+    dependency: "direct main"
+    description:
+      name: google_fonts
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.0"
+  http:
+    dependency: transitive
+    description:
+      name: http
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.13.3"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "4.0.0"
   lints:
     dependency: transitive
     description:
@@ -102,6 +151,69 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.8.0"
+  path_provider:
+    dependency: transitive
+    description:
+      name: path_provider
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.2"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.0"
+  path_provider_macos:
+    dependency: transitive
+    description:
+      name: path_provider_macos
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.0"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.1"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.1"
+  pedantic:
+    dependency: transitive
+    description:
+      name: pedantic
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.11.1"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.0.0"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.1"
+  process:
+    dependency: transitive
+    description:
+      name: process
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "4.2.1"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -163,5 +275,20 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.1.0"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.2.5"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.0"
 sdks:
-  dart: ">=2.12.0 <3.0.0"
+  dart: ">=2.13.0 <3.0.0"
+  flutter: ">=1.20.0"
diff --git a/experimental/linting_tool/pubspec.yaml b/experimental/linting_tool/pubspec.yaml
index a78b1c825..e2d777bd3 100644
--- a/experimental/linting_tool/pubspec.yaml
+++ b/experimental/linting_tool/pubspec.yaml
@@ -9,8 +9,9 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
-
+  adaptive_breakpoints: ^0.0.4
   cupertino_icons: ^1.0.2
+  google_fonts: ^2.1.0
 
 dev_dependencies:
   flutter_test:
diff --git a/experimental/linting_tool/test/widget_test.dart b/experimental/linting_tool/test/widget_test.dart
index b8f99f38d..ca2c76550 100644
--- a/experimental/linting_tool/test/widget_test.dart
+++ b/experimental/linting_tool/test/widget_test.dart
@@ -5,26 +5,29 @@
 // gestures. You can also use WidgetTester to find child widgets in the widget
 // tree, read text, and verify that the values of widget properties are correct.
 
-import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
-
-import 'package:linting_tool/main.dart';
+import 'package:linting_tool/app.dart';
+import 'package:linting_tool/pages/default_lints_page.dart';
+import 'package:linting_tool/pages/home_page.dart';
+import 'package:linting_tool/pages/saved_lints_page.dart';
 
 void main() {
-  testWidgets('Counter increments smoke test', (tester) async {
-    // Build our app and trigger a frame.
-    await tester.pumpWidget(MyApp());
+  testWidgets('NavigationRail smoke test', (tester) async {
+    await tester.pumpWidget(const LintingTool());
 
-    // Verify that our counter starts at 0.
-    expect(find.text('0'), findsOneWidget);
-    expect(find.text('1'), findsNothing);
+    expect(find.byType(SavedLintsPage), findsNothing);
+    await tester.tap(find.text('Saved Profiles'));
+    await tester.pumpAndSettle();
+    expect(find.byType(SavedLintsPage), findsOneWidget);
 
-    // Tap the '+' icon and trigger a frame.
-    await tester.tap(find.byIcon(Icons.add));
-    await tester.pump();
+    expect(find.byType(DefaultLintsPage), findsNothing);
+    await tester.tap(find.text('Default Profiles'));
+    await tester.pumpAndSettle();
+    expect(find.byType(DefaultLintsPage), findsOneWidget);
 
-    // Verify that our counter has incremented.
-    expect(find.text('0'), findsNothing);
-    expect(find.text('1'), findsOneWidget);
+    expect(find.byType(HomePage), findsNothing);
+    await tester.tap(find.text('Home'));
+    await tester.pumpAndSettle();
+    expect(find.byType(HomePage), findsOneWidget);
   });
 }
diff --git a/tool/flutter_ci_script_beta.sh b/tool/flutter_ci_script_beta.sh
index 43591cc6e..3160b6e2d 100755
--- a/tool/flutter_ci_script_beta.sh
+++ b/tool/flutter_ci_script_beta.sh
@@ -22,6 +22,7 @@ declare -ar PROJECT_NAMES=(
     "experimental/federated_plugin/federated_plugin"
     # TODO(redbrogdon): Restore during next beta branch merge.
     # "experimental/web_dashboard"
+    "experimental/linting_tool"
     "flutter_maps_firestore"
     "infinite_list"
     "ios_app_clip"
diff --git a/tool/flutter_ci_script_dev.sh b/tool/flutter_ci_script_dev.sh
index 8fcc9fcb6..0546ec22a 100755
--- a/tool/flutter_ci_script_dev.sh
+++ b/tool/flutter_ci_script_dev.sh
@@ -22,6 +22,7 @@ declare -ar PROJECT_NAMES=(
     "experimental/federated_plugin/federated_plugin"
     # TODO(redbrogdon): Restore during next beta branch merge.
     # "experimental/web_dashboard"
+    "experimental/linting_tool"
     "flutter_maps_firestore"
     "infinite_list"
     "ios_app_clip"
diff --git a/tool/flutter_ci_script_stable.sh b/tool/flutter_ci_script_stable.sh
index b6db4f4cc..3a3a54e32 100755
--- a/tool/flutter_ci_script_stable.sh
+++ b/tool/flutter_ci_script_stable.sh
@@ -17,6 +17,7 @@ declare -ar PROJECT_NAMES=(
     "experimental/desktop_photo_search"
     "experimental/federated_plugin/federated_plugin"
     "experimental/web_dashboard"
+    "experimental/linting_tool"
     "flutter_maps_firestore"
     "infinite_list"
     "ios_app_clip"