Skip to content

feat(claude): trust the project of a permission_policy "allow" task#5

Open
Antisophy wants to merge 1 commit into
CyberShadow:masterfrom
Antisophy:feat/trust-allow-workspaces
Open

feat(claude): trust the project of a permission_policy "allow" task#5
Antisophy wants to merge 1 commit into
CyberShadow:masterfrom
Antisophy:feat/trust-allow-workspaces

Conversation

@Antisophy

Copy link
Copy Markdown
Contributor

Problem

A recent Claude Code version added a per-workspace "trust" gate. When claude runs non-interactively (the -p / stream-json mode cydo uses) it can't show the interactive trust dialog, so it treats the working directory as untrusted and silently drops that project's settings.local.json permissions.allow entries (and its project hooks), printing:

Ignoring 31 permissions.allow entries from .claude/settings.local.json: this workspace has not been trusted. Run Claude Code interactively here once and accept the trust dialog, or set projects["/path/to/workspace"].hasTrustDialogAccepted: true in ~/.claude.json.

This affects every cydo task, because cydo always runs non-interactively. Three things make it awkward to handle from outside cydo:

  • --dangerously-skip-permissions (which cydo already passes) bypasses the permission checks, but not the trust layer, so tools still run while the allow-list and hooks stay ignored.
  • There is no CLI flag to grant trust. The only non-interactive mechanism Claude documents is the projects[<dir>].hasTrustDialogAccepted: true key in ~/.claude.json named in the message above.
  • Trust is keyed per-directory and is not hierarchical: trusting a parent directory does not trust its children, so a workspace whose tasks run in several project directories needs each of them trusted independently.

Approach

When launching a claude session whose workspace permission_policy is "allow", mark that task's working directory as a trusted project in ~/.claude.json.

Keying this off permission_policy: "allow" is deliberate: a workspace configured to auto-allow every tool call is already an explicit statement that the operator trusts it, so reflecting that intent into Claude's trust store is consistent with the existing configuration rather than a separate trust knob. Firing at session launch against the exact directory the session runs in trusts precisely the projects tasks actually enter (including project-discovery subdirectories) and nothing speculative.

Safety

The write is idempotent and atomic. It reads the existing config, returns immediately if the directory is already trusted, and otherwise merges the single flag in and writes via a temp file plus rename so the file is never left half-written. Because it only writes when the flag is genuinely missing, it becomes a no-op read after the first launch in a given project, which keeps the unavoidable window where it races Claude's own writes to ~/.claude.json as small as possible. Any failure is caught and logged; it never throws into session launch.

Limitations

  • It keys off the literal permission_policy == "allow"; a Djinja-expression policy that resolves to allow per-call won't trigger it, since the policy isn't reduced to a single value at the session level.
  • For a sandboxed workspace whose HOME or paths are remapped, the host-side write and the workDir path may not match what the sandboxed claude sees. This targets the common case of unsandboxed allow/trusted workspaces.
  • Claude-only; Codex and Copilot have no equivalent gate.

Test

A hermetic unit test (temp paths) covers the merge: the target directory becomes trusted, an unrelated key and an already-trusted sibling project both survive (merge, not clobber), and a second run is idempotent.

Run non-interactively (cydo's -p mode), Claude leaves a directory untrusted and silently ignores its settings.local.json permissions.allow entries (and project hooks), warning "Ignoring N permissions.allow entries ... this workspace has not been trusted". Trust is keyed per-directory in ~/.claude.json (projects[<dir>].hasTrustDialogAccepted), so each project a task runs in needs its own flag, not just the workspace root.

A workspace configured to auto-allow every tool call is already a statement of trust, so before launching a claude session whose workspace permission_policy is "allow", mark that task's working directory as a trusted project. Idempotent and atomic (merge into existing config, temp-file + rename, only when the flag is missing); never throws into session launch.

Covered by a hermetic unit test (temp paths) asserting the target project is trusted, existing config is preserved, and the write is idempotent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant