# Agent Memory

> Session memory management, browser-based QA testing, and multi-agent coordination skill. Use when the user wants to persist learnings across sessions, review what the agent has learned about their codebase, prune stale knowledge, run browser-based testing with real Chromium, coordinate multiple AI agents on the same task, or set up authenticated browser sessions for testing.

- **Type:** Skill
- **Install:** `agentstack add skill-code-saurabh-openskills-agent-memory`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [CODE-SAURABH](https://agentstack.voostack.com/s/code-saurabh)
- **Installs:** 0
- **Category:** [Web & Browser](https://agentstack.voostack.com/c/web-and-browser)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [CODE-SAURABH](https://github.com/CODE-SAURABH)
- **Source:** https://github.com/CODE-SAURABH/OpenSkills/tree/main/agent-memory

## Install

```sh
agentstack add skill-code-saurabh-openskills-agent-memory
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Agent Memory — Unified Skill

This skill unifies three complementary capabilities into a single, coherent workflow:

1. **`/learn` — Session Memory Management** — Persist, search, prune, and export what the agent has learned about your codebase and project across sessions.
2. **`/browse` — Browser-Based QA Testing** — Drive real Chromium (headless or headed), click elements, take screenshots, import cookies, and assert page state for production-grade QA.
3. **`/pair-agent` — Multi-Agent Coordination** — Spawn parallel sub-agents on isolated scopes, aggregate results, and hand off context cleanly between agents.

---

## Part 1 — Memory Management (`/learn`)

### 1.1 Philosophy: Why Memory Matters

Every time the agent explores your codebase, it discovers implicit patterns that are expensive to rediscover:

- Which modules are load-bearing vs. experimental
- Naming conventions that are project-local (not language-default)
- Fragile integration points that have broken before
- Performance invariants the team cares about
- Domain-specific jargon used in comments and variable names

Without memory, the agent starts cold every session. With memory, compound knowledge accumulates — each session builds on prior sessions, reducing repeated archaeology and increasing the precision of every suggestion.

**Principle: Memory is a first-class engineering artifact. Treat it like documentation.**

---

### 1.2 Memory Scopes

There are two distinct scopes of memory. Always be explicit about which scope you are reading from or writing to.

#### Global Memory (`~/.agent-memory/global/`)

Stores patterns that apply across all projects on this machine:

- Preferred code style decisions (e.g., "always use early-return guards")
- Recurring architectural preferences (e.g., "prefer repository pattern over active record")
- User-level shortcuts and workflow preferences
- Learned tool behaviors (e.g., "this user's Makefile uses `make lint` not `make check`")

#### Project Memory (`/.agent-memory/`)

Stores patterns specific to the current repository:

- Module ownership and dependency graph insights
- Known flaky test files and their workarounds
- Environment setup quirks (e.g., "must source `.env.local` before running tests")
- API contracts with external services this codebase integrates with
- Domain concepts: entity names, lifecycle states, event vocabulary
- Historical bugs and their root causes (for future regression awareness)
- Architecture Decision Records (ADRs) that affect code shape

**Rule:** If a pattern applies only to one repo, it MUST be written to project memory, not global. Polluting global memory with project-specific facts degrades the signal-to-noise ratio for all projects.

---

### 1.3 Memory File Format

All memory entries are stored as structured Markdown files for human readability and diff-friendliness.

```
.agent-memory/
├── patterns/
│   ├── naming-conventions.md
│   ├── architecture.md
│   ├── testing-patterns.md
│   └── fragile-zones.md
├── domains/
│   ├── entities.md
│   └── events.md
├── history/
│   ├── bugs-resolved.md
│   └── refactors-completed.md
└── index.md          ← master index with dates and tags
```

Each entry in a memory file follows this schema:

```markdown
## [PATTERN_ID] Short Title

**Learned:** YYYY-MM-DD  
**Confidence:** high | medium | low  
**Scope:** global | project  
**Tags:** #architecture #naming #performance  
**Source:** session-id or description of how this was discovered  

### Observation
What was observed.

### Pattern
The generalizable rule extracted from the observation.

### Example
Concrete code or command example.

### Caveats
Conditions under which this pattern does NOT apply.
```

---

### 1.4 Writing New Memory

When you discover something worth remembering, write it immediately — not at the end of the session, because sessions can be interrupted.

**Trigger conditions for writing a new memory entry:**

- You found a non-obvious architectural invariant (e.g., "all writes go through the event bus, never direct DB calls")
- You discovered a project-specific naming rule not in any README
- You debugged a recurring error class and want to short-circuit future debugging
- You learned how the build system behaves in an undocumented edge case
- The user explicitly says "remember this" or "add this to memory"

**Writing procedure:**

```bash
# 1. Determine scope
SCOPE="project"  # or "global"

# 2. Determine the correct category file
CATEGORY="patterns/architecture"  # or naming-conventions, testing-patterns, etc.

# 3. Generate a unique pattern ID
PATTERN_ID="ARCH-$(date +%Y%m%d)-001"

# 4. Write the entry (append to the category file)
# Use the schema defined in section 1.3 above.

# 5. Update the index
echo "- [$PATTERN_ID] Short title — $CATEGORY — $(date +%Y-%m-%d)" >> .agent-memory/index.md
```

---

### 1.5 Reading and Reviewing Memory

At the START of every session on a known project, load the memory index and the relevant category files before making any code suggestions.

```bash
# Load the project memory index
cat .agent-memory/index.md 2>/dev/null || echo "No project memory yet."

# Load global memory index
cat ~/.agent-memory/global/index.md 2>/dev/null || echo "No global memory yet."
```

When the user asks to **review** memory:

1. Print the full index with IDs, titles, dates, and tags.
2. Group entries by category (patterns, domains, history).
3. Flag entries older than 90 days as "⚠️ Stale — review for pruning."
4. Flag entries with `Confidence: low` as "🔍 Uncertain — verify before relying on."

---

### 1.6 Searching Memory

When the user asks to **search** memory for a topic:

```bash
# Search all memory files for a keyword
grep -r "KEYWORD" .agent-memory/ --include="*.md" -l

# Search with context lines
grep -r "KEYWORD" .agent-memory/ --include="*.md" -n -B 2 -A 4
```

Search is case-insensitive by default. Present results grouped by file, with the pattern ID and title prominently displayed.

---

### 1.7 Pruning Memory

Memory must be pruned to stay useful. Stale or wrong memory is worse than no memory — it misleads future sessions.

**Prune when:**
- A refactor changed the architectural pattern the entry described
- A dependency was removed (its patterns are now irrelevant)
- An entry is >180 days old and hasn't been referenced or validated
- The user explicitly says "this is no longer true"
- The confidence level was `low` and it never got validated

**Prune procedure:**

```bash
# 1. List entries older than 90 days
find .agent-memory/ -name "*.md" -mtime +90

# 2. For each candidate, present to user for confirm/keep/update
# 3. Delete confirmed-stale entries
# 4. Remove from index.md
# 5. Commit the pruning as a standalone commit with message:
#    "chore(memory): prune stale entries — YYYY-MM-DD"
```

**Never silently delete memory.** Always show the user what will be removed and get confirmation (or use `--force` flag only if user explicitly requests unattended pruning).

---

### 1.8 Exporting Memory

When the user wants to export memory (e.g., to share with a new team member, or to seed a new project):

```bash
# Export as a single consolidated Markdown document
cat .agent-memory/**/*.md > memory-export-$(date +%Y%m%d).md

# Export as JSON for programmatic use
python3 -c "
import os, json, re
from pathlib import Path

entries = []
for f in Path('.agent-memory').rglob('*.md'):
    content = f.read_text()
    entries.append({'file': str(f), 'content': content})

print(json.dumps(entries, indent=2))
" > memory-export-$(date +%Y%m%d).json
```

---

### 1.9 How Learnings Compound Across Sessions

The compounding effect works as follows:

| Session | What Happens |
|---------|--------------|
| 1 | Agent discovers project structure, writes 3–5 foundational entries |
| 2 | Agent loads index, skips re-exploration, writes 2–3 deeper entries |
| 3 | Agent cross-references existing patterns, catches inconsistencies |
| 5+ | Agent predicts issues before the user encounters them |
| 10+ | Agent functions like a senior team member who knows the codebase |

**Key behaviors that enable compounding:**
- Always load memory at session start (not on demand)
- Cross-reference new discoveries against existing entries before writing duplicates
- Upgrade confidence levels when an entry is validated a second time
- Link related entries using `[PATTERN_ID]` references within entries

---

## Part 2 — Browser QA Testing (`/browse`)

### 2.1 Philosophy

Real QA requires a real browser. Mocks and unit tests cannot catch:
- Layout regressions caused by CSS specificity conflicts
- Race conditions in JavaScript initialization
- Server-side rendering hydration mismatches
- Authentication flows that depend on session cookies
- Third-party widget interactions (analytics, chat widgets, payment iframes)

This skill drives **real Chromium** via Playwright, giving you pixel-accurate, JS-executing, network-real browser automation.

---

### 2.2 Prerequisites and Setup

```bash
# Install Playwright with Chromium
pip install playwright
playwright install chromium

# Or via npm
npm install -D playwright
npx playwright install chromium

# Verify installation
python3 -c "from playwright.sync_api import sync_playwright; print('Playwright OK')"
```

---

### 2.3 Basic Navigation and Screenshot

```python
from playwright.sync_api import sync_playwright
import os

def browse_and_screenshot(url: str, output_path: str = "screenshot.png"):
    """
    Navigate to a URL and capture a full-page screenshot.
    Uses stealth settings to avoid bot detection.
    """
    with sync_playwright() as p:
        browser = p.chromium.launch(
            headless=True,
            args=[
                "--no-sandbox",
                "--disable-setuid-sandbox",
                "--disable-blink-features=AutomationControlled",
                "--disable-dev-shm-usage",
                "--disable-accelerated-2d-canvas",
                "--no-first-run",
                "--no-zygote",
                "--disable-gpu",
            ]
        )

        context = browser.new_context(
            viewport={"width": 1440, "height": 900},
            user_agent=(
                "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/120.0.0.0 Safari/537.36"
            ),
            locale="en-US",
            timezone_id="America/New_York",
        )

        # Anti-bot: remove webdriver property
        context.add_init_script("""
            Object.defineProperty(navigator, 'webdriver', {
                get: () => undefined,
            });
        """)

        page = context.new_page()
        page.goto(url, wait_until="networkidle", timeout=30000)
        page.screenshot(path=output_path, full_page=True)
        browser.close()
        print(f"Screenshot saved to {output_path}")

browse_and_screenshot("https://localhost:3000", "qa-screenshot.png")
```

---

### 2.4 Real Clicks and Form Interactions

```python
def test_login_flow(base_url: str, email: str, password: str):
    """
    Test a real login flow with form filling and navigation assertions.
    """
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(f"{base_url}/login")

        # Fill form fields
        page.fill('input[name="email"]', email)
        page.fill('input[name="password"]', password)

        # Screenshot before submit (for debugging)
        page.screenshot(path="before-login.png")

        # Click submit and wait for navigation
        with page.expect_navigation(wait_until="networkidle"):
            page.click('button[type="submit"]')

        # Assert post-login destination
        assert "/dashboard" in page.url, f"Expected redirect to /dashboard, got {page.url}"

        # Assert key element is present
        page.wait_for_selector('[data-testid="welcome-message"]', timeout=5000)

        # Screenshot after login
        page.screenshot(path="after-login.png")
        browser.close()
        print("Login flow: PASS")
```

---

### 2.5 Anti-Bot Stealth Configuration

For sites with advanced bot detection (Cloudflare, Akamai, DataDome):

```python
def stealth_context(playwright_instance):
    """
    Create a maximum-stealth browser context.
    Mimics a real macOS Chrome user as closely as possible.
    """
    browser = playwright_instance.chromium.launch(
        headless=True,
        args=[
            "--disable-blink-features=AutomationControlled",
            "--disable-features=IsolateOrigins,site-per-process",
        ]
    )

    context = browser.new_context(
        viewport={"width": 1440, "height": 900},
        screen={"width": 1440, "height": 900},
        user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        locale="en-US",
        timezone_id="America/Los_Angeles",
        color_scheme="light",
        device_scale_factor=2.0,  # Retina display
        has_touch=False,
        java_script_enabled=True,
        accept_downloads=True,
        extra_http_headers={
            "Accept-Language": "en-US,en;q=0.9",
            "Accept-Encoding": "gzip, deflate, br",
        }
    )

    # Remove all automation fingerprints
    context.add_init_script("""
        // Hide webdriver
        Object.defineProperty(navigator, 'webdriver', { get: () => undefined });

        // Fake plugins
        Object.defineProperty(navigator, 'plugins', {
            get: () => [1, 2, 3, 4, 5],
        });

        // Fake languages
        Object.defineProperty(navigator, 'languages', {
            get: () => ['en-US', 'en'],
        });

        // Hide Chrome automation
        window.chrome = { runtime: {} };

        // Fake permissions
        const originalQuery = window.navigator.permissions.query;
        window.navigator.permissions.query = (parameters) => (
            parameters.name === 'notifications'
                ? Promise.resolve({ state: Notification.permission })
                : originalQuery(parameters)
        );
    """)

    return browser, context
```

---

### 2.6 Cookie Import from Real Browser

To test authenticated sessions without re-logging in via automation (which often triggers 2FA):

#### Step 1: Export cookies from your real browser

Use the browser extension **"Cookie-Editor"** (Chrome/Firefox) to export cookies as JSON, or use the EditThisCookie extension.

Alternatively, export from Chrome's profile directly:

```bash
# macOS — copy Chrome's cookies database (requires Chrome to be closed)
cp ~/Library/Application\ Support/Google/Chrome/Default/Cookies /tmp/chrome-cookies.db

# Extract cookies for a specific domain using sqlite3
sqlite3 /tmp/chrome-cookies.db \
  "SELECT host_key, name, value, path, expires_utc, is_secure, is_httponly
   FROM cookies WHERE host_key LIKE '%yourdomain.com%';"
```

#### Step 2: Load cookies into Playwright context

```python
import json

def load_cookies_from_file(context, cookie_file: str):
    """
    Load cookies exported from a real browser into a Playwright context.
    Supports the Cookie-Editor JSON export format.
    """
    with open(cookie_file) as f:
        raw_cookies = json.load(f)

    playwright_cookies = []
    for c in raw_cookies:
        cookie = {
            "name": c["name"],
            "value": c["value"],
            "domain": c.get("domain", ""),
            "path": c.get("path", "/"),
            "secure": c.get("secure", False),
            "httpOnly": c.get("httpOnly", False),
        }
        # Handle expiry
        if "expirationDate" in c:
            cookie["expires"] = int(c["expirationDate"])

        playwright_cookies.append(cookie)

    context.add_cookies(playwright_cookies)
    print(f"Loaded {len(playwright_cookies)} cookies.")

# Usage
with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    context = browser.new_context()
    load

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [CODE-SAURABH](https://github.com/CODE-SAURABH)
- **Source:** [CODE-SAURABH/OpenSkills](https://github.com/CODE-SAURABH/OpenSkills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** yes
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-code-saurabh-openskills-agent-memory
- Seller: https://agentstack.voostack.com/s/code-saurabh
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
