Skip to content

feat(claude-code): add {user_id} retainTags template variable#1161

Merged
nicoloboschi merged 3 commits intovectorize-io:mainfrom
soichisumi:feat/user-id-template-var
Apr 20, 2026
Merged

feat(claude-code): add {user_id} retainTags template variable#1161
nicoloboschi merged 3 commits intovectorize-io:mainfrom
soichisumi:feat/user-id-template-var

Conversation

@soichisumi
Copy link
Copy Markdown
Contributor

@soichisumi soichisumi commented Apr 20, 2026

Summary

  • Adds {user_id} template variable to retainTags / retainMetadata, resolved from HINDSIGHT_USER_ID.
  • After resolution, drops tags of the form "<ns>:" (empty post-colon segment). Tags without : are untouched.
  • Four new tests covering env-set / env-unset-drop / colon-less-preserved / all-dropped-yields-no-field. Full suite: 133 passed.

Fixes #1160.

What

  • scripts/retain.py: extend template_vars with "user_id": os.environ.get("HINDSIGHT_USER_ID", ""), rewrite the tag-resolution loop to drop dangling namespaced tags (logged via debug_log).
  • tests/test_hooks.py: four new cases in TestRetainHook. {user_id} is injected via _run_hook's extra_env (the helper strips real HINDSIGHT_* vars by design).
  • README.md: expanded retainTags description, template variables reference table, per-user scoping example.
  • CHANGELOG.md: [Unreleased] Added / Changed entries.

How

template_vars["user_id"] is resolved once and applies to both retainTags and retainMetadata because _resolve_template is shared.

After _resolve_template, the loop skips any tag where ":" in resolved and resolved.split(":", 1)[1] == "". Colon-less tags never match the guard, so backward compat is preserved by construction. If every tag drops, tags is normalized to None; HindsightClient.retain's existing field-omission path (client.py:144if tags: item["tags"] = tags) then omits the field from the outgoing request.

Test plan

  • [auto] pytest tests/test_hooks.py -v -k retain_tag → 5 passed (1 existing + 4 new).
  • [auto] pytest tests/ -v → 133 passed, no regression.
  • [manual] CI green on this PR.

Resolve {user_id} from HINDSIGHT_USER_ID env var in retainTags and
retainMetadata. After template resolution, tags whose namespace part is
empty (e.g. 'user:' when HINDSIGHT_USER_ID is unset) are dropped from
the outgoing retain request, so a single portable config works whether
or not the user id is set.

Existing behavior preserved: empty/None retainTags -> tags=None; tags
without ':' are never dropped; fully-resolved tags with non-empty
content pass through unchanged.
Four new cases in TestRetainHook:
- {user_id} resolves from HINDSIGHT_USER_ID env var (via _run_hook's
  extra_env, since the helper strips real HINDSIGHT_* env vars by design)
- dangling 'user:' is dropped when env is unset; other tags survive
- colon-less tags are preserved regardless of env state
- all-dropped tags produce a request with no 'tags' field

Full suite: 133 passed.
- README: expand retainTags description to enumerate all four template
  placeholders ({session_id}, {bank_id}, {timestamp}, {user_id}), add a
  Template variables reference table, and add a per-user memory scoping
  example showing HINDSIGHT_USER_ID usage and recall filter pattern.
- retainMetadata description updated to note shared template support.
- CHANGELOG: add [Unreleased] section with Added (new template var) and
  Changed (dangling-tag drop semantics) entries.
Copy link
Copy Markdown
Collaborator

@nicoloboschi nicoloboschi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@nicoloboschi nicoloboschi merged commit 9181c9a into vectorize-io:main Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(claude-code): add {user_id} retainTags template variable from HINDSIGHT_USER_ID env

2 participants