{"_id":"@aman_asmuei/aman-core","_rev":"4-779f73a8fe2fcda5fa28aaa15affd73b","name":"@aman_asmuei/aman-core","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.0":{"name":"@aman_asmuei/aman-core","version":"0.2.0","keywords":["aman","scope","multi-tenant","storage","ai-companion","ecosystem"],"author":{"name":"Aman Asmuei"},"license":"MIT","_id":"@aman_asmuei/aman-core@0.2.0","maintainers":[{"name":"aman_asmuei","email":"amanasmuei@gmail.com"}],"homepage":"https://github.com/amanasmuei/aman-core#readme","bugs":{"url":"https://github.com/amanasmuei/aman-core/issues"},"dist":{"shasum":"3df09f55fb0001e4e4cc4d1683b36e20c1e8dcd8","tarball":"https://registry.npmjs.org/@aman_asmuei/aman-core/-/aman-core-0.2.0.tgz","fileCount":31,"integrity":"sha512-Cmim9VZuNvbdJpTlviw8ooIGAHvTlEJh5B3MUtfU3jMWpBeqOfbfP5CHJJU+tMwC4YN7A5saS96Z1GkfDLbU+A==","signatures":[{"sig":"MEUCIHR+89YSQWQnG/4umb0NYOYJR7SgRpAj1adZfkaWvnExAiEAttAKVmGyZIMkri7ztt0mk0/5gTW2B3HOporG39gAAa4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":74268},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"e023cd530b9774cb0efa8854ac0cfa8cf93ba453","scripts":{"dev":"tsc --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsc","prepare":"npm run build","test:watch":"vitest"},"_npmUser":{"name":"aman_asmuei","email":"amanasmuei@gmail.com"},"repository":{"url":"git+https://github.com/amanasmuei/aman-core.git","type":"git"},"_npmVersion":"10.9.7","description":"Shared substrate for the aman ecosystem — Scope, Storage<T> interface, MarkdownFileStorage and DatabaseStorage backends, AsyncLocalStorage propagation, paths, and migration helpers.","directories":{},"_nodeVersion":"22.22.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@types/better-sqlite3":"^7.6.0"},"optionalDependencies":{"better-sqlite3":"^12.0.0"},"_npmOperationalInternal":{"tmp":"tmp/aman-core_0.2.0_1775555175518_0.30962001598399636","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Superseded by the aman-agentic package (npx -p aman-agentic aman-mcp / aman). Source: github.com/amanasmuei/aman-substrate"},"0.2.1":{"name":"@aman_asmuei/aman-core","version":"0.2.1","keywords":["aman","scope","multi-tenant","storage","ai-companion","ecosystem"],"author":{"name":"Aman Asmuei"},"license":"MIT","_id":"@aman_asmuei/aman-core@0.2.1","maintainers":[{"name":"aman_asmuei","email":"amanasmuei@gmail.com"}],"homepage":"https://github.com/amanasmuei/aman-core#readme","bugs":{"url":"https://github.com/amanasmuei/aman-core/issues"},"dist":{"shasum":"d842e61cb2ab39a90476731d4b29d60e14fa4207","tarball":"https://registry.npmjs.org/@aman_asmuei/aman-core/-/aman-core-0.2.1.tgz","fileCount":31,"integrity":"sha512-oV9I5k2IYc0GG078M9t+vzRQRPMny8I0ABDCLukwRI8GxataYteURi9QfsIwHnM7b53vqBCej67YcEcJE+MokQ==","signatures":[{"sig":"MEUCIQDKr+MdJs+OxvjvLkn/rIClxrp7ddAXKXxez9X45VlBeQIgGTR4oItJ4IujkRPWLoGfuyMb2qohKc6QMncqYh2kVLI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":74445},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"2663f02c462a5c490cbb316fb3ceb8d58d4429e8","scripts":{"dev":"tsc --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsc","prepare":"npm run build","test:watch":"vitest"},"_npmUser":{"name":"aman_asmuei","email":"amanasmuei@gmail.com"},"repository":{"url":"git+https://github.com/amanasmuei/aman-core.git","type":"git"},"_npmVersion":"10.9.7","description":"Shared substrate for the aman ecosystem — Scope, Storage<T> interface, MarkdownFileStorage and DatabaseStorage backends, AsyncLocalStorage propagation, paths, and migration helpers.","directories":{},"_nodeVersion":"22.22.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@types/better-sqlite3":"^7.6.0"},"optionalDependencies":{"better-sqlite3":"^12.0.0"},"_npmOperationalInternal":{"tmp":"tmp/aman-core_0.2.1_1775577998245_0.12550068180823337","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Superseded by the aman-agentic package (npx -p aman-agentic aman-mcp / aman). Source: github.com/amanasmuei/aman-substrate"},"0.3.0":{"name":"@aman_asmuei/aman-core","version":"0.3.0","keywords":["aman","scope","multi-tenant","storage","ai-companion","ecosystem"],"author":{"name":"Aman Asmuei"},"license":"MIT","_id":"@aman_asmuei/aman-core@0.3.0","maintainers":[{"name":"aman_asmuei","email":"amanasmuei@gmail.com"}],"homepage":"https://github.com/amanasmuei/aman-core#readme","bugs":{"url":"https://github.com/amanasmuei/aman-core/issues"},"dist":{"shasum":"127a5f0346f59b447b0e5995c5b9f9d9e303b5f4","tarball":"https://registry.npmjs.org/@aman_asmuei/aman-core/-/aman-core-0.3.0.tgz","fileCount":31,"integrity":"sha512-dOJFjvl93Xt0rH/cijohmiYRJuPMYGez6uWLn8Vldg4Mp4fTDHqeBZ8I0MJS/QfsCHZmfmWGNjaLua/s6WOe4w==","signatures":[{"sig":"MEYCIQD6wzNPptrhEpZifnmVBFFmJq4RUcQ+Kzg44bCkjKgsDAIhAPfk9O3aR/U21+YoOB4dxgy/Aj08KMi8RDlCdeejYz09","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":81688},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"8aaf222c06380017facb315bcfa9f9b921fa11fc","scripts":{"dev":"tsc --watch","lint":"tsc --noEmit","test":"vitest run","build":"tsc","prepare":"npm run build","test:watch":"vitest"},"_npmUser":{"name":"aman_asmuei","email":"amanasmuei@gmail.com"},"repository":{"url":"git+https://github.com/amanasmuei/aman-core.git","type":"git"},"_npmVersion":"10.9.7","description":"Shared substrate for the aman ecosystem — Scope, Storage<T> interface, MarkdownFileStorage and DatabaseStorage backends, AsyncLocalStorage propagation, paths, and migration helpers.","directories":{},"_nodeVersion":"22.22.2","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@types/better-sqlite3":"^7.6.0"},"optionalDependencies":{"better-sqlite3":"^12.0.0"},"_npmOperationalInternal":{"tmp":"tmp/aman-core_0.3.0_1775745117908_0.5140759067006093","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Superseded by the aman-agentic package (npx -p aman-agentic aman-mcp / aman). Source: github.com/amanasmuei/aman-substrate"}},"time":{"created":"2026-04-07T09:46:15.330Z","modified":"2026-06-10T08:37:26.391Z","0.2.0":"2026-04-07T09:46:15.657Z","0.2.1":"2026-04-07T16:06:38.417Z","0.3.0":"2026-04-09T14:31:58.060Z"},"bugs":{"url":"https://github.com/amanasmuei/aman-core/issues"},"author":{"name":"Aman Asmuei"},"license":"MIT","homepage":"https://github.com/amanasmuei/aman-core#readme","keywords":["aman","scope","multi-tenant","storage","ai-companion","ecosystem"],"repository":{"url":"git+https://github.com/amanasmuei/aman-core.git","type":"git"},"description":"Shared substrate for the aman ecosystem — Scope, Storage<T> interface, MarkdownFileStorage and DatabaseStorage backends, AsyncLocalStorage propagation, paths, and migration helpers.","maintainers":[{"name":"aman_asmuei","email":"amanasmuei@gmail.com"}],"readme":"<div align=\"center\">\n\n# @aman_asmuei/aman-core\n\n**The shared substrate for the aman ecosystem.**\n\nMulti-tenant `Scope`, generic `Storage<T>`, and `AsyncLocalStorage` propagation —\nthe foundation for building MCP-native AI companions that remember every user\nseparately, without threading scope through every function signature.\n\n[![npm version](https://img.shields.io/npm/v/@aman_asmuei/aman-core?style=for-the-badge&logo=npm&logoColor=white&color=cb3837)](https://www.npmjs.com/package/@aman_asmuei/aman-core)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](LICENSE)\n[![Node ≥18](https://img.shields.io/badge/node-%E2%89%A518-brightgreen?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org)\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org)\n[![Tests](https://img.shields.io/badge/tests-74_passing-brightgreen?style=for-the-badge)](#quality-signals)\n[![Part of aman](https://img.shields.io/badge/part_of-aman_ecosystem-ff6b35?style=for-the-badge)](https://github.com/amanasmuei/aman)\n\n[Install](#install) &middot;\n[Quick start](#quick-start) &middot;\n[Concepts](#concepts) &middot;\n[API reference](#api-reference) &middot;\n[Architecture](#architecture) &middot;\n[The aman ecosystem](#the-aman-ecosystem)\n\n</div>\n\n---\n\n## What it is\n\n`aman-core` is the foundation layer of the aman engine. It provides three things,\nand only three things:\n\n1. **`Scope`** — a string convention for multi-tenant addressing\n2. **`Storage<T>`** — a generic interface for layer libraries to implement, plus two ready-to-use backends\n3. **`withScope()`** — `AsyncLocalStorage` propagation so layer code reads scope implicitly\n\nThat's it. No business logic. No LLM clients. No MCP servers. No databases.\nIt is intentionally tiny, focused, and stable — every other aman layer\n(`acore-core`, `arules-core`, future `aflow-core`, etc.) sits on top of it.\n\n---\n\n## Why it exists\n\nThe aman ecosystem is built on a single architectural bet:\n\n> **One engine, three frontends.**\n>\n> The same engine code should serve a developer in Claude Code, a CLI session\n> in their terminal, and thousands of Telegram users in production — with\n> complete state isolation between them, and without any layer library\n> needing to know which one it's running in.\n\nThat bet is impossible without a coherent, propagated, multi-tenant identity\nsystem. `aman-core` is that identity system. Every memory, every rule,\nevery identity record across the aman ecosystem is keyed by a `Scope`, and\nevery layer call automatically picks up the active scope from\n`AsyncLocalStorage` instead of threading it through every function\nsignature.\n\nThe result: a memory you store via the CLI shows up in Claude Code. A rule\nyou write for `dev:plugin` doesn't bleed into `dev:agent`. A Telegram user\nat `tg:12345` and another at `tg:67890` get complete state isolation\neven when their requests interleave on the same server. **Same code path,\ndifferent scope, no leakage.**\n\n---\n\n## Install\n\n```bash\nnpm install @aman_asmuei/aman-core\n```\n\n`aman-core` has **zero runtime dependencies** by design. It uses Node's\nbuilt-in `node:async_hooks`, `node:fs`, `node:path`, and `node:os`. The only\noptional dependency is `better-sqlite3` (loaded lazily, only if you use\n`DatabaseStorage` or run the legacy migration helper).\n\n---\n\n## Quick start\n\n```typescript\nimport {\n  withScope,\n  getCurrentScope,\n  parseScope,\n  formatScope,\n  MarkdownFileStorage,\n  DatabaseStorage,\n  type Storage,\n} from \"@aman_asmuei/aman-core\";\n\n// 1. Hosts wrap their per-session entry points in withScope.\n//    Inside, layer code reads the scope implicitly.\nawait withScope(\"tg:user-12345\", async () => {\n  // Anywhere in this async tree — even inside libraries you import —\n  // calls to getCurrentScope() return \"tg:user-12345\"\n  const scope = getCurrentScope(); // \"tg:user-12345\"\n\n  // ... your layer libraries do their thing here\n});\n\n// 2. Two parallel sessions don't bleed across each other\nawait Promise.all([\n  withScope(\"tg:alice\", async () => {\n    /* Alice's data only */\n  }),\n  withScope(\"tg:bob\", async () => {\n    /* Bob's data only */\n  }),\n]);\n\n// 3. Layer libraries pick a Storage<T> backend by scope prefix\nconst identityStorage = new MarkdownFileStorage<Identity>({\n  root: `${process.env.HOME}/.acore`,\n  filename: \"core.md\",\n  serialize: (i) => i.content,\n  deserialize: (raw) => ({ content: raw }),\n});\n\nawait identityStorage.put(\"dev:default\", { content: \"# Aman\\n...\" });\nconst identity = await identityStorage.get(\"dev:default\");\n// → reads ~/.acore/dev/default/core.md\n\nawait identityStorage.put(\"tg:user-12345\", { content: \"...\" });\n// → writes ~/.acore/tg/user-12345/core.md (different scope, different file)\n```\n\nThat's the whole package, in 30 seconds.\n\n---\n\n## Concepts\n\n### Scope — a colon-delimited string\n\nA `Scope` is a string identifying *who* and *where* in the ecosystem.\nThe format is intentionally simple:\n\n```\n<frontend>:<id>[:<sub>...]\n```\n\n| Scope                       | Tenant       | Context              | Used by                          |\n|----------------------------|--------------|----------------------|----------------------------------|\n| `dev:default`              | local dev    | default              | acore CLI, single-user fallback  |\n| `dev:agent`                | local dev    | aman-agent runtime   | aman-agent CLI sessions          |\n| `dev:plugin`               | local dev    | Claude Code plugin   | aman-plugin / aman-mcp           |\n| `dev:cli`                  | local dev    | generic CLI          | one-off scripts                  |\n| `tg:12345`                 | Telegram 12345 | (unset)            | aman-tg per-user data            |\n| `agent:jiran`              | (none)       | jiran agent persona  | shared agent personality records |\n| `tg:12345:agent:jiran`     | TG 12345     | jiran-for-this-user  | per-user agent customization     |\n\n**Why a string and not a struct?** Three reasons:\n\n1. **Backward compatibility.** `aman-tg` already uses `tg:${telegramId}` in\n   production. A string format means zero migration on day one.\n2. **Wire-format stability.** Strings serialize through MCP request metadata,\n   HTTP headers, and database columns without any conversion.\n3. **Simplicity.** Two segments handle 99% of cases. The N-segment form\n   handles the rest. No nested-object validation, no schema versioning.\n\nIf you need the components, parse it:\n\n```typescript\nparseScope(\"tg:12345:agent:jiran\");\n// → {\n//     frontend: \"tg\",\n//     id: \"12345\",\n//     parts: [\"tg\", \"12345\", \"agent\", \"jiran\"],\n//     raw: \"tg:12345:agent:jiran\"\n//   }\n\nformatScope({ frontend: \"tg\", id: \"12345\", sub: [\"agent\", \"jiran\"] });\n// → \"tg:12345:agent:jiran\"\n```\n\nLegacy strings (from before this convention) are normalized automatically:\n\n```typescript\nnormalizeLegacyScope(\"global\");      // → \"dev:default\"\nnormalizeLegacyScope(\"myproject\");   // → \"dev:myproject\"\nnormalizeLegacyScope(\"tg:12345\");    // → \"tg:12345\"  (already canonical)\nnormalizeLegacyScope(null);          // → \"dev:default\"\n```\n\n### withScope — AsyncLocalStorage propagation\n\nThe killer feature. Hosts wrap their per-session entry points once, and every\nlayer call inside reads the scope implicitly — no parameter threading.\n\n```typescript\nimport { withScope, getCurrentScope } from \"@aman_asmuei/aman-core\";\n\n// In aman-plugin (Claude Code host):\nawait withScope(\"dev:plugin\", async () => {\n  // Every call inside here sees scope = \"dev:plugin\"\n  await amem.recall(\"what do i know about pnpm\");\n  await acore.getIdentity();\n  await arules.checkAction(\"rm -rf /\");\n});\n\n// In aman-tg backend (Telegram bot):\nbot.on(\"message\", async (ctx) => {\n  const scope = `tg:${ctx.from.id}`;\n  await withScope(scope, async () => {\n    // Jiran sees ONLY this user's memories, identity, and rules\n    const reply = await jiran.chat(ctx.message.text);\n    await ctx.reply(reply);\n  });\n});\n```\n\nScope propagates correctly across:\n- `await` boundaries (`Promise.all`, `setTimeout`, callbacks)\n- Nested `withScope()` blocks (inner overrides outer, outer restores after)\n- Concurrent sessions (two `withScope()` calls in parallel never bleed)\n\nIf you call `getCurrentScope()` outside any `withScope` block, it throws.\nUse `getCurrentScopeOr(fallback)` if you want a default instead.\n\n### Storage&lt;T&gt; — the generic interface\n\nEvery layer library implements its records via this interface, parameterized\nby its own record type:\n\n```typescript\ninterface Storage<T> {\n  get(scope: Scope): Promise<T | null>;\n  put(scope: Scope, value: T): Promise<void>;\n  patch(scope: Scope, partial: Partial<T>): Promise<void>;\n  delete(scope: Scope): Promise<void>;\n  listScopes(): Promise<Scope[]>;\n}\n```\n\nTwo production-ready backends ship with `aman-core`:\n\n| Backend                  | Best for                          | Where it persists                                 |\n|-------------------------|-----------------------------------|---------------------------------------------------|\n| `MarkdownFileStorage<T>` | Dev-side (`dev:*`) — human-edited | `{root}/{scopeToPath(scope)}/{filename}` on disk  |\n| `DatabaseStorage<T>`     | Server / multi-tenant — programmatic | SQLite (or Postgres later) table keyed by scope |\n\nBoth implement the same `Storage<T>` interface. Layer libraries pick at runtime:\n\n```typescript\nfunction getStorageForScope(scope: string): Storage<Identity> {\n  return parseScope(scope).frontend === \"dev\"\n    ? markdownStorage   // human-editable\n    : databaseStorage;  // multi-tenant\n}\n```\n\nThat's the *whole* multi-tenant story. Pick by prefix, store by scope.\n\n---\n\n## API reference\n\n### Scope helpers\n\n| Symbol                          | Type        | Purpose                                          |\n|--------------------------------|-------------|--------------------------------------------------|\n| `Scope`                        | type alias  | `= string` — colon-delimited, e.g. `tg:12345`   |\n| `ParsedScope`                  | interface   | `{frontend, id, parts, raw}`                    |\n| `parseScope(scope)`            | function    | Parse a scope into its components               |\n| `formatScope({frontend, id})`  | function    | Build a scope from components                   |\n| `normalizeLegacyScope(s)`      | function    | Convert pre-tenancy strings to canonical form   |\n\n### AsyncLocalStorage propagation\n\n| Symbol                          | Returns     | Purpose                                          |\n|--------------------------------|-------------|--------------------------------------------------|\n| `withScope(scope, fn)`         | `T`         | Run `fn` with `scope` active in the async tree  |\n| `getCurrentScope()`            | `Scope`     | Read active scope; throws if none               |\n| `getCurrentScopeOr(fallback)`  | `Scope`     | Read active scope or return fallback            |\n| `hasActiveScope()`             | `boolean`   | True if a `withScope` block is currently active |\n\n### Storage&lt;T&gt; backends\n\n| Symbol                         | Purpose                                                        |\n|-------------------------------|----------------------------------------------------------------|\n| `Storage<T>`                  | The generic interface — `get/put/patch/delete/listScopes`     |\n| `StorageWithLocation`         | Optional tag interface for backends that expose `.location()` |\n| `MarkdownFileStorage<T>`      | One file per scope, human-editable, git-versionable            |\n| `DatabaseStorage<T>`          | One row per scope in a SQLite table; lazy `better-sqlite3`     |\n\n### Path helpers\n\n| Symbol                          | Returns     | Purpose                                          |\n|--------------------------------|-------------|--------------------------------------------------|\n| `getEngineDbPath()`            | `string`    | `~/.aman/engine.db` (or `$AMAN_ENGINE_DB`)       |\n| `getAmanHome()`                | `string`    | `~/.aman` (or `$AMAN_HOME`)                      |\n| `ensureDir(path)`              | `void`      | Idempotent recursive `mkdir`                    |\n| `scopeToPath(scope)`           | `string`    | `tg:12345:agent:jiran` → `tg/12345/agent/jiran` |\n\n### Migration\n\n| Symbol                          | Purpose                                                        |\n|--------------------------------|----------------------------------------------------------------|\n| `migrateLegacyAmemDb(opts?)`   | One-time copy of `~/.amem/memory.db` → `~/.aman/engine.db` with legacy scopes rewritten |\n\nThe migration is idempotent and never deletes the legacy file.\n\n---\n\n## Architecture\n\n```\n                  ┌─────────────────────────────────────┐\n                  │   aman engine v1 — 4 layer libs     │\n                  │                                     │\n                  │   acore-core    arules-core         │\n                  │   amem-core     (future layers)     │\n                  │       │              │              │\n                  │       └──────┬───────┘              │\n                  │              │                      │\n                  │              ▼                      │\n                  │   ┌─────────────────────┐           │\n                  │   │   aman-core         │ ← YOU     │\n                  │   │   (this package)    │  ARE      │\n                  │   │                     │  HERE     │\n                  │   │  Scope              │           │\n                  │   │  Storage<T>         │           │\n                  │   │  withScope          │           │\n                  │   │  paths + migrate    │           │\n                  │   └─────────────────────┘           │\n                  └─────────────────────────────────────┘\n                              ▲\n                              │\n        ┌─────────────────────┼─────────────────────┐\n        │                     │                     │\n        ▼                     ▼                     ▼\n┌──────────────┐    ┌──────────────┐    ┌──────────────┐\n│ aman-plugin  │    │  aman-agent  │    │   aman-tg    │\n│ Claude Code  │    │  CLI runtime │    │  Telegram    │\n│              │    │              │    │  super-app   │\n│ scope=       │    │ scope=       │    │ scope=       │\n│ dev:plugin   │    │ dev:agent    │    │ tg:userId    │\n└──────────────┘    └──────────────┘    └──────────────┘\n```\n\n`aman-core` is the foundation. The four layer libraries (`acore-core`,\n`arules-core`, `amem-core`, future ones) consume it to build their\nmulti-tenant features. The three frontends (Claude Code via `aman-plugin`,\nCLI via `aman-agent`, Telegram via `aman-tg`) all run on the same engine\nthrough this single substrate.\n\n**A bug fix in `aman-core` propagates to every layer and every frontend\nsimultaneously.** That's the win condition.\n\n---\n\n## What this is NOT\n\nTo stay tiny and stable, `aman-core` deliberately does not provide:\n\n- **A database.** It defines the storage *interface*; concrete backends\n  for layers' record types live in those layers (or use the two backends\n  shipped here).\n- **An LLM client.** That's the runtime's job (`aman-agent`, the `aman-tg`\n  backend).\n- **An MCP server.** That's `aman-mcp`.\n- **Identity, rules, or memory.** Those are separate layer libraries\n  (`acore-core`, `arules-core`, `amem-core`).\n- **A configuration system.** Layers configure themselves via env vars and\n  constructor options.\n\nIf you're looking for the \"full aman experience,\" install the layer\nlibraries and a frontend. This package is the substrate they share.\n\n---\n\n## Quality signals\n\n- **74 unit tests, all passing**, across 5 test files:\n  - `scope.test.ts` — 23 tests covering parse/format/normalize and AsyncLocalStorage propagation including parallel-no-bleed\n  - `paths.test.ts` — 11 tests covering env overrides and `scopeToPath` sanitization\n  - `migrate.test.ts` — 5 integration tests with a real SQLite database\n  - `markdown-file-storage.test.ts` — 16 tests covering get/put/patch/delete/listScopes and isolation\n  - `database-storage.test.ts` — 19 tests covering the same plus table-name SQL-injection rejection\n- **`tsc --noEmit` clean** with `strict`, `noUnusedLocals`, `noUnusedParameters`, `noImplicitReturns`\n- **ESM only**, Node ≥18, TypeScript declarations + sourcemaps included\n- **Zero runtime dependencies.** Optional `better-sqlite3` loaded lazily.\n\n---\n\n## The aman ecosystem\n\n`aman-core` is one of several packages in the aman AI companion ecosystem:\n\n| Layer                                                                   | Role                                                |\n|------------------------------------------------------------------------|-----------------------------------------------------|\n| **[@aman_asmuei/aman-core](https://github.com/amanasmuei/aman-core)**   | **Substrate** — Scope, Storage, withScope (this)    |\n| [@aman_asmuei/acore-core](https://github.com/amanasmuei/acore-core)     | Identity layer — multi-tenant Identity records      |\n| [@aman_asmuei/arules-core](https://github.com/amanasmuei/arules-core)   | Guardrails layer — rule parsing and runtime checks  |\n| [@aman_asmuei/amem-core](https://github.com/amanasmuei/amem)            | Memory layer — semantic recall, embeddings          |\n| [@aman_asmuei/aman-mcp](https://github.com/amanasmuei/aman-mcp)         | MCP server aggregating all layers for any host      |\n| [@aman_asmuei/aman-agent](https://github.com/amanasmuei/aman-agent)     | Standalone CLI runtime, multi-LLM, scope-aware      |\n| [aman-plugin](https://github.com/amanasmuei/aman-plugin)                | Claude Code plugin (hooks + skills + MCP installer) |\n| [@aman_asmuei/aman](https://github.com/amanasmuei/aman)                 | Umbrella installer — one command for the ecosystem  |\n\n---\n\n## License\n\n[MIT](LICENSE) © Aman Asmuei\n\n---\n\n<div align=\"center\">\n  <sub>Built with ❤️ in 🇲🇾 <strong>Malaysia</strong> · Part of the <a href=\"https://github.com/amanasmuei\">aman ecosystem</a></sub>\n</div>\n","readmeFilename":"README.md"}