pdphilip/omniterm
OmniTerm is a terminal UI toolkit for Laravel that lets you write CLI output as HTML with Tailwind classes and renders it as ANSI. It supports truecolor with 256-color fallback, gradients, arbitrary RGB colors, plus ready-made status badges, tables, progress bars, spinners, and live tasks.
composer require. The decision becomes "adopt a dependency and wrap it" rather than "assign an engineer to write a terminal renderer."$this->line() soup. It gives a shared visual vocabulary — status badges, key-value tables, framed progress bars — that maps 1:1 onto a Tailwind design language the team already speaks.$this->omni->view('cli.deploy-status', [...])) means terminal output can live in resources/views and be reviewed, versioned, and reused like any other UI. That supports a governance decision: one house style for all internal commands, owned by the team rather than by whoever wrote the command.statusError('Connection Failed', ..., ['Check .env', 'Ensure MySQL is running'])) turn error output into an onboarding artefact. Supports DX/onboarding roadmap items and reduces support tickets for internal tooling.liveTask counters lend themselves to internal dashboards, server inspectors, and pre-sales demos that run in a terminal — areas where a full web UI is overkill.runTask() / liveTask() with per-row counters (created/updated/skipped/failed) is a credible substitute for bolting a progress dashboard onto a batch job. Supports the "can we skip building the admin screen for this one-off migration?" question.Adopt when:
flex-1, text-emerald-600, bg-gradient-to-r) transfers directly, so the learning cost is near zero and code review is meaningful.text-[R,G,B]), or per-character colour transitions — the differentiators over the incumbent.Look elsewhere when:
liveView() redraws emit cursor-control sequences that corrupt log capture and CI artefacts. Keep a --no-interaction / plain-output path regardless.Decision rule: pilot on one non-critical internal command. If it survives a month without rendering surprises, expand. Do not put it on the critical path of production deploys, and wrap it behind a thin internal ConsolePresenter so swapping to Termwind or Prompts is a day's work.
To executives (one paragraph): Our Artisan commands are an unpolished but heavily used internal product surface, and we currently spend engineering time hand-formatting terminal output. OmniTerm is a free, MIT-licensed Laravel package that gives us a consistent, well-designed look for that output — progress bars, status badges, tables, spinners, and live-updating job counters — written in a styling language our team already uses for the web. The cost is a single dependency and roughly a day of integration on a pilot command; the benefit is that operator-facing tooling looks and reads like a real product, and errors tell people what to do next. The risk is maintenance: it is a young package from a single author with no downstream dependents. We mitigate that by piloting it on one internal command and isolating it behind a small internal wrapper, so removal — if it ever comes to that — is a contained change, not a rewrite.
To engineering:
This removes ANSI string-wrangling from our codebase. Terminal layout becomes Blade templates with Tailwind classes, compiled to truecolor ANSI with automatic 256-colour fallback for older terminals — no config. It ships real components (status blocks, key-value tables, three progress-bar styles, ten spinner animations, async runTask, live-increment counters, a split-pane item browser, prompts) so we delete bespoke cursor-rewrite code instead of writing more of it. Caveat clearly stated: solo maintainer, zero dependents, breaking changes between majors, Laravel 11+ only. So: depend on it behind our own interface, keep a plain-output fallback for CI and non-interactive runs, and do not let it become load-bearing on the deploy path until it has proven itself.
How can I help you explore Laravel packages today?