I’ve been degoogling for a while and noticed I stepped by going to Proton from one walled garden into another. I use Proton’s mail and calendar these days. And even though I like the Proton products, I can’t say I’m a fan of having no access to my data outside their products. This led me to Proton Bridge, which at least offers IMAP/SMTP for their services, but no calendar/contacts. In a chat with one of my friends I figured this would be neat to vibe code (or at least heavily-assisted LLM coding). This is my attempt at journaling the process and findings.

Getting started

Before I let Claude do its thing I figured I should take note of some requirements. This was the first file of the repository, named REQUIREMENTS.md:

# Features
- CalDAV support
- CardDAV support
- API for managing users, calendars, address books
- UNIX philosophy

# Technical
- Golang
- go-chi
- zerolog
- works with DAVx5
- file based, no database

I then prompted it to gather more requirements, seeing what I would like and what not. I specifically specified to do online research here. After a few minutes of going back and forth with Claude I ended up with a much larger file describing the architecture, the features for: CalDAV, CardDAV, sharing and permissions, authentication, storage, configuration, logging, observability, testing, out of scope, admin interface, and the technology stack.

Improving the scope of the project

This would be enough to get started, but I felt insecure in relation to how secure this would end up becoming. This prompted me to generate some additional documents. I let Claude generate several documents from different perspectives for me (information security, software engineering, testing, etc.). This led Claude to spawn a couple of sub-agents which then generated: ARCHITECTURE.md, OPERATIONS.md, REQUIREMENTS.md, RFC-COMPLIANCE.md, and SECURITY.md.

The architecture describes the general layout of the project. It shows which packages should be created, and what the goal of those packages is. The general API is laid out, including health checks and addition DAV-related paths. An example of a configuration TOML is included. The data model of the application is shown, and ‘decisions’ are recorded. This goes on for a while, including migrations, building, error handling, testing, interfaces, etc.

The operations document goes in depth into how set up, backup, maintain the application. And looking back as I write this, seems to quite miss the mark.

The RFC-compliance document contains a table of project-related RFC’s. Claude generated priorities per RFC, and I believe this eventually helps keeping the development on track when the features become more complex.

The final document is the security document and this highlighted some issues in the original design. One of the issues was that CalDAV works with basic authentication, which should definitely not be used on non-TLS connections, another was that using reverse proxy headers could also expose the service to attackers hijacking the headers, path traversal in the file system storage (e.g., using relative paths). Which triggered me to have the documents be updated based on its finding. It made a prioritized list of security-related topics, which I think helps with the overall development and (hopefully) actual security of the app.

Doing the work, the broad strokes at least

Now that all the initial documentation was set up, it was time for Claude to start working on the implementation. It suggested to start with what it called the project scaffold. It ran for a while, downloaded some planned dependencies, creating the directory structure, packages, and initial command to start the app. This is where Claude came back to me, asking me to decide what to do next.

I prompted it figure out what would make the most sense. It then started working on implementing CalDAV, and after that CardDAV. It took multiple interactions, stopping it from endlessly searching ~/.cache/go for more information on packages it had just downloaded itself. I also continuously had to beg for it to create tests for the code it generated.

This process of Claude eventually stopping and asking me to tell it what to do led me to something that seemed like it could work. There was an API, CalDAV and CardDAV routes, and a CLI interface. But it hadn’t taken into account that I wanted to host this on Kubernetes. So after a bit of fussing I got it set up on my cluster and was able to do some requests.

Integrating with the real world

After a while I decided I would like to test it for real. So I took out my phone, loaded up DAVx5 and attempted to connect. This failed right away because the basic authentication was enabled for all HTTP routes. After some tweaking I got a step further, discovering that even though I support non-email usernames it could lead to issues when I would invite people to my calendar events.

After that fix, DAVx5 showed that the calendar and contacts could be loaded from my service. So that was good! Except, I didn’t have an app that could read the calendar data. I tried out Fossify Calendar, but that didn’t have an option to add guests to the calendar events. So I opted for Etar.

After installing Etar, I could create events without issue. Then I figured I could use Google Contacts (which I already had installed) to create users in the address book that DAVx5 arranged for my phone.

Conclusion

All in all I was amazed how well Claude developed the features I asked for. I still mostly worry about security and maintainability. It took me a whole day to get to this point, which somehow feels like it took longer than I would expect. There was still a lot of hand-holding with Claude, but that could be my controlling personality. Coding like this feels more exhausting than doing it myself, hopefully I’ll get used to it more.

What’s next

In the coming period I’m planning to implement more of the API, a user-facing website to manage passwords, calendars and address books, an admin user interface, and sending guests invitation mails. After that I might open source the project to see what others think of it.