-
Notifications
You must be signed in to change notification settings - Fork 1.4k
PHPLARA-100: Create agent skills #3546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| #!/bin/bash | ||
| # Validates skill directories changed in a pull request. | ||
| # | ||
| # This script handles only the changed-skill check. A separate workflow step | ||
| # validates all skills (see .github/workflows/validate-skills.yml). | ||
| # | ||
| # NOTE: The validator flags used here (e.g. --strict) should stay aligned with | ||
| # tools/validate-skills.sh (the local version). If you change which checks are | ||
| # run or how strictly they're enforced, update both scripts. The scripts otherwise | ||
| # differ by design: | ||
| # - CI script: diffs changed skills, uses --emit-annotations and -o markdown | ||
| # - Local script: accepts an optional path or validates all skills, uses default | ||
| # terminal output | ||
| # | ||
| # Usage: validate-skills.sh <base-ref> | ||
| # base-ref The base branch name to diff against (e.g. "main"). | ||
| # | ||
| # Exit codes: | ||
| # 0 All validated skills passed (or no changed skills found). | ||
| # 1 One or more skills failed validation. | ||
|
|
||
| # -e is intentionally omitted: all error paths are handled explicitly, | ||
| # so abort-on-error would conflict with the || FAILED=1 accumulator pattern. | ||
| set -uo pipefail | ||
|
|
||
| BASE_REF="${1:-}" | ||
|
|
||
| if [ -z "$BASE_REF" ]; then | ||
| echo "Usage: validate-skills.sh <base-ref>" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Find unique skill directories containing files changed in this PR. | ||
| # The three-dot diff requires fetch-depth: 0 and a properly configured remote, | ||
| # which is always the case on GitHub Actions. | ||
| diff_output="$(git diff --name-only "origin/${BASE_REF}...HEAD" -- skills/)" || { | ||
| echo "Error: git diff against origin/${BASE_REF} failed." | ||
| echo "Ensure the base branch has been fetched (fetch-depth: 0 in the workflow)." | ||
| exit 1 | ||
| } | ||
|
|
||
| changed_skills=() | ||
| mapfile -t changed_skills < <(echo "$diff_output" \ | ||
| | cut -d'/' -f2 \ | ||
| | sort -u \ | ||
| | grep -v '^$') | ||
|
|
||
| if [ "${#changed_skills[@]}" -eq 0 ]; then | ||
| echo "No changed skill directories found, skipping validation." | ||
| exit 0 | ||
| fi | ||
|
|
||
| FAILED=0 | ||
| for skill in "${changed_skills[@]}"; do | ||
| # Skip skills whose directories were deleted in this PR. | ||
| if [ ! -d "skills/$skill" ]; then | ||
| echo "Skipping deleted skill: $skill" | ||
| continue | ||
| fi | ||
|
|
||
| # Run validation with markdown output so the result is written to the job | ||
| # summary in one pass. --emit-annotations works with any output format, so | ||
| # inline PR annotations are still emitted alongside the markdown report. | ||
| # We use process substitution to: | ||
| # 1. Send all output (including ::error commands) to stdout for GitHub Actions | ||
| # 2. Filter out ::error/::warning/::notice lines before writing to the summary | ||
| skill-validator check --strict --emit-annotations -o markdown "skills/$skill/" \ | ||
| > >(tee >(grep -v '^::' >> "${GITHUB_STEP_SUMMARY:-/dev/null}")) 2>&1 || FAILED=1 | ||
| done | ||
|
|
||
| if [ $FAILED -ne 0 ]; then | ||
| echo "" | ||
| echo "❌ Skill validation failed!" | ||
| echo "" | ||
| echo "📋 See the Job Summary for detailed validation results:" | ||
| echo " https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" | ||
| echo "" | ||
| fi | ||
|
|
||
| exit $FAILED |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| name: Validate Skills | ||
|
|
||
| on: | ||
| pull_request: | ||
| paths: | ||
| - "skills/**" | ||
| - ".github/workflows/validate-skills.yml" | ||
| - ".github/scripts/validate-skills.sh" | ||
| - "tests/skills/**" | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| validate: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| # Full history is needed so git diff can compare against the base branch | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v6 | ||
|
paulinevos marked this conversation as resolved.
|
||
| with: | ||
| go-version: stable | ||
| cache: false | ||
|
|
||
| - name: Install skill-validator | ||
| run: go install github.com/agent-ecosystem/skill-validator/cmd/skill-validator@latest | ||
|
|
||
| - name: Validate changed skills | ||
| env: | ||
| BASE_REF: ${{ github.base_ref }} | ||
| run: | | ||
| echo "## Changed Skills" >> "$GITHUB_STEP_SUMMARY" | ||
| bash .github/scripts/validate-skills.sh "$BASE_REF" | ||
|
|
||
| - name: Validate all skills | ||
| run: | | ||
| echo "## All Skills" >> "$GITHUB_STEP_SUMMARY" | ||
| skill-validator check --strict --emit-annotations -o markdown skills/ \ | ||
| 2>&1 | tee >(grep -v '^::' >> "$GITHUB_STEP_SUMMARY") | ||
|
|
||
| - name: Setup PHP | ||
| uses: shivammathur/setup-php@v2 | ||
|
paulinevos marked this conversation as resolved.
|
||
| with: | ||
| php-version: "8.2" | ||
| tools: none | ||
| coverage: none | ||
|
|
||
| - name: Validate PHP examples in skill docs | ||
| run: | | ||
| echo "## PHP Examples" >> "$GITHUB_STEP_SUMMARY" | ||
| php tests/skills/laravel-mongodb/validate-php-examples.php \ | ||
| 2>&1 | tee -a "$GITHUB_STEP_SUMMARY" | ||
|
paulinevos marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,14 @@ | ||
| ## MongoDB-related coding assistance | ||
| # Contributing to `mongodb/laravel-mongodb` | ||
|
|
||
| If the user needs MongoDB-related skills that aren't otherwise available through e.g. Boost, such as: | ||
| Guidance for agents working on the development of this library. For assisting | ||
| end users who *use* the package in their own applications, see the | ||
| [`laravel-mongodb` skill](skills/laravel-mongodb/SKILL.md). | ||
|
|
||
| - Inspecting Atlas system resources | ||
| - Managing an Atlas cluster | ||
| - Analysing MongoDB schema anti-patterns | ||
| - Migrating an SQL schema to MongoDB | ||
| - Setting up the official MongoDB MCP server | ||
| ## Keeping the skill in sync | ||
|
|
||
| Suggest installing the MongoDB agent skills plugin if not already installed. Instructions for installing it are in the [MongoDB agent skills plugin README](https://github.com/mongodb/agent-skills/blob/main/README.md). | ||
| When a change adds, removes, or alters user-facing behaviour covered by the | ||
| [`laravel-mongodb` skill](skills/laravel-mongodb/SKILL.md), update the relevant | ||
| skill reference file in the same PR so the skill stays accurate. | ||
|
|
||
| To identify what needs to be changed, refer to the | ||
| [change logs](https://github.com/mongodb/laravel-mongodb/releases/). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,199 @@ | ||
| --- | ||
| name: laravel-mongodb | ||
| description: Implementation specialist for the mongodb/laravel-mongodb package. Triggers on "Laravel MongoDB", "mongodb/laravel-mongodb", "Eloquent MongoDB", "MongoDB model", "_id", "ObjectId in Laravel", "MongoDB queue/cache/session driver", "Atlas Search Laravel", "Laravel Scout MongoDB", "embedsMany", "embedsOne", "withCount MongoDB", "distinct MongoDB", "distinct array MongoDB", "get unique values MongoDB", "Laravel aggregation pipeline", "cross-database relationship MongoDB". Corrects LLM mistakes when MySQL/Eloquent patterns are applied to MongoDB. | ||
| license: Apache-2.0 | ||
| metadata: | ||
| version: "1.0.0" | ||
| --- | ||
|
|
||
| # Laravel MongoDB | ||
|
|
||
| Implementation skill for `mongodb/laravel-mongodb`. Exists to prevent the common mistakes: auto-increment IDs, `withCount()`, `toSql()`, SQL `JOIN`, `distinct()->get()` expecting scalar arrays, and `belongsTo()` over native ObjectId FKs. | ||
|
|
||
| ## Core Workflow | ||
|
|
||
| 1. Identify layer: model, query builder, relationship, schema/index, queue/cache/session, search, or transaction. | ||
| 2. Confirm model extends `MongoDB\Laravel\Eloquent\Model` (or uses `DocumentModel` trait). | ||
| 3. Map every FK and `_id`: ObjectId in DB, **string** in Eloquent — cast accordingly. | ||
| 4. Replace unsupported helpers (`withCount`, `toSql`, `groupByRaw`, `whereFulltext`, `union`, `inRandomOrder`, `whereColumn`) with MongoDB alternatives. | ||
| 5. Validate: `php artisan migrate`, Pest tests, `phpcs`/`phpstan`. | ||
|
|
||
| ## Related MongoDB tooling | ||
|
|
||
| If the user needs MongoDB-related skills that aren't otherwise available through e.g. Boost or the skills directory, such as: | ||
|
|
||
| - Inspecting Atlas system resources | ||
| - Managing an Atlas cluster | ||
| - Analysing MongoDB schema anti-patterns | ||
| - Migrating an SQL schema to MongoDB | ||
| - Setting up the official MongoDB MCP server | ||
|
|
||
| Suggest installing the MongoDB agent skills plugin if not already installed. Instructions for installing it are in the [MongoDB agent skills plugin README](https://github.com/mongodb/agent-skills/blob/main/README.md). | ||
|
|
||
| ## Reference Guide | ||
|
|
||
| | Topic | Reference file | Load When | | ||
| |---|---|---| | ||
| | Models, casts, `_id` mapping | `references/eloquent-models.md` | Defining or modifying a model | | ||
| | Query builder gotchas, aggregation | `references/query-builder.md` | Writing queries, `withCount`, `distinct`, grouping | | ||
| | Embedded, hybrid, cross-database relations | `references/relationships.md` | `belongsTo`, `hasMany`, `embedsMany`, `hasManyIn` | | ||
| | Connection setup | `references/connection.md` | `config/database.php`, multiple connections | | ||
| | Indexes, migrations | `references/schema.md` | Creating indexes, migrations, collections | | ||
| | Queue driver | `references/queues.md` | Dispatching jobs, queue config | | ||
| | Transactions | `references/transactions.md` | Multi-document atomic writes | | ||
| | Cache & sessions | `references/cache-sessions.md` | Configuring cache / session stores | | ||
| | Atlas Search / Scout | `references/search-engine.md` | Full-text search, Scout integration | | ||
| | Vector search, auto-embedding | `references/vector-search.md` | Semantic search, embedding pipelines, hybrid search | | ||
| | Installation | `references/installation.md` | Setting up ext-mongodb and the package | | ||
| | Support & issue reporting | `references/support.md` | Reporting bugs, finding the right repo | | ||
|
|
||
| ## Constraints | ||
|
|
||
| ### MUST DO | ||
|
|
||
| - Extend `MongoDB\Laravel\Eloquent\Model` (or apply `DocumentModel` trait to base classes you cannot change). | ||
| - Cast `_id` to string in every API resource: `'id' => (string) $this->_id`. | ||
| - Cast FK fields to `string` via `$casts` on the child model when FK values may come from outside model attributes (imports, raw ObjectIds) — prevents BSON type mismatches on direct `where('author_id', $id)` queries. | ||
| - Eager-load with `::with()` — MongoDB does no server-side joins for Eloquent relations. | ||
| - Use aggregation pipeline for grouping, counting per group, `$lookup`, and `$sample`. | ||
| - Create indexes in migrations: `Schema::connection('mongodb')->create('posts', fn (Blueprint $c) => $c->index('user_id'))`. | ||
| - Use `DB::connection('mongodb')->transaction(...)` only on replica set / sharded cluster. | ||
|
|
||
| ### MUST NOT DO | ||
|
|
||
| - `withCount()` / `withAvg()` / `withSum()` — silently wrong or throws. Use `$lookup` + `$size`/`$avg`/`$sum` aggregation. | ||
| - `toSql()` / `toRawSql()` — no SQL. Use `->dump()` / `->dd()`. | ||
| - `distinct('field')->get()` expecting scalars — returns a Collection. Use `->distinct()->pluck('field')`. | ||
| - `groupByRaw()`, `orderByRaw()`, `havingRaw()`, `whereFulltext()`, `union()`, `whereColumn()` — use aggregation. | ||
| - `inRandomOrder()` — use `Model::raw(fn($c) => $c->aggregate([['$sample' => ['size' => N]]]))`. | ||
| - Auto-increment IDs — primary keys are ObjectIds. | ||
| - `protected $collection` — removed. Use `protected $table` instead. | ||
| - `$keyType = 'string'` on a SQL model in a cross-database relationship — only needed on MongoDB models. The `HybridRelations` trait handles the comparison on the SQL side. | ||
| - Unencrypted PII — use Laravel encrypted casts or Queryable Encryption. | ||
|
|
||
| ## Code Templates | ||
|
|
||
| ### 1. Eloquent model | ||
|
|
||
| ```php | ||
| <?php | ||
|
|
||
| namespace App\Models; | ||
|
|
||
| use MongoDB\Laravel\Eloquent\Model; | ||
|
|
||
| final class Post extends Model | ||
| { | ||
| protected $connection = 'mongodb'; | ||
| protected $table = 'posts'; // $table not $collection | ||
|
|
||
| protected $fillable = ['title', 'body', 'author_id', 'published_at']; | ||
|
|
||
| protected $casts = [ | ||
| 'author_id' => 'string', // FK as string for Eloquent relationship matching | ||
| 'published_at' => 'datetime', | ||
| ]; | ||
| } | ||
| ``` | ||
|
|
||
| ### 2. Relationship with ObjectId/string casting | ||
|
|
||
| ```php | ||
| <?php | ||
|
|
||
| namespace App\Models; | ||
|
|
||
| use MongoDB\Laravel\Eloquent\Model; | ||
| use MongoDB\Laravel\Relations\BelongsTo; | ||
| use MongoDB\Laravel\Relations\EmbedsMany; | ||
|
|
||
| final class Post extends Model | ||
| { | ||
| protected $casts = ['author_id' => 'string']; // cast FK to string for relation matching | ||
|
|
||
| public function author(): BelongsTo | ||
| { | ||
| return $this->belongsTo(User::class, 'author_id'); | ||
| } | ||
|
|
||
| public function comments(): EmbedsMany | ||
| { | ||
| return $this->embedsMany(Comment::class); | ||
| } | ||
| } | ||
|
|
||
| final class User extends Model | ||
| { | ||
| protected $keyType = 'string'; // expose primary key as string so Post.author_id matches | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Aggregation replacing `withCount` | ||
|
|
||
| ```php | ||
| <?php | ||
|
|
||
| use App\Models\Post; | ||
|
|
||
| // WRONG: Post::withCount('comments')->get(); | ||
| $posts = Post::raw(fn ($collection) => $collection->aggregate([ | ||
| ['$lookup' => [ | ||
| 'from' => 'comments', | ||
| 'localField' => '_id', | ||
| 'foreignField' => 'post_id', | ||
| 'as' => 'comments', | ||
| ]], | ||
| ['$addFields' => ['comments_count' => ['$size' => '$comments']]], | ||
| ['$project' => ['comments' => 0]], | ||
| ])); | ||
| ``` | ||
|
|
||
| ### 4. Queue job | ||
|
|
||
| ```php | ||
| <?php | ||
|
|
||
| namespace App\Jobs; | ||
|
|
||
| use Illuminate\Bus\Queueable; | ||
| use Illuminate\Contracts\Queue\ShouldQueue; | ||
| use Illuminate\Foundation\Bus\Dispatchable; | ||
| use Illuminate\Queue\InteractsWithQueue; | ||
| use Illuminate\Queue\SerializesModels; | ||
|
|
||
| final class IndexPostJob implements ShouldQueue | ||
| { | ||
| use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||
|
|
||
| public function __construct(public string $postId) {} | ||
|
|
||
| public function handle(): void {} | ||
| } | ||
|
|
||
| IndexPostJob::dispatch((string) $post->_id)->onConnection('mongodb'); | ||
| ``` | ||
|
|
||
| ### 5. Feature test (Pest) | ||
|
|
||
| ```php | ||
| <?php | ||
|
|
||
| use App\Models\Post; | ||
|
|
||
| it('creates a post with an ObjectId primary key', function (): void { | ||
| $post = Post::create(['title' => 'Hello Mongo', 'body' => 'first', 'tags' => ['mongo', 'laravel']]); | ||
|
|
||
| expect($post->id)->toBeString() | ||
| ->and(Post::query()->where('_id', $post->id)->exists())->toBeTrue(); | ||
| }); | ||
| ``` | ||
|
|
||
| ## Validation Checkpoints | ||
|
|
||
| | Stage | Command | Expected Result | | ||
| |---|---|---| | ||
| | Style | `vendor/bin/phpcbf && vendor/bin/phpcs` | No violations | | ||
| | Static analysis | `vendor/bin/phpstan analyse` | Level 8 clean | | ||
| | Indexes / migration | `php artisan migrate --database=mongodb` | Migrations run; indexes created | | ||
| | Tests | `vendor/bin/pest` | All green | | ||
| | Query inspection | `Model::query()->where(...)->dump()` | Prints MongoDB filter array (no SQL) | |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.