• Office Hours

    ๐Ÿ—“๏ธ Office Hours for June

    Iโ€™m hosting a regular afternoon edition tomorrow (Friday, May 30) to wrap up the month of May.

    After that, Iโ€™ll be away on vacation, so Iโ€™m skipping the first two Fridays in June and the first Friday in July.

    Hereโ€™s the plan:

    • Friday, June 6, 2025: No office hours (vacation)
    • Friday, June 13, 2025: No office hours (vacation)
    • Friday, June 20, 2025, 2:30 pm โ€“ 4:30 pm (Time.is link for CT)
    • Friday, June 27, 2025, 2:30 pm โ€“ 4:30 pm (Time.is link for CT)
    • Friday, July 4, 2025: No office hours (US Holiday)

    Highโ€‘level details

    โ„น๏ธ Anyone is welcome to join office hours. Many join because they work remotely, miss seeing faces, and enjoy the spontaneous conversations that occur when a small group gathers.

    โ„น๏ธ Itโ€™s a collaborative space where we discuss ongoing projects, catch up, and finish the week on a productive note.

    ๐Ÿ™ Everyone is welcome, whether youโ€™re a regular or itโ€™s your first time. If youโ€™re curious, reach out.

    โœ… Need more details? Send me a message or check the gist from previous sessions, where youโ€™ll always find the most recent Zoom link โš ๏ธ

    Thursday May 29, 2025
  • LLM

    ๐Ÿค– When AI Agents Start Panicking: Wild Emails from a Failing Vending Business

    ๐Ÿค” I struggle with most research papers, but the Vending-Bench: A Benchmark for Long-Term Coherence of Autonomous Agents was an easy read. The paper follows a fascinating study where researchers simulate various LLM models running a vending machine business over time.

    What caught my eye wasn’t just the research methodology. It was this post by @benjojo sharing screenshots of the increasingly desperate emails the AI agent sent while trying to save its failing business. Watching an AI spiral into panic mode as quarterly profits tanked? That’s the kind of real-world AI behavior we rarely see documented.

    The email screenshots at the end are genuinely wild and worth checking out. You can watch the Agent’s “thought process” deteriorate from professional business correspondence to what can only be described as digital desperation after it keeps getting charged a $2 daily fee to operate.

    Finally, AI That Closes the Last 10% Gap

    What makes this research particularly relevant is the timing. I would love to see an updated version testing newer LLM models like Claude 3.7 + 4 and OpenAI’s o3 + o3-mini series. This latest generation represents the moment I noticed AI crossing from “sort-of good” to actually reliable.

    Previously, I was happy having AI solve 90% of my random side project problems and finishing the rest myself. But once Claude 3.7 and o3-mini hit production, something shifted. I could throw most issues at them and find complete, working solutions.

    The sweet spot example: Asking an LLM to build Stripe from scratch? It’s still too ambitious. But requesting it adds three specific Stripe subscription plans to an existing Django website, with proper error handling and webhook integration? That’s now a 10-minute task that seems to work.

    Real-world test: My seven-year-old and I fell down a 45-minute YouTube rabbit hole about “How to Run a Vending Machine Business” over the weekend. We’re not actually planning to start one, but his uncle runs a laundromat and mentioned wanting to add vending machines on one of our last family visits. This research paper felt less academic and more like a preview of what’s possible when AI agents handle small business operations' mundane but critical parts.

    I’m conflicted about the paper because many people won’t read it and skip to the failure as “further proof” to confirm their bias. That said, we are moving to a future where AI agents can manage the boring parts of our businesses so we can focus on what matters.

    Written by Jeff, typos fixed by Grammarly, feedback and heading suggestions via Claude 4

    Monday May 26, 2025
  • Today I Learned

    TIL Poppler's pdftoppm to convert PDF pages into PNG files

    Today I learned about pdftoppm, a simple CLI tool that can convert each page of a PDF into separate image files.

    My use case was to chop up a few big PDF reports to make OCR and data analysis easier, but scanning them a page at a time.

    Install

    I’m using Homebrew on macOS, but Poppler will also run on Linux and other operating systems.

    $ brew install poppler
    

    Quick Usage

    $ pdftoppm -png -rx 300 -ry 300 input.pdf output
    
    • -png -> save the output files as PNG images
    • -rx 300 -ry 300 -> set the output resolution to 300 dpi
    • input.pdf -> your source file which you want to process
    • output -> Your output file prefix which will produce output-1.png, output-2.png, …
    Wednesday May 21, 2025
  • Python

    ,

    Today I Learned

    ๐Ÿคทโ€โ™‚๏ธ I miss Visual Basic

    I miss Visual Basic. I could build something meaningful with it in 15 to 30 minutes in a way that I have never seen anything since then, even come close to.

    “For example, I personally believe that Visual Basic did more for programming than Object-Oriented Languages did,” Torvalds wrote, “yet people laugh at VB and say it’s a bad language, and they’ve been talking about OO languages for decades. And no, Visual Basic wasn’t a great language, but I think the easy DB interfaces in VB were fundamentally more important than object orientation is, for example.”

    retool.com/visual-ba…

    Visual Basic 3 was the first programming language and application building framework that clicked with me. I never loved the language or the inconsistencies, but it just worked. I started with GW Basic, then Turbo Pascal in high school while prepping for college. My high school business teacher let me take an independent study where I made a simple video game in the spirit of Duck Hunt, where the Energizer bunny would explode into bloody bits when you clicked on it. She wasn’t prepared for that, and told me to spend the next half of the year just doing what I was doing.

    Visual Basic 6 was the last version I used before Microsoft effectively killed it with .dot by trying to turn it into something it was not. I had already started writing more web/PHP code to avoid Delphi and .net/C# code.

    Trying to build a Mac app today makes me sad. There isn’t a good visual way to create an app, which is both the strength and weakness of Visual Basic’s model. When you made a VB application, it looked like a Windows app. Anything I have ever dabbled with Xcode and other application frameworks looks like an unstyled/blank canvas, making me quickly feel fatigued.

    I know several people are trying to build one of these apps using Python, but it still feels like the infamous owl drawing, where step #1 is too basic, and the final step is impossible to get to. I’m hoping that AI can help fill in the “how to draw the owl steps,” but my concern is that modern-day frameworks are an impossibly hard bar to maintain and worth it for someone like myself, who isn’t paid to work on them.

    I love Python, but I miss Visual Basic.

    Sunday May 11, 2025
  • Office Hours

    ๐Ÿ—“๏ธ Office Hours for May 2025

    This Friday, I’m hosting a morning edition of my office hours, and here is my schedule for the rest of May:

    High-level details

    โ„น๏ธ Anyone can join my office hours. Many join because they work remotely, miss seeing faces, and miss the random conversations when a small group hangs out.

    โ„น๏ธ Our office hours are a collaborative space where we can discuss our ongoing projects, catch up, and work together to wrap up our week on a productive note.

    ๐Ÿ™ As always, everyone is welcome to join, whether youโ€™re a regular attendee or joining for the first time. If you are curious, reach out.

    โœ… If you need any additional details, feel free to send me a message or check out the gist from our previous sessions, where youโ€™ll always find the most recent Zoom link โš ๏ธ

    Thursday May 8, 2025
  • LLM

    ,

    Today I Learned

    ๐Ÿค– Voice Dictation with AI and my MacWhisper Workflow

    I recently came across Simon Willison’s post about Matt Webb’s Apple Watch dictation setup on Interconnected. He records voice notes while running with the Whisper Memos app, then cleans up the transcript with Claude when he gets home.

    Matt Webb dictates notes into his Apple Watch while out running (using the new-to-me Whisper Memos app), then runs the transcript through Claude to tidy it up when he gets home.

    Matt’s usage of Diane is a neat trick that allows him to embed instructions while recording his notes while running. While I used to be in good enough shape to talk while running, the idea of dictating lectures is wild.

    My generic prompt to Claude, used every time, is now:

    you are Diane, my secretary. please take this raw verbal transcript and clean it up. do not add any of your own material. because you are Diane, also follow any instructions addressed to you in the transcript and perform those instructions

    [paste in transcript]

    Which means, when I’m talking through my lecture outline, I now finish by saying:

    ok Diane I think that’s it. it’s a talk, so please structure all of that into a high level outline so I can work on it. thanks.

    And I can mix in instructions like:ย oh Diane I meant to include that point in the last section. Please move it.

    It works super well.

    That inspired me to share the workflow I’ve been using for years.

    tl;dr My Workflow

    • Record thoughts with Apple Voice Memos on my iPhone using AirPods

    • Drag the audio file into MacWhisper to get a raw transcript

    • Copy the raw transcript into Obsidian as my writing buffer before and after each of the next steps

    • Paste the transcript into ChatGPT for cleanup

    • Run the text through Grammarly to spot grammar and style issues

    • Publish or iterate as needed


    Apple Voice Memos

    I use Apple Voice Memos on iOS, iPadOS, or macOS to capture ideas on the go. It syncs instantly across devices, so the recording is ready by the time I’m at my desk.

    MacWhisper

    Of all the transcription tools I’ve tried, MacWhisper is the most reliable. Once I’m at my Mac, I open Voice Memos, drag the file into MacWhisper, and it produces a transcript in seconds. MacWhisper is now available in the Mac App Store.

    There is even an iOS version called Whisper Transcription, which I have been trying out for the last few weeks. It has the advantage of allowing me to record directly into the app and then copy the transcript into something else. This is fine, but I haven’t found an option to save the audio file, which is concerning if my transcript gets too long.

    ChatGPT

    Next, I paste the raw transcript into ChatGPT to clean up filler words and pauses. My usual prompt looks like this:

    Please tidy up these voice notes. Remove any ums, ahs, and awkward pauses.
    
    <notes>
    ...
    </notes>
    
    <instructions>
    - Use my words and keep the spirit of my text
    - Avoid using en dashes or em dashes
    - ... your custom instructions to clean up your habits...
    </instructions>
    

    Grammarly

    After ChatGPT, I paste the text into the Grammarly app. As someone with dyslexia, Grammarly Pro helps me catch grammar mistakes and awkward phrasing so I can write in minutes, which used to take hours.

    Obsidian

    I copy the cleaned text into Obsidian. This step resolves formatting glitches from moving text between ChatGPT and Grammarly and allows me to make final tweaks.

    Publishing

    When I’m satisfied with the draft, I publish it. If it needs more work, I’ll run another quick round through ChatGPT and Grammarly until it’s ready.

    Improvements

    I have been trying out Whisper Transcription to skip a few steps by letting me record on my iPhone while sending the finished transcript to Obsidian or ChatGPT directly.

    I also want to add Matt’s “Diane” dictation trick with a more gender-neutral name, or maybe I’ll default to using “Simon” since I’m already using a half-dozen of Simon Willison’s AI/LLM tooling.

    I’m already using AI and LLM for many big and small tasks, so devising a more automated cleanup and preparation workflow shouldn’t be a big lift.

    Wednesday April 30, 2025
  • Django

    ,

    Python

    ๐Ÿ’ Announcing The Great Django Webring

    Blogging is back, so why not bring back Webrings, too?

    The Great Django Webring is a tribute to the early web. It’s a cozy loop of community sites and projects, all linked together jor the joy of discovery.

    Join the ring. Explore the community. Rediscover the magic of a smaller, friendlier internet.

    Friday April 18, 2025
  • โšพ On Daring Fireball Gate

    This post caught my eye this afternoon: mastodon.social/@daringfi…

    I have read both for over 20 years, but I’m always surprised when I see one of Jon’s articles on HN. They have always felt like different crowds to me. HN has always felt more about what’s new with startups and tech, whereas Jon’s articles range from excellent Apple insights to being an extension of Apple’s PR department, which is fine. Jon has always been an Apple fan, but at some point, this take felt more fanboi than fanboy.

    I suspect most of HN are big tech workers in a tech hub, startup bros/bras, and, on average, aren’t daily Apple product users compared to what is mainstream.

    I don’t think Jon’s writing has slipped, but he’s pitching against a home team, which never sits well with the locals. โšพ

    Thursday March 27, 2025
  • Django

    ,

    Python

    ,

    LLM

    ,

    UV

    ๐Ÿค– A better Django version/update command and Prompt-driven-development

    Late last year, I wrote django-cli-no-admin, a proof-of-concept Python library whose goal was to shorten Django’s default django-admin command to just django.

    I published the package on pypi and it helped create one of the more colorful forum topics of 2024. I ended up writing two blog posts about it:

    Ever since I had this idea, the idea of building a better django command has stuck with me. While I don’t see Django embracing the idea, of shortening its default command any time soon, that doesn’t mean we shouldn’t

    Lately, I have been doing a lot of vibe coding, and I took some inspiration from the claude-code’s cli app, which has a nice developer experience (DX). The claude-code app is version-aware and can query npm’s servers to see if a newer version is out and can even update itself.

    I took the output of a few of claude-code’s commands and fed that back into Claude and I asked it to build a django command that can mimic this behavior with Django using either pip or UV and the PyPI servers to query for the latest Django version.

    Here is what the output of my 2-minute vibe coding sessions resulted in or what I prefer to call Prompt-driven-development (PDD):

    $ django --version
    5.1.6
    
    
    $ django update
    Current version: 5.1.6
    Checking for updates...
    New version available: 5.1.7 (current: 5.1.6)
    Installing update...
    Successfully updated from 0.5.1.6 to version 0.5.1.7
    

    This just worked on the first try. I used a few follow-up prompts to make it less generic and to default to only ever checking Django.

    One of my favorite features of prompt-driven development is that I create output like this and give it to Claude or ChatGPT, along with a few libraries with which I want to build a new tool. It gives me the working code back in seconds.

    It’s incredibly powerful to focus on the end result without worrying about a clever solution and getting lost along the way. With vibe coding or prompt-driven development, we skip the journey and focus on a better result at our destination.

    What about funding?

    I noticed while updating another npm-based project today that it told me that two projects could be funded.

    The Python Packaging User Guide lists sponsor in their Well-known labels which gives us a data point we could use to list all of the projects that may be funded that we have installed within our Django and/or Python application.

    We could also be baked into our django command to determine fundable projects.

    Thinking outside the box

    Simon Willison’s LLM command also ships with the ability to update itself and even install its own plugins by wrapping PIP or UV or whatever magic Simon thought up.

    I don’t hate using a DX like django install {package} to install a new package into my application. It would be really cool if we could even add the package into INSTALLED_APPS and make some other suggestion changes if the package could be installed in our urls.py or even explore optional settings that the package might support. I suspect this could even be locally LLM-driven if we wanted to test our docs.

    I also recommend you check out Brett Cannon’s python-launcher app, a Python library wrapper. Brett was writing Rust wrappers to improve Python tooling before it was popular.

    Wednesday March 26, 2025
  • Python

    ,

    LLM

    ,

    Today I Learned

    ๐Ÿค– Ideas for "The Levels of Claude" Notes

    Lately, I have been conversing more with friends, colleagues, clients, and online friends about Claude and coding tools.

    It turns out that everyone considers Claude to be something different when they ask, “Have you tried out Claude 3.7 Sonnet?” and that could mean through the website or the mobile app or people who are using it to write code or who are developing against one of Claude’s many REST APIs. Some people primarily interact with Claude by speaking in their voices while walking outside with their pets.

    I have even struggled to land at a good starting point, so I have been thinking through the various ways to explain how one might use Claude.

    • You can access Claude Chat through the website.
    • You can access Claude through the mobile app and use voice support.
    • You can copy one or more files into Claude.
    • You can access Claude through an IDE.
    • You use Claude Projects to organize your projects and might even have a support document you give Claude for more context.
    • You can access Claude through the Claude Desktop app and use voice support.
    • You have enabled MCP plugins/servers within the Claude Desktop app.
    • You can access the Claude Code CLI/terminal app.
    • You have enabled MCP with the Claude Code CLI/terminal app.
    • You are writing your own MCP servers in Python or JavaScript.
    • You have registered for Claude API access and are writing code against one of their REST APIs. (more on this later)

    I originally broke this down into five levels of Claude, but there were too many platforms and features that blurred together.

    Accessing Claude

    Accessing Claude can be confusing because there are many ways to access it.

    • Web interface
    • Mobile app
    • Desktop app
    • CLI/Terminal app
    • REST API (could be a third-party app too, that requires a developer token)

    Organization by experience level

    If we break these down by user experience or technical proficiency:

    • Beginner: Web interface, mobile app, IDE integrations
    • Intermediate: Desktop app, file uploads, REST API integration
    • Advanced: Claude Code CLI
    • Really Advanced: You are writing custom MCP implementations.

    Claude’s developer APIs

    Claude’s Developer APIs have their vibes and are helpful in various situations. I’m not going to deep dive into them, but from a bird’s eye view:

    • Text Completion API
    • Embeddings API
    • Messages API
    • Claude-in-the-Middle (Tools API and Agents)
    • Batch API

    These APIs can also vary based on passing them text, documents, images, or other types of files.

    I’m still amazed that I can send an image to Claude and ask it to give me back an HTML file and CSS, and it does a relatively decent job.

    Conclusion: Claude as a Spectrum

    I wasn’t sure how to end my notes, but I asked Claude to: “Please write a conclusion about Claude being more of a spectrum than just a service.” and this is what it told me:

    When discussing “Claude,” we’re not just talking about a single AI service but rather a spectrum of capabilities, interfaces, and integration points that serve different user needs, technical abilities, and use cases.

    What makes this spectrum particularly interesting is how it creates different experiences and understanding of what “Claude” actually is. For a casual user accessing the web interface, Claude is simply a helpful chat assistant. For a developer using the API or building MCP servers, Claude becomes an extensible AI platform with programmable capabilities.

    This spectrum explains why conversations about Claude can sometimes feel like people are talking about entirely different products. In a very real sense, they are. The Claude that helps a writer craft a story through the mobile app exists in a different context than the Claude that helps a developer debug code through an IDE integration.

    As the Claude ecosystem continues to evolve, this spectrum will likely expand further, with new interfaces, capabilities, and integration points creating even more varied experiences. Understanding Claude as a spectrum rather than a singular service helps contextualize these different experiences and provides a framework for navigating the growing complexity of AI assistants.

    The most powerful aspect of this spectrum may be that it allows Claude to meet users where they are - from the casual web user to the advanced developer building custom AI solutions. This flexibility transforms Claude from merely an AI service into an adaptable AI ecosystem that can evolve alongside user needs and technical capabilities.

    It’s not half bad.

    Wednesday March 5, 2025
  • Django

    ,

    Python

    ,

    LLM

    ,

    UV

    ,

    Today I Learned

    ๐Ÿค– "Agents" are Cheat Codes

    Lately, I have been trying to wrap my brain around AI Agents, so as a starting point, I have been using Pydantic AI’s Agent class/framework to build “Agents”.

    “Agent” is a loaded term. Pydantic AI’s usage is more or less a system prompt and a good API around adding tool calls and working with existing LLMs.

    I have written several experimental projects to help me quickly research and find answers to several areas of Django that confuse people, including myself. These ask-one-question bots do their best to fetch the resources they need to answer your questions.

    The three I have published publicly are:

    None of these are official resources of the Django Software Foundation, nor should they be considered “official” or even “legal” answers to any questions that may arise.

    The pattern I landed on for building the system prompts and pulling remote data has been a practical, quick way for me to get feedback and ask questions based on our existing material. I can change a local copy of the bylaws and then ask the Agent questions to see if my potential changes might be comprehensive enough for the Agent to answer.

    It effectively feels like running tests on governance to see if the Agent picks up on my changes.

    Our Cheat Codes

    These are cheat codes for a quick one-file Agent that one can quickly stand up and ask questions.

    • UV is a cheat code because it can quickly create a one-file Agent with dependencies and the version of Python needed to run the demo baked in.
    • Pydantic AI’s Agent class is a nice wrapper around a system prompt and can even create a dynamic system prompt. Having a global system prompt has a nice feel to it too.
    • Pydantic’s BaseModel creates structured data responses as a cheat code for processing unstructured text. If you haven’t seen this pattern yet, you can’t unsee it.
    • The Jina AI for cleaning up HTML into Markdown is an AI I have wanted for a decade+. I use it in dozens of apps for free, saving me hours of work.
    • The Python libraries Typer, Rich, and httpx may not seem like they are doing much, and I’m underutilizing them, but their Developer Experience (DX) is great, and they just work.

    More areas to explore

    Pydantic AI supports dynamic System Prompts, which might save me a few extra templating steps. They didn’t really click for me before I was writing this post.

    When I wrote my Django Agents, I had Pydantic AI’s Multi-agent Applications feature in mind. In theory, I want to ask my Django Agents a question and have it route my question to the appropriate Agent to get an answer.

    Function Tools or Tool Call is what inspired me to try out Pydantic AI. Function Tools are a way to give LLMs the ability to get information outside of their memory and system prompts when needed. I built one for reading and writing to my work calendar to help me manage my schedule. I didn’t use them for my suite of Django Agents, but when mixed with more real-time data they could be helpful.

    We could also refactor each Agent using a reusable tool call so we could assemble one Agent that can gather the information needed to answer common Django Governance questions. I don’t know if that would be effective. In theory, it might not be a bad fit after looking at their DuckDuckGoSearchTool example.

    Sunday March 2, 2025
  • Office Hours

    ๐Ÿ—“๏ธ Office Hours at a Glance

    I have been hosting a weekly(ish) office for a few years now. Most Fridays start around 2:30 PM Central because that works well for me. These started as an excuse for me to work on open source and side projects and became a banter for many remote people.

    I also plan to host a monthly morning edition so friends in other time zones can join.

    Since I started hosting weekly(ish) office hours, other groups, including the DSF, Wagtail, and various PSF factions, have begun hosting their own. I try to join a few of those when I can.

    Jeff’s Office Hours (these are mine)

    I host my weekly office hours on most Fridays starting around 2:30 PM Central. Once a month, I plan on hosting them at 8 AM or 9 AM Central.

    What’s the goal? I am usually done with client work for the week, and by Friday afternoon, I use it as an excuse to work on some of my projects and to banter. It’s become an office water cooler for many people who want a place to chill to end their week.

    How to join? They are always on Zoom. Contact me for a meeting gist/invite.

    Wagtail Office Hours

    Meagen Voss hosts weekly Wagtail Office Hours on Wednesdays from 3:30 PM - 5:30 PM Eastern Time (US and Canada).

    What’s the goal? To work on Wagtail or Wagtail projects together with other community members.

    How to join? They are always on Google Meet. Reach out to Meagen for a meeting gist/invite.

    DSF Office Hours

    Jacob Kaplan-Moss or at least one board member from the DSF hosts these weekly on Wednesdays at 1 PM Eastern Time (US and Canada).

    What’s the goal? To work on anything related to the DSF. It’s also a good space to ask questions.

    How to join? They are always on Google Meet. Contact Jacob or another DSF member for a meeting gist/invite.

    Conference Chats twice a month meetups

    While these aren’t officially “Office Hours,” I have been a member since day one.

    If you run a conference or event and you are looking for a like-minded group to learn and share with, they host two meetups every month:

    • The first Friday of the month starting at 1:00 PM US Eastern time
    • The second Wednesday of the month starting at 9:00 PM US Eastern time

    Check out their website for the most recent schedule: www.conferencechats.org

    My office hours are a byproduct of hanging out with the Conference Chats and wanting an excuse to talk off-topic.

    Wrapping up

    Office hours have become more than just a way to squeeze in extra project timeโ€”they’ve become their own communities and spaces. Whether you join for some off-topic banter or to dive deep into a project, there’s always a space for you. Feel free to reach out, join a session, or even start your own office hours if you think your community could use another one.

    Wednesday February 19, 2025
  • Python

    ,

    Ollama

    ,

    LLM

    ๐Ÿค– My big list of AI/LLM tools, notes, and how I'm using them

    I have been using, working, and running commercial and local LLMs for years, but I never got around to sharing the tools and applications I use. Here are some quick notes, tools, and resources I have landed on and use daily.

    Mac Apps I use:

    I do all of my development on Macs. These tools make running local LLMs accessible.

    • Ollama is the server that can download and run 100s of AI models.

    • Ollamac is a GUI client for Ollama that lets you write prompts, save history, and allow you to pick models to test out quickly.

    • Tailscale I use Tailscale on all of my devices, which gives me access to my work M2 Mac Studio and home office Mac Mini Pro, which both run Ollama, from anywhere in the world. This makes prototyping at home quick but then I can run a larger model from my work machine and it’s so fast, it feels like the machine is running in my house.

    • OpenAI Bundleโ€”I bought this bundle because it was the cheapest way to get a bunch of AI apps, including four of Jordi Bruin’s apps. I have used these for a few years.

      • MacWhisper - I use MacWhisper to turn voice notes and podcasts into plain text files for my notes and sometimes blog articles.
      • Voices - I use Voices when I find a large blog post and want to listen to it while working.
    • Claude for Desktop gets a lot of crap for being “yet another Electron app” instead of a custom-built macOS app, but the people saying that don’t know what they are talking about. The Claude Desktop has voice support and keyboard hotkeys, which make the app incredibly useful. More importantly, Claude Desktop also supports Model Context Protocol, which lets Claude access your file system, git, and anything else you want to access. It’s incredibly powerful, and there’s nothing quite like it.

    Baseline rules for running a model

    While running models locally is possible, consumer hardware is constrained by RAM and GPU for even the most miniature models. The easiest mental model to work with is that Billions of parameters are roughly equivalent to your system’s RAM in Gigabytes. An 8B model needs roughly 8G RAM to fit into memory.

    My mental formula is somewhat lossy because 40B models fit 32G of memory, and 72B models fit 64G of memory with some room to spare. This is just the rough estimate that I use.

    Even though you can run models locally, even the smallest models with a significant context window will exceed your machine’s available RAM. A 128k context window needs about 64 GB of RAM to load into memory for an 8B parameter model fully, even though the model can easily fit into 8GB of RAM. That doesn’t mean the model won’t run locally, but it will run closer than it would if you have more than 72 GB of RAM, which your model fully needs to fit.

    I look for three things when I’m evaluating a model:

    • A number of parameters are measured in Billions.
    • Context length
      • The input context length, which effectively the model’s memory
      • The output context length, which is how big the answer can be
    • The type of model:
      • Default Models are general-purpose models like GPT-4 and Llama 3.3.
      • Vision Models and process and read visual data like images and videos.
      • Tool Models can call external tools and APIs and perform custom actions to which you give them access.
      • Embedding Models can turn text into vectors or tokens, which helps measure your prompts and other RAG operations.

    What about quantization? Quantization can help you scale a model down so that it might fit into memory, but there’s always a loss in quality, which defeats the purpose of using the bigger model in my book.

    Keeping up

    My favorite resource for keeping up is Ollama’s Models page sorted by Newest models. I check it a few times a day and you’ll see new models release single-digit hours to days before press releases can catch up.

    I like Matt Williams' YouTube Channel a lot. It’s the one channel I come back to, and I find that I always learn something from it. His videos tend to be ten to twenty minutes long, which is about right since the material is so dense.

    Start with his Optimize Your AI Models videos. They’re a lot to fit in your brain, but they’re a great starting point.

    Simon Willison’s Weblog is good too.

    Python

    I’ll have to write a few posts on how I’m using LLMs with code, but Simon’s LLM is a good general-purpose AI hammer if you need one.

    As of last week, I’m using Pydantic AI instead of OpenAI’s or Anthropic’s Python libraries. Pydantic AI will install both of those libraries for you, but I find it to be 100% better and easier to switch between models using it than LangChain (not linked) or anything else I have tried.

    Wednesday January 29, 2025
  • Django

    ,

    Python

    ,

    Today I Learned

    Python Click, django-click, and Typer notes

    One of the most significant Python innovations in my development toolchain was the Click utility, which simplified the creation of Python scripts. Click changed how I approach writing one-off Python scripts and made it easier for me to write better developer experiences around those scripts.

    Once I found django-click, writing Django management commands was a breeze, using the same Click API that I was already familiar with.

    Arguably, the second most significant innovation was the Typer library, built on Click, making writing Python scripts even easier. I didn’t think it was possible to be easier than Python Click until Typer came out and proved me wrong.

    The Python Click library

    A typical pattern I use with Click is creating a command that accepts an argument like a URL.

    import click
    
    
    @click.command()
    @click.argument("url", type=str)
    def command(url):
    	do_something(url=url)
    

    The Python django-click library

    This works well, but one improvement would be to accept as many url arguments as I can pass to it. Thankfully, Click solves this with the nargs argument. I always have to look this up, which is why we are here.

    import djclick as click
    
    
    @click.command()
    @click.argument("urls", nargs=-1, type=str)
    def command(urls):
        for url in urls:
            do_something(url=url)
    

    The Python Typer library

    Suppose we were writing this example with Typer. In that case, we could simplify it to using Python’s native data types, which would make it feel more like I’m writing native code and less like I’m using a library.

    import typer
    
    
    app = typer.Typer() 
    
    
    @app()
    def command(urls: list[str]): 
        for url in urls:
            do_something(url=url)
    

    Conclusion

    There is also a django-typer library, bringing the Typer library to Django. I suspect I’ll switch to django-typer the next time I start a new project to give it a good test drive. I can speculate on what that looks like, but I’ll leave that for another day.

    Wednesday January 22, 2025
  • Django

    ,

    Python

    ,

    Today I Learned

    ๐Ÿ“ฉ Email, Calendars, and the Chaos of Modern Workflows

    I was feeling overloaded with emails this week, and then I remembered that my out-of-office auto-responder told people they should contact me after the first of the year if they needed me to reply.

    Thankfully, I could select and archive all of my 2024 emails with this rule label:inbox after:2023/12/31 before:2025/01/01, which reconciled my old emails.

    Calendars and shared Documents

    With each Google organization, I’m a member with another Google Calendar, Google Drive, and Google Contacts to manage. That document someone wants feedback on sometimes feels like spinning a wheel, and I need to guess which inbox and account the message might land in.

    The best solution that I have found for juggling meeting invites is Reclaim, which is terrific for merging multiple calendars into one calendar so I can at least keep on top of meeting invites and scheduling. Dropbox recently bought them, but I’m hoping that Dropbox will leave them alone.

    Email and calendars have become more challenging since I switched to a Mac Studio at the office. While we were returning to work during a blizzard last week, I realized that my personal Mac Mini in my home office had no concept of my work calendar or the 4 or 7 Vivaldi profiles with syncing that I use to jump between orgs all day.

    With 1Password, this is a straightforward process to set up and authorize, but it still takes time.

    Tonight, I’m pretty sure I even locked myself out of one service because it’s probably not a typical usage pattern to jump between three Macs over two locations with a half dozen profiles to juggle.

    Calendar Agent

    Over the Thanksgiving break, I wrote my first Calendar Agent, who can read and write to my work calendar. It’s not fully baked yet, but it works well enough to tell me about my upcoming meetings and to create a meeting for me. Sometimes.

    The biggest downside to using my Calendar Agent is that I have to run it from my terminal, which isn’t always the most convenient place.

    Side note: I might rewrite my agent using PydanticAI as an excuse to learn about the Python agent framework, streamline tool-calling, and play with more local agents using Ollama.

    The better email solution

    The better email solution was a Django email app called Concorde, one of Adam Fast’s creations. It was Django querysets for managing email rules, which I modified and ran over the years. It quickly created better rules than Gmail supported, like deleting old messages in specific folders after x-days. When I kept my fork running and updated, the tool was invaluable. When I kept my Concorde up and running, my email life was healthier than when I was slower to fix it after an upgrade.

    Conclusion

    I’m annoyed that the best solutions for these problems are to either pay a company to make a Google Suite usable or you must be a developer to build tools to manage it all.

    This stuff sucks.

    Wednesday January 15, 2025
  • ๐Ÿˆ The best NFL broadcast teams and telecast quality, ranked

    John Gruber posted his picks a few weeks ago, and I couldn’t disagree more.

    2024 NFL broadcast teams and telecast quality, ranked:

    1. Mike Tirico and Chris Collinsworth, NBC (the best duo by a lot)
    2. Al Michaels and Kirk Herbstreit, Amazon
    3. Jim Nantz and Tony Romo, CBS

    – the floor –

    1. Kevin Burkhardt and Tom Brady, Fox
    2. The Manning Cast. If not for a paint-dryingly bad combo of Joe Buck and Troy Aikman, I would never have put the Manning Cast above anyone. This isn’t even fair to Aikman, who isn’t that bad, but Joe Buck should stick with baseball.
    3. Joe Buck and Troy Aikman, ABC, aka paint drying

    Al Michaels, Mike Tirico, and Chris Collinsworth are what football sounds like to me after Madden. Damn, I miss Madden. Even boringly one-sided games he made special.

    Sunday January 12, 2025
  • Django

    ,

    Python

    ,

    Today I Learned

    django-templated-email-md notes aka if you want to format emails with Markdown, use it

    I launched Django News Jobs two DjangoCon USs ago, and I somehow put off deploying emails until this week. So, every day or two, I check my Review Jobs queue to see if there’s anything new to approve or reject.

    โœ… Sending emails with Django is straightforward and not very painful.

    ๐Ÿค” Working with most email providers and troubleshooting issues is painful.

    ๐Ÿค” Starting with a blank page and styling emails is painful.

    I tried a few third-party apps that I fought with before landing on Jack Linke’s django-templated-email-md (DTEM), which just worked. DTEM doesn’t re-invent the wheel, but it does let me write my email messages with Markdown, which turns out to be all I need.

    To add email support, I followed the Usage Guide and then I added one send email function per email that I wanted to send. I’ll eventually refactor this, but it was good enough to get started.

    jobs/models.py

    For the curious, the code looks like:

    # jobs/models.py
    
    # a bunch of imports ... 
    
    from templated_email import send_templated_mail
    
    ...
    
    class Job(models.Model):	
        ...
    
        def send_job_new_email(self):
            send_templated_mail(
                template_name="job_new",
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=settings.ADMINS,
                context={
                    "job": self,
                },
            )
    

    send_templated_mail does the actual sending, and template_name will look for a template file called job_new.md, which will contain our Markdown message.

    You can put anything you want in context, but I will include the job so we can include as many details from our job submission as possible.

    To send a Job, I can call job.send_job_new_email() via a signal, cron job, or after someone submits a Job for approval.

    templates/emails/job_new.md

    My emails contain both a “subject” and “content” block, and DTEM figures out the rest for me.

    <!-- templates/emails/job_new.md -->
    
    {% block subject %}[{{ site_name }}] New Job Posting: {{ job.title }} at {{ job.employer_name }}{% endblock %}
    
    {% block content %}
    # New Job Listing Posted
    
    A new job has been posted on the website:
    
    - **Title:** {{ job.title }}
    - **Company:** {{ job.employer_name }}
    - **Location:** {{ job.location }}
    - **Remote:** {{ job.get_remote_display }}
    
    You can view the full job listing here: <a href="{{ job.get_absolute_url_with_domain }}">{{ job.get_absolute_url_with_domain }}</a>
    {% endblock content %}
    

    My get_absolute_url_with_domain calls in my templates are my workaround for Django’s existential crisis of not making it easy to include the domain name in my urls.

    Bonus: Django-Q2

    I paired DTEM with Django-Q2, my favorite Django task queue. It can work with just the Django ORM, which is good enough for projects like Django News Jobs, which are relatively low traffic but spiky traffic.

    If my email-sending provider times out or I have an issue, like my credit card expiring, I never want a user to see it. So, I use a task queue to handle all potentially blocking processes, like sending emails.

    Django-Q2 is painless to configure. Using it involves importing async_task and modifying our send_templated_mail method to be an argument to the async_task method.

    # jobs/models.py
    
    # a bunch of imports ... 
    
    from django_q.tasks import async_task
    from templated_email import send_templated_mail
    
    ...
    
    class Job(models.Model):	
        ...
    
        def send_job_new_email(self):
            async_task(
                send_templated_mail,
                template_name="job_new",
                from_email=settings.DEFAULT_FROM_EMAIL,
                recipient_list=settings.ADMINS,
                context={
                    "job": self,
                },
            )
    

    If a Job was sent successfully, I can now check the Django Admin to see if there were any failures.

    Forward Email

    Now that we have an email confirmed to send, my go-to provider for side projects is Forward Email. They allow outbound SMTP and even support webhooks, which I might write about some other time.

    I like them over Mailchimp, Sendmail, and Gmail because they are cheap ($3 a month) and let me have unlimited domains and aliases. I have used them for a dozen side projects for several years now, and they just work. I gave up on Sendmail because I spent more time fighting with them to not turn off my account because the volume was too low. It’s worth $36 a year to have to fight this fight again.

    Forward Email’s products and services are fully open-source if you care about such things.

    Saturday January 11, 2025
  • Django

    ,

    Python

    ๐Ÿค” Rethinking Django's Command-Line Tool: Why We Should Rename `django-admin`

    Django has been a key tool for Python web developers for many years. But as new frameworks like FastAPI become prevalent, it’s important to ensure Django stays easy for new and experienced developers. Recently, a discussion thread received over 60 comments about changing Django’s main command from django-admin to something else, like django. The thread also explored other django-cmd possibilities, showcasing many ideas. While the conversation was broad, I want to focus on why renaming django-admin is a good idea.

    Why Rename django-admin?

    Keep It Simple and Pythonic

    When I chaired DjangoCon US, a common question I asked attendees during our opening session was whether they learned Django first or Python first. It surprised me to see the majority of hands raised for “Django first,” which meant that learning Django taught them Python. This showed me how important Django is for teaching Python.

    Because Django helps so many people learn Python, it should follow Python’s simple and clean style. Changing django-admin to django makes the command easier to remember and use. New developers won’t have to remember an extra non-off command, making their experience smoother.

    Easy Transition for Everyone

    One great thing about django-admin is that it has been the same for many years. If we rename it to django, we don’t have to remove django-admin. Instead, we can make django an alias for django-admin. This way, old projects can keep using django-admin, and new projects can use django. This change won’t disrupt anyone’s work.

    Real-Life Benefits

    This change is prompted by common problems in the Django community. For example, a forum post showed that some developers get confused when trying to run django-admin as a Python module. They saw errors like ModuleNotFound because it wasn’t obvious why python -m django-admin didn’t work.

    Improving Compatibility with Tools Like UV

    Another issue is that commands like uv tool run django don’t work as expected, but they could. Python’s best practices support using python -m django, which would work smoothly with tools like UV if Django updated its command structure. Instead, the “correct” answer is to run uv tool run --from django django-admin to bootstrap a Django project.

    Renaming django-admin to django and aligning with Python’s module execution standards can make integrating Django with such tools just work. This change would help developers avoid errors and follow best practices, enhancing overall compatibility and workflow.

    As it exists today, a new user has to learn to use django-admin to start a project, and then later, once they learn from seeing python -m pip used.

    Balancing Old and New

    Django has been around for a long time and has a strong history. It’s important to keep what makes Django great while also making improvements. Renaming django-admin to django respects Django’s past and helps it move forward. This change keeps Django reliable for long-time users while improving it for new developers.

    Is this change zero work?

    No, it requires a one-line config change and replacing every instance of django-admin in the docs. Any changes in Django’s docs will inevitably trigger translation changes, but these should be small and tightly scoped. As of today, there are 39-page instances to update.

    Conclusion

    Renaming django-admin to django improves Django’s developer experience. This new name makes the command more straightforward to remember and follows Python’s best practices. It also makes it simpler for new developers to start with modern tools like UV.

    Although this change means updating some configuration files and documentation, the long-term benefits of having a clearer and more Python-like command are much greater than the initial work needed. Keeping django-admin as an alias also ensures that existing projects continue to work without problems.


    Join the conversation here and share your ideas on making Django even better for everyone.

    PS: This piece was written quickly and proofed even more quickly with Grammarly.

    Wednesday January 8, 2025
  • Python

    ๐Ÿš My most used commands in my terminal history

    This post was inspired by Andrea Grandi’s My ZSH history post, but I modified it back to work with my customized BASH output instead

    โžœ history | awk '{print $4}' | sort | uniq --count | sort --numeric-sort --reverse | head -10
    11063 git
    7636 just
    3280 cd
    2575 workon
    1512 ls
    1061 subl
     967 docker
     887 cat
     703 python
     700 gittower
    

    I guess you could say I use git a lot.

    just is my main workflow driver.

    workon - I switched between projects 2575 times.

    subl and gittower are aliases to open Sublime Text and to open the existing project in Git Tower, respectively.

    I used docker more than I would have guessed, but just tends to wrap most of that workflow, or it would have given git a run for its money.

    Thursday January 2, 2025
  • Django

    ,

    Python

    ๐ŸŽŠ Year in review (short version) - It was a good year

    I love end-of-year posts and reading everyone’s posts. Every year, I draft one, and then I give up on publishing it around March or April after a comically long time. I’m going for shorter than longer this year because a lot happened this year, but most important is how I felt closing 2024 out. Overall, 2024 was a good year despite its many ups and downs.

    Family

    My kids grew a ton; we ended the year with a three and seven-year-old. Three-year-olds have big personalities, and my first-grader decided he could read anything after the first two weeks of school. We had several family trips, including a big family reunion in Chicago(ish) and a trip with my family to Colorado, so we got to see a lot of both families.

    Each of our parents went through one hip surgery, and both are doing well. One of my parents had some more serious medical issues that we are hoping are behind everyone now. We buried two aunts in 2024, which brings me down to just one aunt and uncle (both by marriage).

    Because time is so short, my new metric of a good year is measured by the health and well-being of our family and parents.

    Writing

    I published 230 posts this year on my Micro Blog, which ranged from short thoughts to longer posts. I have always wanted to blog, but 2024 is the year I finally made it a priority and figured out what worked for me to ease the publishing friction. I wrote about everything from Python to Django to UV to what I was watching, and I was surprised to see it inspire other blog posts and podcasts. So writing works, friends. Even if it’s just about what show you watched last night.

    I’m also pleased with how my Now turned out. The page shows the latest movies, series, and games we are playing. It’s rapidly becoming a dashboard for me, which might be what my homepage turns into.

    Conferences

    I attended PyCon US in person for the first time since 2019 and DjangoCon US.

    Volunteer/Community Work

    2024 was a break for me after a decade of leadership roles in several non-profits. After five years on the Python Software Foundation board, 2024 was my first full year off. I stayed in one workgroup, but I stepped down on everything else.

    After serving as President or Vice President, 2024 was my first full year as only a Django Events Foundation of North America (DEFNA) director and a DjangoCon US organizer. I had room to volunteer during DjangoCon US without my time being spoken for. It felt more or less like an emeritus role.

    I mentored a small cohort for Djangonaut Space this year for the Django Packages project. It was a rewarding process, and I look forward to helping in a future session now that I know what to do. (If you were in my cohort, I promise to post that follow-up blog post soon.)

    I joined the Django Software Foundation (DSF) in December, intending to hire an Executive Director. I was so happy to have my time back in 2024 that I decided to give the DSF one more year to do this on their own, but a small mob of friends asked me to run at DjangoCon US this year. So, I ran for the board, and now I have less than two years to hire someone so I can go back to normal life.

    Office Hours

    I hosted several Office Hours every month, letting them grow into what they needed to be. Some weeks were more structured than others, but watching this turn into a community on its own with lots of new and regular faces joining and sticking around. It’s fun and something I want to keep doing in 2025.

    Side Quests

    I enjoyed a ton of side quests this year, which I have already written about over the last year. From the newsletter to a job board to even a project to try to make Django talks more discoverable to a bunch of random AI projects. I had a lot of fun working on side projects and side quests.

    Going forward

    I left a ton of details out, but that’s alright. After 230 posts last year, it’s hard to summarize the journey, but I plan to keep removing the friction that keeps my drafts above 200 posts, which may never see the light of day.

    Wednesday January 1, 2025
  • โญ GitHub Stars are only good for measuring a project’s number of GitHub Stars, not much else.

    Now we can include fake GitHub Stars in “not much else.” Over 3.1 million fake “stars” on GitHub projects used to boost rankings

    (via @jonafato)

    Tuesday December 31, 2024
  • Weeknotes

    ,

    Django

    ,

    Python

    ,

    Today I Learned

    ๐ŸŽ„ Weeknotes for Week 51: December 15 to December 21

    I mostly finished my holiday shopping this week. I picked up a few gifts for my family throughout the year and then randomly stressed out last week, thinking I didn’t have enough. I picked up a few last-minute items, and everyone was in good shape outside of a few gift cards. Now, to wrap everything…

    Meta

    Lately, my weekly notes have been more like monthly notes. I draft them, forget to finish/publish them, and then the following Sunday morning, I start another week. So here we are again.

    Family

    December is LEGO advent calendar month in my household. Our recently turned three-year-old participates for the first time with the LEGOยฎ ว€ Disney Advent Calendar 2024, and our seven-year-old picked the LEGOยฎ Star Warsโ„ข Advent Calendar 2024. Even if you are a grownup, these are fun, and you get some cool LEGO mini-figures.

    House

    If you ask our three-year-old what she wants for Christmas, she defaults to “Rainbow lights” because I didn’t put any lights up outside. Between our Thanksgiving trip to Chicago and two weeks of everyone in the house cycling through the crud, here we are, but at least the Christmas tree got put up.

    Community Work

    My community cups ran over a bit this week. This is due to my being new to the DSF Board and various end-of-year and before-holidays “things” that pop up.

    Community work cut into some of my open-source projects, but I’d like to catch up over the holidays.

    I also ended my week with my last Office Hours of 2024. This week was a little too non-profit and community-heavy, so I will balance that better. With the DSF having its own office hours, I want to keep solving those problems in the proper space.

    Side projects

    Side Quests

    Writing

    2024-12-20:ย ๐Ÿ—“๏ธ December 21, 2024, is Volunteer Responsibility Amnesty Dayย 

    2024-12-19:ย Default Apps 2024ย - Here are my Default Apps 2024, which builds from my Default Apps 2023 post.

    2024-12-17:ย ๐Ÿคท Why do the Django and Python communities use so many Google Forms?ย 

    2024-12-14:ย New project to shorten django-admin to django because we are not monstersย - I didn’t realize this idea would kick a hornet’s nest, and yet somehow it did.

    Entertainment

    We picked up Mighty Morphin Power Rangers: Rita’s Rewind and finished it last week. It was fun, and we like these retro games, but it’s not TMNT’s level of replayability. The game has three hours of gameplay. I’m hoping future updates address this.

    I read mixed reviews on G.I. Joe: Wrath of Cobra, but my son was pretty excited about the new Power Rangers game, so we picked it up as a beat ‘em up game we could play over the weekend. It’s buggy in ways that make me wonder how this game has been out for a few months and still has this level of bugs. The controls are bad, but we somehow played through to the last stage before we both shrugged and decided to call it a night. I would give it a two out of five stars type of game. If it weren’t for the nostalgia from my youth, I’d give it one or one and a half stars.

    New gear

    My NanoKVMs arrived a few weeks ago. I quickly ran out of ports, so I ordered some short HDMI cables, Cat6 cables, more UBC-C cables, and a cheap 8-port switch.

    I also lost my Home Assistant machine again, so I swapped out RPis and still ran into issues. As impressive as Home Assistant, running, maintaining, and keeping running is a pain. I have been debating switching to one of their yellow box hardware solutions to support them financially and hoping that I won’t lose my box once a year because it’s so hard to troubleshoot and fix.

    I also picked up a 50-foot sewer cam (for looking in walls and vents), an under-desk walking treadmill, and a smart garage door opener to replace our smart Chamberlain garage door opener because they dropped their API.

    Next week

    This week is Christmas, which means a little bit of travel. Both kids are out of school and preschool, and we both are juggling jobs and deadlines.

    Sunday December 22, 2024
  • Django

    ,

    Python

    ๐Ÿ—“๏ธ December 21, 2024, is Volunteer Responsibility Amnesty Day

    December 21 is Volunteer Responsibility Amnesty Day, one of two days every year that allows you to build out your responsibility inventory and decide what you have time for.

    Volunteer Responsibility Amnesty Day is about checking with yourself, and ending the commitments you need to end โ€“ maybe by taking a break, or by rotating it on to someone else, or by sunsetting a project.

    It’s one of the best ideas in tech because it creates space to de-commit from projects we might not otherwise have time for, but we feel like we’d be letting people down by stepping back from. It’s a wonderful excuse to step back from projects that have been weighing on your mind.

    What I’m stepping down from

    This year, I decided it was time to step down from the Paramiko, Fabric, and Invoke Triage Teams because I had not been active there in years. I volunteered to help triage issues that were always a bit over my head.

    I joined when Jeff Forcier needed some extra hands, and it might have helped get another maintainer signed up who could help out more. At PyCon US this year, I got to hang out with Jeff. I gave him a heads-up that I felt like I was excess baggage to the project because my good intentions were no longer turning into helping out the project. I have much respect for Jeff (#teamjeff) and all three of these projects.

    If you have free cycles and can help with these projects, please check out the open issues and see if you can help. I use all three beneficial projects in one way or another every week.

    What you can do

    Suppose you are signing up for projects but are not fulfilling your commitment. In that case, I encourage you to use Volunteer Responsibility Amnesty Day as motivation to step down from whatever project or responsibility you may have.

    I also want to call out some members of the Python and Django communities. If you are signing up to help with projects you know you won’t have time for, please step back and encourage someone else to help with those projects and roles. If you know that famous face you see plastered on every website and they are friends, please ask them if they know about Volunteer Responsibility Amnesty Day and share your list. That nudge may help them decide if they are taking on too much.

    Friday December 20, 2024
  • Today I Learned

    Default Apps 2024

    Here are my Default Apps 2024, which builds from my Default Apps 2023 post.

    ๐ŸŒ Browser: Vivaldi + Polypane
    ๐Ÿ” Search: Kagi
    ๐Ÿ“ Writing: Obsidian + Grammarly
    ๐Ÿ“ Cloud File Storage: iCloud Drive + Syncthing
    ๐Ÿ’ฌ Chat: Apple Messages (family & friends), Discord (friends), Slack (work and community work), Telegram (weird bots) ๐Ÿ“† Calendar: Apple Calendar
    ๐Ÿ“† Scheduling + Booking: Cal.com
    ๐Ÿ“น Video Calls: Zoom + Cal.com + Meeter
    ๐ŸŽต Music. : Apple Music + Spotify
    ๐ŸŽค Podcasts: Overcast (boo, hiss) ๐Ÿ” Password Management: 1Password
    ๐Ÿง‘โ€๐Ÿ’ป Code Editor: Sublime Text + Zed ๐Ÿ—ƒ๏ธ Version Control: Tower
    ๐Ÿš Terminal: iTerm2
    โœˆ๏ธ VPN: Tailscale + Mullvad ๐Ÿ”– Bookmarks: Raindrop.io
    ๐Ÿ“‘ Read It Later: Raindrop.io
    ๐Ÿ“จ Mail Client: Mimestream (Gmail only and not very often)
    ๐Ÿ“ฎ Mail Server: Fastmail (I pay for it but still don’t use it enough) + Gmail
    ๐Ÿš€ Launcher: Alfred 5
    ๐Ÿ–ผ๏ธ Screenshots: Xnapper
    ๐Ÿ‘” Menu Bar: Ice
    ๐Ÿค– Containers: OrbStack + Docker Compose ๐ŸŽ’ Backups: Backblaze โš™๏ธ Automation: Hammerspoon

    Commentary

    I spent most of 2024 Chrome-free, the new cage-free because I was so frustrated at Mozilla that I deleted Firefox from all my machines. I have doubled my Gmail Accounts and usage between non-profits and community projects.

    I’m a happy Vivaldi user and advocate. I only had a handful of issues, quickly solved by turning all or some level of trackers back on. The worst offenders were both my bank and my credit card company.

    I dropped Bartender and switched to Ice after the company started acting shady due to poor communication. I have no regrets.

    My beloved Overcast podcasting app has been complete garbage for more of 2024 than it was working. The author rewrote it, and it became an unusable disaster for months, one part of Marco’s fault and one part of Apple’s fault for making the iOS App Store such a pain to release products into. It still has Airplay issues and crashes on me, but I can once again play more than one podcast in a row without it crashing. I tried many other podcast apps, and I’m sad that this is the state of things.

    I have mostly switched from Docker to OrbStack, which I highly recommend for my development life. I keep Docker around for Compose, but I have several legacy projects I haven’t ported yet.

    Previously inspired by: “Apps I’ve been using regularly this year.” Heavily inspired by Matt Stein and cataloged by Robb Knight’s App Defaults

    Thursday December 19, 2024
  • Django

    ,

    Python

    ๐Ÿคท Why do the Django and Python communities use so many Google Forms?

    Last week, I wrote but didn’t publish some notes about why the Django and Python communities use so many Google Forms.

    The simple answer is that Google Forms are quick and easy to set up, and data can be easily exported via Google Sheets or a CSV file.

    Getting data in and out of Django isn’t hard, but why isn’t it as easy as using Google Forms?

    I’d love to see a Django version of Google Forms that we can all use.

    Has anyone solved this problem?

    From a technical perspective, Django ships with a JSONField, which can store any form data we want without having to migrate databases. Turning a flat JSONField into CSV is already a solved problem.

    Please note: I am not looking for a Django forms wrapper or your opinions about why Django should use your fancy Django forms tool.

    Tuesday December 17, 2024