---
name: agent-memory
description: "Persistent memory layer for RTExit agents. Uses _rtexit-output/data/engagement-context.json. Read this to know how to read/write state across sessions."
---

# RTExit Agent Memory System

> **This is how RTExit agents remember everything.** Every agent reads/writes a shared JSON file. The agent ALWAYS knows what was done, what's pending, and what to do next — even after a context switch.

---

## The Memory File

**Location:** `_rtexit-output/data/engagement-context.json`

**Owner:** All agents share it
**Format:** JSON (versioned with `schema_version`)
**Auto-updated:** On every action
**Persistent:** Survives session restarts

```bash
# View current state
cat _rtexit-output/data/engagement-context.json | jq .

# Or pretty:
python3 -c "import json; print(json.dumps(json.load(open('_rtexit-output/data/engagement-context.json')), indent=2))"
```

---

## Schema v2.0 — Full Structure

```json
{
  "_meta": {
    "schema_version": "2.0",
    "created_at": "2026-06-10T...",
    "updated_at": "2026-06-10T...",
    "project_root": "/path/to/RTExit"
  },

  "engagement": {
    "ref":         "ENG-2026-001",
    "client":      "Acme Corp",
    "start_date":  "2026-06-10",
    "end_date":    "2026-06-24",
    "phase":       "exploitation",     // planning → recon → exploitation → post_exploit → reporting
    "methodology": "PTES",
    "type":        "full",             // web | mobile | network | ad | cloud | full
    "sead_path":   "docs/sead.md",
    "authorized":  true
  },

  "targets": {
    "primary_domains": ["acmecorp.com"],
    "subdomains":      ["api.acmecorp.com", "admin.acmecorp.com", ...],
    "live_hosts":      [{host, ip, port, tech}, ...],
    "endpoints":       [{url, method, params, auth}, ...],
    "api_endpoints":   [{url, version, auth, spec}, ...],
    "mobile_apps":     [{platform, package, version}, ...],
    "cloud_accounts":  [{provider, account_id, role}, ...],
    "ip_ranges":       ["10.0.0.0/16", ...]
  },

  "recon": {
    "status":           "complete",
    "subdomains_found": 47,
    "live_hosts_found": 31,
    "emails_found":     ["john@acmecorp.com", ...],
    "technologies":     {"api.acmecorp.com": ["nginx", "Java", "Spring"], ...},
    "open_ports":       {"api.acmecorp.com": [80, 443, 8080], ...},
    "interesting_paths": ["/admin", "/api/v1", ...],
    "js_secrets_found":  [{url, type, value}, ...],
    "cloud_buckets":    ["acme-backup", ...],
    "historical_urls":  1283,
    "workspace_path":   "docker/lab/workspace/recon/"
  },

  "credentials": {
    "valid":         [{user, pass, service, source, found_by}, ...],
    "hashes":        [{user, hash, type, source}, ...],
    "tokens":        [{type, value, scope, expiry, service}, ...],
    "api_keys":      [{key, service, permissions}, ...],
    "certificates":  [{cert, key, subject, issuer}, ...]
  },

  "access": {
    "initial_access":    [{vector, target, method, timestamp}, ...],
    "privileged_access": [{level, system, method}, ...],
    "shells":            [{ip, type, port, user}, ...],
    "pivot_points":      [{from, to, method}, ...],
    "persistence":       [{type, location, target}, ...]
  },

  "findings": {
    "total":    12,
    "critical": 2,
    "high":     4,
    "medium":   4,
    "low":      2,
    "info":     0,
    "list": [
      {
        "id": "F-001",
        "title": "Unrestricted File Upload RCE",
        "severity": "critical",
        "target": "staging.acmecorp.com",
        "cve": null,
        "cvss": 9.8,
        "status": "verified",
        "found_by": "agent-breaker",
        "poc_path": "/opt/loot/findings/F-001/",
        "verified": true,
        "mitre_techniques": ["T1190", "T1505.003"]
      },
      ...
    ]
  },

  "phases": {
    "planning":     {"status": "complete", "started": "...", "completed": "..."},
    "recon":        {"status": "complete", "started": "...", "completed": "..."},
    "exploitation": {"status": "active",   "started": "...", "completed": null},
    "post_exploit": {"status": "pending",  "started": null,   "completed": null},
    "reporting":    {"status": "pending",  "started": null,   "completed": null}
  },

  "agent_log": [
    {"agent": "commander", "action": "engagement_initialized", "timestamp": "...", "note": "..."},
    {"agent": "scout",     "action": "subdomain_enum",        "timestamp": "...", "note": "47 found"},
    ...
  ],

  "notes": {
    "attack_vectors":   ["file_upload_polyglot", "ssrf_imds", "kerberoast"],
    "blocked_paths":    ["WAF detected: Cloudflare", "Rate limit on /api"],
    "interesting_tech": ["Apache 2.4.49 (vulnerable!)", "Spring Boot 2.6.5"],
    "custom":           ["Use Burp Autorize for IDOR testing"]
  }
}
```

