# `ClaudeWrapper.Settings`
[🔗](https://github.com/genagent/claude_wrapper_ex/blob/main/lib/claude_wrapper/settings.ex#L1)

Read-side access to Claude Code's on-disk **settings** files.

Claude Code reads up to four JSON files in increasing order of
precedence (later layers override earlier ones):

  1. `~/.claude/settings.json` -- user defaults
  2. `~/.claude/settings.local.json` -- user-private overrides
  3. `<project>/.claude/settings.json` -- project-shared
  4. `<project>/.claude/settings.local.json` -- project-private

This module reads each layer as an opaque decoded JSON value and
returns them side by side, **without merging**. Claude Code's merge
semantics are non-trivial and not fully documented, so reproducing
them here would risk diverging from the binary. Callers who want an
"effective" view can merge with full knowledge of which layer produced
which value -- the per-layer split makes that attribution possible.

## Secrets

The `env` block of a settings file often contains secrets
(`ANTHROPIC_API_KEY`, tokens). Use `redact_env_values/1` before
forwarding a layer to a less-trusted consumer.

## Example

    {:ok, settings} = ClaudeWrapper.Settings.load(project_root: "/path/to/repo")

    case ClaudeWrapper.Settings.get(settings, :user) do
      nil -> IO.puts("no user settings")
      user -> IO.inspect(Map.keys(user))
    end

# `layer`

```elixir
@type layer() :: :user | :user_local | :project | :project_local
```

One of the four settings layers, low-to-high precedence.

# `paths`

```elixir
@type paths() :: %{
  user: String.t(),
  user_local: String.t(),
  project: String.t() | nil,
  project_local: String.t() | nil
}
```

Absolute paths the loader checked, whether or not the files exist.

# `t`

```elixir
@type t() :: %ClaudeWrapper.Settings{
  paths: paths(),
  project: map() | nil,
  project_local: map() | nil,
  user: map() | nil,
  user_local: map() | nil
}
```

# `filename`

```elixir
@spec filename(layer()) :: String.t()
```

The filename component (after `.claude/`) for a layer.

# `get`

```elixir
@spec get(t(), layer()) :: map() | nil
```

Return the loaded value for one `t:layer/0`, or `nil` if absent.

# `layers`

```elixir
@spec layers() :: [layer(), ...]
```

All four layers, low-to-high precedence.

# `load`

```elixir
@spec load(keyword()) :: {:ok, t()} | {:error, ClaudeWrapper.Error.t()}
```

Load all four settings layers.

Options:

  * `:user_root` -- the `.claude` directory to read user layers from
    (default: `~/.claude`)
  * `:project_root` -- the project directory whose `.claude/` holds the
    project layers (default: none, so the project layers stay `nil`)

Missing files become `nil`; a malformed JSON file returns
`{:error, %ClaudeWrapper.Error{kind: :invalid_settings_json}}` (with
`:reason` `%{path:, error:}`). Returns `{:error,
%ClaudeWrapper.Error{kind: :no_home}}` when `:user_root` is omitted
and the home directory cannot be determined.

# `redact_env_values`

```elixir
@spec redact_env_values(map()) :: map()
```

Replace every value under the top-level `env` object with
`"<redacted>"`, keeping the keys visible. A no-op on values that are
not maps or that have no map-valued `env` field.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
