concept7/kite-php-sdk

Framework-agnostic Kite PHP SDK for project monitoring
1,646
Install
composer require concept7/kite-php-sdk
Latest Version:v0.1.6
PHP:^8.2
Laravel:8 – 13
License:MIT
Last Updated:Sep 8, 2026
Links: GitHub  ·  Packagist
Maintainer: concept7

Kite PHP SDK

Latest Version on Packagist Total Downloads

Framework-agnostic PHP client for Kite monitoring. Collects project metadata (PHP, Node and database versions, installed packages), reports it to the Kite API, and scans those packages for known security advisories.

This is the core SDK. For a framework integration, use concept7/laravel-kite or concept7/wordpress-kite instead — both build on this package.

Requirements

  • PHP 8.2+
  • Composer

Installation

composer require concept7/kite-php-sdk

Configuration

Set the KITE_TOKEN environment variable with the token generated from the Kite Dashboard.

use Concept7\Kite\Kite;
use Concept7\Kite\KiteConfig;

$config = new KiteConfig(
    token: getenv('KITE_TOKEN'),
);

The API base URL defaults to https://kite-monitor.com. Override it for development:

$config = new KiteConfig(
    token: getenv('KITE_TOKEN'),
    uri: 'https://kite.test',
);

A config without a token is invalid, and report() and checkAdvisories() both throw an Exception rather than sending anything.

Usage

Reporting

$report = Kite::make($config)->report();

echo $report->message;

report() returns a ProjectReportDto. It runs every registered action through a pipeline, drops the records whose value came back empty, and posts the result.

Kite::make() registers these actions by default:

  • GetPhpVersionAction — PHP version
  • GetNodeVersionAction — Node version
  • GetMysqlVersionAction — MySQL/MariaDB version

Adding extra actions

Add your own actions alongside the defaults — see Writing a custom action for what one looks like:

$report = Kite::make($config)
    ->addAction(new GetRedisVersionAction)
    ->report();

Or multiple at once:

$report = Kite::make($config)
    ->addActions([
        new GetRedisVersionAction,
        new GetStatamicVersionAction,
    ])
    ->report();

Replacing default actions

Use setActions() to completely override the defaults:

use Concept7\Kite\Actions\GetPhpVersionAction;

$report = Kite::make($config)
    ->setActions([
        new GetPhpVersionAction,
        new MyCustomAction,
    ])
    ->report();

Project info collector

Packages and project details are only sent when a ProjectInfoCollectorInterface implementation is registered. Its collect() returns an array that becomes the project_info payload; a packages key in it is what gets scanned and filtered.

use Concept7\Kite\Contracts\ProjectInfoCollectorInterface;
use Concept7\Kite\Support\ComposerDependencies;
use Concept7\Kite\Support\NpmDependencies;

class MyProjectInfoCollector implements ProjectInfoCollectorInterface
{
    public function collect(): array
    {
        return [
            'hostname' => gethostname(),
            'environment' => getenv('APP_ENV') ?: 'production',
            'packages' => array_merge(
                ComposerDependencies::all(),
                NpmDependencies::installed(),
            ),
        ];
    }
}

$report = Kite::make($config)
    ->projectInfoCollector(new MyProjectInfoCollector)
    ->report();

Package collection

Helpers to collect installed packages with ecosystem tagging:

// Direct Composer dependencies (from composer.json require)
ComposerDependencies::direct();

// All Composer dependencies, including transitive ones
ComposerDependencies::all();

// All npm packages, from package-lock.json
NpmDependencies::installed();

Each accepts an optional base path and defaults to getcwd(). Every entry has this shape:

[
    'name' => 'vendor/package',
    'version' => '1.2.3',
    'ecosystem' => Ecosystem::Composer,
    'is_direct' => true,
    'required_by' => ['vendor/other-package'],
]

Package filtering

Before sending, report() fetches the project's config from the Kite API. Unless the project is set to share all packages, the reported list is filtered down to the packages Kite is configured to monitor. The advisory scan always runs against the full list, so vulnerable transitive packages still surface.

If that config call fails, nothing is filtered out of the scan and no packages are reported.

Security advisories

report() scans the collected packages and includes the findings in the payload. A failing scan is swallowed — it never blocks the report.

To scan without sending a full report — for a scheduled re-scan between reports, say:

Kite::make($config)
    ->projectInfoCollector(new MyProjectInfoCollector)
    ->checkAdvisories();

checkAdvisories() returns early when no collector is registered or the collector reports no packages.

The scanners can also be used directly:

use Concept7\Kite\Support\ComposerAdvisories;
use Concept7\Kite\Support\NpmAdvisories;

ComposerAdvisories::scan($packages);
NpmAdvisories::scan($packages);

Each picks out the packages belonging to its own ecosystem and ignores the rest:

Scanner Ecosystem Source
ComposerAdvisories composer Packagist advisories API, version-matched with composer/semver
NpmAdvisories npm OSV.dev batch query API

Both return advisories in the same shape:

[
    'advisory_id' => 'PKSA-xxxx-xxxx-xxxx',
    'package' => 'vendor/package',
    'version' => '1.2.3',
    'ecosystem' => 'composer',
    'title' => 'Advisory title',
    'link' => 'https://...',
    'cve' => 'CVE-2026-0000',
    'severity' => 'high',
    'reported_at' => '2026-08-27',
]

severity is normalised through the Severity enum (critical, high, medium, low); OSV's moderate maps to medium, and anything unrecognised becomes null.

Writing a custom action

Implement ActionInterface. Each action receives a Collection of metadata records and passes it along via $next:

use Closure;
use Concept7\Kite\Contracts\ActionInterface;
use Illuminate\Support\Collection;
use Symfony\Component\Process\Process;

class GetRedisVersionAction implements ActionInterface
{
    public function handle(Collection $data, Closure $next): Collection
    {
        $process = new Process(['redis-server', '--version']);
        $process->run();

        if ($process->isSuccessful() && preg_match('/v=(\d+\.\d+\.\d+)/', $process->getOutput(), $matches)) {
            $data->push([
                'key' => 'redis_version',
                'value' => $matches[1],
            ]);
        }

        return $next($data);
    }
}

Each record is an array with key and value. Records with a null or empty value are filtered out before the report is sent, so an action that cannot determine its value can simply push nothing — or push null and let it be dropped.

Built-in actions

Action Meta key Source
GetPhpVersionAction php_version phpversion()
GetNodeVersionAction node_version node --version, falling back to .nvmrc
GetMysqlVersionAction database_version mysql --version, prefixed mysql_ or mariadb_

Ecosystems

The Ecosystem enum tags packages by source:

Case Value
Ecosystem::Composer composer
Ecosystem::Npm npm
Ecosystem::Wordpress wordpress

Testing

composer test
composer lint

License

MIT

Related Packages

jenssegers/rollbar

Rollbar error monitoring integration for Laravel projects

1,078,653 324
foxxmd/laravel-loggly

Loggly logging integration for Laravel projects

1,695 0
jenssegers/raven

Sentry (Raven) error monitoring integration for Laravel projects

197,591 90
twineis/raven-php

Sentry (Raven) error monitoring for Laravel and Lumen with send in background vi...

18,108 11
rollbar/rollbar-laravel

Rollbar error monitoring integration for Laravel projects

11,604,513 140

Version History

Version Released PHP Laravel License
v0.1.6 ^8.2 ^8.0||^9.0||^10.0||^11.0||^12.0||^13.0 MIT
v0.1.5 ^8.2 ^8.0||^9.0||^10.0||^11.0||^12.0||^13.0 MIT
v0.1.4 ^8.2 ^8.0||^9.0||^10.0||^11.0||^12.0||^13.0 MIT
v0.1.3 ^8.2 ^8.0||^9.0||^10.0||^11.0||^12.0||^13.0 MIT
v0.1.2 ^8.2 ^8.0||^9.0||^10.0||^11.0||^12.0||^13.0 MIT