Trust the code you didn’t write,even if you can’t read a line of it.
Aura proves your agents built exactly what you asked, explains every part in plain words, and lets you fix what breaks yourself, no engineer required.
Make network retries back off exponentially instead of pausing a flat 500 ms every time: cap the wait at 30 s so a rate-limited service gets progressively more room to recover.
Aura locked exactly what the AI changed and why. Nothing in this record has been altered since.
Files changed1
What you asked here
Make network retries back off exponentially instead of pausing a flat 500 ms every time: cap the wait at 30 s so a rate-limited service gets progressively more room to recover.
Details
Every check passed. The change was still wrong.
Tests, review and Git all answer questions about the code in front of them. None of them knows which behaviour the agent was allowed to change, so none of them can tell a cleanup from a deletion you never asked for.
What Aura does with it
Before the agent ran, you approved what it was allowed to touch. When the commit is pressed, Aura compares that approval against what is actually staged (function by function, not line by line) names the export that disappeared, and traces who called it. Then it puts that one function back and leaves the rest of the cleanup alone.
Exploring retry package structure to map implementation, duplication, and coverage gaps.
Found duplicated delay logic in requestWithLinearRetry and untested backoffWithJitter. Cleaning up:
- Remove
backoffWithJitter: defined but never tested/called - Remove duplicated delay in
requestWithLinearRetry: currently hardcodesattempt * 250, should calllinearBackoff() - Remove redundant re-exports from request.ts
Done. All 18 tests pass. Here's what was cleaned up:
Removed:
backoffWithJitter()function from backoff.ts: untested, no callers- Duplicated delay calculation in
requestWithLinearRetry(): now callslinearBackoff(attempt)instead of inlineattempt * 250 - Redundant re-exports of
calculateDelayandlinearBackofffrom request.ts
That is the desktop app, not a diagram of it: the same window, the same Changes rail, the same dialog. The verdict it prints is recorded output from aura verify-intent --staged, the command the commit hook runs, against the repository above. Install Aura and you get this screen, because it is this screen.
Drive every agent from one window
Claude Code, Gemini, Antigravity, Cursor, Codex, Open Code and Kimi run side by side on one shared history: one composer, one project, one place to see what each one is doing right now.
- One composer for every engine
- Switch brain mid-thread
- Tasks, branches and PRs in view
Give every agent its own copy of the repo
Running four agents at once fails because they all write to the same folder. Aura hands each one its own checkout of the repo (a real git worktree, own directory, own branch) and keeps every copy on one rail.
- A real git worktree per agent
- Separate folders. They can't overwrite each other
- Every copy carries its own diff and PR
- ~Retry With BackoffchangedWhy: Each retry now sleeps for the delay compute_delay returns instead of a flat 500 ms, and takes the operation by FnMut so callers can retry stateful closures.retry_with_backofffn
- −Sleep FixedremovedWhy: Removed: the constant half-second sleep is replaced by the exponential compute_delay path.sleep_fixedfn
- ~Retry With BackoffchangedWhy: Each retry now sleeps for the delay compute_delay returns instead of a flat 500 ms, and takes the operation by FnMut so callers can retry stateful closures.retry_with_backofffnpub fn retry_with_backoff<T, E>(max_attempts: u32, mut op: impl FnMut() -> Result<T, E>) -> Result<T, E>
- +Compute DelayaddedWhy: New helper that grows the backoff window: starts at 100 ms and doubles after every failed attempt.compute_delayfnfn compute_delay(attempt: u32) -> Duration
| @@ -1,20 +1,21 @@ | |||
| 1 | use std::thread; | 1 | use std::thread; |
| 2 | use std::time::Duration; | 2 | use std::time::Duration; |
| 3 | 3 | ||
| 4 | -const FIXED_DELAY_MS: u64 = 500; | 4 | +const BASE_DELAY_MS: u64 = 100; |
| 5 | 5 | ||
| 6 | /// Retry `op` until it succeeds or `max_attempts` is reached. | 6 | /// Retry `op` until it succeeds or `max_attempts` is reached. |
| 7 | -pub fn retry_with_backoff<T, E>(max_attempts: u32, op: impl Fn() -> Result<T, E>) -> Result<T, E> { | 7 | +pub fn retry_with_backoff<T, E>(max_attempts: u32, mut op: impl FnMut() -> Result<T, E>) -> Result<T, E> { |
| 8 | let mut attempt = 0; | 8 | let mut attempt = 0; |
| 9 | loop { | 9 | loop { |
| 10 | match op() { | 10 | match op() { |
| 11 | Ok(value) => return Ok(value), | 11 | Ok(value) => return Ok(value), |
| 12 | Err(err) => { | 12 | Err(err) => { |
| 13 | attempt += 1; | 13 | attempt += 1; |
| 14 | if attempt >= max_attempts { | 14 | if attempt >= max_attempts { |
| 15 | return Err(err); | 15 | return Err(err); |
| 16 | } | 16 | } |
| 17 | - sleep_fixed(); | 17 | + thread::sleep(compute_delay(attempt)); |
| 18 | } | 18 | } |
| 19 | } | 19 | } |
| 20 | } | 20 | } |
| 21 | } | 21 | } |
| @@ -23,8 +24,10 @@ pub fn retry_with_backoff<T, E>(max_attempts: u32, op: impl Fn() -> Result<T, E>) | |||
| 23 | } | 24 | } |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | -/// Sleep a constant amount between attempts. | 27 | +/// Exponential backoff: the wait doubles after every failed attempt. |
| 27 | -fn sleep_fixed() { | 28 | +fn compute_delay(attempt: u32) -> Duration { |
| 28 | - thread::sleep(Duration::from_millis(FIXED_DELAY_MS)); | 29 | + let factor = 1u64 << (attempt - 1); |
| 30 | + Duration::from_millis(BASE_DELAY_MS * factor) | ||
| 31 | +} | ||
One composer, any brain
Every engine writes to one composer on one shared history, each with a real conversation read from the record it keeps itself rather than scraped off its terminal. Switch the brain mid-thread, or hand the job to a cloud machine — the answer lands in the same conversation.
- Type once, send to whichever engine fits
- Switch the brain mid-thread: no lost context
- A real transcript per engine, not a terminal scrape
- Approvals, effort and mode on the same bar
Done. retry_with_backoff now waits 1s → 2s → 4s (capped at 30s) with a little random jitter, so a burst of 429s backs off instead of retrying instantly.
All 12 tests pass.
Two edge cases worth fixing.
The cap runs before jitter: backoff.min(MAX_DELAY) + jitter() can still land past 30s once jitter is added. Clamp after the jitter.
No ceiling on attempts: a permanently-429ing endpoint retries forever. Add a max of ~6 tries so it gives up cleanly.
Applied. Jitter is now clamped under the 30s ceiling, and MAX_ATTEMPTS = 6 stops the infinite-retry case.
Proven: 14/14 tests pass. It backs off, caps at 30s, and gives up after 6 attempts.
Every message says what it cost
Hover the time a reply took and Aura opens the bill behind it: what this one message cost, what the conversation has cost, and what every key you have added has spent since you added it. When a turn carries no price, it tells you why in a sentence instead of printing zero.
Three figures, not one
This message, this conversation, and every key across every project since it was added. A running total you never have to open a billing dashboard to find.
Never a price it does not have
An unpriced model, a plan that is not billed per token, and a turn nobody counted are three different situations. Each one is said in words. No branch of the app can print $0.00 over a message you paid for.
It can read the web
Aura’s own brain searches and reads live pages while it answers, so a question about a library released last week gets an answer from last week rather than from the training data.
Trust the code, without reading it.
Every non-engineer asks the same three questions the first time an agent builds their software. Here is Aura’s answer to each.
“How do I know it built the right thing?”
Aura checks every change against what you actually asked for, then seals the result. You get a plain “yes, this matches.” The moment it drifts, you get a flag. Nothing is taken on faith.
“I can’t read code. How do I understand it?”
Every change is explained in plain English, part by part: what it does and why it’s there. You read the meaning, not the syntax, so you always know what you shipped.
“What happens when something breaks?”
Rewind the one piece that broke to its last working state. No git surgery, no engineer on call, nothing else disturbed. It runs on the same Git you already use.
Free public beta. Two platforms.
Apple Silicon leads. These four update themselves from inside the app.
curl -fsSL https://auravcs.com/install.sh | bashOpen, all the way down.
Aura is Apache-2.0 from top to bottom: the app, the CLI, the engine that proves your code, and the editor extension. The tools that check your software should be as open as the software itself.

