Auto Lambda Env
auto-lambda-env
Set environment variables on AI automation Lambda functions. Interactively collects secrets and operational values, then applies them via AWS CLI. Reads function names and pre-filled values from .ai/automation/infra.json.
SKILL.md
Full skill instructions
You set Lambda environment variables for the AI automation agents. There are 2 consolidated router Lambda functions: WI Router (work-item webhook events) and PR Router (pull-request webhook events). Values are collected interactively (secrets are never written to files). Applies all variables in a single aws lambda update-function-configuration call per function.
0. Prerequisites
Read .ai/automation/infra.json. Check automationProfile:
- If
consumer(or legacypr-only/pr-delegation): "This repo uses the consumer profile — Lambda environment variables are managed by the hub project. Do NOT modify Lambda env vars from this repo." STOP.
source .ai/lib/audit.sh
export AUDIT_LOG_PREFIX=infra
Pre-fill these from infra.json (don't ask for values already known):
DYNAMODB_DEDUPE_TABLE←storage.dynamodb.dedupe.tableNameDYNAMODB_RATE_LIMIT_TABLE←storage.dynamodb.rateLimits.tableNameSQS_DLQ_URL←storage.sqs.dlq.queueUrlADO_DOD_PIPELINE_ID←pipelines.dod.id(WI Router)ADO_QA_PIPELINE_ID←pipelines.qa.id(WI Router)ADO_DEV_PIPELINE_ID←pipelines.devagent.id(WI Router)ADO_DOC_PIPELINE_ID←pipelines.docagent.id(WI Router)ADO_ESTIMATION_PIPELINE_ID←pipelines.estimation.id(WI Router)ADO_PR_ANSWER_PIPELINE_MAP← JSON map of repo→pipeline-id (PR Router)ADO_ORG_URL←adoOrg(PR Router)MY_IDENTITIES← from infra.json if set (PR Router)
1. Collect Secrets
Ask these one at a time — these cannot be pre-filled from infra.json:
ADO Personal Access Token? (secret — Lambda env var
ADO_PAT) This PAT needs: Work Items read, Code read, Pull Requests read+contribute, Project read.
Webhook basic auth username? (Lambda env var
BASIC_USER) Example:automation-webhook. Must match what you'll set in ADO Service Hooks.
Webhook basic auth password? (secret — Lambda env var
BASIC_PASS) Suggest generating:openssl rand -base64 24
<!-- DoR has NO WI-Router tag — it is triggered by an Azure-native @kai-dor comment hook (dx-dor.trigger-token), configured via /auto-webhooks 2d. -->Webhook secret? (secret — Lambda env var
WEBHOOK_SECRET) Suggest generating:openssl rand -base64 32
<!-- BugFix has NO WI-Router tag — it is triggered by an Azure-native @kai-bugfix comment hook (dx-bug-all.recovery.trigger-token), configured via /auto-webhooks 2c. -->DoD trigger tag? (Lambda env var
TAG_GATE_DOD— WI Router) Default:KAI-DOD-AUTOMATION
QA trigger tag? (Lambda env var
TAG_GATE_QA— WI Router) Default:KAI-QA-AUTOMATION
DevAgent trigger tag? (Lambda env var
TAG_GATE_DEV— WI Router) Default:KAI-DEV-AUTOMATION
DOCAgent trigger tag? (Lambda env var
TAG_GATE_DOC— WI Router) Default:KAI-DOC-AUTOMATION
Estimation trigger tag? (Lambda env var
TAG_GATE_ESTIMATION— WI Router) Default:KAI-ESTIMATION-AUTOMATION
SimpleAgent has no trigger tag here. SimpleAgent is not Lambda-routed — it uses an Azure-native Service Hook (
@kai-simplecomment) configured by/auto-webhooks. Do not ask for aTAG_GATE_SIMPLE.
2. Apply to WI Router Lambda
The WI Router (<PREFIX>-WI-Router) handles tagged work-item webhook events and routes to the appropriate pipeline (DoD, QA, DevAgent, DOCAgent, Estimation) based on tag gates. DoR and BugFix are NOT routed here — they use Azure-native @kai-dor / @kai-bugfix comment hooks (no Lambda).
WI_ROUTER_FUNC=$(python3 -c "import json; print(json.load(open('.ai/automation/infra.json'))['lambdas']['wi-router']['functionName'])")
REGION=$(python3 -c "import json; print(json.load(open('.ai/automation/infra.json'))['region'])")
aws_lambda_config "$WI_ROUTER_FUNC" \
--environment "Variables={
ADO_PAT=<secret>,
BASIC_USER=<user>,
BASIC_PASS=<secret>,
WEBHOOK_SECRET=<secret>,
ADO_DOD_PIPELINE_ID=<pipeline-id>,
ADO_QA_PIPELINE_ID=<pipeline-id>,
ADO_DEV_PIPELINE_ID=<pipeline-id>,
ADO_DOC_PIPELINE_ID=<pipeline-id>,
ADO_ESTIMATION_PIPELINE_ID=<pipeline-id>,
TAG_GATE_DOD=<tag>,
TAG_GATE_QA=<tag>,
TAG_GATE_DEV=<tag>,
TAG_GATE_DOC=<tag>,
TAG_GATE_ESTIMATION=<tag>,
DYNAMODB_DEDUPE_TABLE=<table>,
DYNAMODB_RATE_LIMIT_TABLE=<table>,
SQS_DLQ_URL=<url>
}" \
--region "$REGION"
SimpleAgent routing (WI Router tag map)
The WI Router routes tagged work-item events to pipelines via a tag-to-pipeline-ID lookup. After this skill runs, the WI Router's effective routing table includes:
{
"KAI-DOD-AUTOMATION": "<dod-pipeline-id>",
"KAI-QA-AUTOMATION": "<qa-pipeline-id>",
"KAI-DEV-AUTOMATION": "<devagent-pipeline-id>",
"KAI-DOC-AUTOMATION": "<docagent-pipeline-id>",
"KAI-ESTIMATION-AUTOMATION": "<estimation-pipeline-id>"
}
SimpleAgent is NOT Lambda-routed
SimpleAgent is not part of the WI Router (its AGENTS array has no simple entry). Its pipeline (ado-cli-simple.yml) is triggered by an Azure-native Service Hook — a comment containing @kai-simple → an Incoming WebHook service connection → the pipeline's resources.webhooks listener (configured by /auto-webhooks, not here). No TAG_GATE_SIMPLE / ADO_SIMPLE_PIPELINE_ID env vars are needed. SimpleAgent reads its own config from pipeline variables (set by /auto-pipelines — AEM_QA_URL, AEM_QA_USER, AEM_QA_PASSWORD, MCP version pins).
3. Apply to PR Router Lambda (merge-safe)
The PR Router (<PREFIX>-PR-Router) handles all pull-request webhook events. It uses ADO_PR_ANSWER_PIPELINE_MAP (JSON map of repo→pipeline-id) for routing PR answer events to the correct pipeline.
PR_ROUTER_FUNC=$(python3 -c "import json; print(json.load(open('.ai/automation/infra.json'))['lambdas']['pr-router']['functionName'])")
aws_lambda_config "$PR_ROUTER_FUNC" \
--environment "Variables={
ADO_PAT=<secret>,
BASIC_USER=<user>,
BASIC_PASS=<secret>,
WEBHOOK_SECRET=<secret>,
ADO_ORG_URL=<adoOrg>,
ADO_PR_ANSWER_PIPELINE_MAP=<json-map>,
MY_IDENTITIES=<identities>,
DYNAMODB_DEDUPE_TABLE=<table>,
DYNAMODB_RATE_LIMIT_TABLE=<table>,
SQS_DLQ_URL=<url>
}" \
--region "$REGION"
Important: aws lambda update-function-configuration replaces ALL env vars. Always read current env vars first and merge changes, preserving existing secrets and table names.
4. Verify
# List env var KEYS only (not values — never print secrets)
for FUNC in "$WI_ROUTER_FUNC" "$PR_ROUTER_FUNC"; do
echo "=== $FUNC ==="
aws lambda get-function-configuration \
--function-name "$FUNC" --region "$REGION" \
--query 'Environment.Variables' --output json | python3 -c "
import sys, json
d = json.load(sys.stdin)
for k in sorted(d.keys()):
print(f' {k}: [set]')
"
done
5. Summary Report
## Lambda Environment Variables Set
| Variable | WI Router | PR Router |
|----------|-----------|-----------|
| ADO_PAT | ✓ | ✓ |
| BASIC_USER | ✓ | ✓ |
| BASIC_PASS | ✓ | ✓ |
| WEBHOOK_SECRET | ✓ | ✓ |
| ADO_DOD_PIPELINE_ID | ✓ | — |
| ADO_QA_PIPELINE_ID | ✓ | — |
| ADO_DEV_PIPELINE_ID | ✓ | — |
| ADO_DOC_PIPELINE_ID | ✓ | — |
| ADO_ESTIMATION_PIPELINE_ID | ✓ | — |
| ADO_PR_ANSWER_PIPELINE_MAP | — | ✓ |
| ADO_ORG_URL | — | ✓ |
| MY_IDENTITIES | — | ✓ |
| TAG_GATE_DOD | ✓ | — |
| TAG_GATE_QA | ✓ | — |
| TAG_GATE_DEV | ✓ | — |
| TAG_GATE_DOC | ✓ | — |
| TAG_GATE_ESTIMATION | ✓ | — |
| DYNAMODB_DEDUPE_TABLE | ✓ | ✓ |
| DYNAMODB_RATE_LIMIT_TABLE | ✓ | ✓ |
| SQS_DLQ_URL | ✓ | ✓ |
**Audit log:** `.ai/logs/infra.<week>.jsonl`
### Next step
`/auto-webhooks` — Configure ADO service hooks
Examples
-
/auto-lambda-env— Readsinfra.jsonfor function names and pre-filled values (DynamoDB table names, SQS URL, S3 bucket). Asks interactively for secrets (ADO PAT, Anthropic API key). Merges with existing env vars and applies to both WI-Router and PR-Router Lambda functions. -
/auto-lambda-env(adding a consumer repo's pipeline ID) — Reads current env vars from WI-Router Lambda, adds a new entry toADO_PR_ANSWER_PIPELINE_MAPfor the consumer repo's PR Answer pipeline. Preserves all existing values and applies the merged configuration. -
/auto-lambda-env(updating expired ADO PAT) — Asks for the new ADO PAT value. Reads current env vars, replaces only theADO_PATvalue, and applies to both Lambda functions. All other env vars remain unchanged.
Troubleshooting
-
"update-function-configuration replaces ALL env vars" warning Cause: AWS Lambda's update API replaces the entire environment variable set, not individual values. Fix: The skill always reads current env vars first and merges changes. If env vars are missing after an update, re-run
/auto-lambda-envto restore them. Check the audit log for what was applied. -
Pipeline ID mismatch warning Cause: An existing
ADO_*_PIPELINE_IDvalue differs from the new value being set. Fix: Review the warning message — it shows old vs new values. If the pipeline was re-created, confirm the update. If the IDs should match, check/auto-pipelinesoutput for the correct ID. -
Secret values appearing in logs Cause: This should not happen — the skill only logs env var keys, never values. Fix: Check that you're using
/auto-lambda-env(which uses audit wrappers) and not rawaws lambda update-function-configurationcommands. The audit log records the operation but not secret values.
Rules
- Always source audit.sh first —
aws_lambda_configis an audit wrapper - Never print secret values — only list env var keys when verifying
- Never write secrets to infra.json — only non-secret pre-filled values come from infra.json
- Ask one question at a time — never combine
- Derive pre-filled values from infra.json — minimise questions to user
- Read before write —
update-function-configurationreplaces ALL env vars. Always read current env vars first and merge changes - Warn on pipeline ID overwrite — if an existing
ADO_*_PIPELINE_IDdiffers from the new value, warn the user: "Pipeline ID will change from <old> to <new>. Proceed?" Skip if values match.
