Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Deploys AWS CloudFormation infrastructure stacks for the website (S3, CloudFront, Route 53, ACM, and optionally contact form API).
.claude/skills/grcengclub-website-infra/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 19% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 82% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 96% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 81% | 0% |
| case-17 | ✗→✓ | ▲ Improved | 46% | 0% |
You are running the /grc-portfolio:infra skill. Your job is to deploy the AWS infrastructure needed to host the website using CloudFormation.
Find site-config.json:
$ARGUMENTS for a project directory pathRead it and validate that status.preflightComplete === true. If not, tell the user to run /grc-portfolio:preflight first.
Based on features.customDomain:
$TOOLKIT_DIR/cloudformation/website-infrastructure.yaml$TOOLKIT_DIR/cloudformation/website-infrastructure-no-domain.yamlRun the validation script:
bash$TOOLKIT_DIR/scripts/validate-stack.sh <template-path> <aws.profile>
If validation fails, report the error and stop.
Use aws cloudformation deploy — it is idempotent (creates the stack on first run, applies a change-set on subsequent runs) and waits for completion inline, so the user doesn't need a separate wait step.
With custom domain:
bashaws cloudformation deploy \ --stack-name <aws.stackName> \ --template-file <template-path> \ --parameter-overrides \ ProjectName=<projectName> \ DomainName=<aws.domain> \ HostedZoneId=<aws.hostedZoneId> \ CertificateArn=<aws.certArn> \ --profile <aws.profile> \ --region us-east-1 \ --no-fail-on-empty-changeset
Without custom domain:
bashaws cloudformation deploy \ --stack-name <aws.stackName> \ --template-file <template-path> \ --parameter-overrides ProjectName=<projectName> \ --profile <aws.profile> \ --region us-east-1 \ --no-fail-on-empty-changeset
Note: Check the actual template parameters first by reading the template file, as parameter names may differ from the examples above. Use the actual parameter names from the template.
The deploy command can take 5-15 minutes (especially with CloudFront distribution creation). Tell the user it's in progress and approximately how long it might take.
If the deploy fails, retrieve the failure reason:
bashaws cloudformation describe-stack-events \ --stack-name <aws.stackName> \ --profile <aws.profile> \ --region us-east-1 \ --query "StackEvents[?ResourceStatus=='CREATE_FAILED' || ResourceStatus=='UPDATE_FAILED'].[LogicalResourceId,ResourceStatusReason]" \ --output table
bashaws cloudformation describe-stacks \ --stack-name <aws.stackName> \ --profile <aws.profile> \ --region us-east-1 \ --query "Stacks[0].Outputs"
Extract and save to site-config.json:
aws.bucketName -- the S3 bucket nameaws.distributionId -- the CloudFront distribution IDaws.cloudFrontUrl -- the CloudFront domain name (e.g., d123abc.cloudfront.net)If features.contactForm is true:
stack will refuse to deploy without them):
SESFromEmail: verified sender identitySESToEmail: recipient inbox for submissionsIf either is not yet verified in SES, stop and instruct the user to verify them in the AWS Console (SES → Verified identities → Create identity) before continuing. Save both to aws.sesFromEmail and aws.sesToEmail in site-config.json.
bashaws cloudformation deploy \ --template-file $TOOLKIT_DIR/cloudformation/contact-form-api.yaml \ --stack-name <projectName>-contact-form-api \ --parameter-overrides "SESFromEmail=<aws.sesFromEmail>" "SESToEmail=<aws.sesToEmail>" \ --capabilities CAPABILITY_IAM \ --profile <aws.profile> \ --region us-east-1 \ --no-fail-on-empty-changeset
bashaws cloudformation describe-stacks \ --stack-name <projectName>-contact-form-api \ --profile <aws.profile> \ --region us-east-1 \ --query "Stacks[0].Outputs[?OutputKey=='ApiEndpoint'].OutputValue" \ --output text
aws.contactApiEndpoint in config.$TOOLKIT_DIR/scripts/deploy-contact-api.sh for the pattern -- create temp dir, copy handler, install @aws-sdk/client-ses, zip, update function code). The function name is <projectName>-contact-form-api-handler (derived from the stack name in the template).If using a custom domain, tell the user:
dig NS <domain>Get the nameservers:
bashaws route53 get-hosted-zone --id <aws.hostedZoneId> --profile <aws.profile> --query "DelegationSet.NameServers"
Update site-config.json:
aws.bucketName, aws.distributionId, aws.cloudFrontUrlaws.contactApiEndpoint (if contact form)status.infraDeployed = trueTell the user:
/grc-portfolio:deploy next to push the built site to AWS$TOOLKIT_DIR = read from site-config.json toolkitDir field$ARGUMENTS = arguments passed after /infra (expected: project directory path)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 4,234 | 22,967 | +442% | 1 | 1 | 0% | 222 | 1,735 | +682% | 0 | 0 | — |
case-02 | fail→fail | 15,680 | 4,368 | -72% | 1 | 1 | 0% | 2,901 | 1,778 | -39% | 0 | 0 | — |
case-03 | pass→pass | 10,275 | 4,004 | -61% | 1 | 1 | 0% | 1,647 | 2,156 | +31% | 0 | 0 | — |
case-04 | pass→fail | 6,169 | 3,636 | -41% | 1 | 1 | 0% | 1,047 | 2,086 | +99% | 0 | 0 | — |
case-05 | pass→pass | 5,191 | 4,181 | -19% | 1 | 1 | 0% | 771 | 2,199 | +185% | 0 | 0 | — |
case-06 | pass→pass | 8,390 | 2,793 | -67% | 1 | 1 | 0% | 1,378 | 2,004 | +45% | 0 | 0 | — |
case-07 | fail→pass | 10,155 | 1,743 | -83% | 1 | 1 | 0% | 1,543 | 1,834 | +19% | 0 | 0 | — |
case-08 | pass→pass | 3,242 | 1,570 | -52% | 1 | 1 | 0% | 498 | 1,790 | +259% | 0 | 0 | — |
case-09 | fail→pass | 6,710 | 1,593 | -76% | 1 | 1 | 0% | 972 | 1,773 | +82% | 0 | 0 | — |
case-10 | pass→pass | 3,113 | 2,759 | -11% | 1 | 1 | 0% | 501 | 1,936 | +286% | 0 | 0 | — |
case-11 | pass→pass | 4,111 | 1,547 | -62% | 1 | 1 | 0% | 641 | 1,773 | +177% | 0 | 0 | — |
case-12 | pass→pass | 10,502 | 3,115 | -70% | 1 | 1 | 0% | 1,780 | 2,045 | +15% | 0 | 0 | — |
case-13 | pass→pass | 7,045 | 2,312 | -67% | 1 | 1 | 0% | 1,229 | 1,921 | +56% | 0 | 0 | — |
case-14 | fail→pass | 6,086 | 1,886 | -69% | 1 | 1 | 0% | 957 | 1,875 | +96% | 0 | 0 | — |
case-15 | pass→pass | 4,123 | 1,608 | -61% | 1 | 1 | 0% | 649 | 1,749 | +169% | 0 | 0 | — |
case-16 | fail→pass | 6,149 | 1,697 | -72% | 1 | 1 | 0% | 979 | 1,774 | +81% | 0 | 0 | — |
case-17 | fail→pass | 8,448 | 2,488 | -71% | 1 | 1 | 0% | 1,352 | 1,974 | +46% | 0 | 0 | — |
case-18 | pass→pass | 4,813 | 2,065 | -57% | 1 | 1 | 0% | 749 | 1,931 | +158% | 0 | 0 | — |
case-19 | pass→pass | 4,371 | 1,675 | -62% | 1 | 1 | 0% | 766 | 1,794 | +134% | 0 | 0 | — |
case-20 | fail→pass | 7,756 | 3,043 | -61% | 1 | 1 | 0% | 1,247 | 2,108 | +69% | 0 | 0 | — |
case-21 | fail→pass | 8,171 | 1,742 | -79% | 1 | 1 | 0% | 1,175 | 1,828 | +56% | 0 | 0 | — |
case-22 | fail→pass | 9,815 | 1,398 | -86% | 1 | 1 | 0% | 1,488 | 1,761 | +18% | 0 | 0 | — |
case-23 | fail→pass | 10,221 | 1,280 | -87% | 1 | 1 | 0% | 1,649 | 1,690 | +2% | 0 | 0 | — |
case-24 | pass→pass | 9,362 | 2,822 | -70% | 1 | 1 | 0% | 1,585 | 2,030 | +28% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted, and 23 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +33 percentage points is the difference between those two pass rates over the 23 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.