Perinc...al::FAQ(3pm)

πŸ’… Perinci::CmdLine::Manual::FAQ πŸ’…

okay bestie, welcome to the Perinci::CmdLine FAQ ✨ this is where every "wait, WHY does it do that" question lives, and I'm gonna walk you through all of it, no gatekeeping, fr fr 🫢


πŸŽ€ NOMENCLATURE πŸŽ€

listen, before we start, you gotta know the shorthand, because I use it everywhere and it's giving abbreviation slay:

  • [PC::Classic] β€” this answer is for Perinci::CmdLine::Classic ONLY, not for Perinci::CmdLine::Lite. noted πŸ’…
  • [PC::Lite] β€” this one is specific to Perinci::CmdLine::Lite 🌸
  • [PC::Any] β€” and this one is specific to Perinci::CmdLine::Any πŸ¦‹

✨ GENERAL ✨

πŸ‘‘ Why are there multiple frameworks/flavors for Perinci::CmdLine?

so there are currently 3 (three) flavors of the framework:

  • Perinci::CmdLine::Classic
  • Perinci::CmdLine::Lite
  • Perinci::CmdLine::Inline

which one you should use depends on your needs, because sadly, there is no one-size-fits-all 😭 that's just the reality of it.

Perinci::CmdLine::Classic. So Perinci::CmdLine::Classic (a.k.a. PC:Classic) is the first flavor, the OG, the one I developed first (and it used to just be called Perinci::CmdLine, no suffix, main character energy πŸ‘‘). It has the most complete features AND the prettiest output, but the way that it grew and grew in features, other things like startup overhead and dependencies also grew. it's the "did a lot of side quests" of frameworks.

Perinci::CmdLine::Lite. So another project got started, Perinci::CmdLine::Lite (a.k.a. PC::Lite), and it focuses on keeping startup overhead LOW, specifically so tab completion doesn't get a noticeable delay πŸ™ˆ PC:Lite aims to make CLI scripts typically start below 0.05s, while PC:Classic-based scripts currently start in about 0.2-0.5s, which causes a noticeable delay when doing tab completion. PC:Lite also tries to reduce the number of dependencies (from 100+ down to 30+ or so πŸŽ€). Some PC:Classic features are still missing in PC:Lite (see next question, I got you).

PC:Lite stays more lightweight by avoiding the use of libraries that have large dependencies or add too much to startup overhead. This includes replacing Perinci::Access with Perinci::Access::Lite for metadata access, and avoiding Text::ANSITable for formatting results. no cap.

Implementation-wise, the two share a LOT of common code in the form of their base class, Perinci::CmdLine::Base. the interface is also 99% the same 🫢

