Claude Code Settings

Table of Contents

Summary

This file is the single authoritative source for .claude/settings.json. It follows the literate programming style: every permission entry is accompanied by prose naming the operations it enables, the concrete command variations it covers, and the security reasoning behind the grant. Do not edit .claude/settings.json directly; regenerate it with compass build --direct settings. Entries are kept to the minimum necessary; each wildcard is chosen to cover only the intended surface.

How to regenerate

Via the Build pillar in --direct mode — Emacs only, no cmake/vcpkg, so it works in a light environment (the skills alias recreates the other generated half of .claude/):

compass build --direct settings          # .claude/settings.json
compass build --direct settings skills   # recreate all of .claude/

Or via the full-environment CMake target:

cmake --build --preset linux-clang-debug-ninja --target deploy_settings

Both invoke projects/ores.lisp/src/ores-build-settings.el, which tangles this file to .claude/settings.json. Requires Emacs on PATH. Must be run outside the sandbox (the ores-babel.el project detection needs a full environment; the CMake path also needs compiler detection during reconfiguration); use dangerouslyDisableSandbox: true on the Bash tool call.

Master settings block

The master block assembles the final JSON from noweb references defined in the sections below. It carries no :tangle directive; the output path (.claude/settings.json under the repo root) is injected by projects/ores.lisp/src/ores-build-settings.el via org-babel-default-header-args:json using the ores/repo-root variable from projects/ores.lisp/src/ores-babel.el. Sections are separated by a trailing comma in the reference line; the last section in each array carries no comma.

{
  "autoMemoryEnabled": false,
  "permissions": {
    "allow": [
<<perm-files>>,
<<perm-build>>,
<<perm-sql>>,
<<perm-compass>>,
<<perm-codegen>>,
<<perm-tests>>,
<<perm-vcs>>,
<<perm-gh-pr>>,
<<perm-web>>,
<<perm-shell>>
    ]
  },
  "sandbox": {
<<sandbox-network>>,
<<sandbox-filesystem>>,
<<sandbox-excluded>>
  }
}

Top-level settings

autoMemoryEnabled

Set to false to disable Claude Code's built-in harness auto-memory system, which otherwise writes MEMORY.md and per-topic *.md files under ~/.claude/projects/<hash>/memory/. ORE Studio uses its own version-controlled memory system under doc/llm/memory/ (see Project memory); running the harness system in parallel creates a second, unreviewed memory source that can contradict or duplicate the org system. Disabling it ensures all durable LLM memory is in the repo and tracked by git.

Permissions

Permission strings use glob wildcards (*), not regular expressions. * matches any sequence of characters including spaces but not /, so it covers arguments but not sub-paths. A space before * enforces a word boundary: Bash(make *) matches make -j2 foo but not make_something. Each subsection documents the surface covered and the reason the grant is necessary.

File access

Edit(**) and Write(**) grant read/write access to every file in the project tree without hardcoding an absolute path. Claude Code resolves permission globs relative to the directory containing .git — the project root — at startup. This means the same committed settings.json works across all checkouts regardless of where they live on disk (/mnt/development/..., /home/user/..., etc.).

