# `Pixir.Paths`
[🔗](https://github.com/Ranvier-Technologies/pixir/blob/main/lib/pixir/paths.ex#L1)

Filesystem conventions for Pixir.

Two roots (ADR 0002 / 0003):

  * **Global** `~/.pixir/` — cross-project, user-level state: `auth.json`,
    `config.json`. Created lazily, `0700`.
  * **Project** `.pixir/` — per-Workspace state, rooted at the current working
    directory. Sessions live in `.pixir/sessions/<id>.ndjson` and are the
    source of truth for the Log. Session writer leases live under
    `.pixir/session_leases/` and are live-capability evidence, not History.
    Session Resources live next to the Log under `.pixir/sessions/<id>/resources/`.
    This subtree is gitignored.

Path builders return absolute paths. Content-bearing Log and lease callers use the
structured state-path helpers below before their filesystem operations. Session
Resource payload-path hardening is a documented deferred boundary.

The Workspace root itself is the trusted anchor, including a deliberate symlink alias.
Below that anchor, Pixir performs `lstat`-based component checks and refuses existing
or dangling symlinks. This is a static tripwire, not a same-UID race-free guarantee:
another process may still replace a component between check and use.

# `state_path_state`

```elixir
@type state_path_state() :: :missing | :regular | :directory | atom()
```

Observed state of the final component of a checked Pixir state path.

# `auth_file`

```elixir
@spec auth_file() :: String.t()
```

Global `auth.json` path (OAuth credentials).

# `config_file`

```elixir
@spec config_file() :: String.t()
```

Global `config.json` path.

# `ensure_global_root`

```elixir
@spec ensure_global_root() :: String.t()
```

Ensure the global root exists (mode 0700) and return it.

# `ensure_session_lease_releases_dir`

```elixir
@spec ensure_session_lease_releases_dir(String.t()) :: String.t()
```

Ensure the Session writer lease releases dir exists and return it.

# `ensure_session_leases_dir`

```elixir
@spec ensure_session_leases_dir(String.t()) :: String.t()
```

Ensure the Session writer lease dir exists and return it.

# `ensure_session_resources_dir`

```elixir
@spec ensure_session_resources_dir(String.t(), String.t()) :: String.t()
```

Ensure the Session Resources dir exists and return it.

# `ensure_sessions_dir`

```elixir
@spec ensure_sessions_dir(String.t()) :: String.t()
```

Ensure the project sessions dir exists and return it.

# `ensure_state_dir`

```elixir
@spec ensure_state_dir(String.t(), String.t()) :: {:ok, String.t()} | {:error, map()}
```

Create a Pixir-owned directory one component at a time below the trusted Workspace.

Each existing or newly created component is verified with `lstat`; `mkdir_p` is not
used, so a pre-existing symlink cannot be followed while creating deeper state.

# `global_root`

```elixir
@spec global_root() :: String.t()
```

Global root: `~/.pixir` (override with `PIXIR_HOME`).

# `global_skills_dir`

```elixir
@spec global_skills_dir() :: String.t()
```

Pixir-global Skills root: `~/.pixir/skills` (respects `PIXIR_HOME`).

# `inspect_state_path`

```elixir
@spec inspect_state_path(String.t(), String.t(), keyword()) ::
  {:ok, %{path: String.t(), state: state_path_state()}} | {:error, map()}
```

Inspect every component below the trusted Workspace root with `File.lstat/1`.

`:expected` may be `:any`, `:regular`, or `:directory`. Missing paths are reported as
`state: :missing`; existing symlinks, non-directory ancestors, unexpected final types,
and lstat failures return structured `:unsafe_state_path` errors without following or
reading a target.

# `preflight_new_state_path`

```elixir
@spec preflight_new_state_path(String.t(), String.t()) :: :ok | {:error, map()}
```

Require a checked Pixir state path's final component to be absent.

# `preflight_state_path`

```elixir
@spec preflight_state_path(String.t(), String.t(), keyword()) :: :ok | {:error, map()}
```

Check a Pixir state path, allowing the final component to be absent.

# `project_root`

```elixir
@spec project_root(String.t()) :: String.t()
```

Project root: `<workspace>/.pixir` (workspace defaults to cwd).

# `session_lease`

```elixir
@spec session_lease(String.t(), String.t()) :: String.t()
```

Writer lease path for a given Session id.

# `session_lease_releases_dir`

```elixir
@spec session_lease_releases_dir(String.t()) :: String.t()
```

Directory for Session writer lease diagnostic records.

# `session_leases_dir`

```elixir
@spec session_leases_dir(String.t()) :: String.t()
```

Project Session writer lease directory: `<workspace>/.pixir/session_leases`.

# `session_log`

```elixir
@spec session_log(String.t(), String.t()) :: String.t()
```

NDJSON Log path for a given session id.

# `session_resources_dir`

```elixir
@spec session_resources_dir(String.t(), String.t()) :: String.t()
```

Directory for durable Session Resources attached to a Session.

# `sessions_dir`

```elixir
@spec sessions_dir(String.t()) :: String.t()
```

Project sessions directory: `<workspace>/.pixir/sessions`.

---

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