9:30
GS
Gratitude Summary
Today 9:30 PM
Look at all the GOOD that is happening! • Had lunch with the kids and just laughed the whole time • Finished the project ahead of deadline • Watched the sunset from the back porch “Gratitude unlocks the fullness of life. It turns what we have into enough, and more.”— Melody Beattie
AI Automation July 2026

I built a Gratitude Tracker
Orchestrating Three Ecosystems Into a Nightly Ritual

Claude CLI iOS Shortcuts Google Apps Script OpenAI (GPT-4o + web search) Google Sheets bible-api.com

It’s not an app. It’s three different ecosystems, orchestrated into a single workflow. Dictate a blessing anytime, get the full recap and an encouraging quote every night, and watch a live dashboard grow.

Step 1 · Log

Dictate a blessing, anytime

Tap a Home Screen Shortcut and just talk. Mention more than one good thing — lunch with the kids, then the dog learning a new trick — and GPT-4o splits them into separate entries, each tagged with a theme: family, provision, rest, faith, adding rows for each in the sheet.

Step 2 · Recap

9:30pm, every night

An iOS Personal Automation quietly fetches the full day’s list, adds an encouraging quote, and texts it. A nightly gratitude reflection.

Step 3 · Revisit

A living archive

A hosted dashboard fetches the same data live and shows the running history, every blessing, every night’s quote — a growing record of all the good in life.

Three ecosystems, handing data off to one another over plain HTTP.

Apple · iOS
Shortcuts App
Tap a Home Screen Shortcut and just talk. Data is sent to Google Apps Script.
Apple · iOS
9:30pm Automation
Fires on a schedule, no tap needed, and requests the nightly recap.
Google · Cloud
Apps Script — parse & tag
GPT-4o splits the dictation into blessings and tags each with a theme.
Google · Sheets
Blessings Log
Every blessing is logged as its own row, timestamped and themed.
Google · Cloud
Apps Script — build recap
Reads today’s rows and kicks off the quote pipeline.
OpenAI
Web search & verify quote
Finds a quote via web search, then verifies it’s really on the page.
Google · Sheets
Nightly Summaries cache
Caches the finished recap so it’s only generated once per day.
Apple · Messages
A text, waiting for you
The recap arrives as an iMessage, ready to read and set your mind as you prepare for sleep.
Look at all the GOOD that is happening!

• Watched the sun rise

• Coffee was extra good this morning
JSON endpoint
Live dashboard
Fetches the same JSON live and renders the running archive. Ready for future reflection.
Wed, Jul 29
Watched the sun rise
Coffee was extra good this morning
Tue, Jul 28
Finished a big project at work
Long walk with the dog

Both sheet tabs live in one spreadsheet; a single shared-secret key gates every request across all three systems.

The Quote Pipeline

AI often hallucinates and I don’t want fabricated quotes so I built this verification loop.

1

Search the live web

OpenAI’s Responses API, with its web_search tool, is asked to find one real quote fitting that day’s themes — grounded in an actual page it searched, not generated from memory.

POST /v1/responses · tools: [web_search]
2

Verify it independently

The script re-fetches the exact cited URL itself and confirms the quote text is genuinely on the page — retrying a few times first, since free content sites occasionally have transient hiccups unrelated to accuracy.

3

Fall back to a live Bible verse

If verification doesn’t succeed, the best theme-matching reference is picked from a 33-verse bank — and the actual text is fetched live from a Bible API every time, never typed out or recalled from memory.

GET bible-api.com/{reference}?translation=kjv
4

One hardcoded safety net

Reached only if the Bible API itself is unreachable: a single, pre-verified line (1 Thessalonians 5:18, KJV) — so the message is never empty and never wrong.

Outcome

A nightly ritual, fully orchestrated, with zero fabricated content

  • Three ecosystems, Apple, Google, and OpenAI, wired together over plain HTTP behind a single shared-secret key
  • A verification-first quote pipeline: live web search, then an independent re-fetch to confirm the quote is real, then a live Bible-verse fallback, then one hardcoded safety net — never a quote taken on faith
  • A nightly recap that arrives on its own at 9:30pm, no tap required, and a live dashboard that grows every day

Built with Claude Code — Apps Script, iOS Shortcuts, and a verification-first approach to AI-generated content.

FieldPay Talent app, mobile opportunity and payout screens
FieldPay · Fintech Aug – Nov 2025 · UX Design Lead, Contract

Designing FieldPay's Two-Sided MVP

Figma User Flows Wireframing Design Systems

FieldPay pays trades workers the same day a job is done, not on the next payroll cycle. I was brought on as UX Design Lead to design the two apps that make that possible, one used by a business owner at a desk, the other by a technician standing in the sun with gloves on.

Problem

Labor is the #1 cost center in the trades, and owners are stuck being the bank

FieldPay's own research with pool, HVAC, roofing, and pest-control owners was blunt about it: labor was their single biggest pain point, hiring cycles were running $1,600+ per replacement, and techs would leave for whoever paid fastest. Owners wanted to reward good work, cover a same-day emergency call, or incentivize a slow route, but doing it meant waiting for the next payroll run. The gap between "the job's done" and "you got paid" was where trust broke down.

Constraint

A tight scope, held to on purpose

The engagement was three months, phased, with a defined deliverable at the end of each: workflows, then wireframes, then handoff-ready visual design for two apps, Admin and Talent. Marketing and brand work was explicitly out of scope, so the design effort stayed pointed at the product two founders and I reviewed together two to three times a week. Keeping that boundary is what let a three-month engagement produce two fully specified apps instead of one half-finished one.

Phase 01

Turning a product spec into flows two very different users could follow

The starting point was a founder-written product spec: campaigns (job-specific or general cash incentives), a mixed roster of W-2 and 1099 workers, proof-of-work requirements, and a payout lifecycle that had to stay auditable. My job was to map that into concrete paths, campaign creation, talent roster management, and campaign monitoring on the Admin side; opportunity discovery, claim, proof submission, and cash-out on the Talent side, before a single screen got drawn.

Admin app splash screen with the FieldPay logo Admin app onboarding screen introducing Opps, FieldPay's instant-pay opportunities Admin app campaign templates, choosing between a specific job and a general incentive with pre-filled rate and description Admin app first campaign confirmation, inviting the team to join via a shareable link Admin app talent roster, list of workers with 1099/W2 filters and search
Admin App — Campaign Creation Flow

Business owner configures a cash incentive from a community template or from scratch: rate type, a W-2 and a 1099 rate, proof-of-work requirements, and an optional GPS check-in, then assigns it to talent from the roster.

Phase 02

One product, two rulebooks

The Admin app is used at a desk, in a slow moment, by someone who wants density and audit trails. The Talent app is used in a truck or on a roof, one-handed, often in direct sun, by someone who wants three taps and a clear answer. Wireframing both side by side meant writing a separate set of design rules for each before drawing a single screen, so speed for one side never came at the cost of clarity for the other.

Design Rule Talent App (Field) Admin App (Desk)
PriorityGlare-friendly, high contrast, large bold typeStatus at a glance, color-coded, scannable
Interaction48px minimum tap targets, 1–3 taps per actionInline editing from the list view, with autosave
ResilienceOffline-tolerant, local autosave, deferred syncReal-time refresh with a visible "last updated" stamp
Trust signalPush-first: pay and location visible without opening the appFull audit trail: who created, edited, reassigned, or deleted
Talent app splash screen with the FieldPay logo Talent app opportunity detail, a $100 residential pool filter clean with location, description, and a Request Instant Pay button Talent app opportunity feed, a map of nearby jobs with rates like $20 Service Call and $200 Pool Route, plus a scrollable list below Talent app payout request, proof-of-work photo upload before submitting for approval Talent app payout confirmation notification, you got paid $100 for a residential pool clean
Talent App — Opportunity Feed & Claim

A worker browses open incentives on a map or list, rate, location, and time-to-expire visible up front, and claims or counterbids in one or two taps.

Phase 03

From wireframe to a handoff package engineering could build from

The final phase moved both apps from structure to finished UI, adopting an existing component library rather than building type and spacing decisions from zero, so the engineering team got a Figma handoff package with interaction notes instead of static pictures. The moment the design had to earn its keep was payout: proof of work submitted, fees shown, cash landing the same day. If that screen didn't read as instant and trustworthy, nothing else in the app mattered.

Payout workflow, the full Figma flow from opportunity claim through proof of work to payout confirmation across both apps
Dual-App Workflow, Fully Annotated

The full payout journey mocked up across both apps, interaction notes, state changes, and edge cases called out directly in Figma alongside component references, spacing, and copy, so engineering could build from it without a separate spec.

Outcome

A validated, handoff-ready MVP for both sides of the marketplace

  • Full workflow diagrams, wireframes, and hi-fi UI delivered for both the Admin and Talent apps
  • A documented set of design principles, one for field conditions, one for desk conditions, that now governs how new features get built
  • A Figma handoff package engineering could pick up directly, no separate spec document required
  • Design decisions grounded in the founders' own field interviews rather than generic fintech patterns

This was a pre-launch MVP engagement, so the measure of success wasn't a dashboard metric, it was whether two founders could hand a validated design system to engineers and start building. They could.

Personal Project · AI Automation 2025 · Ongoing

I Didn't Set Out to Build a Job Search OS

Python / Flask Google Apps Script OpenAI API JobSpy TamperMonkey Google Sheets

I started with one goal: stop rewriting my resume for every application. What I built over the following months was something else entirely, a complete job search system that emerged from solving each new bottleneck as it appeared.

2026 YTD · Project Outcome
The goal was never fewer minutes.
Time saved is a means to an end. The end is interviews. Here's what the system actually produced.
—
Interviews
—%
Interview Rate
—
Applications
—
Hours Saved
—
Days Saved
—
Weeks Saved
The Starting Point

Four steps. None of them hard. All of them time-consuming.

Applying for a job online follows a predictable sequence. Find a posting worth applying to. Open your resume, read the job description, identify key requirements, rewrite bullet points, adjust terminology, optimize for ATS keywords, then export. Open the application, upload the file, fill in your name and contact details, paste your LinkedIn URL, paste your portfolio URL, answer the EEO questions. Log it: company, title, date, status. Repeat.

None of those steps are hard. But each application took 15–20 minutes. At job search volume, that overhead adds up to weeks of mechanical work, time that should go toward the parts that actually require judgment.

The manual application loop, four steps from finding a posting to logging it manually
Phase 01

From blank resume to tailored application package, in 10 seconds.

The most time-consuming step was also the most systematic: customizing the resume. I built a pipeline using Google Apps Script and the OpenAI API that takes a job description, identifies the top matching skills and keywords, and rewrites the resume to lead with the most relevant experience.

Quick Apply URL input

Each run produces five things:

Tailored Resume to JDRewritten to match the job description, highlighting the most relevant skills and experience
Custom Portfolio URLA unique ?source=CompanyName link so I can track which employers clicked through to my portfolio
Cover LetterConnects my background to the specific role and company
Fit AnalysisA breakdown of how well my experience maps to the role, including keyword coverage
Tracking Sheet UpdateAll outputs written automatically, one source of truth for every application
Resume automation pipeline output

Initially I triggered the pipeline by pasting the job description into a Google Form. I replaced that with a local Flask app: paste a URL, the job details are fetched automatically, the pipeline fires. No copy-paste. That change surfaced something worth keeping, because every resume already included a personalized portfolio URL, the fit statement and welcome message OpenAI generated became ready-made cover letter material. Content that started as a tracking feature turned into part of the application itself.

15–20 minutes per application. Now 10 seconds.

Tracking spreadsheet showing tailored resume outputs, company, title, resume link, fit statement, keyword coverage, and portfolio URL per application Analytics
Phase 02

One screen. Everything you need to paste.

Generating the resume solved the customization step. But applying still meant tab-switching, job description in one tab, the application in another, the portfolio URL typed from memory. Small friction, repeated hundreds of times.

Quick Apply

I created a Python app running locally that fetches job posting information for review. Clicking "Apply" kicks off the custom resume automation.

Companion app

The tailored resume can now be downloaded, custom links are ready to be pasted into an application, and a custom intro can be used for a Cover Letter, so applying is a matter of pasting, not thinking.

Everything needed to complete an application is in one place: the job description, resume link, custom portfolio URL, fit statement, and cover letter copy, already written, already waiting. A lookup field pulls up any prior application by company name. One click logs it complete.

Phase 03

Stop hunting. Let jobs come to you.

The application steps were faster. Finding jobs was still entirely manual: browsing job boards, scanning listings, deciding what was worth pursuing.

Job feed interface

A scheduled script runs JobSpy against LinkedIn, Indeed, Glassdoor, and others, filtered to the roles and locations I'm targeting. It deduplicates against applications already sent before writing anything, so I never see a posting I've already acted on. New listings land in a Job Feed with status chips: New, Applied, Already Applied, Not Interested.

Clicking a job card fires the description to the Quick Apply panel, which auto-fetches the JD, no URL required. The Command Center loads in the background. The employer's application page opens in the right column when the resume is ready. One click marks it complete and updates the status chip. The entire workflow, from browsing a listing to submitting, in a single view.

Job Feed three-column layout

No more hunting around on separate job boards. Running the JobSpy Python app locally scrapes multiple job boards and delivers curated job postings that I can browse and apply for.

Phase 04

Application history, surfaced where you actually browse.

One gap remained outside the system. Browsing LinkedIn meant landing on postings without knowing whether I'd already applied, or interviewed, or been rejected. Checking required leaving the page and searching the tracking sheet.

A TamperMonkey script closes it. It runs on every LinkedIn job page and queries a local Flask server, which checks the tracking sheet and the job feed for prior activity at that company. The result surfaces inline on the posting: whether I've applied, when, for which role, what the current status is. Multiple interactions with the same company, different roles, an interview, a rejection, all visible before deciding whether to engage again. The system escaped the browser tab.

TamperMonkey script overlaid on LinkedIn job posting
The System Today

Four components. One source of truth.

System overview, four components

Everything runs through Google Sheets as shared state, applications logged, job postings queued, outputs stored, status tracked. Every other component reads from or writes to it.

  • Job postings arrive automatically, deduplicated against applications already sent
  • Resumes generate in 10 seconds, tailored to role type and ATS requirements
  • Application materials, resume, portfolio URL, fit statement, cover letter copy, are staged before the form opens
  • Application history surfaces inline on LinkedIn without leaving the page

The parts that still require judgment, whether a role is worth pursuing, how to position a specific experience, what to say in an interview, get full attention. That was always the point.

Claude as Creative Partner, portfolio redesign
Personal Project · AI Workflow November 2025

Claude as Creative Partner

Figma Claude ChatGPT Photoshop

I first started using Claude Code in July 2025. My first project was to create a new portfolio website. I've always built my portfolio websites manually without the use of template sites like Wordpress or Wix. This time I used Claude Code. Here's how it went.

Problem

The design I wanted would have taken weeks to build by hand

I had a clear vision: scroll-triggered animations, staggered effects on gallery items, a custom lightbox with keyboard navigation, and a responsive layout that worked precisely across all breakpoints. I've built sites in HTML, CSS, and JavaScript before. But reaching that level of precision the traditional way requires a significant time investment, and I wanted to spend that time on design decisions, not debugging CSS.

Insight

AI changes what's worth doing yourself

The design work, layout decisions, visual hierarchy, imagery, copy, was mine to own. The implementation work was systematic: write this component, wire this interaction, fix this breakpoint. That's where AI could compress the timeline without compressing the craft. The question wasn't "can AI design for me?" It was "what's the right division of labor between a designer and an AI execution partner?"

Solution

Designed in Figma. Built with Claude. Iterated constantly.

I designed the full experience in Figma, created imagery in Photoshop, and wrote the core copy myself. Claude handled implementation, and I iterated probably a thousand times, just like any design project. The difference was the pace. Adjusting a timing curve, testing an alternative layout, fixing a mobile edge case, what would have taken hours of manual debugging moved in minutes. The animation system alone, scroll-triggered fade and scale effects, staggered gallery animations, a custom lightbox, would have been days of JavaScript work. With AI, I described the behavior, reviewed the implementation, and refined the details.

Outcome

Production-grade interactions. Days, not weeks.

  • Full bespoke site with custom animation system shipped in days
  • Every design decision made by a human, AI handled execution
  • Responsive design across all breakpoints without manual CSS debugging

AI didn't replace my design judgment. It raised the ceiling on what I could execute within a given timeframe. That's the shift, not "AI instead of designer," but "designer with AI" moving at a pace that wasn't previously possible.

Soccer Coach App
Personal Project · Web App September 2025

Soccer Coach App

Claude ChatGPT Figma

I was coaching a 10U girls soccer team while managing attendance, substitutions, playing time, and three separate timers. The logistics were consuming more attention than the coaching.

Problem

Managing logistics was pulling focus from coaching

With a 5v5 setup, 25-minute halves, and substitutions every 5 minutes to keep players fresh in the Texas heat, I arrived at every game with a notepad full of rotation plans that became obsolete the moment attendance was taken. I'd scramble to recalculate who was present, who'd played the most minutes, who needed time in their preferred position, and when the next sub window was coming, while also running a game clock, a rotation timer, and trying to actually coach. It was error-prone and exhausting. Position preferences mattered (some girls loved playing goalie; others specifically didn't want to). Ensuring fairness across the season required more tracking than any manual system could reliably handle.

Insight

The logistics were rule-based. They could be automated.

The rotation logic followed consistent rules: equal playing time, respect position preferences, account for absences, sub every 5 minutes. That's a solvable system. The human judgment, reading the game, coaching in the moment, responding to what's happening on the field, that's what I should be doing with my attention.

Solution

Select attendance. Get a complete rotation plan.

I built a web app that takes attendance as input and generates a complete substitution schedule. It distributes playing time across positions, respects individual preferences (including goalie restrictions), and accounts for absences automatically. Dual timers, one for the half, one for the 5-minute rotation window, run simultaneously on the same screen. After the final whistle, the app generates a post-game report: minutes played per player, positions covered, number of times out.

Before → After
Area Before After
Rotation PlanningPre-game scramble, obsolete the moment attendance changed30-second attendance tap, complete schedule generated
Sub TrackingManual notepad, error-prone under pressureAutomated 5-minute windows with dual timers
Playing Time FairnessBest-guess, hard to verify across the seasonDistributed automatically, position preferences respected
Post-Game ReportingNoneAuto-generated minutes per player, positions covered
Coach FocusSplit between logistics and the gameFull attention available for coaching
CIRadar · SaaS November 2024 · Contract

CIRadar UI Modernization

Figma Bootstrap 3 CSS

A feature-rich web app with a dated UI. The challenge: deliver a modern visual refresh without changing workflows, within the constraints of a legacy front-end framework.

CIRadar UI modernization
Problem

Strong functionality. Dated presentation.

CIRadar had sophisticated filtering, saved search, and analytics capabilities that outperformed competitors. But the UI looked older than its feature set. Competing products with fewer capabilities looked more polished. The client wanted a visual refresh, scope constrained to the presentation layer, with no changes to existing layouts or user workflows.

Constraint

Bootstrap 3 made a clean upgrade impractical

The app's reliance on Bootstrap 3, a rigid 12-column grid with predefined component styles, made a framework upgrade costly. Refactoring to Bootstrap 5 would have required extensive rework with high regression risk. The practical path: targeted CSS overrides, CSS Flexbox applied in isolated components, and selective UI updates that preserved backward compatibility with the existing structure.

Process

Evaluate → brief → design → iterate → hand off

I started with an independent evaluation using a test account, documenting patterns, capturing assumptions, identifying where visual changes would have the highest impact. I compiled findings into a concise project brief that aligned on scope before any design work began. After initial mockups, one round of client feedback corrected a few assumptions about existing functionality. A second iteration resolved remaining refinements. The design-to-development handoff was straightforward, adherence to the existing layout meant the experienced developer could implement with minimal documentation.

Outcome

Modern aesthetic. No disruption to existing workflows.

  • Visual design modernized without changes to layout or user workflows
  • CSS Flexbox improvements delivered within Bootstrap 3 constraints
  • Smooth handoff, minimal implementation overhead for the development team
  • Client satisfied; UI rollout in progress
UX Metrics System, Q2
Q2 eBanking · Design Leadership 2024 · UX Director

A System for Measuring Design Impact

Pendo Qualtrics PowerBI

Our pre-release usability testing was rigorous. Once work shipped, our ability to capture user sentiment dropped off entirely. I built the infrastructure to close that gap.

Problem

Strong pre-release validation. No post-release signal.

Our team used SUS, ACSI, VisAWI, and other benchmarks to validate design quality before handoff. These worked well for pre-release. After features shipped, feedback collection fell back on broad email CSAT surveys, low engagement, no targeting, no ability to isolate feedback by app, workflow, or user type. Leadership couldn't see the connection between design decisions and customer outcomes. UX's strategic impact was real but invisible.

Insight

We were already using a tool that could solve this

We used Pendo for behavioral analytics. Its Guides feature, typically used for in-app walkthroughs, could target specific users on specific pages after specific actions. I saw the opportunity: iframe a Qualtrics survey directly into a Pendo Guide. Targeted, in-context feedback, no inbox required, no list management, near-zero overhead to activate and deactivate per quarter.

Pendo guide configuration
Solution

Embedded CSAT, intelligent targeting, unified dashboards

Working with Engineering, we embedded Qualtrics surveys directly into Pendo Guides, configured to appear only within specific apps, for specific user roles, on relevant page types, after key actions. Each application got its own CSAT Guide, toggled on for a few weeks each quarter, then off. No manual process. I then built Qualtrics dashboards for real-time trends and a PowerBI master dashboard that unified usability testing data, research insights, and CSAT results with feature-level drilldowns.

Outcome

UX went from invisible to measurable

  • Leadership gained a clear, data-backed view of how design changes improved satisfaction
  • Product teams used CSAT trends to guide roadmap prioritization
  • Engineering saw reduced rework, supported by concrete benchmarks
  • UX elevated from execution-focused to a strategic partner with shared language across the org
Before → After
Area Before After
CSAT CollectionBroad email blastsTargeted, in-product, contextual
Data QualityLow engagement, inconsistentHigh-precision, high-volume
Feedback TimingDelayed, infrequentReal-time, automated
Leadership VisibilityLimitedCentralized dashboards, clear trends
UX InfluenceHard to quantifyMeasurable, strategic, trusted
Q2 eBanking · Fintech 2018 · Design Lead

How Two Workflow Changes Turned Account Openings into Funded Accounts

Figma Pendo

The account opening flow worked. Sub-4-minute completion. Low drop-off. Strong metrics. The problem was what happened next, or didn't.

Online Account Opening, Q2 eBanking
Problem

A successful onboarding that wasn't producing revenue

A newly opened checking or savings account isn't an active customer. A funded account is. Across Q2's financial institution clients, we were seeing the same pattern: users completing account opening and stopping there. Not abandoning, completing. The flow worked. But funding, treated as a separate post-onboarding task, was getting deferred. Sometimes indefinitely. Unfunded accounts meant no deployed capital, no interest revenue, and no live customer relationship for the institution.

Insight, workflow diagram
Insight

The workflow ended at the wrong moment

When users finished opening their account, they were told: your account is open, go fund it when you're ready. Funding lived outside the flow, and "when you're ready" frequently meant never. The account opening experience had a clear finish line. Funding didn't. This pointed to a focused direction: we didn't need to redesign the core workflow. We needed to extend it by two deliberate changes.

Insight, account opening workflow
Solution

Two changes. Both targeted. Neither disruptive.

Change 1, Move funding into the flow. We placed the funding step immediately after account approval, before the confirmation screen. That moment, right after approval, is peak motivation. The account is real. The relationship has just started. Funding placed there lands completely differently than a follow-up email two days later. Nothing about the mechanics changed. The framing did: funding became part of the opening, not a follow-up to it.

Change 2, Add a funding rail users already trusted. Before, users could fund via existing account transfer or ACH bank transfer, both requiring routing numbers or credentials that a brand-new customer often doesn't have at hand. We added debit or credit card as a third option. Instant. No routing numbers. A mental model already internalized through years of e-commerce. One screen. Three funding contexts. Each option's timing made explicit so users could choose with confidence. The deposit field defaulted to $100, above the $25 minimum, a behavioral nudge that anchored users without removing their agency.

Solution, funding options screen
Outcome

Better placement + better options = compounding improvement

  • Immediate funding rate increased post-launch
  • Average opening deposit increased post-launch
  • Funding screen drop-off showed the sharpest improvement of any flow change
  • Sub-4-minute completion promise maintained

Moving funding into the flow changed the psychology of the moment. Adding card funding changed the effort required. Neither change disrupted the core workflow. The changes compounded: better placement increased the number of users who reached the funding screen with intent to act; better options reduced the number who left without completing.