by tedydonel
A block-based content engine and bilingual blog backend for Laravel Gutenberg-style editor, media library, post templates, roles, and an AI writing assistant, with zero host coupling.
# Add to your Claude Code skills
git clone https://github.com/tedydonel/HeisenbergLast scanned: 8/11/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-08-11T05:06:56.870Z",
"npmAuditRan": true,
"pipAuditRan": true,
"promptInjectionRan": true
}See how Heisenberg compares with popular alternatives.
Heisenberg is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by tedydonel. A block-based content engine and bilingual blog backend for Laravel Gutenberg-style editor, media library, post templates, roles, and an AI writing assistant, with zero host coupling. It has 103 GitHub stars.
Yes. Heisenberg passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.
Clone the repository with "git clone https://github.com/tedydonel/Heisenberg" and add it to your Claude Code skills directory (see the Installation section above).
Heisenberg is primarily written in PHP. It is open-source under tedydonel on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh Heisenberg against similar tools.
No comments yet. Be the first to share your thoughts!
Based on votes and bookmarks from developers who liked this skill
⚠️ Third-Party Software Notice
This skill is third-party open-source software developed and hosted independently on GitHub. SkillsLLM is an informational directory and does not control or maintain the underlying repository.
Any security checks, ratings, or warnings displayed by SkillsLLM are automated and limited in scope. They do not constitute a security certification or guarantee that the software is safe, error-free, or free from malicious code, vulnerabilities, compromised dependencies, or prompt-injection risks.
Review the source code, permissions, dependencies, and configuration before installing or running any third-party skill. Use is at your own risk. To the maximum extent permitted by applicable law, SkillsLLM is not liable for losses arising from third-party software.
Heisenberg has no users, no theme lock-in and no frontend framework. Your app keeps its users, its routes and its pages — Heisenberg brings the editor at /editor, the content model, and narrow contracts you bind to make everything yours.
composer require heisenberg/heisenberg
php artisan migrate
php artisan storage:link # public media URLs (the uploads link is pre-registered)
That's it — open /editor. The service provider is auto-discovered, migrations load automatically, and every seam ships a working default. On a machine where APP_ENV=local, everything works anonymously out of the box; real deployments authorize through your own users (below).
Optional but recommended:
composer require intervention/image:^3.9 # responsive image variants (v4 is NOT compatible)
Heisenberg never creates users. Your existing users get abilities through the RoleGate contract, with four canonical roles — WordPress-familiar:
| Role | Can |
|---|---|
admin |
everything, including AI/provider settings |
editor |
publish, schedule, archive; manage anyone's media |
author |
write and draft; upload media; edit own files |
viewer |
browse and pick media, read-only |
The bundled gate reads either Spatie permissions (getRoleNames()) or a plain role string column on your user model:
Schema::table('users', fn (Blueprint $t) => $t->string('role')->nullable());
// then: $user->role = 'editor';
Different role names in your app? Remap them in config/heisenberg.php under roles, or bind your own RoleGate implementation entirely. Production apps should also wrap the route groups in their own auth middleware (heisenberg.middleware.editor / .media / .ai, all default ['web']).
If your app enforces a CSP with nonce-based style/script sources (e.g. via Laravel's Vite::useCspNonce()), Heisenberg's inline <style> and <script> blocks will be blocked by the browser unless they carry the same nonce. Heisenberg automatically reads the nonce from Vite::useCspNonce() — you just need to set it in a service provider:
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Vite;
public function boot(): void
{
Vite::useCspNonce();
// or: Vite::useCspNonce('your-static-nonce') if you manage nonces yourself
}
That's it. Heisenberg picks it up and adds nonce="..." to every inline <style>, <script>, and <link rel="stylesheet"> tag. No 'unsafe-inline' needed.
If you don't use CSP nonces (most dev environments), Heisenberg works without this — the nonce attribute is simply omitted.
Email documents use the same editor and block renderer, with host-registered {{ dotted.key }} variables for per-recipient personalization.
AppServiceProvider::boot():use Heisenberg\Services\EmailVariableRegistry;
use Heisenberg\Support\EmailVariableDefinition;
public function boot(EmailVariableRegistry $variables): void
{
$variables->register(new EmailVariableDefinition(
key: 'user.first_name',
label: 'First name',
type: 'text',
sample: 'Tedy',
group: 'User',
));
$variables->register(new EmailVariableDefinition(
key: 'unsubscribe_url',
label: 'Unsubscribe URL',
type: 'url',
sample: 'https://example.test/unsubscribe/sample',
group: 'Links',
));
}
Author an email post — switch to email document type in /editor, use the variable picker to insert tokens.
Send via your mailer:
use Heisenberg\Mail\HeisenbergMailable;
Mail::to($user->email)->send(new HeisenbergMailable(
$emailPost->getKey(),
$user->preferred_locale ?? 'en',
[
'user.first_name' => $user->first_name,
'unsubscribe_url' => URL::signedRoute('unsubscribe', ['user' => $user->getKey()]),
],
));
use Heisenberg\Services\EmailRenderer;
use Heisenberg\Support\EmailVariableContext;
$result = app(EmailRenderer::class)->render(
$emailPost,
'en',
false,
EmailVariableContext::runtime([
'user.first_name' => 'Ada',
'unsubscribe_url' => 'https://example.test/unsubscribe/ada',
]),
);
// $result->subject, $result->html, $result->text, $result->embeds
Export N recipients × locales in one call (admin-only by default):
POST /editor/email/{post}/batch-export
{
"format": "html",
"locales": ["en", "fr"],
"recipients": [
{ "id": "u1", "values": { "user.first_name": "Ada", "unsubscribe_url": "..." } },
{ "id": "u2", "values": { "user.first_name": "Ben", "unsubscribe_url": "..." } }
]
}
// config/heisenberg.php
'email' => [
'routes' => true,
'route_prefix' => 'emails',
'batch_max_recipients' => 100,
],
'roles' => [
'email.generate' => ['admin'], // who may run batch export
],
Heisenberg does not configure SMTP or send campaigns — it renders the files; you send them. Full guide in docs/email-personalization.md; system reference in docs/email-system.md; copy-paste examples in examples/EmailVariables/.
Heisenberg renders block content; you own the page around it. A post template is a JSON contract declaring which chrome capabilities the page has — featured image, authored table of contents, reading time, breadcrumbs, share buttons, comments, and more:
// config/heisenberg.php (php artisan vendor:publish --tag=heisenberg-config)
'template_root' => resource_path('heisenberg-templates'),
// resources/heisenberg-templates/mysite/mysite.json
{
"name": "heisenberg/mysite",
"render": { "view": "blog.show" }, // YOUR Blade view
"capabilities": {
"featuredImage": { "enabled": true, "source": "post-attribute", "context": "hero" },
"tableOfContents": { "enabled": true, "source": "entries" },
"comments": { "enabled": true, "allowGuests": true, "sortOrder": "newest" }
}
}
Validate with php artisan templates:verify. In your controller, resolve PostTemplateRegistryService from the container, read the contract, and render the body exactly like the built-in preview does (BlockRenderer::renderBlocks() plus the block/theme stylesheets). The full schema — all 11 capabilities and the render-vs-adapter decision for each — is in docs/post-template-schema.md.
Data Heisenberg doesn't own arrives through provider contracts with null defaults — bind yours in the published config:
'post_template' => [
'comments_provider' => App\Support\MyCommentProvider::class, // implements PostCommentProvider
// post_views_provider, related_posts_provider, seo_meta_provider
],
en/fr UI.VirusScanner contract), collision-safe naming (photo(1).jpg), role-scoped permissions.docs/code-view.md).php artisan vendor:publish --tag=heisenberg-config gives you config/heisenberg.php: table names and model classes (all swappable), role map, lifecycle transitions, media rules (size caps, allowed extensions, virus scanner), template root, AI provider settings, and the middleware stacks for each route group. Every contract (RoleGate, MediaResolver, VirusScanner, AuditSink, IconProvider, the four template providers) is a config-named binding with a working default.
*Publishing the config is optional