conduit-ui/contracts

Shared contracts and value objects for the Conduit tool ecosystem

Maintainers

Package info

github.com/conduit-ui/contracts

pkg:composer/conduit-ui/contracts

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.2.0 2026-08-22 17:41 UTC

This package is auto-updated.

Last update: 2026-08-22 18:23:52 UTC


README

Tests Latest Stable Version Total Downloads License

Shared contracts and value objects for the Conduit tool ecosystem.

Overview

Conduit Contracts provides a foundation for building composable, role-based tools with guaranteed quality through shipped tests and custom Pest expectations.

The Composability Guarantee

Every tool in the Conduit ecosystem ships with 100% test coverage. When you compose tools together, you only need to test your composition logic - the tools themselves are pre-validated.

Example leverage:

  • 10 tools × 19 tests each = 190 tests normally required
  • With Conduit: Only 20 tests needed (89% reduction)
  • 8.5x testing leverage

Installation

composer require conduit-ui/contracts

Core Concepts

Tool Roles

Every tool performs exactly ONE role:

use ConduitUI\ValueObjects\ToolRole;

ToolRole::MUSIC;       // Spotify, Apple Music
ToolRole::INTAKE;      // GitHub Issues, Linear
ToolRole::ATTEMPT;     // Git commits, code fixes
ToolRole::SUBMISSION;  // Pull requests
ToolRole::VALIDATION;  // Tests, linters
ToolRole::DELIVERY;    // CI/CD, deployment
ToolRole::MEMORY;      // Vector databases
ToolRole::ANALYSIS;    // LLMs, AI services

Contracts

All tools implement these interfaces:

  • Tool - Base contract (execute, isAvailable, role, getProviderName)
  • Observable - Event emission (emitStarted, emitCompleted, emitFailed)
  • KnowledgeAware - Knowledge integration (recordToKnowledge, loadContext, queryKnowledge)

Role-specific contracts extend the base:

  • MusicProvider - suggestPlaylist(), playSong(), detectEmotionalState()
  • IntakeManager - receiveWorkRequest(), classifyRequest(), routeToAgent()
  • AttemptExecutor - attemptSolution(), validateAttempt(), retryOnFailure()
  • SubmissionHandler - proposeSolution(), requestReview(), handleFeedback()
  • ValidationRunner - runValidation(), getViolations()
  • DeliveryHandler - deploy(), rollback(), healthCheck()
  • MemoryProvider - store(), retrieve(), embed(), search()
  • AnalysisProvider - analyze(), reason(), compare()

Building a Tool

1. Implement the Contract

use ConduitUI\Contracts\Tool;
use ConduitUI\Contracts\Roles\MusicProvider;
use ConduitUI\ValueObjects\{ToolRole, Context, Result, EmotionalState};

class SpotifyTool implements Tool, MusicProvider
{
    public function role(): ToolRole
    {
        return ToolRole::MUSIC;
    }

    public function getProviderName(): string
    {
        return 'Spotify';
    }

    public function isAvailable(): bool
    {
        return ! empty(config('services.spotify.token'));
    }

    public function execute(Context $context): Result
    {
        $this->emitStarted($context);

        try {
            // Implementation
            $result = Result::success('Playlist started');
            $this->emitCompleted($result);
            return $result;
        } catch (\Throwable $e) {
            $this->emitFailed($e);
            return Result::failure('Failed to start playlist', $e);
        }
    }

    // MusicProvider methods
    public function suggestPlaylist(EmotionalState $state): string { /* ... */ }
    public function playSong(string $songId): Result { /* ... */ }
    public function detectEmotionalState(): EmotionalState { /* ... */ }

    // Observable methods
    public function emitStarted(Context $context): void { /* ... */ }
    public function emitCompleted(Result $result): void { /* ... */ }
    public function emitFailed(\Throwable $exception): void { /* ... */ }

    // KnowledgeAware methods
    public function recordToKnowledge(Result $result): void { /* ... */ }
    public function loadContext(string $collection): Context { /* ... */ }
    public function queryKnowledge(array $criteria): array { /* ... */ }
}

2. Extend the Abstract Test

use ConduitUI\Tests\Contracts\Roles\MusicProviderContractTest;
use ConduitUI\ValueObjects\{ToolRole, Context};

class SpotifyToolTest extends MusicProviderContractTest
{
    protected function createTool(): Tool
    {
        return new SpotifyTool();
    }

    protected function createValidContext(): Context
    {
        return new MusicContext(
            mood: 'focused',
            energy: 0.8
        );
    }

    protected function expectedRole(): ToolRole
    {
        return ToolRole::MUSIC;
    }

    protected function getValidPlaylistId(): string
    {
        return 'test-playlist-id';
    }

    protected function getValidSongId(): string
    {
        return 'test-song-id';
    }
}

3. Run the Shipped Tests

The abstract test automatically validates:

  • ✅ Implements all required interfaces
  • ✅ Returns correct role
  • ✅ Executes and returns Result
  • ✅ Emits events properly
  • ✅ Records to knowledge
  • ✅ All role-specific methods work

Custom Pest Expectations

use function ConduitUI\Tests\Pest\Expectations\expect;

// Tool validation
expect($tool)->toBeAValidConduitTool();
expect($tool)->toHaveRole(ToolRole::MUSIC);
expect($tool)->toBeAvailable();

// Execution
expect($tool)->toExecuteSuccessfully($context);
expect($tool)->toFailExecution($invalidContext);

// Events
expect($tool)->toEmitStartedEvent($context);
expect($tool)->toEmitCompletedEvent($result);

// Results
expect($result)->toBeASuccessfulResult();
expect($result)->toBeAFailedResult();
expect($result)->toHaveResultMessage('Operation completed');

// Knowledge
expect($tool)->toRecordToKnowledge($result);
expect($tool)->toLoadContextFromKnowledge('collection');

Value Objects

Result

use ConduitUI\ValueObjects\Result;

// Success
$result = Result::success(
    message: 'Deployment completed',
    data: ['deployment_id' => 123],
    metadata: ['duration' => 45.2]
);

// Failure
$result = Result::failure(
    message: 'Database connection failed',
    error: $exception,
    metadata: ['retry_count' => 3]
);

// Check outcome
if ($result->isSuccess()) {
    // Handle success
}

Context

use ConduitUI\ValueObjects\Context;
use ConduitUI\ValueObjects\ToolRole;

class MusicContext extends Context
{
    public function __construct(
        public string $mood,
        public float $energy,
        public array $preferences = []
    ) {}

    public function role(): ToolRole
    {
        return ToolRole::MUSIC;
    }

    public function toArray(): array
    {
        return [
            'mood' => $this->mood,
            'energy' => $this->energy,
            'preferences' => $this->preferences,
        ];
    }
}

Testing

composer test
composer test-coverage

License

MIT License. See LICENSE for details.

Contributing

Contributions welcome! Please ensure:

  1. 100% test coverage maintained
  2. All Pest expectations pass
  3. Code follows Laravel Pint standards
  4. Documentation updated for new contracts

Related Packages