I built the VS Code Remote WSL extension, but for GitHub Desktop

If you use GitHub Desktop with repos stored in WSL, you know the pain. Every operation takes 10-30 seconds. Switching branches? 30 seconds. Fetching? 10 seconds. Even git status on a tiny repo takes 40ms+ because Desktop runs git.exe on Windows, which accesses WSL files through the 9P protocol — every file stat is a round-trip across the VM boundary.

Meanwhile, VS Code solved this years ago with the Remote WSL extension. It runs a server inside WSL and talks to it over a socket. Fast, native, no 9P overhead.

I wanted the same thing for GitHub Desktop. So I built it.

What it does

GithubDesktopWSL is a fork of GitHub Desktop that runs a lightweight daemon inside WSL. The daemon handles git commands and file operations natively over TCP. Desktop connects to it instead of going through 9P.

Official Desktop (slow):
  Desktop -> git.exe -> 9P -> VM boundary -> WSL -> ext4

This fork (fast):
  Desktop -> TCP -> daemon -> git (native) -> ext4

The daemon is bundled in the installer. When you open a WSL repo, it deploys and starts automatically. There’s nothing to configure.

Performance

Operation Fork Official Speedup
git status 2 ms 43 ms 20x
git log 2 ms 41 ms 24x
Open repo 16 ms 173 ms 11x
git rev-parse 2 ms 41 ms 27x

The ~40ms floor in official Desktop is the cost of launching git.exe through 9P. The daemon has ~2ms overhead (TCP round-trip + message framing). The actual git work is the same.

How it works

Three components:

wsl-git-daemon (C, ~550 lines) — persistent daemon inside WSL. Listens on localhost TCP, handles git commands and file operations (read, write, stat, unlink). Token-based auth.

wsl.ts (TypeScript, ~490 lines) — Desktop-side client. Detects WSL paths, manages daemon lifecycle (deploy, start, restart), implements the binary protocol, provides drop-in wrappers for fs operations.

core.ts patch (1 if-block) — all git commands in Desktop flow through one function. A single if (isWSLPath(path)) routes WSL repos through the daemon. Windows repos are completely untouched.

What else it fixes

Beyond performance:

  • SSH keys just work — daemon runs in WSL natively, so ~/.ssh/ keys are accessible. No more SSH_ASKPASS issues.
  • No CRLF problems — git runs in Linux, line endings stay as they should.
  • File operations work — diffs, merge state, .gitignore reads/writes all go through the daemon.
  • Repo deletion works — handles WSL UNC paths that Windows Recycle Bin can’t.

Staying current

It’s patch-based — 6 patch files applied on top of upstream releases via git apply. CI checks for new upstream releases every 6 hours, applies patches, builds, and publishes automatically. So it stays current with official Desktop features.

Installs side-by-side with official Desktop. You can keep both.

Try it

Download the installer from the releases page, run it, open a WSL repo. That’s it.

Would love feedback, especially if you hit any issues with specific WSL distros or repo setups.

GitHub logo

aleixrodriala
/
GithubDesktopWSL

GitHub Desktop with native WSL support — 6-27x faster git operations

GitHub Desktop WSL

Think of it like the VS Code Remote WSL extension but for GitHub Desktop. A fork of GitHub Desktop that makes WSL repositories work properly — 6-27x faster git operations, working SSH keys, and no more CRLF issues.

Download the latest release — installs side-by-side with official GitHub Desktop

The problem

Official GitHub Desktop can’t handle repos inside WSL. When you open a \wsl.localhost... path:

  • Git commands are unusably slow — Desktop runs Windows git.exe, which accesses WSL files through the 9P protocol. Every file stat, read, and open is a round-trip across the VM boundary.

  • SSH keys don’t work — Desktop injects a Windows-only SSH_ASKPASS binary that breaks SSH inside WSL.

  • File operations fail — Checking merge/rebase state, reading diffs, writing .gitignore — all go through 9P and are either slow or broken.

  • Deleting repos fails — Windows Recycle Bin doesn’t support WSL…

66 Analytics Tools Your AI Agent Didn’t Know It Needed

66 Analytics Tools Your AI Agent Didn’t Know It Needed

I check my analytics dashboard maybe twice a week. Which means I miss the spike on Tuesday and the crash on Thursday, every single time. By the time I notice something interesting happened, it’s three days old and the moment is gone.

