thinkwork-cli 0.12.16 → 0.12.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/dist/cli.js +517 -10403
  2. package/dist/commands/enterprise/templates/deploy-repo/docs/runbook.md +3 -8
  3. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +1 -184
  4. package/dist/drizzle/0050_brain_v0_entity_subtype.sql +2 -2
  5. package/dist/drizzle/0051_brain_v0_tenant_entity_pages.sql +6 -6
  6. package/dist/drizzle/0052_brain_v0_external_refs.sql +2 -2
  7. package/dist/drizzle/0053_brain_v0_unresolved_mentions_subtype.sql +2 -2
  8. package/dist/drizzle/0145_knowledge_graph_thread_ingest.sql +14 -14
  9. package/dist/drizzle/0146_knowledge_graph_source_scope.sql +1 -1
  10. package/dist/drizzle/0157_knowledge_graph_observations_source.sql +2 -2
  11. package/dist/drizzle/0158_wiki_tenant_scope.sql +1 -1
  12. package/dist/drizzle/0165_plugin_premium_entitlements.sql +2 -2
  13. package/dist/drizzle/{0166_company_brain_substrate_contract.sql → 0166_brain_substrate_contract.sql} +9 -9
  14. package/dist/drizzle/{0167_company_brain_artifact_manifest_runtime.sql → 0167_brain_artifact_manifest_runtime.sql} +5 -5
  15. package/dist/drizzle/0168_eval_skill_gate.sql +1 -1
  16. package/dist/drizzle/0183_okf_artifact_manifests.sql +1 -1
  17. package/dist/drizzle/0200_eval_results_execution_tier.sql +40 -0
  18. package/dist/drizzle/0201_brain_dream_runs.sql +72 -0
  19. package/dist/drizzle/0202_backfill_thread_participants_from_senders.sql +110 -0
  20. package/dist/drizzle/0203_threads_mode_override.sql +61 -0
  21. package/dist/drizzle/0204_thread_turns_triggering_message_id.sql +48 -0
  22. package/dist/drizzle/0205_routines_git_python.sql +185 -0
  23. package/dist/drizzle/0206_agent_loop_versions_routine_actions.sql +40 -0
  24. package/dist/drizzle/0207_tenant_credentials_github_repo_kind.sql +52 -0
  25. package/dist/drizzle/0208_knowledge_graph_neutral_identifiers.sql +253 -0
  26. package/dist/drizzle/0209_living_artifacts_schema.sql +109 -0
  27. package/dist/drizzle/0210_think137_automations_additive_schema.sql +113 -0
  28. package/dist/drizzle/0211_backfill_agent_loop_versions_target_spec.sql +120 -0
  29. package/dist/drizzle/0212_fold_webhooks_into_automations.sql +312 -0
  30. package/dist/drizzle/0213_agent_loop_versions_judge_evidence_nullable.sql +63 -0
  31. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +99 -0
  32. package/dist/drizzle/0215_agent_loop_versions_goal_worker_policy_nullable.sql +70 -0
  33. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +81 -0
  34. package/dist/drizzle/0217_agents_capability_folder_dispatch.sql +12 -0
  35. package/dist/drizzle/0218_document_plates.sql +30 -0
  36. package/dist/drizzle/0219_document_section_waivers.sql +29 -0
  37. package/dist/drizzle/0220_artifacts_created_by_user.sql +21 -0
  38. package/dist/drizzle/0221_artifact_shares.sql +29 -0
  39. package/dist/drizzle/0221_workflow_interpreter_thin_slice.sql +71 -0
  40. package/dist/drizzle/0222_compliance_drainer_select_audit_events.sql +21 -0
  41. package/dist/drizzle/0223_document_conformance_reports.sql +38 -0
  42. package/dist/drizzle/0224_artifact_refresh_state.sql +11 -0
  43. package/dist/drizzle/0225_think216_agent_loop_convergence.sql +21 -0
  44. package/dist/drizzle/0226_drop_n8n_agent_step_runs.sql +6 -0
  45. package/dist/drizzle/0227_analyst_reader_role.sql +1055 -0
  46. package/dist/drizzle/0228_tenant_credentials_rds_iam_kind.sql +62 -0
  47. package/dist/drizzle/0229_analyst_reader_rds_iam_grant.sql +79 -0
  48. package/dist/drizzle/0230_analyst_rls.sql +1613 -0
  49. package/dist/drizzle/0231_cost_events_cache_write_enforcement_exempt.sql +11 -0
  50. package/dist/plugins/catalog/package.json +0 -1
  51. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +0 -1
  52. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +16 -8
  53. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +56 -0
  54. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +0 -2
  55. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -5
  56. package/dist/plugins/catalog/src/contracts.ts +112 -0
  57. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -6
  58. package/dist/plugins/n8n/README.md +4 -36
  59. package/dist/plugins/n8n/src/deployment/managed-app.ts +0 -17
  60. package/dist/plugins/n8n/src/manifest.ts +0 -5
  61. package/dist/plugins/n8n/terraform/n8n/main.tf +0 -26
  62. package/dist/plugins/n8n/terraform/n8n/outputs.tf +0 -5
  63. package/dist/plugins/n8n/terraform/n8n/variables.tf +0 -6
  64. package/dist/plugins/n8n/test/manifest.test.ts +0 -1
  65. package/dist/plugins/twenty/package.json +5 -0
  66. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +232 -0
  67. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +489 -0
  68. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +199 -0
  69. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +43 -0
  70. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +230 -0
  71. package/dist/plugins/twenty/scripts/lib/__tests__/twenty-client.test.ts +207 -0
  72. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +282 -0
  73. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +220 -0
  74. package/dist/plugins/twenty/scripts/lib/load-records.ts +680 -0
  75. package/dist/plugins/twenty/scripts/lib/mappers.ts +559 -0
  76. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +381 -0
  77. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +191 -0
  78. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +425 -0
  79. package/dist/plugins/twenty/scripts/lib/twenty-client.ts +246 -0
  80. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +610 -0
  81. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +214 -0
  82. package/dist/plugins/twenty/src/manifest.ts +99 -0
  83. package/dist/plugins/twenty/terraform/twenty/README.md +1 -1
  84. package/dist/plugins/twenty/test/manifest.test.ts +12 -2
  85. package/dist/terraform/examples/greenfield/main.tf +90 -380
  86. package/dist/terraform/examples/greenfield/terraform.tfvars.example +0 -1
  87. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  88. package/dist/terraform/modules/app/agentcore-pi/main.tf +29 -38
  89. package/dist/terraform/modules/app/agentcore-pi/variables.tf +23 -15
  90. package/dist/terraform/modules/app/agentcore-runtime/main.tf +3 -3
  91. package/dist/terraform/modules/app/customer-domain/main.tf +16 -2
  92. package/dist/terraform/modules/app/deployment-control-plane/main.tf +5 -0
  93. package/dist/terraform/modules/app/deployment-control-plane/runner.py +85 -207
  94. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +56 -2
  95. package/dist/terraform/modules/app/hindsight-memory/main.tf +52 -4
  96. package/dist/terraform/modules/app/lambda-api/eval-fanout.tf +7 -0
  97. package/dist/terraform/modules/app/lambda-api/handlers.tf +493 -89
  98. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +215 -96
  99. package/dist/terraform/modules/app/lambda-api/main.tf +24 -5
  100. package/dist/terraform/modules/app/lambda-api/outputs.tf +19 -11
  101. package/dist/terraform/modules/app/lambda-api/variables.tf +94 -67
  102. package/dist/terraform/modules/app/ses-email/main.tf +14 -2
  103. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +493 -0
  104. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/outputs.tf +34 -0
  105. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/variables.tf +32 -0
  106. package/dist/terraform/modules/data/aurora-postgres/main.tf +55 -0
  107. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +15 -0
  108. package/dist/terraform/modules/data/s3-buckets/main.tf +26 -0
  109. package/dist/terraform/modules/thinkwork/README.md +0 -1
  110. package/dist/terraform/modules/thinkwork/main.tf +167 -446
  111. package/dist/terraform/modules/thinkwork/outputs.tf +2 -142
  112. package/dist/terraform/modules/thinkwork/variables.tf +55 -309
  113. package/dist/terraform/schema.graphql +4 -0
  114. package/dist/workspace-defaults/files/AGENTS.md +45 -31
  115. package/dist/workspace-defaults/files/CONTEXT.md +48 -4
  116. package/dist/workspace-defaults/files/GUARDRAILS.md +18 -0
  117. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +32 -4
  118. package/dist/workspace-defaults/files/SPACE.md +34 -19
  119. package/dist/workspace-defaults/files/TOOLS.md +30 -0
  120. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +154 -0
  121. package/dist/workspace-defaults/files/skills/document-composer/references/authoring-rules.md +101 -0
  122. package/package.json +1 -1
  123. package/dist/plugins/company-brain/README.md +0 -37
  124. package/dist/plugins/company-brain/package.json +0 -33
  125. package/dist/plugins/company-brain/runtime/cognee/Dockerfile +0 -11
  126. package/dist/plugins/company-brain/smoke/cognee-managed-app-smoke.mjs +0 -458
  127. package/dist/plugins/company-brain/smoke/cognee-memory-cutover-smoke.mjs +0 -539
  128. package/dist/plugins/company-brain/smoke/company-brain-context-engine-smoke.mjs +0 -312
  129. package/dist/plugins/company-brain/smoke/company-brain-operations-smoke.mjs +0 -449
  130. package/dist/plugins/company-brain/smoke/company-brain-plugin-smoke.mjs +0 -655
  131. package/dist/plugins/company-brain/smoke/hindsight-memory-isolation-smoke.mjs +0 -474
  132. package/dist/plugins/company-brain/src/api/cognee-client.ts +0 -896
  133. package/dist/plugins/company-brain/src/api/cognee-cluster-identity.ts +0 -49
  134. package/dist/plugins/company-brain/src/api/cognee-memory-scope.ts +0 -84
  135. package/dist/plugins/company-brain/src/api/context-engine-provider.ts +0 -888
  136. package/dist/plugins/company-brain/src/api/migration.ts +0 -665
  137. package/dist/plugins/company-brain/src/deployment/cognee-managed-app.ts +0 -396
  138. package/dist/plugins/company-brain/src/index.ts +0 -62
  139. package/dist/plugins/company-brain/src/manifest.ts +0 -112
  140. package/dist/plugins/company-brain/terraform/cognee/README.md +0 -263
  141. package/dist/plugins/company-brain/terraform/cognee/main.tf +0 -766
  142. package/dist/plugins/company-brain/terraform/cognee/outputs.tf +0 -144
  143. package/dist/plugins/company-brain/terraform/cognee/variables.tf +0 -402
  144. package/dist/plugins/company-brain/test/api/cognee-client.test.ts +0 -562
  145. package/dist/plugins/company-brain/test/api/cognee-memory-scope.test.ts +0 -74
  146. package/dist/plugins/company-brain/test/api/context-engine-provider.test.ts +0 -447
  147. package/dist/plugins/company-brain/test/api/migration.test.ts +0 -465
  148. package/dist/plugins/company-brain/test/manifest.test.ts +0 -95
  149. package/dist/plugins/company-brain/tsconfig.json +0 -8
