In short:

  • For five months, I built a tool that visualizes JavaScript execution using only instructions to Claude Code. I did not write a single line of code.
  • The basic pattern: delegate the broad strokes of a new feature, then give detailed instructions when something feels wrong in use. You can reject an approach as early as the plan stage.
  • You don't need to know the name of a technique to give detailed instructions. Describe the behavior in your own words, and the AI can tell you what the technique is called.

Introduction

I'm building JSVisualizer, a web app that runs a JavaScript program one step at a time and shows what happens through 12 different views. You can watch variables change, see the tree of function calls, inspect arrays, and step forward and backward. A separate series introduces the tool itself. This one is about how it was made.

Here is the scale of the work as of November 2, 2026:

  • JSVisualizer: 147 commits and 48 ADRs, started May 25, 2026
  • JSInterpreter, the JavaScript interpreter it depends on: 52 commits, started May 23
  • In use in a first-year university class since September 30, 2026

I did not write a single line of code in these projects. Everything was done through natural-language instructions to Claude Code and documentation in CLAUDE.md and ADRs (Architecture Decision Records).

Terms used in this post

  • Agentic coding: a way of developing where an AI agent reads and writes files and runs commands itself, while a human gives instructions in natural language and checks the results
  • Claude Code: Anthropic's coding agent, used from a terminal or an editor
  • CLAUDE.md: a project guide that Claude Code reads at the start of a session
  • ADR: a short document recording one design decision and the reasons behind it
  • Plan mode: a Claude Code mode that has Claude present a plan before implementing anything

Before going further, here is my background and how I checked the work.

I spent more than 20 years in software research and development in industry, and I have now been teaching software at a university for more than 16 years. Later in this post, I'll describe where that experience helped and where I relied on asking Claude.

I have read almost none of the code Claude wrote. I skimmed it at first out of curiosity, then stopped reading it entirely. When I had a question about how something was built, I asked Claude in natural language and gave instructions the same way. I checked behavior by using the software myself, and I also asked for tests. However, I left the test cases to Claude and have not verified their coverage.

In this series, I look back on that way of working and try to put it into words. My materials are the git history, the ADRs, the history of CLAUDE.md, and the Claude Code session logs. I reread them together with Claude and checked them against my memory. Several times, that rereading overturned what I thought I knew. Those moments are part of the story too.

The first half of the series will cover:

  1. The basic loop of agentic coding (this post)
  2. The first step was CLAUDE.md: how to start a project
  3. I let the AI decide whether to write an ADR
  4. The AI reads old documents and writes new mistakes
  5. Reviewing AI-assisted development with AI: the limits of logs, memory, and git

The quotes from my sessions below are translated from Japanese.

The basic loop

Over those five months, I repeated this loop for each feature:

The basic loop: give the broad strokes, Claude implements at its discretion, then use it. If something feels off, give detailed instructions, Claude fixes it, and you use it again. Repeat as needed. At a stopping point, say "Document this and commit." Claude documents and commits the work, and you move on to the next feature.

In August, when Claude interviewed me to help put this approach into words, I said:

For a feature being implemented for the first time, I gave only the broad strokes. For changes to existing features, I was specific.

The principle was the same whether the decision was about an algorithm, the look of the UI, or what to document. I didn't change how much I delegated based on the kind of decision. I applied the same rule everywhere: delegate first, then give detailed instructions if something feels wrong in use.

Let's go through each stage of the loop with real examples.

Delegating the broad strokes

On the day I started JSInterpreter, this was my entire first instruction about step execution:

It shall provide an API for step execution (step in, step out, step over, step back).

It says nothing about how to implement it. When I'm exploring, I find it faster to see a proposal first and then decide than to write a complete specification up front. (I have also started a project by pinning down the requirements first. I'll cover that in the next post.) I left much of the algorithm selection and UI layout to Claude as well.

As a result, to be honest, I don't know everything that's in the tool I built. On June 14, I asked this:

I don't see how useful the information in the Timeline and Bar Chart tabs is. When would you use them?

I quickly corrected myself: "I meant Lifetime, not Timeline." I had confused the names of tabs in my own tool. At the time, Lifetime was a chart of horizontal bars showing how long each variable existed. Claude reread the source, explained how to use it, and even added a table comparing it with other views, but I still didn't find it useful because its role overlapped with theirs.

Two days later, Lifetime was rebuilt as a stack of horizontal bars showing when each function call started and ended, what's usually called a flame chart. As I remember it, my instruction was along the lines of "If you put the call stack on a timeline, you get this, right?" That is the version in the tool today, and I use it in class.

What I learned is that asking the AI "What is this feature for?" can itself reveal that something is wrong. If the explanation doesn't convince you, that's a signal worth acting on.

You can reject a plan before any code exists

Back to the step execution API. Claude asked one question about the intended use and then presented its first plan. The interpreter would be built with generators and pause at each statement boundary. To step back, it would rerun the program from the start and stop one step earlier.

I rejected the plan. Not one line of code had been written yet. In Claude Code's plan mode, you're asked whether to proceed with the plan, and I simply said no.

Then I wrote out the approach I had in mind:

Here is how I'm thinking about step execution. First, step through the program. Store the state at every step. For step execution, retrieve the appropriate state according to the type of step: step in, step over, step out, or step back. Is this implementation reasonable?

Claude withdrew its plan and adopted mine:

Compared with my original proposal (generators plus replay), the implementation is more intuitive and simpler. In particular, making stepBack O(1) is a major advantage.

My point is that the "use it" in "use it and notice something off" doesn't only happen after you've touched working software. If you read a plan and think "this isn't right," you can stop there and offer your own idea. That is far cheaper than fixing things after the code is written.

You don't need to know the name of the technique

My proposal above doesn't name a technique. Claude's reply began like this:

This is a very good design. This approach corresponds to a technique called omniscient debugging.

My reaction at the time was "What's omniscient debugging?" But I didn't ask. I decided to look it up later and immediately moved on to my next request:

Please revise the plan. I'd also like finer granularity (higher resolution). I want to be able to execute, or rather evaluate, by expression, not just by statement.

I learned something new and got what I wanted, which helped a lot.

To give detailed instructions, you don't need to know the names of techniques or algorithms. If you describe what you want specifically in your own words, the AI can map it to an existing concept and tell you its name. The Lifetime instruction above works the same way. I never said "flame chart." I just combined two terms I knew, "call stack" and "timeline."

What matters more than the name is thinking concretely about what you want and writing it down. When that's hard, you can ask the AI questions to sort out your thinking. Keep in mind, though, that the names and explanations an AI gives you aren't always correct. I didn't stop at hearing the name; I looked it up afterward.

This "record the state of every step" approach became the foundation of JSVisualizer. It's why you can move freely forward and backward through the steps (ADR-001, in Japanese, like the other ADRs linked here). It comes at a cost: because every step is recorded up front, programs that exceed the limit (50,000 steps as of November 2026) are cut off partway. That was acceptable because the tool targets small educational programs.

When something feels wrong, give detailed instructions

This is the heart of the loop. What does "detailed instructions" actually mean? Here are three recent examples from October.

1. The symptom and the desired result (call tree appearance, ADR-045)

In the call tree, I want the arguments next to the function name, not on the line below it. I also want the display to be more compact. There's a lot of empty space inside the call boxes, so please reduce the margins on all sides and make the boxes smaller.

"A lot of empty space" is the symptom. "Next to the function name" and "smaller boxes" are the desired result. I didn't specify any pixel values. Claude reduced the node height from 80px to 34px and made the width fit the text.

2. What feels wrong, a proposal, a request for an opinion, and the scope (tab name)

The Japanese name of one tab used the word for "assignment," although the view has nothing to do with assignment in JavaScript. It shows function calls being replaced with their values (the substitution model).

That Japanese term is a strange translation of "substitute." I think the tab should be renamed to the word for "substitution." What do you think? If that's OK, please fix it everywhere, in the tool's display and all the documentation.

The name had been there since the view was added in June. For four and a half months, nobody, including me, said it was odd. It finally bothered me once the tool was in use in class. I asked "What do you think?" because my idea might not be right. The last sentence sets the scope: not just the screen, but all the documentation.

3. Adding the reason (the sample on the initial screen)

In the fib sample on JSVisualizer's initial screen, the if condition is n <= 1. Please change it to n == 1 || n == 2. My course materials use this form. If the condition differs, the number of function calls differs too, which is likely to confuse students.

