Additional
Access Profiles
Synced from github.com/CoWork-OS/CoWork-OS/docs
Access profiles are CoWork OS's canonical way to decide what an agent may do. They package the execution sandbox, approval behavior, reviewer behavior, network posture, and optional filesystem/domain boundaries into one named policy that is carried with the task.
This follows the access model described in the official Codex sandbox guide: sandboxing defines the technical boundary, while approval policy defines when the agent must stop and ask. CoWork adapts that model into a local, named profile contract. Command tools are part of the selected profile; there is no separate user-facing Shell enabled or Shell disabled switch for a new task.
Quick choice
The main composer exposes these built-in profiles:
| Profile | Sandbox | Approval and reviewer | Network | Best for |
|---|---|---|---|---|
| Ask for approval | workspace-write | on-request / user | on-request | Interactive work where boundary-crossing or risky actions should be shown to the operator |
| Approve for me | workspace-write | on-request / auto-review | on-request | The same bounded workspace posture with fewer interruptions for actions that pass automatic review |
| Full access | danger-full-access | never / none | enabled | Trusted local work that needs high autonomy |
| Custom | Named profile | Named profile | Named profile | A repeatable policy for a workspace, team, automation, or integration |
The local runtime keeps the legacy tool-approval popup queue disabled by default. An allow decision
executes silently. A decision that remains ask is presented as an assistant
message with a durable inline Deny / Allow once input card, including for
network access, credentials, exports, MCP or external side effects, eligible
outside-workspace paths, and operations that explicitly opt out of automatic
approval. This keeps the interaction aligned with Codex-style harnesses while
preserving an explicit human decision where policy requires one. Set
COWORK_APPROVAL_PROMPTS=on before launching CoWork only when you need the
legacy approval queue for diagnostics. Hard denials, administrator policy,
protected operating-system paths, and approval: "never" remain fail-closed.
Runs with nobody to answer the card (headless mode, cowork run, sub-agents,
bot and channel conversations, scheduled or no-human-input tasks) deny the
request instead.
When the permission engine can scope the request (a command prefix, domain, path, tool or MCP server) and allows saving a rule for it, the card also offers Always allow. Choosing it allows the operation and saves a workspace-local allow rule for that scope, so the same request in this workspace no longer asks. The rule is saved only after the decision passes the same checks as Allow once, and never for task-scoped consent or an exact-write review. Remove it from the workspace-local rules in the permission settings.
Private Browser Workbench dialogs and native credential confirmations are separate from the tool-approval queue. Automatic review cannot suppress them, and agent card fills require fresh approval without a standing grant. See Private browser credentials and checkout.
Full access is still subject to hard guardrails, protected operating-system
paths, administrator policy, and explicit export/location/credential consent.
Its never approval policy does not open a consent dialog: an operation that
needs missing authority is denied. Two exports to the model provider are the
exception and still ask when you can answer in the app: visual file analysis,
and reading one of your terminal tabs (read_terminal, once per tab for the
task; see Terminal Tabs). Full access is not
a promise that every native operation will be allowed.
Connected MCP tools are available to the agent without mentioning MCP, a server name, or an exact tool name. Their approval policy is independent of blanket external-service consent. In Settings → Integrations → MCP → Configure, Tool approvals supports the same policy choices as Codex:
- Automatic (
auto, the default): annotated read-only calls run silently; other calls run silently in Full access and ask in bounded interactive profiles. - Ask before writes (
writes): tools withannotations.readOnlyHint: truerun silently; other tools ask. - Ask before every call (
prompt): every call asks. - Allow without asking (
approve): calls run within the remaining hard policy.
Saved server configuration uses defaultToolsApprovalMode; toolApprovals
maps raw MCP tool names to per-tool overrides. These settings come from trusted
local configuration, never model arguments. Missing annotations are treated as
potential writes, even when a tool name contains “search” or “read”. Disabled
servers, task restrictions, explicit permission rules, administrator policy,
network denials, endpoint domain restrictions, and read-only profile ceilings
still apply. An explicit prompt or write approval requirement combined with
approval: "never" denies the call: to approve an MCP write such as a Workday
change, run the task under Ask for approval or Approve for me. The
approval card names the server and shows the call's arguments exactly as they
will be sent. MCP payment tools retain their separate payment consent and limits.
MCP calls execute through the configured server; the local subprocess sandbox
does not sandbox that server's internals. Configuring a server establishes the
MCP connection's authority. Network on-request does not add a second blanket
prompt to an already-authorized MCP call, while disabled networking and explicit
endpoint restrictions remain enforced.
The OpenAI Responses adapter preserves optional MCP arguments by explicitly
disabling implicit strict-schema normalization. MCP isError responses return
to the model as failed tool results, allowing corrected arguments without
disabling the tool. Transport failures still use normal failure handling.
Ordinary work and exceptions
The default Ask for approval profile authorizes file creation, editing, and artifact generation inside the selected workspace, including an isolated temporary session folder. Routine commands run without approval when the required sandbox is available. These actions create normal tool activity, not requested/granted approval events. Approve for me uses the same boundary; its reviewer handles only eligible exceptions.
Explicit ask rules, external side effects, protected credentials, and eligible
filesystem/network boundary crossings remain separate requirements. In an
interactive task they produce the inline assistant decision card; in a task
with nobody to answer it they fail closed. Explicit denials
and custom scope ceilings cannot be overridden by an approval. A bounded profile
can also use approval: "never": allowed work runs; missing authority is
reported as a denial, without entering an approval wait. Approval cards and
legacy approval rows do not survive a restart; the operation must be requested
again so it can receive a fresh decision.
Allowed subprocess network access requires actual backend enforcement. A missing
sandbox does not itself authorize an unsandboxed retry. External ACP runtimes
cannot enforce CoWork's bounded filesystem and network rules, so bounded tasks
must use the native runtime. ACP requires explicit unrestricted Full access and
compatible administrator policy, and retains its separate consent flags. A
CoWork profile never silently sets the adapter to approve-all.
Select a profile
Desktop tasks
- Open the main task composer.
- Open the Permission access mode selector.
- Choose Ask for approval, Approve for me, Full access, or a saved custom profile.
- Send the task or follow-up.
The selector applies to the next task or follow-up that supports execution. The selected profile is persisted in task metadata so resuming the task does not silently adopt a broader profile later.
Defaults and custom profiles
Open Settings → System & Security → Permissions to:
- choose the default profile for newly created tasks;
- create, edit, validate, or remove custom profiles;
- review profile rules and workspace-local permission rules; and
- see the effective profile used by the runtime.
Custom profiles are stored through CoWork's encrypted settings store. The
current CoWork implementation does not treat a plain-text config.toml as the
authority for access profiles. The visible Custom choice is the UI for the
same named-profile concept, with settings validated before they are persisted.
Managed-agent environments (Workspace agents on the Bots page) also have an Access profile field. It controls the profile inherited by managed sessions; command tools, filesystem access, network access, and approvals follow that profile.
Access profiles versus work choices
An access profile answers what the task may do. The separate Ask/Do
choice answers whether CoWork should discuss supplied content or work on a task;
advanced runtime overrides and orchestration controls shape how task work runs.
The legacy chat, plan, analyze, execute, and verified values remain in
the runtime contract, but they are not five peer choices in the main composer.
The legacy Autonomous toggle can reduce optional pauses and enable eligible
automatic approval behavior, but it cannot add a tool, widen a profile boundary,
defeat an explicit deny, or bypass a hard guardrail. Choose Full access
explicitly when a trusted task genuinely needs the full-access profile.
What a profile controls
An access profile has these independent dimensions:
| Field | Values | Meaning |
|---|---|---|
sandbox | read-only, workspace-write, danger-full-access | Process/filesystem boundary applied to spawned commands and code execution |
approval | untrusted, on-request, never | Baseline approval posture; hard denials remain hard |
reviewer | user, auto-review, none | Whether a user or automatic safety reviewer handles approval decisions |
network | disabled, on-request, enabled | Coarse network capability and approval posture |
workspaceRoots | Relative or absolute paths | Additional roots that the profile may reach |
filesystemRules | read, write, deny | Deny-first path rules; write includes reads but never deletes |
domainRules | allow or deny patterns | Built-in network-tool destination boundaries |
extends | Another profile id | Inherit a profile and narrow it without widening the parent |
The profile also determines whether command tools can be materialized for the
task. A legacy shellAccess: false value can preserve an old denial, but new
profiles should not use a shell boolean as a second policy dimension.
Custom profile example
The following example keeps the normal workspace-write sandbox, limits network
tools to a documentation domain, permits writes under src, makes docs
read-only, and denies a sensitive directory:
{
"id": "review-repository",
"label": "Review repository",
"description": "Read the repository, update source files, and use approved docs APIs.",
"sandbox": "workspace-write",
"approval": "on-request",
"reviewer": "user",
"network": "on-request",
"filesystemRules": [
{ "path": "docs", "access": "read" },
{ "path": "src", "access": "write" },
{ "path": ".env", "access": "deny" }
],
"domainRules": [
{ "pattern": "docs.example.com", "access": "allow" },
{ "pattern": "*.example.com", "access": "deny" }
]
}
Paths that are not absolute are resolved relative to the active workspace.
workspaceRoots adds approved roots; it does not turn arbitrary paths into
approved paths. Filesystem rules are evaluated with component-aware path
matching after existing prefixes and symlinks are canonicalized.
Domain patterns are normalized to lowercase hostnames:
example.commatches that exact hostname;*.example.commatches subdomains, not the apex;**.example.commatches the apex and descendants; and*is unrestricted for that domain-rule dimension.
Deny rules win over allow rules. An allowlist is a boundary: if an effective profile has positive domain rules, a destination outside that allowlist is not made available by a later approval or a legacy mode.
Inheritance and narrowing
Custom profiles may use extends to share a baseline. Validation rejects:
- empty, duplicate, or built-in-colliding ids;
- missing parents and inheritance cycles;
- a child sandbox, approval, reviewer, or network setting that is broader than its parent;
- child filesystem roots/rules outside the parent's effective scope; and
- child domain allows that escape a parent's allowlist or remove a parent deny.
Inherited deny rules remain in the effective profile. A child can replace or narrow positive grants, but it cannot use inheritance to recover access that a parent denied.
This same ceiling applies to child tasks: a delegated task may choose a strictly narrower profile, but it cannot widen the parent task's sandbox, approval behavior, network, filesystem, or domain scope.
Agent access limits
An agent can carry an access limit. In the Calm theme's Team view it is May do alone: either No limit: each session's own access, or a profile. The limit only narrows what a session may do; it never grants access.
- A session assigned to the agent runs with its own profile when that is within the limit, with the limit when the session's profile is broader, and otherwise with the narrowest combination of the two. When the two can't be combined (for example, both name different filesystem or domain scopes), the session stops and asks you to change the limit in Team.
- Sub-agents and child tasks the session starts keep the limit, even when they
are assigned to another agent. Scheduled tasks it creates with
schedule_taskcarry the limit to every run. - A legacy session without a named profile asks before acting while a limit applies, and bypass-permissions mode cannot lift a limit.
- If the limit's profile is deleted or can't be read, the agent's sessions stop instead of running without the limit.
- Changing the limit applies to the agent's running sessions right away and to its other sessions when they next start. Limits already passed on to child tasks and schedules stay as they were when passed on.
- Reassigning a session to another agent requires permission to manage that session, and the session's audit records the previous and new agent and the access-limit change (unchanged, added, lifted or changed).
An agent's seniority (lead, specialist or intern) sets how often it checks in and who leads an agent team; it is not a permission. Change it with Edit agent in Team or More settings on the Bots page.
Resolution and compatibility
Profile resolution happens before individual tool approvals:
- An explicit task
accessProfileIdwins. - A configured
defaultAccessProfileIdis attached to new tasks that do not specify a profile or a legacy permission override. - If no named profile is configured, the compatibility mapping uses the existing permission settings and defaults.
- Existing persisted tasks that have only legacy
permissionModeorshellAccesskeep their prior behavior until the user explicitly selects a profile.
The profile is then applied to the workspace view used by that task. The per-request permission engine still evaluates hard task restrictions, guardrails, workspace capabilities, explicit rules, and approval defaults. The later stages cannot widen an earlier profile boundary.
Administrator policy can constrain the result. In particular, administrators can restrict legacy permission-mode mappings, allowed sandbox types, the requirement for sandboxed command execution, and shell egress. A scoped custom profile cannot use an unsandboxed process path that would bypass its filesystem or domain rules; CoWork constrains it to a representable sandbox instead.
If a named profile is missing, malformed, cyclic, or cannot be represented by the selected execution backend, CoWork uses an unavailable read-only profile:
- filesystem access is limited to safe reads;
- command tools and network access are unavailable;
- the task pauses with a user-action state and an
access_profile_unavailablereason; and - no approval prompt can turn that unavailable profile into a broader one.
Filesystem behavior
Profile filesystem access is evaluated separately for read, write, and
delete:
- a
writerule grants read and write, not delete; - an explicit
denyalways wins; - profile rules are checked before legacy
allowedPathsand unrestricted-file flags for profiled tasks; - macOS and Windows operating-system mutation roots remain protected;
..traversal, symlink escapes, macOS/privatealiases, and non-existent file suffixes are canonicalized before the decision; and- a plain path outside the workspace may receive a one-shot external-file approval only when no finite profile filesystem scope covers the task.
A finite profile scope is a hard boundary. The operator cannot use an external file approval, a session “Approve all” shortcut, or a legacy permission mode to expand it. Temporary-workspace scratch-file compatibility is retained only for unprofiled legacy tasks.
Applied skill packs
Plugin packs live outside the workspace. When a task applies a
directory-backed pack skill (/pack:skill or the Skill tool), file tools may
read that skill's pack folder without a prompt under every named profile, so
the skill can open its references/, scripts/, and assets/:
- the grant is read-only; writes and deletes in the pack are evaluated as for any other outside path;
- it covers only the pack
PluginRegistryloaded the applied skill from — not sibling packs, the extensions folder, or anything else; - the requested path and its canonical target must both be inside the pack root as canonicalized at load, so symlink escapes are denied;
- an explicit profile
denyrule, a workspace with reading turned off, and an unavailable profile still win; this also applies to finite (scoped) profiles, which can exclude packs with adenyrule on the extensions folder; - disabled, policy-blocked, and quarantined packs never qualify, and disabling a pack revokes the grant at once; and
- the grant is held per tool call from the task's applied skills, so it ends with the task and never reaches another task or a background service.
The decision reason is applied_skill_pack_read. Shell commands are not
covered by this grant. See
Plugin Packs.
Process backends reject filesystem policies they cannot enforce. In particular, macOS commands cannot move or remove host directories around protected descendants; Docker rejects writable workspace directory mounts and mounts that would expose denied or read-only descendants. Private process scratch remains available. See command-tool sandboxing for backend limits and supported alternatives.
Network and command behavior
Built-in browser, web, and HTTP tools evaluate profile network and domain rules
in-process. Read-only public lookups through web_search, web_fetch,
x_search, and GET/HEAD http_request use the normal read lane when the
workspace has network access. Network on-request remains useful as policy
metadata for browser navigation, MCP and other network-capable tools, code
egress, credential-backed reads, and explicit domain or workspace
boundaries, but the default local runtime does not turn those decisions into a
durable approval wait. data_export remains an explicit approval class even in
high-autonomy profiles, and location access always uses a separate
operating-system consent flow.
For on-request networking, every shell invocation requires explicit network
consent, including local-looking or encoded commands and background launches.
Approval applies only to that invocation; a previous approval does not authorize
the next command. The runtime rechecks the policy before launching the process,
and administrator policy can still prohibit networking. Code execution remains
network-disabled in this mode; use the built-in web/HTTP tools for its network
requests. Unrestricted code subprocess networking requires an enabled network
profile and administrator policy that permits it.
Arbitrary subprocess and code-execution networking is stricter. The native macOS and Docker sandbox boundaries provide coarse network isolation, not a domain-aware proxy. Therefore a profile with domain-scoped network rules cannot run arbitrary shell/code networking unless a domain-aware proxy exists; the request fails closed. Full-profile shell egress also depends on the coarse administrator shell-network gate.
In a network on-request profile, every run_command invocation requires
explicit approval for the command and its potential network access, including
background commands. Shell text cannot reliably identify networking inside
scripts, dynamic imports, or child processes, and the macOS sandbox's localhost
exception can reach a local proxy. Trusted commands, auto-review, command bundles,
and remembered recurring approvals do not replace this per-invocation decision.
A profile that also sets approval to never cannot run these commands because
the required consent is unavailable. Approval does not relax administrator
network restrictions or domain-scoped rules. Use an explicitly enabled network
profile when autonomous shell networking is intended.
Terminal tabs use the same profile boundary as command tools. A profile that does not permit command tools cannot open a new terminal tab. Existing tabs are revalidated when the profile changes, and a downgrade prevents further use.
Surfaces and inheritance
| Surface | Profile contract |
|---|---|
| Desktop composer | Shows the four access choices and carries the selected id with the task |
| CLI | cowork run "task" --access-profile <id> uses the same resolver; --permission-mode and --shell are compatibility inputs |
| Remote Control Plane | Sends the requested profile id to the target node, where it is resolved and enforced; local credentials/cookies are not transferred |
| Managed Agents | ManagedEnvironment.config.accessProfileId is the canonical environment setting; enableShell is legacy compatibility |
| Task automations and cron | New jobs inherit an explicit profile and cannot widen it through a step or trigger setting |
| Agent Teams and child tasks | Child profiles are capped by the parent profile |
| Agent roles | The role's access limit (May do alone) caps its sessions, their child tasks and the schedules they create |
| Side Chat | Does not expose command tools and cannot widen the inherited profile |
| Browser, connector, native, and device tools | Use the same profile, admin policy, and hard guardrails before execution |
| Heartbeat/Dreaming | Background memory reads use a profile-derived read guard; unavailable or denied profiles skip analysis rather than bypassing the boundary |
Migration from the shell toggle
The old shell switch was too narrow to describe the real access decision. The current migration behavior is:
- new desktop tasks use the configured named profile;
- the main UI no longer presents a shell enable/disable control;
- old task records and integrations may still carry
shellAccess,enableShell,defaultShellEnabled, or legacy permission modes; - those fields are read only at compatibility boundaries and do not override a selected named profile;
- the CLI
--shellflag remains a compatibility alias for the boundedask_for_approvalprofile, not a new unrestricted switch; and - managed environments should be edited to set
accessProfileIdexplicitly.
Do not edit the database to migrate a task. Choose a profile in the task selector, update the default in Settings, or update the managed environment through its supported UI/API surface.
Implementation map
The shared policy contract lives in:
src/shared/access-profiles.ts— profile types, built-ins, inheritance, and privilege comparison;src/electron/security/access-profile-resolver.ts— resolution, compatibility mapping, admin constraints, and workspace projection;src/electron/security/access-profile-paths.ts— canonical path and profile-filesystem evaluation;src/electron/security/skill-pack-read-access.ts— read-only grants for the plugin packs of a task's applied directory-backed skills;src/electron/security/permission-settings-manager.ts— validated encrypted persistence for defaults and custom profiles;src/electron/agent/runtime/PermissionEngine.ts— per-request hard-stop and approval decisions; andsrc/electron/agent/tools/shell-tools.tsand the tool registry — command availability and sandbox/network enforcement.
Useful verification commands:
npx vitest run src/shared/__tests__/access-profiles.test.ts src/electron/security/__tests__/access-profile-resolver.test.ts src/electron/security/__tests__/access-profile-paths.test.ts
npx vitest run src/electron/security/__tests__/skill-pack-read-access.test.ts src/electron/extensions/__tests__/registry-skill-pack-read-access.test.ts src/electron/agent/__tests__/executor-skill-pack-read-scope.test.ts
npx vitest run tests/tools/shell-tools.test.ts src/electron/agent/runtime/__tests__/PermissionEngine.test.ts
npm run type-check
npm run build:electron
npm run build:daemon
npm run build:react
Related documentation
- Permission System — request evaluation and rule precedence
- Security Model — defense layers and hard boundaries
- Security Configuration — operator settings
- Security Guide — practical safe-operation guidance
- CoWork OS CLI — local and remote profile selection
- Managed Agents — managed environment inheritance
- Task Automations — unattended profile behavior
- Terminal Tabs — interactive command sessions
- Remote Access — target-node enforcement
- Approval Boundary Migration Plan — implementation contract and migration decisions
- Approval Boundary Validation — executable scenario and platform evidence
Policy rollout and migration
Permission settings are migrated to version 2 with a bounded copy of the prior policy and migration provenance. New root tasks use one normalizer across the standard daemon entry point and direct creators such as tray, gateway, mailbox, and ACP. Explicit profiles win over defaults. Old profile-less tasks keep their legacy per-task authority; resuming them does not adopt a broader global default. Read-only helpers and child-task ceilings remain restrictive.
COWORK_ACCESS_POLICY_VERSION=boundary is the default runtime policy. Set
legacy for a diagnostic rollback or shadow to retain legacy decisions while
recording the compared boundary decision in the local policy trace. Shadow
comparison does not execute tools, create grants, or emit approval requests of
its own. It does not disable hard restrictions. Restore old settings only from a
reviewed migration snapshot; do not replay pending approvals during rollback.
Boundary grants are tied to operation arguments and policy identity. Changing the task scope invalidates incompatible cached grants. Existing approval history remains readable; new allowed actions do not manufacture approval history.
First-time Full access confirmation
Selecting Full access from the chat picker or Permissions settings shows a warning before the selection takes effect. The dialog explains file access, terminal commands, internet and connected apps (including computer use), sensitive-data exposure, and prompt injection. Cancel keeps the previous selection; Confirm applies it and remembers acknowledgement on this device. Later selections do not repeat the warning. Explicit deny rules, administrator policies, and operating system permissions remain in force.