hop-top / kit
Cross-language CLI UX parity toolkit
0.5.0-alpha.4
2026-10-30 15:15 UTC
Requires
- php: ^8.4
- guzzlehttp/guzzle: ^7.9 || ^8.0
- hop-top/cite: ^0.2.0
- jewei/typeid-php: ^1.1 || ^4.0
- laravel/prompts: ^0.3
- psr/http-message: ^2.0
- psr/http-server-handler: ^1.0
- symfony/console: ^7.4 || ^8.0
- symfony/event-dispatcher: ^7.0 || ^8.0
- symfony/yaml: ^7.0 || ^8.0
Requires (Dev)
- nyholm/psr7: ^1.8
- phpstan/phpstan: 2.3.1
- phpunit/phpunit: ^13
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-30 15:17:12 UTC
README
Experimental PHP client SDK for hop-top kit.
Install
composer require hop-top/kit
Requires PHP 8.4. Optional PSR-15 MCP hosting needs a PSR-7
implementation of your choice (nyholm/psr7 in the dev requirements).
Quick start
use HopTop\Kit\Cli\KitCommand; use HopTop\Kit\Output\Flags; use HopTop\Kit\Output\Formatter\ColumnSpec; use Symfony\Component\Console\Application; use Symfony\Component\Console\Attribute\AsCommand; #[AsCommand(name: 'items')] final class ItemsCommand extends KitCommand { protected function handle(): int { $this->render( [['name' => 'alpha', 'count' => 1]], columns: [ColumnSpec::of('name', 'name'), ColumnSpec::of('count', 'count')], ); return self::SUCCESS; } } $app = new Application('tool', '0.1.0'); $app->setAutoExit(false); Flags::register($app); // --format, --format-opt, --cols, --template, -o $app->add(new ItemsCommand());
Already extending another base class? Call HopTop\Kit\Output\KitOutput::for()
instead of KitCommand.
Modules
Every path is relative to src/; namespaces sit under HopTop\Kit.
| Path | What it is | Start here when |
|---|---|---|
Cli/ |
KitCommand base for Symfony Console commands |
you write a kit-powered command |
Serve/ |
serve hierarchy and service lifecycle | your CLI hosts long-running services |
Output/ |
--format flag family, dispatcher, registry, CliError |
a command renders one payload as table, json or yaml |
Output/Formatter/ |
Formatter interface, ColumnSpec, options, projection |
you implement or configure a formatter |
Output/Formatter/Builtin/ |
the shipped formatters and their --format-opt keys |
you need a formatter option or a custom formatter |
Mcp/ |
dual-spec MCP surface over PSR-15 or stdio | MCP clients must call your commands as tools |
Net/ |
--offline marker and Guzzle enforcement |
a request must honour --offline |
Api/ |
JSON API client with the offline guard pre-installed | you call an HTTP API from a kit CLI |
Id/ |
TypeID primitive | you mint or parse prefixed identifiers |
Telemetry/ |
consent-gated usage events and redaction | you record usage under user consent |
Telemetry/Sink/ |
JSONL, HTTPS and null sinks | you choose where envelopes go |
Uri/ |
URI facade delegating to hop-top/cite |
you parse or format kit URIs |
Tui/ |
placeholder class, no members yet | never; reserved for status output |
Contract
outputshipstable,jsonandyaml; column order comes from an explicitColumnSpeclist,--colsreorders as well as selects, andheadermust equalkey.- MCP exposure is default-closed: the default policy blocks every destructive leaf on every remote surface.
--offlineis the highest-precedence network override, exempts loopback, and throwsOfflineExceptionon a guarded Guzzle stack or PSR-18 client. It does not cover raw sockets, PDO orfile_get_contents(), andHttpsSinkis deliberately unguarded.- Telemetry is default-denied: nothing emits without both a granted consent decision and a non-
offmode.
See also
- PHP SDK reference: the URI facade, output formatting rules and worked examples, the MCP mount over PSR-15, offline enforcement in full, telemetry sinks and redaction
- Serve lifecycle contract, CLI parity guide, Serve MCP from any SDK