Blog

Claude Code, Go and a system with no manual

6 min read

How I use Claude Code to write small, single-purpose Go tools, one question at a time, to work out how an undocumented system behaves, and how those probes grow into a real service.

Sooner or later every developer meets a system with no manual: a web application people use every day, with no API meant for what you need and no documentation for the parts that matter. Someone on the team does the same clicks every morning to get data out or put data in, and you’ve been asked to make that stop.

The usual approach is days with the browser’s developer tools open, then one big client that half works. What works better for me is a pile of small, throwaway tools, each answering one question, each written by Claude Code in Go in a few minutes. The useful ones grow up into the real thing; the rest get deleted.

Why Go for throwaway tools

  • One file, one executable. go build produces a single binary I can copy onto a locked-down Windows machine with nothing to install.
  • The standard library covers nearly everything. net/http with cookie jars, crypto/tls, encoding/xml and encoding/json, mime/multipart. Add golang.org/x/net/html for parsing forms and that’s the whole toolkit.
  • It compiles in a second or two, so the loop stays tight.
  • The compiler catches a lot of what generated code gets wrong before it ever touches the server. Generated Go tends to be plain and predictable, which is exactly what you want from a tool you’ll read once and delete.

The loop

  1. Capture what the browser does. Save a recording (a HAR file) of doing the task by hand, so there’s real traffic to work from instead of guesses.
  2. Ask one question. “Can I sign in without a browser?” “What comes back while a long job is still running?” One tool per question.
  3. Have Claude Code write the tool. Give it the relevant requests and the question, and get a single-file Go program back.
  4. Save everything. Every response goes to disk as a numbered file, so nothing depends on terminal scrollback and runs can be compared.
  5. Feed the results back. The saved responses become the starting point for the next question.

One warning about step 1: HAR files are full of session cookies, tokens and sometimes passwords, so strip those out before the file goes anywhere, including into a prompt. I built a HAR sanitizer for exactly that. It swaps every secret for a placeholder, and it can turn the captured requests into a Go, PHP or curl script that replays them, which is a head start on step 3.

Keep a running table of every error you hit and what fixed it, too. By the end it’s usually the most useful document in the folder.

Most probes look something like this: fetch, save, print one line per request.

// probe: fetch each URL with one session and save what comes back
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/http/cookiejar"
	"os"
)

func main() {
	jar, _ := cookiejar.New(nil)
	client := &http.Client{Jar: jar}

	for i, url := range os.Args[1:] {
		resp, err := client.Get(url)
		if err != nil {
			fmt.Println(url, err)
			continue
		}
		body, _ := io.ReadAll(resp.Body)
		resp.Body.Close()
		name := fmt.Sprintf("probe_%02d.html", i+1)
		os.WriteFile(name, body, 0o644)
		fmt.Printf("%s  %d  %d bytes  -> %s\n", url, resp.StatusCode, len(body), name)
	}
}

The kinds of tools that keep coming up

  • A sign-in tester. Walks through the login step by step and reports exactly where it stops working. Sign-in is nearly always the first wall.
  • An explorer. Follows redirects, saves every page along the way, then crawls what it can reach to build a site map.
  • A request replayer. Takes one captured request, replays it with changes, and saves each response, so you can see which parts actually matter.
  • A failure diagnoser. When the biggest jobs fail intermittently, a tool with flags for retry delays, timeouts and how often to sign in again, plus a full log of the HTTP traffic, turns “it fails sometimes” into a pattern you can design for.
  • A counting probe. The most underrated of the lot. More on it below.

Count before you optimize

When something is slow, it’s tempting to start tuning: more workers, longer timeouts, smarter retries. Before any of that, have Claude Code write a probe that just counts: how many rows, grouped by what, filtered how. It takes minutes, and it tells you what the system is really doing instead of what you assume it’s doing.

A counting probe once showed me that a slow job was slow because of how it asked for the data, not because of how much data there was. Changing the question fixed it. Retries and bigger timeouts would only have hidden it.

If the slow part is a MySQL query, EXPLAIN is the database’s own counting probe. My EXPLAIN visualizer turns its output into a readable plan and plain-English problems.

Fixes like that often come with a trade-off, such as a slightly different set of results. The probe can show you the trade-off. Deciding whether it’s acceptable is a judgment call about the data, and that’s a decision I don’t hand to an AI.

From probes to product

The probe that answers the core question (“can I get this done without a browser?”) usually becomes a command-line tool, with its debug commands kept alongside the real ones. If it needs to run unattended, it becomes a service:

  • a single executable with SQLite for run history, so there’s no database server to look after
  • a schedule, a pool of workers, and retries with backoff
  • a re-login that pauses every worker when a session expires, instead of letting them all fail at once
  • a small web dashboard with a live log, so the people who used to do the job by hand can see it being done

You can poke at a simulation of that kind of runner in Labs: turn the failure rate up and watch the retries and re-logins pile in. And once you’re scheduling several of these, the cron timeline shows when they’ll collide, including the night the clocks change.

What Claude Code is good at here, and what it isn’t

It’s very good at:

  • Tedious code that’s easy to get subtly wrong: TLS setup, cookie jars, XML and JSON payloads, multipart uploads, parsing HTML forms.
  • Turning captured traffic into a working client, quickly.
  • Keeping notes. The error table and a write-up of findings can be drafted as you go, while the details are fresh.

Where you still have to lead:

  • It can’t see the system. Every theory is a guess until a probe proves it, so the loop has to run against real responses.
  • Ask what would prove a theory, not just for a fix. A longer timeout or another retry can hide a problem instead of explaining it.
  • Judgment stays with you: what you’re permitted to automate, what data is safe to touch, and which trade-offs the organization will accept.

What I’d tell anyone trying this

  • One question per tool. Small tools are cheap to write and cheap to delete.
  • Save every response to disk from day one.
  • Start the error table in the first hour.
  • Make sure you’re allowed to. Automating a system you don’t own needs the owner’s blessing and should stay within its terms of use.
  • Clean up as you go. Probe output, saved pages and credentials pile up fast. Once the investigation is over, delete what you don’t need.

The tools mentioned here are free in Labs, and like everything there, they run entirely in your browser.

Have a system your team copies data out of by hand? That’s the kind of thing I build.