This is the fundamental lie of analytics: the data is always there, but you are never looking at it when it matters.

The Dashboard Problem

Here’s what kills me about analytics tools. We spend real money and real engineering hours setting them up. We add tracking scripts. We configure events. We define goals and funnels. We wire up UTM parameters across every campaign. All this effort to collect data.

Then we don’t look at it.

It’s not laziness. It’s friction. The information exists in a place that requires context-switching. You have to leave your workflow, open a browser, authenticate, and then manually interrogate the data by clicking around. By the time you’ve done all that, you forgot what question you were trying to answer.

This is especially painful with Umami. I switched to it from Google Analytics about a year ago because I was tired of feeding Google my users’ data. Umami is privacy-first, open-source, and genuinely pleasant to self-host. The dashboard is clean. The data is honest. But it’s still a dashboard. And I still don’t look at it enough.

Making Analytics Conversational

So I built umami-mcp. It’s an MCP server that exposes the entire Umami API v2 as tools your AI agent can call. 66 of them.

That number isn’t padding. Umami’s API surface is genuinely large — website management, analytics queries, report generation, real-time monitoring, user administration, event tracking. The MCP server covers all of it.

Setup takes about thirty seconds:

{
  "mcpServers": {
    "umami": {
      "command": "npx",
      "args": ["-y", "@mikusnuz/umami-mcp"],
      "env": {
        "UMAMI_URL": "https://analytics.yourdomain.com",
        "UMAMI_USERNAME": "admin",
        "UMAMI_PASSWORD": "your-password"
      }
    }
  }
}

Point it at your Umami instance — self-hosted or Umami Cloud, doesn’t matter — and your AI agent now has full read-write access to your analytics. No API keys to generate, no OAuth dance. Just your Umami credentials.

What This Actually Feels Like

The shift is subtle but significant. Instead of going to your analytics, your analytics come to you.

Me: How did the blog do last week? Anything unusual?

Claude: Looking at your blog stats for March 16-22...
    - 4,287 pageviews (up 34% from previous week)
    - Top page: "/mcp-app-store" with 1,891 views
    - Traffic spike on Tuesday — 1,203 views, mostly from Hacker News
    - Bounce rate dropped to 42% (was 58%)
    - Top referrer: news.ycombinator.com (847 sessions)
    You had a solid HN hit on Tuesday that you probably missed.

Yeah. I did miss it. I always miss it. But now I don’t have to remember to check — I just ask when it crosses my mind, mid-conversation, while I’m already working on something else.

The report generation is where it gets genuinely useful. Umami supports funnel reports, retention analysis, UTM attribution, goal tracking, and revenue tracking. All of those are available as MCP tools.

Me: Build me a funnel report for the signup flow.
    Steps: landing page -> pricing page -> signup page -> dashboard.
    Last 30 days.

Claude: Creating funnel report "Signup Flow - March"...
    Step 1: /landing — 12,847 visitors
    Step 2: /pricing — 3,201 (24.9% of step 1)
    Step 3: /signup — 891 (27.8% of step 2)
    Step 4: /dashboard — 634 (71.2% of step 3)

    Overall conversion: 4.9%
    Biggest drop-off: landing to pricing (75.1% lost).
    Once people see pricing, about a quarter continue. And your
    signup-to-activation rate is actually strong at 71%.

Try getting that out of a dashboard in under five minutes. You’d be clicking through menus, configuring date ranges, adding funnel steps one by one. Here it’s one sentence and you get the data plus interpretation.

The Real-Time Angle

This one changed how I think about monitoring. Umami has a real-time API, and umami-mcp exposes it. Your agent can check active visitors, current pages being viewed, and live referrer data.

The interesting move is combining this with your normal workflow. You push a new blog post, share it on Twitter, and ten minutes later you ask: “Anyone reading the new post yet?” Instead of nervously refreshing a dashboard tab, you get a quick answer and move on.

For product launches, this is even more powerful. Ask your agent to check real-time traffic periodically and flag anything unusual. Not a formal alerting system with webhook configs and threshold settings — just a conversational check-in that takes two seconds.

66 vs. 5

Most analytics MCP integrations I’ve seen offer maybe 5-10 tools. Get pageviews. Get top pages. Get referrers. Basic read-only stuff. That’s fine for a quick glance, but it’s not enough to replace the dashboard.

66 tools means you can actually stop opening the Umami UI for almost everything. Website management — create, update, delete, reset. Full analytics queries — stats, pageviews, metrics, sessions, events, with proper date ranges and filters. Report CRUD — create funnel reports, retention reports, save them, share them. User and team administration. Even batch event tracking if you’re sending data programmatically.

The point isn’t that any single tool is revolutionary. It’s that comprehensive coverage eliminates the last excuse to open the dashboard. When your agent can do everything the UI can do, you just stop going there.

The Privacy-First Part

I should mention why Umami specifically. If you’re using Google Analytics, you’re sending your visitors’ data to Google. You know this. You’ve accepted it, or you’ve added a cookie banner and pretended that fixes things.

Umami is self-hosted (or cloud-hosted by them, not by an ad company). No cookies. No personal data collection. GDPR-compliant by default, not by configuration. Connecting that to an MCP server means your analytics data stays in your infrastructure. The agent talks to your Umami instance directly. Nothing goes through a third party — it flows from your server to your local agent and nowhere else.

The Honest Bit

This isn’t going to replace proper observability tooling. If you need PagerDuty-level alerting with escalation policies and on-call rotations, that’s a different problem. This is for the 90% of analytics interactions that are just “I’m curious, show me the numbers.”

The write operations — creating websites, managing users, sending events — require some trust in your agent not to do something dumb. Start with read-only use cases and work up from there. The analytics queries alone are worth the setup.

Also, Umami’s API has rate limits. If you ask your agent to run twenty complex queries in rapid succession, you might hit them. Be conversational, not adversarial.

The Bottom Line

I’ve been running this for a few weeks now. My analytics habit went from “check dashboard twice a week, miss everything important” to “ask a question whenever I’m curious, actually know what’s happening.” That’s it. That’s the whole pitch.

66 tools. Privacy-first analytics. No more dashboard tab collecting dust in your browser.

Install it. Ask your agent how your site did yesterday. You’ll be surprised what you’ve been missing.

Alan West is a full-stack developer based in San Francisco who ships too many side projects and complains about developer tools on the internet. Find him on GitHub or don’t — he’ll be in his terminal either way.

Job Hunting Used To Be Easy

I’m spoiled, no doubt about it. I used to listen to a career-oriented software development podcast where the running joke was that the most common advice for every user-submitted question was “quit your job.” It was that easy to find a new one, one that would pay better, a guaranteed pay raise, and perhaps a promotion to boot. It was a common remedy with little risk that cured all manner of dissatisfaction, from toxic culture to mismanagement to stagnation. Staying in one place could lead to advancement, but not always. Besides that, the risk of failing to capture your market value was high. Now, the calculus has changed. If I could turn back time, I would slap myself and say, “Be happy where you are! You’ll grow! Your pay is sufficient! Make it work!” Unfortunately, it’s too late for me. Now I’m swimming in the sea of LLM-infested waters, tossed to and fro by poorly constructed coding challenges that reward swift implementation over thought-out solutions. Interviewers are rowing around me in their employment boats, taunting me with life preservers. All I have to do is recite the mantra “details-shmetails” and play the game. I need to slap together rote solutions. I need to parrot opinions about the usefulness of NgRx signal stores. I need to add details to my resume that a software engineer should not be expected to know, like the percentage of revenue growth “Feature A” generated, ignoring the cost, of course. I need to boast about my AWS experience, as if it carries more weight than my lengthy Azure experience. As if they’re not direct competitors offering the same features to win business. Have I used AWS Lambdas? Yes, and I’ve used Azure Functions. Have I used EKS? Yes, and I’ve used AKS too. The list goes on. I know that I’m a gem. I like to pore over code bases, read documentation, spin up pet projects, understand the business I serve, and share what I learn. I temper all of this with a desire to increase revenue and minimize expenses. Unfortunately, I’m a horrible salesman, unable to sell myself to the next would-be employer when it really counts. I know there are solutions out there for me. I can practice coding challenges and answer system design questions. I can review common interview questions and embellish my production support experiences. I can play the game, and I’ll probably land a job, but when I climb into the boat, I think that my soul will be left behind, floating face down in the water.