When you include the reason, Claude can make judgments beyond the instruction itself. In this case, Claude decided on its own to leave another sample with the same condition unchanged, and it told me why: the sample came from an earlier evaluation experiment, so changing it would make things inconsistent with the experiment's results.

To sum up, my detailed instructions included what's wrong (the symptom), what I want (the desired result), and why (the reason). In most cases, they didn't say how to implement it.

You don't have to get it right the first time

Some things took many rounds:

  • The view that shows variables changing in a table went from two panes to one, back to two, and finally to one again. Two panes duplicated the code display on the left, narrowed the table, and required complicated scroll syncing (ADR-012).
  • The view that draws object references started with a force-directed layout. It worked, but it left a lot of empty space, and arrows of the same kind pointed in different directions each time, so you couldn't read the shape of the data structure. I replaced it with a hierarchical layout (ADR-021).

There were also plenty of small fixes that never became ADRs. As of August 9, about 20 of the 103 commits started with "fix:".

When I reverted Claude's fix

Sometimes Claude changed the whole approach in response to a bug report. On May 24, I reported this about JSInterpreter's web page:

I tested it, but the samples don't work. When I choose a program from the samples, it doesn't appear in the editor.

Claude concluded that the cause was my opening the file directly. As a "root fix," it changed the bundle format from ES modules to an IIFE and committed the change, so the page would work when opened directly. All 185 tests passed.

But that wasn't the direction I wanted, so I had it reverted with this instruction:

Still, I want to go with ESM. Requiring an HTTP server is fine.

Passing tests won't reveal this kind of difference in judgment. You need to check not only whether a bug was fixed, but also how. Since I don't read the code, my clue was Claude's report.

At a stopping point: "Document this and commit"

At a stopping point, all I said was "Document this and commit." Claude decided what went into CLAUDE.md and what became a separate ADR.

That means I had delegated the editorial decision of what to record, the last step of the loop, just as I had delegated implementation decisions. I'll discuss whether that was a good idea in part 3.

The limits of this approach

  • My software experience helped in places. It's why I could propose the step execution approach myself. At the same time, when my memory was uncertain, I asked Claude, as with "Please explain the contents of package.json line by line in detail." I think being able to ask about what you don't know as you go helps, however much experience you have.
  • I haven't verified test coverage. Bugs have often surfaced later, and I expect more will. Even so, I consider the tool good enough to use in class.
  • You only notice what feels wrong when someone looks at it. That odd tab name stayed for four and a half months. Problems on screens I don't look at go unnoticed.
  • I don't know everything about what I delegated. As with Lifetime, I sometimes learn what a feature is for only by asking.
  • Some session logs no longer exist. I checked the timeline against session logs and git history, but the wording of my instruction for rebuilding Lifetime is from memory. I'll explain why the logs disappeared in part 5.

Checklist

  • [ ] When exploring a feature, give only the broad requirements and let the AI implement them. Don't try to write a perfect specification up front.
  • [ ] If a plan looks wrong, reject it on the spot and offer your own idea.
  • [ ] Use the implementation, and write down what feels wrong or unsatisfying.
  • [ ] If you don't know what a feature is for, ask the AI to explain it. If the answer doesn't convince you, treat that as something wrong too.
  • [ ] When giving new instructions, include the symptom, the desired result, and the reason. You don't need to know the names of techniques.
  • [ ] Look up the names and explanations the AI gives you to confirm them.
  • [ ] Check behavior by using the software yourself, and ask for tests too. Don't assume that passing tests means full coverage.
  • [ ] For bug fixes, read the report to check not only that the bug was fixed, but how.
  • [ ] At a stopping point, explicitly ask the AI to document the work and commit.

Next time

This post was about the loop, but the first thing that stumped me when I started was "What should I do first?" For JSInterpreter, I ran /init in an empty directory and answered Claude's questions.

Next time: "The first step was CLAUDE.md." I'll cover how to start CLAUDE.md both from an empty directory and with existing code, and how it changed over time.

Models changed over this period. The JSInterpreter exchanges in this post (May 2026) used Claude Sonnet 4.6, and the October examples used Claude Opus 5.5.