Logo - Cameron's initials

Building Throughline - Thoughtful AI Co-Creation

Published on
Authors
  • avatar
    Name
    Cameron Perry

6 min read

I recently released Throughline, a knowledge engine for podcasts: "Ask your podcast anything".

I undertook this project to achieve a few goals: First, I wanted to build-out an idea beyond a simple proof of concept into something that is actually useful, taking a product engineering approach. Second, I wanted continue expanding my Applied AI and AI Engineering knowledge and skillset. Finally, I wanted to treat the language model as a pair programmer and co-creator and not a vibe coding token machine. I wanted it to be a knowledgeable aid to help expand my capabilities and capacity - to strenghten how I think, not replace my thinking.

I will discuss the third goal - how I approached development using AI from concept through v1.0 release. First, a bit about Throughline.

Briefly, Throughline allows you to transcribe episodes from podcast feeds and use those transcripts for RAG-based chat sessions about the content discussed in the podcasts. The app is built as local-first, employing local models and services like oMLX, Ollama, or llama-serve on localhost, but it can also make use of external OpenAI-compliant APIs. I've included more information in the github project's README overview.

AI Co-Creation

To help you with a better sense of how I worked with AI, I'll layout a couple foundational points. First, I wanted it to be a deliberate and thoughtful collaboration with the tool - Claude Sonnet. From the first prompts, I laid out my primary objectives (build a product, learn and expand some topics) and the ground rules for working together. This included approaches to determining the correct architecture, impacts on the product and UX, and the absolute importance of being a two-way conversation over code dumps. I'll take blocks of code and file, but not without review, followup questions, and propose revisions. Likewise, I asked for deeper explanation and even questions to draw out my understanding. Think of it like digging deeper with a patient subject matter expert.

The elephant in the room... If you're not vibe coding, are you even AI-ing!?

Vibe coding, for the sake of this discussion, will be defined as the practice of prompting and coming back to finished code with little or no input. We know the effects - it's hard to fully understand what code the LLM produced and how it works into the larger application/system - the output can be too voluminous to reasonably interrogate. Addy Osmani touched on the difference and comprehension debt for us.

As I chose the collaboration approach, I was aiming to reduce (remove) much of the uncertainty and skill atrophy that comes with vibe coding. I used it as a force-multiplier. Practically speaking, this meant taking the conversation to a chat interface, and not using Claude Code directly. That was a deliberate tool choice that forced me to slow down, consider the output, and reason through considerations and variables without blindly accepting the LLM output. In places where code, approach, framework usage wasn't clear, I could dig in and interrogate the decisions brought to me, often finding better alternatives than the initial offer. It's far too easy to let that machine go brrrr and come back to something you're not entirely clear about. For Throughline, it's a back-and-forth conversation, E2E, across features. Truly, I feel my knowledge and skills greatly improved through this experience.

Planning and Execution

In Defining the Work, I discussed how PRDs are helpful steering tools. In this project, I decided to take a lower-structure approach, but still use similar concepts. Over the first few chat sessions, "we" worked out the following pattern to keep progress aligned through phases:

  • ARCHITECTURE.md
  • FUTURE_SCOPE.md
  • IMPLEMENTATION_PLAN.md
  • OPERATIONS.md

We started with architecture and rough implementation skeletons (really - rough) based on what we knew and how I wanted the project to continue taking shape. Single responsibility, dependency injection, proper abstraction for replaceable components and separation of concerns, testable, etc - the same things we'd talk about and implement in any software project we cared about.

As the project progressed, each doc would be updated with my decisions, including architecture, scope, and phase planning. These documents, as they were updated, would be added back into the chat project for the LM to reference. In addition to these steering documents, I included important details into the project Instructions prompt, a phase handoff template and phase handoff instructions that would be used to update the next chat session (eg Phase 1 to Phase 2).

Just as I work with engineers and other leaders on my teams, setting the direction ahead of the work was important. That's not to say I chose waterfall. Rather, I knew the product direction to take and made changes as new information, constraints, or needs arose. One example was deciding to postpone full speaker diarization due to local resource constraints - pyannote is impractical on non-CUDA hardware. Important consideration for a local-first application. That feature will come.

Phases

If I were to open my Claude Chat interface for you, you'd see a project and nearly two dozen different chats associated with different planning and phase conversations. These were guided by the steering docs I mentioned earlier. They kept each phase tightly scoped and prevented us from veering down too many rabbit trails. In those cases where new questions or considerations were brought up, we could either adjust the plan or pin the conversations for followup.

At each phase, we were clear on what we were building and how it would be built. In addition, we constructed a "What to build next" section. As each phase concluded, docs were updated, handoff generated, and code committed.

Conclusion

Would I take the same approach again on the next project? Yes, I think so. While not the absolute fastest approach, I believe that having a hand in the process generated a better product than had I let the machine do the work with only infrequent checkins and limited mental model of its inner workings.

The goal isn't code on the page - it's a product that works the way it should, serving the users in meaningful ways. Version 1.0.0 has been released, and I'm proud of how it turned out. I'm eager to continue with the current roadmap to see how it continues to take shape. Check it out on GitHub: Throughline.