I used Tessl to build Jot's waitlist website, learned what it takes to build a truly reliable AI software factory and then rebuilt the pipeline on Claude.
Can I create a GitHub issue, walk away and come back to a production ready PR?
Not just a code snippet or a first draft that I then had to finish off. I mean the full engineering loop: understand the requirement, implement the change, run the checks, deal with any failures that occur, and then have a PR ready for review. I wanted to find out, but there was one area I wasn't prepared to go into at all: the actual product.
My co-founder and I are building Jot, an iPhone day planner that works around your Home Screen with a Mac companion app. The concept is really simple: you see your day via widgets and notifications, you can make notes on the go and if things change you just ask Jot to update your calendar for you in your own words rather than having to go in and re-build your calendar from scratch. We started off with a bunch of interviews with students and young professionals, most of whom are iPhone and Mac users.
Jot is something we want people to use every day. Giving an experimental agent workflow the keys to the codebase before you actually understand its limitations just doesn't seem like a great idea. So we went looking for something smaller.
Our marketing/waitlist website (jotyourday.com) was a good testbed in that it had real users, a database, privacy implications and sufficient frontend complexity to give an agent some actual work to do. The only downside was that if anything went wrong it wouldn't have impacted the development of the site itself.
That was the experiment: could an AI software factory take a well-defined GitHub issue all the way through to a working pull request without me having to write the implementation at all?
I went with Tessl to put that idea to the test. Over the course of the project I raised 18 issues with the factory. All 18 of those resulted in merged PRs, using up approximately 2240 credits.
Those numbers look very promising. The path to getting there though involved a few things I hadn't anticipated and some lessons that have completely changed the way I now think about building with agents.
I first saw Tessl at AI Native DevCon in NYC in 2026 (attended online). That was where I first encountered the concept of software factories. Rather than treating AI agents as coding assistants that you prompt one-off, you give them skills, workflows and verification so that they can perform repeatable engineering tasks. That's precisely what Tessl was building a platform around.
The idea is pretty simple really. You define reusable skills for agents, chain those skills together into workflows (called loops), and then wrap that work in some form of verification and feedback. Tessl is model and agent agnostic and comes with a number of pre-built workflows for things like ticket to PR, code review against team standards and vulnerability remediation.
At the conference Tessl were offering people $200 in usage credits (which in my account is 10,000 credits) for 30 days from activation. That gave me both the tools and a deadline to actually use them.
I've listened to Tessl's talks and it was there that I first learned how to think about structuring a software factory. Listening to a description of a workflow and then trusting that workflow with an actual codebase are two very different things.
I'm new to the platform so I'm starting with one bit: the ticket to PR factory. I hadn't looked at the skills registry, the evals or most of the guides really at all. Those are things I intend to go and have a look at in more depth.
Before handing over any work at all, there was one thing I needed to get absolutely right first: the environment the agents would be working in.
I didn't want the agents to have to work out the architecture, the design conventions and the engineering standards from scratch every time they got a ticket. If I wanted the same results every time, I needed to give them a codebase that they could understand and a set of rules that they could follow.
So I built the foundations of jot-web myself before letting the factory have any say in it.
The site is on Astro and Cloudflare. It's a very flat repo with just about 15 files. The waitlist sign-ups are in Cloudflare D1 with the unticked consent boxes, the consent text and all the other UK GDPR basics. The survey and call booking is handled via Tally.
The design was all there, thanks to my co-founder. I took that and turned it into colour tokens, fonts and copy notes in the repo so the agents had something concrete to work from rather than having to work out what a component should look like or do. Then came the engineering rules.
I started off with an AGENTS.md file with about 30 lines of instructions in it. It was essentially capturing the conventions that we wanted every agent to follow (token styling, breakpoints, reduced motion, accessibility, data handling, PR formatting etc). As the project progressed that file grew to around 80 lines.
The idea was really quite simple: if you found yourself having to remind an agent of the same rule on more than one occasion, it was clearly something that should be in the repository rather than in some other prompt.
This was important. I wasn't out to get an agent a whole website from a very vague brief. I was giving them a very specific environment, very clear expectations and a fairly small job to do.
With the repository, the design notes and the rules all in place the factory had everything it needed to start working. It was now time to see what actually happened when I handed it a ticket.
The process began with a GitHub issue. I’d write down what needed to change, provide the relevant context and define the acceptance criteria very clearly. I was very conscious of defining what was out of scope. The more precisely I could describe the desired outcome, the less scope there was for the agent to make assumptions.
Once the issue was ready I added the tessl label. That was the trigger. Tessl picked up the issue, created a branch and started implementing the change on its cloud machine. Once it was complete, it opened a PR for me to review.
But opening a PR wasn't necessarily the end of the job. I'd go through the changes, verify that the implementation met the requirements, and review the results of the automated checks. If anything failed or needed to be changed, then I'd send the agent back to fix it (that might be to fix a failing check, make a follow-up change or resolve a merge conflict).
I still tested the changes locally prior to merging. The agent did the implementing, and I was the one who decided whether it was good enough to ship.
Having sorted out the problems, the numbers were very encouraging.
| Measure | Result |
|---|---|
| GitHub Issues | 18 |
| Pull requests merged | 18 |
| Total credits | about 2,240 |
| Average credits per PR | 123 credits |
| Most expensive PR | 243 credits |
The most expensive issue used 243 credits. That was more than just the initial implementation, it also included shepherding the work, dealing with the follow-up changes and the merge conflicts.
The factory worked across a number of areas of the site. Built the waitlist form and its backend endpoint, worked on the header and hero, did the scroll-driven widget animation, and created the side-scrolling section that explains how Jot works. It also did the thank-you page confetti animation and a number of other small bits.
One thing that helped was keeping the issues very small and focused. Each issue produced a single PR, which made the changes much easier to review and gave the agent a very clear target. I wasn't asking it to build a whole page or rework the site. I was just giving it a small piece of work with a very specific outcome.
Looking at the numbers alone, it would be easy to come to the conclusion that it was a fairly straightforward success. 18 issues in, 18 merged PRs out. A merged PR doesn't necessarily equate to a smooth process though, and there was a fair bit of back and forth behind those numbers. There were a number of issues that I hadn't actually anticipated when I started.
The first issue was down to the environment itself. Some of the tasks required browser-based testing via Playwright. When the agent went to run the tests, it failed at the headless Chromium stage due to missing system libraries on the cloud machine. The code wasn't the issue really, the environment just wasn't set up to run the tests.
I sorted it out by having Playwright install its dependencies via the setup hook. Once that was in place, the browser tests could run perfectly.
There were smaller, less obvious problems. Early tickets sometimes repeated instructions that were already documented in AGENTS.md. Agents occasionally referenced stale file paths or PR numbers, resulting in unnecessary review rounds and additional credit usage.
These weren't catastrophic issues by any means, but they did add friction. Every iteration that could have been avoided meant more time spent managing the agent and more credits burned.
It made me look again at how I was preparing work for the factory. I'd originally thought the key bit of working with agents was to write better prompts and give them more detailed instructions. That wasn't quite it.
The biggest difference was in the context they could access in the repo itself: keeping the instructions current, making the project structure clear and understandable and ensuring that each ticket had sufficient context to be workable.
In other words, the quality of the factory's output was so much down to the quality of the environment that I'd prepared for it. That, in turn, made me go back and rethink another element of the workflow completely: how the tickets themselves were being created.
The more I worked with the factory, the more I realised that getting good results wasn't just down to how well the agent actually implemented the code. It was right from the outset with the quality of the tickets we gave it.
Writing a good issue takes time. You need to understand the code as it stands, work out the right scope, think through the edge cases, determine what a successful outcome would be, and ensure that the acceptance criteria are actually testable. Doing that for every little change can itself become a bottleneck.
So I started off by trying a different approach entirely: what if I used Claude to help generate the tickets before passing them over to Tessl?
I built a Claude skill called /ticket.
The idea was to provide a rough observation or feature request, rather than a fully written specification. For ex:
The privacy column is blank following the last PR.
That would get us going. The skill would look at the repo, read AGENTS.md and the design notes and have a look at the relevant GitHub issues and PRs. It would then ask any questions where the requirements were unclear, help to break the work into appropriately sized tickets and draft the issues.
A particularly useful part was how it handled acceptance criteria. Each criterion was tagged according to how it should be verified:
`(test)` for automated tests`(e2e)` for end-to-end tests`(manual)` for checks that needed a person to verify
For the visual requirements, we could go with actual concrete measurements rather than just descriptions. So a spacing requirement might be `36px / 1440px` rather than some vague description.
Once the draft was ready, the skill opened a GitHub issue with the spec:draft label. I'd go through it, make any changes that were required and only then add the label that would trigger the implementation workflow.
This gave me a useful separation of responsibilities. Claude helped turn an idea into a well-defined piece of work, while Tessl handled implementation. It also meant I could use my Claude subscription for the planning and specification work, keeping the Tessl credits for the part they were intended for: building.
The bigger lesson was that the quality of the output wasn't down to the coding agent per se. You needed a good way to take an observation and turn it into a small, testable task before you even started writing any code.
Eventually, I'll run out of Tessl credits (even with the 1000-credit monthly renewals that are free).
But now I had a much clearer idea of what I was after in terms of the workflow. Rather than just stop experimenting and stuff as many PRs as I could into the system with my remaining credits, I decided to see how much of the same process I could replicate using my Claude Pro subscription and GitHub Actions.
I wanted to preserve the important parts: issues as the source of truth, labels as triggers, automated implementation, reviews, fixes and human approval before merging.
The first thing I carried over was the /ticket skill. It was still useful for taking a vague idea and turning it into a properly scoped GitHub issue, so there was no point in changing that at all.
For implementation, I used a Claude label to trigger the workflow. GitHub Actions picked up the issue, kicked off a Claude session, and implemented it. The existing CI pipeline was left completely unchanged. I then added scheduled tasks around GitHub events to handle the rest of the process. One was to check pull requests for review; the other was to handle automated fixes for failed checks and comments. The review task was set to run on PR open and on the addition of a re-review label (rather than on every single update).
I also added a guard hook to stop potentially dangerous Git operations (in particular pushes which could inadvertently impact branches). If the agent wasn't confident it understood the task, it was instructed to leave a comment requesting clarification and to simply remove the trigger label rather than make any assumptions.
The prompts themselves lived in .claude/prompts/, while CLAUDE.md was kept deliberately small. It contained a one-line import of AGENTS.md, so both the workflows could follow the same repository-level instructions without maintaining two separate sets of rules.
The overall process looked familiar:
/ticket. claude label to start implementation.
The very first issue I tried on the Jot app repository went from 'add label' to having a merged, ready PR on the first go.
That was encouraging, particularly as I'd put the workflow together myself using tools I already had access to. I could also access the Claude sessions on my phone or in the terminal, which made it much easier to keep on top of things without being locked into my laptop.
It wasn't a direct 1:1 recreation of Tessl. That said, it was quite sufficient to test whether the underlying workflow could be replicated with a subscription, GitHub Actions and some custom automation.
Rebuilding the workflow on Claude was useful, but there were definitely some drawbacks.
The biggest difference was that I now owned more of the machinery. With Tessl, I was using a platform built around the software factory concept, with ready-made workflows and managed infrastructure. With Claude, I had to put the pieces together myself and maintain the automation around them.
There were also constraints. Claude utilises a shared usage pool, so the work being done in these automated sessions competes with my normal use of Claude. Tessl's credit model meant it was far easier to track the cost of running the factory separately.
Another difference was how GitHub presented the changes (the PRs appeared to be coming from my account), which meant I couldn't approve my own PRs. I had to go with the green CI checks and manual merges rather than just treating an automated approval as a stand-in for a real human reviewer.
And crucially, the Claude workflow is still very much in the experimental stage. Getting one issue through successfully in no way guarantees that all the subsequent issues will go through without some form of intervention.
So how do I compare the two?
Tessl gave me a more managed environment in which to run a software factory. It was a useful way to get the concepts sorted and to have a ticket-to-PR workflow in place without having to build all the infrastructure ourselves.
Claude gave me more control over the individual steps, but also made me responsible for writing them all together, keeping them and dealing with their constraints.
I don't think one makes the other irrelevant. For a solo dev who wants to experiment and has the time to build out the surrounding automation, the Claude approach is a viable option. For a team looking at a more structured, managed approach, Tessl is a different proposition. For now I'm just going to keep on learning and experimenting with both.
The key thing I took away from this wasn't that I could swap one platform for another. I now understand the workflow components well enough to build and adapt one myself.
The waitlist site was always intended to be a test. The more interesting challenge is what happens when you apply that same workflow to the product itself.
Jot's actual app is a completely different engineering problem. We're building a native iPhone app in Swift and SwiftUI with home screen widgets, notifications and a Mac version too. The schedule adjustment is a far more complex planning problem in itself in that you have to work out what has changed, what you can actually move and then restructure the rest of the day without losing the user's priorities. That's a very different ball game to just changing a section of a marketing website.
My next step is to apply the same issue to PR workflow to the native codebase, with the caveat that we have much stricter expectations around testing and verification. The agents will help with implementation, but we absolutely have to remember that people will be using this software in their day-to-day lives.
We're currently on track for an alpha at the end of January. I'll be documenting the journey as we go from a fairly contained website to the actual product, covering how the workflow handles native code, the planning algorithm, and all the more demanding tests.
If you'd like to keep up with it, you can join the waitlist at jotyourday.com or follow us on Instagram at @jotyourday. And if you’ve been building with AI agents, I’d be interested to hear how you’re approaching larger tasks. In particular, how do you break down goals that span multiple components, and how do you keep agents working reliably on tasks that take longer than a single session?