Media memory
AI operating system for product managers. 65 Claude Code skills, 7 multi-perspective review agents, a memory system. Battle-tested in real PM work.
npx -y skills add talgacapri/pm-os --skill media-memoryAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Multimodal long-term memory. Ingest, describe, embed (Gemini Embedding 2 / gemini-embedding-001), and search any media (images, video, audio, documents) stored under /media-memory. Supports semantic similarity search plus structured metadata filtering by type, source, date range, and tag. Use when the user shares any media file, when the assistant generates any media, or when a past asset might be relevant to the current task. Triggers on: log this image, save this media, find that screenshot, do we have a recording of, search media memory, what was that file about.
SKILL.md
8.4 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it
Why this exists, and what I'd change
Why it exists. Stateless chat forgets every screenshot, chart, recording, and doc. Asking "find me the wireframe from last month" becomes "scroll through old Slack." This skill embeds everything so it's actually searchable across sessions and projects.
Design tradeoffs.
- Local ChromaDB instead of a hosted vector DB. Everything stays in your workspace, no cloud dependency. Cost: setup friction (GEMINI_API_KEY, Python deps), and search is single-machine only.
- Description-first indexing instead of raw image embedding. Gemini describes the asset, then we embed the description. Cost: files over 18MB get a placeholder description; full transcription requires routing through the Gemini Files API manually.
- Manual ingest call by default. I didn't auto-trigger on every Claude session because that creates surprise database writes. Cost: people forget to ingest, and a month of screenshots stays unindexed.
What I'd change. Auto-ingest on file paste in Claude Code, with a quiet confirmation. Manual ingest is reliable but rarely happens in practice.
Media Memory
A single source of truth for every piece of media the user shares or the assistant generates. Each asset is described by a multimodal Gemini call, embedded with Gemini Embedding 2 (gemini-embedding-001), and stored in a local ChromaDB collection alongside a JSON metadata sidecar.
Commands
/media-memory ingest <path> # log a single asset
/media-memory ingest <path> --source ai_generated --tags chart,roadmap
/media-memory search "query" # semantic search
/media-memory search "query" --type image --from 2026-01-01 --tag finance
/media-memory status # counts and storage health
Prerequisites
pip install -r scripts/media-memory/requirements.txt
export GEMINI_API_KEY=... # or GOOGLE_API_KEY
google-genai and chromadb are the only runtime deps. Vectors persist to media-memory/chroma/.
When to Auto-Trigger
Use this skill without being asked in any of these cases:
| Trigger | Action |
|---|---|
| User attaches an image, audio, video, or document | ingest with --source user_uploaded |
| You generate an image, diagram, or media artifact | ingest with --source ai_generated and --source-detail "<one-line prompt summary>" |
| User mentions a past asset ("that chart", "the recording from last week") | search with relevant filters before answering |
| Question references visual or audio context | search first, then answer with citations |
If the user explicitly says "don't log this" — skip ingestion and proceed.
Workflow A — Ingest
- Confirm the file path. If the asset only exists in the chat, save it locally first (e.g. into
media-memory/inbox/) and pass that path. - Pick the right
--source:user_uploaded(default for shared files)ai_generated(anything you produced)screenshot(UI screenshots)web_url(downloaded from a URL — put the URL in--source-detail)
- Run the ingest command. The script will:
- Detect MIME and media type (
image | audio | video | document | other) - Call
gemini-2.5-flashto produce a natural language description, OCR/extracted text, and (for audio/video) a transcript - Auto-generate 4-8 semantic tags
- Embed the combined description + extract with
gemini-embedding-001 - Persist:
- The binary under
media-memory/assets/YYYY/MM/<id><ext> - The full record under
media-memory/metadata/<id>.json - The vector + flat metadata in
media-memory/chroma/ - An audit row in
media-memory/index.jsonl
- The binary under
- Detect MIME and media type (
- Confirm to the user with the new
id, type, and tags.
Duplicates are detected by SHA-256 checksum and skipped automatically.
Example
python scripts/media-memory/media_memory.py ingest \
~/Downloads/product-roadmap-q2.png \
--source ai_generated \
--source-detail "Generated for Q2 roadmap review on 2026-04-25" \
--tags product,roadmap,q2
Workflow B — Search
Use this before answering questions that touch on prior assets, designs, recordings, or screenshots.
python scripts/media-memory/media_memory.py search "the dashboard wireframe with the Money In Money Out widget" \
--type image --from 2026-01-01 --tag product -n 5
Filters supported:
| Flag | Meaning |
|---|---|
--type | `image |
--source | Exact match (e.g. user_uploaded, ai_generated) |
--from | ISO date — only assets ingested on/after |
--to | ISO date — only assets ingested on/before |
--tag | Single tag — post-filtered against the asset's tag list |
-n | Top-k results (default 5) |
Returned JSON contains: id, filename, type, source, timestamp_ingested, tags, stored_path, truncated description, and similarity distance.
Citing search results
When you reference an asset back to the user, use this format:
Found in media memory:
<filename>(<type>, ingested<date>) —<one-line description>. Path:<stored_path>.
If the user wants the actual file, point them at <stored_path> (it's repo-relative).
Metadata Schema (canonical record)
See media-memory/README.md. Fields you will most often reason over:
type— coarse media classsource— who created itdescription— natural language summaryextracted_text/transcript— searchable text contenttags— semantic indexingtimestamp_ingested/timestamp_epoch— recency + range filtersstored_path— where the binary lives
ChromaDB metadata stores all primitive fields; tag arrays are mirrored as tags_joined for filtering.
Quality Checklist (before confirming an ingest)
- File saved under
media-memory/assets/YYYY/MM/ - Sidecar JSON written under
media-memory/metadata/ -
descriptionis concrete (not "an image of something") -
extracted_text/transcriptpopulated when content has text/audio - At least 3 semantic tags generated
- Vector added to ChromaDB (script prints
[ingested] id=...) - If the file was ai-generated,
source_detailsummarizes the prompt or context
Edge Cases
| Situation | Handling |
|---|---|
| File >18 MB | Description is skipped with a note; consider Files API upload |
| Unknown MIME | Stored as type=other; description still attempted |
GEMINI_API_KEY not set | Script exits with a clear error; tell the user before retrying |
| Duplicate (same SHA-256) | Skipped; existing id returned |
| Empty Chroma collection on first search | Return empty list — never fabricate citations |
Related
- Pairs with
/research-scout— when scout finds relevant external assets, ingest them with--source web_url. - Pairs with
/morning-brief— screenshots from the brief can be archived for later recall. - Pairs with
/sketchnote,/frontend-design,/prototype— auto-ingest their outputs asai_generated.
Gives 0 of the 12 instructions most memory context skills give in ~1.7k tokens
Counted across 674 of the 847 authors here whose files we hold, read 2026-08-06
- inform the user when setup is completein 21 of 674, across 6 files
- confirm the draft with the user before writingin 21 of 674, across 6 files
- update the agent skills block in place if it existsin 21 of 674, across 6 files
- present findings to the userin 20 of 674, across 5 files
- write the three docs files from seed templatesin 20 of 674, across 5 files
- ask the user about each decision one at a timein 19 of 674, across 4 files
- edit CLAUDE.md if it existsin 18 of 674, across 3 files
- explore current repo statein 18 of 674, across 3 files
- do not overwrite user edits to surrounding sectionsin 18 of 674, across 3 files
- back up the original file before overwritingin 16 of 674, across 8 files
- keep the memory index under 200 linesin 15 of 674
- Provide actionable steps and verificationin 13 of 674, across 2 files
Said here and by no other author read
- ingest media files when shared or generated
- skip ingestion if user explicitly declines
- save local paths before ingesting chat assets
- confirm ingestion with new id, type, and tags
- verify quality checklist before confirming ingest
- check for api key before retrying
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.