npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

oh-my-agentmemory

v0.3.0

Published

opencode plugin enforcing agentmemory proactive use via per-turn directives, slot bootstrap, keyword detection, crystal suggestions, and auto-lesson capture

Readme

oh-my-agentmemory

Make your opencode agent actually use agentmemory.

Companion plugin to agentmemory-capture.ts. Capture already works — this plugin forces the agent to write to memory proactively.

license npm CI opencode agentmemory hooks

English · 한국어


Why

agentmemory ships 54 MCP tools and a rock-solid auto-capture plugin (agentmemory-capture.ts). Sessions get recorded. Semantic memories get generated. Insights get extracted. The read side works.

But the write side stalls:

  • The agent rarely calls memory_save on its own
  • Pinned slots (persona, project_context, user_preferences, tool_guidelines) sit empty for weeks
  • memory_lesson_save is almost never invoked
  • memory_crystallize never fires
  • Users type "remember this" and the agent says "ok" without saving

You can write a rules/memory.md policy file, but the LLM may ignore it. This plugin turns that policy into a per-turn directive the model cannot miss — same pattern as caveman-mode reinforcement, applied to memory hygiene.

Before / after

| Metric (per session) | Without oh-my-agentmemory | With oh-my-agentmemory | |---|---|---| | Pinned slots filled | 0 of 4 | 4 of 4 (auto-bootstrap on session.created) | | memory_save calls | 0 | 1–3 (directive reinforced every turn) | | memory_lesson_save calls | 0 | 2–5 (auto-captured from file history) | | memory_crystallize calls | 0 | occasional (suggested when ≥3 actions done) | | "remember this" actually saved | ~30% | ~90% (keyword detection → directive) |

Numbers are illustrative — actual lift depends on session shape. The learning hook (auto-lesson) is the largest contributor; the enforcement directive is the largest enabler of explicit memory_save calls.


How it works

Six hooks, each owning one slice of the write side. Each has a short purpose name used in OH_AM_DISABLE and a corresponding opencode hook. All coexist with agentmemory-capture.ts (which keeps doing passive observation).

flowchart LR
    subgraph OC[opencode events]
        SC[session.created]
        CM[chat.message]
        ST[system.transform<br/>every LLM turn]
        SI[session.status idle]
        FE[file.edited]
        TU[todo.updated]
    end

    subgraph OH[oh-my-agentmemory]
        INIT[init<br/>bootstrap empty slots]
        INTENT[intent<br/>keyword detection]
        ENF[enforcement<br/>per-turn directive]
        ARCH[archive<br/>crystal suggestion]
        LEARN[learning<br/>auto-lesson from history]
        BRIDGE[bridge<br/>todo → action]
    end

    subgraph AM[agentmemory HTTP API]
        SLOTS[slot / replace]
        OBSERVE[observe]
        LESSON[lesson / save]
        ACT[action / create]
    end

    SC --> INIT --> SLOTS
    CM --> INTENT --> OBSERVE
    ST --> ENF
    SI --> ARCH --> OBSERVE
    FE --> LEARN --> LESSON
    TU --> BRIDGE --> ACT[action / create]
    INTENT -.queued intent.-> ENF
    ARCH -.flag.-> ENF
    INIT -.cache invalidate.-> ENF
    BRIDGE -.done-action count.-> ARCH

| Hook (opencode event) | Purpose | What it does | |---|---|---| | experimental.chat.system.transform | enforcement | Pushes a policy directive into output.system[] every turn. Header + recall rules + write rules + crystal rules + state flags (empty slots, pending keywords, done-action count). Cached per-session to keep the hot path HTTP-free. | | event: session.created | init | Lists slots, finds empties among the four core pinned slots, fills them with templates derived from cwd (project map). Logs a oh_am_bootstrap observation. | | chat.message | intent | Matches user text against bilingual patterns: "remember", "save this", "don't forget", "기억해", "저장해", "잊어". Queues matches for the next directive. | | event: session.status (idle) | archive | When ≥3 actions are done, records a oh_am_crystal_candidate observation. The next directive surfaces the candidate IDs to the LLM. | | event: file.edited | learning | Fetches the file's history, looks for error signals (error, fail, bug, 에러, 실패, …), skips if edit is tiny or no error pattern, dedupes against lesson_recall, then calls lesson/save. 5-min per-file history cache + 60-second per-file debounce. | | event: todo.updated | bridge | Bridges high-priority (priority ≥ 7) todowrite entries into agentmemory actions (tags: from-todo). Medium/low stay session-local. Done high-priority actions feed the archive hook's crystal threshold. |