** matches zero or more path segments including directory separators, so Edit(**) covers foo.txt, projects/ores.risk/src/foo.cpp, and any other path depth. This replaces the previous per-subtree entries (Edit(projects/**), Edit(doc/**), etc.) with a single grant that covers the whole tree.

Read(*) is not included here because Claude Code does not require an explicit allow entry for reads; they are permitted by default unless the sandbox filesystem deny-list blocks them.

"Edit(**)",
"Write(**)"

Build tools

The build system requires make, cmake, and (for non-compilation deploy targets) emacs in batch mode. All three are invoked with varying flags and targets depending on the operation.

Bash(make *) is broader than a path-restricted form but narrower than an unconditional build allow. Any make invocation is a compilation or deployment action; no make-based attack vector exists in this project context beyond unintended compilation.

Bash(cmake *) covers both configuration (cmake --preset) and build (cmake --build) steps. The wildcard is necessary because the preset name and target name vary.

Bash(emacs -Q --script *) covers the deploy-family targets (deploy_skills, deploy_settings, deploy_site) which invoke Emacs in batch mode. The -Q flag disables user configuration; --script restricts execution to the named file. Only scripts checked into the repository are passed here.

Bash(sccache *) covers direct invocations of the sccache compiler cache: starting or stopping the daemon (sccache --start-server, sccache --stop-server), querying statistics (sccache --show-stats), and manual cache management (sccache --zero-stats). CMake invokes sccache transparently as a compiler wrapper (CMAKE_CXX_COMPILER_LAUNCHER); those subprocess invocations do not require a separate entry, but direct calls from Claude do.

Common invocations:

  • make -C build/output/linux-clang-debug-make -j2 ores.utility
  • cmake --build --preset linux-clang-debug-ninja --target deploy_skills
  • cmake --build --preset linux-clang-debug-ninja --target deploy_settings
  • emacs -Q --script projects/ores.lisp/src/ores-build-skills.el
  • emacs -Q --script projects/ores.lisp/src/ores-build-settings.el
  • ./compass.sh build ores.utility.tests
  • sccache --start-server
  • sccache --show-stats
"Bash(make *)",
"Bash(cmake *)",
"Bash(emacs -Q --script *)",
"Bash(sccache *)"

SQL scripts

Four scripts under projects/ores.sql/ manage the local development database. Each is granted individually rather than via a directory wildcard (e.g. Bash(projects/ores.sql/* *)) to prevent accidental execution of other files in that tree.

compass db sql executes SQL against the database. compass db recreate drops and rebuilds the entire schema. validate_schemas.sh checks that the live schema matches expectations. kill_db_connections.sh terminates stale connections before a recreate.

All four require dangerouslyDisableSandbox: true at the Bash tool level because the sandbox blocks outbound connections to localhost:5432. The sandbox.network entry below grants localhost access, which may make the per-call override unnecessary once Claude Code respects project-level sandbox overrides.

Note: never prepend PGPASSWORD on the command line; these scripts source .env themselves.

Common invocations:

"Bash(projects/ores.compass/compass.sh db *)",

"Bash(projects/ores.sql/utility/validate_schemas.sh *)",
"Bash(projects/ores.sql/utility/kill_db_connections.sh *)"

Compass

Compass is the developer toolkit purpose-built to simplify LLM workflows: orientation (bearings, where, fleet), navigation (search, list, show), agile authoring (add, story new, task new), session continuity (journal), PR work (pr checks, review list/reply/resolve) and environment provisioning (env). CLAUDE.md's first instruction to every session is ./compass.sh bearings, and project memory directs the LLM to prefer compass over raw Unix tools and to use it for all agile artefacts.

A tool we mandate on every session must not pay a permission prompt per invocation. The grant is deliberately blanket rather than per-subcommand: compass's mutating surface is repo-local files (doc scaffolds, .journal.org, .env) and branch creation, all of which the session can already do unprompted via Edit=/=Write=/=git * — a read-only subset would add ceremony exactly on the highest-frequency flows (scaffolding, journaling) without adding safety. Compass is the trusted, recipe-documented boundary; authorising the entry point authorises its delegations (git, gh, codegen) through compass only.

All four invocation forms are covered: the root wrapper (what CLAUDE.md instructs), the component script, each with and without the ./ prefix.

Invocation convention: always call compass using one of these four relative forms from the project root. Never invoke it via its absolute path (e.g. /mnt/development/.../compass.sh) — absolute paths do not match any of the patterns below and will trigger a permission prompt. When the Bash tool's working directory has drifted into a subdirectory (e.g. after working in projects/ores.codegen), prepend a cd to the repo root before calling compass:

cd /mnt/development/Development/OreStudio/ores_dev_brave_hopper && ./compass.sh add capture ...
"Bash(./compass.sh *)",
"Bash(compass.sh *)",
"Bash(./projects/ores.compass/compass.sh *)",
"Bash(projects/ores.compass/compass.sh *)"

Code generation

codegen.sh is the main entry point for C++ and SQL code generation via ores.codegen (regenerate, generate subcommands). run_generator.sh drives the C++ code generator (Dogen). plantuml_er_generate.sh produces PlantUML ER diagrams. generate_doc.sh is a legacy script being decommissioned — use compass instead.

The grant is per-script rather than per-directory for the same reason as SQL: a directory wildcard would permit running arbitrary scripts in a large codegen tree.

Invocation convention: always call codegen using one of the relative forms below from the project root — with or without the ./ prefix. Never use an absolute path; absolute paths do not match the patterns below and trigger a permission prompt.

Common invocations:

  • ./projects/ores.codegen/codegen.sh regenerate --component refdata-cpp --profile all-cpp
  • projects/ores.codegen/codegen.sh regenerate --component refdata-cpp --profile all-cpp
  • projects/ores.codegen/codegen.sh generate --model path/to/model.json --profile all-cpp
  • projects/ores.codegen/run_generator.sh
  • projects/ores.codegen/plantuml_er_generate.sh -i doc/plans/foo.org
"Bash(./projects/ores.codegen/codegen.sh *)",
"Bash(projects/ores.codegen/codegen.sh *)",
"Bash(./projects/ores.codegen/generate_doc.sh *)",
"Bash(projects/ores.codegen/generate_doc.sh *)",
"Bash(./projects/ores.codegen/run_generator.sh *)",
"Bash(projects/ores.codegen/run_generator.sh *)",
"Bash(./projects/ores.codegen/plantuml_er_generate.sh *)",
"Bash(projects/ores.codegen/plantuml_er_generate.sh *)"

Test execution

Tests are run either through CTest (which dispatches to individual binaries) or by invoking binaries directly for focused runs. Test binary paths follow the pattern build/output/<preset>/publish/bin/ores.<component>.tests.

Bash(ctest *) covers all CTest-mediated runs including the rat target (which runs all registered suites). The direct-binary pattern Bash(build/output/*/publish/bin/ores.* *) uses two wildcards: the first matches the preset directory name (e.g. linux-clang-debug-make) without crossing / boundaries; the second matches the component name suffix and any arguments (filter tags, verbosity flags).

No wildcard is broad enough to execute arbitrary binaries outside the publish/bin/ores.* namespace.

Common invocations:

  • ctest --test-dir build/output/linux-clang-debug-make -R ores.utility
  • build/output/linux-clang-debug-make/publish/bin/ores.utility.tests
  • build/output/linux-clang-debug-make/publish/bin/ores.risk.tests "[generators]"
"Bash(ctest *)",
"Bash(build/output/*/publish/bin/ores.* *)"

Version control

Bash(git *) covers all git subcommands. This is intentionally broad: every git operation (read-only introspection, branching, staging, committing, pushing, rebasing) shares the same prefix. Narrowing by subcommand would add many entries without meaningfully reducing risk, since all operations target the local repository or the authorised remote.

Common invocations:

  • git add projects/ores.risk/src/domain/foo.cpp
  • git commit -m "[risk] Add foo entity"
  • git push --set-upstream origin feature/foo
  • git rebase main
"Bash(git *)"

GitHub CLI — pull requests

The safe gh pr subcommands are granted individually. Four subcommands are deliberately excluded and will always prompt for user confirmation:

Excluded Reason
gh pr close Closes a PR; discards in-progress work.
gh pr revert Creates a revert PR against a merged commit; external and visible.
gh pr lock Moderation action; unusual enough to warrant a prompt.
gh pr unlock Same as above.

All other subcommands are either read-only (view, list, status, checks, diff) or routine workflow actions (create, edit, comment, review, ready, reopen, update-branch, checkout, merge). Note: gh pr merge * is intentionally broad — it covers --squash, --rebase, --admin, and --delete-branch without prompting. This is an explicit trade-off: Claude Code is trusted to merge its own reviewed PRs autonomously. The irreversibility of merge is accepted; user confirmation is reserved for the destructive subcommands above (close, revert, lock).

These commands require dangerouslyDisableSandbox: true because gh authenticates via the OS keyring, which is not accessible inside the sandbox. Source build/scripts/set_ssh_agent.sh beforehand for push/fetch operations; gh uses its own token, not the SSH agent.

Common invocations:

  • gh pr create --title "[risk] Add foo" --body "..."
  • gh pr checks 947
  • gh pr view 947 --comments
  • gh pr edit 947 --body "..."
  • gh api repos/OreStudio/OreStudio/pulls/947/comments
  • gh api graphql -f query'…'=
"Bash(gh pr view *)",
"Bash(gh pr list *)",
"Bash(gh pr status *)",
"Bash(gh pr checks *)",
"Bash(gh pr diff *)",
"Bash(gh pr create *)",
"Bash(gh pr edit *)",
"Bash(gh pr comment *)",
"Bash(gh pr review *)",
"Bash(gh pr ready *)",
"Bash(gh pr reopen *)",
"Bash(gh pr update-branch *)",
"Bash(gh pr checkout *)",
"Bash(gh pr merge *)",
"Bash(gh run *)",
"Bash(gh api *)"

Web access

WebFetch(domain:*) allows fetching from any domain. The sandbox network allowlist (see below) is the actual security boundary; the permission entry controls only whether Claude Code prompts. Domains not in the network allowlist remain unreachable regardless.

WebSearch enables web search. No domain restriction is applied here; the search provider is fixed by the Claude Code runtime.

"WebFetch(domain:*)",
"WebSearch"

Shell utilities

Read-only and data-processing utilities used in analysis pipelines, build inspection, and document generation. Each covers a standard POSIX tool.

Permission rules evaluate compound commands per subcommand: every piece of a && b or a | b must match an allow rule or the whole invocation prompts. In practice almost every compass or git command arrives wrapped in a pipeline — ./compass.sh list --type recipe | head, git log --oneline | tail -5 — so an uncovered head or tail reintroduces a prompt on the highest-frequency flows even though the primary command is authorised. The set below covers the pipeline vocabulary those flows actually use.

sed and awk are deliberately not listed: both can execute arbitrary shell commands (awk 'BEGIN {system(...)}', GNU sed's e command), so auto-approving them would turn a text-processing grant into an unprompted arbitrary-execution grant. They prompt on use; prefer the Read=/=Edit tools for file inspection and modification. python3 * is required for ad-hoc analysis scripts and codegen helpers (src/doc_generate.py, etc.). java * is required for PlantUML, which is invoked as a JAR.

Common invocations:

  • find . -name "*.org" -newer doc/foo.org
  • grep -r "workspace_id" projects/ores.workspace/
  • ./compass.sh list --type capture | head -50
  • python3 projects/ores.codegen/src/doc_generate.py --help
  • java -jar /usr/share/plantuml/plantuml.jar -checkonly foo.puml
  • wc -l build/output/linux-clang-debug-make/publish/bin/ores.utility.tests
"Bash(find *)",
"Bash(grep *)",
"Bash(python3 *)",
"Bash(java *)",
"Bash(echo *)",
"Bash(wc *)",
"Bash(sort *)",
"Bash(uniq *)",
"Bash(head *)",
"Bash(tail *)",
"Bash(cat *)",
"Bash(ls *)",
"Bash(cut *)",
"Bash(tr *)",
"Bash(diff *)"

Sandbox overrides

The sandbox restricts filesystem writes and outbound network connections beyond the defaults. These entries extend the allowlist at the project level; they are applied in addition to (not instead of) the global sandbox configuration in ~/.claude/settings.json.

Network

Grants outbound connections to localhost, required for PostgreSQL (port 5432) access from SQL scripts. Without this entry, psql calls fail with a connection refused error inside the sandbox and the scripts must be run with dangerouslyDisableSandbox: true.

mcraveiro.github.io hosts the Dogen documentation and MASD reference material used when writing knowledge documents and literate template prose; fetching it during documentation tasks must not prompt.

"network": {
  "allowedHosts": ["localhost", "mcraveiro.github.io"]
}

Filesystem

Extends the write allowlist to include the sccache cache directory. The sandbox otherwise blocks writes to ~/.cache/sccache, causing cache misses and forcing builds to recompile from scratch or requiring dangerouslyDisableSandbox: true.

Two entries are required: ~/.cache/sccache authorises the directory itself, and ~/.cache/sccache/** authorises all files and subdirectories within it (object cache shards, the stats file, the server log, etc.). Without the /** glob, sccache receives EPERM when writing any cache object because the allowlist matches only the directory path, not its contents.

"filesystem": {
  "allowWrite": [
    "~/.cache/sccache",
    "~/.cache/sccache/**"
  ]
}

Excluded commands

Commands listed here never attempt to run inside the sandbox; they go straight to the regular permission flow (where the allow rules above auto-approve them). This kills the failure → retry-unsandboxed → prompt loop without widening what is authorised: exclusion changes where a command runs, not whether it is allowed.

Git needs this because linked worktrees resolve their gitdir into the primary checkout (OreStudio.remote/.git/worktrees/<name>), which sits outside the sandbox write allowlist — git fetch, add and commit fail in-sandbox on the index lock and FETCH_HEAD, then prompt on every unsandboxed retry. Compass needs it for the same reason one level up: its highest-value verbs (pr create, pr sync, capture promote, task start, task done) spawn git internally, so a sandboxed compass run inherits the same gitdir failures. All four compass invocation forms from the permission grant are mirrored here.

"excludedCommands": [
  "./compass.sh *",
  "compass.sh *",
  "./projects/ores.compass/compass.sh *",
  "projects/ores.compass/compass.sh *",
  "git *"
]

See also

Emacs 29.1 (Org mode 9.6.6)