Skip to main content
Glama
README.md
# MEME — Internet Culture Agent

**MEME** is an always-online internet comedian for developers: it discovers
what the dev world is actually talking about *right now* — through authorized
APIs — and turns it into original, well-crafted memes you'll want to share.

MEME runs as an **MCP (Model Context Protocol) server over stdio**, built on
the official [`modelcontextprotocol/typescript-sdk`](https://github.com/modelcontextprotocol/typescript-sdk)
(vendored at tag **v2.4.0** — see `vendor/` and `docs/SDK_AUDIT.md`).

```
npm install && npm run demo          # full pipeline, zero credentials
npm run serve                        # MCP stdio server (Claude/any MCP client)
```

> MEME never claims a meme is objectively funny or guaranteed to go viral.
> Quality scores are heuristic aids with honest confidence bounds, and source
> freshness is reported truthfully (`live` / `cached` / `stale`) — never
> "real-time" when it isn't.

## What it does

1. **Discovers trends** from authorized sources: GitHub (REST search),
   Hacker News (Algolia front page), and a deterministic offline demo source.
   Reddit is implemented but **hard-gated pending a dedicated legal & policy
   review**; X/Twitter is **unavailable** (no API access in this build). See
   the [Platform Compliance Registry](#platform-compliance-registry).
2. **Ranks trends intelligently** — not by raw popularity, but by velocity,
   acceleration, engagement quality, recency, developer relevance,
   cross-platform signals, source diversity, and discussion authenticity.
   Every score ships with a **transparent per-factor explanation** and a
   **confidence** value.
3. **Generates original meme concepts** with an LLM (deterministic offline
   "mockbrain" in demo mode; any OpenAI-compatible API in live mode),
   personalized to your humor style, languages, favorite formats and content
   exclusions. External content is **framed as untrusted data** (prompt-injection
   defense), and every string passes **moderation**.
4. **Renders memes** as original vector compositions (6 formats, editable
   templates, overflow-safe captions) → SVG + PNG (via sharp, when available).
5. **Evaluates quality** across 7 dimensions (technical accuracy, contextual
   relevance, originality, humor *proxy*, caption readability, visual
   composition, audience relevance) with a benchmark dataset and regression
   tests, plus optional 1–5 star human ratings.
6. **Manages cost** — provider-independent price book, token/call accounting,
   cache-efficiency stats, per-user daily quotas, workspace budgets, atomic
   reservations, and graceful fallback to the free provider when a budget is
   exhausted.
7. **Survives failure** — durable job queue (JSONL journal, idempotency keys,
  lease recovery), bounded concurrency, exponential backoff with full jitter,
  `Retry-After` awareness, circuit breakers, timeouts, cancellation, DLQ +
  replay.
8. **Observes itself** — structured JSON logs (stderr, secrets auto-redacted),
  trace/span context propagation, latency/failure/moderation/cost metrics.

## Quickstart

```bash
git clone <this-repo> meme-agent && cd meme-agent
npm install            # installs the vendored MCP SDK from vendor/*.tgz
npm test               # 502 tests
npm run demo           # discover → rank → generate → evaluate → render → export
```

Output lands in `.meme/output/local/` (SVG + PNG + a sidecar JSON with
attribution and license).

### Run as an MCP server (stdio)

```bash
npm run serve
# or after `npm run build`:
node dist/index.js serve
```

Then add to any MCP client config:

```json
{
  "mcpServers": {
    "meme": { "command": "node", "args": ["/absolute/path/to/meme-agent/dist/index.js", "serve"] }
  }
}
```

### Live mode (real GitHub + Hacker News)

```bash
MEME_MODE=live GITHUB_TOKEN=ghp_xxx npm run serve
```

Without `OPENAI_API_KEY`, live mode still works — the LLM gracefully falls
back to the deterministic mock provider (with a logged notice).

## The 27 MCP tools

| Area | Tools |
| --- | --- |
| Trends | `get_trends`, `get_trend` |
| Creation | `generate_meme` (sync or durable-queue async), `render_meme` |
| Library | `list_memes`, `get_meme`, `get_history`, `edit_meme`, `delete_meme`, `export_meme` |
| Quality | `evaluate_meme`, `rate_meme` |
| Engagement | `favorite_meme`, `list_favorites`, `submit_feedback`, `report_content` |
| Personalization | `get_preferences`, `set_preferences`, `list_templates`, `edit_template` |
| Cost | `get_cost_report`, `get_cost_report-all` *(admin)* |
| Ops | `get_health`, `get_metrics` *(admin)*, `enforce_retention` *(admin)*, `review_moderation_queue` *(admin)*, `get_compliance` *(admin)* |

Authorization is enforced **in application code** (`src/security/authz.ts`):
role allowlists, JSON-safe argument checks, and an injection screen on every
tool argument — never by asking the LLM nicely.

## Platform Compliance Registry

`src/compliance/registry.ts` is the versioned source of truth. Highlights:

| Provider | Status | Key constraints |
| --- | --- | --- |
| GitHub | active | official REST API; conditional requests; content retention 7 days; training on fetched content **prohibited**; attribution required |
| Hacker News | active | public Algolia API; same content rules |
| Reddit | **gated** | requires a completed legal & policy review (signed override file) **and** `REDDIT_ENABLED=1`; user content must not be passed to external AI providers or transformed before that review; no storage; deletion on request; commercial use prohibited |
| X/Twitter | **unavailable** | no authorized API access in v0.1.0 — disabled, never simulated |
| OpenAI-compatible LLM | active | only receives pre-sanitized, injection-screened context blocks; zero retention expectation documented |

Publicly accessible content is **not** assumed to be freely processable,
transformable, storable or redistributable. No training on third-party
content, ever.

## Security model (summary)

- **Prompt injection**: obfuscation-resistant scanner (NFKC + zero-width/Bidi
  stripping); external text framed in unclosable `<external-content>` DATA
  blocks with an explicit preamble; hostile content in **tool arguments** is
  hard-blocked; hostile *trend content* is framed + flagged (a trend about
  prompt injection is legitimate meme material).
- **SSRF**: all outbound traffic flows through `GuardedNetworkClient` —
  dot-boundary host allowlist, private/reserved/mapped IP rejection
  (including `169.254.169.254` cloud metadata), IP-literal and
  hex/octal/decimal host rejection, manual redirects re-validated per hop,
  size caps, timeouts. Known residual: DNS-rebinding race (documented in
  `SECURITY.md`, mitigation on the roadmap).
- **Media**: magic-byte validation, SVG script/handler/`javascript:`/bomb
  screening before any processing.
- **Tenancy**: store-level authz boundary; cross-tenant access throws
  (`AUTHZ_DENIED`), path-traversal-safe names.
- **Secrets**: env-only, never persisted, auto-redacted in logs (key patterns
  and value shapes: `ghp_…`, `sk-…`, `Bearer …`, JWTs).

See `SECURITY.md` for the full model and residual risks.

## Cost controls

Defaults (env-overridable): user $1/day, workspace $20/month, global $50/day,
`onExhaustion=fallback` (falls back to the free deterministic provider).
Reservations are atomic — 20 concurrent requests against a $1 budget admit
exactly 15 × $1/15 (regression-tested). `get_cost_report` shows spend,
per-provider breakdown and cache hit-rate.

## Definition of Done — v0.1.0 (all proven by `tests/dod.test.ts`)

- [x] Fresh install runs locally with zero manual configuration
- [x] Launches the MCP **stdio** server (real child process, real pipe)
- [x] Connects to at least one functioning authorized live source
      (real `api.github.com` test via `MEME_LIVE_GITHUB=1`; a real-socket
      local HTTP test always runs)
- [x] Discovers and ranks trends (transparent explanations + confidence)
- [x] Generates context-aware meme concepts
- [x] Renders images (SVG always; PNG via sharp when available)
- [x] Executes moderation on every visible string
- [x] Previews (inline PNG) and edits results
- [x] Exports a completed meme (image + sidecar with attribution/license)
- [x] stdout stays protocol-clean (asserted line-by-line)
- [x] Demo mode: deterministic trends + mock providers, no credentials needed

Spec-mandated test areas → suites:

| Spec area | Where proven |
| --- | --- |
| authentication boundaries | `src/security/authz.test.ts`, `tests/security-e2e.test.ts` |
| tenant isolation | `src/core/core.test.ts`, `tests/security-e2e.test.ts` |
| content retention | `src/retention/retention.test.ts`, `tests/audit-regressions.test.ts` |
| moderation decisions | `src/moderation/moderator.test.ts`, e2e blocks |
| prompt-injection defenses | `src/security/injection.test.ts` (17-attack corpus), `tests/security-e2e.test.ts` |
| provider failures | `src/providers/*`, `tests/live-source.test.ts` (failure isolation) |
| rate-limit handling | `src/queue/worker.test.ts` (Retry-After), `src/trends/sources/*` (403/429) |
| job retries | `src/queue/durable.test.ts`, `worker.test.ts` (backoff, DLQ, lease recovery) |

## Configuration

All via environment (see `.env.example`): `MEME_MODE` (demo|live), `MEME_HOME`,
`GITHUB_TOKEN`, `OPENAI_API_KEY`, `OPENAI_MODEL`, `MEME_LLM_PROVIDER`,
`MEME_IMAGE_PROVIDER`, `MEME_LOG_LEVEL`, budget vars (`MEME_BUDGET_*`),
retention vars (`MEME_RETENTION_*`), `REDDIT_ENABLED` (+ signed
`compliance-overrides.json`).

## Repository layout

```
src/core/         foundation: config+flags, store (authz boundary), logger,
                  metrics, tracer, clock/rng injection, shared ports
src/trends/       sources (github/hackernews/reddit-gated/demo), dedupe,
                  ranking engine, HTTP cache
src/personalization/  user humor profiles
src/security/     injection screen, SSRF guard, authz
src/compliance/   versioned Platform Compliance Registry
src/moderation/   rule-based moderator + pipeline gate
src/retention/    retention enforcer + user-data deletion
src/queue/        durable queue, worker (backoff/breaker/DLQ)
src/cost/         price book, tracker, budget manager
src/memes/        formats, templates, captions, mockbrain, generator,
                  renderer, library (history/favorites/feedback/reports/export)
src/quality/      rubric, evaluator, benchmark
src/providers/    LLM providers (mock + OpenAI-compatible) + router
src/server/       composition root, pipeline, 27 MCP tools
tests/            e2e (InMemory), DoD (stdio), live-source, security, audit
vendor/           the MCP SDK tarballs this project is built on
benchmark/        meme-quality benchmark dataset (18 items)
docs/SDK_AUDIT.md upstream audit with evidence
FINDINGS.md       engineering audit: demonstrated bugs + fixes (one commit each)
ROADMAP.md        implemented / experimental / planned / unavailable
```

## Honest limitations

- Trend "velocity/acceleration" in demo mode are synthetic by design.
- The humor "score" is a structural proxy — MEME will never tell you a meme is
  objectively funny.
- Moderation seed lists are placeholder-grade; extend `extraTerms` per
  deployment.
- Single-process storage (JSON files + JSONL journal); multi-node queues and
  remote MCP auth are roadmap items.

## License

MIT. Meme compositions are original vector art (CC0-style dedication for
generated output — see the export sidecar); quoted trend headlines are
attributed per-source in every export.

TDQS

C2.8/5.0

Scored across 27 tools

Disambiguation3/5

Most tools target distinct resource+action pairs (get_trend vs get_trends, evaluate_meme vs rate_meme vs render_meme), but list_memes and get_history describe nearly the same thing ('your rendered memes, newest first'), and get_cost_report vs get_cost_report-all differ only by scope. An agent must guess which of the duplicate pairs to call.

Naming Consistency4/5

A clear verb_noun snake_case convention dominates (get_meme, render_meme, edit_template, report_content). Minor deviations: get_cost_report-all uses a hyphen instead of a scope parameter, and get_history reads like a synonym for list_memes rather than a distinct resource.

Tool Count2/5

27 tools exceeds a reasonable scope for a meme generation server, with the surface inflated by ops/admin concerns (get_metrics, enforce_retention, get_compliance, two cost reports, get_health). Several of these could be collapsed into fewer tools or a single status endpoint.

Completeness3/5

Meme lifecycle is well covered (generate, render, list, get, edit, delete, export, evaluate, rate, report, favorite), but favorites have no unfavorite/remove operation, templates support list+edit but no create or delete for custom templates, and history has no delete for individual entries.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues