AWS Builder Center
Weekend Challenge: Untangle

Weekend Challenge: Untangle

A sixty second ramble goes in. One sentence you actually said comes back, along with the thing you were avoiding saying. Here is how I built it on Lambda, Transcribe and Bedrock in a weekend, and the one design decision that made people stop treating it like a chatbot.

Cloud Engineer - AWS

What it does, and who it is for

Untangle is an agent you talk to when something is stuck in your head and you cannot name it.
You hold a button and talk for up to sixty seconds. Unrehearsed, unstructured, the way you would complain to a friend. If you are somewhere you cannot speak, you type instead and get the identical result.
It hands back exactly four things:
  1. A sentence you actually said, quoted word for word. This is the headline.
  2. What is really bothering you, underneath the situation you described.
  3. The decisions hiding in there, as two or three choices you have not admitted are choices.
  4. One next action. Only one, small enough to do today.
Then it deletes your audio and forgets you.
Who it is for: anyone with a knotted head and a spare minute. This is deliberately not a developer tool. Most agents built this weekend will help engineers do engineering. My mother could use this one. That constraint drove every decision, because an agent for everyone cannot have a settings panel, an onboarding flow, or a login.

How I built it

Five AWS services, roughly 1,100 lines of code, all of it Terraform.
ServiceWhat it does here
Amazon CloudFrontServes the page over HTTPS and routes /api/* to API Gateway
Amazon S3Two buckets. One serves the page, one holds audio for about twenty seconds
Amazon API GatewayHTTP API in front of the function
AWS LambdaPython 3.12, one function, every route, zero dependencies
Amazon TranscribeAudio to text, identifying which English it is hearing
Amazon Bedrockamazon.nova-pro-v1:0 reads the transcript and writes the result
Amazon CloudWatchContent free metrics, counts only, never words
TerraformAll twenty resources, one environment, one apply
CloudFront is not decoration here, and this is the detail I wish someone had told me. Browsers refuse microphone access on plain HTTP. They require a secure context. S3 website endpoints cannot serve HTTPS. So without a CloudFront distribution, the hold to talk button fails for every single visitor and the product has no reason to exist.
It earns its place a second time. Routing /api/* through the same distribution puts the API on the page's own origin, which removes CORS from the browser's concerns entirely.
The Lambda has no dependencies at all. Standard library and boto3, which the runtime already provides. Terraform zips the directory on every apply. No bundler, no layer, no container image, nothing that can go stale.

The delightful detail, and how I know it worked

The headline of every result is a sentence you said, copied word for word. Not a summary. Not a cleaned up version. The actual words, with the filler and the bad grammar left in.
Here is the problem. Models paraphrase, constantly. Ask one for a direct quote and it will quietly fix your tense, swap a word for a better word, and tidy your hesitation. It thinks it is helping.
A tidied quote destroys the product. It stops being you, legible and becomes a machine doing an impression of you. That is worse than no quote at all.
So I stopped trusting the model. Before anything reaches a screen, the quote is checked against the real transcript:
OutcomeWhat happens
verbatimIt appears word for word in what you said. Used as is.
repairedIt is close to a real sentence. The real sentence is swapped in.
fallbackIt resembles nothing you said. Thrown away, a real sentence picked instead.
A unit test asserts the quote can never escape the transcript, across every input including empty strings and entirely invented sentences. Which of the three outcomes occurred is emitted as a CloudWatch metric, so I can measure quote fidelity in production without ever storing a word anyone said.

How I know it worked

I ran twelve rambles on completely unrelated subjects through the deployed service. A job offer, a flat, an ageing parent, a dog getting old, an unfinished side project. Then I re-checked every quote against the original text independently, rather than trusting the service's own label.
MeasureResult
Rambles completed12 of 12
Quote genuinely present in the transcript12 of 12
Returned as verbatim11
Repaired by the verifier1
Discarded as invented0
Median latency, typed path1.84 seconds
Slowest4.19 seconds
That single repair is the whole argument. For a ramble that ended "I keep thinking I should join something but then I don't", Nova returned a quote that was not quite what the person said. The verifier caught it and swapped in the sentence they did say:
"Sundays are long."
Three words. Nothing a summariser would ever surface. That is the moment people stop treating it like a chatbot.

Proof it works

Hold the button and talk, or click "or type it instead" if you are somewhere public. No sign up, no account, nothing stored.
Here is a real result, from the deployed service, in both themes:
And one more, unedited, from a ramble about moving house:
**"I just havent unpacked the kitchen stuff and its been seven weeks."*You are not really settling in, and you know it. The unpacked kitchen is a sign that something deeper is holding you back. Whether to unpack or to keep delaying
  • Whether eating out is a choice or a habit
  • Whether to be honest with your sister or keep up the facadeOne thing to do: Unpack one kitchen item today. Any item. The point is starting.
Note the typos in the quote. Those are mine, preserved exactly. That is the verifier doing its job.

Everything above is what the challenge asked for. The rest is the part I actually want to talk about.

The problem nobody writes down

Think about the last time something was stuck in your head.
You probably did not need more thinking. You needed someone to listen for ninety seconds and then tell you what you just said. That is a very different job, and almost no software does it.
The reason is that writing it down is itself the work. Opening a journal, finding the words, structuring the thought. By the time you have done that, you have already solved half of it or given up. Talking costs nothing. Being understood is the expensive part.

Prerequisites, if you want to build this yourself

  • An AWS account with Amazon Bedrock access to amazon.nova-pro-v1:0 in us-east-1
  • Terraform 1.5 or newer
  • The AWS CLI, with credentials configured
  • Python 3.12 knowledge, roughly intermediate
  • No frontend framework knowledge. There is no build step at all.

The second detail: making the wait feel like listening

Transcribe takes fifteen to twenty five seconds on a minute of audio. That is a very long time to stare at a spinner directly after saying something difficult.
So there is no spinner. While you talk, the browser captures your amplitude envelope through an AnalyserNode (a Web Audio node that reports the live loudness of a microphone stream) and draws a waveform from it. When you stop, that same waveform replays back at you under the words "listening back to you".
The wait is identical in length. It stops reading as latency and starts reading as attention.
One finding from design research that I obeyed literally: if a waveform does not move with your actual voice, people assume the recording is broken. So it is driven by real microphone amplitude, never a canned animation.

Honest trade-offs

Nova Pro sounded like a horoscope at first. My first live result was "You're worried about being honest with yourself and others, and the fear of disappointing people." That fits every human alive, which means it tells you nothing.
I fixed it in the prompt rather than switching models. Two fully worked examples, each paired with a bad version and a sentence explaining exactly why it is bad. Then a ban on openers that restate your situation back at you, and a ban on decision verbs like "Decide", "Choose" and "Determine", because naming the fork is the entire job. Describing the standard did not move Nova. Showing it twice did.
Two bugs survived every review I gave myself and died instantly when I screenshotted the deployed page. Every stage was rendering at once, because .stage { display: flex } is an author rule and outranks the browser's own [hidden] { display: none }. And the result was clipped at the bottom, because justify-content: center puts overflow out of reach on a short screen. Neither was visible in the code.
There is no remote Terraform state and no CI. Single environment, local state. Right call for a weekend, wrong call for anything real.
Nova Sonic is sitting right there. It is speech native and would remove Transcribe and the twenty second wait entirely. It is a bidirectional streaming API that does not fit a request and response Lambda, so it was a day of work I did not have. That is version two.

Privacy, enforced rather than promised

People ramble about genuinely private things, so this is not a copy decision.
Audio is deleted on every exit path, including failure. Transcribe writes to the service managed bucket, so no transcript ever touches infrastructure I own, and the job is deleted along with AWS's copy of the text. There are no accounts and no history. The polling token lives in the browser, because holding it server side would mean storing something about a session.
The metrics go out as CloudWatch Embedded Metric Format (a way to emit metrics by printing JSON to your logs, with no API call) against a hard allowlist of metric names and dimension values, with tests. Observability is usually exactly where a privacy promise quietly dies.
After a voice run I checked directly against AWS. Zero objects left in the audio bucket. Zero transcription jobs remaining. The only dimensions present were InputMode=voice and InputMode=text.

What it costs

S3, CloudFront, Lambda and API Gateway all sit inside the free tier at this volume. Transcribe is $0.024 per minute of audio. Nova Pro is fractions of a cent per ramble.
A hundred sixty second rambles is about $2.40, almost all of it Transcribe. The entire weekend cost me a few dollars.

Conclusion

The feature I am proudest of is the one that does the least.
Everything in this project moves bytes between AWS services except one file, quote.py, whose only job is to refuse to let the model improve on your words. It adds nothing. It subtracts dishonesty.
That is the actual lesson for agents people enjoy using. The delight was not in giving the model more to do. It was in finding the one place where the model should not be trusted, and guarding it.
Anyone can summarise you. Almost nobody will just quote you back.

Need Help?

If you are building something similar and hit a wall with Transcribe, Bedrock, or getting microphone access working behind CloudFront, feel free to reach out. I am happy to walk you through it.
#agents #challenge
Contact me at khantanseer43@gmail.com
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article