What changed in each build, why, & how to use it. Newest entry first.
The shared-address warning is out of the way
August 14, 2026 · build v1.5.61
The security notice about Punchlist sharing browser storage with other apps on the same domain is now hidden. That shared address currently hosts apps controlled by the same owner, so the recurring board-top warning and the matching notice above the GitHub sync token were more interruption than help.
This is an explicit temporary product policy. The origin detector and warning model remain in the app, dormant behind one switch, so the migration to a custom or dedicated domain can restore or retire the old-address guidance deliberately instead of rebuilding it later.
Nothing about storage or sync changed. Existing boards, images, history, exports, GitHub sync settings, offline reopening, and direct file:// use behave exactly as before. This build only removes the visible notification.
The phone build keeps the board under your fingers
August 13, 2026 · build v1.5.60
This is the mobile stability batch tested on the physical phone. Completing one task after another no longer moves the next checkbox away from the place you were tapping, and revealing a task's actions no longer grows its row or steals width from deeply nested text. Every mobile task keeps a direct +; Delete appears only on the selected row, at its top-right edge.
Deleting a nested branch points at the branch you chose. Its confirmation sits directly above that exact row, follows its indentation, and leaves the rest of the tree visible. Delete and Cancel keep full touch targets. Group deletion uses the same compact treatment instead of squeezing the group title.
Focus mode fits the phone now. Long text, metadata, images, captions, and nested outlines stay inside the screen. Back and Fold all move to a bottom-left dock on small screens, above the phone's safe area, so leaving or folding the view does not require reaching back to the top.
The hamburger stays reachable while you scroll. It pins to the top-right after its original place scrolls away, then returns to that place when you reach the top. Completed and Trash also gain enough end space to clear Safari's bottom controls at maximum scroll.
Hosted and downloaded copies remain portable. The hosted service worker now asks the network for a fresh app shell before falling back to its cache, while offline reopening and direct file:// use still work. No storage key or board format changed, so existing boards, exports, history, images, and sync settings carry forward. A downloaded copy also checks the small latest.json channel rather than waiting for the next GitHub release page poll.
Mobile task actions stay out of the way
August 12, 2026 · build v1.5.53
Every mobile task now keeps a direct + button at its right edge for adding a subtask. Selecting the row reveals a small close-style delete button above it, so deleting remains deliberate without taking a permanent second full-size button from the task text.
The row does not grow when the delete control appears. That keeps the checkbox directly below a selected row in the same on-screen place, while nested tasks retain their usable text width.
A downloaded copy hears about updates faster
August 8, 2026 · build v1.5.42
The update check used to poll GitHub's Releases page. Releases are now cut by hand at milestones, sometimes weeks apart, so a downloaded copy could sit unnotified for 24 builds in a row while the hosted site had long since moved on.
It now checks latest.json instead, a small file the build writes fresh every time. Same silent, no-account, zero-network-otherwise check as before: only a copy opened from disk, only with the setting on, never in the demo, & it says nothing at all if it can't reach the file.
Ctrl+↑ & Ctrl+↓ reach focus mode
July 29, 2026 · build v1.5.39
Ctrl+↑ folds the row your caret is in, Ctrl+↓ opens it back up. On the board that already worked, on tasks & on groups, & it kept working while you were typing inside the row. In focus mode it did nothing at all. The outline there draws the same chevrons the board does & had no key bound to them, so the pair you reach for was dead in the one view built for concentrating on a subtree.
The caret holds its row through the fold. The outline redraws when a row collapses, & landing somewhere else afterwards would cost you your place, which is the whole point of being in focus mode.
The row you focused on is left out on purpose. Focus mode draws its children whatever its own folded state says, so folding the root would change the board underneath you while nothing moved on screen. A key that quietly edits state you cannot see is worse than no key.
The chevron names its shortcut on hover now, the way the other row controls do.
Bold, italic, strikethrough & code, without the caret games
July 29, 2026 · build v1.5.38
**bold**, *italic*, ~~struck out~~, backticks for code, & the underscore spellings. ***both*** nests. Ctrl+B, Ctrl+I & Ctrl+Shift+S apply them, & they write plain Markdown into the task so an export or a paste elsewhere carries the formatting with it.
The row you are typing in shows its markers. Every other row stays formatted. That is the whole design, & it is the reason this works where the first attempt did not. The markers are never removed from the text, only hidden, so clicking into a row re-renders nothing & your caret cannot end up somewhere you did not put it. While you edit, what is on screen is exactly what is stored.
Markers need a space outside them. So 2*3*4, some_file_name.txt & build_task_board stay literal, while bolding a whole sentence still works. The test is the spaces outside the asterisks, not inside.
Settings → Formatting has all three switches: the mode (raw while editing, always rendered, or never rendered), the shortcuts on or off, & the whole-words rule on or off.
Pasting formatted text keeps its formatting now. Copy a few paragraphs out of a browser, a document or a chat & the bold stays bold, the links stay links, & the line breaks stay where they were. It arrives as plain Markdown in the task rather than as foreign markup, so what lands in your board is text you could have typed yourself. One gap: a pasted table runs its cells together on one line.
Type a colon for emoji
July 29, 2026 · build v1.5.34
Type : and keep typing. Arrows move, Enter or Tab inserts, Escape keeps the word literal.
It only triggers on a colon that starts a word. So 10:30 stays a time, note: something stays a note, & https:// stays a link. Press Escape & it stays out of your way while you finish that word, so :fire can just be the word fire.
About 250 emoji, weighted towards what a task board actually needs: status, work, time, feeling. Not the full Unicode set, which with searchable names would be around 200 KB, roughly half the app.
Move done tasks down is a new setting under Lifecycle, off by default. Turn it on & ticking a task sends it to the bottom of its group, under everything. One thing to know first: a task nested under another leaves that nesting to get there, & unticking does not put it back, because nothing recorded where back was.
Reporting a bug takes two fields, & both of them arrive
July 29, 2026 · build v1.5.33
Summary & What happened. The summary becomes the issue title. Every issue used to open titled "Bug report", which made a list of them impossible to read at a glance, & the one line that would have said what broke was buried in the body.
Two ways out, told apart by colour. Purple opens a prefilled GitHub issue. Blue copies the author's email with everything you wrote, & it is now the big obvious button under a small line for anyone who does not have or want a GitHub account.
Your text is not thrown away. Opening the issue clears the form, because by then your words are safely in it. The email path keeps the dialog open & keeps your text, because a copy can fail silently & retyping a bug report is worse than an extra click. Closing the dialog clears it.
Screenshots. They cannot travel from the app into a prefilled issue: the URL carries text only, & GitHub will not render an embedded image in a body it was handed. So the issue asks you to attach them there, where the upload box is.
The board is harder to wipe by accident
July 28, 2026 · build v1.5.32
Restore example board asks twice, & offers you a backup on the way. It used to be a full-width red button in the middle of Settings behind a single browser confirm, one slip from erasing everything. It is a small underlined line at the very bottom now, under Report a bug. Pressing it opens a dialog that counts what you are about to lose in your own numbers, puts Export JSON right there so the backup is one click, & asks again in different words before anything happens.
The sidebar rows line up. Views was a small uppercase caption with no icon while History & Help were full rows with icons, & the gaps between the three ran 10px, 12px & 22px depending where you looked. One row shape, one spacing, & Views has an icon.
The drop line during a drag is a line. It was drawn as an inset shadow, which browsers paint inside the border box, so it followed the row's rounded corners & curled up at both ends. Straight across now.
A stuck backdrop that ate every click. Open the sidebar drawer on a narrow window, then widen the window: the drawer's full-screen backdrop stayed up while the sidebar went back to being an ordinary column behind it, so the whole page dimmed slightly & swallowed every scroll & click over the sidebar. Widening the window now closes the drawer with it.
Sync knows your devices by name, & you can forget one
July 28, 2026 · builds v1.5.28 to v1.5.31
Enter splits a line where you put the caret. A caret sitting at the visual end of a rendered link is actually inside it, & the code that mapped the caret back to your stored text stopped counting the moment it found the caret, so the closing marker never got counted & Enter split the line in the wrong place. Bold had the same bug; pulling bold only hid it.
Naming this device is required for sync. Two names live in Settings & they answer different questions: your name travels with anything you send someone, the device name never leaves this browser & is what tells your phone from your laptop when they disagree about the board. Sync needs the second one, because a conflict dialog that says "another device" cannot be answered. A board already syncing without a name says so on open.
You can forget a device. Settings, Sync, hover a device & press the x. It goes from the list on every device at the next sync, & Ctrl+Z brings it back. One honest caveat, spelled out in the app: forgetting tidies the list, it does not revoke access. Every device shares one token, so a device still holding it rejoins the moment it syncs. The sync guide walks through rotating the token when you actually need to cut one off.
Plus three smaller ones: the keyboard walk down the sidebar no longer stalls at Settings, Enter flips a toggle instead of doing nothing, & an open section's arrow points down at its content rather than up.
Text formatting is gone, & nothing you wrote was touched to do it
July 28, 2026 · build v1.5.27
Bold, italic & strikethrough are pulled. They had too many rough edges to be worth what they gave you, so **bold** shows its asterisks again.
Read this part if you used it. There were two ways to do this. One strips the markers out of everything you have stored, so your text comes out clean & the change is permanent. The other stops rendering & leaves every character exactly where you typed it. This build does the second one. Nothing was rewritten, no migration ran, & the markers are back in your text because they never left it.
That also means a Markdown export still carries them, so **bold** means bold again the moment it lands in Notion or Obsidian.
Ctrl+B, Ctrl+I & Ctrl+Shift+S went with it. They only ever typed those markers, & a shortcut that promises bold & delivers asterisks is worse than no shortcut.
Links are not formatting & stay exactly as they were: [label](url), bare URLs, & pasting a URL over selected text.
One thing this quietly fixed: pasting bold text in from a browser or a document used to add asterisks to your task, because the pasted styling was converted to markers on the way in. It arrives as plain text now.
Every button tells you its shortcut, & Settings works from the keyboard
July 28, 2026 · build v1.5.26
Punchlist has always been meant for the keyboard. The problem was finding out what the keys were.
Hover a button & it names its key. The checkbox says Ctrl+Enter. A chevron names the Ctrl+arrow that matches whether it is open or closed. The plus says Enter then Tab, the bin says Backspace, the grip says Alt+arrows. Nothing new happens, these were all already there; you just had to know.
Alt+S shows & hides the sidebar. It sits next to Alt+A for a new group. On a narrow window it slides the drawer instead, same as tapping the hamburger, & it works while you are typing.
Settings browses like the board does. Arrows walked the sidebar before, but they could not open a section & they skipped straight over every dropdown & text field inside one, so the settings themselves were mouse-only in practice. Now arrows walk everything on screen, Right opens a section, Left closes it & then climbs to the section holding it, & Ctrl+arrows expand & collapse the same way they do on the board.
One deliberate choice in there: arrows walk past a dropdown rather than changing its value, the way arrows move between rows instead of editing them. Alt+Down drops it open when you do want to change it.
There is a cheatsheet now.Every shortcut on one page, grouped by what you are trying to do, with five picked out at the top. It prints. It is linked from Help inside the app too.
Sync stopped travelling back in time
July 27, 2026 · build v1.5.25
If you sync across devices, this is the build to be on, & so is every other device you own.
When two devices disagreed about the board, Punchlist picked the winner by counting how many edits each one had made. Counting, not timing. So a phone sitting on fifty edits from last week outranked the laptop you touched a minute ago, pushed its old board over your fresh work, & the laptop then pulled that old board down onto itself. That is the trip back in time.
Every edit now stamps the time beside the counter, & sync reads both. When they agree it resolves silently exactly as before, so an ordinary day gets no new dialogs. When they disagree, which is precisely the case that used to lose work, it stops & asks, & the dialog names both edit dates so the choice is obvious instead of blind.
The catch worth saying plainly: this only protects you when both sides of a sync have it. A device on an older build sends no stamp, so the newer one falls back to counting, & the old device has no protection at all. Update every device, not just one.
Underscores make text italic & bold now, without wrecking your file names
July 27, 2026 · build v1.5.24
Until today only asterisks worked. _like this_ just sat there as literal underscores. Now _this_ is italic, __this__ is bold, & ___this___ is both, matching the asterisk forms you already had.
The part that took the actual thought: an underscore in the middle of a word is not formatting. If it were, then build_task_board.mjs would turn into buildtaskboard.mjs the moment you typed it, & so would every snake_case name & every __init__ you ever paste in. So an underscore only starts or ends emphasis at the edge of a word. Asterisks keep working mid-word, because that is the rule everywhere else too.
One thing to expect: underscores are stored as asterisks. Type _italic_, edit the line again, & you will see *italic*. It looks exactly the same on screen. Both spellings mean one thing, & keeping track of which one you typed would buy you nothing.
Moving a task stops repainting the whole board, & bold stops running away
July 26, 2026 · build v1.5.23
Four fixes, all things you feel rather than read about.
Moving an item used to redraw everything. Every row on the board was destroyed & rebuilt on each Alt+Arrow, which is why the whole list blinked. Measured on a test board: 26 rows out of 26 thrown away. It now rebuilds one, the row that moved. Your selection & your keyboard focus survive the move as well, which they did not before.
Adding a sub item used to flash the item above it. That item was the parent, & it was being rebuilt along with its child list for no reason. Adding a sub item now touches nothing that already exists on screen, it just inserts the new row. The parent keeps its chevron, its text, & your place in it.
Bold no longer sticks. Press Ctrl+B on a word & keep typing: everything after it came out bold too, because the cursor was left sitting inside the bold text. It now steps out, so what you type next is plain. Backspace & the arrow keys still land on the real character either side, no dead keystroke.
And bolding twice no longer doubles up. Bold a word, then select the whole line & bold that: the markers nested inside each other & you got stray asterisks printed in your text. Bolding a selection that is already part bold now simply makes all of it bold, & bolding it again clears it. The same goes for italic over a bold word.
Restore from history could bring back the wrong item. If you had deleted two items with the same name, every Restore button that mentioned that name pointed at the same deletion, the oldest one. So restoring the newer one quietly handed you the older item instead. Restore now matches on when the deletion actually happened, so each history row brings back its own item.
One more, quieter: on a phone, a drag that got cancelled part way could leave the row it touched faded & outlined for the rest of the session. That row now clears properly.
The status board became a tool of its own, & the app did not move
July 25, 2026 · no app change, still v1.5.20
Nothing in Punchlist changed today. The built file is byte for byte the one from the July 21 build, same version, same behavior. If you use the app, there is nothing here for you & nothing to re-download. This entry is about the workbench beside it.
The status board is the local page a coding agent & I share while working on Punchlist: your task board on the left, a graph of what the agent is doing, & a chat channel. It only ever ran inside this repo, because it looked for its files next to its own scripts & served the board pane from a hardcoded path into the app folder. Now it reads whichever project you start it from, & the board pane is looked up in three places instead of one. Copy thirteen files into any project & it runs there, with that project's tasks, on its own port.
The board pane is still Punchlist. That is the whole reason this is cheap: Punchlist builds to one HTML file with no dependencies & no network calls, so a second project carries a copy of it & nothing else. A new script keeps that copy current by pulling the published build over HTTP, & it refuses to install a file that is missing anything the wrapper reaches for. The server now reports which build the pane is running every time it starts.
One real bug fell out of the survey. The graph's timeline view looked for a group by a fixed name, that group was renamed during a recent cleanup, & the view had been quietly blank ever since. It now works out which group to show from the board itself.
Sync can no longer roll your board back to an old version
July 21, 2026 · build v1.5.20
A board that had not been touched in days could still overwrite your current one. When two devices had both changed, sync always let the local one win, with no check for which board was actually newer. So a device that woke up after five days, still carrying one unsynced edit, pushed its stale board over everyone else. That is what reverted a board to a five day old state.
Now every board carries a small counter that ticks up on each real edit, and sync compares those counters instead of guessing. A stale device can never overwrite a newer board, it takes the newer one instead. When two devices genuinely both moved ahead, the one with more changes wins and the other version stays in your Undo and in the repo history, and a real tie asks you which to keep. No clocks are involved, so a device with a wrong clock cannot fool it.
Also in this build: expanding or collapsing a big group no longer rebuilds the whole group, so the toggle stops lagging on large boards.
The flash is gone: edits repaint rows, not the board
July 21, 2026 · build v1.5.19
The oldest open complaint here was a visible flash while editing a big board. It turned out to be the whole board repainting in one long freeze, and two habits made it worse: link badges were recounted from scratch for every row drawn, and edits to linked copies (the day-planning kind) always repainted everything.
Measured on a 1,400-task board: completing a linked task went from 650ms to 31ms, pressing Enter on a top-level row from around 300ms to 25ms, and hiding a completed task now removes just that row instead of redrawing the page. Same board, same edits, about twenty times less work.
Report a bug, calmer image settings, and focus knows where you are
July 21, 2026 · build v1.5.14
Settings gained a Report a bug button. Describe what happened and one click opens a prefilled GitHub issue (your text plus the app version), or copies an email instead. No account gymnastics for testers.
The image resolution setting now explains itself: changing it never touches images already on the board, only new pastes, and it says so when you change it, on hover, and in Help.
Focus mode keeps its bearings on long lists: the top bar shows what you are focused on while you scroll, group focus shows the group's total tracked time, and the keyboard toggle (Ctrl+Alt+F) is now visible instead of secret.
The phone margin bug is dead, measured this time
July 21, 2026 · build v1.5.12
The board on a phone could sit shifted, dead space on the left and the card running off the right edge. A live probe on the actual device measured the group card at 393px on a 375px screen: one CSS grid track allowed itself to grow past the viewport whenever a task held a wide pasted image. The track is clamped now, and the same board measures a clean 20px margin on both sides with images shrinking to fit.
Checkboxes also toggle reliably now. Pressing the checkbox of an unselected, half-visible row used to select the row and scroll it, which swallowed the click before it could check the box.
Sync stops eating edits and throwing you around the board
July 21, 2026 · build v1.5.8
Three sync fixes in one pass. If you typed something and switched tabs fast, the incoming sync could decide your device had nothing new and pull the other version over your unsaved words; it now lands your typing first, every time. A pull used to jump the view back to the top of the board; it now keeps your place and your selection exactly where they were, and if you are mid-edit it waits until you finish before applying anything. And the "GitHub answered 409" failure now retries by itself instead of sitting there until you poked something.
Buttons stay on one line, and the phone stops drifting sideways
July 21, 2026 · build v1.5.7
Two small fixes. Button labels like Collapse all no longer fold onto a second line when the sidebar is narrow. And on the phone, the page could slowly drift sideways as you scrolled (a left margin creeping in while the right edge slid off screen); the page now refuses sideways panning outright, the same guard the landing page already had.
The downloaded file can tell you when it is out of date
July 20, 2026 · build v1.5.5
If you run the downloaded copy, it now checks once on load for a newer release and shows a small, dismissible note when one exists, with a link to get it and to see what changed. It never reaches out for anything else, and there is a switch in Settings to turn the check off entirely, so the file stays fully offline if you want. The hosted version is always current, so this only matters for a downloaded file.
Settings shows your current version now, and there is a short guide on updating a downloaded copy without losing your board.
Focus mode scrolls, and its header shrank
July 20, 2026 · build v1.5.4
Two quick focus fixes from real use. Long lists in focus now scroll; before, anything past one screen sat stuck out of reach. And the big title at the top was cut down so the tasks lead, not the heading.
Focus mode folds now
July 20, 2026 · build v1.5.3
Focus mode used to open every row flat, so a long list was a wall you had to scroll. Now each row with children has a fold arrow, and it opens in the same folded state as the main board. A Fold all button in the top bar collapses the whole thing, or opens it back up if it is already folded.
This is aimed at the big group-focus case, where dozens of items used to spill out at once.
Dead expand arrows are gone
July 20, 2026 · build v1.5.2
A task could show an expand arrow that opened onto nothing. It happened once every subtask under it was finished and had aged out of the active view: the arrow still counted those hidden children, so tapping it revealed an empty gap. Now the arrow appears only when there is something to reveal.
Small fix, but a real papercut in long-lived lists where completed subtasks pile up under a parent. Your boards are otherwise untouched.
Choose how sharp images stay
July 19, 2026 · build v1.4.0
Pasted images were quietly shrunk to 800px and re-saved at low quality, with the original discarded. A new setting controls how much resolution is kept, in Settings under Paste creates.
The new setting sits in Settings, right under Paste creates.
What changed
A new Image keep resolution setting with four levels.
Medium is the default, and it is sharper than before: 1440px instead of 800.
Each level names its own size right in the menu, so the choice is detail against storage, with no guessing.
The four levels
Original — the original file kept untouched. Pristine, but 1 to 5 MB each.
High — 2560px, up to about 2 MB.
Medium — 1440px, up to about 500 KB. The default.
Low — 800px, up to about 120 KB.
It applies to new pastes only, and every level except Original re-encodes to WebP. Original is the pick when the source bytes genuinely matter, not just a sharp preview.
The phone stops fighting back
July 19, 2026 · build v1.4.0
A touch re-test on the new build surfaced four issues. Three are fixed.
The board at phone width, where the touch fixes land.
What changed
No more pinch-zoom or sideways wiggle. It is a web app, not a document, so zoom is off and the wiggle went with it. Vertical scroll and swipe-to-indent are untouched.
No stray magnifier. A long press on the row body away from the text used to summon the iOS magnifier after a couple of seconds. It stays quiet there now, while a press inside the text being edited still gets the native magnifier.
Sweep select is reversible. Hold to enter select, sweep down to grab a run of rows, then drag back up to drop the ones past the finger. Rows banked in an earlier hold stay selected.
Still open
Holding one row longer to select it was still misbehaving in testing and is being pinned down before the gesture timing changes. 110 tests pass, one new that checks the sweep fills, reverses, and keeps earlier holds.
The landing page catches up to the app
July 19, 2026 · build v1.4.0
The front page had drifted out of date and got cramped on phones. This build brings it back in line.
The landing page: current version, calmer on phones.
What changed
Version and size are right everywhere. It said v1.2.0 and 260 KB; it now reads v1.4.0 and 340 KB in the header, the fact chips, the hero copy, the footer, and the exact byte count in "Why this exists."
The "What the file does" mockups are fixed. Empty checkboxes were white on white and read as smudges; they sit on a tinted fill now. The Nested outline card had gone flat with its guide-line drawing across the text; it steps in properly again. Rows wrap, so a chip no longer collides with the task text.
Phones got room to breathe. Side gutters open from 20px to 30px, the hero title, headings and buttons are calmed down, and the top bar no longer spills its theme button off the right edge on narrow phones. Clean down to a 320px screen.
Two new links. A "View source on GitHub" button up top and a source link in the footer. "What's planned" was rewritten to match reality and links here, to these notes, as the running release log.
The page still makes zero network requests. The single-file app now also ships as a tagged GitHub release you can download, cut with one command at each milestone.
Enter at the start of a line, and a batch of small fixes
July 19, 2026 · build v1.4.0
What changed
Enter at the start of a line. With the cursor at the start of an item, Enter adds a fresh empty line above it at the same indent, ready to type, and the existing text stays put. An already-empty line is the exception: Enter still makes a new item below.
Delete confirmation is readable. The prompt was red on a dark bar; it is white on dark and dark on light now.
Graph timestamp no longer overlaps. The time that sat on a node's text now sits on its own line under it.
Chat polish. Timestamps drop the seconds, and the seen button explains itself on hover with its double-click shortcut.
110 tests green, verified in a real browser.
The ghost that ate taps, & images move out of the board
July 19, 2026
The ghost that ate taps
A "toggles sometimes stop working" report turned out to be a ghost. When the app repaints the row under the pressing finger, the browser silently drops that touch, with no release event ever. The 1.5-second hold timer kept running, armed drag-select with no finger on the glass, and that ghost then ate the next tap's click or every scroll until reload. Reproduced both ways in a real browser, then fixed with one rule: any new press wipes every stale gesture first. A regression test now fails the build if it ever returns.
Two more touch fixes
The copy-paste-looking drag is gone. Rows were marked draggable for desktop mouse drag, and iOS treats a long-press on anything draggable as a native OS drag, stealing the touch before the app's 420ms hold could arm. Touch presses now refuse the native drag and get the real one with drop indicators, rows and group headers both.
Auto-scroll near the top is smooth. Four small sins at once: whole-pixel speed jumps, a ramp that peaked too near the edge, the scroller fighting the iOS rubber-band, and a cleanup killing the scroll mid-drag. All fixed, plus a bug that fell out: drops during a still-finger auto-scroll landed on a stale row, so the target now follows the content.
Images move out of the board
v1.4.0 moves image bytes out of the board file. Each image becomes an immutable record in IndexedDB on the device and one file under assets/ in the sync repo; the board keeps a reference measured in bytes. Push uploads what the remote is missing before the board, pull downloads what the device is missing, every image transfers once, and both devices end up with everything offline. Two ceilings retire together: the 1MB read cap that split phone and laptop, and the browser's ~5MB board limit. Existing images migrate out on next load; exports still embed everything, so backups stay lossless and readable by older builds.
108 tests green, 5 commits, migration and rendering and lightbox and reload all verified in a real browser.
The night the agent learned to listen
July 19, 2026
The agent learned to listen
The biggest fix was not code, it was attention. Messages typed into the status chat used to sit unread until someone typed in the terminal. A file watcher now wakes the agent on every chat message and every intake press; it is part of the session-start ritual for all future agents, and the pause/stop buttons that ride on it got their first real use within the hour.
The graph, redesigned
The old stacked columns were rejected; three rounds of sketches converged on the staircase, now built: a horizontal trunk that reads as a timeline, one path of children stepping down under whichever node is selected, +N pills for collapsed siblings, blue dots on anything new since the last look, and the whole thing walkable with arrow keys.
App and chat
Typing got 60x cheaper. It cost 13ms per keystroke on a 2MB board because every key saved everything; it is 0.2ms now, saves settle 400ms after typing stops and flush on blur.
The background flash is gone. The same hunt found image lazy-loading chasing this stutter in the wrong place and blanking every picture for a few frames.
Small ones.Ctrl+Shift+V pastes a real unlinked copy, and dropping a task on a group header lands it first.
Question cards work as asked. Pick an option, still comment under it, or write a custom one, and the next open question lights up. Agent board edits flow through History like a second user named Claude.
23 commits in one evening, 100 tests green, every interface change verified in isolated browser pages before touching the live tab.
Phone gestures: hold to move, hold longer to grab a bunch
July 18, 2026
The gesture spec, built
A tap selects. A sideways drag indents or outdents. A press held under 1.5 seconds arms move, now from anywhere on the row, not just the grip. Hold past 1.5 seconds and it flips into drag-select: the row joins, sweeping takes every row the finger crosses, and a fast sweep fills the range so it cannot skip rows. Release, hold another row past 1.5 seconds, and it joins too. A plain tap starts over.
Two fixes rode along
No sideways pan. Wide content clips instead of dragging the whole page around, which was also what kept stealing the indent swipe.
Alt+Left no longer triggers browser Back. On a selected row, Alt+Left and Alt+Right outdent and indent, the keyboard twin of the swipe. The status page swallows the shortcut too.
98 tests pass, one new for the selection logic. Evening addition: the status chat now wakes the agent, and desktop notifications got three fixes: run-complete and input-needed fire while the page is open, an unfocused tab counts as away, and a profile that never granted permission shows a "click to allow" button. The running dots stop lying too, a dead server clears them in seconds.
New tasks start empty
July 17, 2026Focus mode already created empty tasks; the board caught up.
What changed
New tasks start empty. The + button, Enter on a task, and Enter on a group used to insert "New task", and if focus slipped that placeholder stuck as a real name. All three create an empty task with the caret ready now. Focus mode already worked this way; the board caught up.
Ctrl+Z keeps its place. Every undo silently reset the selection to the first node and scrolled there; it stays in place now. Testing found a third bug free: + button tasks were never undoable at all.
Enter on a parent behaves. A group opens and adds a task at its top. An expanded parent gets the new item as its first child; a collapsed one gets a sibling right below and stays closed. Splitting text mid-sentence is untouched.
87 tests pass, 3 new for these fixes.
The project now runs its own status board
July 17, 2026
What changed
Not one line of app code. The app, the 83 tests, & the build are untouched. Everything below lives in a new status/ folder.
A live status board at http://localhost:4173/. Stages, blockers, to-dos, known issues, & feature ideas — as an actual Punchlist board, because the page embeds the real app. Arrow keys, Tab to indent, drag, search, focus mode: all of it works, & every improvement to the app improves the status board on the next rebuild.
A flow diagram on top. Foundation → Sync & funnel → Mobile & touch (collect → audit → fix) → Research → Sharing, with the active stage highlighted.
It's two-way. The board & the file status/status-board.json mirror each other every 2 seconds, in both directions. Edits made on the board reach Claude; edits Claude makes appear on the board. A "To Claude" group at the top is the instruction inbox.
It starts itself. A session-start hook launches the server whenever this project opens in Claude Code. The server is 45 lines of Node with zero dependencies, same as everything else here.
One safeguard worth naming: the app generates a signing keypair on boot, & on the first sync it landed in the shared file. Both the page & the server now strip identity before anything is written, & the file is checked clean.
How to use it
Open http://localhost:4173/ during any Claude Code session on this project.
Edit it like any board — check things off, reorder, add notes.
Dump anything into Braindump at the top. Claude does not read that group until you press the Intake braindump button next to its name; then everything gets triaged into the right groups with priorities, & duplicates get checked against what's already tracked (open issue? unbuilt idea? already shipped?) & merged instead of doubled.
Agent_Active shows what's being worked on right now. Add to it when you want; a legend in the header names the three backdrop colors — purple glow for the item being worked this minute, blue for agent-added rows, green for yours. Finished items fold into a collapsed Completed row so only actionable things stay visible.
A purple ACTIVE bar at the very top names what the agent is working on this minute — click it & the page jumps to that item, which carries a slowly glowing purple backdrop. While a braindump is being processed, the Intake button itself glows & reads "Intaking braindump…" until the group is empty.
Press Chat in the top bar to talk to the agent without a terminal. Messages travel through a local file; nothing leaves the machine.
Press Graph for the execution graph: one thread from recently-completed through the glowing active item into the queue ahead (forking where work parallelizes), with named agent chips riding the items being worked. Drag to browse — it glides back to the active item after 15 seconds. The bottom edge drags to resize.
A hosted snapshot of the same board lives at the project's private artifact link; it's rebaked when the status changes. The snapshot is view-only in spirit: edits there don't reach Claude & reset on reload.
v1.3.0: named devices in history & signed exports
July 16, 2026
What changed
Every change now says which device made it. Settings has a new Device name field. Name each device once ("laptop", "phone") & from then on, expanding a history entry shows the device next to the timestamp, & every sync commit reads like punchlist sync (edit, laptop). Your repository's commit list becomes a per-device audit trail for free.
Settings → Sync lists your devices. Every device that saves to the board appears with its name & when it last saved, most recent first.
Board exports are now signed. The board holds one signing key per user (created silently, synced to your other devices through your private repository). Export JSON attaches your username, a short key fingerprint, & a cryptographic signature over the whole board.
Imports check the signature. Importing a signed file tells you, in one toast, whether it verified & whether you've imported from that sender before. A file changed after it was signed gets a blocking warning before anything is touched.
Imports leave a trace. The history now records "Imported a board from JSON, signed by Evren (f63a1e17)" so you can see later where a board came from.
83 automated tests pass on this build, 6 of them new. The signing round trip also ran in a real browser: two fully separate browser profiles exchanged an export, & the second one recognized the first by key on the second import & refused a tampered copy.
How to name your devices
Open Settings on each device.
Fill Username once (it syncs; it names you, not the machine).
Fill Device name on each device separately (it never syncs; that's the point).
Settings
UsernameEvren
Device namelaptop
Signing identity: Evren · f63a1e17
Skipping the device name costs nothing but readability: unnamed devices show as device plus the last 4 characters of their id.
What an import tells you now
"Imported a board from Evren, the first import from this sender." New key. The board remembers its fingerprint from here on.
"Imported a board from Evren, the same sender as before." Same key as last time. This is the guarantee that matters when boards travel by email or chat.
"This file's signature does not match its content." The file was edited after signing, or corrupted. You choose whether to import anyway; declining leaves the board untouched.
Old, unsigned exports still import exactly as before; the toast just says so.
What the signature proves, & what it doesn't
It proves the file was produced by the holder of a specific key & untouched since, which is what "same sender as their last export" needs. It does not prove a legal identity, & the sender name is self-chosen; only the fingerprint is checked. The private key never leaves your own storage: exports carry only the public half, & the automated suite has a test whose whole job is to fail if a private key ever lands in an export. The full design record, including diagrams of every flow, is in docs/IDENTITY.md in the repository.
What's next
The funnel is declared done-for-now, & the next direction is written up in docs/DIRECTIONS.md: mobile & touch refinement driven by a real friction list, with the phone-capture loop running alongside as the test bed. The same file holds a ponytail audit of the codebase (verdict: lean; about 107 removable lines across 4 findings, zero dependencies to cut) & the skills matched to the mobile work.
v1.2.0: sync between your devices, the demo un-cropped, & an iOS storage warning
July 15, 2026
What changed
GitHub sync shipped. Your board can now live as one JSON file in a private GitHub repository & every device that points at it stays current. Details & setup below.
The landing demo no longer crops. The app's own stylesheet pinned the demo body to the frame's height & hid the overflow, so everything below 640 pixels was cut off with no way to scroll. The demo now reports its real height to the page & the frame grows to fit; the frame only ever grows, so the page below it doesn't jump while the demo animates, & the stray scrollbar that flickered during animation steps is gone.
Phone layout works in the embed. At 390 pixels the framed demo now renders the same layout the app uses on a phone, full width, every group reachable.
Two clear ways in. The hero now has "Open the board" (runs at this site's URL) & "Download the board" (the identical file, saved to disk, works offline forever). Same 266,809-byte file behind both buttons.
Demo theme obeys the page. The demo used to remember dark mode forever once it had seen it; it now follows the embedding page on every load.
iOS Safari gets a one-time warning. Safari deletes a site's stored data, tasks included, after 7 days of Safari use without visiting that site. Web apps opened from the Home Screen are exempt, so the board shows one dismissible banner on iOS Safari pointing at Share, then Add to Home Screen. On every platform the app also asks the browser for persistent storage on load.
77 automated tests pass on this build, 8 of them new for sync. Every sync path (first push, edit push, pull, conflict) also ran in a real browser against a mocked GitHub API before shipping.
How to turn on sync
Sync v1 assumes you have a GitHub account. It costs nothing: a free account includes unlimited private repositories.
Create a private repository to hold the board, for example punchlist-data. Empty is fine; the app creates the file itself.
Create a token the board will use. On GitHub: Settings, Developer settings, Personal access tokens, Fine-grained tokens, Generate new token. Under "Repository access" pick Only select repositories & choose the repo from step 1. Under "Permissions", set Contents to Read and write. Nothing else. That token can touch that one repository & nothing more.
Enter both in the app. Open Settings, expand Sync, tick GitHub sync, then fill the two fields. It should look like this:
Sync
GitHub sync✓
Repositoryevrenucar/punchlist-data
Tokengithub_pat_••••••••••••
Sync now
Synced 14:32
Repeat step 3 on each device: open the same board URL (or file) there & paste the same repository & token. The first device to sync fills the repository; every later device pulls that board on its first sync.
Order matters once: do this first on the device whose board you want to keep. Its first push becomes the shared board, & the other devices adopt it. Their previous local boards are replaced (a backup lands in History, & you can export JSON first if you want belt & braces).
How sync behaves day to day
The board pulls when it loads & whenever its tab regains focus; it pushes 2.5 seconds after you stop editing. There's a Sync now button when you'd rather not wait.
Every push is a git commit. The repository holds the board's full history, so any earlier state is recoverable from GitHub's own interface.
If two devices edited while apart, the device that syncs keeps its version & the other version stays one commit back in history; a toast tells you when that happened. No silent data loss, no merge screens.
The token & repository name stay in this browser only. They're stored apart from the board, so JSON exports & settings exports can never contain them.
Per-device things (theme, sidebar width, export preferences) don't sync; tasks, groups, images, Completed & Trash all do.
Ceiling to know about: GitHub's contents API caps the file at about 1 MB. Compressed screenshots run 50 to 200 KB each, so it's roomy but not infinite; the app tells you if a sync ever hits it.
Why the iPhone popup exists
WebKit's tracking prevention wipes a site's script-writable storage after 7 days of Safari use without a visit to that site. A task board you open daily is safe; one you leave for a week on a trip isn't. Adding the board to the Home Screen exempts it, & with sync on, the GitHub copy survives regardless. The banner shows once & never returns after "Got it".