Sample directive (what the LLM sees every turn)

AGENTMEMORY POLICY ACTIVE. Use agentmemory MCP tools proactively.
Rules below override default behavior.
---
## Recall
• Need past context (recent work, decisions, prior bugs)? Call memory_recall
  or memory_smart_search BEFORE exploring files.
• Pinned slots (persona, project_context, user_preferences, tool_guidelines,
  pending_items, guidance) are auto-injected every turn — do NOT re-recall them.
• Trivial tasks (single-file read, arithmetic, grep) skip memory calls.
## Write
• After architectural or non-obvious technical decisions, call memory_save with
  the decision and concepts.
• Discovered an effective or ineffective approach? Call memory_lesson_save with
  what worked / what to avoid.
• Project structure / build pipeline / new module added? Call memory_slot_replace
  on project_context.
• Unfinished work or follow-up promised? Call memory_slot_replace on pending_items.
• Session about to end with loose ends? Call memory_slot_replace on guidance for
  the next session.
• Never claim 'memory updated' without an actual memory_* tool call in this turn.
## Crystal
• Three or more actions with status=done? Call memory_recall first to check for
  an existing crystal, then memory_crystallize with the done action IDs.
• Fewer than three done actions, or pure exploration with zero file changes →
  skip crystallize.

[STATE] Pinned slots empty: project_context, user_preferences. If session.created
bootstrap missed them, fill via memory_slot_replace before session ends.

[USER INTENT] User said: save:"remember this". Act on it via the matching memory_*
tool this turn.
---
Pinned slots are already in your context — do not re-recall them. Calling memory_*
without an actual tool call in this turn = false report (forbidden).

Edit src/core/policy.ts to retune any rule. The directive is rebuilt automatically from data — no string-surgery required.


Install

1. Prerequisites

  • opencode ≥1.14 (provides the experimental.chat.system.transform hook)
  • agentmemory server running on http://localhost:3111:
    npx @agentmemory/agentmemory
  • Bun only if installing from source (opencode bundles the runtime for npm plugins)

2. Register the plugin (alongside capture.ts)

Add oh-my-agentmemory to ~/.config/opencode/opencode.json — opencode installs it automatically from npm at startup:

{
  "plugin": [
    "./plugins/agentmemory-capture.ts",
    "oh-my-agentmemory"
  ]
}

Keep agentmemory-capture.ts — this plugin is write-side only and depends on capture.ts continuing to observe.

3. (Optional) Install slash commands

mkdir -p ~/.config/opencode/commands
for f in am-recall am-save am-bootstrap am-status; do
  curl -fsSL "https://raw.githubusercontent.com/dev-hann/oh-my-agentmemory/main/src/adapters/opencode/commands/${f}.md" \
       -o ~/.config/opencode/commands/${f}.md
done

4. (Optional) Create a config file

Defaults work out of the box (localhost agentmemory, auto mode). For persistent settings — remote server, custom project map, health-check tuning — create ~/.config/opencode/oh-am.jsonc:

// start from the full annotated reference:
// https://github.com/dev-hann/oh-my-agentmemory/blob/main/examples/oh-am.full.jsonc

See Configuration for the full schema.

5. Restart opencode

Verify with /am-status — it should report pinned slots filled.

git clone https://github.com/dev-hann/oh-my-agentmemory.git ~/Documents/oh-my-agentmemory
cd ~/Documents/oh-my-agentmemory && bun install
ln -sfn ~/Documents/oh-my-agentmemory/src/adapters/opencode \
        ~/.config/opencode/plugins/oh-my-agentmemory

