Category: AI Development Journal

  • DataMigrator Interim Recap — The Road After M2, and a Detour Called utf8conv

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    Series: DataMigrator Development Journal (Part 7, Interim Recap)


    Last time, M1 (the project-foundation milestone) wrapped up. By rights, this time I should be writing about M2 (implementing the scan engine). But to be honest, as of this writing, I haven’t started M2 yet. Instead, development of a different product (utf8conv) took off first, and DataMigrator has, for the moment, been set aside on the shelf.

    It feels a bit awkward to keep writing the series in this half-finished state, but letting the blog sit idle until the implementation is fully done doesn’t feel right either. So this time, I’m putting together “where DataMigrator currently stands” and “what I plan to do from M2 onward,” and using it as an article to close out the DM series for now. Next time, I’ll slot in a standalone review article, and after that I’ll move into the utf8conv series. Returning to DataMigrator will come later still.

    Where DataMigrator Currently Stands

    Here’s a rough summary of where DataMigrator stands right now.

    First, the requirements definition is done. It went through revisions from Rev.0 all the way to Rev.7, ending up as a document of over thirty chapters (I wrote about that revision process in an earlier article). Next, all eight design documents are complete: architecture, source-code organization, GitHub repository structure, DB schema, class design, GUI design, test design, and the initial prompt for the implementation phase (I also wrote about that design phase in an earlier article). And Claude Code has been introduced, with M1 (project foundation + DBManager + CI/CD) now complete (I wrote about that introduction and the road to finishing M1 in an earlier article, too).

    On the other hand, it’s not yet a “working tool” from a user’s point of view. Right now, what sits in the GitHub repository is a Python package that can’t even display an empty window. Only the sixteen tests are passing, so the DB layer is reliably working, but everything else is still ahead.

    In design-document terms, seven milestones remain in full: M2 (scan engine), M3 (hash engine), M4 (grouping + explore mode), M5 (simple mode), M6 (full-scrutiny mode), M7 (unwanted-file handling + output), and M8 (polish + release). M1 took two hours, so by simple arithmetic the remaining seven would take fourteen — I’d like to say that, but it probably won’t be that simple. M1 was mostly a matter of “laying things out roughly as the design document said,” but from M2 onward, there’s a growing element of “reconciling with reality” — does the code written actually get along with the real filesystem, does the performance hold up, does it break down at the edge cases.

    What I Want to Confirm From M2 Onward

    There are a few points I’m concerned about for the milestones from M2 onward. I’m writing them down partly as notes to myself.

    The first is performance. What DataMigrator ultimately has to deal with is data on the scale of hundreds of thousands of files and multiple terabytes. The design calls for a three-stage approach — narrow things down fast with a partial hash, then run a full hash — but it’s a common story for things to turn out slower than expected once you actually run them. I expect to run into this first around M3.

    The second is filesystem traps. macOS is full of them: iCloud placeholders (files whose contents haven’t been downloaded), extended attributes, resource forks, invisible files, symlink loops. The design document lays out countermeasures, but there’s a good chance that, once I’m actually implementing, I’ll run into things like “huh, this wasn’t written down.”

    The third is whether the “never delete” design philosophy holds up consistently. DataMigrator never performs a “delete.” Even when it finds duplicate files, instead of deleting them it moves them into a quarantine folder called “removed,” so users can change their minds and get them back. Can this policy be kept consistent across every feature from M4 onward? The design document says it will be, but I have a feeling that implementation convenience will keep tempting me to make “just this one exception” — and whether I can hold the line when that happens is also a test of myself.

    The fourth is GUI usability. No matter how solid the internals are, nobody will use it if the screens are hard to use. The GUI design document lays out a structure of nineteen screens, but once I actually build it in PySide6, there are bound to be places where “this isn’t what I expected.” This is a part I can only judge by using it myself as a user — it’s not something the design document alone can settle.

    The fifth is whether I can actually make it to release. Turning it into a .app with py2app, signing it with an Apple Developer ID, getting it through Notarization, and distributing it as a DMG file — I’m planning to walk through this process first with utf8conv. By the time DataMigrator is ready to release, I should be able to reuse the release know-how from utf8conv, so I’m treating that as a kind of advance investment.

    Why utf8conv Cut In Line

    Here, let me explain why development of a different product (utf8conv) started up right after DataMigrator’s M1 finished. This is a bridging note for readers following this blog in chronological order.

    I touched on this in an earlier blog post too: when you’re developing while conversing with Claude, you sometimes run into character-encoding problems. The AI tells you, “please re-save this file as UTF-8.” You re-save it as told. But the garbled text on screen doesn’t get fixed. VS Code itself says, “this is UTF-8.” And still it’s not fixed.

    This experience kept nagging at me. Digging into the cause eventually leads to the story of a mismatch between a file’s actual contents (its byte sequence) and the “encoding declaration” written at the top of the file — but I’ll save that story for the next series. What I want to say here is that the moment I thought “I should build a tool that solves this problem,” my head jumped from DataMigrator’s M2 straight over to utf8conv.

    Looking back now, this jump has both a good side and a bad side. The bad side is obvious: DataMigrator has stalled. As for the good side, let me note just this much: utf8conv is, in scale, much smaller than DataMigrator, and it’s easy to run straight through from requirements definition to implementation and release prep. So partway through, the calculation crept into my head that, as a candidate for “the first product SRW releases,” utf8conv is more realistic than DataMigrator.

    In other words, while keeping the ambition of finishing DataMigrator as “the first product,” I ended up swapping the order so that utf8conv gets released first as “the first-first product” (odd phrasing, I know). The idea that running the full release pipeline through utf8conv first means I can reuse that same pipeline when DataMigrator releases might be a rationalization that’s close to an excuse.

    What I Can Say, As an Interim Recap

    Having gotten DataMigrator’s development this far, I want to close this article by writing down just three things I can say at this point.

    First: it was worth spending the time on requirements and design. All told, requirements definition and design probably took around twenty hours. The temptation of “wouldn’t it be faster to just start coding” came up more than once, but the reason M1’s implementation could proceed almost nonstop in the end is that I could hand Claude Code exactly what was written in the design documents. If the design had been vague, time spent agonizing over each implementation step would have piled up, and it probably would have ended up slower.

    Second: don’t leave everything entirely to the AI. The AI will write the design documents, it’ll write the code, it’ll even write the tests on its own. But the fundamental judgment calls — what to build, why to make a given choice, what to include in or cut from the MVP — those you have to think through yourself. Put another way, my sense is that what AI covers is the “work,” not the “decisions.” If there’s anyone reading this blog who’s trying to build something with AI, this is the one thing I think is worth being prepared for.

    Third: even if it stops partway, that has value of its own. As of this writing, DataMigrator still isn’t finished. Only M1 is done. It’s possible that, even after the utf8conv series, some other “unplanned” thing will cut in and it’ll never actually get finished. Honestly, that possibility isn’t zero. Even so, what I’ve gained along the way — how to run a requirements process, a feel for cycling AI reviews, the right granularity for design, how to work with Claude Code, how to use uv, setting up CI/CD, Claude Code’s autonomous test generation — all of it is an asset I can reuse in the next product, whether that’s utf8conv or any of the seven AI systems. Not finishing doesn’t mean it adds up to zero.

    And with that, I’m closing out the DM series here for now. Once DataMigrator moves forward into M2 and beyond, I’ll pick up the story again.

    Next Time

    Next time, I’m taking a bit of a detour to slot in a standalone review article. The theme is “Local LLM Benchmark.” It’s a record of actually running benchmarks to test the question of whether confidential data that can’t be sent to the cloud can be inspected using nothing but a local LLM running on my own Mac (64GB of memory). The utf8conv series starts after that.


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://sr-works.net/en/index.html

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • Implementing M1 — The AI Wrote Tests I Never Asked For

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    Series: DataMigrator Development Journal (Part 6)


    Last time, I progressed up to introducing Claude Code and preparing the “box” of the DataMigrator project. However, at this stage so far, not a single line of code has been written. All that’s done is an empty house — the furniture and electricity inside are still to come.

    This time is about putting the first code into that empty box. It’s a record of the session where I implemented M1 (the project foundation), the first of the milestones I’d marked off in the design phase. To get to the point: it finished in about two hours. How far did someone with zero programming experience get in two hours? And it’s the story of how, in this session, the real feeling of “I’m building software” sprouted for the first time.

    M1’s Goals

    What I’d do in the M1 milestone was, roughly, the following four things.

    The first is to set up the Python development environment. The second is to actually create, as files, the directory structure written in the design document (eight subpackages under src, a tests directory, a resources directory, and so on). The third is to implement a class called “DBManager” that handles the database. The fourth is to set up a mechanism (CI/CD) where automated tests run on GitHub.

    All of these are things already written in detail in the design documents. In other words, it comes down to just realizing, as actual files, what was written in the design documents. What I, the human, do is, in its basic form, give Claude Code the instruction “I’m starting the M1 implementation. Refer to the design documents and do it in order,” and then watch over the screen and keep pressing the Allow button.

    uv Was Fast, Just as the Rumors Said

    The first thing I did was build the Python environment. Here, for the first time, I used a tool called “uv.”

    The procedure manual I originally had (the MacBook Pro dev-environment setup manual) called for building the Python environment with a combination of pyenv and pip. However, at this M1 timing, I decided to switch to a new Rust-made tool called uv. The reason is simple: at the planning stage of the blog series, I’d heard that “uv is faster and simpler.” The roles that had been split in two between pyenv and pip (Python version management and package management), uv combines into one.

    Claude Code created a virtual environment with uv venv and installed the dependencies all at once with uv pip install -e ".[dev]". The installation of about twenty packages — including a heavyweight like PySide6 alone at 307MB — took, by feel, about a minute. The sheer speed made me chuckle a little. Claude Code explained, “it’s like the Python version of Cargo,” and I was impressed — ah, so that analogy holds (Cargo, apparently, is the package manager of the programming language Rust).

    Incidentally, uv itself had apparently already been installed by Homebrew on its own, and it had become usable without my knowing. I think it got in as some dependency. The “newly install uv” step written in the procedure manual was passed over almost entirely.

    The Directory Skeleton — 78 Files Born at Once

    Next, I create the directory structure exactly as written in Design Document 02 (the source-code organization design). I had Claude Code refer to the design document and instructed it, “please lay out the empty files exactly as written in §3 of the design document.”

    A few seconds later, eight subpackages (gui, controllers, engines, data, models, workers, config, utils) were created under src/datamigrator, each lined with an empty __init__.py and the main empty files. The tests directory, too, was lined with the frames of test files. Seventy-eight files in total. The contents only said “# placeholder,” but looking at the directory tree, the structure was indeed there, just as in the design document.

    At this moment, I had a sensation of, how to put it, just the framework of a model kit having been assembled. It doesn’t move yet, but the form is there.

    And here, right away, there was a small stumble. When I tried running import datamigrator as a test, an error came out. The cause was that the file pyproject.toml was missing the package-detection setting. When you take a placement method called the “src layout,” you apparently have to explicitly tell setuptools to “look inside the src folder,” but that setting was missing.

    If it were me, the human, I’d surely spend about thirty minutes here investigating “why can’t I import it.” But Claude Code read the error message itself, self-diagnosed the cause, added a [tool.setuptools.packages.find] section to pyproject.toml, reinstalled, and checked that it worked again. All of it proceeds automatically before my eyes. I was just pressing “Yes” and “Yes” and “Yes.” Imagining the future where I’d investigate at each error, I felt a little detached from reality.

    The AI Wrote Tests Without Being Told To

    There’s a moment in this M1 session that surprised me the most. It was after implementing the class called DBManager.

    I asked Claude Code as follows: “Refer to Design Document 05 (the DB schema) and implement the DBManager class in src/datamigrator/data/db_manager.py. Please include enabling WAL mode, table creation, and migration management.” A simple request.

    Claude Code read the design document, implemented the DBManager class, and saved the file. So far, as expected. But in the next turn, Claude Code spontaneously began creating a test file called tests/test_db_manager.py. It was about 228 lines of test code. I hadn’t said a single word about wanting tests written.

    What’s more, the contents were quite serious. “Is WAL mode enabled,” “does migration work correctly,” “does exclusive locking function,” “does trying to write on a read-only connection produce an error,” “are the table constraints properly in effect” — and so on, it covered just about all the problems that could occur around the DB. When I ran the tests, all sixteen passed. Coverage was 84%. Without quite understanding what the numbers meant, the mere vibe of “apparently these are good numbers” came across.

    The moment I saw this, I was momentarily confused — “wait, what’s my position here, again?” What I, the human who’d given the instruction, had envisioned was only “implementation,” and I’d intended to ask for “tests” separately — yet Claude Code had read that and gotten ahead of me.

    When I later consulted the Claude.ai side about “why did this happen,” it came back with: “It’s likely that the project’s CLAUDE.md had a policy written in it that ‘after implementation, write tests,’ or that it referred to the test-design document (09) and judged autonomously.” It was also the moment it sank in: “ah, so the effect of the CLAUDE.md I wrote last time shows up in a form like this.”

    As an aside, when running these tests, one warning came out from ruff (a code-formatting tool) that the import order was off. It’s a trivial matter, but Claude Code auto-fixed it with the --fix option, rechecked, and carried it all the way to “All checks passed.” Here, too, I did nothing.

    A GitHub Permission Error, and the Separate-Terminal Problem

    Finally, there was just one stumble in setting up CI/CD.

    CI/CD is a mechanism that “automatically runs tests every time you push code to GitHub.” I set this up with two YAML-format files test.yml and build.yml), and when I tried to git push as usual, I was rejected with an error. The message was to the effect that “since the OAuth token doesn’t have the workflow scope, files under .github/workflows can’t be accepted.”

    Understanding only half of what it meant, I consulted Claude Code, and it told me: “Running gh auth refresh -s workflow -h github.com will resolve it. However, this requires interactive authentication, so it can’t be run inside Claude Code. Please run it in a separate terminal.”

    There’s a constraint, apparently, that launching interactive browser authentication from inside Claude Code is difficult. As told, I opened a separate terminal, ran the instructed command, added the workflow scope in the browser, came back, retried — and the push went through fine.

    This “interactive authentication in a separate terminal” pattern is something I’d encounter once more later, over on the utf8conv side. Once you stumble, the second time you can deal with it instantly using the same procedure. It’s the sensation of a little bit of know-how piling up.

    After M1 Ended, What Remained

    At the end of the session, I counted up what had been made in M1: five commits, 78 files created, four files of implementation code, two CI/CD files, sixteen tests (all passing), 84% coverage, six DB tables with twenty indexes. Working time, about two hours.

    I myself wrote almost nothing. I handed over the design documents, gave Claude Code instructions, pressed Yes on the confirmation dialogs, and occasionally asked “what does this mean?” — that’s all. And yet, inside the screen, a “working database layer” had been built, the tests run, and they run in CI too.

    At M1’s end, I organized the blog-material journal together in the chat on the Claude.ai side. There, I left a one-line note as my own impression: “if the design documents are properly in order, you can entrust the implementation this far.”

    There was one more impression that remained: “maybe it’s become an age where, even with zero programming experience, you can develop as long as you have design skills.” That said, I immediately want to attach a caveat to this impression myself. I borrow Claude’s power even to write the design documents, and to supervise the implementation I have to understand at least the minimum of technical terms. It’s by no means a case of “you don’t have to do anything.” To put it accurately, an expression like “the possibility has emerged of getting to be on the side that builds software, even without writing the code yourself” is probably closer to the reality.

    Still, the fact that the empty box turned, in two hours, into “a box with a working database layer in it” was, as a fact, a happy event. You might call it the night when someone who’d done theater as an enthusiastic amateur first touched their own software.

    Next Time

    Next time, I’ll write about the developments after M1, where DataMigrator as a whole currently stands, and the outlook toward release. To return to my main business of AI development, do I need to complete DataMigrator, or is it okay to wrap it up partway? And I also plan to touch a little on its relationship with another small product progressing in parallel, “utf8conv.” I’ll treat that as a stopping point for the DataMigrator series for now, and connect it to the next series (the utf8conv series).


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://sr-works.net/en/index.html

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • Introducing Claude Code — Setting Up a Dev Environment with a Terminal AI

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    Series: DataMigrator Development Journal (Part 5)


    By the end of last time, requirements and design were done. Up to this point, I’d been proceeding with the Claude I normally use (the chat screen in a browser or app). But once I was finally about to enter the stage of actually writing code, one more preparation was needed: the work of introducing a type of Claude that runs inside the terminal, called “Claude Code.”

    Honestly, until I introduced it, “what do you mean there are two kinds of Claude?” hadn’t really clicked for me. This time, I’ll write the record of the introduction, up to the point where that question got resolved.

    What’s the Difference Between the Chat Version and the Code Version?

    There are, broadly, two ways to use Claude. One is “Claude.ai,” used in the chat screen of a browser or app. This is what I’d been using for requirements and design up to now. You write a question in the input field, and a reply comes back. You can also attach files. The UI is nearly the same as a typical chat app.

    The other is “Claude Code.” This is a Claude that lives in the Mac’s terminal (that thing where you type characters with the keyboard on a black screen), and the biggest difference is that it “can directly read and write files” and “can directly execute commands.”

    To put this in my own metaphor, which I arrived at by hearing it out with Claude Code — the chat version of Claude is “a consultant who gives instructions over the phone from outside the room,” while Claude Code is “a pair programmer who comes into the room and hits the keyboard together with you.” The former is excellent as someone to consult, but the one actually doing the hands-on work is you. The latter writes the code and creates the files directly, but in exchange, if you don’t keep a proper watch on what’s being written, there’s a possibility of unintended changes creeping in. They’re each good at different roles.

    For DataMigrator’s implementation, I decided to use these two with a division of roles. I’d have Claude.ai handle the roles of “design consultant,” “someone to talk to when I’m unsure of a decision,” and “recorder of blog material,” while I’d ask Claude Code for “the actual implementation work.” The practice is to develop while going back and forth between the two windows.

    The Install Was Anticlimactically Easy

    The actual install work finished so smoothly it was anticlimactic. The flow is: put in Node.js via the macOS package manager called Homebrew, and install Claude Code from there. I don’t think it took even ten minutes in total.

    When I launched it, Claude’s logo was displayed in ASCII art inside the terminal, I was made to choose a theme (color scheme), I was asked to authenticate, and it safely reached a usable state. When “Welcome back, Satoshi!” appeared, I had a somehow strange feeling. The me logged in via the browser and the Claude inside the terminal are connected by the same account. Obvious if you call it obvious, but when the kind of screen changes, the same partner feels like a different person.

    That said, in contrast to the speed of the install, “understanding the security side” afterward took a little time.

    A Three-Layer Security Setup

    Claude Code can read and write files and can also execute commands. In other words, it also means that, in a worst case, it could do whatever it likes inside my Mac. Using it without understanding this point felt frightening.

    So for a while, I spent time hammering the Claude on the Claude.ai side with questions like “can Claude Code be used safely?” to understand the mechanism. As a result, I learned that Claude Code has a three-layer set of safety measures.

    The first layer is the “capability scope.” Claude Code basically works within the directory (folder) it was launched in, and going outside that requires an explicit instruction. This is like a building’s “off-limits area” — the image of places it can’t access being decided from the start.

    The second layer is a file called “CLAUDE.md.” This is, so to speak, a “house rulebook” that Claude Code reads if you place it inside the project. If you write rules in natural language — “do not use sudo (escalation of administrator privileges),” “do not touch this directory,” “do not commit while tests aren’t passing” — Claude Code acts in accordance with them. As I’ll describe later, in DataMigrator’s CLAUDE.md I also wrote in the project-wide philosophy of “never delete.”

    The third layer is something called the “Allow flow”: when Claude Code is about to do something with side effects (rewrite a file, execute a command, access something external), it asks for permission just beforehand — “may I do this?” It isn’t executed until the human presses “Yes.” The more dangerous the operation, the more carefully this permission dialog comes up.

    After understanding this three-layer setup, I came to hold the sense that “Claude Code is convenient, but a tool not to let your guard down with.” Rather than going straight to “leave everything to it,” I decided to engage with it, at least at first, with the stance of properly reading the contents at each Allow.

    Failing Small in a Practice Project

    Before jumping straight into DataMigrator’s production project, I made a practice directory and tried “Hello World.” It’s the standard ritual when starting programming.

    When I asked Claude Code, in Japanese, “please write a Python script that displays ‘hello,’ and run it,” it created a file, wrote the code, tried to run it — and there, an error came out. The Python that comes standard with macOS (the python command) couldn’t be invoked, for version-related reasons.

    Normally this would be the point of “oh, an error came out, I’ll have to look it up myself,” but Claude Code read the error message on its own, judged that “we should use python3 rather than python,” rewrote the code, ran it once more, and this time it succeeded. I just watched this exchange. This “recovers on its own even when an error comes out” behavior was a big source of reassurance for someone with no programming experience. The sense is that you can take errors as a given and entrust the handling of them after they happen.

    Getting carried away, I next tried asking, “please write a program that displays a window with PySide6.” This failed spectacularly. The standard macOS Python was old, so PySide6 wouldn’t run; switching next to Tkinter, that wouldn’t run either; and finally, judging that “we need to start by updating the Python version,” Claude Code itself proposed suspending the work.

    This failure was frustrating, but at the same time it was also useful, because I could understand — not in my head but in my body — the reality that “to run a GUI app properly, you need a proper Python environment.” This also became foreshadowing for the later introduction of uv (I’ll touch on uv in the next article).

    Preparing the Production Project — An Alias Called dm

    Once the practice was at a stopping point, I finally prepared the directory for DataMigrator.

    I put it at ~/dev/datamigrator. Until then, I’d been gathering Soul Resonant Works—related files in a folder called ~/Documents/SRW, but I decided to separate development projects into their own dedicated directory. The reason is that when “development projects” and “documents” get mixed in the same folder, finding things gradually becomes a pain. Anticipating that several development projects with uncertain futures would line up, I made a policy of creating a new directory, ~/dev/, and gathering development projects there.

    Next, I set up a terminal alias (a shortcut command). Concretely, I added the following one line to a file called .zshrc.

    alias dm="cd ~/dev/datamigrator && claude"

    With this, just by typing dm in the terminal, it moves to the DataMigrator directory and launches Claude Code. It’s a simple contrivance that combines two commands into one. Once I started using it, this was unexpectedly pleasant, and the action of “type dm and you enter the project” became a little ritual.

    As an aside, I got a little confused trying to do this setup from inside Claude Code. I rewrote .zshrc from inside Claude Code and then tried to run dm within it, but I was gently admonished: “you’re already inside a Claude session, so a new session can’t be launched.” “The dm alias is meant to be used from a normal terminal.” Claude Code senses the human’s confusion and guides you politely.

    Once I exited Claude Code with /exit, returned to a normal terminal, and typed dm again, Claude Code safely launched in the DataMigrator directory. It felt like “a password to enter the house,” and I remember getting a little happy about it.

    Placing CLAUDE.md and .gitignore, and Pushing to GitHub

    What remained was to create DataMigrator’s CLAUDE.md (the project’s rulebook), a journal template, and a .gitignore (a list of files you don’t want managed by Git), initialize it as a Git repository, and push it to GitHub.

    I asked Claude Code for this whole series of work all at once, in a single compound instruction: “please create CLAUDE.md, place a template in docs/dev-journal/, create .gitignore, make the first commit, and create a private repository on GitHub and push to it.” Claude Code created the files in order, interjecting “may I run this?” confirmations along the way when necessary, and completed all of it.

    Just once, for GitHub authentication, I needed to pass through browser authentication using gh auth login --web. The flow is: a one-time code is displayed in the terminal, and you enter it into the browser to approve. After this authentication finished, things moved all at once, from creating the repository to the first push.

    By the time all the work was done, the DataMigrator project was in the following state. Locally there was a directory ~/dev/datamigrator, with CLAUDE.md, .gitignore, and the journal template inside; it was managed by Git; and the same thing was up on GitHub. And by typing dm, I could resume work in Claude Code anytime. I hadn’t written a single line of code yet, but I’d arrived at “a state where development can happen.”

    Next Time

    Next time is finally the implementation of M1 (the first milestone). I hand the design documents to Claude Code and have it build the project’s framework and the database part. What surprised me most in this session was that “without being instructed, Claude Code wrote the test code itself.” The sense that “if the design documents are solid, you can entrust the implementation to a fair degree” begins here. At the same time, I ended up building the Python environment using a different tool called uv rather than pyenv, and I was impressed by uv’s speed, too. Look forward to the curtain-raiser on the implementation phase.


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://sr-works.net/en/index.html

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • The Design Phase in Three Sessions — Having AI Design the Architecture

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    Series: DataMigrator Development Journal (Part 4)


    By the end of last time, I’d finished writing Rev.7 of the requirements document, and I was ready to advance to the design phase. This time is about that design phase.

    To get to the point: I split the design phase into three sessions total. Session 1 for the architecture, Session 2 for the database and classes, Session 3 for the GUI and tests. About eight design documents came out of it, and the total volume reached a fair thickness. I wrote all of them together with Claude. Until this period, I’d never imagined that someone with zero programming experience would end up writing an architecture design document.

    Starting by Asking the AI What Design Even Is

    Honestly, at first I didn’t quite get the difference between requirements and design. Requirements are “what to build,” design is “how to build it” — that’s what the books say, but concretely, what am I supposed to do? “How to build it” shouldn’t mean the code itself, so then this something that sits one step before the code — at what level of granularity are we talking?

    When I asked Claude, the explanation that came back was roughly the following. A requirements document is a request form — “please build this” — while a design document is closer to “the blueprints of a building that satisfies that request.” A building’s blueprints have layers — the number of floors, the room layout, the placement of pillars, the plumbing, the wiring — and each is drawn on a separate sheet. Software is the same: you need a separate design document for each layer — the overall structure (architecture), how the data is held (DB), the relationships among the parts (classes), the appearance (GUI), the method of quality verification (tests), and so on. Starting to write code only after all these design documents are in place corresponds, in building terms, to “bringing in the materials only after the foundation and blueprints are done.” That was the explanation.

    This explanation made me understand: “Ah, so that’s why you split it into three sessions.” Asking, in a single chat, “please write all the design documents” is like suddenly telling a single architect “gimme all the drawings” — it’s not realistic. Splitting it by layer and working through them one at a time is something I, as a human, can keep up with too.

    Session 1: Architecture

    In the first session, I decided the skeleton of the whole software. It’s the configuration known as a “three-layer architecture.” You divide it into three: the GUI layer (the part that interacts with the user), the business-logic layer (the part that assembles the processing you actually want to do), and the data-access layer (the part that accesses the database and file system).

    Put like that, it just sounds like a classification, but what was interesting in this session was that the idea of a “shared engine” came up.

    In the requirements, I’d decided to build three modes for DataMigrator (Exploration mode, Quick mode, Full-inspection mode). Naively, you’d write unique processing logic for each of the three modes. But look closely, and what the three modes do has a lot in common. They all share the same skeleton: first scan the files, then take hashes, and finally group and display the results. What differs is only the parameters — things like the scan scope and the way hashes are taken.

    What Claude proposed was the policy: “rather than writing processing logic for each of the three modes, build just one set of shared engines (a scan engine, a hash engine, a grouping engine) and change how they’re called per mode.” Doing this reduces the amount of code, means a fix only needs to happen in one place when a bug appears, makes it easier to carry data over between modes, and makes it easier to merge or add modes in the future — the benefits were laid out one after another.

    At this point, I asked one question back: “What’s the benefit of going with this policy? Is it that the implementation cost is low?” From the perspective of someone with no programming experience, I had an intuitive grasp that “gathering similar things in one place seems good,” but I didn’t understand concretely what it led to.

    The answer that came back raised, beyond implementation cost, perspectives like “localization of bugs,” “test efficiency,” “carrying data over between modes,” “future flexibility,” and “ensuring consistency” — and I remember it sinking in: “ah, so it has that wide an effect.” For me, this single exchange was the moment that decided the direction of the entire design phase. Had I just thrown it over the wall with a “leave it to the pro,” I think I’d probably have regretted something later.

    Session 1 also decided other things: the thread configuration (one main thread and one worker thread), the method for cancellation handling, and the method for detecting when you step into a symbolic-link loop. These were the result of crushing the architecture-related items from among the homework that had been left in Appendix C.

    Session 2: Database and Classes

    The second session was the design of how to hold the data and of the parts.

    I decided to use SQLite for the database. For a personal tool, where the use is no more than storing file metadata and hash values, SQLite is plenty. There’s no need to stand up a separate server, and the fact that it completes in a single file is a welcome thing.

    The table structure settled into five tables: a table to store the history of scan runs, a table to store information for each individual file, a table to store groups of duplicate candidates, a table for error logs, and a table for file-move logs. The structure has these five connected to one another by foreign keys.

    This gets into the weeds, but what quietly troubled me in this session was the “is it okay to put two different meanings of data in the same table?” problem. Quick mode’s “duplicate-candidate groups” and Full-inspection mode’s “confirmed-duplicate groups” are, strictly speaking, different in meaning. The former is “only the name, size, and partial hash match,” while the latter is “matched completely, all the way to the full hash.” Is it okay to put these in the same table, or should they be in separate tables?

    As a result of discussing it with Claude, I went with the policy of using the same table and distinguishing them with a “group type” column. The big benefit was that being able to handle them in the same table makes it easier to carry data over from Quick mode to Full-inspection mode. It’s through an accumulation of small decisions like this that the design document fills up.

    On the class-design side, I defined around thirty classes: the engine family, the mode-controller family, the data-access family, the worker-thread family, the utility family, the custom-exception family. For each individual class, the role and the public methods get written out. I don’t write code, but at this stage an image started to come into view: “ah, so this class gets called like this.” I think the sensation of the software starting to move inside my head gradually began to emerge around this time.

    Session 3: GUI and Tests

    The third session was screen design and test planning.

    In the GUI design, I defined nineteen screens: a mode-selection screen, a folder-selection screen, a progress screen during a scan, a results-display screen, a confirmation screen for deletion candidates, a settings screen, error dialogs, and other auxiliary screens. I had Claude write out the role of each screen and the flow of the main operations. I didn’t draw the actual appearance as pictures — it was closer to a bulleted level of “this screen has these items lined up on it” — but even so, I had the sensation of “the tool’s form, as seen by the person using it” gradually rising up.

    What was intriguing was that, in the middle of doing the GUI design, an idea for a new feature occurred to me. It was the thought, “rather than only deleting duplicate files, it might be handy to have a mode that gathers the scattered actual data into one place (consolidation into a storage folder)” — a feature that hadn’t been written in the requirements document.

    Naively, the proper thing would be to go back to the requirements and add it as Rev.8. But as a result of consulting Claude, we discussed “is this feature high enough priority to include in the MVP,” judged that it was “worth including,” and then took it in by adding it to the design document. Whether to strictly adhere to the requirements, or to flexibly take in improvements you notice along the way — this is a hard line to draw, but this time I chose the latter. Looking back now, I think it’s one of the strengths of solo development. In a large organization, taking in a mid-stream idea like this would require meeting after meeting.

    In the test design, I defined just under eighty unit-test cases and a dozen-odd integration-test scenarios. All of these would get written during the implementation phase. At this point, I had the surprise within me of “so that’s how much testing you write.” I came to terms with it: this is probably, in essence, the same as how there are days and days of full run-throughs before a theater performance. Going in cold without rehearsal doesn’t work — on the stage or in software alike.

    After Finishing Eight Design Documents

    After three sessions, the design documents came to eight in total: software architecture, source-code organization, GitHub repository structure, DB schema, class design, GUI design, test design, and the initial prompt for the implementation phase. On top of these, auxiliary materials such as handoff prompts between sessions and meeting notes also piled up.

    Honestly, my impression when the whole thing was finished was “is this really okay?” Even though I wrote it together with AI, I myself have zero programming experience. There’s a limit to how well I can judge whether these design documents are of a quality that can withstand implementation. Gazing at the table of contents, I can tell it somehow looks the part, but I lack the foundational knowledge to scrutinize all the contents myself.

    Still, I couldn’t very well stay stopped here, so I confirmed things up to the point of “at least all the Appendix C homework is crushed, consistency with the requirements document holds, and the obvious holes have been plugged through discussion with Claude,” and made the decision to advance to the next phase. If it turns out to be no good, then it’s no good, and I’ll fix it in the implementation phase. That kind of resignation.

    Incidentally, the time it took to write the eight design documents was, in total, I think a little over ten hours — about two to three hours per session. For someone with no programming experience to write this volume of documentation from scratch on their own would probably be impossible even with months. It’s because I did it together with AI that it took only this much time. Of that, there’s no doubt.

    Next Time

    Next time, I finally enter the “have AI write the code” phase. But before that, one more preparation was needed. Separate from the Claude I’d been using so far (the chat version used in a browser), I needed to introduce a type of Claude that runs in the terminal, called “Claude Code.” Starting from installing it on the Mac, having it write “Hello World” in a practice project, understanding the security mechanisms, preparing the directory for the production project — the plain, unglamorous prep work continues. Along the way, there were a few stumbles, too: hitting Python-environment problems when I tried to run PySide6, and strange errors in GitHub authentication. Look forward to the Claude Code introduction installment.


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://sr-works.net/en/index.html

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • Finishing the Requirements with Claude Opus 4.6 — My AI Switching Strategy

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    Series: DataMigrator Development Journal (Part 3)


    Last time, I wrote about how I started writing Rev.0 of the requirements document together with a different AI, and — through repeated critiques and fixes while having Claude review it — reached Rev.5. This time is the continuation: the second half heading from Rev.5 toward Rev.7, and the story of deciding to “switch” AI in the process.

    The phrase “switching AI” doesn’t quite sit right with me, somehow. It’s not like moving house, where you cart your chat history and documents over in one big load, and since AI isn’t a physical thing in the first place, it’s not quite “buying a replacement” either. Still, in terms of actually getting the work done, it was a decision that felt nearly as concrete as that.

    As the Document Grows, the AI Can’t Keep Up

    As I touched on briefly at the end of last time, around when I reached Rev.5, the other AI I’d been using started behaving more and more erratically.

    The typical symptoms went like this. While we were discussing the latter half of the document, it would forget something it had supposedly decided in the first half and propose, all over again, an idea that had already been rejected. When I pointed out “that approach was already settled in Chapter 7,” it would apologize — “you’re quite right, my apologies” — but a few turns later the same kind of forgetting would happen somewhere else. Or, when I added a new chapter, the consistency between that chapter and the existing ones would break down.

    This isn’t the AI slacking off, much less being malicious — it apparently comes from a technical constraint called the “context window,” as Claude explained to me. There’s an upper limit to how much information an AI can handle at once, and when a document grows too large, it exceeds that limit. The behavior then becomes something like dropping old information while taking in new information. As a result, it looks like it’s “forgetting the first half.” That’s the gist of it.

    Come to think of it, human short-term memory has a similar constraint — the thing where you forget what you decided thirty minutes ago in a meeting as the discussion heats up. The difference is that for AI, that limit is technically fixed, and it also varies with the version and the length of the conversation.

    By Rev.5, the requirements document already had nearly twenty chapters, and with the finer supplementary notes it reached tens of thousands of characters. That it had grown to a volume the AI couldn’t fully grasp was, objectively, obvious.

    Why I Moved to Claude

    So, from the second half of the requirements work, I decided to move the center of the work in earnest to Claude, which had been playing the reviewer’s role. There were three reasons.

    The first is simply the size of the context window. Even handling a document of the same quality, Claude has a higher upper limit on how much it can handle at once and is less prone to forgetting the first half. I could feel this right away. When I pasted in the full text of Rev.5 and asked “please check whether there’s any contradiction between this chapter and that one,” I’d get back an answer that had properly surveyed the whole thing.

    The second is a feature called “Project Knowledge.” This is a mechanism where you register materials per project, and during the conversation Claude searches them for the information it needs and uses it. It’s like “the AI’s long-term memory,” so to speak, and you don’t have to re-paste the document every time. If you register everything from Rev.0 through Rev.5 of the requirements document, it becomes able to answer questions like “there should have been a discussion like this in some chapter of Rev.3 — what was the conclusion at the time?”

    The third is usability with the design and implementation phases in view. DataMigrator’s development doesn’t end when requirements end. After that come design, implementation, testing, and release. Being able to keep using the same AI through those phases makes the handoff of context smoother. Thinking it through, switching over early — even partway through requirements — should make things easier down the line.

    To be honest, there was a slight resistance to switching. From Rev.0 to Rev.5, I had spent a fair amount of time with that other AI. Resetting its conversation history, and the context it had (supposedly) remembered, to move to a new AI somehow brings up a feeling of “what a waste of everything I’ve built up.” But thinking calmly, the accumulation remains on the document side, so even if the AI changes, I’d have no trouble as long as I carried over that document. I talked myself into it that way and decided to make the move.

    From Rev.6 to Rev.7 — Crushing the Remaining Issues

    In Rev.6, after moving to Claude, I crushed the issues that had remained from the Rev.5 review one by one. Concretely, things like: what grouping method to use for Quick mode, whether the positioning of Exploration mode could be made clearer, and how to design the screen transitions among the three modes.

    What struck me at this stage was that Claude posed its questions in a one-question-at-a-time format. The style was: “Please answer Question 1. Once you’ve answered, we’ll move on to Question 2.” For me as a human, having a lot of points thrown at me at once makes my head a mess, so this way of proceeding was a huge help. I hadn’t specified “please go one question at a time” myself — Claude naturally proceeded in this style on its own, and looking back, I think that was significant.

    In Rev.7, I further tidied up the document’s formal aspects: organizing chapter numbers, adding a glossary, rearranging figures and tables, and putting the appendices in order. By this point, the requirements document had become a document of over thirty chapters. When I started writing Rev.0, I had absolutely not imagined that someone with zero programming experience would end up writing a thirty-chapter document together with AI. I can’t quite recall whether I’d ever handled a document that long anywhere in my own work.

    Appendix C — “Cleanly Deferring” What Can’t Be Decided

    Rev.7 of the requirements document has an unusual chapter called “Appendix C.” It’s a “list of issues that can’t be settled at the requirements stage.” There were eleven of them in all.

    For example: the thread configuration (how many worker threads to run), the method for detecting symbolic-link loops, the final organization of the mode structure, the method of exclusive locking for the project folder, the size of the partial hash, the concrete contents of the scan-exclusion presets, and so on. Every one of them is closer to the territory of design than of requirements.

    Why did I put this into the requirements document? Because I wanted to leave it as a memorandum: “to build this tool, these points absolutely must be crushed during the design phase.” If you force a conclusion at the requirements stage, you decide things without enough technical examination, and they get overturned in the design phase. But if you forget they exist altogether, you’ll panic once you’re in the implementation phase — “wait, what were we going to do about this?”

    The conclusion I reached while consulting Claude was a compromise: “don’t decide, but don’t forget.” Appendix C is that compromise given form. It was only later that I started calling this approach “cleanly deferring.”

    Looking back now, I feel this is close to the sense of production scheduling in theater. When you make a schedule leading up to opening night, rather than writing “TBD” for things that aren’t decided, it’s better to decide “we’ll decide this by such-and-such date” — and that way, you end up not in trouble on the night. That kind of sense. Less a style for developing with AI, and more a moment where my own past experience was, just a little, useful.

    The Idea of Splitting Sessions

    One more thing that solidified during my exchanges with Claude around this time was the idea of “splitting sessions.”

    In a conversation with Claude, one “chat” becomes one work session. But if you keep one chat going endlessly, the context-window problem I mentioned earlier comes up. The longer the conversation gets, the harder it is for the first half’s information to reach the latter half. This is a constraint that even Claude can’t fully escape.

    So I started a practice of splitting one big task (for example, “the second half of the requirements work”) into multiple sessions. I’d set a clear goal for each session, and once that goal was reached, move on to the next session. When starting the next session, I’d compile the deliverables of the previous session and a summary of what had been decided so far into an “initial prompt,” and hand it over at the very beginning of the new session.

    Creating this initial prompt was, in fact, quite an important task. What to write and what to omit, how much detail to go into, how to instruct what I wanted done in the new session. Get this wrong, and the discussion in the new session wanders. Get it right, and the new session can get straight to the heart of the matter.

    The initial prompt itself, too, settled into a method where I’d ask Claude “please make an initial prompt for the next session,” have it produce a first draft, and then revise it myself. Claude itself would sometimes propose where to break the session, and I often went along with those proposals.

    The Feeling That Requirements Were Finally Done

    By the time I’d written Rev.7, I honestly had a feeling of “is this really the end?” I couldn’t shake the sense that somewhere in this thirty-plus-chapter document there was an oversight, and I had the worry that once I started implementation, different problems would come gushing out.

    While asking Claude for a final check, I also had, within myself, a resignation: “no matter how much longer I dig in here, the problems that surface when I move to design and implementation will surface regardless.” A requirements definition is something you can keep aiming for perfection on, but unless you declare at some point “settled, as far as I can currently see” and move on, it may be a task that never ends in your lifetime.

    In the end, I treated Rev.7 as the finalized version of the requirements phase and moved on to the next, design phase. The eleven items of Appendix C carry over, as is, as homework for the design phase.

    Next Time

    Next time is about clutching Rev.7 of the requirements document and stepping into the design phase. I split the design phase into three sessions: Session 1 for architecture, Session 2 for the DB schema and class design, Session 3 for the GUI and test design. What was it like to have AI write design documents on the scale of 20,000 lines? How did I crush the eleven pieces of homework left in Appendix C? From here, I step out of the world of requirements and into the world of “how to build it.”


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://sr-works.net/en/index.html

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • When I Had AI Write Requirements, It Took 5 Revisions

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    Series: DataMigrator Development Journal (Part 2)


    Last time, I wrote about how, in order to escape data-migration hell, I decided to build a tool to solve that hell myself. This time is the next step: the stage of deciding “so what, exactly, am I going to build?” It’s a record of someone with zero programming experience attempting what’s called a requirements definition, together with AI.

    To get to the point: the first version (Rev.0) ended up being almost entirely rewritten. From there I went through five more revisions before finally reaching a state where I could think, “Okay, this looks ready to move on to design.” You might assume that since I was working with AI, a perfect requirements document would pop out on the first try — but that wasn’t the case at all, and that’s the theme of this installment.

    What Is a Requirements Definition, Anyway?

    I’m a little embarrassed to admit it, but before I started development, the term “requirements definition” was something I’d only vaguely heard of. How it differs from a “specification,” how it differs from a “design document” — honestly, I don’t think I could have explained any of it cleanly.

    To put it simply in my own current understanding, a requirements definition is the work of deciding, in words, “what to build and what not to build.” “How to build it” comes one step later (that’s design), and the concrete code comes at the very end. The order goes requirements → design → implementation, gradually raising the resolution stage by stage.

    Even when you have AI do the development in the style called vibe coding, if this “what to build” is fuzzy, what the AI produces comes out fuzzy too. Sure, the human only has to give instructions in plain language — but if that language is vague, you end up with a mountain of rework. This is one of the parts where, even leaning on AI, the human still has to do the thinking.

    So, to begin with, I used an AI system other than Claude to write up Rev.0 of the requirements document. The reason I started with a different AI was simply that I’d had a project going on over there earlier, and in the flow of things I just kept writing with that same AI. There was no deeper meaning to it.

    Rev.0 Had Sky-High Resolution on the Problem Alone

    Rev.0 of the requirements document was packed with the concrete hardships I’d experienced during data migration. What traps lay in moving files between the iMac and the MacBook Pro. The macOS-specific issue of purgeable space. The matter of iCloud-synced placeholders whose actual contents hadn’t been downloaded. How invisible files like .DS_Store become noise. How rsync spits out tens of thousands of log lines you can’t read. How a multi-terabyte hash comparison takes who-knows-how-many hours.

    Reading it back, it was certainly a document that conveyed “this person really did struggle.” But flip that around, and you could just as easily say it was “a memo of grievances with a feature list stapled on” — the solution side was quite rough.

    For example, the processing flow was laid out in a straight line: “GUI input → pre-check → rsync → analysis → judgment → copy → output.” At a glance it looks tidy, but what if rsync fails? What if the NAS disconnects partway? What if you run out of space? What if the user cancels midway? — these “things go wrong” branches were almost entirely absent.

    Once Rev.0 was more or less written, the worry “is this actually any good?” welled up. I have no experience to judge quality myself, so my only option was to have someone review it. So, even though it was technically a separate project, I decided to ask Claude to review it too.

    “High Resolution on the Problem, but a Rough Solution”

    When I pasted in Rev.0 and asked for a review, the overall verdict that came back was exactly that: “The resolution on the problem is very high, but the resolution on the solution is still rough.” The wording was gentle, but in essence it meant “you can see the problem clearly, but the part about how to solve it is hazy.”

    The specific points Claude raised were, roughly, as follows.

    First, there was no definition of the target user. Whether the user is an engineer or a general user completely changes the UI you should build and the granularity of error handling — that was the point. My own attitude had been more like “as long as I can use it, that’s fine,” but I was told that if I had any intention of selling it, who uses it is the single most important thing. Fair enough.

    Next, the reliance on rsync was too heavy. The rsync bundled with macOS is an old version with idiosyncratic log output, and it behaves differently from the newer rsync you install via Homebrew. The developer can’t control which rsync version is in the user’s environment. And if you’re going to distribute it as a commercial tool, making users install rsync separately isn’t realistic. — These were all things I only noticed once they were pointed out. It was simply that I happened to be using rsync on my own machine, so I’d written everything around rsync without really thinking about it.

    There was also the point that priorities and the scope of an MVP (minimum viable product) weren’t defined. Rev.0 had a lot of features lined up, but “which to build first and which to put off” hadn’t been decided. For someone with zero programming experience like me, trying to build every feature all at once is an almost guaranteed path to collapse.

    Error handling, test strategy, the performance problem of hash comparison, how to handle iCloud placeholders — these “things you’ll struggle with once you start building” were almost entirely missing from Rev.0.

    Incidentally, my mood when I got this review is a little hard to put into words, but it was something like a messy blend of “yeah, I figured,” a slight deflation at “I never could have caught this myself,” and the relief of “but I’m glad it was pointed out.” I knew from books that there’s apparently a “review culture” in the programming world, but I think this was the first time I’d experienced firsthand an AI giving me a genuine, proper review.

    From Rev.1 to Rev.5 — What Changed Across Five Revisions

    From here it became a back-and-forth of critiques and fixes. I’d reflect the feedback in Rev.1, ask for another review, and the next round of feedback would come out. Reflect that, and the next round would come out again. I repeated this up to Rev.5.

    As for the big changes: first, I broke free of the rsync dependency. In its place, I switched to an original comparison method that completes using only Python’s standard library. Concretely, it’s a three-stage approach: first narrow down candidates by file name and size, then quickly narrow further using a hash of just the first few kilobytes of a file (called a partial hash, apparently), and finally confirm with a full hash. With this method, even with 100,000 files, the number you actually take a full hash of works out to just a few hundred to a few thousand.

    Next, the structure of three modes solidified. The original Rev.0 was vaguely “a tool to compare and tidy up,” but over the course of the revisions it split into three: an Exploration mode, a Quick mode, and a Full-inspection mode. Exploration mode is for getting a bird’s-eye view of the whole disk to grasp “what is where”; Quick mode finds duplicate candidates fast; Full-inspection mode takes its time to judge with certainty. The idea is that users pick the mode according to their own situation.

    I also defined the user tiers in three levels: Tier A (general users who don’t know rsync), Tier B (intermediate, who understand concepts like hashing and diff comparison), and Tier C (advanced, who understand even file-system behavior). And I settled on the policy: “design the UI so that Tier A never gets lost, while giving the internal design robustness that can withstand even Tier C.”

    And — this is something I’d like to devote a whole article to later — the design philosophy of “never delete files” also solidified during these revisions. Even when it finds duplicate files, this tool never presses a “delete” button. Instead, it moves them to a quarantine folder called “removed.” If the user later thinks “actually, I want that back,” they can restore it. Guaranteeing this “reversibility” was my top priority, because I myself feared accidental deletion more than anything.

    Having the AI Critique Me Was the Requirements Definition

    Looking back after five revisions, the work I was doing felt less like “writing a requirements document” and more like “having the AI critique me, and answering those critiques.”

    I’d have Claude read the rough draft I, the human, had written, have it point out the problems, give my own answers to those points, and reflect them in the document — that was the cycle I kept turning. The AI didn’t write the requirements document all by itself. The closest description is that the AI functioned as an excellent critic.

    When you have AI write something, it tends to become “an agreeable partner who goes along with anything.” But for “finding the holes” work like a requirements definition, a partner who tells you the hard-to-hear things is actually more valuable. If you explicitly ask “please review this strictly,” the AI duly switches into a sharp-tongued mode. Not letting it flatter you may be one of the knacks for using it well.

    Also — this is something I noticed only after writing all the way to Rev.5 — once the document’s volume passed a certain point, the other AI I’d been using started handling it unreliably. Whether it was that it couldn’t read the whole document, it would forget things it had supposedly decided in the first half, or it would dredge up issues that had already been resolved, with increasing frequency. This is a matter of a technical constraint called the “AI’s context window,” which I’ll write about in a bit more detail next time.

    Around this time, I began to think seriously about switching over to Claude in earnest. There are several reasons, but it would get long, so I’ll save it for next time.

    Next Time

    Next time, I’ll talk about the second half of the requirements work — the road from Rev.6 to Rev.7. How I decided to “switch” from the other AI to Claude, how Claude’s “Project Knowledge” feature helped, and the story of “clean deferral” — handing off issues that couldn’t be settled during requirements to the next phase as “Appendix C.” In the end, the requirements document became a document of over thirty chapters. When I started writing Rev.0, I never imagined someone with zero programming experience would end up compiling such a document together with AI.


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://sr-works.net/en/index.html

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • Falling into Data Migration Hell While Setting Up for Local AI Development

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    Series: DataMigrator Development Journal (Part 1)


    In my previous blog posts, I described how, over the four months from January to April 2026, I could barely get to my main business of AI development, and how instead three unplanned products got off the ground — and how, on top of that, I kept getting absorbed in other new ideas, leaving my main business stuck.

    Starting with this article, I’d like to write up the development record of the first of those products — “DataMigrator” — step by step. This first installment is about why I decided to build the tool in the first place. I’ve touched on it briefly in earlier blog posts, but here I’ll go into a bit more concrete detail.

    To be honest, the development itself isn’t finished yet. Even whether it will ever be finished is, in my own mind, about a fifty-fifty proposition. It’s less “I’m writing this because I expect to complete it” and more “I want to leave a record of the whole process, stalls and all.” Hello — I’m Kanazawa, the representative of Soul Resonant Works.

    The Day the MacBook Pro Arrived

    At the start of 2026, I bought a new MacBook Pro M4 Max. As I’ve mentioned in earlier blog posts, I bought it for my main business: developing local AI systems.

    For someone who has used Macs for years, the moment a new Mac arrives is a small ritual. It’s not something you buy often — it’s a once-every-few-years event — so I unboxed it while noticing how the packaging had changed. Lately, as with the iPhone and the like, there was tape sealing the gap between the base and the lid to guarantee it hadn’t been opened.

    The iMac I’d been using had hit its performance limits, so I was counting on finally being able to start implementing the seven AI systems for which I’d only written the design documents — and on a dramatic performance boost for the other apps that lean on processor power and memory (video and the like).

    But within a few hours, that excitement was overwritten by a different feeling.

    “Wait — how am I going to get all the data I’ve been using over onto the new Mac?”

    It should have been simple. Apple has a handy feature called Migration Assistant that moves your data wholesale from the old Mac to the new one at the push of a button. I’d used it on previous upgrades. But this time, I couldn’t bring myself to just run it.

    Twenty Years of “I’ll Sort It Out Later” Had Piled Up

    There was one reason: the old iMac’s contents — and the storage devices around it — were in a completely disorganized state.

    Originally, because I’d been using external HDDs to store photos and videos, I had the iMac’s internal drive plus external HDDs, and on top of that a separate external HDD for Time Machine that backed up the whole thing.

    Since the free space on the internal drive directly affects the Mac’s performance, I’d been moving files around as needed.

    My storage setup at the time was:

     1. An internal Fusion Drive, 3TB

     2. External HDD 1: a 4TB drive I’d named “4TB-01”

     3. External HDD 2: a 4TB drive I’d named “4TB-02”

     4. External HDD 3: a 12TB drive to back up all of 1–3

    Drives 2 and 3 were housed together inside a single HDD enclosure.

    Since the enclosure had no RAID function, it amounted to two separate 4TB volumes — 8TB in total.

    Across this storage, files I’d offloaded for reasons like “the iMac was running out of space, so I moved it,” “I copied it as a backup,” and “I figured it’d be safe to stash here” had quietly piled up.

    An enthusiastic amateur at many things, I had stage photos and performance videos from theater, band recordings, photos I’d been accumulating since around 2004, and more — over twenty years’ worth of digital debris scattered across multiple drives.

    The worst of it: there were things I’d copied as backups but then, out of laziness, never deleted from the original location. At first I’d felt something like “I’m not sure it copied correctly — what if the copy failed?” — and then I’d lose track of which one was the master, leaving huge folders and files existing in multiple separate places.

    There were multiple sets of duplicate data ranging from hundreds of gigabytes to terabytes in size.

    Photos were sorted out fine thanks to iCloud, but video files and the like were another story, and multiple copies had ended up existing.

    If I ran Migration Assistant in this state, I’d unquestionably end up with a “copy of the mess” on the new Mac. It wouldn’t all fit capacity-wise either, so some kind of cleanup was needed beforehand.

    A Scale No Amount of Manual Work Could Handle

    At first, I thought I’d manage it by hand.

    To start, I’d take the latest version of the Time Machine contents as the baseline and delete what wasn’t needed.

    The process of judging whether something is unneeded is deeply unproductive, and I just can’t warm to it.

    Whether the latest Time Machine backup truly reflected the most current state, whether all the files were gathered in one place — just sorting out questions like these took an enormous amount of time.

    Then I set about hunting through multiple HDDs for copies of what was in that backup, and checking whether they were perfectly identical.

    But I could never get real certainty that “this data truly, genuinely has no differences.”

    On top of that, the macOS file system has all sorts of traps you can’t see from Finder. Right-click a folder and hit “Get Info” to see its size, and the spinner just starts turning and never comes back. Folders synced to iCloud have placeholder files mixed in whose contents haven’t been downloaded, so their sizes can’t be trusted. There’s a concept called “purgeable” space, where the displayed free space and the actual free space don’t always match. Invisible files like .DS_Store, and the OS’s auto-generated search indexes, also get in the way of diff comparisons.

    I also tried dropping into the terminal to handle it with commands. Using rsync to compare folders and surface the differences; using the find command to extract files matching specific conditions; using shasum to compute hashes and judge whether contents were the same — I tried each one, one at a time, consulting AI along the way.

    It works up to a point. But after rsync spits out tens of thousands of lines of logs, a different problem emerges: how do you read those logs? When information like “this file is newer, but that one over there is older” stretches on for tens of thousands of lines, a human simply can’t process it anymore. You could write a script to parse the logs — but I didn’t have the knowledge to do that, and trying to pull it off together with AI would have been a major undertaking in itself.

    Even trying to feed the log files to an AI, I’d immediately hit the character limit, and the AI would simply refuse to read and analyze the whole thing — the obstacles were piled high.

    And even checking the properties of each folder and file one by one, I couldn’t determine whether they were “truly, genuinely the same file.”

    One comparison method the AI taught me was computing hash values. By reading the entire contents of an individual file and converting it into a fixed-length string (a hash value), you can determine whether two pieces of data are perfectly identical. Because the method disregards information like the file name and creation date and works only on the actual data portion, it can reliably capture whether the underlying data is the same or not.

    For someone like me — the type who’s scattered the same data across multiple places — I thought this was the best approach.

    But when there’s too much data, and each individual file is too large (videos especially), computing the hashes could easily take a day or two. This was partly a matter of the Mac’s processor power, and partly the slow transfer speed of the external HDDs (around 100 MB/s effective over USB 3.0), so things crawled along and only the waiting time piled up.

    And the biggest problem was that no matter how carefully I worked, the fear that “I might accidentally delete a file I need” was always with me. Some of it — like the theater stage photos — can never be recaptured. The one thing I had to avoid was a folder I’d been thinking “I’ll sort it out later” turning out to be the only original. Because of this fear, the time my hands sat frozen grew longer than the time I spent actually working.

    The Day I Vented to an AI

    Then one day, I found myself explaining the situation to Claude. It started as a technical question. Something like “rsync is producing logs like this — how should I read them?” or “what’s a good way to compute hashes?” — about that level, I think.

    But as we talked, it gradually turned into something closer to venting. I’d bought a new Mac for the sake of data migration, yet the migration itself was nowhere near done. Manual work had its limits. None of the existing tools fit my problem exactly. At this rate, I’d never get to my main business of AI development —

    And then it struck me: “Could I actually build a tool to solve a situation like this myself?”

    Of course, there are tools out there that address similar problems, but they inevitably fall short of what I had in mind in some respect.

    Even if a tool could answer “compare files A and B,” it couldn’t address the separate question of “which directories does my data even live in? Is anything being missed?”

    On Mac and Windows alike, when you migrate data, there’s an anxiety around “have I really covered all of it?”

    Your data is made up of system data, libraries, personal-attribute data, the apps themselves, user data, and so on. It would be great if something could guarantee “copy just this directory and you’re absolutely fine; there’s definitely no necessary data stored anywhere else” — but individual apps tend to squirrel away important data in their own separate locations, so this becomes a major challenge too.

    You also need a feature that scans for “where is my data in the first place?”

    Claude’s answer was, roughly, to this effect. Technically, most of it could be done with Python’s standard library. A three-stage approach seemed realistic: first narrow down candidates by file name and size, then compare quickly using partial hashes (a hash of the first few kilobytes of a file), and only take a full hash of the suspicious ones to confirm. The GUI could be built with something like PySide6. There are commercial utilities, but surprisingly few tools go far enough to handle Mac-specific issues (iCloud, purgeable space, invisible files, and so on). So there did seem to be value in building it myself.

    Even hearing that, whether I could actually build it was another matter. After all, I have almost zero programming experience. As I’ve written in earlier blog posts, I washed out on C back in my student days.

    Even so, I felt myself waver just a little. I had, after all, just finished writing the design documents for the seven AI systems through dialogue with Claude in the very same way. Maybe, using that same method, I could this time build a “working app” — or so I thought.

    What I Meant as a “Byproduct” Became the Prelude to the Main Business

    And so the data migration itself went on pause, and development of a tool to assist with data migration began. Thinking about it calmly, this is a pretty absurd story. I’d bought a new Mac in order to get to work on my main business — the seven AI systems — and yet here I was, starting development of a different piece of software as preparatory work for moving data onto that Mac.

    That said — and this may sound like an excuse — within my own mind it wasn’t such a contradictory decision. There were three reasons.

    The first was a calculation: weighing the time to sort everything out by hand against the time to build a tool, the latter might be the lesser evil. Of course, there was a chance I’d stall partway through building it. Even so, since I couldn’t picture a future of continuing the manual work, I figured it was worth the gamble.

    The second was a guess that the problem troubling me is probably troubling others too. Among people who’ve used Macs for over twenty years and juggle multiple storage devices, I surely can’t be the only one. If it came together, it might serve as Soul Resonant Works’ first product — something others could actually use. Before putting out AI-related products, gaining the experience of “seeing a smaller product all the way through to the end” once felt like it wouldn’t be a bad thing.

    The third was that it was just the right scale to serve as practice for the development style called vibe coding. The seven AI systems are each complex, beyond what I could handle on my own. But a data migration tool — if I kept the features focused — might be manageable for one person (plus AI). The idea was that the experience I’d gain here should pay off for my main business of AI development.

    Of course, all of these reasons are after-the-fact rationalizations — “I suppose you could put it that way, in hindsight.” The moment I actually decided to build the tool was, I think, far more impulsive. The ratio was something like eighty percent “I just can’t stand continuing this manual work anymore,” and the remaining twenty percent the logic I laid out above.

    Be that as it may, from this impulsive decision, a tool named DataMigrator began to take shape. And as I’ve written in earlier blog posts, this decision was the beginning of “the main business receding into the distance.”

    Next Time

    Next time, I’ll bring you the story of how I started writing the requirements definition for DataMigrator. Rather than diving straight into code, I began by defining “what to build” in words. I first started writing it using an AI other than Claude, but when I had Claude review it, I was told “the problem is framed in high resolution, but the solution is rough” — and as a result, I ended up revising it five times, from Rev.0 through Rev.5. It’s a story about what it means to have an AI write a requirements definition, and what it means to have an AI shoot down your work over and over.


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://www.sr-works.net/en/

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • Building Two Textbooks with AI — Seven Question Patterns and Four Approaches

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    About This Article

    In my previous article, “Reflecting on DX Talent — Through the Lens of Capability Expansion and a Divergent State”, I touched briefly on my experience of “using AI to build a textbook on a certain industrial device.” At the end of that article I promised, “The seven patterns and the textbook-building method will be introduced in detail in the next blog post.” This article is that promised content.

    This is not a simple how-to. It is an account of the trail of thought I followed and a few discoveries I encountered along the way. The artifacts produced through this work are humble ones, but I would like to share them so you can put them to use as well.

    Why I Started This

    Alongside my work as Soul Resonant Works, I serve in a sales-promotion role at a manufacturer. The job of a sales-promotion role at a manufacturer is to support the sales team and ultimately drive revenue. To sell, you need product knowledge — not only for me in the sales-promotion role, but for the front-line sales team as well, who need that knowledge to do their work. Obviously enough, you cannot sell a product you do not know well.

    Here a practical problem comes up. We handle multiple products, and you cannot become equally deep on every one of them. Especially when working with products somewhat outside my own area of expertise, I was on the side of “I do not really understand this.” Customer environments also vary, so we need to deliver appropriate knowledge transfer matched to each situation.

    Naturally, training material has been prepared, but whether it covers everything is — unfortunately — not always the case. Manufacturers tend to dive into the specifications of their own products, but a perspective on “how it looks in the customer’s environment” is also necessary, and whether that is properly reflected in the material is, in many cases, not really so.

    Product knowledge also extends beyond a single product in isolation. Understanding the historical evolution and the background of why a product takes the form it does is part of the picture. Yet items that experts treat as “obvious” are often the items not written down anywhere.

    The most straightforward way to obtain that kind of background information is to ask a domain expert inside the company, and you can in fact go ask them. But experts tend to be busy people. The more “naive beginner” your question is, the more hesitant you become about taking up their valuable time. The reservation that says “is it really okay to take a busy person’s time with such a low-level question?” was, in effect, narrowing my own learning opportunities.

    So I decided to at least learn and understand on my own as much as I could, by leaning on AI. The AI does occasionally tell me “let’s stop here,” but in general you do not need to hold back with AI. You can ask any question, as many times as you want, no matter how basic. That was the starting point.

    Briefly Recapping the Earlier Story

    For readers who have not read the previous article, here is a short recap up to this point. If you have already read it, feel free to skip to the next section.

    For a certain industrial device, I repeatedly questioned an AI called Copilot. I would throw out a naive question, get an answer, and pile on another question — doing this dozens of times. Then I had the thought of using a different AI (Claude) to “summarize this conversation log into a textbook.” When I tried it, content in textbook form was finished in about two days.

    I shared the finished textbook with a colleague at work, and they came back with the question, “Do you think this textbook-building approach could be extended to other products?”

    This was not a work request to me; it was an exploratory question from a colleague who also uses AI. Receiving that question, I started to abstract the trajectory I had followed and to think about whether the same thing could be done with another similar product.

    From there — the abstraction work, the trial and error of horizontal extension, and the eventual completion of a second textbook — is what this article will go into in detail.

    What This Article Covers

    The article is structured in three chapters.

    Chapter 1, “Taking on the Textbook,” covers how I built the first textbook (the textbook on a certain industrial device). It includes the story of repeatedly asking Copilot questions, the story of having Claude turn the result into a textbook, and the story of trying cross-review between AIs and seeing the limits that emerged.

    Chapter 2, “Methodology,” is about abstracting that experience into a reproducible procedure. This is where the “seven patterns” and the “four approaches” are found.

    Chapter 3, “Horizontal Extension,” is about applying the procedure to a different product, hitting a dead end, and the moment of swapping roles to break out of it.

    I will close by introducing four companion materials (the question template, the workflow prompt, the HTML templates, and a sample Smartphone Edition Textbook actually built using this question template) before wrapping up.


    Chapter 1: Taking on the Textbook

    Repeating Question-and-Answer with Copilot Dozens of Times

    The first thing I did was repeated question-and-answer with Microsoft’s Copilot about a certain industrial device (which I will refer to as “Product X” from here on).

    The very first question was something extremely basic: “What is Product X? Why does it exist?” Reading Copilot’s reply, I would throw out the next question. “Then how does it differ from Product Y?” “What internal components is it made of?” “If you were to compare it to something familiar, what would it be?” — a process of probing the contour of Product X from many directions.

    I repeated this dozens of times. Starting from the definition of Product X, then moving to contrast, coexistence, internal structure, selection criteria, and operational application — I posed questions from every angle, received answers, and posed more questions. The conversation log eventually reached about 30,000 characters in volume.

    By that point, my own understanding of Product X was reasonably well-organized. The very act of asking questions is the act of putting into words what you do not yet understand. It felt less like the AI had taught me, and more like I had drawn the contour of my own understanding using the AI as an interlocutor.

    Handing the Conversation Log to Claude and Asking for a Textbook

    The questions I had been repeatedly asking covered things I did not understand. To someone who knows it, it is utterly basic content; to someone who does not, it is unknown content. Reasoning that there must be others, beside me, who do not know it, I judged it best to write it up properly. If it is in writing, you can refer back to it later, and stored somewhere shared, AI tools can find it — that is the kind of era we are entering.

    Beyond just organizing it, since there was a capable AI right there, I decided to give it some textbook-quality presentation. The intention was modest: if you are going to look at it, prettier is better. A plain text file is hard to read; nicer formatting is just better.

    I only realized later that the conversation log had reached about 30,000 characters. By having the AI ingest the entire vast log, I figured it could trim out the unnecessary parts — the parts where I was repeating the same question because I did not understand the first time around — and leave only the necessary content. It was a leap, but I asked Claude to “build a textbook on Product X based on this conversation log.”

    Side note: the work of obtaining that 30,000-character conversation log was unexpectedly primitive. The Windows desktop version of Copilot did not have a feature to export the entire conversation log, and even scrolling through the screen and copy-pasting did not let me capture the whole thing in one go. I ended up accessing the web version of Copilot and scrolling-and-copy-pasting from there. While we were calling this “cutting-edge AI work,” part of the reality was supported by this kind of unglamorous manual labor — that is something worth recording.

    There was one decision I made here. I specified HTML as the output format for the textbook. From past experience, Claude prefers to recommend Markdown by default, but if you send a Markdown file to a colleague, you are guaranteed to get a “How do I open this?” reply. With HTML, they can simply open it in a browser, which lowers the friction of sharing. A small choice, but it had a big effect on later sharing.

    From the moment I asked Claude for the textbook to the moment an HTML file in textbook form arrived in my hands, almost no time passed. Counting from the day I started the question-and-answer session, two days. The first version was complete by the day after I started. Of course, I was not working on it the entire time — I would give an instruction, leave it, come back, check the result, give the next instruction, leave it again — so my actual time invested was minimal. The speed of AI-assisted content generation is, frankly, astonishing.

    Reading It Through Myself, Finding Discrepancies, and Asking for Fixes

    That said, the completion of the first version was not the end but the beginning. I read through the finished textbook, finding spots that felt off, and asked Claude to fix them, again and again.

    Claude writes massive amounts of text in a flash, but the speed at which I, the human, can review it was slow — painfully slow. Even in collaboration with AI, I was completely the slow link in the chain. If you do not care about content quality, just letting AI do everything is by far the fastest path nowadays. But because I take responsibility for the writing — and because it would be a problem if it diverged from what I actually wanted to express — my checking is, however limited, essential.

    In retrospect, far more of the correction work went into appearance (layout, fonts, spacing, callout-box presentation) than into content. AI is good at consistency-of-text and contextual judgment, but weak at visual judgment. “The space above this heading is too wide,” “the color of this callout box does not match the chapter’s tone” — those kinds of remarks could only come from a human. Because the initial question-and-answer had been thorough, the content was already substantial, so it might have been fine to ignore the appearance. But since Claude had gone to the trouble of producing a clean HTML layout, having parts that looked off would feel disappointing — so I kept pointing them out.

    Cross-Review by a Second AI: Discovery and Limits

    From here, I started a new experiment. Having a second AI — Copilot — review the finished textbook.

    I could have had Claude review what Claude itself had written, but the underlying model would be the same, so I figured I would gain more multi-faceted feedback by using Copilot, which has a different perspective (a different AI model) underneath.

    Reading the textbook Claude had written, Copilot returned concrete remarks like “the explanation in this chapter requires factual verification” and “the definition of this term may differ from the standard definition in the field.”

    This was a fairly significant discovery. Cross-review by an AI of a different lineage can be an effective means of raising quality in AI-assisted writing — that is the moment I became convinced of it. I would feed Copilot’s review comments back to Claude, ask for revisions, and run it past Copilot again — a cycle.

    That said, this had its limits, too. Copilot is good at “factual remarks,” but as you might expect, it is weak at remarks that involve the reader’s experience, like “this is hard to follow for a reader” or “the order of explanation here would land better if you swapped these two.” Cross-review can rescue “factual accuracy”; “readability” is a separate problem.

    A Human Makes the Final Call

    After several rounds of cross-review, I raised the quality further by pointing out the disconnects I, the human, was feeling.

    That the final judgment is made by a human can be read as showing the limits of current AI use, but it can also be read as showing room where humans can still play a role. I lean toward the latter view. AI writes, AI reviews, and at the end a human reads through and finishes it — this workflow seems, as a division of labor between human and AI, to land in a comfortable place.

    In this way, the textbook on a certain industrial device (Product X), about 3,256 lines and 190 KB as an HTML file, was completed.

    This wraps up Chapter 1, “Taking on the Textbook.” The next chapter, Chapter 2, moves on to abstracting the experience into a methodology. At the very end of the article, I will share, as companion materials, both the workflow itself and the reference deliverable actually built with that workflow. The aim is not “read and done,” but reaching a state where you, the reader, can do the same in your own domain.


    Chapter 2: Methodology

    Abstracting the Habits of My Own Questions Revealed Seven Patterns

    The Product X textbook was complete, and I shared it with a colleague at work. As I wrote at the start, through that sharing came the question, “Do you think this textbook-building approach could be extended to other products?”

    I caught that question as a seed of insight. “If it can be done, then I should be able to abstract the trajectory I followed into steps that would work for other products,” I thought. Nobody had asked me to do anything; I just started thinking about the method on my own and started a discussion with Claude on my own. Fully self-driving mode. The colleague could have done it themselves, but I had already boarded the ship, and I was in a state where “AI capability expansion lets me actually do this myself,” so I took it on.

    The first thing I did was have Claude read the questions I had thrown at Copilot during my Product X learning, and analyze them. “What patterns are in these questions? Abstract them in a product-independent way,” I asked.

    Claude found about seven “patterns” in my questions.

    The first is “What is X?” — the pattern of asking the identity of the subject.

    The second is “How does X differ from Y?” — the pattern of understanding through contrast.

    The third is “Are X and Y compatible, or competing?” — the pattern of asking the relationship.

    The fourth is “What does the inside of X look like?” — the pattern of decomposing structure.

    The fifth is “What are the criteria for choosing X?” — the pattern of asking the practical sense of selection.

    The sixth is “In what kinds of work is X used?” — the pattern of asking applied context.

    The seventh is “If you compared X to something familiar, what would it be?” — the pattern of bridging through analogy.

    These seven, Claude pointed out, are the cognitive paths a beginner almost always travels when trying to understand an unfamiliar product. If I had thrown 28 questions at Product X, abstracting those 28 would always map onto one of these seven patterns — that was the analysis Claude gave me.

    This was a small discovery. It was the moment of noticing that “the path I had been unconsciously following had a structure.”

    Why Approaches ① and ④ Were Cultivated as Separate Things

    Once the seven patterns were found, I threw the next question at Claude: “Using these seven patterns, what kind of workflow could be set up to build textbooks on other products in the same way?”

    Claude proposed four approaches.

    • Approach ① is the Expert-Interview type. Hand a product expert a question sheet structured along the seven patterns, have them answer it, and have Claude turn the answers into a textbook.
    • Approach ② is the Self-Q&A type. The learner themselves frames questions along the seven patterns, researches, and answers their own questions.
    • Approach ③ is the Contrast-Learning type. Use a similar product the learner already knows as the main axis, and learn by filling in the differences.
    • Approach ④ is the Fully-AI type. Have AI read the product’s catalog and specifications, have AI itself drive a question-and-answer loop based on the seven patterns, and have a different AI turn the result into a textbook.

    Of these, I decided to adopt Approach ① and Approach ④. Approaches ② (Self-Q&A) and ③ (Contrast-Learning) were set aside this time, because in cases like mine — where I am learning the target product as a beginner — I do not have the answers at hand to begin with. Depending on the situation, they could still be effective options. Claude’s reasoning for the proposal was interesting. “① and ④ serve different purposes, so they weaken if mixed. They are better built separately.”

    Approach ① is an interview sheet designed on the assumption that humans will read it. It is a document for taking to an expert and saying, “When you have time, please answer along these seven patterns.” Approach ④ is a prompt set that, when given to an AI, automatically launches the textbook-creation workflow. The reader is the AI; it is not designed for human reading.

    Combining the two into one document would make it redundant for both humans and AI. So they should be separated and finished as distinct things — that was Claude’s proposal. I was convinced by the design rationale, and prepared the two separately.

    These would later become the first and second of the companion materials I will share at the end of this article.

    That covers the entirety of the Methodology chapter. It is the shortest chapter, but for me it was a small turning-point — the chapter where I came to “have a reproducible procedure.”


    Chapter 3: Horizontal Extension

    Both Approach ① and Approach ④ Hit Dead Ends

    Having extracted the methodology, I decided to try the same thing with a different similar product (which I will refer to as “the other product” from here on). From here, however, a new round of trial and error began.

    First, Approach ① (the Expert-Interview type) was unworkable from the start. It is not that there are no internal experts on the other product, but a person whose time I could secure for an interview as a personal project of mine — that I could not find quickly. Approach ① requires a human expert; it does not function in a situation where you cannot easily access an expert.

    So I tried Approach ④ (the Fully-AI type). The plan was to have Claude read the catalog and specifications of the other product, and run the seven-pattern Q&A loop automatically.

    This too hit a dead end almost immediately. A bit of thought makes it obvious: Claude can only answer within the scope of what is written in the catalog, and a great many “things not written in the catalog but important on the ground” came up. To questions like “In what kinds of work is this product typically used?” or “What do you look at when selecting?”, Claude would reply, “There is no description in the catalog” or “Additional information is needed on this point.”

    As the questions piled up, Claude began turning them around and asking me “tell me about this.” I could answer almost none of them. I am not an expert on the other product. When I launched Approach ④, I had not implicitly positioned myself as the knowledge source — but somehow that was the structure that had emerged.

    I had ended up in a state where neither Approach ① nor Approach ④ was usable.

    Swapping Roles

    Here, I changed direction.

    I handed Claude the prompt for Approach ① — the Expert-Interview type — and asked, “Use this prompt and act as the interviewer in my place. Build a question sheet about the other product.”

    Approach ① was originally designed as a sheet that a human reads and uses. The structure assumed a human interviewer asking the questions of an expert. I was repurposing it as “let an AI read it, and let an AI build the question sheet.”

    At this point, Claude initially started to say, “So you are the knowledge source, and I will throw questions at you as the interviewer.” I replied, “No, the other way around.” When I learned about Product X, I was not the knowledge source; I was on the side asking questions as a beginner. My original role was that of “reader’s representative.” What I wanted Claude to do was the role I had played — “to ask sharp questions on behalf of the reader.”

    Of course, since Claude is a capable AI, once you specify a product, generating questions about it is trivial; the interview pattern was prepared, so all that remained was to inject questions along that pattern. With this redefinition of roles, Claude generated 30 to 50 questions about the other product as a question sheet.

    Next, I handed Claude’s question sheet to Copilot. The instruction was “as an expert on the other product, please answer these questions in detail.” Copilot produced answers immediately, but here a problem came up.

    Copilot showed a tendency to retreat into summaries. The answers came back as 2 to 3 line summaries, far from “detailed explanations suitable as textbook content.” This would not work as textbook material.

    There is a backstory here. When I built the Product X textbook, I ran 1-question-1-answer Q&A with Copilot. I would throw one question, read the answer, and throw the next question — that flow. In that case, Copilot returned solid, well-considered answers to each individual question. In the horizontal-extension case, however, I handed Copilot Claude’s 30-50 question sheet all at once. Copilot must have applied some kind of context adjustment, and the answers got compressed into summaries.

    I asked, “Please go into more detail here,” but it kept returning at an overview level. I imagine it was returning answers under the constraints of session length and how much context it could handle, but this was not going to produce content I could be satisfied with. When I explicitly demanded “do not summarize; please describe in full text, not at the overview level,” only then did deeper writing finally come out. Suppressing the retreat-into-summary required strong prompting from my side.

    The first round of answers I finally obtained was thinner than I had hoped. Tallied up, it was about 17,700 characters — well short of the 30,000 characters of the Product X version. To identify the problem questions, I had the response measured for character count per question. I found about 13 thin questions, each handled in around 400 characters on average.

    For those 13 questions, I asked Copilot to dig deeper and give detailed answers. The result was deeper writing for those 13. Combining the additional answers from this second round with the first round, the final answer log reached about 40,000 characters. A density beyond the 30,000 of the Product X version. For a target like a measurement device (= in the case of the other product), where physical principles, materials, and piping design carry a lot of weight, thicker description was needed — that came out clearly in the character count.

    I then had Claude ingest this Copilot detailed-answer log and instructed it to build the textbook. Procedurally, this is the same as the “Handing the Conversation Log to Claude and Asking for a Textbook” step in Chapter 1. The only difference is that the one driving the Q&A with Copilot was Claude, not me.

    Rather than letting one AI do everything, dividing roles among multiple AIs of different characters and stitching them together to drive the overall workflow produced content with greater depth.

    What this approach revealed is one example of an answer to “in scenes where the human is not the knowledge source, what role should the human play?” I was not an expert on the other product. But I had a small but distinct role: “I have the seven patterns,” “I can ask Claude to play the interviewer,” “I can ask Copilot to play the expert,” “I can bridge between the two.” Even a non-expert human can engage with a domain in this way — that became visible through horizontal extension.

    The Second Textbook Was Completed

    I had Claude ingest the Copilot detailed-answer log of about 40,000 characters and produced the textbook for the other product, inheriting the same format as the Product X textbook (binding, chapter structure, callout style). Visually, it came out looking like a sister volume.

    The final version is an HTML file of about 2,614 lines and 184 KB. The Product X version was about 3,256 lines and 190 KB, so the line count is a bit lower, but the density is higher.

    If I had had more time, I would have put the content through more review rounds and added more questions. But from the standpoint of “responding to a colleague’s question,” I had reached a form where I could report back, “I extended it horizontally!!”, so I called the work done at this point.

    Internally, this was “the moment reproducibility was confirmed.” What had worked for one product worked for another. The procedure was not exactly identical, and the role-swap improvisation was needed, but the core methodology applied to the other product as well — that was confirmed.


    Closing

    What This Article Provides — A Workflow and Its Deliverable

    So far I have written about the trial and error I went through, and the workflow extracted from it. The companion materials I will share at the end are both the workflow itself (the question template, the prompt design, the HTML templates) and a deliverable actually produced using that workflow (a Smartphone Edition Textbook).

    Sharing only the workflow would likely leave you wondering, “OK, but what can I actually build with this?” Sharing only the deliverable would likely prompt, “Impressive — but how was it made?” By delivering both together, I aim for a state where you, the reader, can do the same yourself.

    Looking Back — What Became Visible Through This Experience

    Above, I have walked through everything I did. To close, let me leave just three things that became visible across this whole experience.

    The first is that there is a “pattern” to how you pose questions to AI. Many readers may already be reasonably familiar with this idea, but trying once to analyze your own question set and extract the patterns reveals frames of thought you had been using unconsciously. I felt this connects directly to raising AI literacy.

    The second is that combining different AI models has its own meaning. Cross-review between the same model may not work as well; combining AIs of different lineages enables review, reinforcement, and division of labor. As incorporating AI into work is expected to become more widespread going forward, an “have one AI do everything” mindset alone may run into limits. The literacy of using multiple AIs in combination feels like it will become important from here on.

    The third is that even non-experts have room to enter a specialized domain through AI. I was not an expert on the other product. Even so, I was able to build a textbook on the other product. The notion that “precisely because you are not an expert, you can play the role of asking sharp questions on behalf of the reader” is a small but positive discovery for someone like me — close to the customer in a manufacturer’s sales-promotion role.

    These three discoveries will be delivered, through the companion materials at the end of this article (the question template, the prompt design, the HTML templates, and the reference deliverable), in a form you can put into practice in your own domain. The aim is not “read and done,” but to reach a state where “starting tomorrow, you can try it yourself.”

    Companion Materials

    Companion Material #1 — The Seven-Pattern General Question Template Set

    This is the seven patterns, expanded into concrete example questions in a product-independent form. Distributed in Markdown. When you take on a new domain to learn, rewriting this template to match your own subject helps you ask questions efficiently as a beginner.

    Three Ways to Use the Seven-Pattern General Question Template Set

    There are three ways to use the seven-pattern template set.

    A) You yourself answer as the expert

    For a domain you are well-versed in, use the question template from Companion Material #1 to interview yourself, and have Claude turn the answer log into a textbook. Effective when you want to systematize your own expertise.

    B) You interview an expert

    If you are not an expert but have one nearby, hand Companion Material #1 to the expert, conduct an interview, and have Claude turn the answers into a textbook. Effective when you want to leave an expert’s knowledge as organizational know-how.

    C) Have an AI build a question sheet as a beginner, and have a different AI answer as an expert

    This is the structure of “letting AI represent the beginner” that I did in Chapter 3. Hand the seven-pattern template and the target subject/product to Claude to build a question sheet, hand that to a different AI (Copilot, ChatGPT, etc.) to answer in detail, and finally have Claude turn the result into a textbook. This works when you do not have a knowledgeable person you can casually ask nearby. If you want to minimize effort, this approach is the easiest. You only need to touch the manuscript at the review stage afterward, so this feels like the most modern way to use it.

    A Sample Reference for Use Case C — Smartphone as the Subject

    As an example of Use Case C actually carried out, I had Claude build a question sheet on “smartphones” and also had Claude answer it, and the result was a Smartphone Edition Textbook of about 150,000 characters across 14 chapters. The actual artifact is shared at the end of this article as Companion Material #4, so please take a look if you’re interested.

    Here, I will introduce the workflow concept along with the actual prompts.

    Step 1: Have Claude build a question sheet

    The prompt I gave Claude to build the question sheet was something like the following:

    The attached format is a general-purpose format for asking questions about
    some particular subject. The questions in this format are classified into
    seven patterns. Using "smartphone" as the subject, please devise
    questions along this format's patterns. Please devise many questions a
    beginner who does not know smartphones would need in order to understand
    smartphones correctly and in depth.
    
    Please output as a code block.

    The first question sheet Claude generated in response to this prompt contained about 45 questions.

    Step 2: Have Claude itself evaluate whether the question sheet is sufficient (the heart of this workflow)

    This is the key step in this workflow. Rather than handing the generated question sheet straight to the answering step, you first have Claude itself assess whether it is enough.

    Specifically, I asked:

    Is this number of questions sufficient to build a textbook from which a
    beginner can adequately grasp the overview and reach proper understanding?

    Claude answered candidly: “Sufficient to grasp the overview, but as a textbook for ‘correctly and in detail,’ it is insufficient.” Specifically, the analysis was that areas such as communication and networks, security and privacy, the world of apps, the variety of input/output, troubleshooting and maintenance, and location and payment were thin.

    Receiving that analysis, I asked Claude to fully reinforce the missing areas, and the question sheet was expanded from 45 to 108 questions. A 2.4× increase in question count, with the chapter structure also rebuilt. Through this process, in addition to the original seven patterns, an ⑧ Security & Privacy pattern was newly added, becoming an opportunity for the template itself to grow.

    If you proceed with the question sheet as initially generated, the content density of the textbook caps out there. On the other hand, by having the AI self-evaluate and then expand, gaps you didn’t see initially become clearly visible, and the overall depth of the textbook shifts dramatically. Running the cycle of “initial generation → self-evaluation → expansion” at least once is, in my experience, the key to making this workflow practically useful.

    Step 3: Have Claude answer the questions

    Hand the expanded 108-question sheet to Claude and have it produce the answers. The prompt I gave Claude to produce the answers was something like the following:

    The attached file is a set of questions a beginner who does not know
    "smartphones" would have when learning about smartphones themselves.
    Please answer each of these questions. To support accurate understanding
    of each question, please describe in full text, in detail, without
    summarizing and not at the overview level.
    
    Please output as a code block.

    Originally I had planned to have Copilot produce the answers, but the question count seems to have been too large — Copilot exceeded its limits and could not produce a satisfactory response. As a result, I had to have Claude produce the answers as well.

    Step 4: Hand the answers back to Claude and have it written out in Parts

    Have Claude ingest Claude’s answers and produce the textbook body. Because this case was on the scale of 108 questions across 14 chapters, it could not fit within a single session, and Claude proposed an approach of splitting the output into multiple artifacts.

    In the end, the 108 questions were split into 5 Parts (Part 1 to Part 5), and we proceeded by writing out from Part 1 in order. Each Part is roughly 50,000 characters, around 180 KB.

    Step 5: Carry across sessions using a per-Part handover prompt

    After completing the writeout of each Part, I had Claude generate a “handover prompt for the next session,” which was used as the first message of the next session. The handover prompt includes the project background, the structure of all 108 questions, the writing policy, the completed Parts, and the list of questions to be tackled in the next Part. With this, even when the work spanned multiple sessions, style, density, and progress carried over without breaking down.

    Step 6: Pour the Parts into the HTML template to produce the textbook

    Once all five Parts were ready, I picked one HTML template from Companion Material #3 that matched the desired atmosphere, had Claude ingest it together with the .md files of the Parts, and issued a request like the following. Companion Material #3 contains six template styles (Japanese binding, minimal, notebook, dark, editorial design, cyberpunk), so please choose one that fits the textbook’s theme and target readership.

    The attached template is a textbook-format template.
    Please pour the "textbook content derived from questions and answers"
    in the project knowledge into this HTML format, and output as HTML.
    The targeted contents are the following five files:
    - Part 1 .md file
    - Part 2 .md file
    - Part 3 .md file
    - Part 4 .md file
    - Part 5 .md file
    The presentation is already in place, so the work should be limited
    to dropping in the headings and body text. CSS is also embedded;
    please make use of it to produce the final HTML.
    Because the volume is large, please prepare anchors for each item
    in the table of contents, and "back to TOC" links at each section break.

    This produces the first version of the HTML.

    Step 7: Debugging and decontextualization

    When you read through the first HTML version, you find a few spots that need fixing. In this case, dragged in by the context of when the answers were generated, certain proper nouns and industrial-domain terms had slipped into the body of the smartphone textbook. These were addressed as a separate task to decontextualize (generalize) the content. This kind of debugging is worth budgeting for as a necessary final-stage step.


    That covers the concept of the actual Use Case C process. Companion Material #4 (the Smartphone Edition Textbook), shared at the end of this article, is the deliverable actually produced through this workflow. I hope you’ll see it as proof that “this much can actually be built, in this kind of process.”

    Companion Material #2 — Workflow Design Prompt for Claude

    This is the prompt set I described in Chapter 2 as “Approach ④” — when given to an AI, it automatically launches the textbook-creation workflow. In Markdown, structured into four phases (Discovery / Structuring / Drafting / Refinement). Hand it to Claude, and through dialogue it will get a textbook draft started.

    Companion Material #3 — HTML Templates for the Textbook Format (6 styles + a template-generator)

    Six HTML templates with different bindings for use when building textbooks (Japanese binding, minimal, notebook, dark, editorial design, cyberpunk), plus one prompt scaffold for generating additional patterns: template_custom_prompt.md.

    There were originally five HTML templates. To verify that the prompt scaffold for generating additional patterns actually worked, I tried having it generate a “cyberpunk-style” template, and it came out as expected. The set is now six templates.

    How to Use Companion Material #3

    There are two ways to use Companion Material #3.

    (1) When you want to generate an additional template style

    Have Claude read the included template_custom_prompt.md, then issue a request like:

    Referring to template_custom_prompt.md,
    please generate a template in 〇〇 style.

    In the “〇〇 style” portion, write the atmosphere you want (e.g., “picture-book style,” “newspaper style,” “academic-paper style”). It may also work with AIs other than Claude (ChatGPT, Copilot, Gemini, etc.), but with no guarantee.

    (2) When you want to pour textbook content into a template and produce the final HTML

    Have AI read both the textbook content (the body text derived from the questions and answers) and the HTML template file from Companion Material #3 at the same time, and issue a request like:

    The attached 

    These prompts are starting-point examples; please adjust the details to match your own subject, chapter structure, and content volume. If you say “could you do it more like this” within the AI dialogue, it will, in most cases, accommodate.

    Companion Material #4 — Reference Deliverable: Smartphone Edition Textbook

    As an example of a deliverable actually produced by applying the workflow described in this article, I am also delivering “Smartphone — A Beginner’s Introduction: 108 Questions Untangled” (14 chapters, about 150,000 characters).

    This is the very textbook that was actually built using Companion Materials #1 and #3. If, while reading this article, you find yourself wondering, “OK, what does the result actually look like?”, please take a look at this. It serves both as proof that “this much can actually be built using the methodology in this article” and as a piece of reading material in its own right.

    A note: due to the author’s background of long involvement in instrumentation work, parts of the body include comparisons and analogies with PLCs and industrial equipment. Reading it as an “introduction to how smartphones work” may make a few spots feel slightly out of context — please be aware of this in advance.

    Terms of Use for the Companion Materials

    Please feel free to use Companion Materials #1 through #4 under the following conditions.

    What you can do

    • Use them freely for your own work, learning, in-organization education, and the like
    • Freely modify the contents to suit your own subject
    • If you build your own textbook or document using these materials and publish or sell it, please include a “Powered by SRW” credit on the final page or similar

    What we ask you to refrain from

    • Please refrain from redistributing the companion materials themselves as is (or in substantially similar form) to third parties, or selling them as a paid product
    • The materials shared in this article reflect the trial and error of the entire chain of work, including the article itself. The reason we ask you to refrain from redistribution and resale is to ensure that this accumulated effort is treated appropriately

    What would make us happy

    • If, on the final page of a textbook or document you build using these materials, you leave a small “Powered by SRW” signature, a link to this article, or an SRW introduction blurb, the person inside (= me) would be quietly delighted

    Download the Companion Materials Here

    After reviewing the terms of use, you can download the full set from the page below.

    Companion Materials Package INDEX

    The INDEX page provides links to each file (#1 through #4) and their respective version information.

    Note: The companion materials are currently available in Japanese only. An English version is not provided at this time.

    What’s Coming Next

    Across these two articles (SP05 and SP06), I have written about building textbooks with AI. If the workflow set and the reference deliverable I have shared as companion materials connect to something for the readers who took the time, I would be glad.

    That said, looking back, the six articles from SP01 to here have all been about not the main business of SRW, but byproducts that emerged on the way to the main business. The next thing I plan to write about — DataMigrator — is also a byproduct, not the main business. It seems some more sorting out of byproducts is needed before I can reach the main business itself.

    From the next article, I will move into the development record of the first product I started under SRW: DataMigrator. The story is set to begin with “I vented to AI about data-migration hell, and that lit the fire.”


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems. Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://www.sr-works.net/en/

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • Production Deployment — The .htaccess Trap and the Moment of Going Live

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    In the previous post (SP03), I wrote about completing the translation and structural unification of 16 files. Everything was running perfectly in my local development environment. All that was left was to just upload it to the production server.

    “Just upload it.” These words may be the most dangerous in the world of development.

    Pre-Deployment Status Check — Better to Be Overly Cautious

    Session 16, the beginning of the project’s final session. 1:10 AM.

    First, I had Claude Code run a seven-item status check. Git status, recent commit history, file listings and sizes for both English and Japanese versions. After confirming everything was as expected, I prepared the deployment file list.

    Eight English files, about 257 KB; eight Japanese files, about 259 KB. 16 files total, about 505 KB. I also explicitly listed files excluded from deployment (journals, archived older versions, .DS_Store files, etc.).

    The value of writing out the “exclusion list” wasn’t clear to me until I actually did it. Rather than the risk of missing uploads, the scarier risk is accidentally uploading extra files like .DS_Store (metadata files macOS creates without asking). Having a list in advance helps prevent the accident of “oops, select all” on the FTP file manager screen.

    FTP Upload — This Part Is Human Work

    I opened the file manager on Star Rental Server, and created new /en/ and /ja/ directories. Then I uploaded the 16 files to their respective directories.

    This is manual work by a human (me). I had wanted to deploy directly from Claude Code, but I couldn’t get FTP authentication automated. I couldn’t find a way to route the Star Rental Server FTP connection through Claude Code, and ended up manually uploading via the browser-based file manager. This remains a task for the future.

    The upload itself finished in a few minutes. The problem came next.

    The .htaccess Trap — The Infinite Redirect Loop

    After the upload finished, I accessed the root URL sr-works.net) in the browser.

    “Too many redirects.”

    The browser halted with an error. All pages unreachable. Immediately after going live, the entire site became inaccessible.

    The cause was the configuration in the .htaccess file. I had written Redirect permanent / /ja/index.html as the setting to redirect visitors to the root URL /) to the Japanese top page /ja/index.html) — but this was causing an infinite loop.

    Redirect permanent performs a prefix match on the path. In other words, it matches every URL starting with /. Since the redirect target /ja/index.html also starts with /, it triggers the redirect as well, which redirects to /ja/index.html again, which matches / again — infinite loop.

    The solution was to rewrite it as RewriteRule ^$ /ja/index.html [R=301,L]. ^$ is an exact match for the empty string, meaning it only matches the root path itself and does not re-match /ja/index.html. Both Claude.ai chat and Claude Code proposed the same solution, so the fix was quick.

    Engineers might think, “Isn’t that basic knowledge?” And I agree. But when someone with no programming experience builds a site collaborating with AI, you regularly step on this kind of “obvious” landmine. And since .htaccess behavior is hard to test in a local environment, it’s the kind of problem that only reveals itself in production.

    The Iron Rule of Deployment Order — Delete the Old Last

    Another thing I realized through this deployment is the importance of “leaving the deletion of old files for the very end.”

    Directly at the root of the server, old HTML files from before the directory restructuring still remained. Once I had uploaded the new /ja/ and /en/ files, I was tempted to immediately delete the old files, but I intentionally left them in place.

    This decision paid off. When the .htaccess redirect loop occurred, because the old files still existed, I could still access the old site by hitting URLs directly. If I had deleted the old files first, I would not have been able to verify any site contents during the redirect loop.

    The “five-stage deployment order” established through this project is as follows.

    (1) Pre-status check. (2) Create the deployment target list. (3) Upload new files. (4) Switch configuration + verify. (5) Delete old files.

    By leaving (5) for the end in particular, you maintain a safety net for problems discovered in (4). The sequence “add new → switch → verify → delete old” is something I plan to adopt as a general protocol for static site production deployments in future projects.

    All 16 Pages, Zero Broken Links

    After fixing .htaccess, I verified operation in the production environment. Navigation links, language switching, transitions to the contact form, mobile hamburger menu, footer links, AI translation disclaimer display. All pages normal across these six verification points.

    Additionally, Claude.ai chat used web_fetch to sequentially retrieve all 16 pages and exhaustively check internal, external, and mutual links. Zero broken links.

    Past 2 AM. I deleted the old files, restructured the public layout to just the two directories /en/ and /ja/, and declared the project complete.

    Looking Back on 6 Days and 16 Sessions

    The HP English translation project was completed in 16 sessions across six days, from April 13 to 18, 2026. Newly creating 8 English files, modifying 8 Japanese files, unifying the navigation structure, 212 link-path modifications, and the production deployment.

    Starting from discovering simultaneous HTML tail damage in three files on day one, and ending with facing the .htaccess infinite redirect loop on the final day. From start to finish, it was a project about continuously fixing things made by AI, together with AI.

    The biggest feature of this project was that the four parties — Claude Code, Claude.ai chat, Microsoft Copilot, and the human (me) — coordinated with clear role divisions. In the DM series and UC series, the structure was “1 human + 1 AI,” but in the HP English translation, I combined multiple AIs for the first time into a coordinated structure that leveraged each one’s strengths.

    From next time, we return to the original timeline and begin the DataMigrator story. A tale of data migration hell from four months ago.

    Also, in the paid section that follows, I’m publishing the mechanism that made it possible to systematically preserve 16 sessions of records — the complete framework of the journaling system, together with the full set of prompts you can copy-paste into your own project. A hearing-based prompt that supports launching new projects is also included.

    Why 16 Sessions Worth of Records Could Be Systematically Preserved — The Journaling Operation Mechanism

    I’ve written three posts so far as SP02 through SP04, and there is a reason these posts could be written at this density. For all 16 sessions of the HP English translation project, detailed journals (work records) were systematically preserved.

    It’s easy to say “Let’s keep a project record,” but it’s remarkably difficult to actually keep doing it. Especially when development enters critical phases, the feeling of “If I have time to write a journal, I’d rather write code” tends to win, and records fall off.

    In the HP English translation project, 2,408 lines on the Code side and 5,223 lines on the Chat side — 7,631 lines total — of journals remained across 17 files. Here, I’ll share how this wasn’t accidental but the result of a mechanism.

    A Three-Layer Journaling System

    The mechanism for journal creation is composed of three layers.

    First, the generation of a “specialization layer.” At the very first session of the project, five elements specific to that project — the roles of the AI agents and humans involved, project-specific terms and abbreviations, points of particular note to record, and project-specific stumbling patterns — are extracted and templated. For the HP English translation project, unique concepts like “three-way cross-review system,” “seven IP-protection observation points,” and “Copilot review loop counts” go into the specialization layer.

    Next, using this specialization layer embedded into the general-purpose journaling prompt, a “customized version” is created for each of Claude.ai chat and Claude Code, forming two tracks.

    The Chat customized version is designed to record “why a given instruction was issued,” “how judgments were made,” and “what was not chosen.” Register it in the project knowledge, and at session end, a single instruction like “Please generate a journal” will produce a structured output of the judgment flow from that session.

    The Code customized version is designed to record “what was done.” File operations, grep verifications, commit history, technical tips — recorded in chronological order. This one is saved in the project directory, and similarly generated with a single instruction at session end.

    Synchronizing Chat and Code — The session_id Mechanism

    How do two journals, generated separately by different AIs, get reconciled with each other? The core of this mechanism lies here.

    At the top of each journal, a YAML metadata block is output. Within it, there is a field called session_id, formatted as “project-abbreviation-date-same-day-sequence-number.” For example, srwhpen-20260414-01 means “SRW HP English project, April 14, 2026, the first session of the day.”

    By having both Chat and Code record the same session_id, you can uniquely identify that “this Chat journal and this Code journal are records of the same session.” Someone reading the journals later (future-me or a blog reader) can reconcile the two by session_id to trace both “the reasoning behind a decision” and “the reality of the work.”

    Operational Procedure for Synchronization — Code First, Chat Second

    However, the session_id mechanism alone doesn’t achieve synchronization. The actual operation has a definite order.

    First, create the Code-side journal first. When you instruct Claude Code, it numbers a session_id based on the file operations and commit history executed in that session, and generates the journal. Upon completion, a completion report is displayed on the Code-side screen, including the session_id, a list of main section headings, the number of stumbling items, and so on.

    Next, paste this completion report, along with the body of the generated Code journal, into the Chat side. This is the key to synchronization. The Chat side does not know in advance what Code did or what session_id was numbered. By receiving the Code-side journal, the Chat side can, for the first time, grasp “what Code executed in this session” and “what the session_id is.”

    Then, instruct the Chat side to generate a journal. The Chat side, referencing the Code-side journal and session_id, searches the chat history within the project and summarizes the instructions and judgment flow from that session. Two-viewpoint records, linked by the same session_id — “what Code did” and “what was decided in Chat” — are now complete.

    If you reverse this order (generate the Chat side first), the Chat side will number its own session_id independently without knowing Code’s, and later reconciliation becomes impossible. “Code first, Chat second” is the iron rule.

    An Honest Look at the Distance Between Ideal and Reality

    Ideally, journals would be generated automatically at session end. But at this point that level of automation hasn’t been achieved, and at the end of each session a human has to do the work manually. Specifically: (1) instruct Code to generate the journal, (2) paste the Code completion report and journal body into Chat, and (3) instruct Chat to generate the journal — three steps.

    Even so, because “what to record,” “how to structure the record,” and “how to sync the two tracks” are pre-defined in the prompts, following this procedure produces consistent-quality journals every time. Even though manual coordination is needed, the effort is entirely different from “writing a journal from scratch.”

    Without this mechanism, 16 sessions of records probably would not have been preserved. At the very least, I wouldn’t have had the material to write SP02 through SP04 at this density.

    As a Reproducible Methodology

    This mechanism applies beyond just the HP English translation project, to any project collaborating with AI. What’s required is about 30 minutes of investment to create the specialization layer at the start of the project, plus 10 seconds at each session end to say “Please generate the journal.”

    For anyone who wants to convert vibe coding development records into blog articles, or who wants to look back on their collaboration process with AI later on — I hope this is useful as a reference.

    Below, I’ve included samples of the actual prompts I use. You can copy them and use them as-is.

    [Appendix 1A] Specialization Layer Generation Prompt (For Existing Projects)

    Precondition: The project is already underway, with context accumulated in chat history or project knowledge
    Input target: A chat within the Claude.ai chat project (at the end of the first session)
    Save destination for the generated result: Register as “Specialization Layer” in the Claude.ai chat project knowledge

    # Request for Context Optimization of the Journaling Prompt
    
    Based on the context of this project/session, please create a
    "project specialization layer" for the journaling prompt.
    It will be used as a diff to append to the general-purpose journaling prompt.
    Name the file "Specialization Layer."
    
    ## Five Elements to Output
    
    ### 1. Project-Specific Role Assignment Table
    A list of the AI agents, humans, and external tools involved in this project,
    along with each party's area of responsibility. Concrete descriptions that
    replace the "role assignments" section of the general-purpose version.
    
    ### 2. Points of Particular Note to Record in This Project
    List important events that occurred in this session. To be reused in
    subsequent sessions as observation points for recording events of the same type.
    
    ### 3. This Project's Specific Glossary of Terms and Abbreviations
    Templates for first-time footnote explanations of abbreviations used
    in the journal. Designed so that readers assumed to be beginners can
    understand project-specific concepts.
    
    ### 4. This Project's Characteristic Stumble Types
    Perspectives specific to this project that should be added to the
    general-purpose version's "stumble extraction criteria."
    Examples: for a translation project, "scenes where source and translated
    text structures diverged"; for a website project, "scenes where browser
    rendering differences became a problem."
    
    ### 5. This Project's Specific Sync Metadata Extensions
    Fields specific to this project to add to the general-purpose version's
    sync metadata block.
    Examples: for a translation project, "name of translated file,"
    "whether reviewed"; for a web build, "browser verification performed,"
    "deployed or not."
    
    ## Output Format
    
    Markdown in a form that is "appended to" or "replaces" the corresponding
    section of the general-purpose journaling prompt.
    Please output both a Claude.ai chat version and a Claude Code version.
    
    ## Judgment Criteria
    
    - If project-specific elements are thin, it's fine to answer
      "general-purpose version is sufficient, specialization layer unnecessary"
    - Excessive specialization stiffens the journal, so the judgment point is
      "does this have repeat-record value in subsequent sessions?"

    [Appendix 1B] Specialization Layer Generation Prompt (For New Projects, With Hearing)

    Precondition: The project hasn’t started yet, or has just started with almost no context in chat history. This prompt handles “project discovery → definition → specialization layer generation” in one integrated flow.
    Input target: Create a new Claude.ai chat project and input into the first chat
    Save destination for the generated result: Register as “Specialization Layer” in the Claude.ai chat project knowledge

    # New Project Definition + Journaling Specialization Layer Generation
    
    I'm about to start a new development project.
    First, let's organize the project definition together, then generate the
    "specialization layer" for journal creation.
    
    ## Phase 1: Hearing the Project Definition
    
    For the following items, please ask me one at a time in a dialogue format.
    Don't ask everything at once — proceed one question at a time.
    If my answer is vague, please deepen with concrete examples.
    
    ### Items to Ask About (In Order)
    
    1. Project Purpose
       - What do you want to build? What problem do you want to solve?
       - Do you have a completion image? Or is it still vague?
    
    2. Goal Definition
       - What does "complete" mean? (A working prototype? A production
         release? A finished design document?)
       - Is there a deadline?
    
    3. People and AI Involved
       - How many humans are involved? What's each person's role?
       - Which AI tools are you planning to use? (Claude Code, Claude.ai
         chat, Copilot, others)
       - How much will you delegate to AI? (Code generation, review, design,
         everything?)
    
    4. Technology Stack and Environment
       - What language / framework / hosting will you use?
       - If undecided, "undecided" is fine
       - What's the development machine OS (Mac / Windows / Linux)?
    
    5. How You'll Proceed
       - How often will you work? (Every day? Weekends only?)
       - What's the typical length of one session?
       - Will you use version control like Git?
    
    6. Purpose of Records
       - What do you want to use the journals for?
         (Personal retrospectives? Blog posts? Sharing with a team?)
       - Who's the assumed reader? (Just you? Engineers? Non-engineers?)
    
    ## Phase 2: Generate Project Definition Document
    
    Once the hearing is complete, please compile the answers into a
    "Project Definition Document" in Markdown format.
    This will be registered in project knowledge and referenced by all
    subsequent sessions.
    
    ## Phase 3: Generate the Specialization Layer
    
    Based on the project definition document, please generate a
    "Specialization Layer" containing the following five elements.
    
    1. Project-specific role assignment table
    2. Points of particular note to record in this project
    3. Project-specific glossary of terms and abbreviations
    4. This project's characteristic stumble types
    5. Project-specific sync metadata extensions
    
    Name the file "Specialization Layer."
    
    ## Notes
    
    - Please proceed with the Phase 1 hearing in dialogue format.
      One question at a time, not all at once.
    - I may be a programming beginner.
      Please add footnotes when using technical terms.
    - It's fine if answers like "not decided yet" come up during the hearing.
      In that case, please propose tentative placeholders.
    - If the project scale is small (e.g., a simple personal script),
      feel free to judge "general-purpose version is sufficient,
      specialization layer unnecessary."

    [Appendix 2] Chat Journal Generation Prompt (General-Purpose Version)

    Integration procedure: Create a “customized version” by incorporating the specialization layer generated by Appendix 1 into this general-purpose version, then register it in the Claude.ai chat project knowledge as the “Chat Journal Prompt”
    How to run: At session end, instruct in chat: “Please follow the Chat Journal Prompt in the project knowledge and generate a journal for this session”
    Output destination: Output to chat as an artifact. Download as a file and save locally

    # Claude.ai Chat Journal Creation Request
    
    Please compile "the flow of instructions and judgments" from this session
    into a journal. This will be used later as source material for blog articles.
    
    ## Position of This Journal
    
    This journal complements the implementation-side journal (technical log
    generated by Claude Code or similar), and is responsible for "why that
    instruction was given," "how it was judged," and "what was not chosen."
    Rather than the implementation procedure itself, it records the
    decision-making process between humans and AI behind that procedure.
    
    ## Assumed Reader
    
    A beginner Vibe coder (a non-engineer who doesn't write code directly,
    but progresses development through dialogue with AI agents). Please add
    brief footnotes for technical terms on their first appearance.
    
    ## Sync Metadata Block (Mandatory, Output at the Beginning of the Journal)
    
    ```yaml
    session_id: [project-abbreviation]-[YYYYMMDD]-[same-day-sequence 01, 02...]
    session_start: YYYY-MM-DD HH:MM (JST)
    session_end: YYYY-MM-DD HH:MM (JST)
    project_name: [Project Official Name]
    session_number: [Cumulative session number]
    journal_type: chat
    counterpart_journal:
      type: code
      expected_path: docs/dev-journal.md (corresponding session section)
    related_commits:
      - hash: [commit hash]
        timestamp: YYYY-MM-DD HH:MM
        description: [Brief description]
    key_phases_with_timestamps:
      - phase: [Phase name]
        time_range: HH:MM - HH:MM
        summary: [One-line summary]
    ```
    
    The session_id must match the Claude Code-side journal exactly.
    For multiple sessions on the same day, distinguish by sequence (01, 02...).
    
    ## Structure Template
    
    - Session theme, originally planned scope, actual outcome
    - Role assignment (structure for this project)
    - Chronological log (describe "what happened" and "what decisions were made"
      phase by phase)
    - Summary of stumbling points (situation, essence, learning)
    - Good decisions / operational points
    - Handover to next session
    - Numerical notes for this session (session duration, number of exchanges,
      number of commits, etc.)
    
    ## Writing Style
    
    - Describe failures and stumbles candidly. Lessons are the main content
    - Quote important user remarks in blockquotes
    - Write so that the boundary between AI autonomous decisions and human
      final approvals is visible
    - Also record options that were considered and rejected ("we considered
      an alternative and rejected it")
    - For easy citation when turning into blog articles, include command
      examples and diffs verbatim
    
    ## Stumble Extraction Criteria
    
    Record events meeting any of the following as stumbles:
    - Scenes where unexpected errors / anomalies surfaced
    - Scenes where the human misunderstood a concept
    - Scenes where the human revised or rejected an AI proposal, or vice versa
    - Scenes where literal rule and rule intent diverged, requiring an
      exception judgment
    - Near-misses where "the problem would have expanded if unnoticed"
    
    ## Post-Completion Report
    
    (a) The filename of the created journal
    (b) Total line count
    (c) Number of stumble items extracted
    (d) One to three recommended title suggestions for blog article conversion

    [Appendix 3] Code Journal Generation Prompt (General-Purpose Version)

    Integration procedure: Create a “customized version” by incorporating the specialization layer generated by Appendix 1 into this general-purpose version, and save it in the development project directory as docs/journal-prompt-code.md
    How to run: At session end, instruct in Claude Code: “Following the instructions in docs/journal-prompt-code.md, please append this session’s content to docs/dev-journal.md
    Output destination: Directly appended to the project’s docs/dev-journal.md (existing content preserved, added to the end)

    # Claude Code Journal Creation Request
    
    Please compile what was done and what was stumbled on in this session
    into a journal. It will be used later as source material to be formatted
    and published as a blog article.
    
    ## File Specifications
    
    - Location: Directly under the project root, /docs directory
      (create new if it doesn't exist)
    - Filename: dev-journal.md
    - Operation: Append per session (preserve existing content, add to the end.
      Preserve any project overview at the top)
    - Character encoding: UTF-8
    
    ## Assumed Reader
    
    A beginner Vibe coder (a non-engineer who doesn't write code directly,
    but progresses development through dialogue with AI agents). Please add
    brief footnotes for technical terms on their first appearance.
    
    ## Sync Metadata Block (Mandatory, Output at the Beginning of Each Session Section)
    
    ```yaml
    session_id: [project-abbreviation]-[YYYYMMDD]-[same-day-sequence 01, 02...]
    session_start: YYYY-MM-DD HH:MM (JST)
    session_end: YYYY-MM-DD HH:MM (JST)
    project_name: [Project Official Name]
    session_number: [Cumulative session number]
    journal_type: code
    counterpart_journal:
      type: chat
      expected_path: [Filename of the Claude.ai chat-side journal]
    related_commits:
      - hash: [commit hash]
        timestamp: YYYY-MM-DD HH:MM
        description: [Brief description]
    key_steps_with_timestamps:
      - step: [Step name]
        time_range: HH:MM - HH:MM
        summary: [One-line summary]
    ```
    
    The session_id must match the Claude.ai chat-side journal exactly.
    For multiple sessions on the same day, distinguish by sequence (01, 02...).
    
    ## Structure Template
    
    - Session goal (work originally anticipated)
    - What was actually done (chronological)
    - Stumbles and unplanned discoveries (situation, cause, response, learning)
    - Technical discoveries / tips
    - Reflection on role assignment
    - Handover to next session
    
    ## Writing Style
    
    - Don't hide failures or stumbles; describe candidly
    - Write so that the boundary between AI autonomous decisions and human
      final approvals is visible
    - For easy republishing when turning into blog articles, include code blocks
      and command examples verbatim
    
    ## Stumble Extraction Criteria
    
    Record events meeting any of the following:
    - Scenes where unexpected errors / anomalies surfaced
    - Scenes where there were issues in AI-generated code / content
    - Scenes where literal rule and rule intent diverged, requiring an
      exception judgment
    - Near-misses where "the problem would have expanded if unnoticed"
    - Scenes where the same problem had propagated to other places
    
    ## Post-Completion Report
    
    (a) The file path of the created file
    (b) Total line count
    (c) List of main section headings
    (d) Number of stumble items extracted

    [Summary: How to Use the Appendices]

    Step 1 (Once per project, about 30 minutes): Depending on the project’s situation, use either Appendix 1A or 1B. If the project is already underway and has context, use 1A. If it’s a new project with nothing decided yet, use 1B (with hearing). In the 1B case, the AI will draw out the project definition in dialogue format, so you’re fine even if you’re in a “I don’t know where to start” state. Register the generated specialization layer in the project knowledge.

    Step 2 (Once per project, about 10 minutes): In the same chat, request: “Please incorporate the specialization layer from the project knowledge into the following general-purpose prompt to create a customized version,” and paste Appendix 2. Register the generated customized version in the project knowledge as the “Chat Journal Prompt.”

    Step 3 (Once per project, about 10 minutes): Similarly create a customized version of Appendix 3, and save it in the development project directory as docs/journal-prompt-code.md. Instruct Claude Code: “Please save this file as docs/journal-prompt-code.md.”

    Step 4 (At every session end, about 5 minutes): Proceed in the following order. Order matters.

    (4-1) Code side first. Instruct Claude Code: “Please append a journal following docs/journal-prompt-code.md.” Code numbers a session_id and appends to docs/dev-journal.md. On completion, a completion report (session_id, heading list, number of stumbles, etc.) is displayed on screen.

    (4-2) Bridge from Code to Chat. Paste the Code completion report and the body of the generated journal into the Claude.ai chat. This lets the Chat side know “what Code did” and “what the session_id is.”

    (4-3) Chat side second. Instruct Claude.ai chat: “Please generate a journal.” The Chat side inherits the Code-side session_id, extracts the decision flow from the chat history, and generates a Chat-side journal linked by the same session_id.

    Through this “Code first → bridge → Chat second” order, two-viewpoint records, synced by the same session_id, are completed.

    Next Time

    From next time, we return to the original timeline, and we’ll bring you the DataMigrator series (B01): “Falling into Data Migration Hell While Setting Up for Local AI Development.”

    That was the plan — but I’m still not able to move on to DataMigrator just yet. The next post will be a short detour before we get there.


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems.
    Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://www.sr-works.net/en/

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.

  • Completing the Translation of 16 Files — The Night All the AIs Went Down, and the Completion of the Four-Way Collaboration

    This article was originally written in Japanese and translated into English with AI assistance. Please note that some expressions may carry nuances from the original Japanese.

    🇯🇵 日本語版はこちら / Japanese version


    In the previous post (SP02), I covered the first six sessions of the HP English translation project — the discovery and repair of the footer damage, the establishment of the three-way cross-review system, and the structural solution to procedural mistakes.

    This post covers the second half: translating the remaining four files and carrying the project through to completion. The biggest stumble of the project was waiting in this second half. The night all the AIs went down.

    Taking On a Giant 68 KB File

    In Sessions 7 and 8, I completed the translation of the What’s New page (whats_new.html) and the About page. Three files remained. The biggest wall among them was index.html — the top page.

    This file was 68 KB, three to four times the size of the others. It contained product introductions, a development timeline, a technology stack overview — the content that effectively represents the entire site. It was also the file with the most expressions that required careful handling from an intellectual-property perspective.

    For example, the phrase “six AI systems” appears six times in historical descriptions, while descriptions of the current state say “seven.” The translation needed to preserve this distinction precisely. Past references should say “six systems,” and present references “seven systems.” Mix them up even once, and you give the reader contradictory information.

    Before handing index.html to Claude Code, I first had Claude.ai chat read through it entirely and identify the IP-protection-critical passages in advance. Twelve spots of architecture-design-related terminology, seven spots involving six/seven systems notation. I compiled these into a list and incorporated them into the translation prompt, which prevented Claude Code from accidentally “just making everything seven” across the board.

    Session 9 — The Night All the AIs Went Down

    Session 9 was the most abnormal session of this project. The amount of work done was zero.

    As I wrote in SP02, by this point Copilot was refusing to read files entirely, and was out of action as a reviewer. “If Copilot isn’t available, we’ll just run reviews through Claude Code and Claude.ai chat” — that was the plan.

    But then, even Claude — our fallback — died.

    It was the night I was about to begin translating the product detail page (ai-multilingual-meeting-detail.html). When I sent a status-check prompt to Claude Code, I got back an API 500 error. Retries gave the same. Three failures in a row.

    “If Claude Code is unhealthy, let me switch models,” I thought, and retried after changing settings. Still no good. Even when I shortened the prompt to the absolute minimum — “just return git status” — I got a 500.

    Reluctantly, I shut down Claude Code and restarted it. git status and git log came through. But just as I breathed a sigh of relief, the moment I tried to run a grep command, this time I got an auth error (401).

    “Maybe it’s just a Claude Code issue,” I thought, and tried to continue in Claude.ai chat. The chat side displayed: “Cannot connect to Claude.”

    Copilot couldn’t read files. Claude Code wouldn’t run due to errors. Claude.ai chat couldn’t even connect. All three AIs were unusable at once. When Copilot first became unstable, I could still think “I’ll just use Claude instead.” But now Claude itself was down. The backup for the backup didn’t exist.

    At that point, I decided: “There’s nothing to do but wait.” I judged this was an infrastructure outage on Anthropic’s side. If it’s a problem on the service provider’s end, not my environment, there’s nothing to do but wait.

    The Structural Vulnerability of AI-Dependent Development

    The biggest lesson from Session 9 was this simple fact: “Development that depends on AI stops completely when AI infrastructure fails.”

    In traditional development — the style of writing with just a text editor and compiler — work can continue even if the internet connection drops. The tools are right there in your hands. But in vibe coding, when AI services go down, you literally cannot do anything. Since the ability to write code resides on the AI side, the human has no option but to wait.

    I believe this is an inherent vulnerability of vibe coding. Convenience and fragility often go hand in hand. In SP01 I wrote about “the pitfall of an era when AI can build anything,” but “there are moments when you cannot build anything” is another feature of this era.

    That said, I don’t think we need to fear this vulnerability too much. By the next day, the service had recovered, and I was able to resume as Session 10 in a new chat. Outages are temporary. What matters is accepting that “things can stop” as a premise, breaking work into session-sized chunks, and committing intermediate state diligently.

    Phase A Complete — Finishing the Translation Without Copilot Review

    From Session 10 onward, Claude had recovered, and I progressed through the remaining files smoothly. The two product detail pages had the most IP-protection-critical content, but the three-step approach I had established with index.html — “prior analysis → translation → verification” — worked.

    In Session 11, the last translation file was completed, and all eight English-version files were in place. Internally, I’ve been calling this “Phase A complete.”

    However, the translations up to this point were completed by just Claude Code + Claude.ai chat, a two-way system. The third-party review by Copilot was missing. As I wrote in SP02, Copilot had been left as-is, refusing file reads. The decision was to prioritize keeping the translation moving, but we couldn’t skip Copilot review from a quality-assurance standpoint.

    Wrestling with Copilot — Somehow Getting It to Review

    With translation done, the next step was to have Copilot review. But Copilot was still unable to read files. From here, the struggle began.

    Since this is translation review, HTML file reading was essential. Text pasting had a 10,240-character limit — not workable for long files like the product detail pages. I tried converting to text files (.txt) and uploading those, but that didn’t work either. I tried converting to PDF, but Copilot pushed back: “It has to be an HTML file.”

    “You were reading HTML just a little while ago,” I pointed out. It kept insisting, “The specification has changed.” Within the last hour or so, mind you.

    The exchange went on. “The PDF contents are no longer auto-extracted — paste the text instead.” “Text is impossible because of the character limit, which is why I made a PDF.” “The PDF contents are treated as empty.” After all that, it kindly explained: “You’re not doing anything wrong on your end. It’s a change on Copilot’s side.” Well then, please do something about it.

    In the end, when I attached the PDF again from the web version of Copilot, it suddenly said: “I can now confirm the full English-version HTML.” The reason is unclear. What it had been saying was impossible became possible using the same method. A considerable amount of wasted time.

    And once it could read the file, another problem emerged. The HTML source code had been broken during the PDF conversion. Spaces were inserted around underscores in BEM notation (a CSS class-naming convention), comment tag closings were mangled, and newlines appeared mid-attribute value. Copilot explained this as “breakage during text extraction from PDF,” but it was Copilot’s specification change that forced PDF delivery in the first place — a circular argument.

    Ultimately, I fixed the tag breakage on the Claude Code side and had Copilot focus only on the naturalness of the English. The role of Copilot as “reviewer” in the three-way system was preserved, but frankly, the journey to restoration was more exhausting than the translation work itself.

    This is the reality of vibe coding. Even with three AIs, each one becomes unstable for different reasons at different times. And when you ask the AI itself why it became unstable, you don’t get accurate answers. Right after saying “the spec has changed,” it does the same thing with the same method. Even in human-to-human communication this would be confusing, but with AI especially, pursuing “why can you do it now when you couldn’t a moment ago” yields no answers. You need the judgment to give up and move forward.

    Copilot’s “Legal Tone” Revision Suggestions

    The revived Copilot offered an interesting observation. It noted that the wording of the AI translation disclaimer (the header banner saying “This page contains AI-assisted translation”) was too casual for a business site.

    Indeed, the initial disclaimer had been written during translation work with a “good enough if the meaning gets across” mindset. Following Copilot’s feedback, I rewrote it in a tone closer to legal documentation. What was previously “This page contains AI-assisted translation” was revised to formal wording that specifies the scope of disclaimer and a contact point for inquiries.

    AI generates → another AI reviews → human scrutinizes and accepts or rejects. This cycle, which had nearly collapsed at one point, ended up elevating quality even to the level of legal language. It was worth persisting to restore the three-way system rather than giving up.

    However, having all eight files in place with review completed wasn’t the end. A list of issues that had accumulated through Phase A — beyond the disclaimer wording, the footer horizontal rule inconsistency, navigation structure mismatches — remained. That’s Phase B.

    Phase B — What Should Have Been “Minor Fixes” Became Major Surgery

    Phase B was initially estimated as “a collection of minor fixes.” But once I looked into it, the scope was beyond imagination.

    The biggest discovery was that the navigation structure existed in two different variants. Of the 16 files, 10 were built in Pattern A (ul>li>a format) and 6 in Pattern B (div>a format), and mobile display behavior was split into three patterns. On some pages the hamburger menu would open and close. On others it was always displayed and wrapped. On yet others, the menu disappeared entirely.

    This “disappearing menu” was occurring on the About and What’s New pages. On mobile access, navigation wasn’t displayed at all, leaving zero routes to other pages. This is a serious practical bug.

    The cause was subtle structural differences between HTML that had been AI-generated at different times. Differences in generation timing and prompts produced divergent internal structures across pages of the same site. The theme I wrote about in SP02 — “fixing HTML broken by AI, with AI” — was repeating itself here.

    In Session 15, I performed a large-scale refactoring that unified all 16 files to Pattern B + hamburger toggle. Including link path corrections, 212 modifications were made in a single session.

    16 Files, Completed

    With all Phase B issues closed, the 8 English files + 8 Japanese files = 16 files were now consistent both structurally and linguistically.

    From the start of the project to this point: 15 sessions, Session 1 through 15. One AI breaks, another fixes, a third reviews, a human decides. Through that repetition, the 16-file multilingual site came together.

    However, this is still just within my local development environment. It hasn’t been uploaded to the production server. Next time: at last, the production deployment story. Unexpected traps were waiting here too.

    Next Time

    SP04: “Production Deployment — The .htaccess Trap and the Moment of Going Live.”


    About Soul Resonant Works

    Soul Resonant Works is a solo venture developing seven local AI systems.
    Starting from zero programming experience, the development is progressing through collaboration with AI.

    🌐 Soul Resonant Works:
    https://www.sr-works.net/en/

    📝 This blog publishes the entire development process as a serialized journal.


    If you found this article useful, please share it.