# OpenScope OpenScope is a scoped access broker for AI agents. Today it brokers protected macOS app access such as Apple Notes and Apple Mail, and the same model can extend to sandboxed agents and future remote operations. In the broader Cylonix + OpenScope model, Cylonix provides secure private reach into environments, and OpenScope provides the brokered action layer on top of that reach. ## Architecture ``` AI agent → openscope CLI (thin client, one invocation per request) → openscoped daemon (signed background process, holds macOS Automation approval) → asapple helper (Swift binary that executes AppleScript in-process) → Apple Notes / Apple Mail ``` - **`openscope`**, CLI wrapper that sends requests to the daemon over a Unix socket or an optional localhost HTTP bridge - **`openscoped`**, signed broker daemon: validates requests, enforces policy, executes actions, appends audit events, returns results - **`asapple`**, compiled Swift helper co-located with `openscoped` inside the signed app bundle; the only process that directly touches Apple automation APIs App behavior is declared in YAML, actions, parameters, scripts, so new integrations can be added without changing Go code. ## Build ```bash go build ./... go test ./... go vet ./... ``` The `asapple` Swift helper and the signed macOS app bundle are built via Xcode. See [`macos/XcodeSetup.md`](macos/XcodeSetup.md) for setup instructions. To package for distribution: ```bash # Step 1: Xcode → Product → Archive → Distribute App → Developer ID → export to dist/export/ # Step 2: scripts/build_pkg.sh --version 0.1.0 # produces dist/OpenScope-0.1.0.pkg ``` ## Quick Start > **Governing a coding agent instead?** Brokered SSH to production, `sudo`-free > system actions, and per-agent policy + audit for Claude Code, Codex CLI, > Gemini CLI, and others, that's the main use case for many teams. See > [Coding agents](/docs/coding-agents) for the full setup (install, register, > grant scope, and wire the agent with a single plugin install). After installing the `.pkg`, an `openclaw` agent is pre-registered with default scoped access to Apple Notes and Apple Mail: ```bash # Verify the daemon is running openscope status # List notes in a folder openscope notes list_notes --agent openclaw --folder Work # Read a note openscope notes read_note --agent openclaw --folder Work --note "My Note" # Read just the body (plain text, suitable for piping) openscope notes read_note --agent openclaw --folder Work --note "My Note" --body-only # List up to 20 unread messages in Inbox openscope mail list_messages --agent openclaw --mailbox Inbox --limit 20 --unread true # Read a message by id openscope mail read_message --agent openclaw --mailbox Inbox --id "" # Read just the message body openscope mail read_message --agent openclaw --mailbox Inbox --id "" --body-only # Opt in to bundled passthrough apps such as Calendar sudo openscope app activate --agent openclaw calendar reminders # Validate the installed setup end to end openscope-diag ``` ## Commands ```bash # Protected app actions openscope --agent [flags] # Reset user config to the current app defaults openscope init --force # App management openscope app list openscope app show openscope app enable # user-defined apps only openscope app disable sudo openscope app activate --agent [app...] sudo openscope app deactivate --agent [app...] openscope app validate [--file ] # Policy management openscope policy list openscope policy show --agent openscope policy validate sudo openscope policy allow --agent --app --action [-- ...] sudo openscope policy deny --agent --app --action [-- ...] # Agent registry openscope agent register openscope agent list # Protected Notes folder blacklist openscope notes blacklist list sudo openscope notes blacklist add private sudo openscope notes blacklist remove hidden # Mail sender-domain allowlist openscope mail domains list sudo openscope mail domains add mycompany.com sudo openscope mail domains remove gmail.com # Root-owned HTTP profiles openscope http profiles list sudo openscope http profiles add --name jira-work --base-url https://example.atlassian.net --headers "Authorization=Basic ,Accept=application/json" sudo openscope http profiles remove jira-work # Root-owned SSH targets openscope ssh targets list sudo openscope ssh targets add --alias prod-api-1 --host prod-api-1.internal --user deploy --services web --path-prefixes /var/log/app sudo openscope ssh targets remove prod-api-1 # Diagnostics openscope status openscope doctor ``` ## Policy Rules control which agent may call which action, with optional parameter constraints. `deny` overrides `allow`; no matching `allow` defaults to deny. ```bash # Allow access to a specific folder only sudo openscope policy allow --agent my-agent --app notes --action list_notes --folder Work sudo openscope policy allow --agent my-agent --app notes --action read_note --folder Work # Block a folder (overrides any allow) sudo openscope policy deny --agent my-agent --app notes --action list_notes --folder Private ``` Policy is stored in `~/.openscope/policies.yaml`. Every allow and deny decision is appended to `~/.openscope/audit.jsonl`. OpenScope also enforces a root-owned protected-folder blacklist in `/Library/Application Support/OpenScope/protected_folders.yaml`. By default, folders whose names contain `private` or `hidden` are denied even if the user policy would otherwise allow them. For brokered HTTP integrations such as Jira, root-owned HTTP profiles live in `/Library/Application Support/OpenScope/http_profiles.yaml`. For brokered SSH integrations, named targets live in `/Library/Application Support/OpenScope/ssh_targets.yaml`. For Mail, the default `openclaw` policy is read-only and constrained to the `Inbox` mailbox. No attachment access is provided in the bundled app, and you can optionally restrict readable messages to specific sender domains with `/Library/Application Support/OpenScope/mail_filters.yaml` or the `openscope mail domains` CLI. If you want to reset your user-owned OpenScope YAML files to the current app defaults, run `openscope init --force`. ## Configuration Layout ``` ~/.openscope/ agents.yaml # registered agent IDs policies.yaml # allow/deny rules audit.jsonl # append-only decision log apps.d/ # user-defined app definitions (YAML) state/ enabled_apps.yaml # which user-defined apps are enabled run/ openscoped.sock # daemon Unix socket ``` ## Adding a Custom App 1. Create a YAML manifest following the schema in [`resources/bundled/apps/notes.yaml`](resources/bundled/apps/notes.yaml). 2. Place AppleScript files alongside it (or reference them via the `script:` field). 3. Copy the manifest to `~/.openscope/apps.d/myapp.yaml`. 4. Enable it: `openscope app enable myapp` Bundled apps (like `notes`) are always enabled and live in [`resources/bundled/`](resources/bundled/). For a worked example of a custom HTTP-backed app, see [`docs/jira_over_http.md`](docs/jira_over_http.md). ## macOS Automation Permission The first time `openscoped` accesses Apple Notes or Apple Mail, macOS may show a one-time Automation prompt. Accept it, or pre-grant via: **System Settings → Privacy & Security → Automation → OpenScope → Notes ✓ / Mail ✓** ## Exit Codes | Code | Meaning | |------|---------| | 0 | success | | 2 | invalid command or parameters | | 3 | denied by policy | | 4 | target not found | | 5 | executor or automation failure | | 6 | configuration or manifest error | | 7 | daemon unavailable or IPC failure | ## Troubleshooting ```bash openscope doctor # runs all diagnostic checks openscope status # daemon liveness, socket path, config summary # Restart the daemon launchctl kickstart -k gui/$(id -u)/com.ezblock.openscope.openscoped # Reset Notes Automation permission (triggers a fresh prompt on next use) tccutil reset AppleEvents com.ezblock.openscope && open /Applications/OpenScope.app ``` See [`docs/pilot_guide.md`](docs/pilot_guide.md) for a full walkthrough. ## OpenClaw Integration If you want to use OpenScope as the security boundary for an OpenClaw agent: - use the runtime instructions in [`docs/openclaw/SKILL.md`](docs/openclaw/SKILL.md) - use the setup guide in [`docs/openclaw_user_guide.md`](docs/openclaw_user_guide.md) - use the sandbox bridge guide in [`docs/nemoclaw_socket_demo.md`](docs/nemoclaw_socket_demo.md) for NemoClaw/OpenShell - use the install guide in [`docs/nemoclaw_install.md`](docs/nemoclaw_install.md) for client-only sandbox installs - use the architecture note in [`docs/cylonix_openscope_architecture.md`](docs/cylonix_openscope_architecture.md) for the Cylonix + OpenScope model For local native agents, keep using the `openscope` CLI directly. For sandboxed agents, use the same CLI and point it at either: - `OPENSCOPE_SOCKET` for a provisioned Unix socket - `OPENSCOPE_HTTP_URL` for a localhost bridge such as `http://host.docker.internal:42357` For local setups, OpenScope agent names are best treated as policy and audit labels. For enterprise deployments, registration and policy should be centrally managed and distributed to devices rather than created ad hoc on each machine. Common Apple apps such as Calendar, Reminders, Contacts, Safari, and Messages are now bundled as brokered passthrough apps. They are still denied by default until you opt in with `sudo openscope app activate --agent openclaw `. For Notes, a practical default is to name sensitive folders with `Private` or `Hidden`, or add more protected keywords with `sudo openscope notes blacklist add `. For Mail, keep the default scope to `Inbox` and optionally add sender-domain restrictions with `sudo openscope mail domains add `. ## License BSD 3-Clause, see [LICENSE](LICENSE).