@@ -26,16 +26,16 @@ locals {
26
26
  chat_agent_activity_fn_arn = "arn:aws:lambda:${var.region}:${var.account_id}:function:${local.chat_agent_activity_fn_name}"
27
27
  manifest_log_fn_name = "thinkwork-${var.stage}-api-manifest-log"
28
28
  manifest_log_fn_arn = "arn:aws:lambda:${var.region}:${var.account_id}:function:${local.manifest_log_fn_name}"
29
- pi_image_uri = "${var.ecr_repository_url}:pi-latest"
30
- cognee_vpc_enabled = length(var.cognee_subnet_ids) > 0 && length(var.cognee_security_group_ids) > 0
31
- okf_efs_vpc_enabled = var.okf_efs_enabled && length(var.okf_efs_subnet_ids) > 0 && length(var.okf_efs_security_group_ids) > 0
32
- private_vpc_enabled = local.cognee_vpc_enabled || local.okf_efs_vpc_enabled
33
- private_subnet_ids = distinct(concat(var.cognee_subnet_ids, var.okf_efs_subnet_ids))
34
- private_security_group_ids = distinct(concat(
35
- var.cognee_security_group_ids,
36
- var.okf_efs_security_group_ids,
37
- ))
38
- okf_efs_mount_enabled = local.okf_efs_vpc_enabled && var.okf_efs_file_system_arn != "" && var.okf_efs_read_access_point_arn != ""
29
+ # Release-backed deployments use an immutable, source-derived target tag so
30
+ # changing the release image also changes aws_lambda_function.image_uri.
31
+ # Reusing pi-latest lets Terraform miss the update even after ECR is retagged.
32
+ pi_image_tag = var.source_image_uri != "" ? "pi-${substr(sha256(var.source_image_uri), 0, 16)}" : "pi-latest"
33
+ pi_image_uri = "${var.ecr_repository_url}:${local.pi_image_tag}"
34
+ okf_efs_vpc_enabled = var.okf_efs_enabled && length(var.okf_efs_subnet_ids) > 0 && length(var.okf_efs_security_group_ids) > 0
35
+ private_vpc_enabled = local.okf_efs_vpc_enabled
36
+ private_subnet_ids = var.okf_efs_subnet_ids
37
+ private_security_group_ids = var.okf_efs_security_group_ids
38
+ okf_efs_mount_enabled = local.okf_efs_vpc_enabled && var.okf_efs_file_system_arn != "" && var.okf_efs_read_access_point_arn != ""
39
39
  okf_efs_iam_statements = local.okf_efs_mount_enabled ? [
40
40
  {
41
41
  Sid = "OkfWikiEfsReadOnlyMount"
@@ -349,32 +349,14 @@ resource "terraform_data" "seed_pi_image" {
349
349
  set -euo pipefail
350
350
  repo_root="${abspath("${path.module}/../../../..")}"
351
351
  aws ecr get-login-password --region ${var.region} | docker login --username AWS --password-stdin ${var.account_id}.dkr.ecr.${var.region}.amazonaws.com
352
- if docker pull "${var.source_image_uri}"; then
353
- source_id="$(docker image inspect --format '{{.Id}}' "${var.source_image_uri}")"
354
- docker tag "$source_id" "${local.pi_image_uri}"
355
- else
356
- # Unreachable source must not fail a stack whose target tag is already
357
- # seeded (rerun after a partial deploy, or a registry that went
358
- # private) — the Lambda only consumes the target ECR tag.
359
- repo_name="$(basename "${var.ecr_repository_url}")"
360
- if aws ecr describe-images --repository-name "$repo_name" --image-ids imageTag=pi-latest --region ${var.region} >/dev/null 2>&1; then
361
- echo "WARN: could not pull ${var.source_image_uri}; ${local.pi_image_uri} is already seeded — keeping the existing image."
362
- exit 0
363
- fi
364
- dockerfile="$repo_root/packages/agentcore-pi/agent-container/Dockerfile"
365
- if [[ ! -f "$dockerfile" ]]; then
366
- echo "ERROR: could not pull ${var.source_image_uri} and there is no repo checkout at $repo_root to build from." >&2
367
- echo "The pinned release image must be pullable by this machine (public registry, or docker login to its registry)." >&2
368
- echo "Alternatively set agentcore_pi_source_image_uri in terraform.tfvars to an image this AWS account can pull." >&2
369
- exit 1
370
- fi
371
- echo "Unable to pull release image ${var.source_image_uri}; building Pi image from $repo_root"
372
- docker build \
373
- --platform linux/amd64 \
374
- -f "$dockerfile" \
375
- -t "${local.pi_image_uri}" \
376
- "$repo_root"
352
+ if ! docker pull "${var.source_image_uri}"; then
353
+ echo "ERROR: could not pull pinned Pi release image ${var.source_image_uri}." >&2
354
+ echo "Refusing to retain an older runtime while reporting this release as deployed." >&2
355
+ echo "Authenticate the deploy runner to the source registry or provide a pullable agentcore_pi_source_image_uri." >&2
356
+ exit 1
377
357
  fi
358
+ source_id="$(docker image inspect --format '{{.Id}}' "${var.source_image_uri}")"
359
+ docker tag "$source_id" "${local.pi_image_uri}"
378
360
  docker push "${local.pi_image_uri}"
379
361
  EOT
380
362
  }
@@ -403,8 +385,10 @@ resource "aws_lambda_function" "agentcore_pi" {
403
385
  CHAT_AGENT_ACTIVITY_FN_NAME = local.chat_agent_activity_fn_name
404
386
  MANIFEST_LOG_FUNCTION_NAME = local.manifest_log_fn_name
405
387
  HINDSIGHT_ENDPOINT = var.hindsight_endpoint
406
- THINKWORK_API_URL = var.api_endpoint
407
- API_AUTH_SECRET = var.api_auth_secret
388
+ # THINK-220 cutover flag — see the variable description.
389
+ HINDSIGHT_DATABASE_NAME = var.hindsight_database_name
390
+ THINKWORK_API_URL = var.api_endpoint
391
+ API_AUTH_SECRET = var.api_auth_secret
408
392
  # Plan §005 U4 — AuroraSessionStore uses the RDS Data API to persist
409
393
  # Pi's SessionData blobs against threads.session_data. Empty during
410
394
  # the first greenfield apply (DB cluster doesn't exist yet); the
@@ -412,7 +396,14 @@ resource "aws_lambda_function" "agentcore_pi" {
412
396
  DB_CLUSTER_ARN = var.db_cluster_arn
413
397
  DB_SECRET_ARN = var.db_secret_arn
414
398
  OKF_WIKI_NAVIGATOR_ENABLED = tostring(local.okf_efs_mount_enabled)
415
- OKF_WIKI_ROOT = var.okf_efs_mount_path
399
+ # THINK-173 U6: PUBLIC key only — the container verifies capability
400
+ # manifests and must never hold signing material (KTD-3).
401
+ CAPABILITY_SIGNING_PUBLIC_KEY = var.capability_signing_public_key
402
+ OKF_WIKI_ROOT = var.okf_efs_mount_path
403
+ # Per-model Bedrock region overrides, honored by the patched pi-ai
404
+ # provider (patches/@earendil-works__pi-ai). SigV4 signing and endpoint
405
+ # selection both follow the override.
406
+ PI_BEDROCK_MODEL_REGIONS = jsonencode(var.pi_bedrock_model_regions)
416
407
  }
417
408
  }
418
409
 
@@ -49,6 +49,12 @@ variable "hindsight_endpoint" {
49
49
  default = ""
50
50
  }
51
51
 
52
+ variable "hindsight_database_name" {
53
+ description = "Dedicated Hindsight database name (THINK-220 cutover flag). Empty = the provider's direct SQL (high-confidence-fact recall, access-count writes) targets the `hindsight` schema of the primary database; set = that database's `public` schema."
54
+ type = string
55
+ default = ""
56
+ }
57
+
52
58
  variable "agentcore_memory_id" {
53
59
  description = "AgentCore Memory resource ID. Populated automatically by the agentcore-memory module; injected into the container as AGENTCORE_MEMORY_ID for auto-retention."
54
60
  type = string
@@ -69,12 +75,12 @@ variable "api_auth_secret" {
69
75
  }
70
76
 
71
77
  variable "memory_engine" {
72
- description = "Active long-term memory engine ('hindsight', 'agentcore', or 'cognee'). Surfaced to the runtime as MEMORY_ENGINE for telemetry/debugging only; engine selection itself happens in the API's normalized memory layer when memory-retain is invoked."
78
+ description = "Active long-term memory engine ('hindsight' or 'agentcore'). Surfaced to the runtime as MEMORY_ENGINE for telemetry/debugging only; engine selection itself happens in the API's normalized memory layer when memory-retain is invoked."
73
79
  type = string
74
80
  default = "hindsight"
75
81
  validation {
76
- condition = contains(["hindsight", "agentcore", "cognee"], var.memory_engine)
77
- error_message = "memory_engine must be 'hindsight', 'agentcore', or 'cognee'."
82
+ condition = contains(["hindsight", "agentcore"], var.memory_engine)
83
+ error_message = "memory_engine must be 'hindsight' or 'agentcore'."
78
84
  }
79
85
  }
80
86
 
@@ -96,18 +102,6 @@ variable "db_secret_arn" {
96
102
  default = ""
97
103
  }
98
104
 
99
- variable "cognee_subnet_ids" {
100
- description = "Subnet IDs for Pi's private-network attachment when Company Brain/Cognee direct MCP access is enabled."
101
- type = list(string)
102
- default = []
103
- }
104
-
105
- variable "cognee_security_group_ids" {
106
- description = "Security group IDs for Pi's private-network attachment when Company Brain/Cognee direct MCP access is enabled."
107
- type = list(string)
108
- default = []
109
- }
110
-
111
105
  variable "okf_efs_enabled" {
112
106
  description = "When true, mount the generated OKF wiki EFS view into Pi. Requires subnet/security-group inputs and an access point ARN."
113
107
  type = bool
@@ -143,3 +137,17 @@ variable "okf_efs_mount_path" {
143
137
  type = string
144
138
  default = "/mnt/thinkwork-okf"
145
139
  }
140
+
141
+ variable "pi_bedrock_model_regions" {
142
+ description = "Per-model Bedrock region overrides for the Pi runtime (PI_BEDROCK_MODEL_REGIONS). Routes individual model ids to another region when a regional marketplace endpoint degrades (e.g. the 2026-07-06 moonshotai.kimi-k2.5 us-east-1 throughput collapse). Empty map = no overrides; revert by setting {}."
143
+ type = map(string)
144
+ default = {
145
+ "moonshotai.kimi-k2.5" = "us-west-2"
146
+ }
147
+ }
148
+
149
+ variable "capability_signing_public_key" {
150
+ description = "Ed25519 public key (SPKI PEM) the runtime verifies capability manifests with (THINK-173). Empty = manifest-mode invocations fail closed."
151
+ type = string
152
+ default = ""
153
+ }
@@ -59,12 +59,12 @@ variable "nova_act_api_key" {
59
59
  }
60
60
 
61
61
  variable "memory_engine" {
62
- description = "Active long-term memory engine ('hindsight', 'agentcore', or 'cognee'). Surfaced to the runtime as MEMORY_ENGINE for telemetry/debugging only; engine selection itself happens in the API's normalized memory layer when memory-retain is invoked."
62
+ description = "Active long-term memory engine ('hindsight' or 'agentcore'). Surfaced to the runtime as MEMORY_ENGINE for telemetry/debugging only; engine selection itself happens in the API's normalized memory layer when memory-retain is invoked."
63
63
  type = string
64
64
  default = "hindsight"
65
65
  validation {
66
- condition = contains(["hindsight", "agentcore", "cognee"], var.memory_engine)
67
- error_message = "memory_engine must be 'hindsight', 'agentcore', or 'cognee'."
66
+ condition = contains(["hindsight", "agentcore"], var.memory_engine)
67
+ error_message = "memory_engine must be 'hindsight' or 'agentcore'."
68
68
  }
69
69
  }
70
70
 
@@ -132,6 +132,18 @@ variable "email_inbound_fn_name" {
132
132
  default = ""
133
133
  }
134
134
 
135
+ variable "email_inbound_fn_name_attr" {
136
+ description = "Attribute-based twin of email_inbound_fn_name (dependency ordering; attributes only, never count)."
137
+ type = string
138
+ default = ""
139
+ }
140
+
141
+ variable "email_inbound_fn_arn_attr" {
142
+ description = "Attribute-based twin of email_inbound_fn_arn (dependency ordering; attributes only, never count)."
143
+ type = string
144
+ default = ""
145
+ }
146
+
135
147
  variable "enable_email_inbound_lambda_action" {
136
148
  description = "Attach the email-inbound Lambda action and invoke permission to the customer-domain receipt rule."
137
149
  type = bool
@@ -416,7 +428,9 @@ resource "aws_lambda_permission" "ses_invoke_email_inbound" {
416
428
  count = local.has_lambda ? 1 : 0
417
429
  statement_id = "AllowSESInvokeEmailInboundCustomerDomain"
418
430
  action = "lambda:InvokeFunction"
419
- function_name = var.email_inbound_fn_name
431
+ # Prefer the attribute-based twin: it orders this permission after the
432
+ # function's creation (the static name carries no dependency edge).
433
+ function_name = var.email_inbound_fn_name_attr != "" ? var.email_inbound_fn_name_attr : var.email_inbound_fn_name
420
434
  principal = "ses.amazonaws.com"
421
435
  source_account = var.account_id
422
436
  }
@@ -444,7 +458,7 @@ resource "aws_ses_receipt_rule" "inbound" {
444
458
  dynamic "lambda_action" {
445
459
  for_each = local.has_lambda ? [1] : []
446
460
  content {
447
- function_arn = var.email_inbound_fn_arn
461
+ function_arn = var.email_inbound_fn_arn_attr != "" ? var.email_inbound_fn_arn_attr : var.email_inbound_fn_arn
448
462
  invocation_type = "Event"
449
463
  position = local.has_bucket ? 2 : 1
450
464
  }
@@ -329,6 +329,11 @@ resource "aws_iam_role_policy" "codebuild" {
329
329
  "scheduler:*",
330
330
  "secretsmanager:*",
331
331
  "ses:*",
332
+ # THINK-245 shipped SNS-backed cost alerting (aws_sns_topic
333
+ # cost_alerts) — without this, customer runner applies fail on
334
+ # SNS:CreateTopic. Live TEI/McPherson roles were hand-patched
335
+ # 2026-07-09; this keeps future installs correct.
336
+ "sns:*",
332
337
  "sqs:*",
333
338
  "ssm:*",
334
339
  "states:*",
@@ -543,7 +543,6 @@ def controller_input_summary(payload):
543
543
  "features": payload.get("features")
544
544
  or {
545
545
  "baseInstall": {
546
- "cognee": False,
547
546
  "slack": False,
548
547
  "stripe": False,
549
548
  "twenty": False,
@@ -1147,6 +1146,19 @@ def state_terraform_data_input(state, name):
1147
1146
  return {}
1148
1147
 
1149
1148
 
1149
+ def state_root_resource_attributes(state, rtype, name):
1150
+ for resource in state.get("resources", []) or []:
1151
+ if resource.get("module"):
1152
+ continue
1153
+ if resource.get("type") != rtype or resource.get("name") != name:
1154
+ continue
1155
+ for instance in resource.get("instances", []) or []:
1156
+ attributes = instance.get("attributes")
1157
+ if isinstance(attributes, dict):
1158
+ return attributes
1159
+ return {}
1160
+
1161
+
1150
1162
  def state_cloudflare_zone_id(state):
1151
1163
  for resource in state.get("resources", []) or []:
1152
1164
  if resource.get("type") != "cloudflare_record":
@@ -1829,10 +1841,6 @@ def managed_app_terraform_overrides(payload, stage, account_id, current_outputs,
1829
1841
  if not isinstance(manifest_images, dict):
1830
1842
  manifest_images = {}
1831
1843
  validate_managed_app_desired_state(payload, desired_config, manifest_images)
1832
- cognee_guardrails = state_terraform_data_input(
1833
- current_state,
1834
- "cognee_configuration_guardrails",
1835
- )
1836
1844
  twenty_guardrails = state_terraform_data_input(
1837
1845
  current_state,
1838
1846
  "twenty_configuration_guardrails",
@@ -1843,81 +1851,6 @@ def managed_app_terraform_overrides(payload, stage, account_id, current_outputs,
1843
1851
  )
1844
1852
 
1845
1853
  overrides = {
1846
- "enable_cognee": bool(state_output(current_outputs, "cognee_enabled", False)),
1847
- "cognee_image_uri": cognee_guardrails.get("cognee_image_uri", ""),
1848
- "cognee_db_username": cognee_guardrails.get("cognee_db_username", "thinkwork_cognee"),
1849
- "cognee_db_name": cognee_guardrails.get("cognee_db_name", "thinkwork_cognee"),
1850
- "cognee_db_password_secret_arn": cognee_guardrails.get(
1851
- "cognee_db_password_secret_arn",
1852
- "",
1853
- ),
1854
- "cognee_backend_mode": cognee_guardrails.get("cognee_backend_mode", "dogfood"),
1855
- "cognee_desired_count": cognee_guardrails.get("cognee_desired_count", 1),
1856
- "cognee_brain_tenant_id": state_output(current_outputs, "cognee_brain_tenant_id", ""),
1857
- "cognee_brain_instance_key": state_output(
1858
- current_outputs,
1859
- "cognee_brain_instance_key",
1860
- "",
1861
- ),
1862
- "cognee_brain_storage_tier": cognee_guardrails.get(
1863
- "cognee_brain_storage_tier",
1864
- state_output(current_outputs, "cognee_brain_storage_tier", "default"),
1865
- ),
1866
- "cognee_brain_s3_artifact_root": state_output(
1867
- current_outputs,
1868
- "cognee_s3_artifact_root",
1869
- "",
1870
- ),
1871
- "cognee_brain_s3_manifest_root": state_output(
1872
- current_outputs,
1873
- "cognee_s3_manifest_root",
1874
- "",
1875
- ),
1876
- "cognee_brain_s3_vault_projection_root": state_output(
1877
- current_outputs,
1878
- "cognee_s3_vault_projection_root",
1879
- "",
1880
- ),
1881
- "cognee_private_substrate_mode": bool(
1882
- state_output(current_outputs, "cognee_private_substrate_mode", True)
1883
- ),
1884
- "cognee_llm_provider": cognee_guardrails.get("cognee_llm_provider", "bedrock"),
1885
- "cognee_llm_model": "bedrock/moonshotai.kimi-k2.5",
1886
- "cognee_embedding_provider": cognee_guardrails.get(
1887
- "cognee_embedding_provider",
1888
- "bedrock",
1889
- ),
1890
- "cognee_embedding_model": state_output(
1891
- current_outputs,
1892
- "cognee_embedding_model",
1893
- "amazon.titan-embed-text-v2:0",
1894
- ),
1895
- "cognee_embedding_dimensions": state_output(
1896
- current_outputs,
1897
- "cognee_embedding_dimensions",
1898
- 1024,
1899
- ),
1900
- "cognee_vector_db_provider": state_output(
1901
- current_outputs,
1902
- "cognee_vector_db_provider",
1903
- "lancedb",
1904
- ),
1905
- "cognee_graph_database_provider": state_output(
1906
- current_outputs,
1907
- "cognee_graph_database_provider",
1908
- "kuzu",
1909
- ),
1910
- "cognee_neptune_graph_id": state_output(current_outputs, "cognee_neptune_graph_id", ""),
1911
- "cognee_neptune_endpoint": state_output(current_outputs, "cognee_neptune_endpoint", ""),
1912
- "cognee_production_posture": state_output(
1913
- current_outputs,
1914
- "cognee_production_posture",
1915
- "",
1916
- ),
1917
- "cognee_bedrock_model_resource_arns": cognee_guardrails.get(
1918
- "cognee_bedrock_model_resources",
1919
- [],
1920
- ),
1921
1854
  "twenty_provisioned": bool(state_output(current_outputs, "twenty_provisioned", False)),
1922
1855
  "twenty_runtime_enabled": bool(
1923
1856
  state_output(current_outputs, "twenty_runtime_enabled", False)
@@ -2012,6 +1945,35 @@ def managed_app_terraform_overrides(payload, stage, account_id, current_outputs,
2012
1945
  "n8n_dns_name": "",
2013
1946
  }
2014
1947
 
1948
+ # Foundation updates must not tear down n8n's managed certificate/DNS:
1949
+ # the guardrail records the managed cert's own ARN, which (combined with
1950
+ # a blank n8n_domain) flips n8n_managed_certificate_enabled off and
1951
+ # plans a destroy of a cert still attached to the n8n ALB (observed:
1952
+ # McPherson update to v0.1.0-canary.314). When state shows the root
1953
+ # managed cert, reproduce the install-time inputs instead.
1954
+ managed_n8n_cert = state_root_resource_attributes(
1955
+ current_state, "aws_acm_certificate", "n8n"
1956
+ )
1957
+ if managed_n8n_cert:
1958
+ overrides["n8n_domain"] = (
1959
+ managed_n8n_cert.get("domain_name")
1960
+ or url_hostname(overrides["n8n_public_url"])
1961
+ or ""
1962
+ )
1963
+ overrides["n8n_certificate_arn"] = ""
1964
+ foundation_n8n_dns_name = overrides["n8n_domain"] or url_hostname(
1965
+ overrides["n8n_public_url"]
1966
+ )
1967
+ if overrides["n8n_provisioned"] and foundation_n8n_dns_name:
1968
+ # State-derived zone lookup goes blank once the cloudflare_record
1969
+ # resources are absent (e.g. a prior partial destroy) — fall back
1970
+ # to the Cloudflare API resolver the n8n install path uses.
1971
+ overrides["cloudflare_zone_id"] = overrides[
1972
+ "cloudflare_zone_id"
1973
+ ] or cloudflare_zone_id_for_hostname(stage, foundation_n8n_dns_name)
1974
+ overrides["n8n_dns_name"] = foundation_n8n_dns_name
1975
+ overrides["n8n_dns_enabled"] = bool(overrides["cloudflare_zone_id"])
1976
+
2015
1977
  if app_key == "n8n":
2016
1978
  provisioned = operation != "DESTROY"
2017
1979
  overrides.update(
@@ -2932,6 +2894,31 @@ def pg_literal(value):
2932
2894
  return "'" + value.replace("'", "''") + "'"
2933
2895
 
2934
2896
 
2897
+ def ensure_hindsight_database(database_url, vars_json):
2898
+ """THINK-220: the dedicated Hindsight database is bootstrap SQL — Terraform
2899
+ cannot CREATE DATABASE inside the cluster. Runs post-apply; the Hindsight
2900
+ service may crash-loop briefly on a first enablement until this creates
2901
+ the database, then ECS stabilizes on its own. Vanilla boot migrations
2902
+ (RUN_MIGRATIONS_ON_STARTUP) build the schema, including the maintenance
2903
+ discovery functions the repair migration installs on base-schema runs."""
2904
+ db_name = (vars_json.get("hindsight_database_name") or "").strip()
2905
+ if not db_name:
2906
+ return
2907
+ if not re.fullmatch(r"[a-z][a-z0-9_]*", db_name):
2908
+ raise RuntimeError(f"invalid hindsight_database_name: {db_name!r}")
2909
+ admin_url = re.sub(r"/[^/?]+(\?|$)", r"/postgres\1", database_url, count=1)
2910
+ exists = psql_output(
2911
+ admin_url,
2912
+ f"SELECT 1 FROM pg_database WHERE datname = '{db_name}'",
2913
+ ).strip()
2914
+ if not exists:
2915
+ print(f"[hindsight] creating database {db_name}")
2916
+ psql(admin_url, sql=f'CREATE DATABASE "{db_name}"')
2917
+ hindsight_url = re.sub(r"/[^/?]+(\?|$)", f"/{db_name}\\1", database_url, count=1)
2918
+ psql(hindsight_url, sql="CREATE EXTENSION IF NOT EXISTS vector;")
2919
+ print(f"[hindsight] database {db_name} ready (pgvector ensured)")
2920
+
2921
+
2935
2922
  def push_database_schema(outputs_path, vars_json):
2936
2923
  outputs = json.loads(outputs_path.read_text(encoding="utf-8"))
2937
2924
  checkout_source(
@@ -2940,6 +2927,7 @@ def push_database_schema(outputs_path, vars_json):
2940
2927
  os.environ.get("THINKWORK_RELEASE_VERSION", "main"),
2941
2928
  )
2942
2929
  database_url = database_url_from_outputs(outputs)
2930
+ ensure_hindsight_database(database_url, vars_json)
2943
2931
  fresh = not psql_output(database_url, "SELECT to_regclass('public.tenants')").strip()
2944
2932
  ledger_present = bool(
2945
2933
  psql_output(database_url, "SELECT to_regclass('public.platform_schema_migrations')").strip()
@@ -3065,6 +3053,16 @@ def write_runner_files(payload, runner_secrets):
3065
3053
  "enableHindsight",
3066
3054
  default=False,
3067
3055
  ),
3056
+ # THINK-220: dedicated Hindsight database on the stage cluster.
3057
+ # Empty keeps the legacy hindsight-schema layout; set (e.g.
3058
+ # "thinkwork_hindsight") points the Hindsight service and platform
3059
+ # readers at that database's public schema, where upstream's
3060
+ # maintenance discovery actually runs.
3061
+ "hindsight_database_name": safe_get(
3062
+ reviewed_payload,
3063
+ "hindsightDatabaseName",
3064
+ default="",
3065
+ ),
3068
3066
  "platform_operator_emails": safe_get(
3069
3067
  runner_secrets,
3070
3068
  "adminEmail",
@@ -3264,6 +3262,11 @@ variable "enable_hindsight" {{
3264
3262
  type = bool
3265
3263
  }}
3266
3264
 
3265
+ variable "hindsight_database_name" {{
3266
+ type = string
3267
+ default = ""
3268
+ }}
3269
+
3267
3270
  variable "platform_operator_emails" {{
3268
3271
  type = string
3269
3272
  }}
@@ -3365,106 +3368,6 @@ variable "deployment_control_plane_create_secret_placeholders" {{
3365
3368
  type = bool
3366
3369
  }}
3367
3370
 
3368
- variable "enable_cognee" {{
3369
- type = bool
3370
- }}
3371
-
3372
- variable "cognee_image_uri" {{
3373
- type = string
3374
- }}
3375
-
3376
- variable "cognee_db_username" {{
3377
- type = string
3378
- }}
3379
-
3380
- variable "cognee_db_name" {{
3381
- type = string
3382
- }}
3383
-
3384
- variable "cognee_db_password_secret_arn" {{
3385
- type = string
3386
- }}
3387
-
3388
- variable "cognee_backend_mode" {{
3389
- type = string
3390
- }}
3391
-
3392
- variable "cognee_desired_count" {{
3393
- type = number
3394
- }}
3395
-
3396
- variable "cognee_brain_tenant_id" {{
3397
- type = string
3398
- }}
3399
-
3400
- variable "cognee_brain_instance_key" {{
3401
- type = string
3402
- }}
3403
-
3404
- variable "cognee_brain_storage_tier" {{
3405
- type = string
3406
- }}
3407
-
3408
- variable "cognee_brain_s3_artifact_root" {{
3409
- type = string
3410
- }}
3411
-
3412
- variable "cognee_brain_s3_manifest_root" {{
3413
- type = string
3414
- }}
3415
-
3416
- variable "cognee_brain_s3_vault_projection_root" {{
3417
- type = string
3418
- }}
3419
-
3420
- variable "cognee_private_substrate_mode" {{
3421
- type = bool
3422
- }}
3423
-
3424
- variable "cognee_llm_provider" {{
3425
- type = string
3426
- }}
3427
-
3428
- variable "cognee_llm_model" {{
3429
- type = string
3430
- }}
3431
-
3432
- variable "cognee_embedding_provider" {{
3433
- type = string
3434
- }}
3435
-
3436
- variable "cognee_embedding_model" {{
3437
- type = string
3438
- }}
3439
-
3440
- variable "cognee_embedding_dimensions" {{
3441
- type = number
3442
- }}
3443
-
3444
- variable "cognee_vector_db_provider" {{
3445
- type = string
3446
- }}
3447
-
3448
- variable "cognee_graph_database_provider" {{
3449
- type = string
3450
- }}
3451
-
3452
- variable "cognee_neptune_graph_id" {{
3453
- type = string
3454
- }}
3455
-
3456
- variable "cognee_neptune_endpoint" {{
3457
- type = string
3458
- }}
3459
-
3460
- variable "cognee_production_posture" {{
3461
- type = string
3462
- }}
3463
-
3464
- variable "cognee_bedrock_model_resource_arns" {{
3465
- type = list(string)
3466
- }}
3467
-
3468
3371
  variable "enable_deployment_control_plane" {{
3469
3372
  type = bool
3470
3373
  }}
@@ -3752,33 +3655,9 @@ module "thinkwork" {{
3752
3655
  agentcore_pi_source_image_uri = var.agentcore_pi_source_image_uri
3753
3656
 
3754
3657
  enable_hindsight = var.enable_hindsight
3658
+ hindsight_database_name = var.hindsight_database_name
3755
3659
  enable_workspace_orchestration = true
3756
3660
 
3757
- enable_cognee = var.enable_cognee
3758
- cognee_image_uri = var.cognee_image_uri
3759
- cognee_db_username = var.cognee_db_username
3760
- cognee_db_name = var.cognee_db_name
3761
- cognee_db_password_secret_arn = var.cognee_db_password_secret_arn
3762
- cognee_backend_mode = var.cognee_backend_mode
3763
- cognee_desired_count = var.cognee_desired_count
3764
- cognee_brain_tenant_id = var.cognee_brain_tenant_id
3765
- cognee_brain_instance_key = var.cognee_brain_instance_key
3766
- cognee_brain_storage_tier = var.cognee_brain_storage_tier
3767
- cognee_brain_s3_artifact_root = var.cognee_brain_s3_artifact_root
3768
- cognee_brain_s3_manifest_root = var.cognee_brain_s3_manifest_root
3769
- cognee_brain_s3_vault_projection_root = var.cognee_brain_s3_vault_projection_root
3770
- cognee_private_substrate_mode = var.cognee_private_substrate_mode
3771
- cognee_llm_provider = var.cognee_llm_provider
3772
- cognee_llm_model = var.cognee_llm_model
3773
- cognee_embedding_provider = var.cognee_embedding_provider
3774
- cognee_embedding_model = var.cognee_embedding_model
3775
- cognee_embedding_dimensions = var.cognee_embedding_dimensions
3776
- cognee_vector_db_provider = var.cognee_vector_db_provider
3777
- cognee_graph_database_provider = var.cognee_graph_database_provider
3778
- cognee_neptune_graph_id = var.cognee_neptune_graph_id
3779
- cognee_neptune_endpoint = var.cognee_neptune_endpoint
3780
- cognee_production_posture = var.cognee_production_posture
3781
- cognee_bedrock_model_resource_arns = var.cognee_bedrock_model_resource_arns
3782
3661
  twenty_provisioned = var.twenty_provisioned
3783
3662
  twenty_runtime_enabled = var.twenty_runtime_enabled
3784
3663
  twenty_image_uri = var.twenty_image_uri
@@ -3873,7 +3752,6 @@ output "admin_client_id" {{ value = module.thinkwork.admin_client_id }}
3873
3752
  output "docs_bucket_name" {{ value = module.thinkwork.docs_bucket_name }}
3874
3753
  output "docs_distribution_id" {{ value = module.thinkwork.docs_distribution_id }}
3875
3754
  output "docs_distribution_domain" {{ value = module.thinkwork.docs_distribution_domain }}
3876
- output "cognee_enabled" {{ value = module.thinkwork.cognee_enabled }}
3877
3755
  output "twenty_provisioned" {{ value = module.thinkwork.twenty_provisioned }}
3878
3756
  output "twenty_runtime_enabled" {{ value = module.thinkwork.twenty_runtime_enabled }}
3879
3757
  output "twenty_url" {{ value = module.thinkwork.twenty_url }}
@@ -4508,7 +4386,7 @@ def write_evidence(status, vars_json=None, terraform_exit_code=None, error=None)
4508
4386
  "environmentName": vars_json.get("stage"),
4509
4387
  "awsAccountId": vars_json.get("account_id"),
4510
4388
  "awsRegion": vars_json.get("region"),
4511
- "managedApps": {"cognee": False, "twenty": False},
4389
+ "managedApps": {"twenty": False},
4512
4390
  "codebuildBuildId": os.environ.get("CODEBUILD_BUILD_ID"),
4513
4391
  "terraformExitCode": terraform_exit_code,
4514
4392
  "startedAt": STARTED_AT,