This seems like something that would be ideal as an OO module, your subs could be converted to methods. This would also make the objects safe to mix, instead of simply having one "global" indent level.
As for the code you posted, holli already pointed out that module names in lower case are by convention pragmas. Also, just a small note on ( shift || "" ): this means that if $_[0] is "0" or 0, it will be replaced by an empty string. You probably want the defined-or // instead, but it's usually fine to implement a printf replacement simply as sprintf(shift, @_).
Since your post inspired me, here's my idea using overloading:
use warnings;
use strict;
{
package Indent;
sub new { my $c=shift; bless { i=>shift//"\t", c=>0 }, $c }
use overload '++' => sub { ++shift->{c} },
'--' => sub { my $s=shift; $$s{c}=0 if --$$s{c}<0; $$s{c} },
'""' => sub { my $s=shift; $$s{i} x $$s{c} },
'=' => sub { my $s=shift; bless {%$s}, ref $s },
}
my $recurse; $recurse = sub {
my ($lvl,$i) = @_ ? @_ : (0, Indent->new("foo"));
print "<", $i++, "> Enter\n";
$recurse->($lvl+1,$i) unless $lvl>=2;
print "<", --$i, "> Leave\n";
};
$recurse->();
__END__
<> Enter
<foo> Enter
<foofoo> Enter
<foofoo> Leave
<foo> Leave
<> Leave