---

## How Agents Read & Write

### Read at Start of Any Task

```python
# Python
import json
with open('_rtexit-output/data/engagement-context.json') as f:
    ctx = json.load(f)

# What to check:
phase = ctx['engagement']['phase']                    # current phase
subs = ctx['targets']['subdomains']                   # known subs
creds = ctx['credentials']['valid']                   # known creds
findings = ctx['findings']['list']                    # past findings
last_action = ctx['agent_log'][-1]                    # what was done last
phases = ctx['phases']                                # what's complete
```

```bash
# Bash
PHASE=$(jq -r '.engagement.phase' _rtexit-output/data/engagement-context.json)
SUBS=$(jq -r '.targets.subdomains | length' _rtexit-output/data/engagement-context.json)
FINDS=$(jq -r '.findings.total' _rtexit-output/data/engagement-context.json)
```

### Write After Every Action

**Use the helper function:**

```bash
# Update specific fields
python3 _rtexit/scripts/init-engagement.py update \
  --field "recon.status=complete" \
  --field "recon.subdomains_found=47" \
  --agent "scout" \
  --note "Subdomain enumeration complete"
```

**Or use jq directly (faster):**

```bash
# Add a finding
jq '.findings.list += [{
  "id": "F-001",
  "title": "Unrestricted File Upload RCE",
  "severity": "critical",
  "target": "staging.acmecorp.com",
  "cvss": 9.8,
  "status": "verified",
  "found_by": "agent-breaker",
  "verified": true
}] | .findings.total += 1 | .findings.critical += 1' \
  _rtexit-output/data/engagement-context.json > /tmp/ctx.json && mv /tmp/ctx.json _rtexit-output/data/engagement-context.json
```

---

## Agent Workflow Pattern

Every RTExit agent follows this pattern:

### 1. Read Context
```python
ctx = read_context()
phase = ctx['engagement']['phase']
known_findings = ctx['findings']['list']
known_creds = ctx['credentials']['valid']
```

### 2. Decide Next Action
```python
# Decision logic
if phase == 'planning':
    # Run rt-create-sead
    pass
elif phase == 'recon':
    if ctx['recon']['status'] != 'complete':
        # Continue recon
        pass
    else:
        # Move to exploitation
        update_context('engagement.phase', 'exploitation')
        update_context('phases.recon.status', 'complete')
elif phase == 'exploitation':
    # Read attack_vectors from notes
    vectors = ctx['notes']['attack_vectors']
    for vector in vectors:
        # Try each
        pass
```

### 3. Execute & Update
```python
# After running a scan
result = run_nmap(target)

# Update context
update_context('recon.open_ports.' + target, result.ports)
append_log('scout', 'port_scan', f'Scanned {target}: {len(result.ports)} open')

# After finding a vuln
finding = {
    "id": f"F-{ctx['findings']['total']+1:03d}",
    "title": "...",
    ...
}
append_finding(finding)
append_log('breaker', 'finding_discovered', finding['title'])
```

### 4. Log Everything
Every action goes into `agent_log`. The log is the **agent's memory of what it has done** in this session and across sessions.

---

## Memory Refresh Pattern (After Context Loss)

When the agent starts fresh (e.g., new session), it must re-read context:

```bash
# 1. Load current state
cat _rtexit-output/data/engagement-context.json | jq .

# 2. Check phase
jq -r '.engagement.phase' _rtexit-output/data/engagement-context.json

# 3. Check what's been done
jq -r '.phases' _rtexit-output/data/engagement-context.json

# 4. Check what was found
jq -r '.findings.summary' _rtexit-output/data/engagement-context.json

# 5. Check last 5 actions
jq -r '.agent_log[-5:]' _rtexit-output/data/engagement-context.json

# 6. Decide next action based on state
```

**The agent ALWAYS knows:**
- ✅ What phase we're in
- ✅ What's been done
- ✅ What was found
- ✅ What's pending
- ✅ What the next action should be

---

## Reading Scenarios Based on Context

The agent should consult the **SCENARIOS-MASTER.md** based on the current phase and context:

