Profiles & Credentials — shared pattern reference
Reference skill describing the credential / profile / confirmation pattern used by all claude-team-toolkit skills (azure-devops, fastlane, firebase, heroku, k6, maestro, postgres, rspec, sentry, shopify, slack, trello, etc.). Implementation lives in lib/credentials.sh and lib/confirm.sh.
Overview
All credential-bearing skills share a uniform pattern:
- INI credentials at
~/.<service>/credentials (mode 600)
- Multiple
[profile] sections per file (e.g., [default], [work], [prod])
- Resolution order:
--profile <name> flag → <SERVICE>_PROFILE env → ~/.<service>/active_profile → [default]
- Helper sourced from
lib/credentials.sh populates CTT_<KEY> env vars
- Destructive ops gated by
ctt_confirm from lib/confirm.sh
- Actions audit-logged to
~/.claude-team-toolkit/audit.log (key NAMES only, never values)
When to Use
- Authoring a NEW skill that needs per-account/per-org/per-env switching
- Modifying credential loading in an existing skill
- Adding destructive operations that need typed confirmation
- Debugging why a skill picks the wrong profile
- Reviewing security posture of a skill
When NOT to Use
- One-off scripts not meant for reuse → just hardcode and move on
- Skills with no credentials (e.g.,
react-native, rails-security) → nothing to load
- Cross-cloud unified credential systems → use the cloud's native config (
~/.aws/credentials, etc.) instead of reinventing
Profile file shape
# ~/.<service>/credentials (mode 600)
[default]
field_a = value
field_b = secret
[other-profile]
field_a = different
require_confirm = true # gate every mutation in this profile
After ctt_load_creds <service> [profile]:
CTT_PROFILE=<resolved> (e.g., default)
CTT_FIELD_A=<value>, CTT_FIELD_B=<secret> (uppercased, hyphens → underscores)
Helper API (from lib/credentials.sh)
| Function |
Purpose |
ctt_load_creds <svc> [profile] |
Resolve + load profile into CTT_* env |
ctt_save_profile <svc> <profile> <k=v>... |
Atomic INI section write |
ctt_list_profiles <svc> |
List sections, mark active with * |
ctt_use_profile <svc> <profile> |
Set active profile pointer |
ctt_active_profile <svc> |
Print resolved active profile |
ctt_remove_profile <svc> <profile> |
Refuses to remove last profile |
ctt_mask <value> |
Returns ****<last4> for safe logging |
ctt_validate_perms <file> |
Refuses non-600/400 mode (POSIX only) |
ctt_audit_log <svc> <action> |
Append timestamp + profile + action |
Confirmation API (from lib/confirm.sh)
ctt_confirm "Delete app foo?" || return 1 # y/N prompt
ctt_confirm "Drop table users?" "DELETE" || return 1 # typed phrase
ctt_warn_destructive "Action description" # noisy stderr banner
CTT_NONINTERACTIVE=1 auto-denies all confirmations (CI safety).
Common Mistakes
- Reading credentials directly with
awk instead of ctt_load_creds → bypasses perm validation
- Logging full credential values instead of
ctt_mask → secrets leak to terminal/CI logs
- Using
eval to set vars from credentials → injection risk. Helper uses printf -v for safety.
- Audit log records values not just key names → audit log itself becomes a secret store
- Confirmation without typed phrase for irreversible ops → "y" is too easy a typo
- Service name with uppercase or special chars → helper validates
^[a-z0-9-]+$
Security defaults
- Credentials directory:
chmod 700. File: chmod 600. Helper refuses to load otherwise (POSIX).
- Windows: best-effort (NTFS ACLs not enforced by helper) — document in skill's safety section.
CTT_NONINTERACTIVE=1 in CI → auto-deny destructive ops (no surprise mutations).
- Audit log at
~/.claude-team-toolkit/audit.log (mode 600). Records: timestamp, service, profile, action.
- Never write credentials into git, chat output, or any file outside
~/.<service>/credentials.
1---2name: profiles-and-credentials3description: Use when authoring or modifying any claude-team-toolkit skill that loads credentials, switches between accounts/orgs/environments, or needs confirmation for destructive operations. Reference for the shared profile + ctt_* helper pattern used by all credential-bearing skills.4---5
6# Profiles & Credentials — shared pattern reference
7
8Reference skill describing the credential / profile / confirmation pattern used by all claude-team-toolkit skills (azure-devops, fastlane, firebase, heroku, k6, maestro, postgres, rspec, sentry, shopify, slack, trello, etc.). Implementation lives in [`lib/credentials.sh`](../../lib/credentials.sh) and [`lib/confirm.sh`](../../lib/confirm.sh).
9
10## Overview
11
12All credential-bearing skills share a uniform pattern:
13
14- INI credentials at `~/.<service>/credentials` (mode 600)
15- Multiple `[profile]` sections per file (e.g., `[default]`, `[work]`, `[prod]`)
16- Resolution order: `--profile <name>` flag → `<SERVICE>_PROFILE` env → `~/.<service>/active_profile` → `[default]`
17- Helper sourced from `lib/credentials.sh` populates `CTT_<KEY>` env vars
18- Destructive ops gated by `ctt_confirm` from `lib/confirm.sh`
19- Actions audit-logged to `~/.claude-team-toolkit/audit.log` (key NAMES only, never values)
20
21## When to Use
22
23- Authoring a NEW skill that needs per-account/per-org/per-env switching
24- Modifying credential loading in an existing skill
25- Adding destructive operations that need typed confirmation
26- Debugging why a skill picks the wrong profile
27- Reviewing security posture of a skill
28
29## When NOT to Use
30
31- One-off scripts not meant for reuse → just hardcode and move on
32- Skills with no credentials (e.g., `react-native`, `rails-security`) → nothing to load
33- Cross-cloud unified credential systems → use the cloud's native config (`~/.aws/credentials`, etc.) instead of reinventing
34
35## Profile file shape
36
37```ini
38# ~/.<service>/credentials (mode 600)
39[default]
40field_a = value
41field_b = secret
42
43[other-profile]
44field_a = different
45require_confirm = true # gate every mutation in this profile
46```
47
48After `ctt_load_creds <service> [profile]`:
49- `CTT_PROFILE=<resolved>` (e.g., `default`)
50- `CTT_FIELD_A=<value>`, `CTT_FIELD_B=<secret>` (uppercased, hyphens → underscores)
51
52## Helper API (from `lib/credentials.sh`)
53
54| Function | Purpose |
55|---|---|
56| `ctt_load_creds <svc> [profile]` | Resolve + load profile into `CTT_*` env |
57| `ctt_save_profile <svc> <profile> <k=v>...` | Atomic INI section write |
58| `ctt_list_profiles <svc>` | List sections, mark active with `*` |
59| `ctt_use_profile <svc> <profile>` | Set active profile pointer |
60| `ctt_active_profile <svc>` | Print resolved active profile |
61| `ctt_remove_profile <svc> <profile>` | Refuses to remove last profile |
62| `ctt_mask <value>` | Returns `****<last4>` for safe logging |
63| `ctt_validate_perms <file>` | Refuses non-600/400 mode (POSIX only) |
64| `ctt_audit_log <svc> <action>` | Append timestamp + profile + action |
65
66## Confirmation API (from `lib/confirm.sh`)
67
68```bash
69ctt_confirm "Delete app foo?" || return 1 # y/N prompt
70ctt_confirm "Drop table users?" "DELETE" || return 1 # typed phrase
71ctt_warn_destructive "Action description" # noisy stderr banner
72```
73
74`CTT_NONINTERACTIVE=1` auto-denies all confirmations (CI safety).
75
76## Common Mistakes
77
78- Reading credentials directly with `awk` instead of `ctt_load_creds` → bypasses perm validation
79- Logging full credential values instead of `ctt_mask` → secrets leak to terminal/CI logs
80- Using `eval` to set vars from credentials → injection risk. Helper uses `printf -v` for safety.
81- Audit log records values not just key names → audit log itself becomes a secret store
82- Confirmation without typed phrase for irreversible ops → "y" is too easy a typo
83- Service name with uppercase or special chars → helper validates `^[a-z0-9-]+$`
84
85## Security defaults
86
87- Credentials directory: `chmod 700`. File: `chmod 600`. Helper refuses to load otherwise (POSIX).
88- Windows: best-effort (NTFS ACLs not enforced by helper) — document in skill's safety section.
89- `CTT_NONINTERACTIVE=1` in CI → auto-deny destructive ops (no surprise mutations).
90- Audit log at `~/.claude-team-toolkit/audit.log` (mode 600). Records: timestamp, service, profile, action.
91- Never write credentials into git, chat output, or any file outside `~/.<service>/credentials`.