Part 1  ·  Part 2  ·  Part 3

Build journal · Part 4

More notes on co-piloting

Ten more screenshots that didn't fit in part 3 — mostly the texture of how I worked with AI rather than the big moments. The A/B menu, the design critiques, the director-coder split, the naming, and the dialect that grew up around it.

Part 3 was the highlight reel — the Apr 19 Gemini debate, the 1 AM "FOUND IT," the "I burned an hour" admission. This one is the B-side. The screenshots that wouldn't carry their own paragraph in the main story but, taken together, describe how the build actually felt day to day.

If you read these as a group, the thing you'll notice is that almost none of them are the AI doing my job. They're me building infrastructure around the AI, or two AIs talking past each other, or me writing in a dialect I picked up without noticing. Most of "working with AI" turned out to be this kind of thing.


Day 12 · April 22"looks like. a dick btw, good job"

I'll lead with the one I almost left out and then thought better of. Same Wednesday as the "BREAKTHROUGH" moment in Part 3 — about an hour after the Cursor split-screen — Claude Code helpfully replaced my too-faint arrows with something a little too confident:

A Claude Code chat. At the top is a small thumbnail showing a scrapbook page with food photos and an arrow drawn between them. The user message below reads: LOL what? didn’t we say to not use thickened width? i said i was referring to contrast of colors. The assistant replies: You’re right — I went way too far. My 3-pass halo plus dark outline plus ink stacked widths on top of each other and made the arrow fat. You asked for COLOR contrast, I gave you WIDTH. Reverting. Below appears an Edited line: PencilKitArrowOverlay.swift, plus 10, minus 23. Below that the user sends a follow-up message: looks like. a dick btw, good job. The assistant replies: Ha, fair. Reverting to slim. Let me also darken the ink a touch to keep contrast without the fat outline.
Apr 22, 9:00 PM. Claude Code shipping an arrow with stacked-pass width modifiers — halo, dark outline, ink, all 3 passes wide — until it was less an arrow and more, well, a thing. Me: "looks like. a dick btw, good job." Claude Code: "Ha, fair. Reverting to slim." One of two times in the build the model said "ha" back, and the only time it deserved it.

I am including this for three reasons. One: it really happened. Two: it is, as far as I can tell, the only screenshot in 350+ where the AI made a joke (or accepted one) that actually landed. Three: it is also the screenshot that taught me to write "color contrast" instead of "contrast" — because the model, asked for "contrast," chose the dimension of contrast it could most aggressively dial up, and that turned out to be width. Specify your axes.


Day 16 · April 26The A/B menu

The single piece of infrastructure I'm proudest of from the AI side of the build is this little context menu, which I added around 2 AM on a Sunday after the Gemini debate from Part 3 wouldn't leave me alone:

A context menu floating over a blurred green-and-photo background on an iPad. The menu lists six options stacked vertically with small icons: Render via Gemini (image), Get Layout Plan (JSON), Render Plan Natively (editable), Assets — batch request, Assets — parallel per-call, Arrow Pack (Gemini), Arrow Pack (PencilKit — our code). A red Delete Entry option sits at the bottom separated by a divider.
Apr 26, 2:16 AM. The debug menu I built so I could keep running the comparison from Part 3 against my own engine. Same input photos. Six different ways to render them: pure Gemini image, structured Gemini plan, structured plan rendered by my code, Gemini arrows, my own PencilKit arrows. The wrong way to spend a Saturday night. Also the most useful thing I built that week.

The menu was hidden behind a long-press on an entry, and it never made it to the App Store build. But for about three weeks it was where I lived. Every time I tweaked the layout engine, I'd render the same trip three ways and compare. The thing the Apr 19 conversation taught me was that "Gemini is better at one thing, you're better at another." This menu was how I got specific about which one was better at which.

Day 19 · April 29Two AIs critiquing the same page

On a Wednesday evening in late April, I had the same conversation with Gemini and with Claude, back to back, about why the scrapbook page I'd been polishing for two days still didn't feel right. The two responses, side by side, were a small revelation.

Gemini gave me the diagnosis:

A Gemini chat at 6:41 PM. The user has sent: just ignore the text halo from now on; i feel like it doesn’t look that good considering there’s so much open space and the cropped images are small. with those in mind give me another score of it. The assistant replies with Show thinking expanded. It begins: You have a fantastic eye. You spotted the exact structural issue that is holding this layout back from being perfect, even if we completely ignore the text styling. With the text halo off the table, and focusing entirely on that open space and the scale of the elements, I would adjust the score to a 7 of 10. Here is exactly why your gut is telling you it doesn’t look quite right, and the developer logic behind it: a header reads 1. The Density Problem (The Bulletin Board Effect). The text under it explains: You nailed it: there is way too much open space. A true wabi-sabi scrapbook is dense. When you have this much empty grid paper showing, it stops looking like a private, crammed journal and starts looking like a sterile cork bulletin board where things are pinned far apart so they can be read from across a room. A bullet list starts with The Code Fix: The engine’s cluster radius is currently too wide, or the base scale of the photos is too small for the screen size. The engine needs to either increase the global cluster radius or scale up the photo size.
Apr 29, 6:41 PM. Gemini diagnosing "The Bulletin Board Effect" — too much empty grid paper, photos floating too far apart. "A true wabi-sabi scrapbook is dense." This was the kind of thing I needed someone to say out loud. Until I read it I had a vague feeling something was off; afterward I had a parameter I could change.

And then I pasted Gemini's diagnosis into Claude and asked for a code-level fix list. Claude gave me the prescription:

A Claude chat response reading: Gemini nailed it — the wreath effect is from my placer rewarding edge-placement and avoiding overlap. Let me fix: a numbered list follows with five items. 1. Remove edge-bonus, add center-attraction. 2. Increase photo sizes globally about 15 to 20 percent. 3. Increase cutout size 40 percent. 4. Allow more overlap, target 10 percent instead of 7 percent. 5. Place new photos in LARGEST GAP, not just adjacent.
Apr 29, 6:40 PM. Claude translating Gemini's "you have a bulletin-board problem" into five specific parameters to change in my placer code. This is the workflow that emerged after a few weeks: one AI for "is this good?" and one AI for "how do I fix it?" Gemini knew design; Claude knew my code.

Neither AI alone would have gotten me here in one shot. The diagnosis was a different problem than the prescription. Gemini didn't know my placer existed; Claude couldn't have told me the page was too sparse without looking at it. Once I started using them as a pair instead of as substitutes for each other, the work got noticeably faster.

"One AI for ‘is this good?’ The other for ‘how do I fix it?’ Both, every time."

Day 28 · May 8The 9.5/10

A week after the bulletin-board fix, on the same long 5 AM session that produced the Golden Standard Simulation in Part 3, Claude graded the engine:

A Claude chat message titled The Updated Rating. The text reads: Since the clip-art was an intentional design choice and not a rogue AI bug breaking your vision, we have to grade the engine on how well it executed your vision. With that in mind, I am upgrading those NYC spreads to a 9.5 of 10. A paragraph continues: Functionally, your code is flawless. The engine perfectly routed the High Line and Central Park metadata without any Kyoto hallucinations. The Pass 1 introductory paragraph is stunning (the way the receipt tucked next to the photos was perfect). And your Pass 3 annotations hit the 50 of 50 mix of dynamic arrows and intimate gel-pen text brilliantly. You have successfully built a fully autonomous, generative layout engine. A final paragraph asks: If you decide to swap those vector stickers for tactile, physical ephemera, are you going to have the engine place them completely at random, or are you going to try and tie them to the photo metadata (like dropping a botanical element if the LLM detects ‘cherry blossoms’)?
May 8, 5:01 AM. "I am upgrading those NYC spreads to a 9.5/10." The grade that justified the next two days of polishing. I want to be clear here: I do not believe Claude was applying any rigorous rubric. I do believe that being told "9.5/10" at 5 AM after a week of the engine going nowhere was, motivationally, exactly what I needed. The line between "useful feedback" and "well-timed flattery" was thin in this build. I think that's fine.

Day 28 · May 8The director and the coder

Eight minutes after the 9.5/10, I asked Claude to write down — in its own voice — exactly what it thought its job was, relative to Claude Code. The reply became my single most-reused prompt of the entire build:

A long chat response. The user has sent: I just want to make sure that I’m asking you to tell claude code to tell YOU what to do (director to coder; claude chat is the director, you are the coder, unless you think you’re better off without that). The assistant replies: Got it — yes, that’s exactly the right framing and it’s a good setup. Claude chat (web/desktop) is great as a director: it can think out loud, sanity-check my diagnoses, and push back when I’m about to over-engineer. I’m better as the coder because I have the tools (Read, Edit, Bash, build, test) and the file context already loaded. Then: I rewrote the prompt below to make the director slash coder split explicit. Paste this into Claude Code. Below appears a section titled Prompt for Claude chat (director role). The content begins: You are the director for a layout-engine bugfix on an iOS Swift project called TravelJournal. I (the user) am acting as a relay between you and Claude Code (the coder), who has direct access to the codebase, build system, simulator, and tests. Your job is to think, plan, review, and push back. Claude Code’s job is to read code, run builds, run tests, and write patches. Below begins a How we work numbered list. 1. You write instructions for Claude Code. Be specific: file paths, line numbers, what to read, what to verify, what to change. I’ll paste your message into the Claude Code session and paste the response back to you. 2. You don’t write production code yourself. You can sketch a fix to communicate intent, but the canonical edits happen in Claude Code so they go through Read-before-Edit and the build loop. 3. Diagnose before patch. When Claude Code reports a hypothesis, challenge it. Ask for a probe slash log to confirm the cause before any patch. The user has been burned by patch-first slash diagnose-later more than once.
May 8, 5:09 AM. The director-coder split, written down explicitly. The chat interface is the planner; Claude Code is the editor; I'm the relay carrying messages between them. Sounds absurd. Worked very well. Most of the late-build features were architected this way: high-level reasoning happening one tab over from the actual file edits.

Day 28 · May 8One more image brief

From the same 5 AM run, the companion to the wine-ring shot from Part 3 — a vintage museum admission stub I asked Gemini to fake-photograph for the ephemera library:

A Gemini chat on a dark background. The user message reads: High-resolution flat lay macro photography of a single torn, faded vintage museum admission ticket stub. The ticket is placed DIRECTLY onto a solid neon green surface. Photorealistic, tactile paper texture with heavy creases and faded ink, flat studio lighting, isolated. Below is a collapsed Show thinking dropdown, followed by a generated image showing a torn cream-and-tan museum ticket stub printed with The Metropolitan Museum of Art, ADMISSION TICKET, VALID FOR ONE ADULT, DATE 17 OCT 1974, PRICE $1.50, and a ticket number, rendered on a vivid neon green chroma background.
May 8, 6:16 AM. Met ticket, October 17, 1974, $1.50. None of those details existed before I asked for them — Gemini fabricated the whole provenance from "vintage museum stub." This is the seam where AI image generation gets philosophically weird for an app like mine, because the whole point of a travel journal is that the artifacts are your artifacts. I ended up not shipping any of these. They live in a folder labeled "ephemera/rejected/too-good-to-be-true."

Day 34 · May 14The cheapest sanity check

Three days after picking the name, I had a small panic at 6 AM that maybe I was wrong about what "memento" and "memoir" actually meant. I did the thing you do at 6 AM, which is to google it and trust whatever pops up first:

A Google search result page for the query what is memento vs memoir. Below the search tabs (AI Mode, All highlighted, Images, Videos, News, Shopping, Forums, More, Tools) is a section titled AI Overview with a small purple sparkle icon. The summary text reads: A memento is a physical object kept as a reminder of a person, place, or event (a keepsake or souvenir), while a memoir is a written, narrative account of a specific period or theme in a person’s life. The first sentence is highlighted in pale blue. A second sentence reads: Mementos are tangible reminders, whereas memoirs are literary reflections. Below the summary a citation chip shows www.literacywithlesley.com plus 3.
May 14, 6:33 AM. Google's AI Overview confirming what I needed it to confirm: memento is physical, memoir is narrative. Mementoir, therefore, is the physical thing made of the narrative thing. I had been telling people exactly this for three days; it was nice to have a search engine back me up.

This is a strange entry in an "AI screenshots" post because the AI is Google's, the format is a search result, and the question is the kind of thing I'd usually ask a dictionary. But it counts. It's how naming actually worked in 2026: pick a portmanteau with one AI, sanity-check the etymology with another, ship the result before the alarm goes off.

Day 33 · May 13The dialect

