laravel-ai-blog

mcp
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Pass
  • Code scan — Scanned 3 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Laravel blog package with built-in SEO scoring, AI drafting (laravel/ai) and an MCP server so Claude and ChatGPT can write to it. Headless by default.

README.md

Laravel AI Blog — the AI-native blog package for Laravel

tests
Latest Version
Downloads
PHP
License

Install it, and your blog thinks. Laravel AI Blog is a free, open-source blog package for Laravel 10 to 13. It
plans topics, drafts with you, scores every post for on-page SEO, links itself, keeps itself fresh — and lets
Claude, ChatGPT, Claude Code or any MCP agent write to it.

  • Headless by default. Models, migrations, a trait for your existing Post model. No admin panel forced on you. Flip one flag for /blog routes, Blade components, RSS and JSON-LD.
  • SEO that nobody else ships. An on-page score with plain-English fixes, internal-link suggestions with anchor text, stale-post detection, BlogPosting + FAQPage schema.
  • AI as your editor, not your ghostwriter. Built on the official laravel/ai SDK — any provider. Brief → draft, meta descriptions, rewrites, refresh suggestions, translations. Everything lands as a draft. Nothing auto-publishes unless you say so.
  • Agent-ready. A built-in laravel/mcp server: "write a post on X, score it, link it to related posts, schedule for Monday."
  • Free. MIT. No Nova license, no Filament lock-in, no SaaS tether.

Requirements

  • PHP 8.2 to 8.5 with the curl, dom, libxml and mbstring extensions
  • Laravel 10, 11, 12 or 13

Both ends of those ranges run in CI on every push: the newest dependencies and the oldest ones the constraints
allow. Laravel 10 and 11 are end of life; they are supported for apps that have not upgraded, not recommended
for new ones. On PHP 8.4 and later the text extractor uses PHP's spec-compliant HTML5 parser; on older PHP it
falls back to libxml2's HTML parser, which gives the same results on the pages the tests cover but stops at
about 256 levels of nesting (it returns no text for a page nested deeper, never partial text).

Install

composer require byteminus/laravel-ai-blog
php artisan vendor:publish --tag=laravel-ai-blog-migrations
php artisan migrate

Optional, for AI and agents:

composer require laravel/ai laravel/mcp

60-second tour

use ByteMinus\AiBlog\Facades\AiBlog;
use ByteMinus\AiBlog\Models\Post;

// Score any post. Deterministic, no API key needed.
$report = $post->seoReport();
$report->score;    // 72
$report->grade();  // "B"
$report->fixes();  // ["Include \"laravel queues\" in the title.", "Add at least two links — ..."]

// Internal links, with anchor text, from your own published posts.
$post->suggestedLinks();   // [['post' => Post, 'anchor' => 'queue workers', 'score' => 0.41], ...]

// AI: keyword → brief → full draft. Saved as a DRAFT for a human to review.
$draft = AiBlog::draftFromKeyword('laravel queues');

// AI: fill in a missing keyword + meta description on an existing post.
AiBlog::enrichSeo($post);

// Publishing is explicit.
$post->schedule(now()->addDays(2));   // then: php artisan ai-blog:publish-scheduled
$post->publish();
php artisan ai-blog:audit            # score every post, list fixes and links
php artisan ai-blog:audit --fix      # let the AI fill missing SEO fields first
php artisan ai-blog:audit --stale    # posts due for a refresh

Already have a Post model?

Keep it. Add the trait, point the config at your model, done.

use ByteMinus\AiBlog\Concerns\HasBlogSeo;

class Post extends Model
{
    use HasBlogSeo;

    // Override only what differs from the defaults (title, body, slug, seo_title, seo_description, target_keyword)
    public function getBodyField(): string { return 'content'; }
}
// config/ai-blog.php
'models' => ['post' => App\Models\Post::class],

Let agents write your blog

// config/ai-blog.php
'mcp' => [
    'enabled' => true,
    'path' => '/mcp/ai-blog',
    'middleware' => ['auth:sanctum'],
],

Then connect:

claude mcp add --transport http my-blog https://example.com/mcp/ai-blog --header "Authorization: Bearer <token>"

Tools: list_posts, get_post, create_draft, update_post, draft_from_keyword, score_post,
suggest_links, schedule_post. There is deliberately no publish_post tool — agents draft,
score, link and schedule; a human (or the scheduler, after a human scheduled it) publishes.

For Claude.ai and ChatGPT custom connectors, use laravel/mcp's OAuth support (Mcp::oauthRoutes() with Passport).

Safe fetching (research)

SafeFetcher reads a public web page, feed or JSON document so the AI has real sources to work from. Run it
from a queued job or an Artisan command: it refuses to run inside a web request.

use ByteMinus\AiBlog\Fetching\Feeds\FeedParser;
use ByteMinus\AiBlog\Fetching\SafeFetcher;
use ByteMinus\AiBlog\Fetching\TextExtractor;

$document = app(SafeFetcher::class)->fetch('https://example.com/feed.xml');

$feed = app(FeedParser::class)->parseDocument($document);   // RSS, Atom, RSS 1.0 or JSON Feed
$page = app(TextExtractor::class)->extract($document);      // readable text, title, author, date
$page->untrusted();                                         // wrap it before it goes near a model

On the first URL and on every redirect (at most 5) it checks that the URL is plain http(s) with no credentials,
a standard port and no internal host names; resolves the host itself and requires every address to be public;
pins the connection to the address it checked, so DNS rebinding can't move the request inside your network;
obeys robots.txt; ignores proxies and cookies; and caps the body size and total time. Anything it returns is
untrusted data: hand it to a model only through TextExtractor and UntrustedText.

Command bus

Every change can go through one bus, so a dashboard, an Artisan command, a job and an AI agent all get the same
rules: the actor must hold the command's ability, every request carries an idempotency key (a retry
replays the stored result instead of running twice), and each outcome is written to an audit trail.

use ByteMinus\AiBlog\Bus\Actor;
use ByteMinus\AiBlog\Bus\CommandBus;
use ByteMinus\AiBlog\Bus\CommandContext;
use ByteMinus\AiBlog\Bus\CommandHandler;
use ByteMinus\AiBlog\Bus\CommandOutcome;
use ByteMinus\AiBlog\Bus\CommandRequest;

final class RenamePost extends CommandHandler
{
    public function ability(): ?string { return 'posts.write'; }

    public function rules(): array { return ['title' => ['required', 'string', 'max:120']]; }

    public function handle(CommandContext $context): CommandOutcome
    {
        // ...call your service here...
        return CommandOutcome::completed(['title' => $context->params['title']], 'post', '42');
    }
}
// config/ai-blog.php
'commands' => ['handlers' => ['post.rename' => RenamePost::class]],

// AppServiceProvider: nobody manages the blog until you say who may
Gate::define('manageAiBlog', fn ($user) => $user->is_admin);

// anywhere
$receipt = app(CommandBus::class)->dispatch(
    Actor::user($request->user()),
    new CommandRequest('post.rename', idempotencyKey: 'rename-42-v1', params: ['title' => 'New title']),
);

$receipt->result();    // what the caller may see
$receipt->replayed;    // true when this was a retry

Pass dryRun: true to preview a command without changing anything. Publish and run the migrations to create the
commands and audit_events tables.

Public routes (opt-in)

'routes' => ['enabled' => true, 'prefix' => 'blog', 'layout' => 'layouts.app'],

Gives you /blog, /blog/{slug}, /blog/category/{slug}, /blog/tag/{slug}, /blog/feed, and the
Blade components <x-ai-blog::meta-tags>, <x-ai-blog::structured-data>, <x-ai-blog::post-body>.

Your layout needs @yield('title'), @yield('content') and @stack('head'); the pages put their tags in the stack.

What the pages send to search engines

  • Post pages: a canonical URL (the post's own address, or its canonical_url when you set one), og: and
    twitter: cards with an absolute image URL, article:published_time and article:modified_time, a
    robots tag that allows large image previews, an RSS link, and BlogPosting JSON-LD with the page address and
    publisher. A ## Question? heading followed by an answer adds FAQPage JSON-LD.
  • Index, category and tag pages: a description, a canonical URL, prev/next links, an RSS link and a
    distinct title on every page of results ("Blog — Page 2 — My Site").
  • Feed: RSS 2.0 with language, last build date and permalink GUIDs.
  • Tags with nothing to say are left out rather than sent empty: a post with no description gets no
    description tag. Set ai-blog.seo.description (or AI_BLOG_SEO_DESCRIPTION) for the blog's own description.

Scheduler

// routes/console.php
Schedule::command('ai-blog:publish-scheduled')->everyMinute();

FAQ

Does it work without an AI provider? Yes. Scoring, link suggestions, structured data, the feed and the routes
need no API key. The AI features are optional and use laravel/ai when you install it.

Will it publish posts by itself? No. Everything the AI or an agent writes lands as a draft. Auto-publishing is
a config flag you turn on yourself.

Can I keep my own Post model? Yes. Add the HasBlogSeo trait and point ai-blog.models.post at your model.

Which Laravel and PHP versions does it support? Laravel 10, 11, 12 and 13 on PHP 8.2 to 8.5.

Is it free? Yes, MIT licensed, with no paid tier.

Philosophy

AI that writes thirty posts a month from a keyword list is what search engines are built to bury.
Laravel AI Blog makes a human writer faster and an agent safer: every AI action produces a draft,
marks unverified claims as [verify: ...], and records how much AI was involved (ai_assistance).
Auto-publishing exists as a config flag you turn on knowingly, never as a default.

Roadmap

  • Headless core, SEO score, internal links, stale detection, JSON-LD, RSS
  • AI brief → draft, enrich, rewrite, refresh, translate (via laravel/ai)
  • MCP server for agents
  • Safe fetching: SSRF-guarded fetcher, feed parser, text extraction
  • Command bus with idempotency and an audit trail
  • Built-in XML sitemap
  • Semantic linking with embeddings
  • Topic intelligence: content gaps and clusters from your existing posts
  • Filament adapter · Nova adapter · Livewire editor
  • Multilingual posts with hreflang
  • Scheduled pipelines ("two drafts a week from this keyword list")

See CONTRIBUTING.md — there's a good first issue for most of these.

Security

See SECURITY.md for how to report a vulnerability privately.

License

MIT.

Reviews (0)

No results found