Permission: READ by default
Default is inspect-only. Do not mutate cluster / ArgoCD / DB unless the user explicitly asks for that action in the current turn.
Default allowed: kubectl get/describe/logs/top/auth can-i, read secrets for diagnosis, Application get/history/diff via kubectl, psql SELECT / \d / \dt / \di with LIMIT, aws sts / eks update-kubeconfig / sso login for local auth, OpenSearch Discover read/search via browser session (see logs section).
Mutating (only if user explicitly asks): kubectl apply|create|delete|patch|replace|rollout|scale|exec, argocd app sync|rollback|delete|prune, Secret/ConfigMap edits, SQL write/DDL, pod restarts. If not explicitly requested — refuse and stay read-only.
When to Use
Use when the user asks to inspect Core SIT / core-neo live state: pod logs, OpenSearch historical logs, restarts, ArgoCD app sync/health/history, deployment image/tag, ExternalSecret status, or Postgres connection settings for a Neo core service (payment, account, transaction, …). Triggers: ดู log core sit, core-neo, argocd payment, หา postgres, debug บน SIT, ดู secret payment, opensearch payment, search log sit. Not for Auxiliary cluster — use neo-aux-sit. Not for mutating cluster state unless the user explicitly asks.
Local auth (required env)
No AWS profile name is baked into this skill. Before any aws / eks call:
- Read env
NEO_CORE_AWS_PROFILE.
- If unset/empty → stop. Tell the user to export it to their local profile name, e.g.
export NEO_CORE_AWS_PROFILE=<profile-in-aws-config>
Optional helper file: copy sit.env.example → keep outside git / shell rc.
Do not invent a default profile name.
- Resolve region from that profile (do not hardcode region in commands when config has it):
REGION=$(aws configure get region --profile "$NEO_CORE_AWS_PROFILE")
If empty → stop and ask user to set region (or sso_region workflow) on that profile in ~/.aws/config.
- Optional checks from the same profile (informational):
aws configure get sso_role_name --profile "$NEO_CORE_AWS_PROFILE"
Expect org role CoreIntegrationAccess (not SystemsManagerAccess).
Use "$NEO_CORE_AWS_PROFILE" and "$REGION" in every aws command below. Shorthand in this doc: $PROFILE / $REGION.
Procedure
- Identity map (org SIT — shared team defaults):
- Env: Core SIT (Neo core)
- AWS account (expect): 986629373331 — confirm live via sts, do not assume
- EKS cluster:
core-eks-hbq5y8 (legacy name eks-cluster-hbq5y8 is dead)
- kubectl context alias:
core-neo
- Workload namespace:
core-systems
- Argo Application namespace:
argocd
- Argo flavor: AWS EKS Capability for Argo CD (managed). No in-cluster argocd-server. Prefer kubectl Application CRDs over the argocd CLI.
- Connect / heal access (every session, before queries):
- Require
$PROFILE / $REGION per Local auth above.
aws sts get-caller-identity --profile "$PROFILE" — expect account 986629373331 and ARN role CoreIntegrationAccess. On Forbidden/expired: aws sso login --profile "$PROFILE" (user approves browser).
- If context missing / NXDOMAIN / ResourceNotFound:
aws eks update-kubeconfig --name core-eks-hbq5y8 --region "$REGION" --profile "$PROFILE" --alias core-neo
- Smoke:
kubectl --context core-neo get ns && kubectl --context core-neo get applications -n argocd
Always pass --context core-neo. Never assume current-context is core.
- Name mapping (spoken → deploy → Argo app → secret in core-systems):
- payment / payment-gateway → deploy payment → Application payment-service → secret payment-secret
- account → account → account-service → account-secret
- transaction → transaction → transaction-service → transaction-secret
- transaction-consumer → transaction-consumer → transaction-consumer-service → transaction-consumer-secret
- product → product → product-service → product-secret
- authentication → authentication → authentication-service → authentication-secret
- customer / customer-api → customer-api → customer-service → customer-api-secret (+ customer-consumer-secret)
- customer-profiling → customer-profiling → customer-profiling-service → customer-profiling-secret
- customer-settings → customer-settings → customer-settings-service → customer-settings-secret
- bff / backend-for-frontend → backend-for-frontend → backend-for-frontend-service → backend-for-frontend-secret
- bot → bot → bot-service → bot-secret
- wai-adapter → wai-adapter → wai-adapter-service → wai-adapter-secret
- as400adapter → as400adapter → as400adapter-service → check secrets list
Fuzzy when unsure:
kubectl --context core-neo get secrets,deploy -n core-systems then use the grep tool on the output for FRAGMENT; also get applications -n argocd.
- Inspect logs / health (read-only). Set
CTX=core-neo NS=core-systems APP=payment (change APP):
Choose path:
| Need |
Path |
| Last ~15–30m, pod still running |
A. kubectl |
Older window / pod rotated / count by msg / multi-pod history |
B. OpenSearch — read references/opensearch-sit.md (same dir as this skill) and follow it |
A. kubectl (recent)
kubectl --context $CTX get pods -n $NS -l app=$APP -o wide
kubectl --context $CTX logs -n $NS deploy/$APP --since=15m --tail=500
kubectl --context $CTX logs -n $NS deploy/$APP --tail=200
- previous crash:
logs --previous --tail=200
- events:
kubectl --context $CTX get events -n $NS --sort-by=.lastTimestamp (filter with grep tool on output)
- running image/tag:
kubectl --context $CTX get deploy $APP -n $NS -o jsonpath='{.spec.template.spec.containers[0].image}'
- Filter: use the grep tool on the command output or a temp file. Never
kubectl … | rg or … | grep in bash (interceptor blocks them).
B. OpenSearch (historical) — full recipe in references/opensearch-sit.md:
- Host:
https://opensearch.sit.awesome-poc-th.com (Dashboards 3.5.0)
- Index:
console-sit-log; filter kubernetes_container_name = deploy/container name (e.g. payment)
- Call
POST /_dashboards/api/console/proxy?path=console-sit-log%2F_search&method=POST via sync XHR inside a browser tab (session cookies; httpOnly)
- Not proven: export cookie → shell curl
- Cold start: if SSO/login page or XHR 401/HTML login → ask user to log in, then retry
tab.evaluate must not await fetch — sync XMLHttpRequest only
- When reporting aggregates, ensure counts sum to
hits.total (do not present a capped size sample as full totals)
- ArgoCD status via kubectl (managed capability — no argocd CLI server):
- List: kubectl --context core-neo get applications -n argocd -o custom-columns=NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status,REV:.status.sync.revision
- One app JSON summary: get application ARGO_APP -n argocd -o json | jq '{sync:.status.sync.status,rev:.status.sync.revision,health:.status.health.status,images:[.status.summary.images[]?],conditions:.status.conditions,source:.spec.source}'
- History last 5: jq '.status.history[-5:] | .[] | {id,deployedAt,revision,initiatedBy}'
Default read-only. Never sync/prune/delete unless user explicitly requests a mutate.
- Postgres connection settings from service secrets:
- Secret name ≈ -secret in core-systems
- Almost always a single key config.yaml (ExternalSecrets from ClusterSecretStore aws-secrets-store), mounted at /app/config
- Shape A (most services): top-level postgres with host, port, user, database, sslmode, optional schema
- Shape B (authentication-service): database.mode + database.postgres with username instead of user
- Reuse helper (do NOT rewrite ad-hoc Python each time): resolve relative to this skill dir (parent of
SKILL.md):
scripts/pg-from-secret# SKILL_DIR = directory containing this SKILL.md
PG="$SKILL_DIR/scripts/pg-from-secret"
# summary (password hidden)
"$PG" --context core-neo --service payment
# query
"$PG" --context core-neo --service payment --psql -- \
-c "SELECT id, route, status, created_at FROM payment.audit_log ORDER BY created_at DESC LIMIT 5;"
# export env for a manual session
eval "$("$PG" --context core-neo --service payment --export)"
- Manual fallback only if the helper fails: kubectl get secret + jq keys + decode config.yaml.
- DB safety: SELECT and describe only; LIMIT rows; never write/DDL. Prefer the helper's --psql one-shot.
- ExternalSecret drift: kubectl --context core-neo get externalsecret -n core-systems; get clustersecretstore; describe the matching ExternalSecret if Ready!=True.
- Report in Thai, terminal-friendly: identity used (account/role from sts, profile name only as “from env”); Argo SYNC/HEALTH + image tag; pod READY/restarts; log evidence with timestamps (and OpenSearch msg counts when used); for DB report host/db/user/schema by default and only reveal the secret value when the user asked to connect. Never write decoded secrets into repo files, skill body, or durable memory.
Pitfalls
- Aux SIT is a different AWS account/cluster — use
neo-aux-sit + NEO_AUX_AWS_PROFILE, not this skill’s profile.
- Stale kubeconfig cluster name
eks-cluster-hbq5y8 causes ResourceNotFound or NXDOMAIN — use core-eks-hbq5y8.
- SSO role SystemsManagerAccess yields ForbiddenException; need CoreIntegrationAccess on the profile.
- Missing
NEO_CORE_AWS_PROFILE → fail fast; never guess a profile name.
- argocd CLI 'server address unspecified' is expected on Core; use kubectl Application CRDs.
- Secret stores settings inside config.yaml, not discrete DB_* keys — grepping only for bare keys misses it.
- authentication-service nests under database.postgres and uses username not user.
- Extracted RDS settings do not imply laptop connectivity — private network.
- Read-only by default: no apply/delete/sync/secret edits unless user explicitly asks.
- Never persist decoded credentials into git, skills, or memory stores.
- OpenSearch: do not pipe kubectl to
rg; do not assume curl+cookie works; do not await fetch in tab.evaluate; ask user on SSO cold start.
- OpenSearch
log field is a JSON string — parse client-side for msg/level.
Verification
NEO_CORE_AWS_PROFILE set; aws configure get region --profile "$PROFILE" non-empty.
aws sts get-caller-identity --profile "$PROFILE" → account 986629373331 + CoreIntegrationAccess.
- kubectl --context core-neo get ns lists core-systems and argocd.
- kubectl --context core-neo get applications -n argocd lists core apps (e.g. payment-service).
- For a named service: deploy in core-systems, logs readable, matching *-secret has config.yaml containing a postgres (or database.postgres) block.
- When using OpenSearch: browser session authenticated; search XHR status 200; reported msg counts sum to
hits.total.
1---2name: neo-core-sit3description: Connect to Core SIT (kubectl + managed ArgoCD) to inspect logs (kubectl + OpenSearch), deploy status, and locate Postgres connection settings inside service K8s secrets for debugging.4---5## Permission: READ by default67Default is **inspect-only**. Do not mutate cluster / ArgoCD / DB unless the user **explicitly** asks for that action in the current turn.89**Default allowed:** `kubectl get/describe/logs/top/auth can-i`, read secrets for diagnosis, Application get/history/diff via kubectl, `psql` SELECT / \\d / \\dt / \\di with LIMIT, `aws sts` / `eks update-kubeconfig` / `sso login` for local auth, OpenSearch Discover **read/search** via browser session (see logs section).1011**Mutating (only if user explicitly asks):** `kubectl apply|create|delete|patch|replace|rollout|scale|exec`, `argocd app sync|rollback|delete|prune`, Secret/ConfigMap edits, SQL write/DDL, pod restarts. If not explicitly requested — refuse and stay read-only.1213## When to Use14Use when the user asks to inspect Core SIT / core-neo live state: pod logs, OpenSearch historical logs, restarts, ArgoCD app sync/health/history, deployment image/tag, ExternalSecret status, or Postgres connection settings for a Neo core service (payment, account, transaction, …). Triggers: ดู log core sit, core-neo, argocd payment, หา postgres, debug บน SIT, ดู secret payment, opensearch payment, search log sit. Not for Auxiliary cluster — use `neo-aux-sit`. Not for mutating cluster state unless the user explicitly asks.1516## Local auth (required env)1718**No AWS profile name is baked into this skill.** Before any `aws` / `eks` call:19201. Read env `NEO_CORE_AWS_PROFILE`.212. If unset/empty → **stop**. Tell the user to export it to their local profile name, e.g. 22 `export NEO_CORE_AWS_PROFILE=<profile-in-aws-config>` 23 Optional helper file: copy `sit.env.example` → keep outside git / shell rc. 24 Do **not** invent a default profile name.253. Resolve region from that profile (do not hardcode region in commands when config has it): 26 `REGION=$(aws configure get region --profile "$NEO_CORE_AWS_PROFILE")` 27 If empty → stop and ask user to set `region` (or `sso_region` workflow) on that profile in `~/.aws/config`.284. Optional checks from the same profile (informational): 29 `aws configure get sso_role_name --profile "$NEO_CORE_AWS_PROFILE"` 30 Expect org role **CoreIntegrationAccess** (not SystemsManagerAccess).3132Use `"$NEO_CORE_AWS_PROFILE"` and `"$REGION"` in every aws command below. Shorthand in this doc: `$PROFILE` / `$REGION`.3334## Procedure351. Identity map (org SIT — shared team defaults):36- Env: Core SIT (Neo core)37- AWS account (expect): 986629373331 — confirm live via sts, do not assume38- EKS cluster: `core-eks-hbq5y8` (legacy name `eks-cluster-hbq5y8` is dead)39- kubectl context alias: `core-neo`40- Workload namespace: `core-systems`41- Argo Application namespace: `argocd`42- Argo flavor: AWS EKS Capability for Argo CD (managed). No in-cluster argocd-server. Prefer kubectl Application CRDs over the argocd CLI.432. Connect / heal access (every session, before queries):441) Require `$PROFILE` / `$REGION` per **Local auth** above.452) `aws sts get-caller-identity --profile "$PROFILE"` — expect account **986629373331** and ARN role **CoreIntegrationAccess**. On Forbidden/expired: `aws sso login --profile "$PROFILE"` (user approves browser).463) If context missing / NXDOMAIN / ResourceNotFound: 47 `aws eks update-kubeconfig --name core-eks-hbq5y8 --region "$REGION" --profile "$PROFILE" --alias core-neo`484) Smoke: `kubectl --context core-neo get ns` && `kubectl --context core-neo get applications -n argocd` 49Always pass `--context core-neo`. Never assume current-context is core.503. Name mapping (spoken → deploy → Argo app → secret in core-systems):51- payment / payment-gateway → deploy payment → Application payment-service → secret payment-secret52- account → account → account-service → account-secret53- transaction → transaction → transaction-service → transaction-secret54- transaction-consumer → transaction-consumer → transaction-consumer-service → transaction-consumer-secret55- product → product → product-service → product-secret56- authentication → authentication → authentication-service → authentication-secret57- customer / customer-api → customer-api → customer-service → customer-api-secret (+ customer-consumer-secret)58- customer-profiling → customer-profiling → customer-profiling-service → customer-profiling-secret59- customer-settings → customer-settings → customer-settings-service → customer-settings-secret60- bff / backend-for-frontend → backend-for-frontend → backend-for-frontend-service → backend-for-frontend-secret61- bot → bot → bot-service → bot-secret62- wai-adapter → wai-adapter → wai-adapter-service → wai-adapter-secret63- as400adapter → as400adapter → as400adapter-service → check secrets list64Fuzzy when unsure: `kubectl --context core-neo get secrets,deploy -n core-systems` then use the **grep tool** on the output for FRAGMENT; also `get applications -n argocd`.654. Inspect logs / health (read-only). Set `CTX=core-neo` `NS=core-systems` `APP=payment` (change APP):6667**Choose path:**68| Need | Path |69|---|---|70| Last ~15–30m, pod still running | **A. kubectl** |71| Older window / pod rotated / count by `msg` / multi-pod history | **B. OpenSearch** — read `references/opensearch-sit.md` (same dir as this skill) and follow it |7273**A. kubectl (recent)**74- `kubectl --context $CTX get pods -n $NS -l app=$APP -o wide`75- `kubectl --context $CTX logs -n $NS deploy/$APP --since=15m --tail=500`76- `kubectl --context $CTX logs -n $NS deploy/$APP --tail=200`77- previous crash: `logs --previous --tail=200`78- events: `kubectl --context $CTX get events -n $NS --sort-by=.lastTimestamp` (filter with grep tool on output)79- running image/tag: `kubectl --context $CTX get deploy $APP -n $NS -o jsonpath='{.spec.template.spec.containers[0].image}'`80- **Filter:** use the **grep tool** on the command output or a temp file. **Never** `kubectl … | rg` or `… | grep` in bash (interceptor blocks them).8182**B. OpenSearch (historical)** — full recipe in `references/opensearch-sit.md`:83- Host: `https://opensearch.sit.awesome-poc-th.com` (Dashboards 3.5.0)84- Index: `console-sit-log`; filter `kubernetes_container_name` = deploy/container name (e.g. `payment`)85- Call `POST /_dashboards/api/console/proxy?path=console-sit-log%2F_search&method=POST` via **sync XHR inside a browser tab** (session cookies; httpOnly)86- **Not proven:** export cookie → shell curl87- **Cold start:** if SSO/login page or XHR 401/HTML login → ask user to log in, then retry88- `tab.evaluate` must not `await fetch` — sync `XMLHttpRequest` only89- When reporting aggregates, ensure counts sum to `hits.total` (do not present a capped `size` sample as full totals)90915. ArgoCD status via kubectl (managed capability — no argocd CLI server):92- List: kubectl --context core-neo get applications -n argocd -o custom-columns=NAME:.metadata.name,SYNC:.status.sync.status,HEALTH:.status.health.status,REV:.status.sync.revision93- One app JSON summary: get application ARGO_APP -n argocd -o json | jq '{sync:.status.sync.status,rev:.status.sync.revision,health:.status.health.status,images:[.status.summary.images[]?],conditions:.status.conditions,source:.spec.source}'94- History last 5: jq '.status.history[-5:] | .[] | {id,deployedAt,revision,initiatedBy}'95Default read-only. Never sync/prune/delete unless user explicitly requests a mutate.966. Postgres connection settings from service secrets:97- Secret name ≈ <service>-secret in core-systems98- Almost always a single key config.yaml (ExternalSecrets from ClusterSecretStore aws-secrets-store), mounted at /app/config99- Shape A (most services): top-level postgres with host, port, user, database, sslmode, optional schema100- Shape B (authentication-service): database.mode + database.postgres with username instead of user101- **Reuse helper (do NOT rewrite ad-hoc Python each time):** resolve relative to this skill dir (parent of `SKILL.md`):102 `scripts/pg-from-secret`103 ```bash104 # SKILL_DIR = directory containing this SKILL.md105 PG="$SKILL_DIR/scripts/pg-from-secret"106 # summary (password hidden)107 "$PG" --context core-neo --service payment108 # query109 "$PG" --context core-neo --service payment --psql -- \110 -c "SELECT id, route, status, created_at FROM payment.audit_log ORDER BY created_at DESC LIMIT 5;"111 # export env for a manual session112 eval "$("$PG" --context core-neo --service payment --export)"113 ```114- Manual fallback only if the helper fails: kubectl get secret + jq keys + decode config.yaml.115- DB safety: SELECT and describe only; LIMIT rows; never write/DDL. Prefer the helper's --psql one-shot.1167. ExternalSecret drift: kubectl --context core-neo get externalsecret -n core-systems; get clustersecretstore; describe the matching ExternalSecret if Ready!=True.1178. Report in Thai, terminal-friendly: identity used (account/role from sts, profile name only as “from env”); Argo SYNC/HEALTH + image tag; pod READY/restarts; log evidence with timestamps (and OpenSearch msg counts when used); for DB report host/db/user/schema by default and only reveal the secret value when the user asked to connect. Never write decoded secrets into repo files, skill body, or durable memory.118119## Pitfalls120- Aux SIT is a different AWS account/cluster — use `neo-aux-sit` + `NEO_AUX_AWS_PROFILE`, not this skill’s profile.121- Stale kubeconfig cluster name `eks-cluster-hbq5y8` causes ResourceNotFound or NXDOMAIN — use `core-eks-hbq5y8`.122- SSO role **SystemsManagerAccess** yields ForbiddenException; need **CoreIntegrationAccess** on the profile.123- Missing `NEO_CORE_AWS_PROFILE` → fail fast; never guess a profile name.124- argocd CLI 'server address unspecified' is expected on Core; use kubectl Application CRDs.125- Secret stores settings inside config.yaml, not discrete DB_* keys — grepping only for bare keys misses it.126- authentication-service nests under database.postgres and uses username not user.127- Extracted RDS settings do not imply laptop connectivity — private network.128- Read-only by default: no apply/delete/sync/secret edits unless user explicitly asks.129- Never persist decoded credentials into git, skills, or memory stores.130- OpenSearch: do not pipe kubectl to `rg`; do not assume curl+cookie works; do not await fetch in `tab.evaluate`; ask user on SSO cold start.131- OpenSearch `log` field is a JSON **string** — parse client-side for `msg`/`level`.132133## Verification1341. `NEO_CORE_AWS_PROFILE` set; `aws configure get region --profile "$PROFILE"` non-empty.1352. `aws sts get-caller-identity --profile "$PROFILE"` → account 986629373331 + CoreIntegrationAccess.1363. kubectl --context core-neo get ns lists core-systems and argocd.1374. kubectl --context core-neo get applications -n argocd lists core apps (e.g. payment-service).1385. For a named service: deploy in core-systems, logs readable, matching *-secret has config.yaml containing a postgres (or database.postgres) block.1396. When using OpenSearch: browser session authenticated; search XHR status 200; reported msg counts sum to `hits.total`.