Then register "./plugins/oh-my-agentmemory/plugin.ts" instead of the npm package name in opencode.json.


jcode support

The same write-side enforcement runs on jcode via its lifecycle hooks — no opencode required.

scripts/install-jcode.sh            # install / update
scripts/install-jcode.sh --remove   # uninstall

What it installs:

  • Hook entry + feedback scripts in ~/.jcode/plugins/oh-am/
  • Lifecycle hooks in ~/.jcode/config.toml ([hooks] array values): session_start → init, post_tool → learning + bridge, turn_end → archive, session_end → cleanup, post_tool_feedback → throttled reminder
  • The policy overlay at ~/.jcode/overlays/oh-am.md, registered under [prompt] overlay_files (requires jcode with configurable overlay files)
  • The agentmemory MCP server in ~/.jcode/mcp.json (same npx @agentmemory/mcp command as the opencode config)
  • ~/.jcode/oh-am.jsonc with defaults if absent (falls back to the opencode config when missing)

Phase coverage differs slightly from opencode: intent (user-prompt keyword detection) is delegated to the overlay policy — jcode has no per-message hook — and enforcement is handled by the overlay plus a throttled post_tool_feedback reminder rather than a per-turn system-prompt transform. The installer is idempotent; re-running updates the scripts without duplicating config entries.


Slash commands

| Command | Action | |---|---| | /am-recall <query> | Search past observations + lessons via memory_recall | | /am-save <text> | Save an insight to long-term memory via memory_save | | /am-bootstrap | Force re-bootstrap empty slots right now (use when cwd project detection was wrong) | | /am-status | Show slot fill state + recent sessions + latest lessons + crystal candidates |


Configuration

Three layers, in descending precedence:

  1. Process env vars (override everything for one-shot runs / CI)
  2. ~/.config/opencode/oh-am.jsonc (persistent settings, JSONC = comments allowed)
  3. Built-in defaults (see src/core/config-types.ts)

Env vars (one-shot overrides)

| Var | Default | Effect | |---|---|---| | AGENTMEMORY_URL | http://localhost:3111 | agentmemory server base URL | | AGENTMEMORY_SECRET | "" | Bearer token if auth enabled on server | | OH_AM_MODE | auto | auto | full | mcp-only | | OH_AM_DISABLE | "" | Comma-list of purpose names to disable: enforcement, init, intent, archive, learning | | OH_AM_COMPACTION | 0 | Set to 1 to force-enable observation compaction for one run (see "Observation compaction") | | OH_AM_COMPACTION_DELETE | — | off is the deletion emergency brake (reports still written); see "Observation compaction" | | OH_AM_DEBUG | 0 | Set to 1 for verbose stderr logging |

Example: OH_AM_DEBUG=1 OH_AM_DISABLE=learning opencode

Config file (persistent)

Create ~/.config/opencode/oh-am.jsonc:

{
  // agentmemory server
  "url": "http://localhost:3111",
  "secret": "",

  // operating mode: "auto" | "full" | "mcp-only"
  "mode": "auto",

  // purpose names to disable
  "disabled": ["learning"],

  // extend built-in project map without code edit (always prepended)
  "projectMap": [
    {
      "match": "my-new-project",
      "projectId": "mnp",
      "displayName": "My New Project",
      "stack": ["Go", "Postgres"]
    }
  ],

  // health check on plugin init
  "healthCheckOnBoot": true,
  "healthCheckTimeoutMs": 2000,
  "healthCheckFatal": false,

  // stale session GC (agentmemory-side only; see "Stale session GC")
  "sessionGc": {
    "enabled": true,
    "maxAgeDays": 7
  },

  // observation compaction (see "Observation compaction")
  "compaction": {
    "enabled": false,
    "baseUrl": "http://127.0.0.1:8017",
    "keepThreshold": 0.35,
    "importanceGuard": 2
  },

  // verbose stderr logging
  "debug": false
}

Full reference with every field documented: examples/oh-am.full.jsonc.

