Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Garden Cli Laravel Package

vanilla/garden-cli

Garden CLI is a command-line toolkit for Laravel and PHP projects, offering commands to scaffold, manage, and run common development tasks from the terminal. It streamlines local workflows and application maintenance with an easy-to-use CLI.

View on GitHub
Deep Wiki
Context7

Getting Started

Garden CLI is a standalone PHP command-line framework (the console layer that powers Vanilla Forums). It is not Laravel-specific, but it slots into a Laravel codebase easily as a small, dependency-light alternative to artisan for scripts, cron jobs, and internal tooling.

Minimal setup:

composer require vanilla/garden-cli

Create an entry point at the project root (e.g. bin/console) and register your commands:

#!/usr/bin/env php
<?php
require __DIR__.'/../vendor/autoload.php';

$dispatcher = new Garden\Cli\Dispatcher();
$dispatcher->setDefaultCommand('help');
$dispatcher->addClassCommands([App\Console\MyCommand::class]);
exit($dispatcher->call($argv));

A command is a class extending Garden\Cli\Task\BaseTask with an @cli docblock describing args/options:

/**
 * @cli My command description
 * @opt name: The name to greet (required)
 * @opt loud: Shout the output
 */
class MyCommand extends BaseTask
{
    public function run(string $name, bool $loud = false): void
    {
        $this->cli->write(!$loud ? "Hello, $name" : "HELLO, $name");
    }
}

Where to look first:

  1. Dispatcher — argument parsing, command routing, help output.
  2. Task\BaseTask — the base class your commands extend; gives you $this->cli for I/O and $this->cli->input()/output().
  3. Cli — the I/O wrapper (write, writeLine, prompt, error).

First use case: replace ad-hoc cron scripts and one-off admin jobs with typed, documented commands that produce consistent --help output. PHP 8.1 is now supported in v4.0, so typed properties and enums in command signatures work correctly.

Implementation Patterns

Command classes over closures. Garden CLI is class-oriented: define tasks extending BaseTask, let the dispatcher instantiate and run them. This keeps command logic testable and autoloadable, unlike a Closure-based Artisan::command.

Docblock-driven schema. Options and arguments are declared in the class docblock (@opt, @arg, @command). The dispatcher parses $argv against this and injects values into run() by name. Keep your docblock and run() signature in sync — this is the contract.

Subcommand grouping. Register multiple commands via addClassCommand / addClassCommands and let the dispatcher dispatch on argv[1]. For larger suites, wrap registration in a small ConsoleServiceProvider and resolve command classes from Laravel's container so they can inject repositories, config, and services.

Integrating with Laravel. Two practical patterns:

  • Standalone binary: a bin/console script that boots bootstrap/app.php enough to get the container, then hands off to Dispatcher. Good for heavy long-running jobs where you don't want the full Artisan boot.
  • Bridging into Artisan: register a single Artisan command (php artisan garden {command?} {argv*}) that constructs a Dispatcher and forwards $this->argument() values. This gives you one entry point and lets Artisan's scheduler own the tick.

Configuration. Garden CLI reads defaults from an optional Cli::class options array / config file. For Laravel, prefer reading config via config('...') inside run() and pass a --env or --dry-run flag rather than baking environment decisions into the command class. Use $this->cli->input() for interactive prompts (--no-interaction handling is your responsibility — check for a --no-interaction/--quiet flag yourself).

Testing. Commands are plain classes: instantiate, pass an ArrayInput/mock Cli where possible, and assert on run()'s return. For end-to-end, shell out to the binary with proc_open and assert stdout/stderr/exit code. Prefer exit codes over exceptions for expected failures — Dispatcher maps task return values/throws to exit codes.

Output. Use $this->cli->write()/writeLine() rather than echo. This keeps output testable and consistent with the framework's formatting, and respects --quiet if you route through the Cli instance.

Gotchas and Tips

This is not Laravel's console. There's no signature string like $signature = 'foo:bar {--opt=}', no handle() convention, no automatic DI of command dependencies, no Artisan::call return-code marshalling. Budget a half-day if you're porting Artisan commands; the docblock DSL is the main conceptual shift.

Breaking-change surface for v4.0 is small — but verify. The headline change is PHP 8.1 compatibility (two PRs from new contributors). The v3.1.2 → v4.0 bump is a major version, so treat it as semver-significant: the maintainers likely raised the PHP floor and may have touched signatures/typing to satisfy 8.1's stricter internals. Pin to a known-good version, run your command suite against both, and check composer.json for the minimum PHP constraint before upgrading. Don't assume it's purely additive just because release notes read like bugfixes.

Docblock typos fail silently or confusingly. A misspelled @opt won't produce a clear error — you'll get an unexpected-null or a missing-argument failure at dispatch time. Keep --help output (auto-generated from your docblocks) in the loop during development; it's your fastest sanity check that the schema parsed as intended.

Optional parameters and defaults live in the signature. --opt values arrive as strings unless typed; a bool default won't coerce a --flag=0 the way you might expect. Cast explicitly at the top of run().

Exit codes. Returning nothing usually means 0; a thrown exception typically means non-zero but the message formatting is yours. For cron and CI, catch exceptions in run(), write a clean message via $this->cli->error(...), and return an explicit code. Silent success on failure is the classic cron bug.

Interactive vs. non-interactive. Cron/CI environments have no TTY. Gate any prompt/readline behaviour behind a --no-interaction (or --force) flag and fail loudly instead of hanging.

Bootstrap carefully. If you boot Laravel's kernel inside the binary, you'll pay full framework startup on every invocation. If you only need an Eloquent model or two, boot the container and DB connection — not the HTTP kernel. Conversely, if you're long-running (while (true) workers), watch for stale DB connections and memory growth (Eloquent hydration, queued Model events); unset()/recycle per iteration.

Logging and observability. Route command logs to the same channel as the app (Log::channel(...)) so cron output and application logs correlate. Include the command name and argv (redacting secrets) in a start/end log line — you'll thank yourself the first time a scheduled job fails silently.

Extension points. Dispatcher exposes the Cli instance and allows custom Task resolvers/containers; Cli can be subclassed for custom output formatting. If you find yourself repeating flag parsing, subclass BaseTask with your own shared flags (--dry-run, --verbose) and read them in a shared beforeRun-style hook rather than duplicating docblock entries.

Alternatives worth a thought. If your team is heavily invested in Artisan, the Symfony Console bridge, or a modern framework (Laravel Zero / MiniCLI), Garden CLI's advantage is being tiny and dependency-light — evaluate against that niche rather than as a general Artisan replacement.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle