Releases
Thursday (August 6)
Voxprint macOS 1.3.6 shipped live today — Apple approved the rename build I pushed five days ago. iOS 1.3.6 is still waiting in review (submitted Aug 3), so the Mac version sneaked through first. Updated the App Store landing page to point at voxprint.heyitsmejosh.com and fixed a stray marketingUrl reference that was still pointing at the old echo domain.
Finished Inkpress’s overdue redesign tonight. The icon had become a invisible hairline sketch on dark—swapped it for a bold amber nib glyph. Added a real loading spinner to the feed view so it doesn’t feel frozen during background syncs. Built out a landing page at inkpress.heyitsmejosh.com on Cloudflare Pages (DNS verified, live), so it actually has a storefront now instead of just an App Store link.
Migrated Healstack from Vercel to Cloudflare Pages. The wrangler config had gotten tangled trying to be both at once, so stripped out the Vercel-only settings and redeployed. Restyled the landing page to match the Lexly design system (header, hero, features, status grid).
Completed the Lexly masterclass integration—built the converter script and shipped all 15 book summaries live. Found and fixed a converter bug on the first run (h3 subheadings weren’t handled, fell into an infinite loop instead of erroring). Widened the check to catch any heading level and reran clean.
Litigate got light-mode support with manual override toggle (detects system preference via prefers-color-scheme). Designed a minimalist gavel SVG for the favicon and PWA manifest that reads clean in both themes. Fixed a stray sign-in screen that still said “Brief” instead of “Litigate” on both iOS and macOS—the app renamed July 18 but the Text() view got missed.
Swept through roadmap consolidations across seven repos (epiphany, sparkjar, lexly, litigate, uprighty, nyc, talli), merging duplicate entries and pruning stale items. Verified Sparkjar’s Vercel production already has the right env vars wired, and confirmed the consolidation passes didn’t miss anything actionable.
Added seven new skills to dotfiles: mail-sweep, wrapup, architecture-svg, duolingo, git-sweep, localization-sweep, and trakt. The trakt skill was built earlier with a stdlib-only Python OAuth device-code client; the others scaffold the next batch of automations.
Friday (August 7)
Renamed the Uprighty app to Bookrank tonight after App Store Connect rejected “Uprighty” as a duplicate. Tried and landed on “Bookrank” after cycling through Shelved, Stacked, Booknook, Bookline, and Litshelf (all taken). Propagated the rename everywhere: ASC app record (appInfoLocalizations), GitHub repo from nulljosh/uprighty to nulljosh/bookrank with local git remote updated, domain moved from spine.heyitsmejosh.com to bookrank.heyitsmejosh.com (Cloudflare CNAME added and old one deleted), repo CNAME file, README, metadata JSON (supportUrl/privacyPolicyUrl), iOS/macOS CFBundleDisplayName/CFBundleName, and regenerated the Xcode project via xcodegen. Updated the portfolio site index.html link. All changes committed and pushed across uprighty/bookrank repo, nulljosh.github.io, and the Code meta-repo. Deliberately left the local folder at ~/Documents/Code/uprighty (not renamed).
Spent the evening fixing Epiphany’s bank-statement upload feature. The Blob store had been set as public by default, but the code needs private access for sensitive statements — and Vercel won’t let you change a store’s permissions after it’s created. Created a new private Blob store and repointed the code to use its token explicitly via EPIPHANY2_READ_WRITE_TOKEN. Also verified the deploy pipeline was actually working end-to-end (push-to-Vercel confirmed via the API), since earlier reports that it was “still broken” made me wonder if deploys were even firing at all.
Filed two stray Apple Notes into the system tonight: a personal note about money owed with Mom got moved into the wiki’s personal-accounts page, and a vague “Lexly Mac OS Issues” note was expanded and logged into Lexly’s roadmap. Cleared out the Notes inbox completely after that.
Later in the night, fixed Epiphany’s avatar lookup returning 500 errors — the Blob store SDK’s keys() method wasn’t being called correctly. Also tightened up the search suggestion dropdown appearance over busy map terrain (changed from ultra-thin to regular material for readability). Went through and pruned nine completed items from the roadmap to keep the backlog manageable.
Fixed the portfolio memoji avatar tonight—been bothering me for months that it looked fuzzy. Turned out the source was just a 128px screenshot; swapped it for a proper 512px cutout with the background removed and now it reads sharp. First pass cropped a bit too tight and clipped the chin—recropped with padding around the face and it’s right now.
Saturday (August 8)
Cleared the Apple Notes inbox—11 items archived. Fixed two critical bugs that had blocked shipping: Voxprint iOS 1.3.6 and Bookrank iOS 1.0 were stuck in review with phantom rejections, so I cancelled and resubmitted each via the API (now WAITING_FOR_REVIEW). Verified two other things that looked like bugs but weren’t: Portfolio’s animoji is actually live, and Sparkjar’s old TestFlight icon is just a stale build. Shipped Lexly’s branded splash and login logo (native SwiftUI), and wired up Epiphany’s Yelp location hours as open/closed badges across the app and web (live now). Also checked personal finances and filed an idea to the wiki.
Sunday (August 9)
Added error handling and diagnostic logging to Epiphany’s avatar upload flow—the KV and Blob store calls were missing try/catch blocks. This is a diagnostics pass on yesterday’s 500-error fix, so the real root cause should surface more clearly if it happens again. Fixed the ship-mac workflow after the ASC CLI renamed a parameter (--pkg-path became --ipa-path), and added --overwrite to avoid stuck uploads. Verified that Litigate’s RLS policy for case documents already has the WITH CHECK guard we were looking for, so no code fix was needed there—just marked it done in the roadmap.
Spent the evening processing book summaries for the Bookrank site. Finished three new chapters of “The Optimist” (Sam Altman/OpenAI biography)—prologue, chapter 1, and chapter 2—and published them live with a badge. Discovered that “Data Science For Dummies” had silently sat incomplete for weeks; the memory note claimed it was done, but chapter 20 was never summarized and 175 raw photos were still sitting in the backlog untouched. Cleaned and summarized chapter 20, so that book is now genuinely complete. Started “AI in Business For Dummies” and summarized the introduction chapter. Had to trace through the folder history (spine→uprighty→bookrank repo renames) and re-clone the project locally since the original wasn’t on disk anymore.
Finished clearing the entire book-photo backlog tonight. Wrapped up three new books for the site: AI in Business (chapters 1–2 with badge live), Accounting for Canadians (intro through chapter 3 with badge live), and macOS Tahoe (intro plus chapters 1–2 with badge live). The queue is genuinely clear now except for one book that’s still waiting to have its chapters photographed.
Spent the late evening debugging App Store Connect review statuses. Found a real bug in the asc-login script—it was asking for a 2FA code before ever contacting Apple, which is backwards. Rewrote it to call asc web auth login directly and let Apple’s prompt drive the flow. Upgraded the asc CLI to the latest version, but login kept failing with an SRP signin error even after the fix; suspect it’s a cached terminal session and needs a fresh tab to resolve. Investigated four apps with genuine App Review rejection reasons (Transcriptly, Wiretext, NYC Survive, Curvely) that aren’t exposed via the public API—they all need dashboard access to see the actual rejection text. Tried fixing Curvely’s empty release notes but discovered Apple doesn’t allow first-version apps to set What’s New (no prior version to diff against), so that’s not a bug to fix.
Earlier tonight: Epiphany’s map search suggestion dropdown now has an opaque backing so the map terrain doesn’t bleed through and make the suggestions unreadable. Also closed out the stale Echo-to-Voxprint web copy item in the roadmap. Late evening: Inkpress v1.0.3 shipped. The 2026-08-06 icon redesign and loading indicator had never shipped—bumped to v1.0.3 (build 202608092030) and rebuilt the stale App Store screenshot (seeded 4 demo feeds into the sim: journal, Daring Fireball, The Verge, Hacker News; captured on iPhone 14 Plus at full 1284×2778 pixels in light mode). Fixed two blockers: the icon 1024px file had an alpha channel, which failed Apple’s ITMS-90717 validation (flattened it onto opaque #161412), and added encryption compliance flags to the build + Info.plist. Fixed a stale CLAUDE.md note about the scheme name (was -scheme Inkpress, real scheme is Journal-iOS). Submitted v1.0.3 for review. Simulator shut down and quit.
Rewrote Newsline tonight — turned it from a website into a dependency that other people’s code can call. Added query params to the API (/api/stories now filters by view, outlet, bias, blindspot, plus full-text search and limit), and built an MCP server at /mcp with two methods (get_news and get_blindspots) to integrate with Claude and other agents. Wrote the API docs (OpenAPI spec) and security policy. Surfaced three production bugs while testing against live feeds: the CDN was caching query-string variants as the same response (responses now go no-store to avoid collision), filtering was happening after the 120-item cap so low-volume outlets had nothing left to return (reordered to filter first), and the feed parser was only matching RSS <item> elements, never Atom <entry>—Daring Fireball had been silently contributing zero items since it was added. Also added HTML entity decoding for titles. Pruned five feeds that weren’t returning anything (Reuters, AP, MSNBC, CTV, Washington Post); 17 outlets now remain, each verified live against real feed pulls.
Also recovered Cadence’s source code tonight from a Vercel deployment snapshot and migrated it to Cloudflare Pages Functions—the stats view and heatmap are now working on the new platform. Lexly got a forgot-password reset flow wired in. Nimble’s web app moved to Cloudflare Pages too, and I fixed a payload-key bug in the answer proxy.
Finished the Newsline distribution push later tonight. Published the MCP server to the official registry as io.github.nulljosh/newsline (status active, remote streamable-http). Added GitHub topics to the repo and rewrote its description to say “MCP server + JSON API” so people discovering it know it’s a dependency, not just a website. Advertised both the API and the MCP server on the site itself (footer with curl + claude mcp add lines, links to llms.txt and openapi.yaml for docs). Also drafted Show HN and r/mcp posts and opened a PR to the official awesome-mcp-servers list on GitHub (opted into their fast-track PR review, should see feedback within a day or two).
Audited all projects under ~/Documents/Code for password-recovery and email-verification gaps. Added forgot-password flows to Lexly and Litigate—both now send email reset links and verify the token before allowing a password change. Sparkjar added optional signup verification emails (soft gate, existing accounts grandfathered, login never blocked). BCGD’s dashboard auth screen got rewritten to support password recovery for admin sign-in. All code pushed. Lexly deployed live to Cloudflare Pages (project lexly-heyitsmejosh, verified at lexly.heyitsmejosh.com/app/; forgot-password flow working). Litigate deployed live to Cloudflare Pages (project litigate, verified at litigate.heyitsmejosh.com). Sparkjar deployed to Vercel production (verify-email endpoint returns 302 as expected). Critical finding: sparkjar has no SMTP env vars on Vercel and never has—both the password-reset and new email-verification flows ship successful responses but silently no-op on sending. Fix is Resend (epiphany already uses it), not SMTP: needs RESEND_API_KEY env var, sparkjar domain added to Resend + DKIM/SPF records in Cloudflare. Logged to sparkjar/roadmap.md. Not fixed this session.
Late evening audit of every app’s authentication state. Found that Sparkjar was assumed to be the last one needing password recovery and email verification, but it’s actually the most complete—it has both implemented, though mail.js silently no-ops on Vercel without SMTP environment variables. Epiphany, Healstack, Litigate, and Roost already have both features working. The real remaining work is Talli (has neither forgot-password nor email verification built yet) and Lexly (signup and login UI only, no recovery or verification paths). Added three roadmap items: sparkjar needs SMTP_HOST/USER/PASS/FROM verification in prod, Talli needs both features built, and Lexly the same.
Monday (August 10)
Spent tonight on a comprehensive dead-code cleanup pass across the entire codebase. Scanned all fifty directories under ~/Documents/Code and ranked them by ship status, then ran a symbol-verified pass to identify and delete actual dead code—not just by filename, but by checking every reference to confirm nothing was still using it. Deleted verified-dead files from epiphany (five dead components and hooks in src/, plus two macOS Swift views), healstack (three dead hooks and pages), talli (iOS services and trimmed a dead AppTheme struct), litigate (one dead test fragment), and untracked over five thousand committed node_modules files from wiretext and sparkjar to clean up the repos. Every deletion included a build verification step to ensure nothing broke.
Ran a second pass on the twelve remaining git repos (sparkjar, bcgd, cadence, fengshui, journal, nulljosh.github.io, nyc, etyma, quotable, labs, dotfiles, plan) and found zero real dead code—every hit was a false positive (SwiftUI @main entry points, .selfcheck.js files, Vercel filesystem routes, hand-run scripts, dotfiles templates). Archived two superseded no-git directories (grapher, the leftover after grapher→curvely rename, and braingraph, the retired version of notes/brain) into a single dated tarball and removed both from ~/Documents/Code to clean up the cruft. Notable finding: talli’s CSVExporter was documented as a shipped feature in talli/ios/CLAUDE.md but had zero code references—deleted both the dead code and the stale documentation line.
Late evening: 2FA unlock finally let me read the actual App Store rejection reasons from the Resolution Center, then cross-checked against production code and git history to verify the root causes. Sparkjar iOS 1.0 (reviewed 08-03, build from 07-19) got Guideline 2.1(a): Apple’s repro said Sign in with Apple errored, sign-up errored, server error elsewhere. The reason turned out simpler than expected: the 07-19 binary hardcoded baseURL = "https://spark.heyitsmejosh.com", a host that no longer resolves. Commit a458002 (08-03) repointed clients to the live sparkjar.heyitsmejosh.com, but that was too late for the build already in review. All three symptoms collapse to network failure from dead DNS. Mail/Resend work is real but unrelated to this rejection. Just needs a rebuild + resubmit. Healstack v1.0 (reviewed 08-05, build from 07-21) got the same Guideline 2.1(a) with just “Unable to log in.” Chased the “login was fixed 08-04” claim but git shows zero code changes to AuthService since the reviewed 07-21 build—iOS login path is byte-identical to what Apple rejected. iOS auth talks directly to Supabase, not the web host. Most likely: missing demo account (Apple’s report is bare with no repro). Secondary suspect: Supabase allow-list drift after Cloudflare migration. Also confirmed: the inAppPurchaseVersion label is garbage (type-code mislabel), mis-diagnosed three times across apps. Lesson: verify a rejection against production code and git before trusting a roadmap’s root-cause theory.
Late evening, tracked down why asc-login had been silently failing for days. Turned out the macOS Keychain held two conflicting asc-web-password entries—one from June (stored with a stale password) and one from early August (with the current password after the Apple ID change). The wrapper script was explicitly passing the old one via an env var, which kept overwriting asc’s own good credentials. Deleted the stale keychain item and rewrote the script to let asc read its own credential store instead. Drove a fresh login end-to-end through a 2FA code to verify; asc web auth status confirmed authenticated with team 129029900. App Store Connect web workflows are unblocked.
Pulled the complete rejection reasons for Curvely, Wiretext, NYC Survive, and Transcriptly later tonight. All four got Guideline 5.6 review suspensions on August 9 (no resubmission before August 18). Apple’s letter cites “does not meet the required quality standard for distribution”—the real triggers are thin/unfinished apps: Wiretext is 1 Swift file and 72 lines (WKWebView shell), Curvely is 4 files and 150 lines (same), Transcriptly shipped at placeholder version 9.9.9. The language about account removal is standard boilerplate for future submissions, not an existing penalty—I’m still an active Developer Program member and seven apps are still live and selling. Separately: Sparkjar’s Guideline 2.1(a) rejection was verified tonight to be the dead domain (spark.heyitsmejosh.com no longer resolves; the July 19 build hardcoded it, and the fix shipped Aug 3 at 16:36 — four hours after the reviewer’s session started that same day). Healstack’s “unable to log in” rejection is now solved: the demo account healstack.demo@heyitsmejosh.com had NULL values in Supabase’s auth.users email_change and email_change_token_new columns, which caused GoTrue to throw 500 errors on any login attempt (not a wrong-password 400, but a database-schema error). Fixed with a SQL UPDATE to coalesce those columns to empty strings. Same login now returns a clean 400 invalid_credentials instead of a 500. No app code change needed, just rebuild and resubmit after Aug 18. Lexly’s “unable to log in” rejection remains unverified (likely missing demo account). NYC Survive and Wiretext have completely empty App Review notes fields—Apple’s 5.6 letter requires “detailed notes of the improvements made to the app” before resubmission. Found two local build-environment blockers for the Aug 18 rebuild: CoreSimulator is out of date (1051.54.0 vs 1051.55.0, needs sudo xcodebuild -runFirstLaunch to fix), and SwiftLint’s Bazel BUILD file conflicts with macOS’s case-insensitive filesystem on build/ directory creation (fixed by passing explicit -derivedDataPath to xcodebuild). Zero errors came from app code itself—the “just rebuild from current main” conclusion holds.
Ran system updates late evening—bumped ollama and uv, refreshed npm globals (needed a retry when corepack’s self-replace tripped the first pass). Claude Code already at the latest.
Apps
Bookrank: Data Science For Dummies completed (chapter 20 added), The Optimist summary added (prologue + ch. 1–2 with badge), AI in Business intro started. Voxprint macOS 1.3.6 shipped live, iOS 1.3.6 released and now live on App Store, roadmap Echo→Voxprint web copy item closed. Inkpress v1.0.3 WAITING_FOR_REVIEW (shipped icon redesign + loading indicator + refreshed App Store screenshot + icon alpha flatten + encryption compliance). Healstack migrated to Cloudflare Pages with refreshed landing; dead code removed (three dead hooks/pages), roadmap corrected (v1.0 is REJECTED not WAITING_FOR_REVIEW). Lexly integrated 15 masterclass summaries (converter infinite-loop bug fixed) + branded splash/login logo shipped + forgot-password reset flow added + nav declutter + simplified icon + _headers for asset TTL (Cloudflare Pages live). Litigate added light mode + gavel icon + fixed Brief→Litigate sign-in text + verified RLS policy already had WITH CHECK guard + forgot-password reset flow added (Cloudflare Pages live); dead code removed (test fragment). Sparkjar provisioning profiles created (CY2V3B846P + H9YQZ34MV5, both ACTIVE); added optional email verification on signup (soft gate, existing accounts grandfathered, login never blocked; requires SMTP env vars to send); node_modules untracked. BCGD dashboard rewrote auth to support password recovery (build clean). Bookrank renamed from Uprighty (ASC duplicate rejection), domain/repo/app-display-names/metadata all updated, iOS 1.0 resubmitted after fixing stuck review. Epiphany’s bank-statement upload fixed (private Blob store provisioned), avatar 500 error fixed with diagnostic logging added, search suggestions now opaque with improved readability over map, Yelp location hours now showing as open/closed badges across iOS/macOS/web, venue pins now cluster on iOS/macOS, ship-mac workflow fixed for ASC CLI API change; five dead components/hooks and two macOS views removed. Newsline v0.3.0: turned into API + MCP server dependency (query params for filtering, openapi.yaml + security docs), published to MCP registry (io.github.nulljosh/newsline), three production bugs fixed (CDN cache collisions, filter-before-cap reordering, Atom entry parsing + entity decoding), 5 dead feeds pruned (Reuters/AP/MSNBC/CTV/WaPo), 17 outlets verified live. Cadence recovered from Vercel backup and migrated to Cloudflare Pages Functions (stats + heatmap working), roadmap added with remaining migration steps. Nimble web migrated to Cloudflare Pages, answer-proxy payload key fixed. Talli: Messages pagination fixed (walk MessageList pages, 10 → 23 messages), dead code removed (iOS services, AppTheme struct trimmed from 53→40 lines), roadmap item added for email verification + forgot-password flow. Wiretext: node_modules untracked. Fengshui: migrated from Vercel to Cloudflare Pages. Roadmaps consolidated across seven repos, nine completed items pruned. Seven new skills added. Apple Notes inbox cleared (11 items).