It is possible that in the future the two versions will merge. (iconic potential crossover event, we'll see)

Perinci::CmdLine::Inline. There is another flavor called PC:Inline. The goal of this flavor is to make your CLI scripts depend on nothing but Perl and the core modules πŸ”₯ (it is also possible to make PC:Classic- or PC:Lite-based CLI script also be freestanding by techniques like fatpacking or datapacking, but the resulting packed script will be much larger). It has the lowest number of dependencies and the fastest startup overhead (around 0.01s). But currently it also has the least features πŸ’€

It reduces startup overhead further by skipping the Riap layer and prefetching the Rinci metadata, precomputing the command-line options, and embedding all these in the scripts.

See Perinci::CmdLine::Inline for more details of the features it currently supports. This flavor is suitable for simple CLI scripts that need to be as lean and fast as possible, for example: hr (in App::hr) or gen-uuids (in App::UuidUtils) 🌸

All the flavors share the basic concept: running your Rinci-described functions on the command-line. periodt.

So which one should you choose? PC:Lite is the sane default choice πŸ’… unless you need features that are currently not supported by PC:Lite, in which case you can consider using PC:Classic. If you really need fast startup, you can opt for PC:Inline. But note that when the backend function's Rinci metadata changes, you will need to rebuild the script, because the metadata is embedded in the script (while in PC:Lite and PC:Classic, the script simply requests the Rinci metadata during runtime). iykyk.

😭 What Classic features are currently still missing in Lite?

strap in bestie, here's the whole list:

  • More sophisticated formatting

Instead of Perinci::Result::Format (especially for 'text*' formats which use Data::Format::Pretty::Console and Text::ANSITable), to keep dependencies minimal and formatting quick, PC::Lite uses the following simple rules that work for a significant portion of common data structures:

  1. if result is undef, print nothing.
  2. if result is scalar, print it (with newline automatically added).
  3. if result is an array of scalars (check at most 5 first rows), print it one line for each element.
  4. if result is a hash of scalars (check at most 5 keys), print a two column table, first column is key and second column is value. Keys will be sorted.
  5. if result is an array of hashes of scalars (check at most 5 elements), print as table.
  6. if result is an array of arrays of scalars (check at most 5 elements), print as table.
  7. otherwise print as JSON (after cleaning it with Data::Clean::JSON).

YAML and the other formats are not supported. πŸ™ˆ

Table is printed using the more lightweight and much faster Text::Table::Tiny.

PC::Classic supports more sophisticated formatting, can keep colored and full-width Unicode characters stay aligned in a table. πŸ’…

  • Support for extra protocols

Instead of Perinci::Access, PC::Lite uses the more lightweight alternative Perinci::Access::Lite, which does not support some URL schemes (riap+tcp, riap+unix, riap+pipe). http/https and local are supported though 🌈

  • Extra stuffs that Perinci::Sub::Wrapper adds

PC::Classic uses function wrapper to automatically add argument validation, dependency checking, and so on. However, this adds too much overhead, so PC:Lite avoids it and does some of the stuffs by itself to avoid the overhead.

PC:Lite does argument validation, as well as dependency checking. But there are other stuffs that Perinci::Sub::Wrapper adds that are not available, including: result validation, validation of input stream (streaming argument) as well as output stream (streaming result). 😭

  • Color themes
  • Undo
  • I18N
  • The following environment variables
PERINCI_CMDLINE_COLOR_THEME
PERINCI_CMDLINE_SERVER
COLOR
UTF8

πŸ¦‹ What is Perinci::CmdLine::Any then?

this is a module that allows you to select PC::Classic or PC::Lite 🫢 so your scripts do not need to be modified when a user wants to switch between the two. literally the peacekeeper of the family.

πŸ”₯ How does Perinci::CmdLine compare with other CLI-app frameworks?

the main difference is that Perinci::CmdLine accesses your code through the Riap protocol, not directly πŸ‘€ which means that aside from local Perl code, Perinci::CmdLine can also provide CLI for code in remote hosts/languages.

for a very rough demo, download and run this PHP Riap::TCP server <https://github.com/sharyanto/php-Phinci/blob/master/demo/phi-tcpserve-terbilang.php> on your system. after that, try running:

% peri-run riap+tcp://localhost:9090/terbilang --help
% peri-run riap+tcp://localhost:9090/terbilang 1234

everything β€” from help message, calling, argument checking, tab completion β€” works for remote code as well as local Perl code. no cap, it's giving magic ✨

πŸ™ˆ But my application is OO? But I want an OO framework?

this framework is currently function-centric. There are already several OO-based command-line frameworks on CPAN. so like... they exist, go look πŸ’…


🌸 GENERATING DOCUMENTATION 🌸

πŸ’– How do I add examples using Rinci metadata?

in your Rinci function metadata, add the examples property, e.g.:

# myapp script
use Perinci::CmdLine::Any;
our %SPEC;
$SPEC{myadd} = {
    v => 1.1,
    args => {
        num1 => {summary=>'First number' , schema='float*', req=>1, pos=>0},
        num2 => {summary=>'Second number', schema='float*', req=>1, pos=>1},
        round => {
            summary=>'Round to nearest integer',
            schema =>'bool*',
            cmdline_aliases=>{r=>{}},
        },
    },
    examples => [
        {
            summary => 'Add two integers',
            args => {num1=>7, num2=>5},
        },
        {
            summary => 'Add two floats, round to nearest integer',
            args => {num1=>7.1, num2=>5.5, round=>1},
            result => 13,
        },
    ],
}
sub myadd { ... }
Perinci::CmdLine::Any->new(url => '/main/myadd')->run;

if you run myapp --help, you'll see the examples shown as:

Examples:
  Add two integers:
  % myadd 7 5

  Add two floats, round to the nearest integer:
  % myadd 7.1 5.5 --round

and if you use Dist::Zilla and Pod::Weaver and Pod::Weaver::Plugin::Rinci to generate your POD, you'll also have the Synopsis section filled with the above πŸŽ€ slay.


πŸ” DEBUGGING πŸ”

🫢 How do I enable/view log messages?

the framework produces log messages using Log::ger ✨ you can display them on the screen, e.g. using Log::ger::App like:

% TRACE=1 perl -MLog::ger::App /path/to/yourscript.pl

or:

% TRACE=1 PERL5OPT=-MLog::ger::App yourscript.pl

πŸ’€ How do I debug my CLI script?

to see stack trace on error, you can use Devel::Confess 🌈 Perinci::CmdLine::Base detects if Devel::Confess is loaded and will return the stack trace for you:

% perl -d:Confess /path/to/yourscript.pl

or:

% PERL5OPT='-d:Confess' yourscript.pl

πŸ¦‹ PROGRESS INDICATOR πŸ¦‹

✨ How do I show progress indicator?

Perinci::CmdLine can work together with the Progress::Any framework πŸ’…

Option 1: you setup progress output module manually:

use Perinci::CmdLine::Any;
use Progress::Any '$progress';
use Progress::Any::Output 'TermProgressBarColor';

$SPEC{app} = {
    v => 1.1,
    ...
};
sub app {
    $progress->target(5);
    for (1..5) {
        $progress->update(message => "Item $_");
        sleep 1;
    }
    [200];
}

Perinci::CmdLine::Any->new(url => "/main/app")->run;

Option 2: or you can set progress feature in your function metadata, in which case Perinci::CmdLine::Lite will setup Progress::Any::Output::TermProgressBarColor for you automatically:

use Perinci::CmdLine::Any;
use Progress::Any '$progress';

$SPEC{app} = {
    v => 1.1,
    ...
    features => { progress=>1 },
};
sub app {
    $progress->target(5);
    for (1..5) {
        $progress->update(message => "Item $_");
        sleep 1;
    }
    [200];
}

Perinci::CmdLine::Any->new(url => "/main/app")->run;

the former way gives you flexibility to choose/customize your progress output module πŸŽ€


🌈 TODO 🌈

migrate to the Divio information structure. Some FAQ items belong in the Explanation category, some in How-To Guide category, ... (a glow-up for later, bestie)


πŸ‘‘ HOMEPAGE πŸ‘‘

please visit the project's homepage at <https://metacpan.org/release/Perinci-CmdLine>. 🫢


⭐ SOURCE ⭐

source repository is at <https://github.com/perlancar/perl-Perinci-CmdLine>. 🌸

πŸ’– SEE ALSO πŸ’–

Okay bestie, you want MORE?? Periodt, I respect the thirst. Go read:

  • Perinci::CmdLine::Manual β€” the big manual, the main character of the docs.
  • For the Generating Documentation section specifically: Rinci::function and Rinci::FAQ (peep the Documentation section in there). 🌸

✨ AUTHOR ✨

The one, the only, the icon who made this whole thing: perlancar <perlancar@cpan.org>. πŸ‘‘


🫢 CONTRIBUTING 🫢

Want to help out? Obsessed, we love a contributor. Here's the vibe:

  • Send patches by email or via RT, or drop pull requests on GitHub. Pick your fighter. πŸ’…

Most of the time you don't even need to build the distribution yourself, fr fr. Just edit the code and test it like so:

% prove -l

That's it. That's the whole ritual. πŸ•―οΈ

But like, if you DO want to build the distribution (say, to try installing it locally on your own system β€” main character move), you're gonna want:

  • Dist::Zilla
  • Dist::Zilla::PluginBundle::Author::PERLANCAR
  • Pod::Weaver::PluginBundle::Author::PERLANCAR

…and sometimes one or two other Dist::Zilla- and/or Pod::Weaver plugins, it's giving ✨ecosystem✨.

Any additional steps required beyond that are considered a bug and can be reported to me. So if something extra is needed, that's not a feature, bestie, that's a glitch in the matrix and I want to know. 😭

This software is copyright (c) 2026 by perlancar <perlancar@cpan.org>.

It's free software, no cap: you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. 🌈


πŸ’€ BUGS πŸ’€

Found a bug? Want a feature? Please report it on the bugtracker website:

<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-CmdLine>

When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. This is the way. πŸ™ Not me begging for reproductions, but like… yes actually, that's exactly what's happening. A test-file is the love language. πŸ“

And that's a wrap, bestie!! πŸŽ€ This page was rendered by perl v5.40.1 on 2026-04-05 β€” shoutout to the version and the date, iconic duo, they literally showed up in the footer and everything. Now go run some commands and slay. πŸ’–βœ¨πŸ¦‹

πŸ“¦ where this page comes from