Agent skill
af-setup-project
Set up new AgentFlow projects and install modules after Discovery. Use when bootstrapping infrastructure, configuring Doppler, GitHub, Linear, or local environment variables.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/af-setup-project
SKILL.md
Setup Process
Quick Reference
| Setup Type | Use Case | Command |
|---|---|---|
| Minimal Setup | New project bootstrap (always the same) | /af:setup |
| Module Setup | Install modules after Discovery | Post-Discovery |
| Brownfield | Add AgentFlow to existing repo | /brownfield:add |
Templates: .claude/templates/setup/
Detailed guide: docs/guides/setup-guide.md
When to Use
✅ Use Setup Process for:
- Creating new AgentFlow projects (greenfield)
- Adding AgentFlow to existing projects (brownfield)
- Bootstrapping BDD/TDD development environments
❌ Don't use for:
- Updating AgentFlow framework (use
/af:sync) - Fixing broken configurations (use troubleshooting)
Prerequisites
Required:
- Node.js v20+
- Git installed
- 2GB+ free disk space
- Internet connectivity
For GainInsight Infrastructure:
- Access to gidev server
LINEAR_API_KEYavailable in environment (provided automatically on gidev)
Rules
Critical Setup Rules
- Linear team creation is automatic - Setup creates the team via GraphQL API
- Never skip validation phase - Always verify setup completed correctly
- Use templates - Reference
.claude/templates/setup/for CLAUDE.md and handoff messages - Add to project registry - Use
project-registryCLI for gidev projects - Commit with --no-verify - Initial commits skip git hooks (no code to lint yet)
Setup State Rules
- State is tracked - Setup maintains JSON state for resume capability
- Resume on failure - Just re-run setup command to continue
- Validate before declaring success - Run build and tests
Workflows
Workflow: Greenfield Setup (GainInsight)
When: Creating a new project from scratch on gidev infrastructure.
Prerequisites: LINEAR_API_KEY available in environment (provided automatically on gidev)
Questions to ask:
- Project name? (for Linear team and GitHub repo)
- Linear team key? (2-5 uppercase letters, unique in workspace)
- Development model? (trunk, trunk+develop, or feature branch)
- Trunk: Single branch (
main), PRs merge directly to main → deploys to Live - Trunk + develop: Two branches (
develop→ Dev,main→ Live), but trunk-based workflow (develop is the working branch, main is promotion-only) - Feature branch: Multiple environments, PRs to develop → Dev → Test → Live
- Trunk: Single branch (
- GitHub repo exists? If no, what name? Org or personal?
- Brief project description?
- Zulip stream? (optional)
Steps:
- Create Linear team (via GraphQL API - see
af-query-linear-api)- Use
teamCreatemutation with name, key,cyclesEnabled: true - Archive default workflow states
- Create AgentFlow states based on development model
- Create standard labels (Epic, BDD, UX, Docs, Debt)
- Use
- Create GitHub repo if needed:
gh repo create GainInsightDev/{repo-name} --private - Create Linear issue for setup (via GraphQL API)
- Create Doppler project:
doppler projects create {project-name} --description "Secrets for {project-name}"- Creates default configs (dev, stg, prd)
- Module Installation will later populate with AWS credentials, API keys, etc.
- Create bare repo on gidev:
add-repo [email protected]:Owner/repo.git - Create stable worktree based on development model:
- Trunk:
git worktree add /srv/worktrees/{repo}/main main - Trunk+develop: Create
developbranch, thengit worktree add /srv/worktrees/{repo}/develop develop(main stays remote-only) - Feature branch:
git worktree add /srv/worktrees/{repo}/develop develop
- Trunk:
- Sync AgentFlow:
npx ts-node .claude/scripts/sync/sync-from-agentflow.ts - Create CLAUDE.md from template:
.claude/templates/setup/greenfield-claudemd.md - Create security config:
mkdir -p .github && cp .claude/templates/github/dependabot.yml .github/ - Initial commit and push (use --no-verify)
- Add to project registry via
project-registryCLI (see "Project Registry Entry" workflow) - Create docs portal files:
docs/_category_.json,docs/README.md - Update Linear issue to Done
- Show handoff message:
.claude/templates/setup/greenfield-handoff.txt
Success criteria:
- ✅ Linear team created with AgentFlow workflow states
- ✅ Doppler project created with default configs
- ✅ GitHub repo exists and has initial commit
- ✅ Stable worktree at
/srv/worktrees/{repo}/develop - ✅ Project in registry with docs config
- ✅ Linear issue created and marked Done
- ✅ Security config (dependabot.yml) in place
Workflow: Linear Team Setup
When: Creating a new Linear team with AgentFlow workflow states (part of Greenfield setup).
Prerequisites: LINEAR_API_KEY available in environment (provided automatically on gidev)
Inputs:
- Project name (human-readable)
- Team key (2-5 uppercase letters, unique)
- Development model:
trunk,trunk+develop, orfeature
Steps:
-
Create team:
bashcurl -s -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation { teamCreate(input: { name: \"PROJECT_NAME\", key: \"KEY\", cyclesEnabled: true }) { success team { id } } }" }' -
Get and archive default states:
bash# Get default states curl -s -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{"query": "{ team(id: \"TEAM_ID\") { states { nodes { id name } } } }"}' # Archive each default state curl -s -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{"query": "mutation { workflowStateArchive(id: \"STATE_ID\") { success } }"}' -
Create AgentFlow workflow states:
State Type Color Position Trunk Trunk+Develop Feature Discovered backlog #bec2c8 0 ✅ ✅ ✅ Refining started #5e6ad2 1 ✅ ✅ ✅ Approved unstarted #bec2c8 2 ✅ ✅ ✅ In Progress started #f2c94c 3 ✅ ✅ ✅ Waiting for Feedback started #eb5757 4 ✅ ✅ ✅ In Review started #0f783c 5 ✅ ✅ ✅ Dev completed #f2c94c 6 — ✅ ✅ Test completed #26b5ce 7 — — ✅ Live completed #5e6ad2 8 ✅ ✅ ✅ Canceled canceled #95a2b3 9 ✅ ✅ ✅ Duplicate canceled #95a2b3 10 ✅ ✅ ✅ bashcurl -s -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation { workflowStateCreate(input: { teamId: \"TEAM_ID\", name: \"STATE_NAME\", type: \"TYPE\", color: \"COLOR\", position: POSITION }) { success } }" }' -
Create standard team labels:
Label Color Purpose Epic #f2994a Epic grouping BDD #26b5ce BDD scenario work UX #4cb782 UX/design work Docs #5e6ad2 Documentation Debt #f7c8c1 Technical debt Workspace-scoped labels (created once, apply to all teams):
Label Color Purpose approved:test #26b5ce Signal: deploy to test environment approved:live #0f783c Signal: deploy to production bashcurl -s -X POST https://api.linear.app/graphql \ -H "Content-Type: application/json" \ -H "Authorization: $LINEAR_API_KEY" \ -d '{ "query": "mutation { issueLabelCreate(input: { teamId: \"TEAM_ID\", name: \"LABEL_NAME\", color: \"COLOR\" }) { success } }" }'
Success criteria:
- ✅ Team created with correct key and cycles enabled
- ✅ Default states archived
- ✅ AgentFlow states created with correct colors
- ✅ Standard labels created
Full script: See af-query-linear-api skill for complete team setup script.
Workflow: Module Setup (Post-Discovery)
When: After Discovery phase completes with a Tech Stack Agreement listing selected modules.
Prerequisites:
- Minimal setup (greenfield or brownfield) already completed
- Discovery phase complete with Tech Stack Agreement at
docs/architecture/tech-stack-agreement.md - Module registry available at
.claude/docs/reference/module-registry.yml
Process:
-
Read the Tech Stack Agreement
- Parse selected modules list
- Identify applicable integration guides
-
Resolve dependency order
- Load module registry
- Topologically sort selected modules by
depends_on - Example order: doppler → git → aws-infrastructure → amplify → auth → email → testing → ui-styling → cicd
- Note: doppler and git are core modules (already installed), so Module Installation starts with aws-infrastructure
-
For each module in dependency order: a. Load the module's skill (e.g.,
af-configure-cognito-authfor auth) b. Load applicable integration guides (e.g., if both auth and email selected, loadcognito-ses.md) c. Execute setup steps following the skill's installation workflow d. Run validation tests before proceeding to the next module e. Record completion in the Tech Stack Agreement -
Post-installation validation
- Run full validation suite
- Verify all integration points
- Update Linear with setup status
Module installation order example (GainInsight Standard combination):
1. aws-infrastructure → af-provision-infrastructure skill
Integration: none at this stage
2. amplify → af-build-amplify-features skill
Integration: amplify-esm.md (ESM configuration)
3. auth → af-configure-cognito-auth skill
Integration: cognito-ses.md (if email also selected)
4. email → af-configure-ses-email skill
Integration: ses-per-account.md, auth-testing.md (if testing selected)
5. testing → af-configure-test-frameworks skill
Integration: auth-testing.md (if auth selected)
6. ui-styling → af-design-ui-components skill
7. cicd → af-deliver-features skill
Integration: cicd-amplify-polling.md (if amplify selected)
8. posthog → af-integrate-posthog skill
9. security → af-audit-security skill
10. figma → af-sync-figma-designs skill (optional, depends on ui-styling)
Setup: Add MCP server URL, set up Code Connect, create Figma project structure
Success criteria:
- ✅ All selected modules installed in dependency order
- ✅ All applicable integration guides followed
- ✅ Validation tests pass for each module
- ✅ Tech Stack Agreement updated with completion status
- ✅ Ready for Refinement phase
Workflow: Component Installation
When: Installing individual components during greenfield setup.
Templates location: .claude/templates/setup/components/
Validation tests: .claude/templates/setup/validation/
Install Testing Component
# 1. Create directories
mkdir -p tests/unit tests/e2e
# 2. Copy config files
cp .claude/templates/setup/components/testing/jest.config.js ./
cp .claude/templates/setup/components/testing/playwright.config.ts ./
# 3. Copy sample tests
cp .claude/templates/setup/components/testing/sample-unit.test.ts tests/unit/sample.test.ts
cp .claude/templates/setup/components/testing/sample-e2e.spec.ts tests/e2e/sample.spec.ts
# 4. Install dependencies
npm install --save-dev jest @types/jest ts-jest @playwright/test
# 5. Add scripts to package.json (merge manually or use jq)
# "test": "jest"
# "test:unit": "jest --selectProjects unit"
# "test:e2e": "playwright test"
# 6. Install Playwright browsers
npx playwright install chromium
Validation:
npm run test:unit # Should pass with sample test
ls tests/unit tests/e2e # Directories exist
Install CI/CD Component
# 1. Create directory
mkdir -p .github/workflows
# 2. Copy workflow based on stack
# For base/generic:
cp .claude/templates/setup/components/cicd/ci-base.yml .github/workflows/ci.yml
# For Directus:
cp .claude/templates/setup/components/cicd/ci-directus.yml .github/workflows/ci.yml
# 3. Optionally add Claude review
cp .claude/templates/setup/components/cicd/claude-review.yml .github/workflows/
Validation:
ls .github/workflows/ci.yml # File exists
yq eval '.' .github/workflows/ci.yml # Valid YAML
Install Security Component
# 1. Create directory
mkdir -p .github
# 2. Copy Dependabot config
cp .claude/templates/setup/components/security/dependabot.yml .github/
Validation:
ls .github/dependabot.yml # File exists
yq eval '.version' .github/dependabot.yml # Should return 2
Install Documentation Component
# 1. Create directories
mkdir -p docs/architecture/adr docs/guides
# 2. Copy templates
cp .claude/templates/setup/components/docs/_category_.json docs/
cp .claude/templates/setup/components/docs/docs-README.md docs/README.md
# 3. Replace {DATE} placeholders
sed -i "s/{DATE}/$(date +%Y-%m-%d)/g" docs/README.md
Validation:
ls docs/README.md docs/_category_.json # Files exist
head -5 docs/README.md | grep -q "^---" # Has frontmatter
Install AWS Infrastructure Component
When: Project will be hosted on AWS (Amplify, Lightsail, ECS, etc.)
Template: .claude/templates/setup/components/aws-infrastructure/
Environment Models:
| Model | Accounts | Use Case |
|---|---|---|
simple |
prod only | Prototypes, small projects |
standard |
dev + prod | Most projects (recommended) |
full |
dev + test + prod | Enterprise, regulated |
Prerequisites: Doppler project already created (core module in Minimal Setup)
Installation Steps:
- Ask environment model via AskUserQuestion
- Follow setup guide:
.claude/templates/setup/components/aws-infrastructure/setup-guide.md - Key steps:
- Create AWS Organization Unit
- Create AWS accounts (per model)
- Add AWS credentials to existing Doppler project (dev/stg/prd configs)
- Set up DNS delegation (optional)
- Create git branches matching environments
Validation:
# AWS credentials stored in Doppler (project already exists from Minimal Setup)
doppler run --project {project-name} --config dev -- aws sts get-caller-identity
After AWS Infrastructure, choose hosting component.
Install Amplify Hosting Component
When: Next.js + GraphQL + DynamoDB stack
Template: .claude/templates/setup/components/hosting-amplify/
Prerequisites: AWS Infrastructure component completed
Installation Steps:
- Bootstrap CDK in each account
- Create Amplify apps per environment
- Configure service roles for Gen 2 deployments
- Set platform to WEB_COMPUTE for SSR
- Configure custom domains
- Copy amplify backend template
- Create amplify.yml build config
Files to copy:
cp -r .claude/templates/setup/components/hosting-amplify/amplify/ ./
cp .claude/templates/setup/components/hosting-amplify/amplify.yml ./
Validation:
# CDK bootstrapped
doppler run --project {project-name} --config dev -- \
aws cloudformation describe-stacks --stack-name CDKToolkit
# Amplify app exists
doppler run --project {project-name} --config dev -- \
aws amplify get-app --app-id $(doppler secrets get AMPLIFY_APP_ID --plain)
Full guide: .claude/templates/setup/components/hosting-amplify/setup-guide.md
Install Lightsail Hosting Component
When: Docker/Directus + PostgreSQL stack
Template: .claude/templates/setup/components/hosting-lightsail/
Prerequisites: AWS Infrastructure component completed
Installation Steps:
- Create Lightsail instance(s) per environment
- Configure firewall (ports 22, 80, 443)
- Set up instance with Docker
- Generate secrets (Directus keys, Postgres password)
- Deploy Docker Compose
- Configure SSL with Caddy
- Configure DNS A records
Files to copy:
cp .claude/templates/setup/components/hosting-lightsail/docker-compose.yml ./
Validation:
# Instance running
doppler run --project {project-name} --config prd -- \
aws lightsail get-instance --instance-name {project-name}-prod
# Directus responding
curl -s https://{project-name}.gaininsight.global/server/health
Full guide: .claude/templates/setup/components/hosting-lightsail/setup-guide.md
Workflow: Run Validation Suite
When: After component installation to verify everything works.
# Option 1: Run from AgentFlow templates
cd .claude/templates/setup/validation
npm install
PROJECT_ROOT=/path/to/new-project npm test
# Option 2: Copy validation to project and run
cp -r .claude/templates/setup/validation /path/to/new-project/
cd /path/to/new-project/validation
npm install
npm test
Expected output:
Running 4 projects...
✓ testing.spec.ts (5 tests)
✓ cicd.spec.ts (6 tests)
✓ security.spec.ts (5 tests)
✓ docs.spec.ts (5 tests)
21 passed
Workflow: Brownfield Setup (GainInsight)
When: Adding AgentFlow to an existing repository.
Prerequisites:
- Bare repo exists at
/srv/repos/{repo}.git(viaadd-repo) - Running on gidev (LINEAR_API_KEY available via Doppler)
Questions to ask:
- Repo name? (validate exists at /srv/repos/)
- Linear team exists? If no:
- Project name for Linear team?
- Team key? (2-5 uppercase letters)
- Development model? (trunk, trunk+develop, or feature)
- If team exists: Linear team key? (validate exists, check for AgentFlow states)
- Which branch for stable worktree?
- Zulip stream? (optional)
Steps:
- Validate bare repo exists:
ls /srv/repos/{repo}.git - Check if Linear team exists (via GraphQL API)
- If no: Create team with AgentFlow states (see "Linear Team Setup" workflow)
- If yes: Verify AgentFlow states exist, add missing states if needed
- Create Doppler project if not exists:
doppler projects create {project-name} --description "Secrets for {project-name}" - Detect default branch from bare repo
- Create or use stable worktree
- Install dependencies:
npm install - Sync AgentFlow framework
- Create CLAUDE.md from template:
.claude/templates/setup/brownfield-claudemd.md - Create security config if missing:
mkdir -p .github && cp .claude/templates/github/dependabot.yml .github/ - Commit and push (use --no-verify)
- Add to project registry via
project-registryCLI (see "Project Registry Entry" workflow) - Create docs portal files
- Create Linear issue with next steps (docs retrofit, security audit)
- Show handoff message:
.claude/templates/setup/brownfield-handoff.txt
Success criteria:
- ✅ Linear team exists with AgentFlow workflow states
- ✅ Doppler project created with default configs
- ✅ AgentFlow framework synced to
.claude/ - ✅ CLAUDE.md created with project context
- ✅ Project in registry with docs config
- ✅ Linear issue created with retrofit instructions
Workflow: Project Registry Entry
When: Adding any project to gidev infrastructure.
Registry: project-registry CLI (backed by PostgreSQL/RDS — but always use the CLI, never raw SQL).
Reading config:
project-registry list # All project keys
project-registry <project> # Full config (YAML format)
project-registry <project> <field> # Single field (dot notation)
project-registry <project> linear.team_id # Example: get Linear team UUID
Updating config:
project-registry set <project> <field> <value>
# Examples:
project-registry set myproject agent_enabled true
project-registry set myproject branching_strategy trunk+develop
project-registry set myproject linear.team_key HLM
Key fields:
| Field | Purpose |
|---|---|
name |
Display name |
linear.team_key / linear.team_id |
Linear team mapping (use UUID for linearis CLI) |
zulip.stream / zulip.stream_id |
Zulip stream for agent notifications (legacy: slack.channel_id) |
github.repo |
GitHub repo (Org/repo) — always use GainInsightDev/{repo} |
repo_path |
Bare repo on server |
worktree_base |
Where worktrees live |
run_as |
Unix user for agent sessions |
port_base |
Base port for dev servers |
agent_enabled |
true to allow Agentflow to spawn agents |
branching_strategy |
trunk, trunk+develop, or feature-branch |
doppler.project / doppler.config |
Secrets management |
Steps to add a new project:
- Find next port_base:
project-registry listthen check existing port_base values, add 10000 - Create project entry with initial config:
bash
project-registry set {project-key} name "{Display Name}" project-registry set {project-key} linear.team_key "{TEAM_KEY}" project-registry set {project-key} linear.team_id "{team-uuid}" project-registry set {project-key} github.repo "GainInsightDev/{project-key}" project-registry set {project-key} repo_path "/srv/repos/{project-key}.git" project-registry set {project-key} worktree_base "/srv/worktrees/{project-key}" project-registry set {project-key} run_as "tmux-shared" project-registry set {project-key} port_base "{next-port-base}" project-registry set {project-key} agent_enabled true project-registry set {project-key} branching_strategy "feature-branch" project-registry set {project-key} doppler.project "{project-key}" project-registry set {project-key} doppler.config "dev" project-registry set {project-key} zulip.stream "{project-key}" - Verify:
project-registry {project-key}
Lookups:
project-registry find-by-team HLM # Find project by Linear team key
project-registry find-by-channel C0ACD7LK95J # Find by channel (legacy Slack, migrating to Zulip)
project-registry find-by-repo myproject # Find by repo name
project-registry teams # List all team→project mappings
project-registry channels # List all channel→project mappings
Portal Integration
The project registry drives two portals on gidev:
| Portal | Registry Field | What It Does |
|---|---|---|
| Docs Portal | docs config | Syncs documentation from repo to docs site |
| Costs Portal | AWS account IDs | Queries AWS Cost Explorer for project spend |
Docs Portal:
- Automatically syncs when registry entry exists
- Requires
docs/README.mdin the specified branch/subpath - No manual refresh needed
Costs Portal:
- Requires AWS account IDs in project config
- Must run
sudo /usr/local/bin/collect-aws-costsafter adding accounts - Runs automatically on schedule, but manual run picks up new projects immediately
Workflow: Resume After Failure
When: Setup failed partway through.
Steps:
- Setup detects incomplete state automatically
- Prompts to resume or restart
- Continues from last successful phase
- Preserves completed work
Just re-run the setup command - resume is automatic.
Decision Points
Greenfield vs Brownfield?
- New project from scratch → Greenfield
- Existing codebase → Brownfield
- Failed setup → Resume (automatic)
Which modules to install?
Module selection happens during Discovery, not during Setup:
- Discovery outputs a Tech Stack Agreement with selected modules
- Setup reads the agreement and installs modules in dependency order
- See
.claude/docs/reference/module-registry.ymlfor available modules - See
.claude/docs/guides/integrations/for cross-module integration guides
Common Pitfalls
-
Linear team key already exists
- Team keys must be unique across the workspace
- Check existing teams first:
curl ... '{"query": "{ teams { nodes { key } } }"}' - Choose a different 2-5 character uppercase key
-
Running in non-empty directory
- Greenfield needs empty directory
- Prevents conflicts
-
Skipping project registry
- Docs portal won't sync
- Add entry via
project-registryCLI
-
Wrong port_base
- Check existing:
project-registry listthen inspect port_base values - Add 10000 to highest existing value
- Prevents port collisions
- Check existing:
-
Missing docs portal files
- Create
docs/_category_.jsonanddocs/README.md - Required for docs portal sync
- Create
-
Costs portal not showing new project
- Add
aws.accountsto project registry - Run
sudo /usr/local/bin/collect-aws-coststo refresh - Costs data appears after next collection run
- Add
Zulip Notifications
Optional - requires Zulip bot credentials in Doppler.
Steps:
- Identify the target Zulip stream from the project registry
- Post message via Zulip API using bot credentials (
ZULIP_BOT_EMAIL,ZULIP_API_KEY,ZULIP_REALM)
If bot not subscribed to stream:
- Subscribe bot to the stream, or tell user to do so
- Don't block setup completion
Message template:
:white_check_mark: AgentFlow setup complete for *{repo-name}*
:package: *{Project Name}*
:link: GitHub: https://github.com/{owner}/{repo}
:ticket: Linear: https://linear.app/gaininsight/issue/{ISSUE-ID}
:file_folder: Worktree: `/srv/worktrees/{repo}/{branch}`
Run `start-work {repo-name} {ISSUE-ID}` to begin development.
Success Criteria
A successful setup means:
- ✅ All phases completed
- ✅ Build succeeds:
npm run build - ✅ Tests pass:
npm test - ✅ Git repository initialized
- ✅ Project in registry (gidev)
Workflow: Pre-E2E Infrastructure Requirements
When: After Layer 1 (Infrastructure) but before E2E tests can pass.
Problem: E2E tests involving email (signup, password reset, invitations) will fail without proper infrastructure setup.
Full guide: See Auth Setup Guide for comprehensive Cognito + SES workflows. Skills: af-configure-cognito-auth, af-configure-ses-email.
Checklist:
| Requirement | Command to Check | Impact if Missing |
|---|---|---|
| SES production access (per account) | aws sesv2 get-account --query ProductionAccessEnabled |
Emails don't send in sandbox mode |
| Gmail testing credentials | doppler secrets get GMAIL_TESTING_SERVICE_ACCOUNT |
Can't verify emails in tests |
| Domain DKIM verification | aws sesv2 get-email-identity --email-identity domain |
Custom emails rejected by Gmail |
| Cognito attributes mutable | Check amplify/auth/resource.ts |
Can't update user attributes |
SES Production Access Request:
# Request for each environment's AWS account
doppler run --project {project} --config {env} -- aws sesv2 put-account-details \
--mail-type TRANSACTIONAL \
--website-url "https://your-url.com" \
--use-case-description "Transactional emails for authentication" \
--production-access-enabled
Approval takes 24-48 hours per account.
DKIM Setup for Custom Email Domain:
# 1. Add domain identity
aws sesv2 create-email-identity --email-identity your-domain.com
# 2. Get DKIM tokens
aws sesv2 get-email-identity --email-identity your-domain.com \
--query 'DkimAttributes.Tokens'
# 3. Add 3 CNAME records to DNS:
# {token1}._domainkey.your-domain.com → {token1}.dkim.amazonses.com
# {token2}._domainkey.your-domain.com → {token2}.dkim.amazonses.com
# {token3}._domainkey.your-domain.com → {token3}.dkim.amazonses.com
# 4. Verify DKIM is active (may take 72h)
aws sesv2 get-email-identity --email-identity your-domain.com \
--query 'DkimAttributes.Status' # Should be "SUCCESS"
Note: Without DKIM, custom emails (invitations, notifications) sent directly via SES client may be silently rejected by Gmail even though SES returns success. Cognito emails work because Cognito uses its own configured identity.
Workflow: Cross-Account Resource Access
When: Test/prod accounts need access to shared dev resources (S3 report buckets, etc.)
Problem: Test reports fail to upload to S3 bucket in dev account from test/prod accounts.
Solution: Add cross-account bucket policy:
{
"Sid": "CrossAccountAccess",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::TEST_ACCOUNT_ID:user/deploy-user",
"arn:aws:iam::PROD_ACCOUNT_ID:user/deploy-user"
]
},
"Action": ["s3:ListBucket", "s3:PutObject", "s3:GetObject"],
"Resource": [
"arn:aws:s3:::bucket-name",
"arn:aws:s3:::bucket-name/*"
]
}
Workflow: Doppler→GitHub Sync (CI/CD Credentials)
When: Configuring GitHub Actions to access Doppler secrets at runtime.
Problem: CI/CD workflows need credentials (AWS, Linear API, etc.). Manual copying of each secret to GitHub is error-prone and creates sync drift.
Solution: Use Doppler runtime fetch - create a single service token that workflows use to fetch all secrets at runtime.
Prerequisites:
- Doppler project exists with dev/stg/prd configs
- GitHub repo accessible via
ghCLI - Doppler CLI authenticated (
doppler login)
Steps:
-
Create Doppler service token for the environment:
bash# Create token for dev config (most common for CI) DOPPLER_TOKEN=$(doppler configs tokens create \ --project {project-name} \ --config dev \ --name github-actions \ --plain) -
Set token as GitHub secret:
bashgh secret set DOPPLER_TOKEN \ --repo {owner}/{repo} \ --body "$DOPPLER_TOKEN" -
Verify secret is set:
bashgh secret list --repo {owner}/{repo} | grep DOPPLER_TOKEN
Workflow usage pattern:
In GitHub Actions, use the Doppler action to inject secrets:
steps:
- name: Fetch secrets from Doppler
uses: dopplerhq/[email protected]
with:
doppler-token: ${{ secrets.DOPPLER_TOKEN }}
inject-env-vars: true
- name: Use secrets
run: |
# All Doppler secrets are now environment variables
aws s3 ls # Uses AWS_ACCESS_KEY_ID from Doppler
Or use doppler run directly:
steps:
- name: Run with Doppler
env:
DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }}
run: doppler run -- npm run deploy
Benefits:
- Single secret to manage in GitHub
- Secrets stay in sync with Doppler automatically
- New secrets in Doppler immediately available to CI
- Audit trail in Doppler for secret access
Multiple environments:
For staging/prod deployments, create separate tokens:
# Create tokens for each environment
doppler configs tokens create --project {project} --config dev --name gha-dev --plain
doppler configs tokens create --project {project} --config stg --name gha-stg --plain
doppler configs tokens create --project {project} --config prd --name gha-prd --plain
# Set as separate GitHub secrets
gh secret set DOPPLER_TOKEN_DEV --body "$DEV_TOKEN"
gh secret set DOPPLER_TOKEN_STG --body "$STG_TOKEN"
gh secret set DOPPLER_TOKEN_PRD --body "$PRD_TOKEN"
Validation:
# Token works
DOPPLER_TOKEN=$DOPPLER_TOKEN doppler secrets --only-names
# GitHub secret exists
gh secret list | grep DOPPLER_TOKEN
Workflow: Test Script Configuration (Doppler)
When: Configuring package.json test scripts for projects using Doppler for credentials.
Problem: Integration and E2E tests require AWS/cloud credentials. Without proper configuration, developers must remember to prefix commands with doppler run ....
Solution: Create paired scripts - raw scripts for CI/CD, :local variants for local development.
Required scripts in package.json:
{
"scripts": {
"test:unit": "jest --selectProjects unit",
"test:integration": "jest --selectProjects integration",
"test:integration:local": "doppler run --project {project} --config dev -- npm run test:integration",
"test:coverage": "jest --coverage",
"test:coverage:local": "doppler run --project {project} --config dev -- jest --coverage",
"test:e2e": "playwright test",
"test:e2e:local": "doppler run --project {project} --config dev -- npm run test:e2e",
"test:all": "npm run test:unit && npm run test:integration && npm run test:e2e",
"test:all:local": "npm run test:unit && npm run test:integration:local && npm run test:e2e:local"
}
}
Replace {project} with the Doppler project name (usually matches repo name).
Script purposes:
| Script | Credentials | Use Case |
|---|---|---|
test:unit |
None needed | Always works, no external deps |
test:integration |
Injected by CI/CD | GitHub Actions with Doppler |
test:integration:local |
Via Doppler CLI | Local development |
test:coverage |
Injected by CI/CD | CI coverage report |
test:coverage:local |
Via Doppler CLI | Local coverage (unit + integration) |
test:e2e |
Injected by CI/CD | GitHub Actions with Doppler |
test:e2e:local |
Via Doppler CLI | Local development |
Why this pattern?
- CI/CD environments inject credentials differently (GitHub Actions Doppler integration)
- Local developers get automatic credential injection
- Clear distinction between CI and local execution
- Unit tests work everywhere without configuration
Validation:
# Unit tests (no credentials needed)
npm run test:unit
# Integration tests (local with Doppler)
npm run test:integration:local
# E2E tests (local with Doppler)
npm run test:e2e:local
Essential Reading
Comprehensive guide:
- Setup Guide - Full 1600+ line guide
Templates:
.claude/templates/setup/- CLAUDE.md and handoff templates
Related skills:
af-discover-scope- Next phase after setupaf-configure-test-frameworks- For E2E infrastructure requirements
Module system:
- Module Registry - Available modules and dependencies
- Integration Guides - Cross-module integration knowledge
Remember:
- Linear team must exist before setup
- Use templates from
.claude/templates/setup/ - Add project to registry for docs sync
- Resume is automatic on failure
- Validate before declaring success
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?