feat(api): export canonical tag helpers via opencode-mem/tags subpath#125
Merged
Merged
Conversation
Adds a stable subpath export so third-party plugins can compute canonical
container tags without reverse-engineering the format from the source.
```ts
import { getProjectTagInfo, getUserTagInfo, getTags } from "opencode-mem/tags";
const projectTag = getProjectTagInfo(process.cwd()).tag;
// → "opencode_project_<sha16-of-git-remote-or-path>"
const userTag = getUserTagInfo().tag;
// → "opencode_user_<sha16-of-git-email>"
```
## Why
The canonical format encodes meaning that several handlers depend on:
- `handleListMemories` (no-tag path) and `handleStats` `byScope` recognize
scope via the literal `_project_` / `_user_` substring
- Auto-capture writes use these exact tag shapes
- `extractScopeFromTag` parses them with the same convention
Third-party plugins that hand-roll their own tags can land in a shadow
shard whose `container_tag` doesn't match either substring. Those rows
become invisible to listing endpoints and miscount in stats — easy to do
by accident because the docs and helpers were internal-only.
Exposing the helpers via a stable subpath turns this into intentional
public API. The functions are already exported at the source level; this
PR just makes them reachable via package resolution.
## What's in the subpath
```
TagInfo (interface)
getProjectTagInfo(directory) → TagInfo with `opencode_project_<sha>`
getUserTagInfo() → TagInfo with `opencode_user_<sha>`
getTags(directory) → { user, project }
getProjectIdentity(directory) → git-remote-or-path
getProjectRoot(directory) → repo root or directory
getProjectName(directory) → human-readable name
getGitEmail() → git config user.email
getGitName() → git config user.name
getGitRepoUrl(directory) → remote.origin.url
getGitCommonDir(directory) → `git rev-parse --git-common-dir`
getGitTopLevel(directory) → repo top-level
```
The main entries are the three tag helpers; the git/path utilities come
along for free since they're in the same module.
## Verification
- `bun test`: 143 pass / 0 fail
- `bun run typecheck`: clean
- `bun run build`: clean
- `npx prettier --check`: clean
- Subpath resolution verified: `node -e "import('opencode-mem/tags')..."` returns
all 11 helpers including the three documented entry points.
## Use case
I needed this while building a sibling plugin that exposes opencode-mems
`/api/search` + `POST /api/memories` as opencode LLM tools, so the agent
can do explicit `memory_search(query)` / `memory_remember(...)` calls
mid-conversation (complement to the existing implicit `injectOn: "first"`
path). Without canonical tag helpers, every such plugin would either
hand-roll the convention (and silently end up in shadow shards — I did
exactly that on first try) or copy-paste the internal `tags.ts` code.
A public subpath makes opencode-mem easier to build on top of and
encourages an ecosystem of tool-style plugins around the same data.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a stable
opencode-mem/tagssubpath export so third-party plugins can compute canonical container tags without reverse-engineering the format from the source.Why this matters
The canonical format encodes meaning that several handlers depend on:
handleListMemories(no-tag path) andhandleStatsbyScoperecognize scope via the literal_project_/_user_substringextractScopeFromTagparses them with the same conventionThird-party plugins that hand-roll their own tags can land in a shadow shard whose
container_tagdoesn't match either substring. Those rows become invisible to listing endpoints and miscount in stats — easy to do by accident because the helpers were internal-only and the format was only documented in source comments.Exposing them via a stable subpath turns this into intentional public API. The functions are already exported at the source level; this PR just makes them reachable via package resolution.
What's in the subpath
The main entries are the three tag helpers; the git/path utilities come along for free since they're in the same module. If you'd rather keep the git/path helpers internal and only expose the three tag entry points, I'm happy to add a thin facade — but they're already lifted as
exportat the source so the surface is "what's already public, just reachable now."Use case
I needed this while building a sibling plugin that exposes opencode-mem's
/api/search+POST /api/memoriesas opencode LLM tools, so the agent can do explicitmemory_search(query)/memory_remember(...)calls mid-conversation (complement to your existing implicitinjectOn: "first"injection path — your built-inmemorytool covers the same functional surface; mine just splits into single-purpose tools because some agent runtimes choose them more reliably).Without canonical tag helpers, every such plugin would either hand-roll the convention (and silently end up in shadow shards — I did exactly that on first try, then traced the bug via
extractScopeFromTag) or copy-paste the internaltags.tscode. A public subpath makes opencode-mem easier to build on top of.Verification
bun test: 143 pass / 0 fail (no behavior change, pure visibility addition)bun run typecheck: cleanbun run build: cleannpx prettier --check: cleannode -e "import('opencode-mem/tags')..."returns all 11 helpers including the three documented entry points.Out of scope
If a future PR wants to address the shadow-shard problem upstream (e.g. have
handleAddMemoryreject malformedcontainerTagvalues), that's a separate, opinion-laden change. This PR just makes the right thing easier to do voluntarily.