PHPackages                             fanmade/laravel-adr-manager - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. fanmade/laravel-adr-manager

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

fanmade/laravel-adr-manager
===========================

Git-first, file-based Architectural Decision Record (ADR) manager for Laravel.

v0.2.0(1mo ago)01MITPHPPHP ^8.3CI passing

Since Jul 4Pushed 1mo agoCompare

[ Source](https://github.com/Fanmade/laravel-adr-manager)[ Packagist](https://packagist.org/packages/fanmade/laravel-adr-manager)[ Docs](https://github.com/fanmade/laravel-adr-manager)[ RSS](/packages/fanmade-laravel-adr-manager/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (11)Versions (3)Used By (0)

Laravel ADR Manager
===================

[](#laravel-adr-manager)

Git-first, file-based Architectural Decision Records (ADRs) for Laravel. Records are plain Markdown on disk — the source of truth — with an optional relational index for fast search, a JSON control plane, and an MCP endpoint for AI agents.

Requirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 12 or 13
- Livewire 3.5+ or 4 (optional, for the built-in dashboard)

Installation
------------

[](#installation)

```
composer require fanmade/laravel-adr-manager
```

Publish the configuration:

```
php artisan vendor:publish --tag=adr-manager-config
```

The migrations load automatically. If you use the relational index (see [Sync](#index-and-sync)), run them:

```
php artisan migrate
```

Publish them first only if you need to adapt the schema:

```
php artisan vendor:publish --tag=adr-manager-migrations
```

Record format
-------------

[](#record-format)

Records live in `docs/adrs/` (configurable) as `{id}-{slug}.md`. Each file is YAML front-matter followed by the standard Nygard sections:

```
---
id: '0007'
title: Use PostgreSQL for persistence
status: accepted
date: 2026-01-15
author: Ben
supersedes:
  - '0002'
---

# 0007. Use PostgreSQL for persistence

## Context

We need a relational store with strong consistency.

## Decision

We will use PostgreSQL.

## Consequences

Operations must run and back up PostgreSQL.
```

Valid statuses are `proposed`, `accepted`, `deprecated` and `superseded`.

Two conventions keep parsing unambiguous:

- Quote the `id` in front-matter (`id: '0007'`) so YAML does not coerce it to a number and drop the zero-padding.
- `## Context`, `## Decision` and `## Consequences` are reserved section delimiters. Use `###` or deeper for headings inside a section's prose.

Commands
--------

[](#commands)

CommandPurpose`adr:make`Create the next record from the terminal. Options: `--status`, `--author`, `--supersedes=*` (reciprocal linking). Prints the git commands to commit it.`adr:sync`Reconcile the database index with the files on disk.`adr:lint`Validate format, statuses, links, reciprocal supersedes and sequence integrity. Exits non-zero on any issue.`adr:changelog`Compile a Markdown changelog. Options: `--from`, `--to`, `--output`.`adr:install`Publish a frontend starter stack (`livewire`, `vue`, `react`).`adr:lint` is designed for CI:

```
php artisan adr:lint
```

Index and sync
--------------

[](#index-and-sync)

The filesystem is authoritative. On staging or production, `adr:sync` projects the files into `adr_records` and `adr_relations` for fast querying. The index is disposable and can be rebuilt from disk at any time:

```
php artisan adr:sync
```

Dashboard
---------

[](#dashboard)

When [Livewire](https://livewire.laravel.com) is installed, the package serves a dashboard (Index / Show / Create / Edit) under the configured prefix:

- `GET /adr` — record index (searchable)
- `GET /adr/create` — author a new record
- `GET /adr/graph` — supersede relation graph (reads the index; run `adr:sync`)
- `GET /adr/{id}` — view a record
- `GET /adr/{id}/edit` — edit a record

Writing is only enabled in the environments listed in `adr-manager.authoring.environments` (default: `local`). Elsewhere the forms are replaced by the exact Markdown and `git` commands to commit the record by hand, keeping deployed tiers aligned with the Git workflow.

`php artisan adr:install livewire` publishes the Blade views for restyling. The Vue and React stacks publish editable Inertia components instead, covering the full dashboard (Index / Show / Create / Edit with the same environment write gate). Register the routes yourself — the published controller's docblock contains a copy-paste example.

Control plane and authorization
-------------------------------

[](#control-plane-and-authorization)

Alongside the dashboard, a JSON API is always available under `api/adr`:

- `GET /api/adr` — record index
- `GET /api/adr/{id}` — single record
- `POST /api/adr/mcp` — MCP endpoint (see below)

Both are guarded by the `viewAdrManager` gate, which is **open in the local environment and denied everywhere else** until you define it yourself:

```
Gate::define('viewAdrManager', fn (?Authenticatable $user) => $user?->isAdmin() ?? false);
```

Because the routes are not authenticated, the gate is evaluated for a guest, so the closure's user parameter must be nullable.

Routing is fully configurable in `config/adr-manager.php` (prefix, domain, middleware, or disable it entirely with `routing.enabled`).

MCP endpoint
------------

[](#mcp-endpoint)

`POST /api/adr/mcp` speaks JSON-RPC 2.0 following the Model Context Protocol. It supports `initialize`, `ping`, `tools/list` and `tools/call`, exposing:

- `list_adrs` — the decision timeline
- `get_adr_context` — the full content of one record by `id`
- `search_adrs` — case-insensitive substring search over titles and sections
- `create_adr` — the only write tool. It persists solely in the environments listed in `adr-manager.authoring.environments`; everywhere else it returns the rendered Markdown plus the git commands so the agent (or you) can commit the record through the normal Git workflow. Like every route, it also sits behind the `viewAdrManager` gate.

```
curl -X POST https://your-app.test/api/adr/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_adr_context","arguments":{"id":"0007"}}}'
```

The endpoint reads the Markdown source of truth, so responses are always current without a prior `adr:sync`.

Extending storage
-----------------

[](#extending-storage)

Every read and write flows through the `AdrRepository` contract. The default binding is `LocalMarkdownRepository`. To use different storage, bind your own implementation in a service provider:

```
$this->app->bind(
    \Fanmade\AdrManager\Contracts\AdrRepository::class,
    \App\Adr\MyRepository::class,
);
```

Development
-----------

[](#development)

```
composer test        # Pest
composer test:coverage
composer stan         # PHPStan (max) + Larastan
composer lint         # Pint
```

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md).

License
-------

[](#license)

MIT.

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance90

Actively maintained with recent releases

Popularity1

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

48d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/03ee7b67b9a5fc7e28528dcd9756394b83f8923c6592fde5aaa43189d0022f7b?d=identicon)[Fanmade](/maintainers/Fanmade)

---

Top Contributors

[![Fanmade](https://avatars.githubusercontent.com/u/2896491?v=4)](https://github.com/Fanmade "Fanmade (12 commits)")

---

Tags

laraveldocumentationarchitectureadrdecision-records

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/fanmade-laravel-adr-manager/health.svg)

```
[![Health](https://phpackages.com/badges/fanmade-laravel-adr-manager/health.svg)](https://phpackages.com/packages/fanmade-laravel-adr-manager)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M331](/packages/laravel-ai)[illuminate/queue

The Illuminate Queue package.

20433.0M1.8k](/packages/illuminate-queue)[laravel/sail

Docker files for running a basic Laravel application.

1.9k212.4M1.5k](/packages/laravel-sail)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

265.2k](/packages/aedart-athenaeum)[flarum/core

Delightfully simple forum software.

211.5M2.5k](/packages/flarum-core)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
