# Snow CLI Usage Documentation - Privacy Settings Guide Privacy Settings let Snow CLI send selected tool result content to a local privacy filter API for redaction before the content is passed to the model. This is useful when code, logs, terminal output, file content, or search results may contain personally identifiable information such as names, email addresses, phone numbers, or similar sensitive text. ## Feature Overview Snow CLI's privacy filter currently focuses on tool result content: - Tool results such as file reads, code search results, and terminal output can be redacted according to your configuration. - The redaction service is self-hosted by the user. Snow CLI only calls the HTTP API you configure. - Both project-level and global settings are supported. Project-level settings take precedence over global settings. - You can select which tools should have their results redacted. - If the privacy filter API is unavailable, returns an unexpected response, or has no URL configured, Snow CLI keeps the original content and continues working. The recommended local deployment project is: ```text https://github.com/MayDay-wpf/privacy-filter-api ``` This project uses Hugging Face Transformers.js to load OpenAI's `openai/privacy-filter` ONNX model locally. It provides local PII detection and text masking APIs without sending the text to a remote inference service. ## privacy-filter-api Findings `privacy-filter-api` is a local HTTP API service. Its main capabilities are: | Capability | Description | | --- | --- | | Local model | Uses `openai/privacy-filter` and loads local ONNX model files through Transformers.js. | | PII detection | `POST /detect` returns detected entities, including `label`, `score`, `text`, `start`, and `end`. | | Text masking | `POST /mask` returns `masked_text`; `mask_token` controls the placeholder format. | | Health check | `GET /health` returns service status, model name, whether the model has been loaded, and auth status. | | API docs | `/docs` provides Swagger UI, and `/openapi.json` provides the OpenAPI JSON. | | Authentication | Supports the `x-api-key` header and `Authorization: Bearer `. | | Deployment | Supports npm startup, PM2 daemon mode, and Docker deployment. | | Model precision | Supports downloading precision variants such as `fp32`, `fp16`, `q4`, `q4f16`, and `quantized`. | When Snow CLI calls the masking API, it sends a request like: ```json { "text": "text to redact", "aggregation_strategy": "simple", "mask_token": "[{label}]" } ``` The expected response is: ```json { "model": "openai/privacy-filter", "masked_text": "redacted text", "entities": [] } ``` Therefore, the URL configured in Snow CLI should be the full `/mask` endpoint, for example: ```text http://127.0.0.1:3000/mask ``` ## Quick Deploy the Privacy Filter API ### Requirements The deployment machine needs: - Git - Node.js 20 or later - npm - Python 3, only required for the initial Hugging Face model download ### One-command Installation with PM2 Daemon Run from any directory: ```bash git clone https://github.com/MayDay-wpf/privacy-filter-api.git privacy-filter-api cd privacy-filter-api npm install npm run install:daemon ``` The script installs dependencies, checks the local model, asks which model precision to download if needed, and starts `privacy-filter-api` with PM2. Common options: ```bash npm run install:daemon -- --precision fp16 npm run install:daemon -- --dir /opt/privacy-filter-api --precision fp16 npm run install:daemon -- --yes npm run install:daemon -- --no-startup ``` For first-time use, `fp16` is recommended because it usually provides a good balance between size and speed. Use `fp32` if you prioritize precision, or try `q4` / `q4f16` if resources are limited. After installation, check the service with: ```bash pm2 status pm2 logs privacy-filter-api pm2 restart privacy-filter-api ``` ### Manually Download the Model and Start If you want to control model precision manually, run: ```bash git clone https://github.com/MayDay-wpf/privacy-filter-api.git privacy-filter-api cd privacy-filter-api npm install npm run download:model -- fp16 npm run start:model -- fp16 ``` By default, the service listens on: ```text http://127.0.0.1:3000 ``` Health check: ```bash curl http://127.0.0.1:3000/health ``` The model is loaded lazily on the first `/detect` or `/mask` request, so `loaded:false` in the health check is normal before the first inference request. ### Configure API Key Copy the sample environment file: ```bash cp .env.example .env ``` It is recommended to set an API key: ```env API_KEY=your-secret-key API_KEY_HEADER=x-api-key TRANSFORMERS_DTYPE=fp16 LOCAL_FILES_ONLY=true ``` After this, `/detect` and `/mask` require an API key. `/health`, `/docs`, and `/openapi.json` remain public. Snow CLI sends both of the following headers: ```text x-api-key: your-secret-key Authorization: Bearer your-secret-key ``` So you only need to enter the same API key in Snow CLI Privacy Settings. ## Configure Privacy Settings in Snow CLI ### Open the Settings Page 1. Start Snow CLI. 2. Select `Privacy Settings` on the welcome screen. 3. Choose the configuration location, enable the privacy filter, fill in API settings, and select which tool results should be redacted. ### Configuration Location Privacy Settings support two locations: | Location | Description | | --- | --- | | Project settings | Saved in the current project's settings and only applies to the current working directory. Use this when you only want protection for a specific project. | | Global settings | Saved in user-level settings and applies to directories without project-level overrides. Use this when all projects share the same local privacy filter service. | Project settings have higher priority than global settings. If the current project defines `privacy.enabled`, API URL, or the tool list, Snow CLI uses the project value first; missing fields fall back to global settings. ### Enable Privacy Filter Toggle the `Enable Privacy Filter` item: - `Enabled`: tool results enter the privacy filtering flow according to the remaining settings. - `Disabled`: Snow CLI does not call the privacy filter API, and tool results remain unchanged. Note: even when enabled, a valid API URL is still required before redaction can happen. ### API Configuration Open `API Config` and fill in: | Field | Example | Description | | --- | --- | --- | | URL | `http://127.0.0.1:3000/mask` | Required. Use the full `/mask` endpoint. | | API Key | `your-secret-key` | Optional. Required if the service has `API_KEY` configured. | | Model | `openai/privacy-filter` | Model name. The default is `openai/privacy-filter`. It is mainly used for recording and UI display at the moment. | Recommended configuration: ```text URL: http://127.0.0.1:3000/mask API Key: your-secret-key Model: openai/privacy-filter ``` ### Tool Result Detection Configuration Open `Tool Results Config` to select which tools should have their returned content redacted. The default enabled tools are: ```text filesystem-read ace-search terminal-execute ``` Common recommendations: - `filesystem-read`: recommended. File content may include names, email addresses, tokens, paths, or customer data. - `ace-search`: recommended. Search results may include source snippets or sensitive information in comments. - `terminal-execute`: recommended. Command output may include environment variables, logs, usernames, paths, or API responses. - `websearch-*`: enable as needed. Public web content usually does not need redaction, but enable it if search results may include user-provided sensitive text. - MCP tools: decide based on business context. Enable redaction for MCP tools that return customer data, tickets, or database query results. ### Custom Rules Open `Custom Rules` to add, edit, enable/disable, and delete user-defined regex masking rules. Custom rules apply in both Local Rules mode and Online API mode: in local mode they are matched together with the built-in rules; in API mode they run once more on the text returned by the remote filter. | Field | Description | | --- | --- | | Name | Required, used for display and identification, up to 120 characters. | | Pattern | Required, JavaScript regex syntax, up to 2000 characters. To share rules with Snow App, a leading `(?i)` / `(?m)` / `(?s)` flag and `(?P...)` named groups are also accepted. | | Capture group | Capture group to mask; `0` masks the whole match. | | Replacement | Literal replacement text; leave empty to mask every character with `*`. | | Status | Disabled rules are kept but not applied. | | Test sample | Enter sample text to preview this rule's masking result below; the sample is not saved. | Saving validates that the regex compiles and the capture group exists; each location holds at most 200 rules. Rules are stored in `privacy.customRules` of the selected location and, like other fields, the project value wins over the global one. You can also edit `settings.json` directly: ```json { "privacy": { "customRules": [ { "id": "custom_order_no", "name": "Order number", "pattern": "(?i)order[-_ ]?no[:=]\\s*(\\w+)", "group": 1, "replacement": "[ORDER]", "enabled": true } ] } } ``` Note: JavaScript regexes use backtracking, so avoid patterns such as `(a+)+` that can cause catastrophic backtracking. #### Let the AI write rules for you Snow CLI ships a built-in `privacy-rules` Skill and `privacy-rules.*` commands on the session-command control plane. Just describe what you need in chat, for example "mask employee ids like EMP-1234 in logs". The AI will: 1. Ask for sample text and whether the key should stay visible; 2. Dry-run the regex on the samples with `privacy-rules.test` (read-only, no config writes) and iterate until it matches correctly; 3. Show the final rule and masked preview and ask for your approval; 4. Save it with `privacy-rules.upsert` (requires confirmation) to the project or global settings. You can also call the commands from a terminal: ```bash snow cmd privacy-rules list --json snow cmd privacy-rules test '{"sample":"by EMP-1234","pattern":"\\bEMP-\\d{4}\\b"}' --json snow cmd privacy-rules upsert '{"name":"Employee id","pattern":"\\bEMP-\\d{4}\\b"}' --yes snow cmd privacy-rules remove "Employee id" --yes ``` ## Test the Masking Service Use curl to verify the service first: ```bash curl -X POST http://127.0.0.1:3000/mask \ -H 'content-type: application/json' \ -H 'x-api-key: your-secret-key' \ -d '{"text":"My name is Harry Potter and my email is harry.potter@hogwarts.edu.","mask_token":"[{label}]"}' ``` Example successful response: ```json { "model": "openai/privacy-filter", "masked_text": "My name is [private_person] and my email is [private_email].", "entities": [ { "label": "private_person", "score": 0.9999, "text": " Harry Potter", "start": 10, "end": 23 }, { "label": "private_email", "score": 0.9999, "text": " harry.potter@hogwarts.edu", "start": 40, "end": 67 } ] } ``` If curl succeeds, enter the same `/mask` URL and API key in Snow CLI. ## Docker Deployment Example Build the image: ```bash docker build -t privacy-filter-api . ``` Run the container and mount the local model directory: ```bash docker run --rm \ -p 3000:3000 \ -e API_KEY=your-secret-key \ -e TRANSFORMERS_DTYPE=fp16 \ -e LOCAL_FILES_ONLY=true \ -v "$PWD/models:/app/models" \ -v "$PWD/.cache:/app/.cache" \ privacy-filter-api ``` If the model was downloaded into the image during build, you can omit the `models` mount. ## Troubleshooting ### Snow CLI Does Not Redact Anything Check: 1. Whether `Enable Privacy Filter` is set to Enabled. 2. Whether the API URL is the full `/mask` endpoint, not just the service root. 3. Whether the current tool is selected in `Tool Results Config`. 4. Whether project-level settings override global settings. 5. Whether the API key matches the `API_KEY` in the service `.env` file. ### Health Check Works, but the First Masking Request Is Slow This is normal. `privacy-filter-api` loads the model on the first `/detect` or `/mask` request, so the first request is slower than later requests. ### 401 Unauthorized The service has API key authentication enabled, but the API key in Snow CLI is missing or incorrect. Confirm: ```env API_KEY=your-secret-key API_KEY_HEADER=x-api-key ``` Then enter the same `your-secret-key` in Snow CLI `API Config`. ### Original Content Is Returned Unchanged Possible causes: - The model did not detect any PII in the text. - The privacy filter API request failed, and Snow CLI preserved the original content to avoid interrupting the workflow. - The URL is incorrect and does not point to `/mask`. - The model precision or local model files do not match `TRANSFORMERS_DTYPE`. ### Production Recommendations - Deploy the service on localhost or a trusted internal network whenever possible. - Set `API_KEY`; do not expose an unauthenticated service to the public internet. - Keep `LOCAL_FILES_ONLY=true` to avoid runtime remote model downloads. - Use a firewall or reverse proxy to restrict access sources. - For highly sensitive projects, prefer project-level settings and explicitly select which tools require redaction.