
Building a Production-Ready Drupal Module in a Weekend with AI: The LinkStash Story

June 25, 2026
At Tag1, we believe in proving AI within our own work before recommending it to clients. This post is part of our AI Applied content series, where team members share real stories of how they're using Artificial Intelligence and the insights and lessons they learn along the way. Here, Dénes Szabó (Drupal Developer) built LinkStash, a production-ready Drupal 11 bookmarking module, in one weekend using Claude Sonnet 4.5.
The Browser Tab Apocalypse
You know the feeling. It's Tuesday afternoon, you have 47 browser tabs open across three different browsers, and somewhere in that digital haystack is that one article you absolutely need to reference. Chrome has the documentation you bookmarked last week. Firefox has the GitHub issues you were reviewing. Safari has... honestly, you can't remember what Safari has anymore. Your browser's "Reading List" feature is laughing at you. Your bookmarks folder looks like a digital hoarder's attic. And don't even get started on those "bookmark this page to read later" services that require uploading all your data to someone else's server.
As a Drupal developer, I looked at this chaos and thought: "I could fix this. I have the technology. I have the skills. I have... absolutely no time to actually build it because I'm too busy managing 47 browser tabs."
So naturally, I decided to see if AI could help me build it in a weekend instead.
The Experiment: Can AI Build a Real Drupal Module?
The goal was ambitious but clear: build LinkStash, a personal bookmarking tool, as a production-ready Drupal 11 contrib module suitable for release on drupal.org. Not a prototype. Not a proof-of-concept. A real, tested, documented, standards-compliant module that follows all of Drupal's best practices and passes the strict quality requirements for the official repository.
The feature list was substantial: entity system with full CRUD operations, browser bookmarklet for one-click saving, automatic metadata fetching with SSRF protection, smart domain-based auto-categorization, video embed support for YouTube and Facebook, Views integration with filters, 100% PHPCS compliance, PHPStan Level 1 static analysis, and a full test suite. Oh, and proper documentation including README, CHANGELOG, and API docs.
You know, just a light weekend project. What could possibly go wrong?
Why Claude Sonnet 4.5, Not Opus?
Here's where it gets interesting. Everyone assumes you need the biggest, most powerful AI model for serious development work. But I deliberately chose Claude Sonnet 4.5 instead of Opus, and here's why: it's way cheaper, significantly faster, and (here's the kicker) equally clever for code generation.
For structured development tasks with clear requirements, Sonnet 4.5 absolutely shines. It understands Drupal architecture, follows coding standards precisely, writes comprehensive tests, and generates production-quality code. The speed difference is noticeable: responses come back in seconds instead of tens of seconds. When you're iterating on test failures or fixing PHPCS violations, that speed compounds into serious time savings.
The cost difference? Even more dramatic. We're talking roughly one-fifth the cost per token. Over the course of building LinkStash, which consumed an estimated 200-250K tokens across multiple development sessions, Sonnet 4.5 probably cost around $3-$5 total.
That's less than a fancy coffee, for a complete, production-ready Drupal module. Let that sink in.
The Human-AI Collaboration: How We Actually Built It
AI didn't build this module alone. This was a collaboration, and understanding the dynamics matters.
What AI did (the heavy lifting):
- Generated all entity boilerplate following Drupal 11 patterns
- Implemented three complete plugin systems (ContentFetcher, CategoryRule, MediaProvider)
- Wrote 187 tests (132 unit + 55 kernel) with proper fixtures and mocks
- Wrote the documentation (README, CHANGELOG, API docs)
- Fixed all PHPCS and PHPStan violations autonomously
- Debugged test failures systematically (13 failures across 3 test suites, all resolved)
- Generated field configurations, Views configs, and taxonomy vocabularies
What I did (the professional supervision):
- Created the Product Requirements Document with the 3-phase roadmap
- Made all architectural decisions (entity structure, plugin patterns, security model)
- Decided on module naming (checked drupal.org availability, chose "LinkStash")
- Identified critical security requirements (SSRF protection, XSS prevention)
- Reviewed and corrected AI assumptions when they didn't match Drupal realities
- Ran the actual tests in DDEV (AI can't access Docker environments)
- Caught edge cases AI missed (like the DNS rebinding vulnerability in SSRF protection)
- Made final calls on trade-offs (documented limitations vs. complex solutions)
When I Had to Intervene: The Learning Moments
The most surprising part wasn't what went smoothly; it was where AI stumbled and needed human expertise.
The constant mystery. AI kept trying to use EntityStorageInterface::SAVED_NEW, but that constant doesn't live in that interface. It's a global constant in core/includes/common.inc. I had to explicitly correct this: "This constant does not exist in this interface. It's defined in common.inc. Fix it." The AI course-corrected immediately.
The access control saga. All seven access tests were failing despite correct permissions and entity ownership. AI tried using AccessResult::allowedIf(), which should work, but didn't in Drupal 11's kernel test environment. After systematic debugging, I suggested trying explicit conditionals instead. That fixed it instantly; it was a behavioral quirk AI wouldn't have discovered alone.
The vocabulary ID confusion. Tests were creating a tags vocabulary, but the actual config created linkstash_tags. AI confidently wrote tests that failed due to this mismatch. Human pattern recognition caught it: "You're testing against the wrong vocabulary ID."
The YouTube ID format. AI used 3-character test IDs (abc, xyz), but YouTube video IDs are exactly 11 characters using base64url encoding. The regex pattern [a-zA-Z0-9_-]{11} doesn't lie. Once I pointed out that YouTube IDs are standardized at 11 characters, AI immediately generated valid test data.
These weren't AI failures; they were collaboration points. AI had the speed to generate code and tests. I had the domain expertise to catch subtle Drupal-specific issues. Together, we debugged faster than either of us could alone.
The Development Speed
The numbers are worth a look:
- Calendar time: Friday/Saturday to Sunday (February 7-9, 2026)
- My active time: 10-20 hours of supervision, decision-making, and testing
- AI sessions: Multiple sessions totaling ~200-250K tokens
- Code generated: 8,000+ lines across entity classes, plugins, services, tests, and configs
- Test suite: 187 tests written and debugged to 100% pass rate
- Documentation: 1,800+ lines (README, CHANGELOG, module intro HTML)
Here's what "one weekend" actually delivered:
- Complete entity system with 12 fields
- Three working plugin systems with 8 plugin implementations
- Browser bookmarklet with popup fallback logic
- Automatic metadata fetching with SSRF protection
- Smart auto-categorization based on 5 domain-matching rules
- YouTube and oEmbed video embed support
- Two Views (list + detail) with exposed filters
- 187 tests (100% passing, ~85% code coverage)
- Zero PHPCS violations, PHPStan Level 1 clean
- Complete documentation ready for drupal.org submission
The security model deserves a callout: SSRF protection blocks private IP ranges, local thumbnail storage prevents IP leaking, and all data is isolated per user. All three plugin systems are also fully extensible, other developers can add custom content fetchers, categorization rules, and media providers. The module ships with sensible defaults but is built for extension.
Could I have built this solo in a weekend without AI? Absolutely not. The test suite alone would have taken days. Could AI have built this without supervision? Also no. Those subtle Drupal-specific issues required experienced judgment calls.
But together? We shipped a release-ready beta in 48 hours.
The Numbers: What Did This Actually Cost?
Let's break down the economics.
Time investment:
- Human time: ~15 hours (let's split the 10-20 range)
- AI compute time: Maybe 30-45 minutes total across all sessions
- Calendar time: One weekend
Token usage:
- Estimated total: 200-250K tokens (spanning multiple sessions)
- Breakdown by task (from
progress.md):- Project setup: ~10K tokens
- Entity/field architecture: ~14K tokens
- Major features (8-10): ~15K tokens each
- Test suite (187 tests): ~30K tokens
- Code review + fixes: ~15K tokens
- Documentation: ~20K tokens
Actual costs (Claude Sonnet 4.5 pricing):
- Input tokens: ~$3 per million tokens
- Output tokens: ~$15 per million tokens
- Rough estimate: $3-$5 total for the entire project
Traditional development cost (rough estimate):
- Senior Drupal developer: $100-$150/hour
- Time required (solo): 40-60 hours (conservative)
- Traditional cost: $4,000-$9,000
The AI-assisted approach wasn't just faster; it was two to three orders of magnitude cheaper while maintaining professional quality standards.
The Future: Where Do We Go From Here?
Building v1 in a weekend was exhilarating, but it's just the beginning. The roadmap has two more phases.
Phase v2 (enhanced features):
- Browser extension for Chrome/Firefox (deeper integration than a bookmarklet)
- Import/export (JSON, CSV, HTML bookmark files)
- Link health checking (detect broken links via cron)
- Duplicate detection and merging
- Collections system (folders, boards, groups)
- Full-text content archival (Wayback Machine style)
Phase v3 (advanced capabilities):
- AI-powered auto-tagging using actual page content (not just domain matching)
- Smart recommendations based on browsing patterns
- Multi-site synchronization for users with multiple Drupal sites
- Drupal Recipe for one-click installation
- Social features (public collections, sharing)
The best part? Now that the architecture is solid and the plugin systems are proven, adding these features becomes incremental. Each new feature is just another plugin implementation or service extension. The hard architectural work is done.
Was It Fun? (Spoiler: Yes, Incredibly)
Nobody warns you that AI-assisted development is fun.
There's something magical about describing what you want, for example, "Now we need a plugin system for content fetchers that can pull metadata from any URL with SSRF protection," and watching structured, working code appear in seconds. Then catching a subtle bug, pointing it out, and watching the immediate course correction. It feels less like programming and more like conducting. You're directing the architecture and reviewing the output, not typing every curly brace.
The debugging sessions were particularly entertaining. When all seven access tests failed, AI and I became detective partners:
Me: "Add debug assertions before the access check. Let's see if the user actually has permissions."
AI: Adds assertions. "Okay, permissions confirmed. User owns the entity too."
Me: "So why is
AccessResult::allowedIf()not working?"AI: "Let me try explicit conditionals instead..."
Me: "That... actually fixed all seven tests. Interesting."
That back-and-forth, that collaborative debugging energy, reminded me of pair programming with a really fast typist who never gets tired but occasionally needs you to remember obscure Drupal API behaviors.
The satisfaction of running ddev composer run-tests and seeing "187 tests, 846 assertions, OK" flash green? That hit the same way shipping your first module to production does. Except this time, we'd done it in a weekend instead of a month.
The Real Lesson: Augmentation, Not Replacement
If there's one takeaway from this experiment, it's this: AI is an amplifier, not a replacement.
I couldn't have built LinkStash in a weekend alone. But AI couldn't have built it without me either, not to production quality, not with proper security considerations, not with the architectural decisions that make it extensible and maintainable.
What AI gave me was force multiplication. Instead of typing boilerplate entity code, I specified requirements and reviewed output. Instead of writing 187 tests manually, I described what needed testing and verified the results. Instead of formatting documentation, I outlined structure and AI filled in details.
I stayed in the driver's seat for architecture, security, and critical decisions. AI handled the mechanical work of code generation, test writing, and standards compliance. Together, we shipped something neither of us could have done alone in the same timeframe.
And honestly? For a problem that's been in the back of my mind for months, "I really need a better bookmarking solution," going from idea to a release-ready beta in one weekend feels like the future.
Now if you'll excuse me, I need to actually use LinkStash to bookmark all the tabs I've accumulated while writing this blog post. The irony is not lost on me.
LinkStash is available at drupal.org/project/linkstash. Built with Claude Sonnet 4.5 via Claude Code. Source code, documentation, and contribution guidelines are available in the project repository.
Development metrics: 1 weekend, ~15 human hours, ~240K AI tokens, $3-5 compute cost, 8,000+ lines of code, 187 tests, 0 PHPCS violations, live on drupal.org.
If you're weighing whether AI can carry real weight on your next Drupal contrib module, or you want to talk through where human oversight still has to stay in the loop, let's start a conversation! We'd love to hear from you.
This post is part of Tag1’s AI Applied content series, where we share how we're using AI inside our own work before bringing it to clients. Our goal is to be transparent about what works, what doesn’t, and what we're still figuring out, so that together, we can build a more practical, responsible path for AI adoption.
Image by Mahmoud Ramadan from pexels
Related Insights
-
/