Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Linear Laravel Package

marshmallow/laravel-linear

marshmallow/laravel-linear is a Laravel integration for Linear's issue-tracking API, offering a configured GraphQL client, facade, and fluent helpers to query and manage issues, projects, teams, and workflows from your Laravel app.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. composer require marshmallow-packages/laravel-linear — v1.4.1 is a patch release on the 1.4 line, so ^1.4 is a safe constraint.
  2. Publish the config: php artisan vendor:publish --tag=linear-config (check the README for the exact tag in your version).
  3. Generate a personal API key in Linear under Settings → API → Personal API keys, then add it to .env as LINEAR_API_KEY. Never commit it; the package reads it from config/linear.php.
  4. Where to look first, in order:
    • config/linear.php — endpoint, key, default team, timeout, any caching knobs.
    • src/LinearServiceProvider.php — shows whether the client is a singleton, how it's bound, and what's publishable.
    • The facade / client class — the actual query surface (issues(), teams(), comments(), etc.).
    • README.md and tests/ — the tests are the most accurate documentation of return shapes.
  5. First use case: a read-only smoke test in php artisan tinker — resolve the client from the container, list teams, then fetch one issue. Once that works, wire an "create an issue from a bug report" path, which is the most common integration.

Implementation Patterns

Inject, don't app() everywhere. Resolve the client through the container in constructors (or type-hint it in jobs/commands) so you can swap it in tests. If the package registers a facade, prefer the facade in controllers/commands and constructor injection in services.

Issue creation from user input. The classic pattern is a support form or Handler::report() hook that creates a Linear issue:

  • Validate input locally first (Linear returns opaque GraphQL errors otherwise).
  • Resolve teamId, stateId, and labelIds from config or a cached lookup — never hard-code UUIDs in blade/controllers.
  • Create the issue in a queued job so a slow/failing Linear call never blocks a user request; return your own DB record ID immediately and store the Linear ID on it.

Sync/backfill. For anything beyond fire-and-forget, keep a local projection table (linear_issues with id, identifier, state, updated_at) and poll with a filter on updatedAt greater than your last successful run. Store the high-water mark in cache/DB, not in memory. Use jobs with WithoutOverlapping so a slow run doesn't stack.

Webhooks. Point a Linear webhook at a route, verify the signature from the header using the signing secret in config, then dispatch a job. Persist the event id (or a hash of payload+timestamp) and short-circuit duplicates — Linear retries deliveries.

Nullable fields from v1.4.1 onward. message is now nullable (string|null). Treat this as the general rule for Linear payloads: many fields are optional depending on the resource type. Normalise at the boundary — map the raw response into your own DTO/array with explicit defaults ('message' => $raw['message'] ?? '') — so the rest of your app never has to branch on null.

Testing. Fake the HTTP layer against the GraphQL endpoint with Http::fake([...]) and return fixture payloads captured from real calls. Add an explicit fixture with "message": null so a regression in your null handling fails CI rather than production. Assert on the request body (query + variables) for write operations, since that's where mistakes hide.

Config over code. Keep team IDs, default state, label sets, and the project mapping in config/linear.php, keyed by environment or product area. It makes staging vs production and multi-team setups a config change instead of a deploy.

Gotchas and Tips

  • GraphQL returns HTTP 200 on errors. A failed mutation can come back as 200 OK with an errors array and a null data. If you only check $response->successful() you will silently drop issues. Always inspect errors and throw your own exception.
  • message is now null-able (v1.4.1). Audit anything that type-hints string $message, does strlen()/trim()/htmlspecialchars() on it, or writes it into a NOT NULL column. On PHP 8.1+ passing null to those functions throws a deprecation/TypeError depending on the call. Make the column nullable (or coalesce to ''), and check rendering paths ({{ $comment->message }} is fine, {!! nl2br($comment->message) !!} is not). This is the only functional change in this release; the webpack bump is a dev-dependency only and does not affect runtime.
  • Rate limiting is complexity-based. Large first: 250 queries with nested fragments burn quota fast. Prefer narrow selections, paginate with cursors, and add retry with backoff on the HTTP client for 429s — but don't retry 400/401, which are configuration problems, not transient ones.
  • Personal keys attribute actions to a human. If you create issues from an integration, they show as that user. For anything multi-tenant or production-critical, plan for OAuth/service-account handling rather than a single shared key.
  • Two kinds of identifiers. The UUID and the human key (ENG-123) are different fields; use the UUID for API calls and the key for display and user-facing lookups.
  • Webhook signature verification and idempotency are your responsibility. The package may verify for you depending on version — read the middleware before trusting it, and add replay protection regardless.
  • Debugging tip: log the GraphQL query, variables, and the response errors (redact the key) on failure. Without the variables in the log, Argument 'teamId' is invalid is very hard to trace.
  • Upgrade note for v1.4.1: no breaking changes and no migration required. Still, grep your codebase for message before deploying — the type widened, and PHP's tolerance for that depends entirely on how strictly you type-hinted.
  • Extension points: published config, the container binding (swap in a fake or a decorated client for logging/metrics), and Laravel's HTTP client options (timeout, retries) if the package passes them through. If you need behaviour the package doesn't expose, wrap it in your own service class rather than forking — this package moves in patches, and a fork will drift.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager