{"_id":"@amail/plugin-sdk","name":"@amail/plugin-sdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@amail/plugin-sdk","version":"0.1.0","description":"AMail plugin contract. Locked at end of Phase 2 — stable surface for plugin authors.","license":"MIT","homepage":"https://github.com/sobingt/email-tool/tree/main/packages/plugin-sdk","repository":{"type":"git","url":"git+https://github.com/sobingt/email-tool.git","directory":"packages/plugin-sdk"},"bugs":{"url":"https://github.com/sobingt/email-tool/issues"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"bin":{"amail-plugin-check":"dist/bin/amail-plugin-check.js"},"publishConfig":{"access":"public"},"dependencies":{"@anthropic-ai/sdk":"0.52.0","js-yaml":"^4.1.1","zod":"^4.4.3"},"devDependencies":{"@types/js-yaml":"^4.0.9","@types/node":"^20","typescript":"^5.7"},"scripts":{"build":"tsc -p tsconfig.build.json && chmod +x dist/bin/amail-plugin-check.js","clean":"rm -rf dist"},"_id":"@amail/plugin-sdk@0.1.0","_integrity":"sha512-cnIDhzvjQXlrTd+z3QiqQnZOz9RyRuG/BRs8xxrsfxbNmpsL2sYYB6v1lFzLBBJOsuExYM/rJAwums2DfT/zYw==","_resolved":"/private/var/folders/s0/gzzhqcjn6f1d4mh9wq6y2mp40000gn/T/9854f98f6dd02e3551b734df2e057f79/amail-plugin-sdk-0.1.0.tgz","_from":"file:amail-plugin-sdk-0.1.0.tgz","_nodeVersion":"22.22.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-cnIDhzvjQXlrTd+z3QiqQnZOz9RyRuG/BRs8xxrsfxbNmpsL2sYYB6v1lFzLBBJOsuExYM/rJAwums2DfT/zYw==","shasum":"f3be15d0d48166f25b2a7c9a59f8e4c969f6990a","tarball":"https://registry.npmjs.org/@amail/plugin-sdk/-/plugin-sdk-0.1.0.tgz","fileCount":23,"unpackedSize":59878,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCyQpK4zOpIuQkKVq6nlRfnT6AeKIF1/XEdwS1mbLsQ2QIhAOs7YjAZQsoWzBpaBNTDJiFwxvAmzyNjt42oLF7phOuC"}]},"_npmUser":{"name":"sgthomas","email":"sobingt@bitbrothers.in"},"directories":{},"maintainers":[{"name":"sgthomas","email":"sobingt@bitbrothers.in"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/plugin-sdk_0.1.0_1779086412612_0.17731861289714068"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-18T06:40:12.535Z","0.1.0":"2026-05-18T06:40:12.742Z","modified":"2026-05-18T06:40:12.986Z"},"maintainers":[{"name":"sgthomas","email":"sobingt@bitbrothers.in"}],"description":"AMail plugin contract. Locked at end of Phase 2 — stable surface for plugin authors.","homepage":"https://github.com/sobingt/email-tool/tree/main/packages/plugin-sdk","repository":{"type":"git","url":"git+https://github.com/sobingt/email-tool.git","directory":"packages/plugin-sdk"},"bugs":{"url":"https://github.com/sobingt/email-tool/issues"},"license":"MIT","readme":"# @amail/plugin-sdk\n\nThe locked plugin contract for AMail. Phases 3 (sandbox), 4 (HR plugin), and 7\n(PR proposer) all build on the types exported from this package — do **not**\nchange the shapes here without a phase-spanning review.\n\n## Installation\n\n```bash\npnpm add -D @amail/plugin-sdk\n# or\nnpm install --save-dev @amail/plugin-sdk\n```\n\nRequires Node ≥ 20.\n\n## What's in `dist/`\n\n- `index.js` / `index.d.ts` — the public API (`AmailPlugin`, `ToolSchema`, etc.)\n- `manifest.js` — `parseManifest`, `PluginManifestSchema`, helpers\n- `context.js` — `AmailRuntimeContext`, `AttachmentRef`, `defaultV1Entitlement`\n- `types.js` — plugin/tool/skill types\n- `bin/amail-plugin-check.js` — the [`amail-plugin-check`](#amail-plugin-check-cli) CLI\n\n## `amail-plugin-check` CLI\n\nA `npx`-able validator that runs the same Zod schema the marketplace scan\nworkflow runs. Authors should run it before opening a submission PR so they\nget all the field-level errors locally — no Docker required.\n\n```bash\n# From inside a plugin package directory:\nnpx @amail/plugin-sdk amail-plugin-check\n\n# Also import the plugin entry and verify manifest ↔ entry tool-name parity\n# (catches \"I forgot to register the new tool in both places\"):\nnpx @amail/plugin-sdk amail-plugin-check --load\n```\n\n\n\n## What a plugin exports\n\nA plugin package's entrypoint must export a default value conforming to\n[`AmailPlugin`](./src/types.ts):\n\n```ts\nimport type { AmailPlugin } from \"@amail/plugin-sdk\";\n\nconst plugin: AmailPlugin = {\n  id: \"my-vertical\",\n  version: \"0.1.0\",\n  tools: [\n    {\n      name: \"doThing\",\n      description: \"Do the vertical-specific thing.\",\n      input_schema: { type: \"object\", properties: { /* … */ } },\n    },\n  ],\n  handlers: {\n    doThing: async (args, ctx) => {\n      ctx.logger.info(\"doing thing\", { thread: ctx.threadId });\n      return { ok: true, data: { /* … */ } };\n    },\n  },\n  defaultSkills: [\n    { name: \"Vertical Skill\", body: \"# Steps\\n\\n1. …\\n2. …\\n\" },\n  ],\n  amailFragment: \"## Vertical vocabulary\\n\\nTickets have a Vendor field…\",\n};\n\nexport default plugin;\n```\n\nThe instance loads plugins listed in the `INSTANCE_PLUGINS` env var (comma-\nseparated package names). At boot the host:\n\n1. `await import`s each plugin\n2. validates that no two plugins declare the same tool name (fail-fast)\n3. merges plugin `tools` into the registry and `defaultSkills` into the skill\n   set (S3-authored skills win on collision, so operators can override)\n4. concatenates `amailFragment` strings into the effective `Amail.md` shown to\n   the agent.\n\n## The determinism rule (read this before writing a handler)\n\nThe core runtime caches every tool call by\n`(emailMessageId, toolName, sha256(canonicalJSON(args)))` in the\n`tool_executions` collection (TTL 7 days). On a cache hit, the cached result\nis returned to the model **and PostToolUse / ThreadClosed hooks are skipped**\nso external side effects don't fire twice.\n\nThat has three consequences for handler authors:\n\n1. **Handlers must be deterministic given `(args, ctx)`** — same input must\n   produce the same observable outcome. If you need server-side dedup (e.g. an\n   external API's idempotency key), derive it from `args` / `ctx`, not from\n   `Date.now()`.\n2. **Do NOT add your own idempotency layer for the same triplet.** It will\n   fight the core cache and double-count.\n3. **Throwing vs returning `{ ok: false }`**: a returned `{ ok: false }` is\n   intentional and **is** cached (re-running would just fail again). A thrown\n   exception is treated as a transient error and is **not** cached, leaving\n   the next retry free to re-attempt.\n\n## What the runtime context gives you\n\n[`AmailRuntimeContext`](./src/context.ts):\n\n| Field | Use it for |\n|---|---|\n| `instanceId` | scoping plugin-internal state to the instance |\n| `threadId` | every external action that needs the AMail thread reference |\n| `skill` | log attribution; `\"auto\"` if the agent picked the tool freely |\n| `emailMessageId` | informational only — do NOT use as your own dedup key |\n| `s3.read` / `s3.write` | persistent plugin state, scoped to `plugins/{pluginId}/` |\n| `attachments.list` / `attachments.fetch` | inbound email attachments |\n| `llm.complete` | internal LLM calls (e.g. classification, summarisation) |\n| `logger.info` / `logger.error` | structured logs propagated to the host |\n\nPhase 2 plugins run in-process so `process.env`, raw `aws-sdk`, raw Mongo, etc.\nall technically work. Phase 3 will isolate the worker and block everything\noutside this context — code against the context only and you get a free\nmigration.\n\n## Versioning\n\nReleased to public npm via [Changesets](https://github.com/changesets/changesets)\nalongside `@amail/plugin-host`. Major bumps follow a 6-month deprecation window\nwith two preview releases (per [plan.md](https://github.com/sobingt/email-tool/blob/main/plans/multi-instance-and-plugins/plan.md) decision #14).\n\nAny PR in the upstream repo that modifies `packages/plugin-sdk/` or\n`packages/plugin-host/` must include a `.changeset/*.md` file describing the\nchange — CI enforces this.\n\n## License\n\nMIT — see `LICENSE`.\n","readmeFilename":"README.md","_rev":"1-1feb82f8dda871cc45f23275ac37cade"}