Building a License Gate for MemStack: From Simple Validation to HMAC-Protected Grace Periods
Today I spent about 2 hours building out a proper licensing system for MemStack, and wow, it turned into quite the rabbit hole. What started as "just add license validation" ended up being a complete tiered access system with tamper-resistant grace periods.
The Journey: From Gate to Grace Period
I kicked things off with my usual multi-agent setup (Manager, Builder, Reviewer via agent-bridge) to build a simple skill gate. The goal was straightforward: validate MemStack Pro licenses before allowing access to MCP tools.
The first version was pretty basic:
- Created
license.pywith async validation against AdminStack - Added in-memory caching with server-controlled TTL
- Used per-key locks to prevent duplicate API calls
- Graceful degradation for network errors (but immediate reject for HTTP 4xx)
My Reviewer agent caught 6 issues right off the bat, including a nasty async race condition. Good thing I have that safety net!
Plot Twist: Tiered Access
Then I realized a binary gate was too harsh. Nobody likes hitting a paywall with zero context. So I pivoted to a three-tier system:
- No key: Fully blocked with a friendly "Get your free key" message
- Free key: Access to 77 out of 80 skills
- Pro key: Full access to all 80 skills
The 3 Pro-exclusive skills are consolidate, context-db, and api-docs - basically the power-user features.
I also added an activate_license MCP tool so users can enter their key interactively, plus email capture for contact tracking in AdminStack.
The Grace Period Challenge
Here's where it got interesting. I didn't want to break existing users, so I added a 14-day grace period. Anyone without a key gets full Pro access for 2 weeks.
But then my paranoid developer brain kicked in: "What if someone just deletes the grace period file to reset it?"
So I added HMAC tamper detection:
- Grace period stored in
~/.memstack/grace-period.json - File signed with HMAC-SHA256 using a machine-specific secret
- Secret derived from
HMAC(hostname + username, "memstack-grace-v1") - Tampered files get immediately rejected
The machine-specific approach is clever because it ties the grace period to the actual machine without requiring external key management.
AdminStack Integration
On the backend side, I had to fix the contact tagging system. Instead of hardcoding "MemStack Pro" tags, it now creates tier-appropriate tags:
- Free tier → "MemStack Free" (blue)
- Pro tier → "MemStack Pro" (purple)
I also caught a silent failure bug where I was using .single() instead of .maybeSingle() for find-or-create patterns. Those Supabase gotchas will get you every time.
The Technical Details
Some implementation notes that might be useful:
- Caching strategy: In-memory cache with server-controlled TTL, but graceful fallback to stale cache on network errors
- Concurrency: Used
asyncio.Lockfor API calls andthreading.Lockfor grace period file creation - Error handling: HTTP 4xx means immediate rejection (bad key), network errors mean graceful degradation
- Migration: Legacy grace files without HMAC auto-migrate on first read
All the unit tests passed (11/11 for v1, plus 5/5 e2e tests for v2), and the Reviewer agent helped catch several critical bugs along the way.
What's Next
The core licensing system is done and pushed, but there's still work to do:
- Build the memstack.pro landing page with free key signup
- Add a proper license management UI to AdminStack
- Move the Pro-exclusive skill list to config instead of hardcoding
- Test the email capture flow end-to-end
It's satisfying when a "simple" feature turns into a robust system. The HMAC tamper detection especially feels like the kind of detail that separates hobby projects from real products.
Now I just need to resist the urge to over-engineer the landing page... 😅