At the TinyGo hack session in Seattle I flew a Parrot minidrone through a stunt routine from a Go program on my laptop, on a library written by one of TinyGo's maintainers, who was in the room. What the code does, what broke, and what the rest of the conference taught me about where Go is going.
By Patrick Donahue.
GopherCon 2026 was in Seattle in early August, close enough to home that I could go for the week. Most of my career has been in other languages, and I went to get a feel for the Go community from the inside rather than from blog posts. The thing I did not expect to be the highlight was a table of small drones.
The TinyGo session was run by Ron Evans, known on GitHub as deadprogram, one of TinyGo’s maintainers
and the creator of Gobot. TinyGo is a Go compiler for small places: microcontrollers, WebAssembly,
devices with kilobytes of memory. Ron’s team had a set of Parrot minidrones, palm-sized quadcopters
controlled over Bluetooth Low Energy, and a tutorial that takes you from “scan for the drone” to
“fly it from the keyboard” in six steps, using his tinygo-minidrone package.
I worked through the tutorial with an AI coding agent alongside me, which is how I write most code now: I read the package, the agent drafts, I decide what runs. The first program was a test flight: find the drone, connect, take off, climb at full throttle for a second, hover, land. The second was a routine. Climb to a safe height, then a front flip, a back flip, a right flip and a left flip, a fast spin, and a clean landing, all started with one keystroke.
It worked. Ron posted a clip of it, the conference photographer took a run of pictures, and one of the organisers came over to say it was the best thing he had seen all day, mostly because I was standing still with my hands off the keyboard while a drone did somersaults in front of me. The code is short enough to read in a couple of minutes, and it is in a gist exactly as I ran it.
There are three layers. At the bottom, tinygo.org/x/bluetooth is a cross-platform BLE package: on
my Mac it talks to CoreBluetooth, on Linux to BlueZ, and on a microcontroller with a radio it talks to
the hardware directly. That is the trick that makes the whole thing interesting. The same Go code
that flew the drone from my laptop can be compiled with TinyGo and flashed onto a conference badge.
In the middle, tinygo-minidrone speaks Parrot’s protocol. A minidrone exposes two GATT services, one
for commands and one for notifications, and you fly it by writing small byte packets to a
characteristic. Steering is not a one-shot command. The package starts a goroutine that sends the
current piloting state (roll, pitch, yaw, throttle) every 50 milliseconds, and calls such as Up(70)
or Clockwise(100) change the values that loop sends. Discrete manoeuvres like TakeOff() and
FrontFlip() are single packets. It is a tidy example of the Go idiom of a long-lived goroutine
owning a piece of state while the rest of the program talks to it through method calls.
At the top is my program, which is deliberately boring. It enables the adapter, scans until it sees a device whose advertised name matches the drone, connects, starts the package, and then runs a straight line of commands with sleeps between them. It also subscribes to the drone’s flying-state notifications and prints them, so the log shows “taking off”, “hovering”, “flying”, “landing” as they actually happen rather than as the sleeps assume they happen.
The first attempt scanned forever and found nothing, with no error. The cause was physical: these drones go to sleep after a few idle minutes and stop advertising, and a BLE scan for a device that is not advertising simply never returns. Pulling the battery and putting it back fixed it. The lesson I took into the stunt script was to make the scan handler print every named device it sees, so a silent hang becomes a visible list that does not contain the drone.
The second surprise was addressing. On macOS, CoreBluetooth never gives you a device’s MAC address. It gives you a UUID that is stable for that host only, so a program that hard-codes an address from one machine will not find the drone from another. The script matches on the advertised name as well as the UUID for that reason.
The third was choreography. A flip takes a moment to complete and the drone needs a moment to settle afterwards, so the timing between commands is the routine. I gave every manoeuvre four seconds, which is conservative and looks deliberate on video. It also matters that the drone accepts one BLE connection at a time, so the official phone app has to be closed or the program cannot connect at all.
The drone was the fun part, but the talks and the hallway were the useful part, and I left with more notes than I expected.
The conference had quietly become a conference about building with AI agents in Go. The workshop
I was told not to miss, “Agents the Hard Way”, builds an agent from the ground up rather than starting
from a framework, which is a very Go-shaped way to approach it. Lightning talks covered making tool calls durable so
an agent can resume after a crash, and encoding a team’s conventions as linters so that neither people
nor models re-argue them in review. The Go team’s closing panel struck the same note. The approach the
community seems to be settling on is to use AI inside the guard rails that Go already has (the type
system, go vet, gofmt, table tests) rather than around them. I find that persuasive, and it matches
how I already work.
Ron’s package fits that pattern neatly. Besides the tutorial, tinygo-minidrone ships an MCP server,
which lets an AI agent fly the drone through a small set of typed tools. The interesting design choice
is how little it exposes: take off, land, move, flip. The safety of the whole system comes from the
narrowness of that interface, which is a lesson that generalises well beyond drones.
The best hallway argument of the week was about time. A group of us started with “store everything in UTC and let the client localise it”, which is what I have done in every system I have run, and it lasted about a minute against scheduled jobs. What happens to a job scheduled in local time on the day a time zone changes? On a day with a leap second? In a place like northern Arizona, where the Navajo Nation observes daylight saving time, the state does not, and the Hopi reservation, which sits inside the Navajo Nation, does not either? We did not reach a neat answer. The practical one was to stop pretending a timestamp is enough and keep the metadata with the job: the zone it was scheduled in, the rule that was in force, and what “run once” means for that job.
I also had a long dinner-table conversation over pizza with an engineer who builds terminal tools in Go for every datastore he uses, and who pointed me at the agents workshop in the first place. Most of what I learned about how working Go developers actually spend their days came from conversations like that one.
I write Go because it rewards the things I care about in production code: explicit control flow, small interfaces, a standard library that covers the sensitive parts, and binaries that run anywhere without ceremony. Flying a drone from the same language that runs my childcare compliance backend is a small demonstration of the reach that buys. The code that steers four rotors over Bluetooth and the code that hashes a signed PDF read the same way, and that consistency is most of the reason the language is worth learning well.
The drone routine took an afternoon. Meeting the people who build the tools, and hearing where they think the language is going, was worth the whole week.
Support automation, AI phone agents, n8n back-office work, and the engineering loop itself — always behind a gate you control.