MCP-only mode

Set "mode": "mcp-only" (or OH_AM_MODE=mcp-only) when running without agentmemory-capture.ts — e.g. on Cursor, Claude Desktop, or a second machine that only consumes a shared agentmemory instance.

In this mode:

  • learning and archive hooks skip entirely (their data sources — file history, done actions — are empty without capture.ts)
  • enforcement directive gains a stronger banner warning the LLM that no auto-capture is running, and the write responsibilities shift to it entirely

Auto-detection ("mode": "auto") probes the agentmemory server on first session.created; if recent sessions average <5 observations each it switches to mcp-only. Set explicitly to skip the probe.

Health check

By default, the plugin pings ${url}/agentmemory/health on init. If unreachable:

  • Default (healthCheckFatal: false): logs a warning, continues running (hooks will silently fail their HTTP calls)
  • healthCheckFatal: true: plugin returns no hooks, effectively disabled

Stale session GC

"sessionGc": { "enabled": true, "maxAgeDays": 7 } runs a one-shot sweep on plugin boot that ends agentmemory sessions sitting active with no updates for more than 7 days. This is agentmemory bookkeeping only — the opencode chat session on disk is never touched. If a prompt later arrives for an ended session (the user resumed an old conversation), the record is automatically reactivated. When the sweep ends sessions, a TUI toast shows the count (best-effort; headless runs skip it silently).

Observation compaction

"compaction": { "enabled": true } cleans a session's observations when it goes idle, using a two-layer filter:

Layer 1 — structural (no model). Empty observations (no title and no narrative, older than a 5-minute enrichment grace) and lifecycle telemetry types (config_loaded, llm_params, step_finish) are dropped outright without calling jev. A 3,274-observation benchmark showed ~85% of noise is identifiable this way, and jev returns a uniform 0.512 on empty state that no threshold can filter.

