Enterprise Deployment Repo
For enterprise customers, deploy ThinkWork from a customer-owned deployment repository, not from a fork of the ThinkWork source repository. The deployment repo pins a released ThinkWork manifest, stores customer-specific overlays, and uses GitHub Actions OIDC to deploy into the customer’s AWS account.
This is not a fork of the ThinkWork source repository.
This gives the delivery team a controlled place for stage configuration, customer eval packs, workspace defaults, skill packs, branding, approval gates, and deploy evidence while keeping upstream ThinkWork upgrades simple.
Deployment Model
Section titled “Deployment Model”The first setup has one privileged bootstrap step. After that, every deploy runs through the generated customer repo workflow.
operator laptop -> bootstrap AWS/GitHub trust -> customer deployment repocustomer deployment repo -> GitHub Actions OIDC -> customer AWS accountrelease manifest -> customer S3/ECR/static hosting/AgentCore runtimescustomer overlays -> deployed tenant evals, skills, workspace defaultsBootstrap creates or updates:
- S3 bucket for Terraform state:
<customer>-thinkwork-terraform-state - DynamoDB lock table:
<customer>-thinkwork-terraform-locks - S3 bucket for release artifacts:
<customer>-thinkwork-release-artifacts - GitHub Actions OIDC provider in the customer AWS account
- One AWS deploy role per stage:
thinkwork-<customer>-<stage>-deploy - GitHub Environments for each stage
- GitHub Environment variables:
AWS_REGION,AWS_ROLE_ARN,THINKWORK_ARTIFACT_BUCKET - Local deployment repo files, including
thinkwork.lock,.github/workflows/deploy.yml,terraform/, andcustomer/
The CLI generates or prompts for required GitHub Environment secrets and writes
them through gh secret set. Secret values are not written to the deployment
repo or local ThinkWork metadata.
| Secret name | Used for |
|---|---|
TF_VAR_DB_PASSWORD | Terraform variable db_password |
TF_VAR_API_AUTH_SECRET | Terraform variable api_auth_secret |
Exact First Deploy
Section titled “Exact First Deploy”Run these commands from an operator machine that has temporary customer AWS administrator access and GitHub admin access to the deployment repository.
-
Log in and verify readiness
Terminal window thinkwork loginThe AWS identity should be in the customer AWS account. The GitHub identity should be authenticated with
ghand allowed to create repository environments, variables, and secrets. -
Run the guided bootstrap
Terminal window thinkwork deploy --bootstrapIn an interactive terminal, this command walks through the setup: customer slug, stage, GitHub deployment repo, whether to create the repo if it does not exist, and production-like secret values. It creates or reuses a managed checkout, bootstraps dev and prod deployment authority, commits and pushes the generated repo files, dispatches the requested stage, waits for GitHub Actions, and prints the run URL plus discovered ThinkWork URLs.
For scripted first deploys, pass the values explicitly:
Terminal window thinkwork deploy --bootstrap \--customer acme \--repo acme-corp/acme-thinkwork-deploy \--create-repo \--stage devWith the example values above, the deployment repo is
--repo acme-corp/acme-thinkwork-deploy. -
Deploy again after repo or overlay changes
Terminal window cd acme-thinkwork-deploythinkwork deployFrom inside the generated deployment repo, bare
thinkwork deployreads the customer, stage, and repository context from the repo and dispatches the normal customer workflow. Use--customer acme --stage devfrom outside the repo, or add--component overlays,--component smokes, or--no-waitwhen you need a narrower follow-up run. -
Remove a stage
Terminal window thinkwork destroyFrom inside the generated deployment repo, this prompts for the stage, confirms the destructive action, dispatches the customer repo workflow with
operation=destroy, waits for GitHub Actions, and reports the run URL. It removes the selected stage stack through Terraform while preserving the customer deployment repo, Terraform state bucket, artifact bucket, OIDC provider, and GitHub Environment configuration. -
Log in to the deployed stack
Terminal window thinkwork login --stage devthinkwork me --stage dev
What the CLI Does
Section titled “What the CLI Does”The one-line path automates the manual bootstrap flow:
- Prompts for or resolves the customer, stage, repository, and managed checkout.
- Creates or clones the private customer deployment repo.
- Resolves the ThinkWork release manifest and computes its checksum.
- Bootstraps AWS state buckets, lock table, artifact bucket, OIDC provider, and per-stage deploy roles.
- Creates GitHub Environments and writes non-secret environment variables.
- Generates or prompts for required GitHub Environment secrets.
- Writes
thinkwork.lock, workflow files, Terraform files, andcustomer/overlay defaults. - Commits and pushes the generated deployment repo.
- Dispatches
.github/workflows/deploy.ymlfor the requested stage. - Waits for the run by default, reports failed jobs on error, lists deploy evidence artifacts, and prints discovered Admin, API, AppSync, and Docs URLs when available.
Manual Fallback
Section titled “Manual Fallback”Use the lower-level commands only when troubleshooting the one-line flow or when a scripted environment needs to split the steps apart.
-
Confirm local tools and access
Terminal window node --versionnpm --versiongh auth statusaws sts get-caller-identity -
Create or clone the customer deployment repository
Terminal window CUSTOMER=acmeREPO=acme-corp/acme-thinkwork-deploygh repo create "$REPO" --private --clonecd "$(basename "$REPO")" -
Choose and verify the release to deploy
Bootstrap defaults to the installed CLI version. For a repeatable manual deploy, pin the release manifest URL and checksum explicitly:
Terminal window VERSION="$(thinkwork --version)"RELEASE="v${VERSION#v}"MANIFEST_URL="https://github.com/thinkwork-ai/thinkwork/releases/download/${RELEASE}/thinkwork-release.json"MANIFEST_SHA256="$(curl -fsSL "$MANIFEST_URL" | shasum -a 256 | awk '{print $1}')" -
Bootstrap with a dry run
Terminal window AWS_REGION=us-east-1thinkwork enterprise bootstrap . \--customer "$CUSTOMER" \--repo "$REPO" \--stage dev \--stage prod \--region "$AWS_REGION" \--release-version "$RELEASE" \--manifest-url "$MANIFEST_URL" \--manifest-sha256 "$MANIFEST_SHA256" \--dry-run -
Run bootstrap for real
Terminal window thinkwork enterprise bootstrap . \--customer "$CUSTOMER" \--repo "$REPO" \--stage dev \--stage prod \--region "$AWS_REGION" \--release-version "$RELEASE" \--manifest-url "$MANIFEST_URL" \--manifest-sha256 "$MANIFEST_SHA256" \--yes -
Set required GitHub Environment secrets if you bypassed top-level deploy
Terminal window gh secret set TF_VAR_DB_PASSWORD --repo "$REPO" --env dev --body "$DEV_DB_PASSWORD"gh secret set TF_VAR_API_AUTH_SECRET --repo "$REPO" --env dev --body "$DEV_API_AUTH_SECRET"Repeat for
prodbefore production. -
Verify GitHub Environment variables
Bootstrap should have set these for every stage:
Terminal window gh variable list --repo "$REPO" --env devgh variable list --repo "$REPO" --env prodConfirm the values:
Variable Expected value AWS_REGIONTarget AWS region, for example us-east-1AWS_ROLE_ARNarn:aws:iam::<account>:role/thinkwork-<customer>-dev-deployTHINKWORK_ARTIFACT_BUCKET<customer>-thinkwork-release-artifacts -
Review stage Terraform values
Edit
terraform/stages/dev.tfvarsbefore first deploy. The generated file is intentionally minimal:stage = "dev"region = "us-east-1"account_id = "123456789012"database_engine = "aurora-serverless"lambda_artifact_bucket = "acme-thinkwork-release-artifacts"lambda_artifact_prefix = "releases/v0.12.5/lambdas"Add customer-specific non-secret values such as domain, hosted zone, Google OAuth client ID, callback URLs, SES settings, tags, or capacity settings. Do not put passwords, OAuth client secrets, API auth secrets,
.envvalues, or connector secrets interraform/stages/*.tfvars. -
Review the customer overlay contract
The generated
customer/deployment.jsonalready contains each stage:{"schemaVersion": 1,"customerSlug": "acme","stages": {"dev": {"tenantSlug": "acme-dev","evalPacks": [],"seedPacks": [],"skillPacks": [],"workspaceDefaultPacks": [],"branding": null},"prod": {"tenantSlug": "acme","evalPacks": [],"seedPacks": [],"skillPacks": [],"workspaceDefaultPacks": [],"branding": null}}}Add customer evals, skill packs, workspace defaults, seed packs, and branding under
customer/only when they are ready to apply. -
Commit any stage or overlay edits
Terminal window git add terraform/stages customergit commit -m "chore: configure dev ThinkWork deployment"git push -
Dispatch the first dev deploy
Terminal window gh workflow run deploy.yml \--repo "$REPO" \-f stage=dev \-f component=all \-f run_smokes=trueWatch the run:
Terminal window RUN_ID="$(gh run list --repo "$REPO" --workflow deploy.yml --limit 1 --json databaseId --jq '.[0].databaseId')"gh run watch "$RUN_ID" --repo "$REPO" --exit-status -
Download deploy evidence
Terminal window mkdir -p "deploy-artifacts/dev-${RUN_ID}"gh run download "$RUN_ID" \--repo "$REPO" \--name "thinkwork-deploy-dev-${RUN_ID}" \--dir "deploy-artifacts/dev-${RUN_ID}"jq . "deploy-artifacts/dev-${RUN_ID}/deploy-summary.json"jq . "deploy-artifacts/dev-${RUN_ID}/smoke-summary.json"Keep the deploy summary artifact as customer deployment evidence.
-
Log in to the deployed stack
Terminal window thinkwork login --stage dev --region "$AWS_REGION"thinkwork me --stage dev --region "$AWS_REGION"Use the admin URL from
deploy-summary.jsonto open the admin app and verify the first tenant, agent template, evals, and overlay files. -
Deploy production
Before production, require approval on the GitHub
prodEnvironment and set production secrets. Then dispatch the same workflow:Terminal window gh workflow run deploy.yml \--repo "$REPO" \-f stage=prod \-f component=all \-f run_smokes=true
Workflow Inputs
Section titled “Workflow Inputs”The generated .github/workflows/deploy.yml accepts these inputs:
| Input | Values | Use |
|---|---|---|
operation | deploy or destroy | Deploys or destroys the selected stage stack. |
stage | Any stage generated by bootstrap, for example dev | Selects terraform/backend-<stage>.hcl, terraform/stages/<stage>.tfvars, and customer.deployment.json stage config. |
component | all | First deploy and normal release upgrades. |
component | foundation | Terraform apply plus artifact/runtime/static sync, without overlays. |
component | artifacts | Re-copy release Lambda/static/runtime artifacts without Terraform apply. |
component | overlays | Apply only customer evals, skills, workspace defaults, seed validation, and branding records. |
component | smokes | Run smoke checks against an already-deployed stage. |
run_smokes | true or false | Runs scripts/smoke.mjs after component=all or component=smokes. |
What CI Does
Section titled “What CI Does”For operation=deploy and component=all, the workflow runs this exact
sequence:
- Check out the customer deployment repo.
- Read
thinkwork.lock,customer/deployment.json, the stage backend file, and the stage tfvars file. - Download
thinkwork-release.jsonfrom the pinned GitHub release. - Verify the manifest checksum when
manifestSha256is notCHANGE_ME. - Assume the stage AWS role through GitHub Actions OIDC.
- Download release Lambda/static artifacts and upload Lambda zips into the customer artifact bucket.
- Run
terraform init, select or create the stage workspace, and runterraform apply -auto-approve. - Copy pinned runtime images from GHCR into the customer ECR repository.
- Update AgentCore runtimes to the copied stage image tags.
- Sync static site bundles from the pinned release.
- Run
thinkwork enterprise overlay apply. - Run smoke checks when
run_smokes=true. - Write and upload deploy evidence JSON artifacts.
For operation=destroy, the workflow verifies the repo and release metadata,
assumes the stage deploy role through GitHub Actions OIDC, selects the existing
Terraform workspace, and runs terraform destroy -auto-approve with the
stage’s tfvars. It does not run overlays, smokes, runtime image copy, or URL
discovery after the stack is removed.
Overlay-Only Changes
Section titled “Overlay-Only Changes”Use this path when only customer/ files changed:
thinkwork enterprise overlay apply . \ --stage dev \ --region us-east-1 \ --dry-run \ --json
git add customergit commit -m "chore: update acme ThinkWork overlays"git push
thinkwork deploy --customer acme --stage dev --component overlays --no-run-smokesCI writes overlay-report.json into the workflow artifact.
Release Upgrades
Section titled “Release Upgrades”To adopt a new ThinkWork release, update thinkwork.lock in the customer repo,
commit it, and run component=all.
VERSION="0.12.5"RELEASE="v${VERSION#v}"MANIFEST_URL="https://github.com/thinkwork-ai/thinkwork/releases/download/${RELEASE}/thinkwork-release.json"MANIFEST_SHA256="$(curl -fsSL "$MANIFEST_URL" | shasum -a 256 | awk '{print $1}')"
tmp="$(mktemp)"jq \ --arg release "$RELEASE" \ --arg manifestUrl "$MANIFEST_URL" \ --arg manifestSha256 "$MANIFEST_SHA256" \ --arg terraformModuleVersion "${RELEASE#v}" \ '.thinkwork.release = $release | .thinkwork.manifestUrl = $manifestUrl | .thinkwork.manifestSha256 = $manifestSha256 | .thinkwork.terraformModuleVersion = $terraformModuleVersion | .artifacts.lambdaPrefix = ("releases/" + $release + "/lambdas")' \ thinkwork.lock > "$tmp"mv "$tmp" thinkwork.lock
git add thinkwork.lockgit commit -m "chore: bump ThinkWork to ${RELEASE}"git push
thinkwork deploy --customer acme --stage dev --component allAfter dev passes, repeat the workflow dispatch for production.
Repository Layout
Section titled “Repository Layout”| Path | Owner | Purpose |
|---|---|---|
thinkwork.lock | Delivery team | Pins the ThinkWork release manifest URL and checksum. |
.github/workflows/deploy.yml | ThinkWork template | CI deploy path. Regenerated by bootstrap and updated on release bumps. |
terraform/stages/*.tfvars | Customer/delivery | Non-secret stage configuration. |
terraform/backend-*.hcl | Bootstrap | S3 state backend for each stage. |
customer/deployment.json | Customer/delivery | Declares which overlay packs apply per stage. |
customer/evals/ | Customer/delivery | Customer eval packs. |
customer/skills/ | Customer/delivery | Workspace skill packs installed onto the target template. |
customer/workspace-defaults/ | Customer/delivery | Customer GUARDRAILS.md, MEMORY_GUIDE.md, and related defaults. |
customer/seeds/ | Customer/delivery | Customer-owned seed payloads validated by the overlay command. |
customer/branding/ | Customer/delivery | Static brand assets referenced by deployment config. |
docs/runbook.md | Customer/delivery | Customer-local runbook generated from this deployment model. |
What Goes Upstream
Section titled “What Goes Upstream”Put reusable platform behavior, Terraform module changes, runtime fixes, schema migrations, built-in tools, and generic eval improvements in the ThinkWork source repository. Put customer-specific templates, guardrails, skills, datasets, branding, and stage configuration in the deployment repo.
That split is the whole point: customize without forking, then contribute general improvements back upstream through normal ThinkWork PRs.
Failure Modes
Section titled “Failure Modes”| Symptom | Likely cause | Fix |
|---|---|---|
manifestSha256 check fails | thinkwork.lock URL and checksum do not describe the same release asset. | Recompute the checksum from the manifest URL and recommit thinkwork.lock. |
| Workflow cannot assume role | GitHub Environment name, repository name, or OIDC trust policy does not match. | Re-run thinkwork enterprise bootstrap ... --yes with the exact --repo and stage names. |
| Terraform backend init fails | State bucket or lock table was not created, or the stage backend file points at the wrong region. | Re-run bootstrap and inspect terraform/backend-<stage>.hcl. |
| Terraform prompts for variables | Required GitHub Environment secrets are missing. | Set TF_VAR_DB_PASSWORD and TF_VAR_API_AUTH_SECRET on the target GitHub Environment. |
| Overlay apply cannot find template | customer/deployment.json target template slug does not exist yet. | Use the default generated template slug or create the template before applying overlays. |
Smoke summary is degraded | One or more deployed URLs returned an error or could not be reached. | Inspect smoke-summary.json, CloudWatch logs, and the workflow step logs. |
Related Pages
Section titled “Related Pages”- Customer Overlay Contract - overlay schema and pack layout
- Configuration Reference - Terraform values and secret handling
- CLI Commands -
thinkwork enterprisecommands