```python
# Example logic
phase = ctx['engagement']['phase']
subs = ctx['targets']['subdomains']
creds = ctx['credentials']['valid']

if phase == 'recon' and len(subs) < 5:
    # Read rt-subdomain-enum scenarios
    scenarios = read_scenarios('01-recon/rt-subdomain-enum/scenarios.md')
    # Try top scenarios
    for s in scenarios[:5]:
        try_scenario(s)
elif phase == 'exploitation' and 'admin@acmecorp.com' in [c['user'] for c in creds]:
    # Have creds → try BOLA, BFLA, business logic
    scenarios_bola = read_scenarios('03-api/rt-exploit-api/scenarios.md', category='BOLA')
    for s in scenarios_bola[:3]:
        try_scenario(s, credentials=creds)
```

---

## Tool + Scenario + Memory = Complete Loop

```
┌──────────────────────────────────────────────────────────┐
│ User: "Continue the engagement"                          │
└──────────────────────────────────────────────────────────┘
                          ↓
┌──────────────────────────────────────────────────────────┐
│ Agent reads engagement-context.json (MEMORY)             │
│ → Phase: exploitation, 2 critical findings, 4 creds     │
└──────────────────────────────────────────────────────────┘
                          ↓
┌──────────────────────────────────────────────────────────┐
│ Agent reads SCENARIOS-MASTER.md                          │
│ → Maps "exploitation" → rt-exploit-api, rt-exploit-web │
└──────────────────────────────────────────────────────────┘
                          ↓
┌──────────────────────────────────────────────────────────┐
│ Agent reads rt-exploit-api/scenarios.md                  │
│ → Picks top 3 scenarios (BOLA, BFLA, mass assignment)  │
└──────────────────────────────────────────────────────────┘
                          ↓
┌──────────────────────────────────────────────────────────┐
│ Agent reads TOOLS-MASTER.md                              │
│ → Picks tools: burp, sqlmap, jwt_tool                   │
└──────────────────────────────────────────────────────────┘
                          ↓
┌──────────────────────────────────────────────────────────┐
│ Agent runs in Docker Kali:                               │
│ $ docker exec -it rtexit-kali bash                       │
│ $ burpsuite ...                                          │
└──────────────────────────────────────────────────────────┘
                          ↓
┌──────────────────────────────────────────────────────────┐
│ Agent updates engagement-context.json (MEMORY)           │
│ → Adds new finding, updates phase, logs action          │
└──────────────────────────────────────────────────────────┘
                          ↓
                  (Loop continues)
```

---

## Memory Helpers (Built-in Scripts)

The `_rtexit/scripts/` directory has helpers:

```bash
# Initialize engagement
python3 _rtexit/scripts/init-engagement.py --project-root .

# Read context
python3 _rtexit/scripts/init-engagement.py read

# Update context
python3 _rtexit/scripts/init-engagement.py update \
  --agent "scout" \
  --field "recon.subdomains_found=47" \
  --note "Subdomain enumeration complete"

# Add finding
python3 _rtexit/scripts/finding_tracker.py add \
  --title "Unrestricted File Upload RCE" \
  --severity "critical" \
  --target "staging.acmecorp.com" \
  --cvss 9.8

# List findings
python3 _rtexit/scripts/finding_tracker.py list --severity critical

# Get stats
python3 _rtexit/scripts/finding_tracker.py stats

# Auto-doc activity
python3 _rtexit/scripts/autodoc_engine.py log \
  --action "port_scan" \
  --agent "scout" \
  --target "staging.acmecorp.com"
```

---

## What the Agent MUST Remember

**Critical context (always load first):**
1. Current phase
2. Active findings
3. Known credentials
4. Known attack surface (subdomains, endpoints)
5. Last 5 actions

**Optional context (load as needed):**
6. Tools used
7. Blocked paths
8. All findings
9. Full agent log

---

## Session Continuity

If a session ends abruptly, the next agent:

1. Reads `engagement-context.json`
2. Sees what was being done
3. Continues from there

Example:
```bash
# New session starts
$ cat _rtexit-output/data/engagement-context.json | jq '.agent_log[-3:]'
[
  {"agent": "scout",     "action": "subdomain_enum", "note": "47 found"},
  {"agent": "scout",     "action": "tech_detect",    "note": "Identified Java/Spring on api"},
  {"agent": "breaker",   "action": "fuzzing",        "note": "Found 12 endpoints on /api/v1"}
]
# → New agent knows exactly where to pick up
```

---

## Key Principle

**The agent NEVER has to "remember" things itself. Everything is in the JSON file.**

The agent's job is to:
1. **Read** the file → know current state
2. **Decide** next action based on state
3. **Execute** the action
4. **Write** back to the file → update state
5. **Repeat**

This is the RTExit way.
