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

Botman Tinker Laravel Package

mpociot/botman-tinker

BotMan Tinker adds an interactive REPL to the BotMan chatbot framework, letting you chat with and test your bots straight from the terminal. Send messages, inspect conversation state, and debug bot responses instantly without wiring up a messaging platform first.

View on GitHub
Deep Wiki
Context7

Getting Started

What it actually is. A single Artisan command — php artisan botman:tinker — that boots your existing BotMan instance and drops you into a REPL. Every line you type is handed to the bot as an incoming message; replies are printed to the terminal. No webhook, no channel credentials, no HTTP round-trip. Think laravel/tinker, but the object you're poking is a conversation.

Install as a dev dependency, pinned exactly. The last release is 1.2.0 (May 2020) and its entire changelog is a composer.json bump for Laravel 7.x. A floating constraint buys you nothing and risks a silent dev-environment change.

composer require --dev mpociot/botman-tinker:1.2.0

Verify resolution before you commit to it:

composer require --dev mpociot/botman-tinker:1.2.0 --dry-run
composer why-not mpociot/botman-tinker 1.2.0

If the only path to installation involves downgrading Laravel, PHP, or symfony/console, stop and read the escape hatch in Gotchas — this tool is ~40 lines.

Where to look first, in order.

  1. The package's own composer.json. It is the most accurate documentation the project ships: the declared bounds on illuminate/*, symfony/console, and php tell you immediately whether you can use it.
  2. The package's command class under src/. Read it once. It shows you exactly how it resolves the BotMan instance and which driver it drives — that single fact determines everything about whether tinker output is trustworthy.
  3. Your own BotMan service provider / container binding. The command resolves the same binding your webhook controller uses, so a failure here is itself a useful diagnostic.
  4. config/botman.php (or wherever your driver config is assembled). This decides which driver the REPL runs against.

First use case. Pick one Conversation class or one hears() listener. Run the command, walk the happy path plus two failure branches. That's the whole adoption story:

php artisan botman:tinker
> hi
> order a pizza
> large
> nonsense
> yes, confirm

If that loop isn't measurably faster than curling your real webhook, don't standardise on it.