Layer 2 — jev. Everything else is scored by a local jevos decision model (a Jev-compatible System One server, default http://127.0.0.1:8017):

  • keep iff keep_call >= 0.35 OR importance >= 2
  • Cross-validated by full LLM re-judgment of 3,274 observations across 26 sessions: false-drop 0 (jev never dropped something the LLM kept), all 81 jev drops confirmed as lifecycle-hook noise

Deletion. Drop verdicts are deleted for real via the audit-logged agentmemory forget route, the report is stamped with deletedAt, and the session summary is regenerated so it no longer references deleted noise. Dropped verdicts carry a content snapshot (title + ~500-char excerpt) for post-deletion audit and manual re-ingest if ever needed. Guarded (importance >= 2) verdicts are never deleted. A failed delete leaves the report unmarked so the next run (idle or GC sweep) retries.

Stale session GC hookup. The boot-time sweep runs the same pipeline for stale sessions the idle hook missed (crashed or abandoned), skipping sessions that already have a report — historical noise cleans itself up over time.

Controls.

  • Deletion runs whenever compaction is enabled — there is no separate config toggle
  • OH_AM_COMPACTION_DELETE=off — emergency brake that stops deletion (reports are still written); disable compaction.enabled to stop scoring as well
  • Scoring errors default to keep (conservative); if jevos is entirely unreachable the compaction step is skipped entirely
  • Reports live at ~/.local/share/oh-am/compaction/<sessionId>.json

Architecture

Hexagonal (ports & adapters). The core/ layer is pure TypeScript with zero I/O — easy to unit-test, easy to port to other agents later.

oh-my-agentmemory/
├── src/
│   ├── core/                       # agent-agnostic, pure TS, no I/O
│   │   ├── directives.ts           # buildDirective(ctx) → string
│   │   ├── bootstrap.ts            # SLOT_TEMPLATES + detectProject(cwd)
│   │   ├── keywords.ts             # pattern loader + matchKeywords()
│   │   ├── lessons.ts              # buildLessonFromFileHistory() → LessonCandidate
│   │   ├── policy.ts               # rules/memory.md encoded as data
│   │   ├── config-types.ts         # OhAmConfig + ResolvedConfig types
│   │   └── types.ts                # shared types
│   │
│   ├── data/                       # locale-keyed keyword / signal data
│   │   ├── keywords.ts             # save / forget / recall patterns per locale
│   │   └── error-signals.ts        # error keywords per locale (lessons filter)
│   │
│   └── adapters/
│       └── opencode/               # current; claude-code/codex later
│           ├── plugin.ts           # single entry, registers all hooks
│           ├── config.ts           # JSONC parser + env/file/default merge
│           ├── mode.ts             # auto-detect full vs mcp-only
│           ├── client.ts           # agentmemory HTTP wrapper
│           ├── hooks/
│           │   ├── _shared.ts      # isPhaseDisabled / isMcpOnly helpers
│           │   ├── system-transform.ts   # enforcement
│           │   ├── session-created.ts    # init
│           │   ├── chat-message.ts       # intent
│           │   ├── session-idle.ts       # archive
│           │   └── file-edited.ts        # learning
│           └── commands/
│               ├── am-recall.md
│               ├── am-save.md
│               ├── am-bootstrap.md
│               └── am-status.md
│
├── examples/
│   └── oh-am.full.jsonc            # complete config reference
│
└── tests/
    ├── core/                       # unit tests (no network)
    │   ├── directives.test.ts
    │   ├── keywords.test.ts
    │   ├── bootstrap.test.ts
    │   └── mcp-only.test.ts
    └── adapters/
        └── config.test.ts          # JSONC parse + mergeConfig

Future agents

adapters/claude-code/ and adapters/codex/ will reuse core/ unchanged — only the hook glue differs. The hexagonal split keeps the porting cost down to "write one adapter file per agent."


Testing

bun install
bun run test            # vitest, 72 tests, ~350ms
bun run typecheck       # tsc --noEmit, strict mode

All tests target core/ and the JSONC config layer — pure functions, deterministic, no network. Adapter behavior is verified manually against a running agentmemory server.


Comparison

| | Built-in (CLAUDE.md / rules/) | agentmemory-capture.ts | oh-my-agentmemory | |---|---|---|---| | Layer | Static policy file | Plugin (read side) | Plugin (write side) | | Captures observations | No | Yes (22+ hooks) | No (capture.ts does it) | | Forces LLM to call memory_save | Honor system | No | Yes (per-turn directive) | | Fills empty slots | No | No | Yes (cwd-based bootstrap) | | Reacts to "remember" / "기억해" | No | No | Yes (keyword detection) | | Auto-saves lessons from bug history | No | No | Yes (file.edited hook) | | Suggests memory_crystallize | No | No | Yes (idle + done ≥3) | | Config file | n/a | env vars only | oh-am.jsonc (JSONC) + env vars | | Profiles (multi-instance switch) | n/a | No | No | | MCP-only mode branching | n/a | No | Yes (auto-detect or explicit) | | Health check on init | n/a | No | Yes (optional self-disable) | | Cloud dependency | None | None | None | | Cost | $0 | $0 | $0 |

This plugin is complementary, not competitive, with capture.ts. Disable either one and you lose half the loop.

vs opencode-supermemory

opencode-supermemory is the right choice if you want cloud-hosted memory, Notion/Drive connectors, auto user-profiles, and a one-line install.

oh-my-agentmemory is the right choice if you:

  • Already run agentmemory locally and have invested in 50+ sessions of data
  • Want to keep everything self-hosted (no cloud, no API keys)
  • Need agentmemory's 54-MCP-tool surface (slots, lessons, crystals, actions, insights, consolidation pipeline) rather than supermemory's 3
  • Prefer "directive reinforcement" over "automatic API-side extraction"

Both plugins can coexist — they push to different memory systems.


Troubleshooting

  1. Confirm plugin loaded: check opencode logs for [oh-am] plugin loaded (with OH_AM_DEBUG=1 or debug: true in config)
  2. Confirm opencode.json has both entries (capture.ts AND oh-my-am/plugin.ts)
  3. Confirm symlink target exists: ls -la ~/.config/opencode/plugins/oh-my-agentmemory/plugin.ts
  4. Confirm agentmemory server is up: curl http://localhost:3111/agentmemory/health — or set "healthCheckOnBoot": true, "healthCheckFatal": false to see the warning on plugin init
  5. Confirm enforcement is not disabled via OH_AM_DISABLE=enforcement env var or "disabled": ["enforcement"] in oh-am.jsonc
  1. Run /am-bootstrap to force re-bootstrap and see proposed content
  2. Check stderr with OH_AM_DEBUG=1 (or "debug": true in config) for [oh-am] bootstrap filled N/N slots
  3. If detection picks the wrong project, either:
    • Add your cwd to PROJECT_MAP in src/core/bootstrap.ts, or
    • Add an entry to projectMap in ~/.config/opencode/oh-am.jsonc (no code edit needed)
  4. The init hook may be disabled via OH_AM_DISABLE=init env var or "disabled": ["init"] in config

The learning hook is conservative by default — it requires both an error signal in file history AND a meaningful edit size. If still too noisy:

  1. Disable temporarily:
    • Env: OH_AM_DISABLE=learning opencode
    • Config: "disabled": ["learning"] in oh-am.jsonc
  2. Tune filters in src/core/lessons.ts:
    • Raise MIN_EDIT_LINES (default 5)
    • Add exclude patterns to skip test files or generated code
    • Edit src/data/error-signals.ts to expand or narrow error keywords

The directive body is ~600 tokens. To shrink:

  1. Edit src/core/policy.ts to shorten rule texts (or drop sections by removing entries from RECALL_POLICY / WRITE_POLICY / CRYSTAL_POLICY)
  2. Or use compact mode by editing system-transform.ts to call buildDirective(ctx, { compact: true }) — this drops the rule bodies and keeps only state/keyword lines

opencode runs all plugins' hooks in sequence. Multiple plugins can push to output.system[] without conflict — caveman pushes its reinforcement line, oh-my-am pushes its directive, both reach the LLM.


Development

git clone https://github.com/dev-hann/oh-my-agentmemory.git
cd oh-my-agentmemory
bun install
bun run test         # 35 unit tests
bun run typecheck    # strict TS

The core/ layer has no I/O — every function is testable in isolation. Adapter tests require a running agentmemory server.

Roadmap

  • Skill layer — using-agentmemory opencode Skill (auto-loaded by opencode when relevant, stronger than directive)
  • Claude Code adapter — adapters/claude-code/ (.claude/settings.json hook scripts that invoke core/)
  • Codex adapter — adapters/codex/ (Codex hook format)

Contributions welcome. Open an issue first to discuss scope.

Releasing

npm publishing happens only via GitHub Actions (.github/workflows/publish.yml) — never npm publish from a laptop. It uses OIDC trusted publishing, so no npm token is involved anywhere.

The workflow triggers on tag push only (v*). Pushing to main does nothing by itself — CI runs tests, but no release.

# 1. bump "version" in package.json
# 2. add the release section to CHANGELOG.md
# 3. commit both to main and push
git checkout main
git add package.json CHANGELOG.md
git commit -m "chore(release): vX.Y.Z"
git push origin main

# 4. tag and push the tag — this triggers the Publish workflow
git tag vX.Y.Z main
git push origin vX.Y.Z

Verify: the Publish workflow succeeds under Actions, then npm view oh-my-agentmemory version shows the new version.


Uninstall

# Remove "oh-my-agentmemory" from opencode.json plugin[]
rm -rf ~/.cache/opencode/node_modules/oh-my-agentmemory
rm ~/.config/opencode/commands/am-{recall,save,bootstrap,status}.md

Your agentmemory data is untouched — only the directive plugin is removed.


License

MIT © dev-hann

Acknowledgments

  • agentmemory — the memory engine this plugin drives
  • agentmemory-capture.ts — the canonical observer plugin this complements
  • opencode-supermemory — reference implementation for keyword detection and reasoned-recall directive patterns
  • caveman — reference implementation for per-turn system.transform reinforcement