Tricked Claude to Design the system, Not to Code (part 1)
I wanted to explore automation for a few days, and I came across Minicor , a company working on the problem of automating legacy software. The problem is simple, and I'm still figuring out whether it is worth solving at this level. But I learned a lot while building this project. Let's start. Folks

I wanted to explore automation for a few days, and I came across Minicor, a company working on the problem of automating legacy software. The problem is simple, and I'm still figuring out whether it is worth solving at this level. But I learned a lot while building this project.
Folks who want to see and demonstration github live link watch the demo
I can relate to this problem from my experience working with Tally back in 2018. You simply couldn't automate many scenarios easily. Tally was licensed software, and in practice, some people used pirated versions. The software generally had to be installed on a particular system, and there often wasn't an API available for the workflow you wanted to automate. Add network restrictions and other environment-specific limitations, and the problem becomes even harder.
There may be more integration options available today, but the broader question remains:
How do we reduce manual work and make these workflows faster when the software wasn't designed to be automated?
That's where Minicor caught my attention.
As far as I understand it, Minicor breaks the problem into a few steps:
I took this idea and started building SmartPay: an automation that creates an invoice on every API hit.
But how would we design this for more users and more legacy systems while keeping the system reliable?
While working through distributed-system design, I realised something important: before jumping into requirements and fancy features, we should first track the events and understand how a payload moves from one service to another.
Business demonstrates a scenario → Engine proposes a workflow → Business approves it → API is exposed → Business calls the API → Workflow succeeds, fails, or ends in an uncertain state.
That last part is important. What happens if the system fails and we don't know whether the invoice was created?
Let's derive the requirements from the flow above.
Out of scope for now: AI-based repair when a screen changes, editing workflow steps through the UI, tenant and user management, and billing for the automation engine itself.
Every non-functional requirement should support one or more of the functional requirements above.
Before defining them, let's look at two important failure scenarios.
We need to understand what happens when a workflow is interrupted while saving an invoice.
In the second scenario, the invoice exists, but our system may not know that. If we retry blindly, we could create a duplicate invoice and potentially charge a customer twice.
This leads to an important requirement: we must prevent duplicate invoice creation, even when the outcome of an execution is uncertain.
We need idempotency for each invoice operation. We also need to distinguish a confirmed failure from an uncertain outcome. An uncertain run should be reconciled before another attempt is allowed to create an invoice.
In other words, we shouldn't blindly retry an API request just because we didn't receive a successful response. The same request needs a stable idempotency key, and the execution system must check whether the intended effect already happened.
We also need to store the workflow definitions, parameters, mappings, and rules in a structured format, such as JSON, so every API request can be validated against the workflow it invokes.
Here's the catch: we can optimise everything on our side, but what if the target application itself is slow?
We might be able to acknowledge a request in under 500 ms, but that does not mean the invoice will be created in 500 ms. The legacy billing application may take much longer to complete the operation.
So we need to distinguish between API response time and workflow completion time.
This leads to another question: what happens when we receive 50,000 requests?
That's what I spent a good few hours discussing with Claude. Before getting into the cost estimates, I found it useful to understand a few basic concepts.
Before going deeper, here are three questions that help us estimate capacity and cost.
We also need to ask one more question: what is the limiting resource, and where does that limit live?
Suppose we need to process 50,000 invoices in four hours.
Four hours is 14,400 seconds, so the average arrival rate is:
50,000 ÷ 14,400 ≈ 3.5 requests per second
Now suppose the legacy application takes around 30 seconds to create one invoice.
Concurrency ≈ 3.5 requests/second × 30 seconds ≈ 104 concurrent runs
At first, that doesn't sound too bad. Around 104 runs in progress seems manageable from an infrastructure perspective.
Let's assume each business has one legacy application instance, and that instance can create only one invoice at a time.
If one business needs to process 500 invoices, and each invoice takes 30 seconds:
500 × 30 seconds = 15,000 seconds = 4 hours and 10 minutes
That already exceeds our four-hour target.
Adding more API servers or workers won't solve this problem. If the target application can process only one invoice at a time, the automation engine cannot make that individual instance process invoices faster simply by adding infrastructure.
The real capacity limit is the concurrency supported by each business's legacy application. Increasing it may require additional sessions, application instances, or licences, depending on what the software and the business environment support.
So the important question isn't simply, "How do we handle 50,000 requests?"
It is: How many requests can arrive, how long does each workflow take, and how many workflows can each target system safely execute at once?
For this assumed workload, we don't necessarily need Kafka or SQS from day one.
We could start with PostgreSQL as the durable job queue, keeping the execution record and queue state in the same database. That reduces the number of systems we need to operate and helps keep the execution state consistent with the queued work.
Before implementing the system, I want to identify the core entities and how they relate to each other.
At a high level, the relationships look like this:
Tenant ├── Target Instances ──> Target App │ └── Agents ├── Client Apps │ └── Runs ──> Target Instance └── Workflows └── Demonstrations Workflow ──> Runs Enter fullscreen mode Exit fullscreen mode Where I'll pause for now I wanted to keep this part focused on understanding the problem, tracing a request through the system, and identifying the first set of design constraints. There is still a lot to explore, especially around queue implementation, failure recovery, and cost estimation.
I'll leave the deeper implementation details for the next part. For now, the main lesson is simple: before scaling the automation engine, understand the workflow, track the request end to end, and identify the system that actually limits throughput.