Run Libretto workflows as ECS Fargate tasks, triggered from your API or EventBridge.
123456789101112131415161718192021222324// src/main.ts import { pullReferrals } from "./workflows/pull-referrals"; import { submitPriorAuth } from "./workflows/submit-prior-auth"; const workflows = { "pull-referrals": pullReferrals, "submit-prior-auth": submitPriorAuth, } as const; type WorkflowName = keyof typeof workflows; async function main() { const name = process.env.LIBRETTO_WORKFLOW as WorkflowName | undefined; const inputJson = process.env.LIBRETTO_INPUT ?? "{}"; if (!name || !(name in workflows)) { throw new Error( `Set LIBRETTO_WORKFLOW to one of: ${Object.keys(workflows).join(", ")}`, ); } await workflows[name](JSON.parse(inputJson)); } void main();
12345678910111213141516# Dockerfile FROM mcr.microsoft.com/playwright:v1.58.2-noble RUN apt-get update && apt-get install -y git \ && corepack enable \ && corepack prepare pnpm@latest --activate WORKDIR /app RUN mkdir -p /root/.cache && cp -a /ms-playwright /root/.cache/ COPY . . RUN pnpm install --frozen-lockfile ENV NODE_ENV=production ENTRYPOINT ["pnpm", "start"]
12345678910aws ecr create-repository --repository-name browser-agent --region us-east-1 aws ecr get-login-password --region us-east-1 | \ docker login --username AWS --password-stdin \ 123456789012.dkr.ecr.us-east-1.amazonaws.com docker build -f apps/browser-agent/Dockerfile \ -t 123456789012.dkr.ecr.us-east-1.amazonaws.com/browser-agent:latest . docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/browser-agent:latest
buildspec.yml that tags both :latest and :$CODEBUILD_RESOLVED_SOURCE_VERSION.123456789101112131415161718192021222324{ "family": "browser-agent-task", "requiresCompatibilities": ["FARGATE"], "networkMode": "awsvpc", "cpu": "1024", "memory": "2048", "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole", "taskRoleArn": "arn:aws:iam::123456789012:role/browserAgentTaskRole", "containerDefinitions": [ { "name": "browser-agent", "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/browser-agent:latest", "essential": true, "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/browser-agent", "awslogs-region": "us-east-1", "awslogs-stream-prefix": "task" } } } ] }
123aws ecs register-task-definition \ --cli-input-json file://browser-agent-task.json \ --region us-east-1
1234567891011121314import { SecretsManagerClient, GetSecretValueCommand, } from "@aws-sdk/client-secrets-manager"; const client = new SecretsManagerClient({ region: process.env.AWS_REGION }); export async function getSecret(name: string): Promise<string> { const { SecretString } = await client.send( new GetSecretValueCommand({ SecretId: name }), ); if (!SecretString) throw new Error(`Secret ${name} is empty`); return SecretString; }
browserAgentTaskRole that allows secretsmanager:GetSecretValue on the specific ARNs the workflows use.12345678910111213141516171819202122232425262728import { ECSClient, RunTaskCommand } from "@aws-sdk/client-ecs"; const ecs = new ECSClient({ region: "us-east-1" }); await ecs.send( new RunTaskCommand({ cluster: "browser-agent-cluster", launchType: "FARGATE", taskDefinition: "browser-agent-task", networkConfiguration: { awsvpcConfiguration: { subnets: ["subnet-abc123"], assignPublicIp: "ENABLED", }, }, overrides: { containerOverrides: [ { name: "browser-agent", environment: [ { name: "LIBRETTO_WORKFLOW", value: "pull-referrals" }, { name: "LIBRETTO_INPUT", value: JSON.stringify(input) }, ], }, ], }, }), );
/ecs/browser-agent).aws ecs list-tasks --cluster browser-agent-cluster --desired-status STOPPED..libretto/sessions/<name>/ to S3 at the end of each run for post-hoc debugging.