# @kody/stash — agent notes Human setup and intent live in [`README.md`](./README.md). This file is for agents: imports, smoke/dryRun execute snippets, and edge cases. No user secrets. Do not disable live webhooks or jobs. ## Secrets None. Zero-auth. Do not open OAuth connect or secrets URLs for this package. If a call returns 403 or "insufficient scope", you are usually running a static `kody:@kody/stash` import against the live official package (platform bucket) or invoking outside the package runtime so `packageStorage()` is missing. Fork the listing or invoke your installed fork as shown below. ## Import paths | Export | Import | | --- | --- | | dispatcher (add/search/overview) | `kody:@kody/stash` | | add | `kody:@kody/stash/add` | | search | `kody:@kody/stash/search` | | recent | `kody:@kody/stash/recent` | | by-tag | `kody:@kody/stash/by-tag` | | get | `kody:@kody/stash/get` | | update | `kody:@kody/stash/update` | | archive | `kody:@kody/stash/archive` | | retriever | `kody:@kody/stash/retriever` | | app | `kody:@kody/stash/app` | Named ESM exports work via static `import { ... }`. Prefer static `kody:@…/stash/...` imports from `execute` when calling **your fork**. When the installed fork's specifier is data (from `packageGet`), use computed `import(specifier)` — do not lead with `packages.invoke`. Root dispatcher: `add` when `text` is present, `search` when `query` is present, otherwise overview. Explicit `action`: `add`, `update`, `get`, `recent`, `by-tag`, `archive`, `search`, `overview`. ## Installed-fork storage `packageStorage()` is per saved package. To write to the caller's bucket, resolve the installed fork's import specifier, then call that export: ```ts import { kody } from 'kody:runtime' export default async function main() { const saved = await kody.packageList({}) const packageId = saved.packages.find((pkg) => pkg.kody_id === 'stash') ?.package_id if (!packageId) throw new Error('Install or fork stash first.') const installed = await kody.packageGet({ package_id: packageId }) const specifier = (subpath: string) => { const value = installed.exports.find( (entry) => entry.subpath === subpath, )?.import_specifier if (!value) throw new Error(`Installed stash is missing ${subpath}.`) return value } const recentSpec = specifier('./recent') const recentMod = await import(recentSpec) return await recentMod.default({ limit: 5 }) } ``` Prefer a subpath whose **default export** is the function (for example `./recent`), or call the root dispatcher. ## Smoke test (read-only) ```ts import { kody } from 'kody:runtime' export default async function main() { const saved = await kody.packageList({}) const packageId = saved.packages.find((pkg) => pkg.kody_id === 'stash') ?.package_id if (!packageId) throw new Error('Install or fork stash first.') const installed = await kody.packageGet({ package_id: packageId }) const recentSpec = installed.exports.find( (entry) => entry.subpath === './recent', )?.import_specifier if (!recentSpec) throw new Error('Installed stash is missing ./recent.') const recentMod = await import(recentSpec) return await recentMod.default({ limit: 5 }) } ``` A successful smoke test returns a `notes` array. It does not create a note. Static import against the live platform package (read-only overview only): ```ts import runStash from 'kody:@kody/stash' export default async function main() { return await runStash() } ``` ## dryRun / confirm (mutations) `add`, `update`, and `archive` accept `dryRun: true` and must be previewed that way before a live write. ```ts import { kody } from 'kody:runtime' export default async function main() { const saved = await kody.packageList({}) const packageId = saved.packages.find((pkg) => pkg.kody_id === 'stash') ?.package_id if (!packageId) throw new Error('Install or fork stash first.') const installed = await kody.packageGet({ package_id: packageId }) const addSpec = installed.exports.find( (entry) => entry.subpath === './add', )?.import_specifier if (!addSpec) throw new Error('Installed stash is missing ./add.') const addMod = await import(addSpec) return await addMod.default({ text: 'Projector bulb: 250W #home', dryRun: true }) } ``` Expect `dryRun: true` plus a preview `note` (inferred kind/tags). No write. ## Edge cases - Static `kody:@kody/stash` imports hit the **platform** package bucket when the official listing runs live — fork first for personal notes. - Search ranks over the newest **500** notes; recent defaults to 20 (max 50). - Hashtags in text become tags; kind is inferred when omitted. - Soft-archive via `./archive`; do not hard-delete unless the API grows that. - Put a URL in the note body to point at files elsewhere — no R2/blob store. - Not an email inbox; use mail packages for that.