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

Links For You (6/21/26)

1 Share

Greetings and salutations, readers. It's been a few weeks since I shared one of these, mostly due to the job search being somewhat exhausting, but I've got a backup of links so it's time to get back in the habit. And of course, it's Father's Day and I want to wish all the dads out there (myself included) a very happy father's day. This weekend I got to officiate my first wedding (for my brother-in-law and his fiance) so my plan today is to do... nothing. Enjoy your links!

Mastodon and Translation with Chrome AI

First up is a presentation by Thomas Steiner demonstrating Chrome built-in AI APIs doing language detection and translation for Mastodon. I'm a pretty big fan of those APIs (my last presentation was on them!) so I enjoyed this quite a bit. Thomas has been a big help with my demos and posts on these APIs and is a scary smart dev.

Play Video

Datatype - Text into Charts

Next is Datatype, a font that creates charts. Seriously. For example:

Sales {l:20,45,60,55,80,95} are up this quarter.

And this was driven by CSS and text:

<style>
@font-face {
  font-family: 'Datatype';
  src: url('https://static.raymondcamden.com/fonts/Datatype-Regular.woff2') format('woff2');
  font-weight: 100 900;      /* Variable weight axis */
  font-stretch: 0% 100%;     /* Variable width axis */
  font-display: swap;
}

.chart {
  font-family: 'Datatype', monospace;
}
</style>

<span class="chart">{l:20,45,60,55,80,95}</span>

It supports bar charts, sparklines, and pie charts. As it's just text, in theory it would be easy to animate and make it 'live' with just a bit of JavaScript.

You Don't Know HTML Lists

Finally there's a spectacular deep dive into HTML lists by Frank Taylor, You don't know HTML lists. You know this is going to be a great article with a sentence like this in the intro:

"We're skipping over the MDN and W3Schools introductory pages and instead we're going into the kind of stuff you discover after accidentally taking your cousin's Ritalin right before you open up the W3C specs."

I knew maybe... half of this? Maybe a bit more? Either way, it's a damn good investigation into a part of HTML you may not know even got that complex.

Just For Fun

Looking for your next read? Are you mostly through your current book and getting a bit of anxiety over whether or not you'll have your next read as soon as you finish? Good news, you're in luck. I've spoken about Scott Stroz in the past (and linked to some of his cool blogs too), he's one of my oldest, and best friends. He's a father as well to two incredible kids, one of which just released his first novel, "The Dreaded."

The Dreaded cover

Tyler's shared some of his works for me in the past so as soon as this one became available, I went ahead and purchased a copy for myself. Grab your copy today - available on Kindle, paper and hardback.

Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

Making A Guided Animated Tour For A Blazor App

1 Share
On Reddit I saw the following post:   The Github project is at: https://github.com/MiracleFoundation/GuideFlow   The project has excellent documentation: https://miraclefoundation.github.io/GuideFlow/   These days good documentation is all you need to supply your AI with the information it needs to leverage any library or tool. I decided to make a guided tutorial for my Blazor RFP Response Creator app located at: https://github.com/BlazorD
Read the whole story
alvinashcraft
11 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Migrating Agentic Code Python -> C# Part 4

1 Share

In the previous blog post we looked at the Blogger (orchestrator) code in C#. Let’s move on to some of the other agents.

The Blogger invokes the Researcher, so let’s go there next.

The Researcher class is created with an IChatClient (the principal object for llms), a set of options and the search tool (Tavily)

using System.Text.Json;
using Microsoft.Extensions.AI;

namespace BlogMigration;

/// <summary>Creates a researcher agent that uses Tavily search.</summary>
public class ResearcherAgent(IChatClient llm, ChatOptions chatOptions, AIFunction tavilyTool) : IResearcherAgent
{

The main method is InvokeAsync which gets a copy of the query and uses Tavily to search the web using that query. The results are JSON, and the next step is to extract a JsonDocument object by parsing these results.

try
        {
            object? searchResult = await tavilyTool.InvokeAsync(
                new AIFunctionArguments { ["query"] = query });

            string searchJson = searchResult switch
            {
                JsonElement je => je.ValueKind == JsonValueKind.String ? je.GetString() ?? "{}" : je.GetRawText(),
                string s => s,
                _ => searchResult?.ToString() ?? "{}"
            };

            var formattedResults = new List<string>();

            using (JsonDocument document = JsonDocument.Parse(searchJson))
            {
                if (document.RootElement.TryGetProperty("results", out JsonElement results)
                    && results.ValueKind == JsonValueKind.Array)
                {
                    foreach (JsonElement result in results.EnumerateArray().Take(3))
                    {
                        string title = result.TryGetProperty("title", out JsonElement t) ? t.GetString() ?? "Untitled" : "Untitled";
                        string url = result.TryGetProperty("url", out JsonElement u) ? u.GetString() ?? "N/A" : "N/A";
                        string content = result.TryGetProperty("content", out JsonElement c) ? c.GetString() ?? "" : "";
                        string snippet = content.Length > 250 ? content[..250] : content;
                        formattedResults.Add($">>{title}\nSource: {url}\n{snippet}...\n");
                    }
                }
            }

            string rawOutput = formattedResults.Count > 0
                ? string.Join("\n", formattedResults)
                : "No results found";

We next instruct the llm using a system prompt, passing in the raw output we just created. We get back the summary of the findings and if that is not empty we return it.

           string summaryPrompt = $"""
                Based on these search results about '{query}',
                provide a concise summary of key findings:
                {rawOutput}
                """;

            ChatResponse summaryResponse = await llm.GetResponseAsync(summaryPrompt, chatOptions);
            string summary = summaryResponse.Text;

            return !string.IsNullOrEmpty(summary) ? summary : rawOutput;

Finally, we handle any exceptions raised

       catch (Exception e)
        {
            Console.WriteLine($"Research error: {e.Message}");
            return $"Research completed on: {query}. Key information has been gathered from web sources.";
        }
 

As we did with Blogger, we also create a Node, passing in the state and getting back the updated state.

   public async Task<ResearchState> ResearchNodeAsync(ResearchState state)
    {
        Console.WriteLine("\n>>>RESEARCHER");

        string subTask = !string.IsNullOrEmpty(state.CurrentSubTask) ? state.CurrentSubTask : state.MainTask;
        Console.WriteLine($"Researching: {subTask}");

        string findings;
        try
        {
            findings = await InvokeAsync(subTask);
            string preview = findings.Length > 100 ? findings[..100] : findings;
            Console.WriteLine($"Found: {preview}...");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Research error: {e.Message}");
            findings = $"Research on {subTask} - information gathered";
        }

        state.ResearchFindings.Add(findings);
        return state;
    }

In the next blog post we’ll look at the Author

Read the whole story
alvinashcraft
20 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

File-based WinUI apps with Microsoft.UI.Reactor

1 Share

One of the things I've been wanting to try for a while was whether Reactor could work nicely with .NET file-based apps.

Turns out: it can.

The idea is pretty simple. Instead of creating a full project, you put everything in a single App.cs file, add a few #: directives at the top, and run it directly with `dotnet run`.

The smallest example

Here's a complete Reactor app in one file:

#:property TargetFramework=net10.0-windows10.0.22621.0
#:property WindowsAppSDKSelfContained=true
#:package Microsoft.UI.Reactor@0.1.0-*

using Microsoft.UI.Reactor;
using Microsoft.UI.Reactor.Core;
using static Microsoft.UI.Reactor.Factories;

ReactorApp.Run<App>("SingleFileReactor", width: 900, height: 600);

class App : Component
{
    public override Element Render()
    {
        var (name, setName) = UseState("World");

        return VStack(
            Heading($"Hello, {name}!"),
            TextBox(name, setName, placeholderText: "Your name")
                .AutomationName("NameInput")
        ).Padding(16);
    }
}

Save that as `App.cs`, then run: dotnet run App.cs -a x64

The -a x64 part matters here. Since the script uses WindowsAppSDKSelfContained=true, you need to tell the build which Windows architecture you want (you could also add #:property RuntimeIdentifier=win-x64 to the header instead)

And that's really it. You get a native desktop window with a heading and a text box, and as you type your name, the greeting updates live.

What the directives do

The three lines at the top do most of the magic:

#:property TargetFramework=net10.0-windows10.0.22621.0
#:property WindowsAppSDKSelfContained=true
#:package Microsoft.UI.Reactor@0.1.0-*

The target framework makes this a Windows app targeting WinUI.

WindowsAppSDKSelfContained=true makes sure the Windows App SDK bits are available the way the app expects.

And the package line is just a normal NuGet dependency, except declared inline for the file-based app model.

A normal Reactor app created from the project template is still the right place to start for a "real" app. You get a .csproj, a proper project structure, and something you can keep growing.

But file-based apps open up a different kind of scenario.

Sometimes you don't want to start a project. Sometimes you just want a little tool.

Maybe you want:

  • a quick internal utility
  • a tiny prototype
  • a one-off helper app
  • a script that sometimes needs a proper interactive UI

That's where this gets really fun.

Mixing scripting with a real UI

I often use file-based apps for running little scripts with C# instead of using Batch or Bash. This got me the idea that you can create a script that can either run in plain console mode, or pop a UI if you ask for interactive mode.

Here's a cleaned up version of that:

#:property TargetFramework=net10.0-windows10.0.22621.0
#:property WindowsAppSDKSelfContained=true
#:package Microsoft.UI.Reactor@0.1.0-*

using Microsoft.UI.Reactor;
using Microsoft.UI.Reactor.Core;
using Microsoft.UI.Xaml;
using static Microsoft.UI.Reactor.Factories;

if (args.Length > 0 && (args[0] == "-i" || args[0] == "--interactive"))
{
    Console.WriteLine("Waiting for user to enter their name...");
    ReactorApp.Run<EnterUsernameApp>("Username", width: 300, height: 130);
}
else
{
    Console.WriteLine("Enter your user name:");
    AppState.Username = Console.ReadLine() ?? string.Empty;
}

if (string.IsNullOrEmpty(AppState.Username))
{
    Console.WriteLine("No username entered.");
    return -1;
}

Console.WriteLine($"Hello {AppState.Username}!");
return 0;

class EnterUsernameApp : Component
{
    public override Element Render()
    {
        var (name, setName) = UseState("");

        return VStack(
            TextBox(name, setName, placeholderText: "Enter username")
                .AutomationName("UsernameInput"),
            Button("Accept", () =>
                {
                    AppState.Username = name;
                    ReactorApp.PrimaryWindow?.Close();
                })
                .IsEnabled(!string.IsNullOrEmpty(name))
                .HAlign(HorizontalAlignment.Stretch)
        ).Padding(10);
    }
}

static class AppState
{
    public static string Username { get; set; } = string.Empty;
}

Run it in console mode: dotnet run App.cs -a x64
Or launch the UI mode: dotnet run App.cs -a x64 -- -i

If you're writing automation or a developer tool, that can be incredibly useful. Most of the time maybe the script can stay headless and work in the terminal. But if the user needs to make a choice, enter a value, or confirm something in a friendlier way, you can just pop a real window. Another example could be that you can either provide filenames as arguments, or if you don't provide this as argument, a UI allowing you to browse to the required files instead.

Is this how you should build every app?

Nope! Once the app grows beyond a quick tool or prototype, a normal project structure is still going to be much easier to maintain.

But for small utilities? Demos? Quick experiments? Interactive scripts, this is really nice.

I especially like that it lowers the bar for building little native Windows helpers. If I can keep a whole app in one file and still get a proper WinUI window, I'm far more likely to reach for a native UI instead of settling for a clunky prompt loop.

And that's probably the biggest compliment I can give this setup: it makes a real Windows UI feel cheap enough to use for the small stuff too.

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

Android Weekly Issue #732

1 Share
Articles & Tutorials
Sponsored
Only 7% of mobile EMs are confident anyone on their team could run a release end to end. The rest are one resignation away from a stall. Our 2026 Decision Guide shows where release knowledge actually sits and how the fastest teams move it out of a few people's heads. Free read.
alt
Marco Gomiero reflects on ten years of his RSS-Parser library, tracing its evolution from Java to Kotlin Multiplatform.
Maia walks through migrating her Android TagSpotter app to KMP across iOS, Desktop, and Android in a weekend using Antigravity and parallel subagents.
Sponsored
Mobile reflects reality, and it’s messy: Intermittent connections, mid-onboarding drop-offs, force quits, and more. bitdrift captures 100% of real-time data, unsampled across 1B+ installs, so you and your agents can query reality. Try bitdrift: mobile observability for the real world.
alt
Ivan Mikhailuts explains how he built an Android Studio plugin offering live AGSL shader preview, uniform controls, and full editor support.
James Cullimore shows how to use Compose Previews as the source of truth for screenshot testing across locales, font scales, and string-key display mode.
Jaewoong Eum explains Jetpack Compose internals — compiler transformations, the SlotTable, snapshot state, and the single-pass layout pipeline — traced through AOSP source.
Swapnil Gupta shares an honest 11-week review of Android Journeys powered by Gemini, covering CI setup challenges, test writing lessons, and production results.
Marcin Moskała explains why truly learning Kotlin requires letting go of Java preconceptions rather than treating it as syntactic sugar.
KMP Bits shows how Coil 3 simplifies cross-platform image loading and caching in Compose Multiplatform for Android and iOS.
Jaewoong Eum introduces Compose HotSwan v2, which enables full-screen structural hot reloads in native Jetpack Compose without app restarts.
Place a sponsored post
We reach out to more than 80k Android developers around the world, every week, through our email newsletter and social media channels. Advertise your Android development related service or product!
alt
Jobs
Join Chordify as an Android Developer in our Monetization team and build Premium, payment, subscription, and conversion features for musicians worldwide. Work with Kotlin, data, A/B tests, and product impact while improving our Android app.
Libraries & Code
A Kotlin Multiplatform library for VIN decoding, validation, and NHTSA API integration, targeting Android, iOS, and JVM.
A Gradle plugin that bakes runtime self-protection into your APK, detecting root, hooks, clones, and tampering entirely on-device.
News
Google announces Android XR Developer Preview 4 with new tooling, Unreal Engine and Godot support, and glasses-focused APIs.
Google releases Android 17, introducing adaptive-first large-screen requirements, on-device AI via AppFunctions, and next-generation privacy and performance.
Google announces Android developer verification launches September 2026 in four countries, with new bulk-registration APIs and a 2027 global rollout.
Google previews the Geospatial API in ARCore for Jetpack XR, demonstrating a Gemini-powered immersive walking tour app.
Mark Murphy considers whether Maven Central's dominance over artifact distribution creates unhealthy ecosystem centralization.
Jake Wharton announces Retrofit, OkHttp, Okio, and SQLDelight are moving to the Commonhaus Foundation under the new lysine.dev organisation.
Videos & Podcasts
Dave Leeds covers Kotlin 2.4's new Collection Literals, letting you declare collections with bracket syntax.
alt
Android Developers rounds up the latest Android XR development updates, tools, and resources for building immersive apps.
Android Developers shows how to build and test Android XR apps without any physical hardware.
Kotlin by JetBrains marks 15 years of Kotlin by showing how its principles of conciseness and efficiency play out in everyday situations.
Android Developers covers building Android XR apps with Unity, Unreal Engine, and Godot using the new XR Engine Hub and Interaction Framework.
Philipp Lackner discusses why AI tooling is likely to improve rather than degrade overall codebase quality.
Kotzilla demonstrates diagnosing and fixing Android ANRs and slow screens using their MCP server with session data.
Android Developers summarizes the latest updates and tools for building Android XR apps in 2026.
Code with the Italians live-streams building an Android app and learning Jetpack Compose from scratch.
Android Developers covers the five key AOSP updates landing with Android 17, from adaptive layouts to granular privacy pickers.
Read the whole story
alvinashcraft
35 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

The 5-Minute AI Weekly Recap: Realignment Week

1 Share
From: AIDailyBrief
Duration: 5:57
Views: 495

This week, the Fable fallout became a broader realignment across AI, pushing more attention toward open models, model routing, local control, and the risks of building around any single frontier system. GLM 5.2, OpenRouter’s Fusion, SpaceX’s Cursor acquisition, and Europe’s AI sovereignty scramble all point to the same shift: the model ecosystem is getting more fragmented, more strategic, and more contested.

Register for our new enterprise-grade AI training programs: ⁠⁠http://training.besuper.ai/⁠⁠

The AI Daily Brief helps you understand the most important news and discussions in AI.
Subscribe to the podcast version of The AI Daily Brief wherever you listen: https://pod.link/1680633614
Get it ad free at http://patreon.com/aidailybrief
Learn more about the show https://aidailybrief.ai/

Read the whole story
alvinashcraft
43 seconds ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories