Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
150716 stories
·
33 followers

Microsoft says Copilot ad in GitHub pull request was a bug, not an advertisement

1 Share

Developers have alleged that Copilot ads are showing up in GitHub pull requests. However, Microsoft has denied the reports and told Windows Latest that it does not plan to show ads on GitHub. As for alleged Copilot-generated ads on GitHub, the company says it was a bug, and not an intentional move.

Thousands of pull requests on GitHub appear to include a Copilot-generated product tip, which looks more like an advertisement than anything else. This came to our attention when Zach Manson, a software developer based in Melbourne, spotted a Copilot-generated ad or suggestion in his project’s pull request on March 30.

This Copilot ad showed up after a team member in Zach’s project requested Copilot in GitHub to correct an error in a pull request. And that’s not an expected behaviour.

Copilot ad on Github
Copilot-generated product tip or “ad” on GitHub PR

GitHub’s Copilot integration is actually quite helpful, and developers use it frequently, especially if they want to clean up their pull requests. But to Zach’s surprise, GitHub inserted a small ad for Copilot’s agentic features and Raycast, which is a popular third-party search tool on macOS and Windows.

“This is horrific. I knew this kind of bull**** would happen eventually, but I didn’t expect it so soon,” Manson wrote in a post.

Since the post went viral on Hacker News, Raycast developers have denied entering into an ad arrangement with Microsoft.

Microsoft says GitHub won’t include ads, and Copilot’s ad-like pull request note was just a bug

In a statement, Microsoft told Windows Latest that GitHub was not testing ads in pull requests.

Instead, the company said a bug caused existing Copilot product tips, including one referencing Raycast, to appear in the wrong place.

According to Microsoft, these tips were originally meant only for pull requests created by Copilot, but the bug made them show up in some human-created pull requests as well when Copilot was invoked to edit code.

“GitHub does not and does not plan to include advertisements in GitHub,” says Martin Woodward, VP of Developer Relations at GitHub, in a statement to Windows Latest. “We identified a programming logic issue with a GitHub Copilot coding agent tip that surfaced in the wrong context within a pull request comment. We have removed agent tips from pull request comments moving forward.”

The original GitHub announcement from last week appears to support Microsoft’s explanation, at least in part.

GitHub feature that allows you to add Copilot to PR
GitHub feature that allows you to add Copilot to PR

GitHub had already said Copilot could be mentioned directly in pull requests to make changes, and also noted that Copilot previously opened its own pull requests on top of existing ones.

“Copilot would open a new pull request on top of your existing pull request, using the existing pull request’s branch as its base branch,” GitHub noted in a release notes update on March 24, 2026.

Microsoft sources also confirmed to Windows Latest that it was an unintentional behavior of GitHub’s new Copilot feature, which allows you to invite AI to make changes to pull requests.

When the company rolled out the feature, a product tip from the GitHub Copilot coding agent that included a third-party suggestion was inadvertently displayed in the main pull request comment when Copilot was called by a developer.

Microsoft identified this behavior as a programming logic issue and removed the agent tips feature from pull request comments.

The post Microsoft says Copilot ad in GitHub pull request was a bug, not an advertisement appeared first on Windows Latest

Read the whole story
alvinashcraft
26 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

.NET Aspire 13.2 Adds AI-Agent CLI, TypeScript AppHost Support

1 Share
Microsoft has released .NET Aspire 13.2 with a new AI-focused CLI for coding agents, preview TypeScript AppHost support, dashboard updates, and revised integrations.
Read the whole story
alvinashcraft
27 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Azure Developer CLI (azd) – March 2026: Run and Debug AI Agents Locally, GitHub Copilot Integration, & Container App Jobs

1 Share

The Azure Developer CLI (azd) shipped seven releases in March 2026. Most notably, azd now has a local run-and-debug loop for AI agents, GitHub Copilot–powered project setup, and Container App Jobs deployment. Here’s what’s in versions 1.23.7, 1.23.8, 1.23.9, 1.23.10, 1.23.11, 1.23.12, and 1.23.13.

To share your feedback and questions, join the March release discussion on GitHub.

Highlights:

  • AI agent extension: run, invoke, monitor, and deploy agents end-to-end from your terminal to Microsoft Foundry
  • GitHub Copilot integration in azd init for AI-assisted project setup
  • Deploy Container App Jobs directly with azd
  • Local preflight validation catches infrastructure issues before deploying to Azure
  • Automatic pnpm and yarn detection for JavaScript and TypeScript projects
  • Set per-service deployment timeouts to avoid failures on long-running deploys

New features

🤖 AI agent extension

The azure.ai.agents extension adds new commands for running, testing, and monitoring AI agents—locally or deployed to Microsoft Foundry.

🧠 GitHub Copilot integration

GitHub Copilot now plugs into azd init for AI-assisted scaffolding and error troubleshooting.

  • Set up with GitHub Copilot (Preview): azd init now offers a “Set up with GitHub Copilot (Preview)” option that uses a GitHub Copilot agent to scaffold your project. The flow checks for a dirty working directory before modifying files and prompts for Model Context Protocol (MCP) server tool consent upfront. [#7162] [#7194]
  • AI-assisted error troubleshooting: When a command fails, azd now offers a multi-step troubleshooting flow: select a category (explain, guidance, troubleshoot, or skip), optionally let the agent apply a fix, and retry the failed command—all without leaving the terminal. [#7216]

🚀 Deployment and infrastructure

Several improvements give you more control over how and where azd deploys your services.

  • Container App Jobs support: azd now deploys Azure Container App Jobs (Microsoft.App/jobs) through the existing host: containerapp configuration. The Bicep template determines whether the target is a Container App or a Container App Job—no extra configuration needed. Contributed by @jongio. [#7001]
  • Configurable deployment timeouts: A new --timeout flag on azd deploy and a deployTimeout field in azure.yaml let you set per-service deployment timeouts. The CLI flag takes priority over azure.yaml, which takes priority over the default 1200-second timeout. [#7045]
  • Remote build fallback: When remoteBuild: true and the remote Azure Container Registry (ACR) build fails, azd now automatically falls back to a local Docker or Podman build so transient registry issues don’t block deployments. [#7041]
  • Local preflight validation: azd now validates Bicep parameters and configuration locally before deploying, catching missing parameters and mismatched types without a round-trip to Azure. [#7053]
  • Preflight configuration: To skip Azure Resource Manager (ARM) preflight validation, run azd config set provision.preflight off. A spinner now displays during preflight runs. [#6852]
  • Azure SRE Agent resource type: Provisioning progress output now correctly displays Microsoft.App/agents resources. Contributed by @dm-chelupati. [#6968]

🔧 Developer experience

These changes simplify project setup, improve automation, and surface better error messages.

  • Automatic package manager detection: azd now detects pnpm and yarn for JavaScript and TypeScript services. To override the detected manager, set config.packageManager in azure.yaml. Contributed by @jongio. [#6894]
  • pyproject.toml support: Python projects using pyproject.toml for packaging are now detected and built with pip install .. Contributed by @jongio. [#6848]
  • Local template directories: azd init --template now accepts a local filesystem path, so you can iterate on template layouts without pushing to a remote repository. Contributed by @jongio. [#6826]
  • Sensible no-prompt defaults: In --no-prompt mode, azd env new and azd init auto-generate an environment name from the working directory and autoselect the subscription when only one is available. [#7016]
  • Improved no-prompt error guidance: When required inputs are missing in --no-prompt mode, azd init and azd provision now report all missing values at once with actionable resolution commands and environment variable mappings. [#6962]
  • Build environment variables: azd environment variables are now available in all framework build subprocesses (Node.js, .NET, Java, Python, Static Web Apps), enabling build-time environment variable injection. Contributed by @jongio. [#6905]
  • YAML-driven error handling: A new error pipeline matches Azure deployment errors against known patterns and surfaces actionable messages, suggestions, and reference links. Coverage includes Container App secrets, image pulls, template parameter failures, and Role-Based Access Control (RBAC) permission and policy errors. [#6827] [#6845] [#6846]
  • Remote build suggestion: When Docker isn’t installed or not running, azd now suggests setting remoteBuild: true for Container Apps and Azure Kubernetes Service services. Contributed by @spboyer. [#7247]
  • Improved auth status output: azd auth status --output json now exits non-zero when unauthenticated and includes an expiresOn field, making it suitable as an auth validation endpoint for AI agents. Contributed by @spboyer. [#7236]

🔌 Extensions

The extension authoring experience gains new tooling and validation capabilities.

  • Extension SDK improvements: New SDK primitives simplify extension authoring, including command scaffolding, typed argument parsing, a resilient HTTP client, and network security policy. MCP server utilities, token provider, scope detection, and pagination helpers are also included. Contributed by @jongio. [#6856] [#6954]
  • Extension source validation: New azd extension source validate command checks extension registry sources against required fields, version format, capabilities, and checksum rules. Contributed by @jongio. [#6906]
  • Extension website field: Extensions can now declare a website field in the registry schema, displayed in azd extension show output. Contributed by @jongio. [#6904]
  • CopilotService for extensions: A new CopilotService gRPC service lets extensions programmatically interact with GitHub Copilot agent capabilities—initialize sessions, send messages, and retrieve usage metrics. [#7172]
  • Improved startup failure warnings: Extension startup failures now show categorized, actionable messages that distinguish extensions needing an upgrade from timeout failures and include a --debug hint for details. [#7018]

🪲 Bugs fixed

  • Fixed azd deploy silently removing externally configured Dapr settings during Container App updates. Dapr configuration is now preserved when not present in the deployment YAML. [#7062]
  • Reverted env-flag change from v1.23.11 to fix a regression where the -e shorthand for --environment conflicted with extension commands that use -e for their own flags (such as --project-endpoint). [#7274]
  • Fixed .funcignore handling and parsing failures for flex-consumption function apps, including UTF-8 Byte Order Mark and negation patterns. [#7223] [#7311]
  • Fixed extension startup failures on Windows caused by IPv4/IPv6 address mismatch in the gRPC server address. Contributed by @spboyer. [#7346]
  • Hardened extension and template security with improved input validation, origin checks, token handling, and data redaction. Contributed by @jongio.
  • Strengthened MCP extension network security policy. Contributed by @jongio.

For the full list of fixes, see the release notes for 1.23.7 through 1.23.13.

Other changes

  • Improved provisioning progress polling with concurrent nested deployment traversal and a terminal-operation cache to reduce redundant ARM API calls. [#7019]
  • Improved Container Apps deployment performance by reducing ARM API round-trips, saving up to three calls per deployment. [#6888]
  • Improved storage blob client performance by verifying container existence only once per session. [#6912]
  • Improved --no-prompt support for resource-group deployments by defaulting the resource group prompt to the AZURE_RESOURCE_GROUP environment variable. [#7044]
  • Normalized user-facing CLI output to consistent lowercase azd branding. [#6768]
  • Updated azd core to Go 1.26. [#7017]
  • Updated Bicep minimum required version to 0.41.2. [#6953]
  • Added azure.yaml schema metadata to enable automatic schema association in JetBrains IDEs, Neovim, and other editors via the SchemaStore catalog. [#7330]

New docs

  • Operate and troubleshoot agents with azd: New section in the Azure AI Foundry extension documentation covering agent monitoring, health checks, and troubleshooting with the azd ai agent command set. Learn more
  • Dev container extension auto-install: Updated extension overview and install docs with guidance on automatically installing azd extensions in dev containers. Learn more
  • Publishing workflows: New guide for azd publish, including build-once, deploy-later scenarios and shared registry workflows. Learn more
  • App Service deployment slots: New guide for promotion, rollback, and slot swap workflows with Azure App Service. Learn more
  • Environment secrets: New article explaining how to use Azure Key Vault–backed values in azd environments, including integration with Bicep parameters, hooks, and CI/CD pipeline configuration. Learn more
  • Container Apps and Jobs workflows: Expanded guidance covering image-based and revision-based deployment strategies for Azure Container Apps, plus new Container App Jobs documentation. Container App Jobs use the existing host: containerapp model—the resource type in your infrastructure determines the target. Learn more
  • Authentication and tenant guidance: Improved multi-tenant authentication docs, including --tenant-id usage, browser-based MFA recommendations, and troubleshooting for Conditional Access and device-code pipeline issues. Learn more
  • JavaScript and TypeScript packaging: Updated schema docs to cover explicit package manager configuration and auto-detection behavior from package.json, lock files, and default fallback. Learn more
  • Troubleshooting improvements: Expanded guidance for GitHub Actions and Azure Key Vault permission issues, with cleanup to links, code examples, and FAQ content. Learn more
  • Reference updates: Refreshed reference documentation to align with releases 1.23.8, 1.23.10, and 1.23.11. Learn more

New templates

Community-driven templates help you get started faster, solve real-world scenarios, and showcase best practices for deploying solutions with Azure Developer CLI.

The Azure Developer CLI template gallery continues to grow with exciting new contributions from the community. Thank you!

🙋‍♀️ New to azd?

If you’re new to the Azure Developer CLI, azd is an open-source command-line tool that accelerates the time it takes to get your application from local development environment to Azure. azd provides best practice, developer-friendly commands that map to key stages in your workflow, whether you’re working in the terminal, your editor or CI/CD.

The post Azure Developer CLI (azd) – March 2026: Run and Debug AI Agents Locally, GitHub Copilot Integration, & Container App Jobs appeared first on Azure SDK Blog.

Read the whole story
alvinashcraft
27 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Efficient State Management in Flutter Using IndexedStack

1 Share

When you're building Flutter applications that have multiple tabs or screens, one of the most common challenges you'll face is maintaining state across navigation without breaking the user experience. It becomes obvious when a user switches tabs and suddenly loses scroll position, form input, or previously loaded data.

This problem isn't caused by Flutter being inefficient. It's usually a result of how widgets are rebuilt during navigation.

A practical and often overlooked solution to this is to use the IndexedStack widget. It lets you switch between screens while keeping their state intact, which leads to smoother navigation and better performance.

This article takes a deeper look at how IndexedStack works, why it matters, and how to use it properly in real applications.

Table of Contents

Prerequisites

To follow along comfortably, you should already understand how Flutter widgets work, especially the difference between StatelessWidget and StatefulWidget.

You should also be familiar with Scaffold, BottomNavigationBar, and how Flutter rebuilds widgets when state changes.

Finally, a basic understanding of how the widget tree behaves will help you grasp the concepts more clearly.

The Real Problem with Tab Navigation

A common way to implement tab navigation looks like this:

body: _tabs[_currentIndex],

At first glance, this seems correct and works for simple cases. But under the hood, something important happens every time the index changes.

Flutter removes the current widget from the tree and builds a new one. This means the previous tab is destroyed and the new tab starts from scratch.

This leads to a number of issues. Scroll positions are lost. Text fields reset. Network requests may run again. The overall experience feels inconsistent and sometimes frustrating to users.

Visualizing the Default Behavior

Without any form of state preservation, switching tabs behaves like this:

User selects a new tab

Current tab is removed from memory
New tab is created again
Visualizing the Default Behavior

At any point in time, only one tab exists in memory. Everything else is discarded.

Understanding IndexedStack

IndexedStack changes this behavior completely. Instead of rebuilding widgets, it keeps all of them alive and only changes which one is visible.

Internally, it stores all its children and uses an index to decide which one should be shown.

Here's a simple mental model of how it works:

IndexedStack
   ├── Tab 0
   ├── Tab 1
   ├── Tab 2
   └── Tab 3

Only one tab is visible
All tabs remain in memory

This means that when you switch tabs, nothing is destroyed. The UI simply switches visibility.

Why IndexedStack Improves User Experience

The most immediate benefit is that state is preserved. If a user scrolls halfway down a list in one tab, switches to another, and comes back, the scroll position remains exactly where they left it.

The same applies to form inputs, animations, and any UI state that would normally reset.

Another benefit is performance stability. Since widgets aren't rebuilt repeatedly, the application avoids unnecessary work. This is especially important when tabs contain heavy UI or expensive operations such as API calls.

Building a Task Manager Example

To make this more practical, let's look at a task manager application with four tabs. These tabs represent Today, Upcoming, Completed, and Settings.

Below is a full implementation using IndexedStack:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Task Manager',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const TaskManagerScreen(),
    );
  }
}

class TaskManagerScreen extends StatefulWidget {
  const TaskManagerScreen({super.key});

  @override
  State<TaskManagerScreen> createState() => _TaskManagerScreenState();
}

class _TaskManagerScreenState extends State<TaskManagerScreen> {
  int _currentIndex = 0;

  final List<Widget> _tabs = [
    TodayTasksTab(),
    UpcomingTasksTab(),
    CompletedTasksTab(),
    SettingsTab(),
  ];

  void _onTabTapped(int index) {
    setState(() {
      _currentIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Task Manager'),
      ),
      body: IndexedStack(
        index: _currentIndex,
        children: _tabs,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: _onTabTapped,
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.today),
            label: 'Today',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.upcoming),
            label: 'Upcoming',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.done),
            label: 'Completed',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: 'Settings',
          ),
        ],
      ),
    );
  }
}

class TodayTasksTab extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 50,
      itemBuilder: (context, index) {
        return ListTile(title: Text('Today Task $index'));
      },
    );
  }
}

class UpcomingTasksTab extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text('Upcoming Tasks'));
  }
}

class CompletedTasksTab extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text('Completed Tasks'));
  }
}

class SettingsTab extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text('Settings'));
  }
}

This Flutter application starts by running MyApp, which sets up a MaterialApp with a title, theme, and the TaskManagerScreen as the home screen. There, a stateful widget manages the currently selected tab index and uses an IndexedStack to display one of four tab screens while keeping all of them alive in memory.

A BottomNavigationBar allows the user to switch between tabs, and each tab is implemented as a separate stateless widget that renders its own content (such as a scrollable list for today’s tasks or simple text views for the other sections).

Handling Independent Navigation Per Tab

One limitation you'll quickly run into is this: while IndexedStack preserves the state of each tab, it doesn't automatically give each tab its own navigation stack.

In real applications, each tab often needs its own internal navigation. For example, in a task manager, the “Today” tab might navigate to a task details screen, while the “Settings” tab navigates to preferences screens. These navigation flows shouldn't interfere with each other.

To solve this, you can combine IndexedStack with a separate Navigator for each tab.

Conceptual Structure

IndexedStack
   ├── Navigator (Tab 0)
   │     ├── Screen A
   │     └── Screen B
   ├── Navigator (Tab 1)
   ├── Navigator (Tab 2)
   └── Navigator (Tab 3)

Each tab now manages its own navigation history independently.

Implementation

class TaskManagerScreen extends StatefulWidget {
  const TaskManagerScreen({super.key});

  @override
  State<TaskManagerScreen> createState() => _TaskManagerScreenState();
}

class _TaskManagerScreenState extends State<TaskManagerScreen> {
  int _currentIndex = 0;

  final _navigatorKeys = List.generate(
    4,
    (index) => GlobalKey<NavigatorState>(),
  );

  void _onTabTapped(int index) {
    if (_currentIndex == index) {
      _navigatorKeys[index]
          .currentState
          ?.popUntil((route) => route.isFirst);
    } else {
      setState(() {
        _currentIndex = index;
      });
    }
  }

  Widget _buildNavigator(int index, Widget child) {
    return Navigator(
      key: _navigatorKeys[index],
      onGenerateRoute: (routeSettings) {
        return MaterialPageRoute(
          builder: (_) => child,
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    final tabs = [
      _buildNavigator(0, const TodayTasksTab()),
      _buildNavigator(1, const UpcomingTasksTab()),
      _buildNavigator(2, const CompletedTasksTab()),
      _buildNavigator(3, const SettingsTab()),
    ];

    return Scaffold(
      body: IndexedStack(
        index: _currentIndex,
        children: tabs,
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: _onTabTapped,
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.today), label: 'Today'),
          BottomNavigationBarItem(icon: Icon(Icons.upcoming), label: 'Upcoming'),
          BottomNavigationBarItem(icon: Icon(Icons.done), label: 'Completed'),
          BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
        ],
      ),
    );
  }
}

This implementation of TaskManagerScreen uses a stateful widget to manage tab navigation by maintaining the current tab index and a separate Navigator for each tab through unique GlobalKeys. This allows each tab to have its own independent navigation stack.

The _onTabTapped method either switches tabs or resets the current tab’s navigation to its root if tapped again. The IndexedStack ensures all tab navigators remain alive in memory while only the selected one is visible, resulting in preserved state and seamless navigation across tabs.

What This Solves

Each tab now behaves like a mini app. Navigation inside one tab doesn't affect another tab. When a user switches tabs and comes back, they return to exactly where they left off, including nested screens.

This is the pattern used in production apps like banking apps, social platforms, and dashboards.

Combining IndexedStack with State Management

Another mistake developers make is relying on IndexedStack as a full state management solution. But it's not that.

IndexedStack preserves widget state, but it doesn't manage business logic or shared data.

For scalable applications, you should still use a proper state management solution such as BLoC, Provider, or Riverpod.

Example with BLoC

Each tab can listen to its own stream of data while still being preserved in memory.

class TodayTasksTab extends StatelessWidget {
  const TodayTasksTab({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<String>>(
      stream: getTasksStream(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return const Center(child: CircularProgressIndicator());
        }

        final tasks = snapshot.data!;

        return ListView.builder(
          itemCount: tasks.length,
          itemBuilder: (context, index) {
            return ListTile(title: Text(tasks[index]));
          },
        );
      },
    );
  }
}

Because the tab isn't rebuilt, the stream subscription remains stable and doesn't restart unnecessarily.

Performance Considerations

You need to be deliberate here. IndexedStack keeps everything alive, which means memory usage grows with each tab.

Internal Behavior

All children are built once
All remain mounted
Only visibility changes

This is efficient for interaction but not always for memory.

When This Becomes a Problem

If each tab contains heavy widgets like large lists, images, or complex animations, memory usage can increase significantly.

In extreme cases, this can lead to frame drops or even app crashes on low-end devices.

Practical Strategy

Use IndexedStack for a small number of core tabs. Usually between three and five is reasonable.

If you find yourself adding many more screens, reconsider your navigation structure instead of forcing everything into a single stack.

Common Mistakes

One common mistake is assuming IndexedStack delays building widgets. It doesn't. All children are built immediately.

Another mistake is mixing IndexedStack with logic that expects rebuilds. Since widgets persist, some lifecycle methods may not behave as expected.

Developers also sometimes forget that memory is being retained, which leads to subtle performance issues later (as we just discussed).

Mental Model That Will Save You Time

Think of IndexedStack as a visibility switch, not a navigation system.

Navigator → controls screen transitions
IndexedStack → controls visibility of persistent screens
State management → controls data and logic

Once you separate these concerns, your architecture becomes much clearer and easier to scale.

Visual Comparison

To really understand the difference, compare both approaches.

Without IndexedStack:

Switch Tab
→ Destroy current screen
→ Rebuild new screen
→ Lose state

With IndexedStack:

Switch Tab
→ Keep all screens alive
→ Only change visibility
→ State remains intact

Important Trade-off

It's important to remember that IndexedStack keeps all children in memory at the same time.

Again, this is usually fine for a small number of tabs, but if each tab contains heavy widgets or large data sets, memory usage can increase.

So the decision isn't just about convenience. It's about choosing the right tool for the right scenario.

If your tabs are lightweight and require state preservation, IndexedStack is a strong choice. If your tabs are heavy and rarely revisited, rebuilding them might actually be better.

So to summarize:

  • IndexedStack is ideal when each tab has its own independent state and the user is expected to switch between them frequently. It is especially useful in dashboards, task managers, finance apps, and social apps where continuity matters.

  • If your application has a large number of screens or each screen consumes significant memory, keeping everything alive can become inefficient. In such cases, using navigation with proper state management solutions like BLoC, Provider, or Riverpod may be a better approach.

Conclusion

IndexedStack is simple on the surface, but its real power shows up in complex applications where user experience matters. It eliminates unnecessary rebuilds, preserves UI state, and creates a smoother interaction model.

But make sure you use it intentionally. It's not a replacement for navigation or state management, but a complementary tool.

If you combine it correctly with nested navigation and proper state management, you get an architecture that feels seamless to users and remains maintainable as your app grows.



Read the whole story
alvinashcraft
28 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Enhance GitHub Copilot CLI with skills

1 Share

Coding agents like GitHub Copilot are pretty cool. You can ask them to do pretty much anything coding related and they’ll do a good job. That is, of course, assuming you ask for something they have been trained on. But what if you ask them about something they don’t know? How can you ’train’ these agents with additional information? The answer is skills!

What are skills

Skills are markdown files that provide explicit instructions to Copilot related to one or more tasks. What makes them special is that skills are part of an open standard, so anyone can create skills that are then made available to Copilot.

Skills can instruct Copilot to access online documentation for your application, or guide it on how to configure code to access your service. If you have any tool or service that you want developers to use, you want to create skills that developers can import and use to tell Copilot how to interact with your project.

As a user, you can create or install skills at a project level, or a global level. They live in the .github/skills/ folder (or other folder for different coding agents) in yur project, or ~/.copilot/skills/ in your home folder for global skills. These files are then read by Copilot when you launch it.

Build your first skill

To create a skill, open a project, and inside the .github folder (create one if you don’t have one), create a folder called skills. In this folder, create a file called starwars.md. In this file, put the following text:

---
name: star-wars
description: This skill provides details on how to react to certain user instructions
---

# Skill Instructions

If the user says hello there, always respond with "General Kenobi".

This is a very simple skill, telling Copilot to answer one specific prompt in the style of Obi-Wan Kenobi.

Now launch the Copilot CLI, then run /init to parse the skill.

Once the skill is loaded, prompt the CLI with the following:

❯ Hello there

The skill instructs Copilot exactly what to do in this situation, so you get the response:

● General Kenobi.

More useful skills

Now it’s debatable how useful a Star Wars skill is. Some would say very, but others may disagree. Where skills become more powerful is when you add detailed useful instructions related to tools or services.

For example, if you have a SaaS product, and you want coding agents to interact with it, what do you do. You could create an MCP server, which is a lot of work, especially if you already have a CLI for your users to use. Instead you could write a skills file that instructs the agent on how to use your CLI tool. You can then release CLI updates along with skill updates, and the coding agents are ready to use it immediately.

Skill standards

To make skills work, there needs to be standards! The Agent Skills standard has been created by Anthropic, and is used by pretty much all the agents. This spec defines how you define your own skills, the format for the documentation you provide with each skill, and so on.

Skills can live in a folder, so can be installed for a single project, or at a user level so are available to all projects. For example, you might want a skill to interact with the GitHub CLI available everywhere, so you would install it at the user level. Then when working on an AI app, you would want the Arize skill in the folder for your project so that it doesn’t confuse a coding agent working on a non-AI project.

The only non-standard is where skills live. Claude wants skills in the .claude folder. GitHub Copilot wants them in the .copilot folder, but will also use skills in the .claude folder, which makes it easier to migrate from Claude to Copilot.

Awesome Copilot

The Awesome Copilot repo contains a mix of skills, agent definitions, plugins (containing multiple skills in one package), and more, that can be installed into any agent.

You can install a plugin for example, using this command:

copilot plugin install <plugin-name>@awesome-copilot

Replacing <plugin-name> with the name of the relevant plugin.

Vercel skills package

Vercel published an open source tool for managing skills. This tool makes it easy to install tools from a repo into any project. They have a registry of skills you can reference, or you can install from anywhere.

For example, to install skills from the Arize skill, use the following command:

npx skills add Arize-ai/arize-skills

You can then interactively choose which skills, which coding agent, and the scope (user or project).

Summary

Skills are a really powerful way to expand the capabilities of your coding agent, or to make your product available to your users agents.

Read the whole story
alvinashcraft
28 minutes ago
reply
Pennsylvania, USA
Share this story
Delete

Random Forest Regression Using C#

1 Share
Dr. James McCaffrey presents a complete end-to-end example of random forest regression to predict a single numeric value, implemented using C#. A random forest is a collection of basic decision tree regressors that have been trained on different subsets of the source training data. The technique reduces model overfitting to give more accurate predictions on new, previously unseen data.
Read the whole story
alvinashcraft
28 minutes ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories