Ferrum_Flux_Fenice
Enterprise Innovation DeveloperFerrum_Flux_Fenice

FerrumFluxFenice

Erin Dalton · Florida

Original orange Ferrum Flux Fenice phoenix crestFerrum_Flux_Fenice
Ferrum Flux Fenice Pilgrim phoenix crestferrumclaudepilgrim
Diagnose

What went wrong?
How do I fix it?

Prevent

What could go wrong?
How do we prevent it?

Created & maintained

claude-code-
android

Your phone.
A working development environment.

Not affiliated with or endorsed by Anthropic.

I was stuck. I wanted to run Claude Code on my Android phone and the official routes weren’t cutting it. This is the product of that. Over several very long days, I worked through it with ADB (Android’s debugging tool), Claude Code on my desktop and a lot of reading through the Anthropic and Termux docs. That became the original install path. It has changed quite a bit since then.

Today’s repo has a much more advanced and stable install script, a clearer install and troubleshooting package, and what I am most grateful for: community support.

Whether it’s native Termux, Ubuntu via proot, or Android’s Linux VM (Android Virtualization Framework) there’s probably a path for your Android phone.

To get rocking and rollin you are going to need a compatible ARM64 (64-bit ARM) Android phone (Android 8 minimum, with extra caveats on older devices), Termux for the native or Ubuntu setup, and a Claude subscription that includes Claude Code or supported API access. Older phones may need the pinned install. Android’s Linux VM path has its own hardware requirements and doesn’t need Termux.

Explore the project

Public work

The work.
In the open.

Upstream fixes. Client delivery.
From the first failure to the shipped change.

01 / Tailscale / CrostiniMerged

Don’t create the interface.

A 2-year-old thread and a Chromebook whose Linux Terminal would not open. I ran across it while chasing the same trouble on my Chromebook, frost-biddle. I wanted to find out which part of the suggested workarounds actually mattered.

The problem, the work, the result
The problem
On my Chromebook, a cold boot with Tailscale installed could leave the Linux Terminal unable to open. Garcon, which connects Linux apps to ChromeOS, was crashing. The issue thread had been open since May 2024, with workarounds that helped some people and not others.
The work
I compared 4 cold-boot configurations. Both tests with tailscale0 present crashed; both without it did not. But avoiding the crash was not enough: one configuration left Tailscale nonfunctional. Userspace networking let both the Terminal and Tailscale work without creating the interface. That gave me a useful default to propose.
The result
Tailscale detects Crostini before Debian and defaults to userspace networking when that mode is available, avoiding creation of tailscale0. Anyone who wants the interface back can still pass --tun=tailscale0.
Diff excerpt / cmd/tailscaled/tailscaled.go
if buildfeatures.HasNetstack &&
   distro.Get() == distro.Crostini {
    return "userspace-networking"
}

This changes Tailscale’s default, not garcon’s code. My comparison covered one Chromebook running Debian 12 on aarch64, with one cold boot per configuration. The same investigation led to the ChromiumOS change in the next case.

PR #19628 ↗
02 / Google ChromiumOS / GarconMerged

All that trouble. One missing check.

My Chromebook, frost-biddle, was having a bad time. Following the Tailscale trouble led me into garcon, the part connecting Linux apps to ChromeOS. Several resets of Claude’s 5-hour usage limit later, I was looking at one missing check.

The problem, the work, the result
The problem
Garcon helps connect Linux apps to ChromeOS. While setting up Android app sideloading, it looked through the network interfaces for an IPv4 address. It tried to read an address even when an entry didn’t have one, which could crash garcon.
The work
At this point I didn’t even know what a CL (changelist) was. I jumped into the docs, started setting up Ubuntu for the build and got to work. I added a check to skip entries without an address, then took the change through ChromiumOS review and the commit queue.
The result
One file, one check. ChromiumOS CL 7881724 guards the null address in arc_sideload.cc. A Chromebook receives the fix when Google ships a ChromeOS build containing it.
Diff excerpt / arc_sideload.cc
if (current->ifa_addr == nullptr) {
  continue;
}

This guard covers the Android app sideloading path. Its merge does not establish that every cold-boot or GUI failure reported in the Tailscale thread was fixed.

03 / Bubba’s LandsClient work

“I want a website.”

A small, locally owned property services business wanted to expand its online presence. We started with the site. From those 4 words to the work we’re doing now, I’ve helped the business grow while developing my own skills along the way.

The problem, the work, the result
The problem
Find out what the business actually needed from the site and how it fit the work already happening. Services, quote requests, returning customers. A website was the first ask, but the conversation kept going.
The work
From discovery, design and critique through deployment, I worked with the owner to build the site the business needed, paying attention to load times and how business and customer data were handled. Once the site was up, we added a Housecall Pro lead form and customer portal. I continue to update and maintain the site. The business owns the code and can move it elsewhere.
The result
9+ months in as of September 2026 and we’re still moving along. A few tweaks to the site but mostly behind the scenes: a pricebook integrated into the CRM to help make estimates more efficient and accurate, process improvement, and tech fluency.
Delivery scope
Website / CI/CD / maintenance
Housecall Pro form / customer portal
Pricebook / process improvement
Ongoing maintenanceVisit the website ↗
04 / Google ChromiumOS / App launchMerged

An empty argument. Still an argument.

Linux apps can receive an empty argument on purpose. Garcon, which connects those apps to ChromeOS, was dropping it. Everything after it moved up a position, changing the command the app received.

The problem, the work, the result
The problem
I was just reading and scrolling Google Issue Tracker and ran across an issue I thought I could at a minimum reproduce. I couldn’t, but it led me to this area of the codebase and that is how this CL came to be. Linux desktop entries describe how to launch an app. Garcon was parsing their Exec commands, but discarding explicitly empty quoted arguments. Empty and missing mean different things when an app expects its inputs in a particular order.
The work
I changed the parser to keep a quoted argument when its closing quote is reached, even if it’s empty. Then I added regression tests for empty arguments at different positions, quoting, escaping and file expansion.
The result
The 27-test DesktopFileTest suite and 3 related test binaries passed in the ChromiumOS SDK. Explicitly empty arguments now keep their place in the generated command.
Diff excerpt / desktop_file.cc
- if (in_quotes && !curr_arg.empty()) {
+ if (in_quotes) {

This fixes desktop-entry argument parsing in garcon. It is a different garcon path from the Crostini crash.

05 / OpenAL SoftMerged

Back at OpenAL. This time with a lab.

I had come across OpenAL Soft once. Read the issue, pocketed it, kept going. Months later, a ping to test an audio fix in Termux brought me back to Oboe, an Android audio library. Then OpenAL Soft came up again. By now I had the 4 lab phones as well as ferro-nerro, my daily driver.

The problem, the work, the result
The problem
This started with trying to get voice input working in Claude Code on my phone. I opened a Termux PR and was still learning how to contribute. Even squashing commits gave me trouble. In July, I got pinged to retest. The original input problem no longer reproduced, but getting back into the audio work led me to a different failure in OpenAL Soft. With its Oboe audio backend enabled, repeatedly creating audio devices and resetting playback left streams open until there weren’t enough left. Now I needed to find out whether my Termux changes had caused the problem or exposed something upstream.
The work
Having the lab phones meant I could leave a device running a repeated test without tying up the phone I use all day. I reproduced the failure with stock NDK r29 and unpatched Oboe 1.10.0, outside the Termux packaging. A move to shared pointers had removed the cleanup that closed each stream. Testing the original code against the fix showed why releasing ownership was no longer enough. The stream needed an explicit close.
The result
The fix closes streams during playback probing, reset and backend destruction. The original build reproduced the device-creation and playback-reset failures; the fixed build passed those comparisons. Android 32-bit and 64-bit builds passed too. OpenAL Soft PR #1322 was reviewed and merged. The larger Termux audio work is still separate.
Diff excerpt / alc/backends/oboe.cpp
if(mStream)
{
    mStream->close();
    mStream.reset();
}

I also checked audio capture. Those tests passed with both the original code and the fix. The change keeps Oboe’s shared-pointer API.

PR #1322 ↗
06 / Termux CUPSMerged

My first upstream merge.

I already had Termux. I was already changing things for my own use. Contributing to somebody else’s repo was new territory. The CUPS printing package gave me a place to start.

The problem, the work, the result
The problem
I wanted to learn how to contribute properly. Read CONTRIBUTING.md, find a scoped issue, pick something I could test on my own phone. CUPS had an issue with useful diagnostic work already behind it: broken web UI permissions, missing runtime directories and a configuration problem that blocked administration.
The work
Almost the entire PR happened in Claude Code through Termux on my S26 Ultra, using claude-code-android. The Docker builds went to my PC, ole Frostbyte-Ferrum. I worked from the earlier issue findings, fixed the package, tested it on the phone and learned from the review. Even the chmod needed to happen at the right build step or it wouldn’t survive into the package.
The result
The web interface loaded again, the runtime directories were created and the administration configuration was restored.
Package fix excerpts / paths shortened
mkdir -p …/var/spool/cups/tmp
mkdir -p …/var/cache/cups
chmod -R o+rX …/share/doc/cups

Earlier issue contributors identified the permissions cause and the missing runtime-directory problem. Their diagnostic work is credited in the linked PR.

PR #29123 ↗

The Lab²

Real devices.
Repeatable work.

The same change can behave
differently on another phone.

4 phones.
Android 8 to 17.

The original Lab is my 4-phone Android bench. Agents and I use ADB through my PC, Frostbyte-Ferrum, to reproduce bugs, develop new software, test PRs and just do fun stuff. My daily driver ferro-nerro (Samsung S26 Ultra) no longer participates in most tests but still runs claude-code-android to this day.

The phones teach me as much as they help me. I love when I get pinged for a GitHub notification about an issue I can probably repro.

Inside The Lab²

Frostbyte-Ferrum

Ryzen 9 · 64GB DDR5 · 12GB VRAM

USB / ADB · 4 physical devices

  • Pixel 10 ProAndroid 17
  • Pixel 6Android 17
  • Moto G7 PowerAndroid 10
  • Galaxy S7Android 8

How I work

Fixer. Navigator.
Builder.

If it isn’t clear by now, I’m not going to hand-write a 1000-line diff for a repo. What I can do is find solutions. I love chasing bugs, reproducing them and testing fixes on real equipment. I use agents from different model providers to compare approaches and question the answers I get.

By day, I’m an Enterprise Innovation Developer working in the Microsoft stack: process improvement, automation, Power Automate, and Copilot Studio. Governance, RPA, Azure, and the multi-user side of AI are what keep me curious.

The first time I opened a production workflow in Power Automate to really work inside it, I was sitting in my new (but not first) cubicle. Backpack to my left, fidget cube in my hand, and there it was: this gorgeous flow that immediately made me think, Microsoft Learn isn’t going to save me now. It’s been more than a few moons since that fateful day. That flow isn’t as scary anymore. I do still respect it though.

After hours it gets a little more eclectic but on the same path: local models, automation for my family, continued improvement on web development, lots of A/B testing on the lab and reading of repos and developer docs.

I work by learning and learn by doing.

FixerFind the root cause, be curious. Ask questions to understand, not to just complete.

NavigatorWhat could go wrong? Where do the weak points sit? How can we strengthen this?

BuilderTry it. Test it. Break it. Fix it back (hopefully). Compare results to your previous failures, other successes. Build again.

Open a channel

Something worth figuring out?

Need a website, help with a workflow, or Android testing? Working on something and want another set of eyes on it? Tell me what you have in mind.

ferrumclaudepilgrim@gmail.com ↗

Connect with me on LinkedIn to collaborate or talk through an idea.