# `Clarity`
[🔗](https://github.com/team-alembic/clarity/blob/v0.5.1/lib/clarity.ex#L8)

<img src="priv/static/images/logo.svg" alt="Clarity Logo" width="250px" />

![Elixir CI](https://github.com/team-alembic/clarity/workflows/CI/badge.svg)
[![Hex.pm License](https://img.shields.io/hexpm/l/clarity)
](https://opensource.org/licenses/Apache-2.0)
[![Hex version badge](https://img.shields.io/hexpm/v/clarity.svg)](https://hex.pm/packages/ash)
[![Hexdocs badge](https://img.shields.io/badge/docs-hexdocs-purple)](https://hexdocs.pm/clarity)

⚠️ **Alpha Notice**: Clarity is currently in an **alpha state**. APIs and features
may change rapidly, and things may break. Feedback and contributions are very
welcome!

Clarity is an interactive introspection and visualization tool for Elixir projects.  
It automatically discovers and visualizes applications, domains, resources,
modules, and their relationships, giving you a navigable graph interface
enriched with diagrams, tooltips, and documentation.

![Clarity Screenshot](docs/assets/screenshot.png)

## Features

- 📊 **Graph navigation** – explore your application structure visually.
- 🗂 **Extensible introspection** – support for Ash domains/resources, Phoenix
  endpoints, Ecto repos, and more.
- 🖼 **Mermaid & Graphviz diagrams** – ER diagrams, class diagrams, and policy
  diagrams where available.
- 📝 **Markdown rendering** – show documentation from moduledocs and resource
  definitions.
- 🔎 **Interactive tooltips** – quick overviews of vertices and edges.
- ⚡ **LiveView-powered** – fully dynamic, real-time updates in the browser.
- 🔌 **Custom extensions** – add your own introspectors to visualize
  domain-specific concepts.

## Third-Party Libraries

Third-party libraries can add custom content to Clarity, extending its
visualization capabilities. To install any of these libraries, simply add them
to your `mix.exs` dependencies.

- **[ash_diagram](https://hex.pm/packages/ash_diagram)** – Provides mermaid
  diagrams for Ash

> **Library authors:** see
> [Integrating a Library with Clarity](documentation/how_to/integrate-from-a-library.md)
> for the convention used to ship Clarity content from inside your own
> library — no host-side configuration required on the consumer's part.

## Installation

### Igniter

```bash
mix igniter.install clarity
```

If you want to include Ash diagramming and visualisation support then also install ash_diagram:

```bash
mix igniter.install clarity ash_diagram
```

### Manual

The package can be installed by adding `clarity` to your list of dependencies
in `mix.exs`:

```elixir
def deps do
  [
    {:clarity, "~> 0.1.0"}
  ]
end
```

Router:

```elixir
import Clarity.Router
clarity("/clarity")
```

## License

Copyright 2025 Alembic Pty Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

# `event`

```elixir
@type event() ::
  :work_started
  | :work_completed
  | {:work_progress, queue_info()}
  | :__restart_pulling__
```

- `:work_started` - Emitted when work starts
- `:work_completed` - Emitted when all work is completed
- `{:work_progress, queue_info()}` - Emitted periodically with current queue info

Topics starting with `:__` are internal.

# `modules_diff`

```elixir
@type modules_diff() :: %{changed: [module()], added: [module()], removed: [module()]}
```

# `queue_info`

```elixir
@type queue_info() :: %{
  future_queue: non_neg_integer(),
  requeue_queue: non_neg_integer(),
  in_progress: non_neg_integer(),
  total_vertices: non_neg_integer()
}
```

# `status`

```elixir
@type status() :: :working | :done
```

# `subscription_topic`

```elixir
@type subscription_topic() ::
  :work_started | :work_completed | :work_progress | :__restart_pulling__
```

- `:work_started` - Emitted when work starts
- `:work_completed` - Emitted when all work is completed
- `:work_progress` - Emitted periodically with current queue info

Topics starting with `:__` are internal.

# `t`

```elixir
@type t() :: %Clarity{
  graph: Clarity.Graph.t(),
  queue_info: queue_info(),
  status: status()
}
```

# `unsubscribe`

```elixir
@type unsubscribe() :: (-&gt; :ok)
```

# `get`

```elixir
@spec get(GenServer.server(), :partial | :complete) :: t()
```

Get current clarity state.

For `:partial` mode, returns the current state immediately.
For `:complete` mode, waits for all work to complete before returning the final state.

# `introspect`

```elixir
@spec introspect(
  GenServer.server(),
  :full | {:incremental, Application.app(), modules_diff()} | [module()]
) :: :ok
```

Start introspection process.

## Options

- `:full` - Full introspection, clears graph and re-introspects everything
- `{:incremental, app, modules_diff}` - Incremental introspection based on module changes for specific app
- `[module()]` - Introspect specific modules (legacy support)

# `subscribe`

```elixir
@spec subscribe(
  GenServer.server(),
  subscription_topic() | [subscription_topic()],
  reference() | nil
) :: unsubscribe()
```

Subscribe to clarity events. Returns an unsubscribe function.

## Examples

    # Subscribe to specific events only
    unsubscribe = Clarity.subscribe([:work_started, :work_completed])

    # Unsubscribe later
    unsubscribe.()

---

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