Non-negotiable prerequisite: confirm the REPL is pointed at a local driver (BotMan's null/echo driver or a test driver), not Slack or Telegram. See the first Gotcha — this is the one mistake that can page a customer.

Implementation Patterns

Extract first, then tinker. The tool is only as useful as your bot is testable. Conversations belong in app/BotMan/Conversations/* extending BotMan\BotMan\Conversations\Conversation; hears() handlers belong in dedicated listener classes registered from a service provider. Once that's true, your daily loop becomes: edit the conversation class → rerun botman:tinker → replay the same four lines.

Keep that sequence in a scratch file so you're not retyping it from memory:

# notes/pizza-flow.txt
hi
order a pizza
large
yes, confirm

Add a local-only logging middleware to see what BotMan actually matched. With the HTTP boundary gone, tinker is the cleanest place to inspect incoming message shape:

// app/Providers/BotManServiceProvider.php
if (app()->environment('local')) {
    $botman->middleware->heard(function ($message, $bot) {
        logger()->debug('botman.heard', [
            'text'    => $message->getText(),
            'driver'  => $message->getDriver(),
            'payload' => $message->getPayload(),
        ]);
    });
}

Gate it on local so it never runs in production. This is how you validate pattern-matching assumptions and confirm reply payload assembly — menus, buttons, and cards as raw arrays.

Exercise stateful flows deliberately. Multi-turn conversations work in a single REPL session because the process keeps the BotMan instance alive between turns. Use that property rather than fighting it:

  • Walk the same conversation twice in one session to hit the "already in progress" branch.
  • Type garbage mid-conversation to exercise the ask() validation loop.
  • Walk a flow, exit, restart, and re-enter. State should not persist — if it does, your cache backend is leaking between sessions.

Separate intent routing from rendering. Use tinker to confirm the right branch fires and the right payload is built — not what it looks like. Rich templates get flattened or dumped as arrays in a terminal, so UX review belongs in a real channel. For CI assertions, use BotMan's own tester helpers (BotManTester or a fake driver depending on your BotMan major), not this.

Demo and onboarding prep. Before a stakeholder demo, script the exact prompt sequence into a notes file and rehearse it in tinker with the target channel's driver config copied over. For onboarding, pair a new engineer on it — it's the fastest way to show how a Conversation moves between ask() and reply() without handing out channel credentials.

Keep it out of CI. It expects an interactive TTY, produces free-form output, and makes no assertions. Treat it as a debugger, not a test suite. If someone proposes wiring it into a pipeline, that's the signal to build a proper fake-driver harness instead.

Gotchas and Tips

Your "local" REPL can message real customers. Replies echo in your terminal, but the BotMan instance is booted with your real driver config. If config/botman.php selects Slack or Telegram, $bot->reply() may hit the live API from your terminal. Point the command at an echo/test driver, or use a dedicated local config, before typing anything. This is the number one way people accidentally notify a customer from php artisan.

It needs a TTY. Without one it hangs or exits immediately:

docker compose run --rm -it app php artisan botman:tinker   # -it is required
echo "hi" | php artisan botman:tinker                       # exits on EOF; don't rely on it

For arrow-key history and line editing, confirm the PHP readline extension is present in the container. Without it you get raw stdin and the tool feels broken rather than minimal.

Conversation state bleeds between sessions. BotMan persists conversation state through its cache driver. Array/in-memory caches die with the process (fine). Redis and file caches survive, so a flow abandoned yesterday resumes mid-conversation today and looks like a code bug. When a flow behaves impossibly, run php artisan cache:clear before debugging anything else.

Green in tinker does not mean it works on the channel. The REPL bypasses webhook signature verification, HTTP payload shape, retries, and channel templating. Nothing you learn here proves integration. Say so explicitly when reporting "tested" to a reviewer — otherwise you'll be blamed for a Slack formatting bug you never could have seen.

Legacy vendor mismatch. This package is mpociot/botman-tinker while BotMan itself moved to botman/botman. Confirm your app uses botman/botman and that Composer isn't pulling a second, older BotMan alongside it. Two BotMan classes in one autoloader produces confusing "method does not exist" errors that look like your code's fault.

composer show | grep -i botman   # one-second check

Framework ceiling. 1.2.0 targets Laravel 7.x. Laravel 8+ and PHP 8.2/8.3 are unverified; expect composer why-not conflicts on illuminate/* or symfony/console. Never downgrade your framework to keep a dev convenience tool.

Provider auto-discovery can be off. If discovery is disabled or you curate providers manually, add the provider class (check extra.laravel.providers in the package's composer.json) to config/app.php, or the command simply won't appear in php artisan list.

Interactive prompts collide with the REPL prompt. ask() inside a conversation consumes lines from the same stdin the REPL loop is reading. Usually fine, but if prompts get swallowed during a long ask() chain, type an empty line to nudge the loop.

Exit cleanly. Use exit / quit or Ctrl+D. Ctrl+C mid-listen() can wedge the process, especially with streaming drivers; if the terminal stops echoing, stty sane restores it.

The escape hatch — own the command. This package is roughly 40 lines you can write in an afternoon, and doing so removes the Laravel version ceiling, the vendor mismatch, and the abandonment risk in one move:

protected $signature = 'botman:chat';

public function handle()
{
    $botman = app(\BotMan\BotMan\BotMan::class);

    while (($line = readline('> ')) !== false) {
        if (trim($line) === 'exit') {
            break;
        }
        // feed $line through a local/test driver, then $botman->listen()
    }
}

The exact wiring depends on your BotMan major and how the instance is bound — read the package's command class as the reference implementation and mirror it. For any team on Laravel 8+, writing it is the default recommendation; adopting the package is the exception you justify.

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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle