Multi-agent SEO engineering system. Analyses your website files, generates SEO recommendations, and automatically applies approved fixes to your S3 bucket.
The analysis pipeline is orchestrated by AWS Step Functions and runs 8 Amazon Bedrock Agents in sequence. Each agent reasons with a foundation model and calls structured tools (Lambda action groups) that hold the deterministic SEO logic.
``` src/ui/ → React frontend (Vite + TanStack Router) src/agents/ → SEO agent logic (Context, Stack, TechnicalSEO, Content, Competitor, Approval, AutoEdit, Report) src/storage/ → DynamoDB + S3 clients src/scoring/ → SEO score engine src/orchestration/ → Workflow orchestrator + failure classification infra/ → AWS CDK stack, Lambda API handlers, Bedrock agents, Step Functions state machine ```
- DynamoDB — single table
aura-seo-data(ap-southeast-2), GSI1 + GSI2 - API Gateway — HTTP API (projects, scores, audit, content, competitor, recommendations, workflows, reports, profile)
- 8 Amazon Bedrock Agents — Context, Stack, TechnicalSEO, Content,
Competitor, Approval, AutoEdit, Report. Each has an action-group Lambda
(
aura-<agent>-agent-action-handler) and alivealias. - AWS Step Functions —
aura-seo-pipelinestate machine running the agents in order: Context → Stack → Technical → Content → Competitor → Approval → AutoEdit → Report. Blocking agents (Stack, Technical, Approval) halt the workflow on failure; non-blocking agents are skipped and the pipeline continues. - Agent invoker Lambda (
aura-agent-invoker) — bridges each Step Functions step to the BedrockInvokeAgentAPI. Also fetches the project's S3 source files and injects them into the Stack/Technical/Content/AutoEdit prompts, calculates the SEO score after the Approval step, and writes live per-agent progress (PROGRESS#records) including failure reasons. - Pipeline finalizer Lambda (
aura-pipeline-finalizer) — invoked at the state machine's terminal states to write the finalcompleted/failedstatus (and failureerrorMessage) back to the execution record. - EventBridge + re-analysis Lambda (
aura-reanalysis-trigger) — S3 upload events trigger re-analysis with a 60-second batching window; re-analysis reuses the existing Business Context Profile and starts from the Stack agent. - S3 — reads your existing website bucket; stores snapshots and reports.
AURA uses a mixed-model strategy to balance quality and token efficiency:
| Agents | Model | Reason |
|---|---|---|
| Context, Stack, TechnicalSEO, Content, Competitor, AutoEdit | au.anthropic.claude-haiku-4-5-20251001-v1:0 |
Fast, cheap tool-routers — the actual logic is in Lambda action groups |
| Approval, Report | au.anthropic.claude-sonnet-4-6 |
Judgment-heavy: confidence scoring, roadmap narrative generation |
Both use AU-local cross-region inference profiles (lowest latency for ap-southeast-2, routes across Sydney + Melbourne).
To change a model: update HAIKU_MODEL_ID/SONNET_MODEL_ID (and the corresponding BASE_MODEL constants) in infra/lib/bedrock-agents.ts, then redeploy and re-prepare the affected agents (setup step 5).
The agent role IAM policy grants InvokeModel, InvokeModelWithResponseStream, GetInferenceProfile, and GetFoundationModel on both inference profiles and their base models. All four actions are required — Bedrock validates them at CreateAgent/UpdateAgent time.
- Node.js 18+
- AWS CLI configured (
aws configure) - AWS CDK CLI (
npm install -g aws-cdk) - Bedrock access to Anthropic models in the account — see step 3 below. This is a one-time, account-wide gate.
- Adequate Bedrock quota for Claude Sonnet 4.6 — the pipeline makes many model calls per run. If the "Cross-region model inference requests per minute for Claude Sonnet 4.6" quota is low (the default applied value can be as low as 50/min), concurrent or heavy runs get throttled and a blocking agent (e.g., Approval) can time out at 5 minutes, halting the pipeline. Request an increase in Service Quotas → Amazon Bedrock before heavy use, and avoid running multiple analyses concurrently until it's raised.
git clone <repo-url>
cd AURA
# Backend dependencies
npm install
# UI dependencies
cd src/ui && npm install && cd ../..
# Infra dependencies
cd infra && npm install && cd ..aws configure
# Access Key ID, Secret, region: ap-southeast-2, output: jsonVerify:
aws sts get-caller-identityThe Bedrock agents run on Anthropic Claude. Anthropic models require a one-time
use case details form to be submitted for the account before they can be
invoked or bound to an agent. Until this is done, agent deploys fail with
AccessDenied and agent runs fail with "Model use case details have not been
submitted for this account."
The old "Model access" console page has been retired. To submit the form:
- Open the Amazon Bedrock console in ap-southeast-2 (Sydney).
- Go to Model catalog → open Claude Sonnet 4.6 (Anthropic).
- Click Open in Playground (or invoke the model once).
- Fill out and submit the Anthropic use case details form that appears.
- Wait ~15 minutes for it to propagate.
Verify access is live (should print a small JSON completion, not an error):
aws bedrock-runtime invoke-model \
--region ap-southeast-2 \
--model-id au.anthropic.claude-sonnet-4-6 \
--body '{"anthropic_version":"bedrock-2023-05-31","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}' \
--cli-binary-format raw-in-base64-out \
/dev/stdoutThis gate is account-wide: once one user submits it, all users/roles in the account can use the model (subject to IAM).
cd infra
# Bootstrap CDK (one-time per account/region)
cdk bootstrap aws://YOUR_ACCOUNT_ID/ap-southeast-2
# Deploy all resources (DynamoDB, API, Lambdas, Bedrock agents, Step Functions)
npm run deployAt the end you'll see outputs including:
AuraStack.ApiUrl = https://xxxxxx.execute-api.ap-southeast-2.amazonaws.com
AuraStack.StepFunctionsStateMachineArn... = arn:aws:states:...:aura-seo-pipeline
AuraStack.BedrockAgentsContextAgentId... = XXXXXXXXXX
... (one agent ID per agent)
Copy the ApiUrl.
Newly created or updated Bedrock agents start in NOT_PREPARED. They must be
prepared before Step Functions can invoke them. Prepare all 8 (replace IDs with
the values from the deploy outputs):
for AID in <ContextId> <StackId> <TechnicalSEOId> <ContentId> \
<CompetitorId> <ApprovalId> <AutoEditId> <ReportId>; do
aws bedrock-agent prepare-agent --region ap-southeast-2 --agent-id "$AID"
doneConfirm each reaches PREPARED:
aws bedrock-agent get-agent --region ap-southeast-2 --agent-id <AgentId> \
--query 'agent.agentStatus'Create src/ui/.env:
VITE_API_URL=https://xxxxxx.execute-api.ap-southeast-2.amazonaws.com
cd src/ui
npm run devOpen http://localhost:3000.
# UI dev server
cd src/ui && npm run dev
# Backend tests
npm test
# Deploy infra changes
cd infra && npm run deployRemember: if a deploy changes a Bedrock agent (instruction, action group, model), re-run the prepare step (step 5) for the affected agents.
- Create a project (New Project → name + website S3 URL).
- Fill in the Profile (industry, keywords, competitors) — the Context agent needs a Business Context Profile before analysis can run.
- Click Run Analysis. This calls
POST /projects/{projectId}/workflows/trigger, which starts theaura-seo-pipelineStep Functions execution. - The Workflow Monitor shows live agent progress.
- Scores, recommendations, and the report appear when the pipeline completes.
aws stepfunctions list-executions \
--region ap-southeast-2 \
--state-machine-arn arn:aws:states:ap-southeast-2:<ACCOUNT>:stateMachine:aura-seo-pipeline- Go to Approval Queue.
- Review recommendations (Pending / Failed / Reviewed / All).
- Click Approve — the Auto-Edit agent backs up the file to S3, applies the fix, validates it, and writes it back. Failed validations auto-revert.
- Check Change Log for what was applied; any change can be rolled back.
Uploading files to s3://<bucket>/projects/{projectId}/source/... triggers
re-analysis automatically (60-second batching window). The source bucket must
have S3 → EventBridge notifications enabled. Re-analysis reuses the existing
Business Context Profile and starts from the Stack agent; if no profile exists,
the run is halted and a notification is recorded.
| Variable | Where | Description |
|---|---|---|
VITE_API_URL |
src/ui/.env |
API Gateway endpoint URL |
VITE_MOCK_API |
src/ui/.env |
Set to true to use mock data (no AWS needed) |
Lambda environment (set by CDK, not manual): TABLE_NAME, WEBSITE_BUCKET,
REGION, STATE_MACHINE_ARN, and MODEL_ID (the Sonnet 4.6 inference profile
used by the Context and Competitor Lambdas for real competitor discovery via
bedrock:InvokeModel).
For UI-only development:
Create src/ui/.env:
VITE_MOCK_API=true
The UI uses built-in mock data for all API calls.
src/
agents/ Context, Stack, TechnicalSEO, Content, Competitor,
Approval, AutoEdit, Report (agent logic + property tests)
models/ TypeScript types
orchestration/ Workflow orchestrator, workspace connector
scoring/ SEO score engine
storage/ DynamoDB + S3 clients
ui/ React app (api/, components/, features/, hooks/, types/)
infra/
bin/aura.ts CDK app entry
lib/aura-stack.ts Core stack (DynamoDB, API, Lambdas)
lib/bedrock-agents.ts 8 Bedrock agents + action groups + IAM
lib/step-functions.ts Pipeline state machine + EventBridge trigger
lambda/api/ HTTP API handlers (one per domain)
lambda/agents/ Bedrock agent action-group handlers
lambda/orchestration/ agent-invoker, reanalysis-trigger
- Source files must live under
projects/{projectId}/source/for the Auto-Edit agent and rollback to work. Auto-Edit backs up files toprojects/{projectId}/snapshots/{executionId}/...and rollback restores from there. If a project's files are uploaded to the bucket root, analysis still runs (the invoker falls back to reading root-level files), but Auto-Edit creates no snapshots and rollback has nothing to restore. Upload each project's files under itssource/prefix — this is also required for correct multi-project isolation in a shared bucket. - Competitor discovery uses the foundation model's training knowledge (not live web search). It returns real, well-known businesses but may miss very small/new/local competitors and can occasionally produce a slightly stale URL. A live-search option (Google Programmable Search) is documented as a future enhancement.
- No authentication — the API is currently open; do not share the API URL publicly.
AccessDeniedonAWS::Bedrock::Agentduring deploy — the Anthropic use case form hasn't been submitted for the account, or the agent IAM role is missingGetInferenceProfile/GetFoundationModel. Complete setup step 3, wait ~15 minutes, then redeploy. If the form was already submitted, check that theBedrockModelAccessinline policy inbedrock-agents.tsincludes all four required actions:InvokeModel,InvokeModelWithResponseStream,GetInferenceProfile,GetFoundationModel.- Agent run fails with "Model use case details have not been submitted" — same cause as above (setup step 3).
- Pipeline halts with
BlockingAgentFailure— a blocking agent (Stack, Technical, or Approval) failed. The Workflow Monitor shows the failed agent in red and a "Failure reason" banner with the cause; the execution record also stores anerrorMessage. For deeper detail check theaura-agent-invokerand the agent's action-group Lambda logs in CloudWatch, and the Step Functions execution history. - "Report Generation" shows incomplete but the report never generated — the
real failure is usually an earlier blocking agent (commonly the Approval
agent timing out due to Sonnet 4.6 throttling — see the quota note in
Prerequisites). Report is the last step and only runs if the pipeline reaches
it. Check the Failure reason banner / execution
errorMessageto see the actual failing agent. - Settings won't save / report detail 404 / no live progress — ensure the UI
is running against the latest build (
git pull, restartnpm run dev); these were fixed by usingPUTfor settings, navigating reports byexecutionId, and sorting executions bystartedAt. - Agent invoked but returns nothing /
NOT_PREPARED— run the prepare step (setup step 5) for that agent. - Heading fix fails ("code pattern not found") — the H1 text in your file differs from the generated pattern; re-run analysis after editing.
