How do I deploy the settings?

Table of Contents

Two harnesses run agents in this checkout, and each has its own generated settings. The authoritative source for .claude/settings.json is Claude Code Settings (doc/llm/claude_code_settings.org); for the DSH sandbox rules it is DSH Settings (doc/llm/dsh_settings.org). Never edit the generated files directly. For CMake setup and preset names see CMake setup.

1. Question

How do I regenerate the agent settings from their literate org sources?

2. Answer

compass build --direct settings runs Emacs in batch mode to tangle each surface's document, and calls Emacs directly (no cmake, no vcpkg), so it works in a light environment. The settings alias deploys both surfaces; --claude and --dsh narrow it to one:

./compass.sh build --direct settings            # both surfaces
./compass.sh build --direct settings --claude   # .claude/settings.json only
./compass.sh build --direct settings --dsh      # .dsh/, copied into ~/.dsh

A surface flag with any other target is refused rather than ignored, because build ores.storage.tests --dsh would otherwise report a successful build of something the caller did not ask for.

Expected output for --claude:

Tangled 7 code blocks from claude_code_settings.org
Settings deployed to …/.claude/settings.json

And for --dsh, which tangles into the checkout and then copies the result to ~/.dsh, the directory the harness reads:

Tangled 2 code blocks from dsh_settings.org
DSH settings tangled to …/.dsh
Installed …/.dsh/sandbox-writable-paths
Installed …/.dsh/bin/dsh-bwrap-writable-ores.sh
The home patch selects the runner: …/.dsh/cordis.patch.yml

The two halves place their output differently. The Claude half derives its tangle target from ores/repo-root (defined in projects/ores.lisp/ores-babel.el), so no path appears in its document. The DSH half declares its targets on the master blocks of its own document, relative to that document, because org resolves a relative :tangle against the file it is reading rather than against the working directory.

Both halves must run outside the sandbox. The Claude half needs a full environment for the ores-babel.el project detection; the DSH half writes ~/.dsh, which the sandbox deliberately does not grant, so that the rules cannot rewrite the sandbox that reads them. Use dangerouslyDisableSandbox: true on the Bash tool call.

In a full environment the equivalent CMake targets (deploy_settings and deploy_dsh_settings, both dependencies of deploy_org) run the same scripts; prefer the compass command above.

2.1. Prerequisites

  • Emacs on PATH. (No cmake configure step is required for --direct.)

2.2. Verify

python3 -m json.tool .claude/settings.json

The output should be valid JSON with a permissions.allow array and a sandbox object. The number of allow entries is small by design (25 as of the initial version); if the count grows unexpectedly the source file should be audited.

For the DSH half, read the live rules and compare them with what the document generated:

cat ~/.dsh/sandbox-writable-paths
diff .dsh/sandbox-writable-paths ~/.dsh/sandbox-writable-paths

The diff is empty when the deploy is current. A difference means the host is running rules the document no longer states, which is worth resolving before trusting either.

3. Script

projects/ores.lisp/src/ores-build-settings.el is the Emacs script the target invokes. It:

  1. Loads projects/ores.lisp/ores-babel.el to make ores/repo-root available.
  2. Sets org-babel-default-header-args:json with the absolute tangle target path derived from ores/repo-root, so the org file itself carries no path.
  3. Calls org-babel-tangle-file on doc/llm/claude_code_settings.org, which assembles the JSON via noweb-referenced permission blocks.

compass build --direct settings runs this script directly via Emacs. The equivalent deploy_settings CMake target (used for full-environment builds) lives in CMakeLists.txt near add_custom_target(deploy_settings ...) and invokes the same script.

The DSH half has its own script, projects/ores.lisp/src/ores-build-dsh-settings.el, and the same shape: it makes ores/repo-root available, tangles doc/llm/dsh_settings.org, then copies the two generated files into ~/.dsh and marks the runner executable. The copy is the point — a symbolic link would sit in the checkout, which a confined command can write, so the sandbox could widen itself. The script reports whether ~/.dsh/cordis.patch.yml selects the runner rather than writing that file, because the harness manages part of it. Its CMake target is add_custom_target(deploy_dsh_settings ...).

4. Tested by

Manual. Run the target and verify .claude/settings.json is valid JSON. Tested 2026-05-22 against preset linux-clang-debug-ninja; CMake reconfiguration was not required on a warm build.

5. See also

Emacs 29.3 (Org mode 9.6.15)