laravel-ai-blog
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 6 GitHub stars
Code Gecti
- Code scan — Scanned 3 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
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.
Laravel AI Blog — the AI-native blog package for Laravel
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
/blogroutes, 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,libxmlandmbstringextensions - 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 thecommands 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_urlwhen you set one),og:andtwitter:cards with an absolute image URL,article:published_timeandarticle:modified_time, arobotstag that allows large image previews, an RSS link, andBlogPostingJSON-LD with the page address and
publisher. A## Question?heading followed by an answer addsFAQPageJSON-LD. - Index, category and tag pages: a description, a canonical URL,
prev/nextlinks, 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
descriptiontag. Setai-blog.seo.description(orAI_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.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi