Getting Started
Configuration
How config/docent.php is organized: sites, shared defaults, and the options you're most likely to change.
Everything about Docent is configured in config/docent.php, published by the
installer. The file has two layers. A sites array holds one entry per
documentation site, and the top level holds shared defaults that every site
inherits. Most applications run a single site, the shipped docs entry, and
never think about the second layer. The defaults are production ready, so this
page sticks to the options you're most likely to change.
Sites and shared defaults
return [
'default' => 'docs',
// Shared defaults, inherited by every site.
'authorization' => [...],
'search' => [...],
'theme' => [...],
'sites' => [
'docs' => [
'name' => env('DOCENT_NAME', config('app.name').' Docs'),
'route' => ['prefix' => 'docs', 'middleware' => ['web']],
'filesystem' => ['path' => null],
// ...
],
],
];
A value resolves in three steps: the site's own entry wins, then the top-level
shared value, then the package default. The shared sections are theme,
search, ai, insights, content, database, cache, authorization,
widget, and seo. Set them once at the top level, and override any of them
inside a site entry when one site needs to differ.
The rest never cascade, because they define what a site is: name,
description, route, filesystem, admin, navigation, and layouts
only take effect inside a site entry.
default names the site used when nothing more specific applies: the widget
without a site attribute, and console output outside a request. It must match
a key in sites.
Running one documentation site? Everything below happens inside sites.docs
or at the shared top level, and you can ignore the machinery. When you want a
second site, say public help plus internal admin docs, read
multiple sites.
Site name
'sites' => [
'docs' => [
'name' => env('DOCENT_NAME', config('app.name').' Docs'),
'description' => env('DOCENT_DESCRIPTION'),
],
],
The name shown in the title bar and header. It defaults to your application name
with "Docs" tacked on; set DOCENT_NAME to override it. The optional description
summarizes the site in its llms.txt file. When it is omitted, Docent writes a
neutral description from the site name.
Route
// inside sites.docs
'route' => [
'prefix' => 'docs',
'domain' => null,
'middleware' => ['web'],
],
The site is served under prefix (and an optional domain), guarded by
middleware. Want the whole site behind authentication? Add auth:
'middleware' => ['web', 'auth'],
Now every docs URL runs through your app's auth middleware before Docent renders anything. Combine this with per-page access control for finer-grained rules.
Route names carry the site key: the reader routes for the docs site are
docent.docs.home and docent.docs.show, and the same pattern holds for any
site you add. Use the keyed names anywhere your application links into the
docs.
Filesystem
// inside sites.docs
'filesystem' => [
'path' => null,
],
Where the Markdown lives. For the shipped docs site, null resolves to
resource_path('docs'). Point it somewhere else if your docs live outside the
default location. Any other site you add must set its path explicitly;
docent:check reports a site without one.
Authorization
'authorization' => [
'denied_response' => 404,
],
Shared across sites, overridable per site. This controls what a denied viewer
gets when a page's authorize or audience front matter excludes them. The
default 404 hides the page's existence entirely. Set 403 to acknowledge the
page but forbid it, or use a redirect string to send viewers somewhere else:
'denied_response' => 'redirect:/login',
Content
'content' => [
'allow_html' => true,
],
Whether raw HTML authored in repository Markdown is emitted. Repository content
is app code that goes through code review, so this defaults to true. Shared
across sites.
Rendering
'render' => [
'strict_tokens' => false,
],
How a registered value or link closure that throws is handled. The default
substitutes nothing, reports the exception, and lets the rest of the page
render, so one closure failing for one reader's session state doesn't cost them
the whole document. Set it to true to get the exception instead. Shared across
sites, overridable per site. See
dynamic content.
Share links
'share' => [
'enabled' => false,
'gate' => 'shareDocentPage',
'salt' => env('DOCENT_SHARE_SALT'),
'ttl' => 30,
'max_ttl' => 90,
'throttle' => '60,1',
'login_url' => null,
'before' => Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
],
Lets a viewer who passes gate hand one page to someone who isn't signed in.
Off until you enable it, and gate answers false for everyone until you define
it, so nobody can create a link by accident.
ttl is the lifetime offered by default and max_ttl the longest anyone may
pick, both in days. Changing salt invalidates every outstanding link.
throttle applies only to requests carrying a token that fails to verify, in
Laravel's attempts,minutes form. login_url points the "sign in for
everything else" line at a specific address; left null it uses your login
route, and offers nothing when you have none. before names the middleware the
token stands in for, which only needs changing if your guard is neither
Laravel's auth nor a subclass of it.
Shared across sites, overridable per site. See share links.
Search
'search' => [
'enabled' => true,
],
Toggles the ⌘K search palette and the _search endpoint. Search runs on the
server and respects permissions: results pass through the same authorization as
pages, and conditional block content is never indexed. Each site indexes and
searches only its own corpus.
Search is ranked rather than exact. Titles and section headings carry the most weight, followed by descriptions, optional keywords, and page text. Docent also ignores common filler words, accepts a partial final word while someone is typing, and tolerates a one-character typo in longer terms. That means a query like "how do I insert a video" can still find a guide that says "embed a video." No external search service or AI provider is involved.
Docent ships with a conservative English stop-word list. Replace it when your help center uses another language, or empty it when every word should count:
'search' => [
'enabled' => true,
'stop_words' => [],
],
A site whose documentation uses a different language than the rest can override
search.stop_words in its own entry. Authors can cover the last bit of
vocabulary drift with page-level search.keywords.
Keywords influence ranking without being shown to readers or included in
snippets.
Persistent navigation links
Use navigation.links for a few destinations people should always be able to
reach from the sidebar and mobile menu. Navigation belongs to a site, so this
block lives inside the site entry:
// inside sites.docs
'navigation' => [
'default_section' => 'Documentation',
'links' => [
['label' => 'Support', 'icon' => 'lifebuoy', 'url' => 'https://example.com/support'],
['label' => 'Setup guide', 'icon' => 'rocket-launch', 'page' => 'getting-started/setup'],
['label' => 'Admin console', 'icon' => 'wrench', 'route' => 'admin.dashboard', 'can' => 'admin'],
],
'topbar' => [
['label' => 'GitHub', 'icon' => 'github', 'url' => 'https://github.com/acme/acme'],
],
],
Each link takes exactly one of url, page, or route. Add can to show it
only when the viewer passes that ability. Page links also inherit the page's
authorize and audience rules, and they stay inside the compact help widget.
External links open in a new tab. Icons may be bundled Heroicon names or public
image URLs; an invalid icon is simply omitted and reported by docent:check.
navigation.topbar takes the same link shape but renders as icon buttons on
the right side of the top bar, next to the theme toggle. That's the spot
readers expect a repository or community link, so Docent bundles a few brand
icons alongside the Heroicons: github, discord, slack, x-twitter, and
youtube. On phones these move into the navigation drawer with their labels.
Top-bar links never appear in the help widget.
Pinned links are navigation aids for people, so they aren't included in
llms.txt or other Markdown feeds. See organization
for splitting a larger help center into top-level sections.
Cache
'cache' => [
'store' => null,
'prefix' => 'docent',
],
The store used for parsed ASTs, the navigation skeleton, and the search index.
null uses your default cache store. Each site keeps its own cache namespace
under this prefix. After any content change, clear it:
php artisan docent:clear
docent:clear bumps a version stamp that's folded into every cache key, so it
works with any cache driver, even ones without tag support. On a multi-site
install it clears every site; pass --site=docs to clear one.
Theme
The entire theme section gets its own page. See theming for the
accent color, logos, fonts, gray palette, and corner radius.