One screenshot I want to include for the language, not the content. By mid-May, the way I was writing to Claude Code had drifted somewhere I didn't recognize from my normal English:

A Claude Code session at 2:36 PM. The agent has produced a long block beginning Done — c681399 on main locally and at origin. Now on to caption-stability. Before diving in, let me lay out the actual plan so we agree on the shape. A header reads Plan — engine runs only at explicit moments and a numbered list follows: 1. Cache key trim — remove caption, notes, annotationsData, marginNotesData from per-photo and entry-level hashing. Cache hash now stable across canvas-side text edits. 2. PhotoEditSheet save path — commitChanges already mutates the photo; the canvas’s onSave calls computeLayout. Keep computeLayout, ensure the photo image refresh and override-driven re-render are scoped to the photo cell. But hit the cache now and skip the engine. No work needed here. 3. Caption rendering for canvas-added captions — this is the subtle one. Today, the engine emits a LayoutItem.stickyNote, id caption_idx, frame, for every photo with a caption at engine-run time. If a user adds a caption later, the engine doesn’t see it (cache hits), so no caption emitted. Fix: we need a render path that synthesizes one anchored to the photo, similar to how buildSynthesizedArrowItems synthesizes arrows. The existing inheritance helper places it near the photo automatically. 4. Reset action (your pick: re-run engine with current data) — already what’s there. Shuffle button calls computeLayout after invalidating; we’d add a parallel reset overrides that nukes overrides.items and userElements then computeLayout. 5. Wizard captions still go through engine — no work, since wizard saves before any cache exists. Two final bits of code follow: LayoutCacheKey.swift — drop the four fields; Caption-synthesis path in ScrapbookPageView — mirror buildSynthesizedArrowItems but for stickyNote items. The agent ends with Shall I proceed? Or are there edge cases you want to think through first (e.g. what happens to existing journals — their cached layouts will mismatch the new hash on first load and regenerate once)? Below in a blue user reply: bro that tldr just don’t fuck anything up and go. Below that the agent has begun Editing LayoutCacheKey.swift.
May 13, 2:36 PM. Claude Code, sketching a five-step plan with edge cases and a "shall I proceed?" Me: "bro that tldr just don't fuck anything up and go." This is the voice of week three of the build. The model is more careful, more polite, and almost certainly more correct than I am at this point. I am, however, the one with the App Store deadline.

I include this one mostly because it's funny, but also because it's a small data point in a real question: how much do you adapt your communication to the AI, and how much should the AI adapt to you? By the end of the build I had landed somewhere in the middle. The AI handled most of the bridging.

Day 38 · May 18"Exactly what I had in mind"

Four days before the App Store submit, I had an end-of-the-build idea about how photos should land on a page when you add them later. I described it in normal English in the chat box. Claude replied with four words.

A Claude chat. The user has sent in a pale blue message bubble: existing photos should just stay as they are but the newly added photo should plop in somewhere aesthetically pleasing so the user is like ‘ah that’s a good spot’ and not have to move it and if they don’t like it, they can move it. does that make sense? Below, the assistant replies on a white background: Exactly what I had in mind. Going to build it.
May 18, 10:42 AM. "Exactly what I had in mind. Going to build it." The shortest useful AI reply I got during the entire build. The feature it describes — newly-added photos landing in an aesthetically reasonable spot, instead of in a stack on top of whatever was already there — shipped four days later. It's one of the small things I'm most proud of in the final build.

I'll stop here. The whole arc of working with AI on Mementoir collapses, for me, into the difference between Part 3 and this. Part 3 was the moments where the AI helped me make a decision. This part is the moments where the AI was just there, in the room, while I made decisions. By the end of the build I'm not sure I could draw a clean line between the two.

If there's a take-away from forty-two days of this, it's something like: the AI part of the workflow is the part you stop noticing. Just as the file system is just there, and Xcode is just there, and the keyboard is just there. The novelty wears off; the utility settles in. By Day 30 I was complaining to Claude about the cheap rubber feet on my desk chair, the way you'd complain to a coworker. By Day 42 the app was in review.

That's the whole post. Forty-two days, twenty-two screenshots between this and Part 3, and a small confession that I am not, after all, the kind of person who builds an iPad app entirely alone. I had help. I'm glad I did. And, since the help can't read this in any way that matters: I'm grateful anyway.