{"_id":"@jim80net/memex-core","_rev":"6-9d90373cbd7084578376d45f45f0dc36","name":"@jim80net/memex-core","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@jim80net/memex-core","version":"0.1.0","license":"MIT","_id":"@jim80net/memex-core@0.1.0","maintainers":[{"name":"jim80net","email":"jim@ramtank.com"}],"dist":{"shasum":"a674646d99bf8f7243b798f8fc2afc6bef38f8cd","tarball":"https://registry.npmjs.org/@jim80net/memex-core/-/memex-core-0.1.0.tgz","fileCount":61,"integrity":"sha512-9/ogL3PwJzZAiijC2eD0pC9n2M3DGos6Gn8AkWoyzetFOsSl++iHT6cQ1tIMpZwKX7bIYe5kNpU6+mCHMVxwbg==","signatures":[{"sig":"MEQCIB9tlONRiI+MGIlfiRifeL6H8AU18U19JnnkSiZ4z5p+AiARAGiKr+AOeoMsLgh4yyT+A/Gm+/zdvqDE2EJ6zZ3XgQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":129482},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"8e2d2dc09640fc3e44c2c0cb8bef12cc9343e0fe","scripts":{"lint":"biome check src/ test/","test":"vitest run","build":"tsc","check":"pnpm lint && pnpm typecheck && pnpm test","lint:fix":"biome check --write src/ test/","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"jim80net","email":"jim@ramtank.com"},"_npmVersion":"10.9.2","description":"Shared core engine for memex skill routers — embeddings, indexing, caching, telemetry","directories":{},"_nodeVersion":"22.17.1","_hasShrinkwrap":false,"packageManager":"pnpm@8.3.1","devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@biomejs/biome":"^2.4.7"},"optionalDependencies":{"@huggingface/transformers":"^3.8.1"},"_npmOperationalInternal":{"tmp":"tmp/memex-core_0.1.0_1773607463389_0.5132943537317187","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@jim80net/memex-core","version":"0.2.2","license":"MIT","_id":"@jim80net/memex-core@0.2.2","maintainers":[{"name":"jim80net","email":"jim@ramtank.com"}],"homepage":"https://github.com/jim80net/memex-core#readme","bugs":{"url":"https://github.com/jim80net/memex-core/issues"},"dist":{"shasum":"845fbda9e08eaf1660b5edc58159ecaa0ba7a75d","tarball":"https://registry.npmjs.org/@jim80net/memex-core/-/memex-core-0.2.2.tgz","fileCount":62,"integrity":"sha512-UudndSTMnOJEJfAIYprtLIdfEGJxEnl6k9rqJeP/ENF0b+y5b+hTUXIywAIPHKx/FElEigTJX/cKh4QgdOpE1g==","signatures":[{"sig":"MEQCIBzmKEJ7c7diMCy0JVG8ahsDvNgoJcYSju0iiNLCLuz7AiAUd/U2mSe5nOdQAFEQTG0HTVDNJSA2RtSKBFs5A4g/Yg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@jim80net%2fmemex-core@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":138054},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"a401d4b01e8ead0006514c90cf136577b7f9602f","scripts":{"lint":"biome check src/ test/","test":"vitest run","build":"tsc","check":"pnpm lint && pnpm typecheck && pnpm test","lint:fix":"biome check --write src/ test/","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5dd2831e-5721-423f-b46e-9b542c240957"}},"repository":{"url":"git+https://github.com/jim80net/memex-core.git","type":"git"},"_npmVersion":"11.11.1","description":"Shared core engine for memex skill routers — embeddings, indexing, caching, telemetry","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"packageManager":"pnpm@8.3.1","devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@biomejs/biome":"^2.4.7"},"optionalDependencies":{"@huggingface/transformers":"^3.8.1"},"_npmOperationalInternal":{"tmp":"tmp/memex-core_0.2.2_1773614250623_0.1058389794116914","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@jim80net/memex-core","version":"0.2.3","license":"MIT","_id":"@jim80net/memex-core@0.2.3","maintainers":[{"name":"jim80net","email":"jim@ramtank.com"}],"homepage":"https://github.com/jim80net/memex-core#readme","bugs":{"url":"https://github.com/jim80net/memex-core/issues"},"dist":{"shasum":"bebd325d328a3b6962b8b551949763c840ef2575","tarball":"https://registry.npmjs.org/@jim80net/memex-core/-/memex-core-0.2.3.tgz","fileCount":62,"integrity":"sha512-NSkXSfYdAMiXqE13KcWw/KOQlBVgW9UCzBN0gmkc3r71iz3hWW+Z2JF6+F0dyb0ciURbIKgbmst0D2cESeeRaQ==","signatures":[{"sig":"MEUCIDD9CJI0+qXZxmbowMXDV9gNV1EUuuCUyNhRr8mTmPTmAiEAjDHcAVzYggEl1NEx8aouw57JTQ+nQThkuVmxNjbqsVE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@jim80net%2fmemex-core@0.2.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":140086},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"1d067bf8dd222907d2fb1014593b8d32eeeee70e","scripts":{"lint":"biome check src/ test/","test":"vitest run","build":"tsc","check":"pnpm lint && pnpm typecheck && pnpm test","lint:fix":"biome check --write src/ test/","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5dd2831e-5721-423f-b46e-9b542c240957"}},"repository":{"url":"git+https://github.com/jim80net/memex-core.git","type":"git"},"_npmVersion":"11.11.1","description":"Shared core engine for memex skill routers — embeddings, indexing, caching, telemetry","directories":{},"_nodeVersion":"22.22.0","_hasShrinkwrap":false,"packageManager":"pnpm@8.3.1","devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@biomejs/biome":"^2.4.7"},"optionalDependencies":{"@huggingface/transformers":"^3.8.1"},"_npmOperationalInternal":{"tmp":"tmp/memex-core_0.2.3_1773639931633_0.8880991291453031","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@jim80net/memex-core","version":"0.3.0","license":"MIT","_id":"@jim80net/memex-core@0.3.0","maintainers":[{"name":"jim80net","email":"jim@ramtank.com"}],"homepage":"https://github.com/jim80net/memex-core#readme","bugs":{"url":"https://github.com/jim80net/memex-core/issues"},"dist":{"shasum":"fd6919a99f98260ddd132a1246cd83deda6860a1","tarball":"https://registry.npmjs.org/@jim80net/memex-core/-/memex-core-0.3.0.tgz","fileCount":62,"integrity":"sha512-cIWbzhKxdM1Xdz4xqKcJk1mcYh5Yeg9Hz+t5Ol9sHHTWNDansIJ2gIKgkw0R8v4GGUf81TVAu+UfDrp4TNKv0A==","signatures":[{"sig":"MEUCIANjYZP/mrTgjfai7TMim4ktNE7B6YShuVDnsy3LnPlTAiEA/IYIBhM/crfDiZ8q0ouq1fsjM3fFnTvuON2rUeEcGKQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@jim80net%2fmemex-core@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":147233},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"6a867352955e10f29ea887353dc79e81b9e30742","scripts":{"lint":"biome check src/ test/","test":"vitest run","build":"tsc","check":"pnpm lint && pnpm typecheck && pnpm test","lint:fix":"biome check --write src/ test/","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5dd2831e-5721-423f-b46e-9b542c240957"}},"repository":{"url":"git+https://github.com/jim80net/memex-core.git","type":"git"},"_npmVersion":"11.11.1","description":"Shared core engine for memex skill routers — embeddings, indexing, caching, telemetry","directories":{},"_nodeVersion":"22.22.0","_hasShrinkwrap":false,"packageManager":"pnpm@8.3.1","devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@biomejs/biome":"^2.4.7"},"optionalDependencies":{"@huggingface/transformers":"^3.8.1"},"_npmOperationalInternal":{"tmp":"tmp/memex-core_0.3.0_1773654206488_0.8263625381028388","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@jim80net/memex-core","version":"0.3.1","license":"MIT","_id":"@jim80net/memex-core@0.3.1","maintainers":[{"name":"jim80net","email":"jim@ramtank.com"}],"homepage":"https://github.com/jim80net/memex-core#readme","bugs":{"url":"https://github.com/jim80net/memex-core/issues"},"dist":{"shasum":"d53b27dd3180273a08373be3cb7c4782be75d197","tarball":"https://registry.npmjs.org/@jim80net/memex-core/-/memex-core-0.3.1.tgz","fileCount":62,"integrity":"sha512-zOmqxMoSohuSS3ozKyQoKqowXwvF5KjEVw8qAuAHWJ1DwKPLsprXqeWokW0LXKAe89FPx3A0wIyKI7UbZEr/Ig==","signatures":[{"sig":"MEUCIQCF+HONADMuo1ElPu7L1UFlex2qbk7zKwkp4/2ogAIsPAIgD7wWEqwX+cWPHHWzU8p1NpkE+xvgcMgmb28nmmksCoU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@jim80net%2fmemex-core@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":147948},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"43c9dda16871ad675cdf4f83c6c73a93d5d107a7","scripts":{"lint":"biome check src/ test/","test":"vitest run","build":"tsc","check":"pnpm lint && pnpm typecheck && pnpm test","lint:fix":"biome check --write src/ test/","typecheck":"tsc --noEmit","prepublishOnly":"pnpm build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5dd2831e-5721-423f-b46e-9b542c240957"}},"repository":{"url":"git+https://github.com/jim80net/memex-core.git","type":"git"},"_npmVersion":"11.11.1","description":"Shared core engine for memex skill routers — embeddings, indexing, caching, telemetry","directories":{},"_nodeVersion":"22.22.1","_hasShrinkwrap":false,"packageManager":"pnpm@8.3.1","devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@biomejs/biome":"^2.4.7"},"optionalDependencies":{"@huggingface/transformers":"^3.8.1"},"_npmOperationalInternal":{"tmp":"tmp/memex-core_0.3.1_1773745811502_0.6529611501347519","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@jim80net/memex-core","version":"0.4.0","description":"Shared core engine for memex skill routers — embeddings, indexing, caching, telemetry","license":"MIT","repository":{"type":"git","url":"git+https://github.com/jim80net/memex-core.git"},"type":"module","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsc","test":"vitest run","typecheck":"tsc --noEmit","lint":"biome check src/ test/","lint:fix":"biome check --write src/ test/","check":"pnpm lint && pnpm typecheck && pnpm test","prepublishOnly":"pnpm build"},"devDependencies":{"@biomejs/biome":"^2.4.7","@types/node":"^22.0.0","typescript":"^5.7.0","vitest":"^3.0.0"},"optionalDependencies":{"@huggingface/transformers":"^3.8.1"},"packageManager":"pnpm@8.3.1","_id":"@jim80net/memex-core@0.4.0","gitHead":"c5d43bece9aab0d213eaf82c196c75fd6f6c0758","bugs":{"url":"https://github.com/jim80net/memex-core/issues"},"homepage":"https://github.com/jim80net/memex-core#readme","_nodeVersion":"22.22.2","_npmVersion":"11.6.0","dist":{"integrity":"sha512-OuY1Ff051w0HlqTQAs5ZYXB4ve7ziPIJ9aVpjs2Qhf5XGJMlf8dkydXhN9jKmvlovfJQkHPPSiPjJQra0icCsA==","shasum":"35a7b83d95c36c23d43339189aa81bd5e0e4edb7","tarball":"https://registry.npmjs.org/@jim80net/memex-core/-/memex-core-0.4.0.tgz","fileCount":70,"unpackedSize":185896,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@jim80net%2fmemex-core@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCqEV8TbJyXlDStp3F7xJ6qgC3m/UhjzQ8LDikrs10h8wIgMqCFUueMnIcT9ZkSeaujmG275CLV9+ESklA3Le3bAkw="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5dd2831e-5721-423f-b46e-9b542c240957"}},"directories":{},"maintainers":[{"name":"jim80net","email":"jim@ramtank.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/memex-core_0.4.0_1775719164518_0.26217163674844834"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-15T20:44:23.329Z","modified":"2026-04-09T07:19:24.905Z","0.1.0":"2026-03-15T20:44:23.544Z","0.2.2":"2026-03-15T22:37:30.797Z","0.2.3":"2026-03-16T05:45:31.783Z","0.3.0":"2026-03-16T09:43:26.640Z","0.3.1":"2026-03-17T11:10:11.647Z","0.4.0":"2026-04-09T07:19:24.651Z"},"bugs":{"url":"https://github.com/jim80net/memex-core/issues"},"license":"MIT","homepage":"https://github.com/jim80net/memex-core#readme","repository":{"type":"git","url":"git+https://github.com/jim80net/memex-core.git"},"description":"Shared core engine for memex skill routers — embeddings, indexing, caching, telemetry","maintainers":[{"name":"jim80net","email":"jim@ramtank.com"}],"readme":"# @jim80net/memex-core\n\nShared core engine for semantic skill, memory, and rule routing in AI agent systems. Provides local embedding generation (via ONNX), a vector-similarity search index, file caching, session tracking, telemetry, cross-device sync, and execution traces -- all with no external API keys required. This package is consumed by platform-specific routers like [memex-claude](https://github.com/jim80net/memex-claude) (Claude Code hooks) and [memex-openclaw](https://github.com/jim80net/memex-openclaw) (OpenClaw plugin).\n\n## Install\n\n```bash\nnpm install @jim80net/memex-core\n# or\npnpm add @jim80net/memex-core\n```\n\nFor local embeddings (recommended), also install the optional ONNX dependency:\n\n```bash\npnpm add @huggingface/transformers\n```\n\n## Quick Start\n\n```typescript\nimport {\n  LocalEmbeddingProvider,\n  SkillIndex,\n  resolveCoreConfig,\n} from \"@jim80net/memex-core\";\n\n// 1. Create an embedding provider\nconst provider = new LocalEmbeddingProvider(\"Xenova/all-MiniLM-L6-v2\", \"/tmp/models\");\n\n// 2. Resolve config (merges your overrides with defaults)\nconst config = resolveCoreConfig({ topK: 5, threshold: 0.35 });\n\n// 3. Build the index\nconst index = new SkillIndex(config, provider, \"/tmp/cache/memex-cache.json\");\nawait index.build({\n  skillDirs: [\"./skills\"],\n  memoryDirs: [\"./memory\"],\n  ruleDirs: [\"./rules\"],\n});\n\n// 4. Search\nconst results = await index.search(\"how do I deploy?\", config.topK, config.threshold);\nfor (const { skill, score, bestQueryIndex } of results) {\n  console.log(`${skill.name} (${skill.type}): ${score.toFixed(3)} [query #${bestQueryIndex}]`);\n  const content = await index.readSkillContent(skill.location);\n  console.log(content);\n}\n```\n\n## Architecture\n\n| Module | Purpose |\n|--------|---------|\n| `embeddings` | `EmbeddingProvider` interface with two implementations: `LocalEmbeddingProvider` (ONNX via `@huggingface/transformers`) and `OpenAIEmbeddingProvider`. Also exports `cosineSimilarity()`. |\n| `skill-index` | `SkillIndex` class -- the main engine. Scans directories for skills, rules, and memories; embeds their queries; caches embeddings; searches by cosine similarity. Also exports `parseFrontmatter()` and `parseMemoryFile()`. |\n| `cache` | Persistent embedding cache (version 2). Loads/saves a JSON file keyed by file location and gated by mtime. |\n| `config` | `DEFAULT_CORE_CONFIG` and `resolveCoreConfig()` for merging partial config with type-safe defaults. |\n| `session` | `SessionTracker` interface and `InMemorySessionTracker` for tracking which rules have been shown per session (graduated disclosure). |\n| `telemetry` | Match telemetry: records how often each skill/rule/memory is matched, across which sessions. Tracks per-query hit counts, observations (ASI from deep-sleep), and generates formatted reports. |\n| `sync` | Git-based cross-device sync: pull with auto-conflict resolution, commit and push local changes. |\n| `traces` | `TraceAccumulator` for recording execution traces (skills injected, tools called, outcome) per session. |\n| `file-lock` | Advisory file locking via `mkdir` (atomic on all platforms). `withFileLock()` for safe concurrent writes. |\n| `path-encoder` | `encodeProjectPath()` -- encodes absolute paths into safe directory names. |\n| `project-mapping` | Resolves a working directory to a canonical project ID (git remote URL, manual mapping, or encoded path fallback). |\n| `project-registry` | Tracks known project directories with `lastSeen` timestamps. |\n| `types` | All TypeScript types and interfaces. |\n| `version` | `VERSION` constant, injected at compile time or defaulting to `\"dev\"`. |\n\n## Key Concepts\n\n### EmbeddingProvider\n\nAn interface with a single method:\n\n```typescript\ninterface EmbeddingProvider {\n  embed(texts: string[]): Promise<number[][]>;\n}\n```\n\nTwo built-in implementations:\n\n- **`LocalEmbeddingProvider`** -- Runs ONNX models locally via `@huggingface/transformers`. No API key needed. Default model: `Xenova/all-MiniLM-L6-v2`. Lazily initializes the model on first call.\n- **`OpenAIEmbeddingProvider`** -- Calls the OpenAI embeddings API. Requires an API key and model name. Batches in groups of 2048.\n\n### SkillIndex\n\nThe central class. Constructed with `(config, provider, cachePath)`.\n\n- **`build(scanDirs)`** -- Scans `skillDirs`, `memoryDirs`, and `ruleDirs` for markdown files. Parses frontmatter, generates embeddings for queries, and caches results. Skips unchanged files (mtime-gated). The consumer constructs the `ScanDirs` object -- no paths are hardcoded.\n- **`search(query, topK, threshold, typeFilter?, scoringMode?, maxDropoff?)`** -- Embeds the query, computes cosine similarity against all indexed entries, applies per-skill `boost`, and returns the top matches. Each result includes `bestQueryIndex` (the index into `skill.queries` that matched best).\n- **`readSkillContent(location)`** -- Reads the body content of a matched skill, stripping frontmatter. Handles memory sections (locations like `path#SectionName`).\n- **`needsRebuild()`** -- Returns `true` if the cache TTL (`cacheTimeMs`) has expired.\n\n### ScanDirs\n\n```typescript\ntype ScanDirs = {\n  skillDirs: string[];   // directories containing skill-name/SKILL.md subdirectories\n  memoryDirs: string[];  // directories containing *.md memory files\n  ruleDirs: string[];    // directories containing *.md rule files\n};\n```\n\nThe consumer builds this from platform-specific paths (e.g., `~/.claude/skills/`, `~/.openclaw/skills/`). This is how the core stays platform-agnostic.\n\n### MemexPaths\n\n```typescript\ntype MemexPaths = {\n  cacheDir: string;\n  modelsDir: string;\n  sessionsDir: string;\n  syncRepoDir: string;\n  projectsDir: string;\n  telemetryPath: string;\n  registryPath: string;\n  tracesDir: string;\n};\n```\n\nA descriptor for all filesystem paths the engine uses. The consumer constructs this and passes individual paths to the relevant functions. The core never assumes path locations.\n\n### Scoring Modes\n\n- **`\"relative\"`** (default) -- If the best match clears the threshold floor, include up to `topK` results that are within `maxDropoff` of the best score. Good for surfacing a cluster of related content.\n- **`\"absolute\"`** -- Each result must individually exceed the threshold. Stricter, but may return fewer results.\n\n### Frontmatter Extensions\n\nSkills and rules use YAML frontmatter with these fields:\n\n```yaml\n---\nname: my-skill\ndescription: What this skill does\ntype: skill          # skill | memory | rule | workflow | session-learning | tool-guidance | stop-rule\nqueries:\n  - \"how do I deploy\"\n  - \"deployment steps\"\nkeywords:\n  - deploy\n  - release\npaths:\n  - \"src/**/*.ts\"\nhooks:\n  - PreToolUse\none-liner: Short reminder text for repeated matches\nboost: 0.05\n---\n```\n\n`queries` and `keywords` are embedded and used for similarity search. `one-liner` is used for graduated disclosure (full content on first match, one-liner on subsequent matches in the same session). `boost` is an optional float added to the raw similarity score before threshold comparison -- use it to nudge skills that are consistently near the threshold boundary.\n\n## Configuration\n\n`resolveCoreConfig()` merges a partial config with these defaults:\n\n| Field | Default | Description |\n|-------|---------|-------------|\n| `enabled` | `true` | Master switch |\n| `embeddingModel` | `\"Xenova/all-MiniLM-L6-v2\"` | Model name for embeddings |\n| `embeddingBackend` | `\"local\"` | `\"local\"` (ONNX) or `\"openai\"` |\n| `cacheTimeMs` | `300000` (5 min) | How long before `needsRebuild()` returns true |\n| `topK` | `3` | Max results per search |\n| `threshold` | `0.35` | Minimum similarity score |\n| `scoringMode` | `\"relative\"` | `\"relative\"` or `\"absolute\"` |\n| `maxDropoff` | `0.1` | Max score gap from best match (relative mode only) |\n| `maxInjectedChars` | `8000` | Character budget for injected context |\n| `types` | `[\"skill\", \"memory\", \"workflow\", \"session-learning\", \"rule\"]` | Which entry types to index |\n| `skillDirs` | `[]` | Additional skill directories |\n| `memoryDirs` | `[]` | Additional memory directories |\n\nConsumers typically extend `MemexCoreConfig` with platform-specific fields (hooks config, sync config, sleep schedule, etc.) and handle file loading themselves.\n\n## Sync\n\nThe `sync` module provides Git-based cross-device sync via `syncPull` and `syncCommitAndPush`. Both accept a `SyncConfig` object.\n\n### Case-insensitive project IDs (default)\n\nProject IDs are lowercased by default across all three resolution paths\n(manual mappings, git remote URLs, and encoded `_local/` path fallbacks).\nA clone of `git@github.com:Jim80Net/Repo.git` and `git@github.com:jim80net/repo.git`\nnow map to the same canonical id: `github.com/jim80net/repo`.\n\nTo preserve the original case, set `caseSensitive: true` in your sync config:\n\n```typescript\nconst syncConfig: SyncConfig = {\n  enabled: true,\n  repo: \"git@github.com:me/memex-sync.git\",\n  autoPull: true,\n  autoCommitPush: true,\n  projectMappings: {},\n  caseSensitive: true, // preserve case as-is\n};\n```\n\nOn first sync after upgrading from a version that wrote mixed-case directories,\n`syncPull` will run a one-shot migration that renames legacy paths to lowercase\nand writes a `.memex-sync/version.json` marker so the scan only runs once. The\nmigration is safe across devices (only runs against post-pull state), idempotent,\nand handles case-insensitive filesystems (macOS APFS, Windows NTFS) correctly.\n\n## Development\n\n```bash\npnpm install --ignore-scripts   # skip onnxruntime postinstall\npnpm test                       # run vitest\npnpm typecheck                  # tsc --noEmit\npnpm lint                       # biome check\npnpm lint:fix                   # biome check --write\npnpm check                      # lint + typecheck + test\npnpm build                      # compile to dist/\n```\n\nNote: `pnpm install` without `--ignore-scripts` may fail because `onnxruntime-node` tries to download CUDA binaries in its postinstall. The ONNX runtime loads at runtime, not install time, so this is safe to skip.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}