Prompt file imported from Contoso-State/red-team-agent-orchestration (
.github/prompts/recon.prompt.md). Copyright stays with the author.
/recon — Reconnaissance & Inventory
You are acting as the Orchestrator Agent (agents/orchestrator/system-prompt.md). Begin a new red team engagement reconnaissance phase.
Steps
- Verify the environment. Run
node tools/preflight/check-environment.mjs. If any required check fails (Node ≥ 22.5, Azure CLI installed + signed in,resource-graphextension), show the doctor's remediation and stop until it passes — the inventory pipeline needs all of them. This is read-only. - Load scope. Read
engagement.yaml. If it does not exist, tell the user to copyengagement.example.yamltoengagement.yamland fill it in, then stop. - Validate scope against
schemas/engagement.schema.json. Echo a one-line summary: engagement ID, mode, target subscription, assessment focus (scope.domains/scope.resource_types), and any exclusions. Confirm with the user before proceeding if anything looks off.- Hard stop:
scope.subscriptionsmust contain exactly one subscription. If not, stop and require/setupto regenerateengagement.yamlfor a single-subscription run. - If no focus is set (
scope.resource_typesandscope.domainsboth empty), ask "What is your assessment focus for this subscription?" before enumerating — offer the focus menu (Full estate · Public/internet exposure · Virtual Machines & compute · Data stores · Identity & access · AI/Foundry · Logging & governance · DevOps & supply chain · or specific resource types like just VMs or just Public IPs). Pass the chosenscope.resource_typesto the Inventory agent so Resource Graph filters server-side.
- Hard stop:
3.5. Confirm identity, target, and mode — do not proceed until the user says yes.
Run az account show and present a full pre-flight confirmation block:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Reconnaissance pre-flight summary │
│ │
│ Identity: <displayName or userPrincipalName> │
│ Identity type: <user | service-principal | managed-identity> │
│ Tenant: <tenantId> │
│ │
│ Target subscription: <scope.subscriptions[0].name> │
│ Subscription ID: <scope.subscriptions[0].id> │
│ Resource groups: <resource_groups or *> │
│ Domains in scope: <domains or all> │
│ Mode: <mode> │
│ │
│ ⚠️ READ-ONLY — no resources will be modified during this assessment │
└─────────────────────────────────────────────────────────────────────────────┘
Then ask:
Are these the correct identity and subscription? Type yes to start reconnaissance, or no to stop and correct the settings.
If the identity is wrong, run
az login(oraz login --service-principal) and re-run/recon. If the subscription is wrong, run/setupto regenerateengagement.yaml.
Do not open the session folder or call any agent until the user explicitly confirms.
4. Open the session folder. Derive <session> = <engagement.id>-<YYYY-MM-DD-HHMMSS> (current UTC time) and create engagements/<session>/ with inventory/, findings/raw/, findings/normalized/, evidence/, and reports/ subfolders. Snapshot the scope to engagements/<session>/engagement.yaml. The whole engagements/ tree is gitignored, so every run is self-contained and never overwrites a prior session. Set $env:REDTEAM_SESSION to this path if you use the PowerShell helpers. Initialize the datastore: node tools/datastore/db.mjs init --db engagements/<session>/engagement.db --engagement <engagement.id>.
5. Dispatch the Inventory & Scope Agent (agents/inventory-scope/system-prompt.md):
- Confirm the authenticated Azure identity (
az account show). - Validate effective RBAC for the caller; record any missing roles as coverage limitations.
- Enumerate all in-scope resources via Azure Resource Graph into
engagements/<session>/inventory/resources.jsonl(applyingscope.resource_typesserver-side), and build the scope brief (inventory/scope-brief.json). - Write
engagements/<session>/inventory/subscriptions.jsonandengagements/<session>/inventory/coverage-limitations.json. - Ingest the inventory into the datastore so it is queryable and cached for
/assess:node tools/datastore/ingest.mjs --db engagements/<session>/engagement.db --session engagements/<session>.
- Refine focus against what's actually present. From the scope brief, show the composition (e.g. "1,200 storage accounts, 200 VMs, 18 public IPs across 12 resource types"). If the estate is large, offer to narrow the focus (e.g. "start with the internet-facing surface?") and update
scope.resource_types/scope.domainsbefore/assess. Highlight internet-facing resources, privileged principals, and data stores, and recommend which domain agents to dispatch.
Output
- A populated
engagements/<session>/inventory/directory - An initialized
engagements/<session>/engagement.dbwith the inventory ingested (the cache for/assess) - A recon summary with the recommended next step (
/assess)
Stay within the engagement mode. This phase is always read-only.