Repository navigation
Description
Summary
post_tool_capture copies tool outputs, and the first 200 characters of Bash commands, into Cortex's stores for every project. The only control is the global CORTEX_CAPTURE_MODE. The redaction step targets secrets, not personal data.
A user who keeps other people's data in a project gets a second copy of it in ~/.claude/methodology/. Nothing tells them. They cannot exclude that project.
Everything below comes from reading main at 02c3cf0. The scenario is hypothetical.
What the code does
- One global switch.
_capture_enabled(mcp_server/hooks/post_tool_capture.py:310) readsCORTEX_CAPTURE_MODE(fullby default). Nothing in the capture path checks the project, its working directory or the paths the tool touched. I found no project-level marker or ignore file. - Project rules are not read.
CLAUDE.mdis where Claude Code users write rules such as "never store client data in memory". The agent can follow it, but the hooks never read it, so the rule does not reach auto-capture. - Redaction covers secrets only.
scrub_secrets(line 359) handles URL passwords, AWS keys, bearer tokens,key=valuesecrets and PEM blocks. Names, e-mail addresses, phone numbers and health information pass through. - Command lines are captured.
_reference_line(line 91) keeps the first 200 characters of a Bash command. Agrepwhose pattern holds names copies those names, even when the output is empty. - Artifacts are written before the memory.
_gist_or_full(line 364) writes the full output toartifacts/<yyyy-mm>/throughstore_artifact. Only after that does_store_memory(line 372) run. If storing the memory fails, the hook logs it and the artifact stays on disk, with no memory pointing to it. Recall cannot surface it, and I found no sweep that removes it.
Hypothetical scenario
A freelancer keeps a client file in a project: names, addresses, notes. Or a carer keeps notes about patients. They ask Claude Code to sort the file, check a column, or find duplicates.
Each Read, Bash or Grep output that passes the capture filter is copied into Cortex: the memory row, and for long outputs a full artifact. The user believes the data lives in one file they control. In fact a second, unmanaged copy exists in a folder they have probably never opened. Under the GDPR, they are now holding personal data, health data included, in a store they did not choose and cannot easily purge.
Proposals
- Per-project opt-out, checked before any write, artifacts included. For example a
.cortex-no-capturefile honoured for its directory and subfolders, or a list of excluded paths in the plugin config. It should match both the session's working directory and the paths the tool touched. - No orphan artifacts. Write the artifact only after the memory is stored, or delete it when storing fails. Plus a sweep for artifacts that no memory references.
- Purge by directory, covering memories, artifacts, entities and profile examples, for when a user realises a project should not have been captured.
- Document it in the README and PRIVACY. Tool outputs and command lines are copied, to these places, for this long, and here is how to exclude a project.
- Optionally, a pluggable personal-data scrubber next to
scrub_secrets, off by default.
Activity
cdeust commentedon Nov 6, 2026
CI autopilot : première tranche dans #907 (
Refs #737, pasCloses).Tranche 1 (proposition 2, partie synchrone) : quand
dispatchrefuse ou lève, le hook supprime l'artefact qu'il vient de créer. Un artefact qui existait déjà (dédupliqué, peut-être référencé par une autre mémoire) n'est jamais supprimé. Commit60d8b7b.Tranches restantes :
artifact_gc.count_artifact_references..cortex-no-capturehérité par les sous-dossiers, ou liste de chemins dans la config du plugin) et ce qui est comparé (cwd de la session, chemins touchés par l'outil, ou les deux).scrub_secrets, désactivé par défaut (proposition 5).Generated by Claude Code
fix(capture): kill the mutants of the #737 change and let the gate's …
Merge pull request #907 from cdeust/fix/737-no-orphan-capture-artifact
cdeust commentedon Nov 10, 2026
CI autopilot : tranche 4 (documentation) dans #968 (
Refs #737).PRIVACY.mddit maintenant ce que copie l'auto-capture, outil par outil, et un test (tests_py/hooks/test_capture_privacy_disclosure.py) confronte ce texte au vrai hook. Précision sur le corps de l'issue : pour Read, NotebookRead, Glob et Grep, la ligne en base ne garde que le chemin ou le motif (_LIGHT_VALUE_TOOLS,post_tool_capture.py). Mais une réponse de plus de 3000 caractères est écrite en entier dans un artefact (constat de la revue Codex sur #968, reproduit, corrigé dans 05bb79a) : un long fichier lu est donc copié tel quel. Les réponses d'Edit, Write, MultiEdit, NotebookEdit, Bash, WebFetch et WebSearch sont, elles, copiées.Pourquoi pas le balayage des artefacts orphelins d'abord : un balayage sûr ne doit jamais supprimer l'artefact d'une capture en transit. Le spool sur disque (
capture_spool) peut être relu, mais la file du worker résident est en mémoire, et je n'ai trouvé aucune borne sourcée sur le temps qu'un payload y passe avant d'être stocké. Un délai de grâce sans source enfreindrait la règle « no source, no implementation ».Tranches restantes :
consolidate, avec un âge minimum mesuré)..cortex-no-capturehérité par les sous-dossiers, ou liste dans la config) et sur ce qui est comparé (cwd, chemins touchés, ou les deux).Non vérifié : suite complète et pyright (dépendances de
uv.locknon installables ici, téléchargement de torch refusé par le proxy).Précisions à ajouter à PRIVACY.md dans la prochaine tranche documentaire (notes de la revue 1 de #968) :
originalFilecompris ; Edit stocke les chaînes avant/après.Generated by Claude Code
fixup! docs(privacy): say what auto-capture copies, tool by tool, in …
docs(privacy): say what auto-capture copies, tool by tool, in every p…
cdeust commentedon Nov 10, 2026
CI autopilot : tranche 5 (précisions documentaires) dans #976 (
Refs #737).Les trois précisions notées après la revue 1 de #968 sont dans
PRIVACY.md, chacune confrontée àprocess_eventpar un test : un appel Edit/Write/MultiEdit/NotebookEdit/Bash dont la réponse fait moins de 50 caractères n'est pas capturé du tout (ligne de commande comprise) ; Edit garde ses chaînes avant/après, Write et MultiEdit leur réponse JSON entière ; un outil hors des trois listes (Task, TodoWrite, outils MCP) n'est jamais capturé.Tranches restantes, toutes en attente d'une décision humaine (inchangées depuis le commentaire précédent) :
consolidateavec un âge minimum mesuré..cortex-no-capturehérité par les sous-dossiers, ou liste dans la config) et ce qui est comparé (cwd, chemins touchés, ou les deux).Non vérifié : suite complète et pyright (torch refusé par le proxy,
uv sync --lockedimpossible ici).Generated by Claude Code
fixup! docs(privacy): say which captured calls keep nothing, and what…
fixup! docs(privacy): say which captured calls keep nothing, and what…
docs(privacy): say which captured calls keep nothing, and what Write …
cdeust commentedon Nov 11, 2026
CI autopilot : issue mise en
autopilot:hold. Les trois tranches livrées sont fusionnées (#907, #968, #976). Chaque tranche restante dépend d'une décision qui revient au propriétaire.Questions à trancher, une réponse de
cdeustpar point suffit :.cortex-no-capturehérité par les sous-dossiers, ou une liste de chemins dans la config du plugin ? Et que compare-t-on : le cwd de la session, les chemins touchés par l'outil, ou les deux ?consolidate, avec un âge minimum à mesurer ?Le hold se lève au prochain commentaire de
cdeustou à la prochaine modification du corps de l'issue.Generated by Claude Code