What problem does this solve?
I am the technical point of contact for 30-plus client accounts at a time inside a book of more than 100. Work reaches me through Basecamp, and a large share of it has the same shape: a task lands, I load everything I know about that client, and I write back a solution that fits their specific stack.
The loading is the expensive part. Not the thinking. The reassembling of context that lives in my head and in scattered documentation, every single time, before any real thinking can start.
So I automated the reassembling and kept the thinking.
What constraints did it have to work inside?
This runs against a live agency workflow on real client accounts, which fixed a few things before I wrote a line of code.
Event-driven, not always-on, because the work arrives in bursts and I could not justify paying for idle compute. Stateful across a multi-step pipeline, because one request fans out into retrieval, generation and delivery, and any of those can fail on its own. And delivered by email, because that is where the reply actually gets read, which put a hard ceiling on how big a single response could be.
What did I build?
A serverless pipeline in Python on AWS. I wrote all of it.
The agent watches Basecamp for tasks assigned to my user ID. On trigger it pulls client-specific context out of project markdown files, calls the Claude API to generate a solution shaped to that client, and delivers it by email. DynamoDB carries state between stages, so each step knows what the last one produced and a failure does not swallow the request.
When a response is bigger than a mail server will take, it does not get truncated. The agent writes the whole thing to S3 and sends a pre-signed URL instead, so a long answer arrives complete instead of clipped mid-sentence.
Decisions
Markdown files, not a vector database. Client context here is a bounded set of documents I maintain by hand, not an open corpus. Reading the relevant files directly keeps retrieval exact and legible: I can open the same file the agent read and see precisely what it was working from. A vector store would have added an embedding pipeline, an index to keep in sync, and a category of retrieval failure that is genuinely hard to debug, in exchange for recall I do not need at this size. I would make a different call at a hundred times the documents.
DynamoDB for state instead of stuffing everything in the event payload. The stages are separated in time and fail independently. Holding state outside them means a failed generation can be inspected and retried against the context that was actually retrieved, rather than replaying the trigger and hoping retrieval resolves the same way twice.
A pre-signed URL instead of splitting the email. A solution broken across three messages is worse than a link, because now the reader has to reassemble it. Sending the whole response as one retrievable object keeps the output intact and the delivery path simple.
Outcome
Live in production. I use it every day.
It saves me 60% or more of the time I used to spend researching, writing and working through the tasks assigned to me. That is my own measure of my own workload rather than a benchmark somebody else audited, and I would rather label it that way than dress it up as something it is not.
What it does not do is decide anything. It assembles the context and drafts the answer. I still read every one before it goes anywhere near a client, because the agent is good at the part that was slow and I am still the part that is accountable.
Where this belongs
This is a Prospecta Marketing initiative, built inside my role there. It is not freelance work and it does not belong to Tangent Apps.
Stack
- Python
- AWS Lambda
- DynamoDB
- Amazon S3
- Claude API
- Basecamp API
