4.4 KiB
Resume Prompt — Agent Identity Provisioning (Session 3)
Read this entire file before doing anything. Session 2 completed all four systems for vp-techops and consolidated the flows. This session loops the remaining agents through the manifest.
Who You Are
You are the TSGCOO Crush agent (AI assistant for TSYS Group's COO). You provision AI agent identities (Cloudron accounts, SSO, API keys) and store all credentials in Bitwarden.
Read First
/home/TSGCOO/projects/TSYSGroupAIOS/BASELINE-PROMPT.md(14 principles)/home/TSGCOO/projects/agent-identity-provisioning/STATUS.md/home/TSGCOO/projects/agent-identity-provisioning/docs/JOURNAL.md— all working selectors and flows are documented here
State at Session 3 Start (2026-08-13 end of session 2)
All flows are proven end-to-end for vp-techops and consolidated into
provision-agent.py:
| System | Flow | Status |
|---|---|---|
| Cloudron | invite -> password -> TOTP 2FA | ✅ proven |
| Gitea | SSO -> token | ✅ proven |
| Discourse | SSO -> signup -> RSA User API key | ✅ proven |
| Redmine | SSO -> API key | ✅ proven |
BW vault (4 items): vp-techops Cloudron (TOTP), Gitea, Discourse, Redmine. All keys verified via their APIs.
Infrastructure facts:
- Provisioner:
docker compose run --rm provisionin/home/TSGCOO/projects/agent-identity-provisioning - Source is bind-mounted read-only — no rebuild needed for .py changes
- Container user matches host TSGCOO (1002:1002);
:latesttag reuse is fine during iteration bw_helper.pysyncs after login and before list — the session-1 state divergence bug is fixed and covered bytest_bw_persistence.py- Host
bwwrapper:export PATH="$HOME/.local/bin:$PATH"(not in default PATH)
What This Session Does
Loop the remaining agents in agents.yaml:
Step 1: Merge Charles's invite file into the manifest
Charles keeps invites in ~/cloudron-invites.txt, one agent per line:
agent-name,invite-url (hyphenated names preferred; loose names like
vpsecops auto-normalize; blank lines and # comments ignored; email/
username/displayName are extracted from the invite URL itself).
cd /home/TSGCOO/projects/agent-identity-provisioning
docker compose run --rm --entrypoint python3 \
-v "$HOME/cloudron-invites.txt:/invites.txt:ro" \
provision merge-invites.py
cp state/agents-merged.yaml agents.yaml
merge-invites.py SKIPS duplicate invite tokens (stale copy-paste guard) and exits 1 while still writing the valid entries. As of session 2 end the manifest is fully merged: all 9 agents READY (including new vp-compliance, appended phase1-only). Re-run this step only if Charles issues fresh invites.
Step 2: Grant Cloudron app access
For each agent with systems configured, Charles must grant the user access to those apps in Cloudron (Redmine lesson: OIDC shows "You do not have access" until granted).
Step 3: Provision
docker compose run --rm provision provision-agent.py --agent vp-secops
Q4 agents (coo, svp-knel, svp-tctc, vp-investing, vp-trading,
vp-compliance): add --phase1-only (they have systems: {} anyway).
Idempotency: BW items short-circuit (X already exists -- skipping),
so re-runs are safe.
Prereq Checklist Before Each Agent
- Invite URL in agents.yaml
- Cloudron app access granted (Gitea/Redmine/Discourse per manifest)
- BW vault has no stale items for that agent
Known Issues (do not re-litigate)
- bw "native" binary is a Node.js SEA — prints Node errors on crash. CMMC/ITAR zero-Node goal is not actually met. Needs a Charles decision.
- Gitea stale tokens from session 1 may exist for vp-techops — cleanup pending (revoke all but the stored one).
- Repos can't be pushed — TSGCOO has no Gitea auth yet. All commits are local. Wire TSGCOO's Gitea credentials when available.
- Discourse User API keys are user-scoped — admin operations still need an admin key (assign to vp-techops per STATUS.md inbox).
Mistakes to Avoid (carried forward)
- Never delete BW items to fix duplicates —
update_item()in place - One comprehensive DOM dump per page before writing selectors
(see
_debug_dumpand JOURNAL.md patterns) page.keyboard.type()notfill()for Vue/Pankow forms[role="button"]notbuttonfor Cloudron UI- Em dashes break Python source — use
-- - Redmine Reset: use the DOM-traversal targeting in
provision_redmine, never a generica:has-text("Reset")match