PHPackages                             mikehins/ecoute - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. mikehins/ecoute

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mikehins/ecoute
===============

Capture DOM context and transform into structured issues via AI

v1(1mo ago)02MITPHPPHP ^8.4CI failing

Since May 10Pushed 4w agoCompare

[ Source](https://github.com/mikehins/ecoute)[ Packagist](https://packagist.org/packages/mikehins/ecoute)[ RSS](/packages/mikehins-ecoute/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (1)Dependencies (5)Versions (2)Used By (0)

Ecoute
======

[](#ecoute)

[![Code Style](https://camo.githubusercontent.com/dc6d484f003651810a1660154df5d187c57a630b4216f03bdabf98c4ee305ffe/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64655f7374796c652d70696e742d3842363931342e7376673f7374796c653d666c61742d737175617265)](https://github.com/mikehins/ecoute)[![Code Coverage](https://camo.githubusercontent.com/994d68acb2aadf1c3c7711ddcb3b30429246a6c05da9e601f62c3f932ac795a8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f7665726167652d3130302532352d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://github.com/mikehins/ecoute)[![PHPStan](https://camo.githubusercontent.com/44cd24acad9111ff16dc9324efa466f34bd0cc5bd6923ddcd842443e9b76d1bd/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068707374616e2d6c6576656c5f392d626c75652e7376673f7374796c653d666c61742d737175617265)](https://github.com/mikehins/ecoute)

Ecoute lets your admin users click on any element on the page, describe a problem, and have an AI turn that into a structured issue — automatically saved to your database.

No forms to fill out. No screenshots to attach manually. Just press a keyboard shortcut, click the broken thing, and type a sentence.

```
Press Ctrl+Shift+E (Default)
      │
      ▼
Click any element on the page
      │
      ▼
Type what's wrong → Submit
      │
      ▼
AI receives: the element's HTML, surrounding text,
             page URL, title, and your description
      │
      ▼
AI returns a structured issue:
  title, description, type, suggested fix
      │
      ▼
Saved to your database (status: completed)

```

---

What You Need Before Starting
-----------------------------

[](#what-you-need-before-starting)

- **PHP 8.4 or higher**
- **Laravel 10, 11, 12, or 13**
- **An AI API key** — either [OpenAI](https://platform.openai.com) or [Anthropic](https://console.anthropic.com)
- **A queue worker** — a background process that handles the AI call without making the user wait (explained in step 5 below)

---

Step 1 — Install the package
----------------------------

[](#step-1--install-the-package)

Install with Composer. Two common workflows are shown below: installing the published package from Packagist, or using the package from a local path during development.

Option A — Install from Packagist (normal use)

```
composer require mikehins/ecoute
```

Option B — Local development (install from a local path)

If you're working on the package inside a larger application repository, add a `path` repository entry to your app `composer.json` and then require it:

```
"repositories": [
  {
    "type": "path",
    "url": "./packages/mikehins/ecoute",
    "options": { "symlink": true }
  }
]
```

Then run:

```
composer require mikehins/ecoute --prefer-source
```

Notes:

- Use `--prefer-source` when developing so Composer creates a VCS checkout you can edit.
- If you used the `path` repository approach you can use `--no-update` and run `composer update` after editing composer.json.

---

Step 2 — Publish migrations and run them
----------------------------------------

[](#step-2--publish-migrations-and-run-them)

Ecoute stores every capture in a database table. Publish the migration file and then run your migrations:

```
# Copy package migrations into your app
php artisan vendor:publish --tag=ecoute-migrations --provider="MikeHins\Ecoute\EcouteServiceProvider"

# Run the migrations
php artisan migrate
```

You should see a line similar to `2024_01_01_000000_create_ecoute_captures_table ......... DONE`.

---

Step 3 — Publish the configuration and assets
---------------------------------------------

[](#step-3--publish-the-configuration-and-assets)

Publish configuration, views and public assets in one step (or individually with the tags shown):

```
# Configuration
php artisan vendor:publish --tag=ecoute-config --provider="MikeHins\Ecoute\EcouteServiceProvider"

# Migrations (if not already done)
php artisan vendor:publish --tag=ecoute-migrations --provider="MikeHins\Ecoute\EcouteServiceProvider"

# Browser assets (JS/CSS)
php artisan vendor:publish --tag=ecoute-assets --provider="MikeHins\Ecoute\EcouteServiceProvider"
```

If you have already published `config/ecoute.php`, review the diff carefully before overwriting it. Recent hardening releases add new config keys and safer defaults (notably screenshot storage and code scanning).

---

Step 4 — Verify assets
----------------------

[](#step-4--verify-assets)

If you published the `ecoute-assets` tag the public files will be placed in `public/vendor/ecoute`. When developing with Vite make sure to rebuild assets if needed:

```
# For development (hot-reload)
npm run dev

# For production build
npm run build
```

Note: The package ships a prebuilt `overlay.js` and CSS which are published into `public/vendor/ecoute` when you run `php artisan vendor:publish --tag=ecoute-assets`. You only need to run the `npm`/`vite` build commands if you plan to modify and rebuild the JavaScript/CSS assets locally (see CONTRIBUTING.md or the package's assets directory for developer build steps).

---

Step 5 — Add your settings to `.env`
------------------------------------

[](#step-5--add-your-settings-to-env)

Update your application's `.env` with the settings Ecoute needs. Minimum required values for normal use:

```
ECOUTE_ENABLED=true
ECOUTE_AI_PROVIDER=openai   # or 'anthropic'

# OpenAI (only if provider is openai)
ECOUTE_AI_API_KEY=sk-...    # package reads ECOUTE_AI_API_KEY by default
ECOUTE_OPENAI_MODEL=gpt-4o

# Anthropic (only if provider is anthropic)
ANTHROPIC_API_KEY=sk-ant-...
ECOUTE_ANTHROPIC_MODEL=claude-sonnet-4-5

# Optional: store screenshots on disk for GitHub issue attachments
# Default is 'none' for safer installs.
ECOUTE_SCREENSHOT_STORAGE=none

# Optional: send resolved Blade/Livewire source snippets to the AI prompt.
# Default is false because this can expose host application code to third-party providers.
ECOUTE_CODE_ENABLED=false

# Optional: email to notify when a capture completes
ECOUTE_MAIL_TO=you@example.com
```

Notes:

- Only provide the API key that matches your chosen `ECOUTE_AI_PROVIDER`.
- Keep API keys secret. Ecoute will redact and truncate provider error messages by default to avoid leaking secrets.
- `ECOUTE_SCREENSHOT_STORAGE=none` is now the default. Opt in to `disk` only if you explicitly want screenshots persisted.
- `ECOUTE_CODE_ENABLED=false` is now the default. Opt in only if you are comfortable sending selected source snippets to your AI provider.

---

Step 6 — Decide who can use Ecoute (Gate)
-----------------------------------------

[](#step-6--decide-who-can-use-ecoute-gate)

Ecoute only enables the overlay for users that pass the `ecoute-admin` Gate. Add or update this Gate in `app/Providers/AppServiceProvider.php`

```
use Illuminate\Support\Facades\Gate;
use App\Models\User;

public function boot(): void
{
    Gate::define('ecoute-admin', fn (User $user) => $user->isAdmin());
}
```

Examples:

- Check a users table column: `fn ($user) => $user->role === 'admin'`
- Spatie roles: `fn ($user) => $user->hasRole('admin')`
- For testing you can temporarily allow all users: `fn ($user) => true` (do not leave this in production).

---

Step 7 — Add the Overlay to Your Layout
---------------------------------------

[](#step-7--add-the-overlay-to-your-layout)

A **layout file** is the shared HTML wrapper that surrounds every page — it contains the ``, ``, and `` tags along with things like your navigation and footer. In most Laravel projects it lives at `resources/views/layouts/app.blade.php`.

Add this one line just before your closing `` tag:

```
@ecoute
```

This is a **Blade directive** — a custom tag (similar to `@routes` or `@inertia`) that Ecoute registers automatically when you install the package. When Ecoute is disabled or the current environment is not in the allowed list, the directive outputs nothing at all, so it's safe to leave it in your layout permanently.

---

Step 7 — Start the queue worker
-------------------------------

[](#step-7--start-the-queue-worker)

Captures are processed in the background. Start a worker when testing locally:

```
# Recommended for local development (fast restart when code changes)
php artisan queue:work --tries=3 --sleep=1

# Alternatively (simpler) - listen keeps the worker running and reloads the framework each job
php artisan queue:listen
```

Production: run the worker under a process manager (Supervisor, systemd, Laravel Octane, etc.). Make sure `ECOUTE_QUEUE_CONNECTION` in `.env` is set to the queue connection you want to use.

---

Try It
------

[](#try-it)

1. Log in as a user who passes your `ecoute-admin` gate.
2. Open any page in your browser.
3. Press **Ctrl + Shift + E** (or your configured shortcut) — a blue outline appears and the page enters selection mode.
4. Click any element on the page. A small panel slides in at the edge of the screen.
5. Type a description of the problem and press **Send**.
6. Within a few seconds (while your queue worker is running), the capture is processed by the AI.

---

Check That It Worked
--------------------

[](#check-that-it-worked)

Run this command to see the most recent capture and its status:

```
php artisan tinker --execute "print_r(\MikeHins\Ecoute\Models\EcouteCapture::latest()->first()->toArray());"
```

You're looking for `status` to be `completed` and `ai_response` to contain a JSON object with `title`, `description`, `type`, and `suggested_fix`.

If you configured a notification email, check your inbox too.

---

Configuration Reference
-----------------------

[](#configuration-reference)

All settings live in `config/ecoute.php` and are driven by `.env` values.

`.env` keyDefaultWhat it does`ECOUTE_ENABLED``false`Master on/off switch. Must be `true` for anything to work.`ECOUTE_SHORTCUT``ctrl+shift+e`Keyboard shortcut to open/close the overlay. Format: `modifier+modifier+key`, e.g. `alt+shift+f`. Valid modifiers: `ctrl`, `alt`, `shift`, `meta`.`ECOUTE_AI_PROVIDER``openai`Which AI service to use. Options: `openai`, `anthropic`.`ECOUTE_AI_API_KEY`—Your OpenAI API key (only needed if provider is `openai`).`ECOUTE_OPENAI_MODEL``gpt-4o`Which OpenAI model to use.`ANTHROPIC_API_KEY`—Your Anthropic API key (only needed if provider is `anthropic`).`ECOUTE_ANTHROPIC_MODEL``claude-sonnet-4-5`Which Anthropic model to use.`ECOUTE_AI_TEMPERATURE``0.0`How creative the AI is. 0 = consistent/deterministic, 1 = more varied. Leave at 0 for structured issues.`ECOUTE_QUEUE_CONNECTION``default`Which queue connection to use for background jobs.`ECOUTE_QUEUE_NAME`—Optional: a named queue to dispatch Ecoute jobs onto (e.g. `ecoute-high`).`ECOUTE_SCREENSHOT_STORAGE``none`Whether to persist screenshots. Use `disk` only when you intentionally want screenshot files stored for issue attachments.`ECOUTE_SCREENSHOT_DISK``public`Filesystem disk used when screenshot storage is `disk`.`ECOUTE_GITHUB_TEMPLATE_WHITELIST`—Optional comma-separated allowlist of GitHub issue template filenames. When set, only those templates are listed and accepted.`ECOUTE_CODE_ENABLED``false`Opt-in source-code enrichment for AI prompts. Disabled by default to avoid sending host application source snippets to third-party AI providers.`ECOUTE_CODE_CACHE_TTL``3600`Cache TTL, in seconds, for resolved source snippets.`ECOUTE_CODE_MAX_FILES``3`Maximum number of source files to include when code enrichment is enabled.`ECOUTE_CODE_GREP_MAX``2`Internal limit for selector-based source matches when code enrichment is enabled.`ECOUTE_MAIL_TO`—Email address to notify when a capture completes. Leave empty to disable.**Environments** — by default Ecoute only activates in `local` and `staging`. This means the overlay won't appear in production even if `ECOUTE_ENABLED=true`. To change this, edit `config/ecoute.php`:

```
'environments' => ['local', 'staging', 'production'],
```

---

Security and Privacy
--------------------

[](#security-and-privacy)

**Sensitive data is masked automatically.** Before anything is sent to the AI, Ecoute redacts:

- Email addresses
- Credit card numbers
- Social Security numbers (SSNs)

**Screenshots are no longer persisted by default.** New installs default to `ECOUTE_SCREENSHOT_STORAGE=none`. If you enable disk storage, treat screenshots as sensitive operational data and choose an appropriate disk, visibility model, retention period, and access policy.

**Source-code scanning is opt-in.** Ecoute can enrich prompts with likely Blade/Livewire snippets, but this is disabled by default behind `ECOUTE_CODE_ENABLED=false`. Enable it only if you are comfortable sending selected application source to your configured AI provider.

**Mark your own sensitive elements.** Add the CSS class `ecoute-sensitive` to any element you want hidden from screenshots:

```
{{ $user->secret_token }}
```

**Rate limiting.** Each user can submit at most 10 captures per minute. After that they'll see a "too many requests" message automatically.

**Deduplication.** If the same user submits the same problem on the same URL twice within 24 hours, the second submission returns the original result without calling the AI again. This prevents duplicate issues and unnecessary API costs.

**Environment protection.** The overlay will not render outside of your allowed environments. If `APP_ENV=production` and `production` is not in the `environments` list in `config/ecoute.php`, `@ecoute` outputs nothing and Ecoute's routes are not registered.

---

Troubleshooting
---------------

[](#troubleshooting)

SymptomMost likely causeWhat to doOverlay doesn't appear at all`ECOUTE_ENABLED` is false, or current environment is not in the allowed listSet `ECOUTE_ENABLED=true` in `.env` and check `config/ecoute.php` → `environments`Alt+Shift+E does nothingJS file wasn't published, or `` is missing from layoutRe-run `php artisan vendor:publish --tag=ecoute-assets` and check your layout fileSubmit returns a 403 errorThe logged-in user doesn't pass the `ecoute-admin` gateCheck your `Gate::define('ecoute-admin', ...)` rule in `AppServiceProvider`Submit returns a 401 errorUser is not logged inMake sure you're testing while logged in as a userStatus stays `pending` foreverQueue worker is not runningOpen a terminal and run `php artisan queue:listen`Status is `failed`Bad API key, network error, or AI returned unexpected outputRun `php artisan pail` to tail your logs and look for the errorSecond submission returns the same resultExpected — deduplication is workingSame selector + prompt + URL within 24 h returns the cached capture without calling the AI again---

Events You Can Listen To
------------------------

[](#events-you-can-listen-to)

Ecoute fires events you can hook into from your own code. Add listeners inside the `boot()` method of `app/Providers/AppServiceProvider.php`:

```
use Illuminate\Support\Facades\Event;
use MikeHins\Ecoute\Events\CaptureProcessed;
use MikeHins\Ecoute\Events\CaptureFailed;

// Fired when the AI successfully processes a capture:
Event::listen(CaptureProcessed::class, function ($event) {
    // $event->capture is the fully processed EcouteCapture model.
    // You could push it to Linear, send a Slack message, open a GitHub issue, etc.
});

// Fired when processing fails after all retries:
Event::listen(CaptureFailed::class, function ($event) {
    // $event->capture->failure_reason contains the error message.
});
```

---

GitHub integration &amp; creating issue templates
-------------------------------------------------

[](#github-integration--creating-issue-templates)

Ecoute can create GitHub issues for processed captures. Integration is optional — enable and configure it using `config/ecoute.php` or environment variables (see the `github` section in the config).

Quick enablement (in your `.env`):

```
ECOUTE_GITHUB_ENABLED=true
ECOUTE_GITHUB_TOKEN=ghp_...      # Personal Access Token with `repo` scope
ECOUTE_GITHUB_OWNER=your-org-or-username
ECOUTE_GITHUB_REPO=your-repo-name
# Optional: ECOUTE_GITHUB_TEMPLATE_WHITELIST=bug_report.yml,ux_issue.yml
```

What Ecoute does when GitHub is enabled

- Lists templates from your app's `.github/ISSUE_TEMPLATE/` directory (YAML or Markdown files).
- Shows a preview rendered from the selected template (or a default body when none found).
- Creates a GitHub issue via the GitHub REST API using the configured token, owner and repo.
- Appends the capture screenshot only when you explicitly enable screenshot storage and a screenshot file exists.
- Appends any AI-generated code suggestion to the issue body.

Repository templates — where to put them

- Create a directory at the root of your app: `.github/ISSUE_TEMPLATE/`.
- Place any number of `.yml`, `.yaml`, or `.md` files there. Ecoute will discover them and present them in the UI.

Package-provided sample templates

- The package ships with two sample templates you can publish into your app:
    - `bug_report.yml`
    - `ux_issue.md`

You can publish them using the normal vendor:publish flow (this WILL copy files and may overwrite existing files):

```
php artisan vendor:publish --tag=ecoute-templates --provider="MikeHins\\Ecoute\\EcouteServiceProvider"
```

If you prefer a safe publish that will not overwrite any existing templates, use the new console helper provided by the package. It skips existing files by default and accepts `--force` to overwrite:

```
# Safe publish (skips files that already exist)
php artisan ecoute:publish-templates

# Overwrite existing templates
php artisan ecoute:publish-templates --force
```

YAML template example (`.github/ISSUE_TEMPLATE/bug_report.yml`)

```
name: Bug report
labels: [bug, ecoute]
body:
  - type: textarea
    attributes:
      label: Description
      description: Describe what happened and what you expected.
      placeholder: "What did you do and what went wrong?"
    validations:
      required: true
  - type: dropdown
    attributes:
      label: Urgency
      options:
        - Low
        - Medium
        - High
```

Notes about YAML templates

- Ecoute parses the template and converts each non-markdown field into a `###` heading + placeholder. The AI fills each `{{SECTION:...}}` placeholder with the best matching value (description, suggested fix, location, urgency, etc.).
- The `name:` field is used as the display label in the template picker. `labels:` from the frontmatter are merged into the created issue.

Markdown template example (`.github/ISSUE_TEMPLATE/ux_issue.md`)

```
# UX issue

Please explain the UX problem here.

```

Security &amp; safety

- If you want to limit which templates Ecoute may use, set `ECOUTE_GITHUB_TEMPLATE_WHITELIST` to a comma-separated list of filenames (e.g. `bug_report.yml,ux_issue.md`). Ecoute will refuse templates not present in the whitelist.
- The GitHub token must have `repo` (or at least `public_repo` for public repositories) permission to create issues. Keep this token secret and store it in your environment or secret manager.
- If you want screenshots embedded in GitHub issues, set `ECOUTE_SCREENSHOT_STORAGE=disk` and choose a disk whose URLs are intentionally reachable by GitHub readers.

How Ecoute fills &amp; posts the issue

- For YAML templates Ecoute builds a markdown skeleton and resolves each template section using the AI response (description, suggested\_fix, type, user prompt, etc.).
- For Markdown templates Ecoute appends an "Ecoute Analysis" block containing the AI description, suggested fix, metadata and a screenshot (if available).
- Screenshots are omitted entirely unless you enable disk storage. When enabled, the issue body embeds the storage URL returned by your configured disk.

Testing templates locally

1. Add a template file to `.github/ISSUE_TEMPLATE/`.
2. Optionally set `ECOUTE_GITHUB_TOKEN`, `ECOUTE_GITHUB_OWNER`, and `ECOUTE_GITHUB_REPO` in `.env` (for local testing you can use a personal repository).
3. Use the Ecoute overlay to capture an issue and choose the template in the preview. The preview endpoint (`/ecoute/preview`) also renders the filled template for inspection before creating the issue.

The AI Response Format
----------------------

[](#the-ai-response-format)

Every successfully processed capture stores an `ai_response` in the database. It is a JSON object with these four keys:

```
{
  "title": "Submit button unresponsive on mobile",
  "description": "The checkout submit button does not register taps on iOS Safari. Users cannot complete purchases on mobile devices.",
  "type": "bug",
  "suggested_fix": "Investigate touch event handlers on the button. Consider replacing onClick with onPointerUp for better mobile compatibility."
}
```

`type` will always be one of: `bug`, `ux`, `content`, `performance`, `accessibility`, `other`.

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance94

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

30d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1184036?v=4)[Mike Hins](/maintainers/mikehins)[@mikehins](https://github.com/mikehins)

---

Top Contributors

[![mikehins-fliip](https://avatars.githubusercontent.com/u/258842908?v=4)](https://github.com/mikehins-fliip "mikehins-fliip (3 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mikehins-ecoute/health.svg)

```
[![Health](https://phpackages.com/badges/mikehins-ecoute/health.svg)](https://phpackages.com/packages/mikehins-ecoute)
```

###  Alternatives

[friendsoftypo3/content-blocks

TYPO3 CMS Content Blocks - Content Types API | Define reusable components via YAML

101466.4k44](/packages/friendsoftypo3-content-blocks)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.4M506](/packages/shopware-core)[2lenet/crudit-bundle

The easy like Crud'it Bundle.

1715.6k12](/packages/2lenet-crudit-bundle)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1155.2k](/packages/rcsofttech-audit-trail-bundle)[markwalet/nova-modal-response

A Laravel Nova asset for Modal responses on an action.

17818.7k](/packages/markwalet-nova-modal-response)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
