Why data permissions?
By default, a pipe has full access to all screenpipe data: every app, every window, all content types, 24/7. This is fine for personal pipes, but problematic for:- Team deployments: Admins need to prevent AI agents from accessing sensitive apps (1Password, banking, HR tools)
- Compliance: HIPAA, GDPR, SOC 2 require deterministic access control
- Privacy: Users want to run third-party pipes without giving full access
- Security: A malicious or buggy pipe shouldn’t be able to exfiltrate password manager data
YAML frontmatter fields
All fields are optional. Omitting a field means “no restrictions.”App filtering
- Case-insensitive substring matching:
"slack"matches"Slack","slack.app","Slack - General" deny-appsalways wins overallow-apps- Empty
allow-apps= allow all (except denied)
Window filtering
- Glob patterns:
*matches any sequence,?matches any single character - Case-insensitive
deny-windowsalways wins overallow-windows
Window titles are the text in the app’s title bar. For browsers, this is usually the page title. For editors, it’s the file name.Examples:
- Chrome:
"Google Docs - Project Plan" - VS Code:
"screenpipe-js/index.ts - VS Code" - Zoom:
"Zoom Meeting - Standup"
Content type filtering
ocr— Text extracted from screen (accessibility tree + OCR fallback)audio— Speech transcriptionsinput— Typing, clicks, clipboard, app switchesaccessibility— UI elements (buttons, labels, menus)
deny-content-types wins over allow-content-types.
Time & day restrictions
time-range: Format isHH:MM-HH:MMin 24-hour time. Uses local timezone.days: Comma-separated. AcceptsMon,Monday,Tue, etc.- Both filters use the timestamp of the data item (when it was captured), not when the pipe runs.
Endpoint gating
allow-raw-sql: Iffalse, the pipe cannot call/raw_sqlendpoint. Default:true.allow-frames: Iffalse, the pipe cannot access/frames/*endpoints (screenshots). Default:true.
Complete example
Here’s a pipe for team standups that only accesses work-related data during business hours:- ✅ Can access Slack, Notion, GitHub during work hours
- ❌ Cannot access 1Password or incognito windows
- ❌ Cannot see what was typed or copied
- ❌ Cannot query raw SQL or view screenshots
- ❌ Cannot access any data outside 9am-6pm on weekdays
Three-layer enforcement
Permissions are enforced at three independent layers:1. Skill gating (prevent agent from learning)
If a pipe hasallow-raw-sql: false, the Pi agent doesn’t get the skill/tool for raw SQL queries. The agent doesn’t even know the endpoint exists.
Similarly for allow-frames: false — the agent doesn’t learn about screenshot endpoints.
This prevents the agent from attempting unauthorized actions.
2. Agent interception (block before execution)
If skill gating is bypassed (e.g., agent hallucinates an API call), the Pi extension intercepts API calls before execution. It:- Parses the HTTP request URL and params
- Checks against
PipePermissions(fromSCREENPIPE_PIPE_PERMISSIONSenv var) - Filters results based on app, window, content type, time, day
- Returns filtered results (or error if endpoint is blocked)
3. Server middleware (enforce at API boundary)
If agent interception is bypassed (e.g., agent spawns a curl subprocess), the screenpipe server middleware validates every request:- Extracts
pipe_tokenfromX-Pipe-Tokenheader - Looks up associated
PipePermissionsin the token registry - Blocks requests to denied endpoints (e.g.,
/raw_sqlifallow-raw-sql: false) - Filters response data based on permissions
Why three layers?
- Skill gating: Performance — don’t waste tokens teaching the agent about skills it can’t use
- Agent interception: User experience — filter results transparently without error messages
- Server middleware: Security — enforce at the trust boundary, even if agent is compromised
PipePermissions struct, ensuring consistency.
How permissions are resolved
- Queue time: When the scheduler queues a pipe execution, it calls
PipePermissions::from_config(&pipe_config)to resolve the YAML frontmatter into aPipePermissionsstruct. - Token generation: A cryptographic token is generated and associated with the permissions in the token registry (a
DashMapon the app state). - Agent spawn: The
PipePermissionsstruct is serialized to JSON and passed as theSCREENPIPE_PIPE_PERMISSIONSenv var to the Pi agent subprocess. The token is stored in the agent’s config. - API calls: When the agent calls the screenpipe API, it includes the token in the
X-Pipe-Tokenheader. The server middleware validates the token and enforces permissions. - Cleanup: When the execution finishes (completed, failed, or cancelled), the token is removed from the registry.
Permission semantics
Deny always wins
If a field appears in both allow and deny lists, deny wins:Empty allow = allow all
Ifallow-apps is empty (or omitted), all apps are allowed (except explicitly denied):
Filters are AND
All filters must pass for a data item to be included:- App is Slack, AND
- Content type is OCR, AND
- Timestamp is between 9am-5pm
Time filters use data timestamp
time-range and days filter by the timestamp of the data (when it was captured), not when the pipe runs.
Example:
Testing permissions
Manual test runs
Run the pipe manually via UI and check the output. If data is missing, check:- Does the pipe’s frontmatter allow that app/window/content type?
- Is the data timestamp within the allowed time range?
- Are you using
allow-raw-sql: true? (Try setting tofalseto isolate)
Check logs
Execution logs (~/.screenpipe/pipes/{pipe_name}/logs/{timestamp}.json) include:
- The resolved
PipePermissions(what the agent was allowed to access) - API calls made (endpoint, params, response size)
- Any permission-denied errors
Permission-denied responses
If the agent tries to access denied data, the API returns:Team deployments
For screenpipe Teams, admins can push pipe configs with data permissions to all employees:- Admin creates a pipe with strict permissions in the admin dashboard
- Pipe is synced to all team members’ devices
- Employees can run the pipe but cannot modify its permissions (config is read-only)
- Employees can add stricter filters (e.g., also block personal email) via override rules, but cannot weaken admin-set restrictions
FAQ
Can I bypass permissions by using raw SQL?
Can I bypass permissions by using raw SQL?
No. If
allow-raw-sql: false, the server middleware blocks /raw_sql requests entirely. The agent gets a 403 error.Even if allow-raw-sql: true, the agent can only query the database — all app/window/time filters are still enforced at the server middleware layer (the SQL query must include WHERE clauses that respect the permissions).Can the agent spawn a subprocess to bypass the extension?
Can the agent spawn a subprocess to bypass the extension?
The extension filters API calls, but if the agent spawns a subprocess (e.g.,
curl), the request goes directly to the server. This is why server middleware is the final enforcement layer — it validates all requests regardless of how they’re made.Do permissions affect manual runs?
Do permissions affect manual runs?
Yes. Permissions are enforced for both scheduled and manual runs. The frontmatter is always respected.
Can I use environment-specific permissions?
Can I use environment-specific permissions?
Not directly. Permissions are defined in
pipe.md and apply to all runs. Workaround: create multiple pipes with different names and permissions (e.g., standup-dev, standup-prod).What if I have no restrictions?
What if I have no restrictions?
If all permission fields are omitted (or set to defaults),
PipePermissions::has_any_restrictions() returns false. The agent runs with full access, and the permissions file is not written (saves resources).Can permissions restrict output files?
Can permissions restrict output files?
No. Permissions only control input data (what the agent reads from screenpipe). The agent can write to
./output/ and call external APIs regardless of permissions.To restrict output, use file system permissions on the pipe’s directory.Next steps
Creating Pipes
Step-by-step guide to writing pipes
Examples
Real pipe examples with various permission patterns
Teams
Deploy pipes with centralized permissions to your team