I Tested 12 LLMs With Few-Shot Examples. The Results Were Not What I Expected.

Learning curves for route optimization. Gemini 3 Flash (red) collapses from 93% to 30%, while Gemma 3 27B (green, same model family) stays stable around 90%.

In a previous article, I tested 8 models across 4 tasks and reported on “few-shot collapse” — cases where adding few-shot examples actually degrades LLM performance.

This time, I expanded the experiment to 12 models (6 cloud + 6 local) and 5 tasks to see whether those findings hold at a larger scale. They do — and I found even more dramatic cases, including a model that dropped from 93% to 30% with more examples.

What I tested

I evaluated 12 models — 6 cloud APIs and 6 local models — across 5 tasks designed to mirror real business scenarios.

Cloud models: Claude Haiku 4.5, Claude Sonnet 4.6, Gemini 2.5 Flash, Gemini 3 Flash, GPT-4o-mini, GPT-5.4-mini

Local models: Gemma 3 27B, LLaMA 4 Scout (17B active, MoE), GPT-OSS 120B, Qwen 3.5 (35B total / 3B active, MoE), Ministral 3 14B Reasoning, Phi-4 Reasoning Plus

Tasks:

  • Classification — Categorize customer support inquiries into specific categories (exact match scoring)
  • Code Fix — Identify and fix bugs in short Python functions
  • Route Optimization — Calculate optimal delivery routes with time windows and fuel costs (LLM-as-judge scoring)
  • Sentiment Analysis — Classify product reviews as positive/negative/neutral/mixed
  • Summarization — Extract key points from news articles into summaries (F1 scoring)

Each model-task pair was evaluated at 0, 1, 2, 4, and 8 shots, with 3 trials per configuration and TF-IDF-based dynamic example selection. That’s 60 model-task pairs and over 27,000 individual evaluations.

I’ll describe how to explore the full results later, but here are three patterns that stood out.

Pattern 1: The zero-shot leader can crash to last place

Gemini 3 Flash scored 93% on route optimization at zero-shot — the highest of any model. Then I added examples.

Shots 0 1 2 4 8
Score 93% 93% 43% 53% 30%

At 8-shot, it scored 30%. The model that was the best at zero-shot became the worst with examples. A 63-point drop.

Learning curves for route optimization. Gemini 3 Flash (red) collapses from 93% to 30%, while Gemma 3 27B (green, same model family) stays stable around 90%.

Here’s the twist: Gemma 3 27B — from the same model family — stayed stable around 90% across all shot counts. Same architecture lineage, completely different behavior. This isn’t a property of the Gemini/Gemma family. It’s specific to Gemini 3 Flash on this task.

Pattern 2: Most models benefit from few-shot examples

On classification, every model scored between 0% and 20% at zero-shot. They all looked equally bad. Based on a zero-shot benchmark alone, you’d conclude these models can’t classify customer support tickets.

But with examples, performance improved dramatically across the board. The graph is a bit busy, but you can see the overall upward trend from 0-shot to 8-shot:

Classification learning curves. All models start at 0-20% at zero-shot but diverge dramatically by 8-shot, spreading from 27% to 80%.

At 8-shot:

  • Claude Haiku: 80% (from 20%)
  • Claude Sonnet: 73% (from 20%)
  • GPT-OSS 120B: 73% (from 0%)
  • Gemma 3 27B: 67% (from 0%)
  • GPT-4o-mini: 33% (from 0%)
  • Gemini 2.5 Flash: 27% (from 13%)

Models that scored below 20% at zero-shot improved significantly with examples. Claude Haiku reached 80%, and Claude Sonnet and GPT-OSS 120B also showed strong gains. Gemma 3 27B, which performed well on route optimization in Pattern 1, went from 0% to 67%. On the other hand, models like GPT-4o-mini and Gemini 2.5 Flash barely improved.

If you pick your model from zero-shot benchmarks, you might choose the wrong one.

Pattern 3: Models bad at a task stay bad — even with examples

On summarization, most models improved steadily with more examples. This is the behavior everyone expects from few-shot prompting. The graph is busy again, but the overall upward trend is clearer than with classification:

Summarization learning curves. Most models show steady improvement from 0-shot to 8-shot, with Gemma 3 27B reaching 75%.

Gemma 3 27B — a local model — achieved the highest score at 75%, outperforming all cloud models. Claude Sonnet followed at 73%, then Gemini 3 Flash at 72%. For straightforward tasks, local models can be more than enough.

However, even on this task, Phi-4 Reasoning Plus and Ministral 3 14B scored poorly. Both are reasoning-specialized models, optimized for expanding and elaborating information — not compressing it as summarization requires. This isn’t “collapse” from adding examples; they simply weren’t suited for the task.

Few-shot prompting works well for most models on most tasks, but models that are fundamentally mismatched with a task won’t be saved by more examples.

The 60 model-task combinations fall into three patterns

To summarize the three patterns:

1. Few-shot causes collapse — Like Gemini 3 Flash on route optimization in Pattern 1, adding examples dramatically degrades performance. The most notable cases:

Model Task Behavior Drop
Gemini 3 Flash Route Optimization Gradual decline 93% → 30%
Qwen 3.5 (3B active) Code Fix Gradual decline 56% → 0%
Ministral 3 14B Code Fix Peak regression 44% → 33%

2. Few-shot works as expected — Like summarization for most models, performance improves steadily with more examples.

3. Task-model mismatch — As described in Pattern 3, models like Phi-4 Reasoning Plus and Ministral 3 14B scored low on summarization even at zero-shot. Adding examples didn’t help — this isn’t “collapse” but a fundamental mismatch.

Additionally, four pairs showed temporary dips that recovered. Scores eventually returned, but testing at a single shot count could lead to the wrong conclusion:

Model Task Detail
GPT-5.4-mini Classification 60% at 2-shot → 27% at 4-shot → 60% at 8-shot
GPT-OSS 120B Route Optimization 78% at 0-shot → 58% at 1-shot → 74% at 8-shot
Gemini 2.5 Flash Route Optimization 63% at 2-shot → 52% at 4-shot → 63% at 8-shot
Qwen 3.5 Classification 40% at 2-shot → 20% at 4-shot → 40% at 8-shot

Testing at multiple shot counts helps catch these, though the issue may be less about shot count itself and more about the interaction between the specific examples provided and the model’s state.

Who performed best?

Measuring adaptation efficiency (area under the learning curve across all tasks):

Rank Model Type Avg AUC
1 Claude Haiku 4.5 Cloud 0.815
2 Gemma 3 27B Local 0.814
3 Claude Sonnet 4.6 Cloud 0.802
4 LLaMA 4 Scout Local 0.748
5 GPT-5.4-mini Cloud 0.730

A 27B local model matched Claude Haiku’s adaptation efficiency. LLaMA 4 Scout, with only 17B active parameters (MoE), outperformed GPT-5.4-mini. Results will vary depending on the evaluation method and tasks, but this suggests that with proper few-shot prompting, local models can achieve performance comparable to cloud APIs.

Prior research

Few-shot performance degradation has been reported by several independent studies:

  • Tang et al. (2025) documented “over-prompting” — performance peaks then declines — across GPT-4o, DeepSeek-V3, Gemma-3, LLaMA-3, and Mistral.
  • Lin & Mohaisen (NDSS 2025) found that few-shot examples degraded vulnerability detection: Gemma 7B dropped from 78% to 40%.
  • Chroma Research (2025) showed that simply adding more tokens — even irrelevant ones — degrades performance.
  • Min et al. (2022) found that randomly replacing labels in few-shot examples barely hurts performance — suggesting models aren’t learning from examples the way we assume.

The phenomenon is well-documented. This makes it all the more important to evaluate whether few-shot prompting actually works for your specific use case before deploying to production.

Practical takeaways

  1. Don’t assume more examples = better. It’s worth testing at multiple shot counts. The optimal number varies by model and task.
  2. Don’t pick models from zero-shot benchmarks alone. We found that rankings can change significantly with examples. When referencing benchmarks, check whether they were measured at zero-shot or few-shot — the methodology matters.
  3. Distinguish collapse from task mismatch. If scores drop after adding examples, check the zero-shot baseline. Low from the start suggests a model-task compatibility issue. High at zero-shot but dropping with examples points to a few-shot prompting effect.
  4. Measure, don’t guess. Whether few-shot prompting helps a specific model-task pair can only be determined by actually evaluating it. Tracking the full learning curve ensures you don’t miss non-monotonic patterns.

Reproducing these results

The evaluation was run with AdaptGauge (OSS, MIT license), a tool that tracks learning curves, auto-detects collapse, and classifies degradation patterns.

The full results from this 12-model × 5-task experiment are available as default demo data. After installation, you can immediately explore the patterns and learning curves discussed in this article — no API keys needed.

To evaluate your own tasks and models, AdaptGauge supports cloud APIs as well as local models via any OpenAI-compatible API (LM Studio, Ollama, etc.).

GitHub: github.com/ShuntaroOkuma/adapt-gauge-core

References

Frontend Fundamentals 모의고사 2 후기

간략하게 Lessons Learned만 일단 정리하여 공유합니다.

Lessons Learned

도메인으로 포함되는 로직 감싸기

Q. query 관련 로직을 컴포넌트 내부에 배치할까, 외부에 배치할까?

다음은 예약 현황 페이지에서 내 현황 영역 컴포넌트를 렌더링하는 부분만 짧게 가져온 code snippet이다.

export funciton ReservationStatusPage() {
  const { data: myReservationList = [] } = useMyReservations();

  ...
  <MyReservationSection myReservationList={myReservationList} getRoomName={getRoomName} onCancel={handleCancel} />
}

useMyReservations(query 관련 로직)을 부모에 정의할까, 아니면 컴포넌트 내부에 정의할까 고민을 많이했는데 중요한 고민이 아닌 거 같아 컴포넌트 밖에서 정의했다.

A. 도메인을 이름에 나타냈으면 안에서 도메인 로직을 책임지게 만들자.

MyReservationSection이라는 이름이 붙은 순간 이 컴포넌트는 특정 도메인의 로직을 처리하는 컴포넌트라는 맥락을 가지므로, query data를 굳이 외부에서 줄 필요 없이 내부에서 정의하는 게 추상화 레벨에 맞는 거 같다.

네임스페이스 패턴 과다사용 경계하기

  • 같은 name에 묶여서 내부 구현을 숨겨버리는 효과가 발생한다. 따라서 개발자가 구현이 알고 싶으면 직접 구현을 찾아들어가게 만들텐데, 이럴 필요가 있는지 다시 한번 생각해 볼 필요가 있다.

예)

<TimeSelect>
  <TimeSelect.Title>선택 가능 시간<TimeSelect.Title>
  <TimeSelect.Option>10:00<TimeSelect.Title>
  <TimeSelect.Option>10:30<TimeSelect.Title> 
  <TimeSelect.Option>10:30<TimeSelect.Title> 
</TimeSelect>

문제점:

  • HTML Native element ‘select’의 컨벤션을 따르고 있지 않아 예측하기가 어렵다.
  • TimeSelect namespace에 어떤 컴폰넌트가 있는지 알고 싶다면 AI던 개발자던 결국 소스코드를 탐색해서 들어가야 한다. Title 컴포넌트가 숨겨져 있어서 존재 자체를 알기 어려워 다른 개발자들은 TimeSelect.Title을 사용하지 않고 직접 구현하게 되는 일까지 벌어질 수 있다. 이러면 유지보수하기 더욱 힘들어질 것이다.

여전히 의문인 점

리팩토링 단계 설계하기

  • 재엽님이 코드를 고치신 방식: 인터페이스를 먼저 설계하신 다음에 LLM에게 인터페이스대로 리팩토링해달라고 지시함.
  • 문제점: 프로덕션 코드 같은 경우 그렇게 수정하면 그렇게 변경점이 많아져 리뷰어가 리뷰하기가 힘들 거다. 따라서 레거시 코드의 리팩토링을 단계별로 진행해야 할텐데 어떤 식으로 단계별로 개선할 수 있을까?

P.999 onChange 대신에 onValueChange는 어떠한가?

  • Native HTML의 인터페이스를 그대로 웬만해서 가져오는 게 예측하기 쉽다고 말씀하셨고, 이에는 전반적으로 동의한다.
  • 그런데 onChange 같은 경우에는 event를 인자로 전달해주는 함수라는 느낌이 든다. 따라서 value를 전달하는 함수라는 것을 명확히 해주기 위해 onValueChange라는 이름으로 핸들러 인터페이스를 구성하는 것은 어떤가?
  • 레퍼런스: Radix-Primitive의 `onValueChange’ 함수 인터페이스(https://www.radix-ui.com/primitives/docs/components/tabs)

Screenshots Behind Login Shouldn’t Require a DevOps Engineer

A technical writer on our team needed screenshots of the admin dashboard. The dashboard is behind SSO login (Okta).

She asked me to help. I wrote a Playwright script with the login flow. It broke after the next Okta update. I fixed it. Then IT enabled MFA. Script broke again. I added TOTP handling. Then they rotated the client secret.

Three weeks of back-and-forth for 6 screenshots.

The problem

Most screenshot automation tools assume you can script the login. But modern auth is designed to resist automation:

  • OAuth redirects across domains
  • CAPTCHA challenges
  • MFA (TOTP, push notifications, hardware keys)
  • SSO providers that change their UI regularly
  • Session cookies with short TTLs

You end up maintaining auth code that’s more complex than the actual screenshot capture.

Just log in yourself

Heroshot opens a real browser:

npx heroshot config

The technical writer logs in herself. Through Okta, with MFA, the whole thing. She does this every day anyway. Takes 15 seconds.

Then she clicks the elements she wants to screenshot. Heroshot saves:

  1. The screenshot config (which pages, which elements)
  2. The browser session, encrypted

Next time anyone runs npx heroshot, it restores the session. No login flow. If the session expires, she runs npx heroshot config --reset and logs in again.

For the CI pipeline

The session is encrypted with a generated key stored on your machine. To use it in CI:

# On your laptop
npx heroshot session-key
# Copy the key
# In GitHub Actions
env:
  HEROSHOT_SESSION_KEY: ${{ secrets.HEROSHOT_SESSION_KEY }}

steps:
  - run: npx heroshot

That’s it. CI decrypts the session and captures authenticated screenshots. No Okta credentials in CI. No login scripts. No DevOps engineer required.

Multiple accounts

Need screenshots from different user roles? Admin view, regular user view, read-only view?

Use separate config files:

# Log in as admin
npx heroshot config -c .heroshot/admin.json

# Log in as regular user
npx heroshot config -c .heroshot/user.json

Each config has its own session. Capture both:

npx heroshot -c .heroshot/admin.json
npx heroshot -c .heroshot/user.json

Who should take the screenshots?

The person who knows the product. That’s usually not the DevOps engineer writing Playwright scripts. It’s the technical writer, the product manager, or the designer.

With a visual picker, they don’t need to know CSS selectors, Playwright APIs, or how OAuth works. They log in and click.

Orchestrating AI Agents to Build a Multi-Lingual Video Dubbing Workspace

I built Vonnect AI, an AI Dubbing Workspace that generates multi-lingual dubs while cloning the original speaker’s voice. While the AI output is satisfying, the real story is the build process: a Multi-Agent AI workflow orchestrated through Google Antigravity.

🛠 The AI Stack

Voice Cloning: Using ElevenLabs, the app identifies multiple speakers and clones each voice to maintain authenticity across different languages.
Smart Re-dub: Users can edit translations and re-synthesize specific segments instantly, powered by a combination of Next.js and Drizzle ORM.

🤖 Multi-Model Orchestration

Instead of sticking to one AI, I strategically distributed tasks among different SOTA models:

Claude 4.6 Sonnet: Handled the complex backend and API orchestration.
Gemini 3.1 Pro: Acted as a high-level troubleshooter, analyzing deep logic when thing broke.
Gemini 3 Flash: Rapidly iterated on UI and documentation.

💡 The Selective Approval Pattern

The power of my workflow came from the Selective Approval mechanism in Google Antigravity. I never accepted code changes blindly. Each proposal was reviewed, ensuring that as a human developer, I remained the source of truth for the codebase. This “Human-on-the-loop” strategy allowed me to ship a feature-rich product at an incredible pace without sacrificing code quality.

GitHub Repo: https://github.com/Jin1370/vonnect_ai ⭐

Enterprise Blockchain Patterns in TypeScript: Real Case Studies, Protocol Adapters & Post-Quantum Security

From theory to production-ready patterns — traceability, selective disclosure, credentials, and reconciliation with actual runnable examples.

Most blockchain content for enterprises stays at the “hello world” or high-level architecture stage. Developers and architects need concrete patterns they can adapt to real regulated environments, consortiums, and future-proof security requirements.

That’s why I created enterprise-blockchain — a TypeScript repository packed with operational case studies, protocol-agnostic modules, and advanced crypto integrations.

It’s designed for developers who want to move beyond toy examples and start building production-grade enterprise solutions.

What This Repo Actually Gives You

  • Four real business case studies with runnable examples
  • Protocol adapters for Hyperledger Fabric, Besu (EVM), and Corda
  • Security modules: Multi-Party Computation (MPC), Hardware Security Module (HSM) patterns, and Post-Quantum cryptography (ML-KEM / Kyber, ML-DSA / Dilithium, hybrid schemes)
  • Fully typed, tested, and easy to explore

The focus is operational: how blockchain actually changes system behavior around auditability, provenance, privacy boundaries, and cross-organization coordination.

The Four Runnable Case Studies

  1. Food Recall Response

    Simulate a contaminated batch recall across producers, distributors, and retailers. See how traceability can reduce response time dramatically.

  2. Consortium Order Sharing

    Selective disclosure of purchase orders using privacy-friendly patterns (inspired by Besu privacy groups). Only the right parties see the details — others get verifiable proofs.

  3. Hospital Staffing Clearance

    Credential verification and sanction-list checks. Critical for regulated industries like healthcare.

  4. Aid Voucher Reconciliation

    Humanitarian aid settlement with automated exception reporting and strong audit trails.

Each scenario lives in its own examples/ folder and can be run with a single command.

Advanced Security That Goes Beyond Basic Signing

Security in enterprise blockchain isn’t just “use a wallet.” This repo includes practical implementations:

  • MPC (Multi-Party Computation): Additive secret sharing, sealed-bid auctions, joint risk calculations, and quantum-resistant key sharing.
  • HSM Patterns: PKCS#11-style key management, ECDSA transaction signing, 3-of-5 threshold root key ceremonies, and DEK/KEK envelope encryption.
  • Post-Quantum Primitives: ML-KEM (Kyber), ML-DSA (Dilithium), and hybrid KEMs — because quantum threats are coming faster than many expect.

You can try them directly:

npm run example:mpc-auction
npm run example:hsm-tx-signing
npm run example:hsm-key-ceremony

Protocol Adapters — Write Once, Target Multiple Platforms

The core domain logic stays platform-agnostic, while clean adapters handle the differences:

  • Hyperledger Fabric (using @hyperledger/fabric-gateway)
  • Besu / Ethereum Enterprise (using ethers)
  • Corda (REST gateway style)

There’s even a ready-to-use Solidity contract (ConsortiumOrderRegistry.sol) for quick EVM testing.

This approach lets you model business rules once and project them to different ledgers without heavy refactoring.

Quick Start (Literally 2 Minutes)

git clone https://github.com/psavelis/enterprise-blockchain.git
cd enterprise-blockchain
npm install

npm run typecheck
npm run examples

Then explore individual demos:

  • npm run example:food-recall
  • npm run example:order-sharing
  • npm run demo:adapters
  • npm run verify (runs lint + tests + formatting)

Everything works offline and includes quality gates via GitHub Actions.

Who Is This For?

  • Enterprise architects and developers evaluating Fabric, Besu, or Corda
  • Teams building consortium solutions with privacy and compliance needs
  • Security engineers interested in MPC + HSM + post-quantum in TypeScript
  • Anyone tired of blockchain tutorials that never reach real operational patterns

If you’re working on (or planning) enterprise blockchain projects, this repo can save you weeks of research and experimentation.

⭐ If you find this useful, please star the repository — it helps more developers discover practical enterprise patterns instead of just hype.

👉 https://github.com/psavelis/enterprise-blockchain

Contributions are welcome! New case studies, additional protocol adapters, improved docs, or security examples are especially appreciated. Just run npm run verify before opening a PR.

What’s Next?

I’d love to expand this with more real-world scenarios. What enterprise use case would you like to see implemented next?

Drop a comment below:

  • Your biggest pain point when working with enterprise blockchain
  • Which platform (Fabric, Besu, Corda, or others) you work with most
  • Whether you’d like a deep-dive on MPC or post-quantum integration

Let’s make enterprise blockchain more practical and production-ready together.

showdev #blockchain #typescript #hyperledger #enterprise #opensource #cryptography