From grc-portfolio
Deploys AWS CloudFormation infrastructure stacks for the website (S3, CloudFront, Route 53, ACM, and optionally contact form API).
How this skill is triggered — by the user, by Claude, or both
Slash command
/grc-portfolio:website-infraThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are running the `/grc-portfolio:infra` skill. Your job is to deploy the AWS infrastructure needed to host the website using CloudFormation.
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:
$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:
aws 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:
aws 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:
aws 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
aws 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:
Ask the user for two SES-verified email addresses (no defaults — the 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.
Deploy the contact form stack:
aws 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
aws 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
Save to aws.contactApiEndpoint in config.
Package and deploy the Lambda function code (reference $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:
aws 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)npx claudepluginhub vantainc/claude-grc-engineering --plugin grc-portfolioGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.
Dispatches multiple subagents concurrently for independent tasks without shared state. Use when facing 2+ unrelated failures or subsystems that can be investigated in parallel.
2plugins reuse this skill
First indexed Jul 18, 2026