daemon8/php

Daemon8 SDK for PHP — framework-agnostic runtime observation primitives

Maintainers

Package info

github.com/daemon8ai/daemon8-php

Homepage

Issues

pkg:composer/daemon8/php

Statistics

Installs: 12

Dependents: 2

Suggesters: 0

Stars: 0

dev-main / 0.1.x-dev 2026-04-21 20:02 UTC

This package is auto-updated.

Last update: 2026-04-22 13:45:50 UTC


README

Daemon8

Framework-agnostic runtime observation primitives for Daemon8.
Ship logs, queries, exceptions, and custom events into a local observation stream your AI coding agent can query.

Website · Docs · Daemon · SDKs · Demo · Contact

Free and open source. No tiers, no license keys, no phone-home.

Active development. This package is in public alpha. Tracked work for this SDK lives as GitHub Issues; the broader roadmap is maintained on the primary daemon8 repo.

Daemon8 SDK for PHP

PHP 8.4+. Zero framework dependencies. Safe to leave on in production. When the daemon is unreachable, SDK calls are silent no-ops — your application keeps running.

Getting Started

Install the SDK:

composer require daemon8/php

Start the local daemon (if you haven't already):

daemon8 install   # one-time setup + start as a system service

Emit an observation from anywhere in your app:

use Daemon8\Daemon8;

Daemon8::log('checkout completed', severity: 'info');
Daemon8::warn('rate limit near threshold');
Daemon8::exception(new \RuntimeException('pay gateway timeout'));
Daemon8::query('SELECT * FROM users WHERE active = ?', durationMs: 42.1);

Query from your terminal or agent:

daemon8 tail --kinds log,exception --severity warn

Or from code, against the local daemon's HTTP API:

curl 'http://127.0.0.1:9077/api/observe?kinds=log,exception&severity_min=warn&limit=20'

Facade vs. instance client

The Daemon8 facade is a static entry point backed by a lazily-configured singleton. Use it when global access is simplest:

use Daemon8\Daemon8;
use Daemon8\Config;

Daemon8::configure(Config::create(
    ingestUrl: 'http://127.0.0.1:9077/ingest',
    appName: 'checkout-api',
    debug: true,
));

Daemon8::log('user signed in', severity: 'info');

For DI-friendly, testable, multi-tenant code, construct Daemon8Client directly:

use Daemon8\Config;
use Daemon8\Daemon8Client;

$client = new Daemon8Client(Config::create(
    ingestUrl: 'http://127.0.0.1:9077/ingest',
    appName: 'workers',
));

$client->log('job dispatched');
$client->send(
    ['user_id' => 42, 'action' => 'checkout'],
    severity: 'info',
    kind: 'custom',
    channel: 'audit',
);

Daemon8Client is the real implementation. The Daemon8 facade forwards every call to a lazily-configured singleton client — use whichever style fits your host.

Configuration

Config is an immutable, validated DTO. Build it once at bootstrap and pass it everywhere.

use Daemon8\Config;

$config = Config::create(
    ingestUrl: 'http://127.0.0.1:9077/ingest',
    baseUrl:   'http://127.0.0.1:9077',
    udpHost:   '127.0.0.1',
    udpPort:   9078,
    timeoutMs: 50,
    batchSize: 100,
    appName:   'my-app',
    debug:     false,
);

Every argument is optional. Omitted fields take package defaults.

Environment

DAEMON8_URL=http://127.0.0.1:9077/ingest
DAEMON8_BASE_URL=http://127.0.0.1:9077
DAEMON8_UDP_URL=127.0.0.1:9078
DAEMON8_TIMEOUT_MS=50
DAEMON8_BATCH_SIZE=100
DAEMON8_APP=my-app
DAEMON8_DEBUG=1

Config::fromEnv() reads these. The SDK never touches $_ENV anywhere else.

Observations

Every helper on Daemon8 / Daemon8Client eventually becomes an Observation. For advanced cases build one directly:

use Daemon8\Observation;
use Daemon8\Kind;
use Daemon8\Severity;

$client->push(new Observation(
    kind: Kind::HttpExchange,
    severity: Severity::Warn,
    data: ['method' => 'POST', 'url' => '/checkout', 'status' => 502, 'duration_ms' => 1200],
    channel: 'http.outbound',
    app: 'checkout-api',
));

Kinds

Kind::Log · Kind::Query · Kind::HttpExchange · Kind::Exception · Kind::JsException · Kind::Metric · Kind::StateSnapshot · Kind::Lifecycle · Kind::Custom

Severities

Severity::Trace · Severity::Debug · Severity::Info · Severity::Warn · Severity::Error

Severity::fromStatusCode(int) maps HTTP status codes (5xx → Error, 4xx → Warn, else → Info).

Sensitive data

Redaction has three complementary lanes. Configure once on SensitiveRules, wire it into Config.

use Daemon8\Sanitization\SensitiveRules;
use Daemon8\Sanitization\Sensitive;

$rules = new SensitiveRules(
    fields: ['password', 'api_key', 'authorization'],
    patterns: ['/\bsk-[a-z0-9]{24,}\b/i'],
);

$config = Config::create(sensitiveRules: $rules);

// Or wrap specific values at call sites:
$client->send(['token' => Sensitive::wrap($token)], severity: 'debug');
  1. Field names — case-insensitive key match anywhere in the data tree, redacted to [masked].
  2. Value wrappingSensitive::wrap() forces redaction regardless of key.
  3. Regex patterns — run against scalar values to catch structural leaks (JWTs, API keys, PANs).

Live subscription

Long-running processes can subscribe to the daemon's SSE stream and react to new observations:

use Daemon8\Observation\SseStream;
use Daemon8\Observation\StreamEndpoint;
use Daemon8\Filter;
use Daemon8\Severity;

$stream = new SseStream(StreamEndpoint::fromUrl('http://127.0.0.1:9077/api/stream'));

$filter = new Filter(
    kinds: ['log', 'exception'],
    severityMin: Severity::Warn,
);

foreach ($stream->subscribe($filter) as $observation) {
    handleAlert($observation);
}

The stream reconnects with exponential backoff (1s → 2s → 4s → max 30s) and resumes from the last seen id via Last-Event-ID.

Transports

Default: ChainTransport([CurlMultiTransport, FsockopenTransport]). curl is preferred, raw sockets is the fallback when ext-curl is missing. UDP is available for ultra-low-overhead fire-and-forget (Daemon8::sendUdp() or UdpTransport).

Every transport implements Daemon8\Contracts\Transport. Supply your own via Daemon8Client construction if you need queue-backed or bespoke wire semantics.

Requirements

  • PHP 8.4+
  • ext-json
  • ext-curl (optional — falls back to fsockopen)
  • ext-sockets (optional — required for UDP transport)

Development

composer install
composer check      # phpstan + rector dry-run + phpcs + phpunit
composer test
composer analyse
composer cs:fix

Level 8 phpstan. Rector with phpunit + php84 sets. Slevomat coding standard.

License

MIT. See LICENSE.