Laravel package for instruckt — visual feedback for AI coding agents. Provides the backend API, MCP tools, JSON file storage, and a Blade toolbar component.
Users annotate elements in the browser, annotations are copied as structured markdown, and your AI agent can also read them via MCP.
composer require joshcirre/instruckt-laravel --dev
php artisan instruckt:install
The install command publishes the config, installs the npm package, and automatically:
vite.config.js with server: falseimport 'virtual:instruckt' to your JS entry pointTo uninstall, run php artisan instruckt:uninstall. See Uninstall for details.
The install command adds the instruckt Vite plugin to your vite.config.js:
import laravel from 'laravel-vite-plugin'
import instruckt from 'instruckt/vite'
export default defineConfig({
plugins: [
laravel({ input: ['resources/js/app.js'] }),
instruckt({
server: false,
endpoint: '/instruckt',
adapters: ['livewire', 'blade'],
mcp: true,
}),
],
})
And a single import in your JS entry point:
// resources/js/app.js
import 'virtual:instruckt'
The server: false flag tells the Vite plugin that Laravel owns the backend — it only provides the virtual module for client injection.
The plugin only runs during vite serve (apply: 'serve'), so instruckt is completely absent from production builds — zero bytes shipped.
If you'd rather not touch your JS/Vite config, use the Blade component in your layout before </body>:
<x-instruckt-toolbar />
The component is gated behind config('instruckt.enabled'), which defaults to true only when APP_ENV=local. It loads the IIFE build and accepts optional attributes:
<x-instruckt-toolbar
theme="dark"
position="bottom-left"
:adapters="['livewire', 'vue']"
:colors="['default' => '#6366f1', 'screenshot' => '#22c55e', 'dismissed' => '#71717a']"
:keys="['annotate' => 'a', 'freeze' => 'f']"
/>
The install command automatically detects your AI agent and configures MCP. If you need to do it manually, add to .mcp.json (Claude Code):
{
"mcpServers": {
"instruckt": {
"command": "php",
"args": ["artisan", "mcp:start", "instruckt"]
}
}
}
storage/app/_instruckt/ via API routesThe package registers these MCP tools for your AI agent:
| Tool | Description |
|---|---|
instruckt.get_all_pending |
Get all pending annotations |
instruckt.get_screenshot |
Get the screenshot image for an annotation |
instruckt.resolve |
Mark an annotation as resolved (removes marker from browser) |
Annotations are stored in storage/app/_instruckt/annotations.json. Screenshots are saved as PNGs in storage/app/_instruckt/screenshots/. No database migrations needed.
Publish the config file to customize:
php artisan vendor:publish --tag=instruckt-config
Published to config/instruckt.php:
return [
// Only enabled in local env by default
'enabled' => (bool) env('INSTRUCKT_ENABLED', env('APP_ENV') === 'local'),
// API route prefix
'route_prefix' => env('INSTRUCKT_ROUTE_PREFIX', 'instruckt'),
// Middleware applied to API routes
'middleware' => explode(',', env('INSTRUCKT_MIDDLEWARE', 'api')),
// Override JS source (e.g. pinned CDN version) — only used by Blade component
'cdn_url' => env('INSTRUCKT_CDN_URL', null),
// Marker pin colors (CSS color strings) — only used by Blade component
// When using the Vite plugin, set these in vite.config.js instead
'colors' => [
// 'default' => '#6366f1', // indigo — standard annotations
// 'screenshot' => '#22c55e', // green — annotations with screenshots
// 'dismissed' => '#71717a', // gray — dismissed
],
// Keyboard shortcuts — only used by Blade component
// When using the Vite plugin, set these in vite.config.js instead
'keys' => [
// 'annotate' => 'a', // toggle annotation mode
// 'freeze' => 'f', // freeze page
// 'screenshot' => 'c', // region screenshot capture
// 'clearPage' => 'x', // clear current page
],
];
Note: When using the Vite plugin, toolbar visual config (colors, keys, position, theme) lives in
vite.config.js. The PHP config governs backend behavior (enabled, routes, middleware, MCP).
Instruckt is designed as a dev-only tool with multiple layers of protection:
| Layer | Vite Plugin | Blade Component |
|---|---|---|
| Frontend | Plugin uses apply: 'serve' — absent from production builds entirely |
@if(config('instruckt.enabled')) — component doesn't render |
| Backend routes | Only registered when config('instruckt.enabled') is true |
Same |
| Config default | enabled defaults to true only when APP_ENV=local |
Same |
All routes are registered under the configured prefix (default: /instruckt):
| Method | Route | Description |
|---|---|---|
| GET | /instruckt/annotations |
List all annotations |
| POST | /instruckt/annotations |
Create annotation |
| PATCH | /instruckt/annotations/{id} |
Update annotation |
Default shortcuts (customizable via keys in your Vite plugin options or config):
| Key | Action |
|---|---|
A |
Toggle annotation mode |
F |
Toggle freeze animations |
C |
Screenshot region capture |
X |
Clear annotations on current page |
Esc |
Exit annotation/freeze mode |
navigator.clipboard requires a secure context (HTTPS or localhost). On http://*.test domains, auto-copy on annotation submit is skipped. Use the copy button in the toolbar which uses a fallback method.
To cleanly remove instruckt from your project:
php artisan instruckt:uninstall
This scans for all instruckt artifacts, shows you what will be removed, and asks for confirmation before proceeding. It reverses everything the install command did:
vite.config.*import 'virtual:instruckt') from your JS entry pointconfig/instruckt.php).mcp.json, .cursor/mcp.json, etc.)storage/app/_instruckt/)instruckt npm packageAfter uninstalling, remove the Composer package:
composer remove joshcirre/instruckt-laravel --dev
Options:
| Flag | Description |
|---|---|
--force |
Skip the confirmation prompt |
--keep-config |
Keep config/instruckt.php |
--keep-npm |
Keep the npm package installed |
MIT
How can I help you explore Laravel packages today?