ClearFrame

Security · Architecture

Designing the permission model for a coding agent

In build 1.15.9, a task that had already run a shell command refused to accept an elevation to Full access. The access menu closed without a message, and the level appeared stuck at its previous value.

Last updated

The defect was reported as a stuck setting. It was not. The persistent shell belonging to the task had been opened under the earlier access level, and granting a new one would have left a process running with permissions that no longer matched the configuration.

ClearFrame now closes the task's persistent shell before applying the change. The release note for 1.15.9 states the resulting behaviour: the level selected is the level that applies, "and a switch that is still refused tells you why instead of closing silently."

The repair is the visible part of a permission model that is mostly invisible until it is tested. The model itself has three levels.

Three levels

The application names them for what they permit. The descriptions below are its own.

Access levels as presented when a task is created.
LevelScope
Read onlyThe task can inspect the project and cannot modify it.
Workspace accessChanges are confined to the project folder. The default for ordinary work.
Full accessThe task can read and change files available to the macOS user account.

Elevation is requested in a dialog rather than configured in advance. The dialog states the consequence in the same words used to name the level — that the task can read and change files available to the user account — so the decision is made against a description of its scope rather than a label.

A global preference set before the task begins would move that decision to the moment when the least is known about what the task will need.

Why long-lived processes complicate permissions

Most permission models assume the unit of work is a command. That assumption fails once a task keeps a shell session alive across turns, which is what allows an agent to remain in the correct directory, retain an environment and hold a long-running process.

A process that outlives the decision that created it carries the old decision with it. Any tool that supports both persistent shells and mid-task permission changes has to decide what happens to that process. Closing it keeps the displayed setting and the running reality in agreement.

The second half of the repair

Closing the shell was one change. The other was making the refusal audible. A control that declines an action and reports nothing is indistinguishable, from the user's side, from a control that is broken. The 1.15.9 note records both: the level applies, and a switch that is still refused explains itself.

What the levels do not claim

They bound the scope of a task. They are not a sandbox against hostile code: a task with workspace access runs as the user. ClearFrame does not present access levels as a security certification, and the security page states what is claimed, including the absence of any third-party certification.

Remote execution is a separate boundary. Where it is used, it runs in a separate workspace, and local files are not uploaded automatically.

What Full access permits, exactly

The dialog does not describe Full access as unlimited. It states that the task can read and change files available to the macOS user account, which is a boundary with a definition rather than an absence of one. Files owned by another user, protected by system integrity protection, or reachable only with elevated privileges remain out of reach.

The distinction matters when reading the level name. "Full" describes the scope the application can offer, not the machine. A reader who takes it to mean root privileges will misjudge the risk in both directions: expecting more capability than exists, and less caution than the level warrants.

Why the default is the middle level

Workspace access is the default for a reason that is about the shape of agent work rather than about caution. Nearly all coding tasks read and write files inside one project. A default of Read only would require an elevation prompt for the first legitimate write of every task, and a prompt that appears every time is a prompt that gets dismissed without reading.

A default of Full access would remove the prompt entirely and leave the scope undisclosed. The middle level keeps the prompt meaningful: it appears when a task genuinely needs to reach outside the project, which is the moment a person should think about it.

The elevation record

Because elevation happens mid-task, it has to be visible after the fact. A reviewer reading a change set needs to know which access level the task was running at when it produced them, since a change that reaches outside the project is consistent with Full access and inconsistent with Workspace access. A diff on its own does not carry that context.

Why the fix took the shape it did

The alternative to closing the persistent shell would have been to keep it running and treat the new level as applying only to subsequent commands. That is defensible in a diagram and wrong in practice, because the shell retains the environment and working directory it was opened with, and a command issued after the change would still run against the old context. Closing the shell makes the setting true rather than approximately true.

Related reading

Choosing an access level, in the documentation. The defect and its resolution are recorded in the 1.15.9 release note, and the boundary of what the product claims is set out at Security.