Skip to content

fix(recall): honour TEAMAI_RECALL_DISABLED in pull and recall status - #1464

Merged
SaulMoro merged 2 commits into
Tencent:mainfrom
ColumbusLabs:fix/1457-recall-disabled-env
Oct 27, 2026
Merged

SaulMoro merged 2 commits into
Tencent:mainfrom
ColumbusLabs:fix/1457-recall-disabled-env

Conversation

@ColumbusLabs

@ColumbusLabs ColumbusLabs commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

TEAMAI_RECALL_DISABLED=1 is documented to force recall off, and the guide says pull then does not install it, but isRecallEnabled never read the variable. Only hooks honoured it, so teamai pull still installed the recall subagent and rule and teamai recall status said "enabled". isRecallEnabled now checks the variable first, the same way its siblings isContributeHintEnabled and isMrHintEnabled do, and recall status names the variable when it is what turns recall off. The share skill gate's refusal and its skill list note name it too, instead of pointing to teamai recall enable.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature causing existing behavior to change)
  • Documentation only
  • Refactor / internal cleanup

Test Plan

  • npx tsc --noEmit passes
  • npm run lint passes
  • npx vitest run passes
  • Added/updated tests for the change

Full npx vitest run on the first commit, before its last two tests and the review follow-up were added: 17250 passed, 3 failed (git-discovery "lists no main checkout made bare..." and two submodule-checkout hook tests). The same 3 fail with main's src/types.ts and src/recall-toggle.ts; they look tied to my local git 2.47.3 (git config --get hook.teamai-post-checkout.command fails), and the review reports they pass on git 2.56.0. I did not rerun the full suite, so I left that box unticked.

New tests:

  • recall-toggle.test.ts: '1' wins over the user override and the team config (both shapes); the default env parameter reads process.env, which is how pull calls it; unset, '0', '' and 'true' leave the config layers in charge (same rule as the sibling variables); recall status prints "Recall: disabled" plus the env line when set, and does not mention the variable when it is unset or when the user override is what turns recall off.
  • pull-skip-sync.test.ts: with recallEnabled: true and the variable set, pull removes the CLAUDE.md recall block and does not write .claude/agents/teamai-recall.md.
  • skill-recall-gate.test.ts: share is blocked with reason recall when the variable is set, even with recall on, and skill get share and skill get --all then name the variable and say to unset it instead of pointing to teamai recall enable; with the variable unset, '0', '' or 'true' the refusal keeps the teamai recall enable hint; skill list then tells the member to unset the variable beside share instead of teamai recall enable.
  • pull-agent-places.test.ts: a full pull with recallEnabled: true and the variable set does not deploy the recall agent, while the team's own agent still lands.

Revert check: with src/types.ts and src/recall-toggle.ts put back to main, 6 of the new tests fail (76 total in the 5 files). With only src/recall-toggle.ts put back, the status test fails. With the fix, all 76 pass. For the share gate message (second commit): with src/skill-content.ts and src/skill-cmd.ts put back to the first commit, 5 of the 18 tests in skill-recall-gate.test.ts fail; with the check loosened to any non-empty value, the '0'/''/'true' test fails. With both commits, the 5 files give 80 passing.

Also run: npx vitest run on recall-attribution, recall-unreadable-config and todowrite-hint (other readers of the variable, 192 passed), and npm run test:e2e -- src/__tests__/e2e/source-freshness-recall.test.ts src/__tests__/e2e/skill-serving-cli.test.ts (15 passed; the first already sets TEAMAI_RECALL_DISABLED=1, the second covers the skill recall gate through the CLI). For the follow-up, src/__tests__/e2e/recall-toggle-dry-run.test.ts with those two (16 passed).

Real CLI run (isolated HOME, local git team repo, init --agent claude --scope project, then recallEnabled: true in the workspace config). On main:

$ TEAMAI_RECALL_DISABLED=1 teamai pull --force
- [workspace] Pulling team repo...
✔ [workspace] Team repo: already up to date
✔ [workspace] Synced 1 rule(s)
$ ls .claude/agents .claude/rules
.claude/agents:
teamai-recall.md

.claude/rules:
team-rule.md
teamai-context.md
teamai-recall.md
$ TEAMAI_RECALL_DISABLED=1 teamai recall status
Recall: enabled
  Team config (sharing.recall.enabled): false
  User override (recallEnabled): true

With this branch:

$ teamai init <team repo> --provider git --agent claude --scope project --force   (output omitted)
$ TEAMAI_RECALL_DISABLED=1 teamai pull --force
- [workspace] Pulling team repo...
✔ [workspace] Team repo: already up to date
✔ [workspace] Synced 1 rule(s)
$ ls .claude/agents .claude/rules
ls: cannot access '.claude/agents': No such file or directory
.claude/rules:
team-rule.md
$ TEAMAI_RECALL_DISABLED=1 teamai recall status
Recall: disabled
  Env override (TEAMAI_RECALL_DISABLED=1): disabled
  Team config (sharing.recall.enabled): false
  User override (recallEnabled): true
$ teamai pull --force   (variable unset)
✔ [workspace] Synced 1 rule(s)
$ ls .claude/agents .claude/rules
.claude/agents:
teamai-recall.md

.claude/rules:
team-rule.md
teamai-context.md
teamai-recall.md
$ teamai recall status   (variable unset)
Recall: enabled
  Team config (sharing.recall.enabled): false
  User override (recallEnabled): true
$ TEAMAI_RECALL_DISABLED=1 teamai skill get share
✖ share needs recall, which TEAMAI_RECALL_DISABLED=1 turns off in this environment.
  Unset TEAMAI_RECALL_DISABLED to use it; `teamai recall enable` does not override the variable.

Related Issues

Fixes #1457

Notes for Reviewers

  • src/skill-content.ts:158 gates the share skill on isRecallEnabled, so with the variable set the skill gate now blocks too, and so does the Stop-hook share reminder that asks the same gate (contributeHintAllowed). The recall block a session hook adds (resolveInstructionBlocks) is left out as well. That matches "forces it off". When the variable is the cause, the gate's refusal now says so and tells the member to unset TEAMAI_RECALL_DISABLED, since teamai recall enable would succeed and leave share blocked; otherwise the teamai recall enable hint is unchanged. skill list does the same beside share.
  • The guide (English and zh-CN) now also notes that the variable changes files every shell in the scope shares: a pull from a shell with it set removes the recall files and the CLAUDE.md recall block for the whole scope, and a pull from a shell without it puts them back.
  • teamai recall search itself is not gated by isRecallEnabled, so it is unchanged.
  • [feat] Read every member setting in one order: environment, this scope, this machine, the team #1459 proposes a single order for member settings and keeps the environment as level 1 inside each resolver such as isRecallEnabled; this change is in line with that.

The guide says TEAMAI_RECALL_DISABLED=1 forces recall off and that pull
then does not install it, but isRecallEnabled never read the variable,
so pull installed the recall subagent and rule anyway. isRecallEnabled
now checks it first, like isContributeHintEnabled and isMrHintEnabled,
and recall status names the variable when it decides. The share skill
gate also follows it, since it asks isRecallEnabled.

Fixes Tencent#1457
@github-actions

Copy link
Copy Markdown

No confident findings in the specified diff.

The PR description documents sufficient testing, including representative real-CLI runs with the variable set and unset, targeted tests, and E2E results. No testing-related blocking finding is warranted.

Review was read-only; I did not run, build, or install anything from the PR.

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This was generated by AI during triage.

@ColumbusLabs Thanks, the fix does what #1457 asks. We ran it with the built CLI against main, in a workspace and a user-scope install, with Claude and OpenCode:

  • With TEAMAI_RECALL_DISABLED=1, pull no longer installs the recall agent or rule; main still does.
  • recall status names the variable.
  • With the variable unset, the next pull restores everything.
  • Only '1' counts, as with the sibling variables.

One change before this is approved, the one your body already offers:

  • [P2 non-blocking, needed for approval] The share gate now sends the member to a command that doesn't help. With the variable set, teamai skill get share exits 1 with share needs recall, which is disabled for this team. Turn it on with \teamai recall enable`… (src/skill-content.ts:334). The team has recall on. Following the hint, recall enableexits 0 and prints "Recall enabled". It also writesrecallEnabled: trueand deploys the recall files, and share stays blocked. Onmainshare is not gated by the variable, so this dead end is new. When the variable is what turns recall off, the message should say so and tell the member to unsetTEAMAI_RECALL_DISABLED`.

Non-blocking:

  • [P3 nit] The variable now changes files that every shell in the scope shares. A pull from a shell with it set removes the CLAUDE.md recall block for the whole scope, and a pull from another shell puts it back. That follows from the option #1457 chose; a line in docs/guide/knowledge.md saying so would help.

CI review: we agree the testing record is enough, but not with "no findings", because of the share message above.

Verified at 8b11229: tsc and lint pass. The PR's 4 test files (71 tests) pass, also under a symlinked TMPDIR, and 6 of the new tests fail on main. 7 other recall test files (408 tests) and 3 e2e files (16 tests) pass. The 3 failures in the body pass here on git 2.56.0. Not run here: Codex, CodeBuddy and Windows.

@SaulMoro
SaulMoro self-requested a review October 27, 2026 14:06
With TEAMAI_RECALL_DISABLED=1 the share skill gate refused with a hint to
run `teamai recall enable`, which succeeds and leaves share blocked. When
the variable is set, the refusal now names it and says to unset it.
`skill list` says to unset it too. The guide also notes that the variable
changes files every shell in the scope shares.

Refs Tencent#1457
@ColumbusLabs

Copy link
Copy Markdown
Contributor Author

Thanks @SaulMoro for running it end to end.

I pushed a follow-up commit. When TEAMAI_RECALL_DISABLED=1 is what turns recall off, the share gate now names the variable as the reason and tells the member to unset it, instead of pointing at teamai recall enable. skill list now says to unset it too. With the variable unset, the message is unchanged. The tests for this are in skill-recall-gate.test.ts. I also added the docs note in English and zh-CN.

Thanks too for checking the three full-suite failures on git 2.56.0; that matches my guess that they came from my local git 2.47.

Ready for another look when you have time.

@github-actions

Copy link
Copy Markdown

No confident findings in the specified diff. The earlier review raised no findings, so none require resolution.

The PR description documents sufficient testing, including representative real-CLI runs with TEAMAI_RECALL_DISABLED set and unset, plus targeted tests and E2E results. No testing-related blocking finding is warranted.

Review was read-only; I did not run, build, or install anything from the PR.

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This was generated by AI during triage.

Approving at eb1c4f8. The share-gate message we asked for is fixed: with TEAMAI_RECALL_DISABLED=1, skill get share, skill get --all and skill list name the variable and say to unset it, instead of pointing to teamai recall enable. With the variable unset or true, the output is unchanged. Checked with the built CLI on a workspace install with Claude and OpenCode; the 5 new tests fail on the previous head and pass here. The docs note is in both guides.

npm ci, npm run build, npx tsc --noEmit and npm run lint exit 0; the PR's unit files (75 tests) and 4 other files that read the variable (284 tests) pass, also with a symlinked TMPDIR; CI is green at this head.

One optional nit: when both the team config and the variable turn recall off, the message only says to unset the variable, and the recall enable hint shows after that. Two steps, neither wrong.

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.

[bug] TEAMAI_RECALL_DISABLED=1 does not stop pull installing recall

3 participants