Skip to main content

Real projects · real findings

Bugs found. Automatically.

These issues were found by tailtest running alongside a Claude Code session. No test was written manually, tailtest generated the scenarios, ran them, and surfaced what failed.

securo-finance/securo

Personal finance · open source

Python ★ 536

Recurring transactions permanently lose their date after February

Monthly transactions on the 29th, 30th, or 31st get clamped to Feb 28 when February arrives. On the next advance, the function reads the clamped day instead of the original, the intended date is permanently gone.

_advance_date(date(2026, 1, 31), "monthly")
→ 2026-02-28 # correct (Feb has 28 days)
_advance_date(date(2026, 2, 28), "monthly")
→ 2026-03-28 # wrong, should be 2026-03-31
dongdongbh/Mindwtr

GTD productivity · open source

TypeScript ★ 737

Monthly calendar events set by weekday appear on the wrong date

Events set to repeat on "the first Monday of the month" use a fixed day number instead. A meeting every first Tuesday shows up on the 6th of each month, regardless of what day that is.

RRULE:FREQ=MONTHLY;BYDAY=1MO # first Monday of each month
Jan 6 → Feb 3 → Mar 3 → Apr 7 # expected
Jan 6 → Feb 6 → Mar 6 → Apr 6 # actual
theDakshJaitly/mex

Docs drift detector · open source

TypeScript ★ 655

A file that trips both staleness thresholds is penalised twice

When a file exceeds both the day threshold (≥90 days) and the commit threshold (≥200 commits), checkStaleness returns two separate STALE_FILE errors for the same condition. computeScore deducts 10 points per error, so one stale file silently subtracts 20 points instead of 10.

checkStaleness("docs/api.md", cwd) // days=100, commits=250
→ [{ code: "STALE_FILE", message: "100 days..." },
{ code: "STALE_FILE", message: "250 commits..." }]
computeScore([issue1, issue2]) // deducts 10 + 10 = 20
paperclipai/paperclip

AI-native code editor · open source

TypeScript ★ 53749

Monthly backup retention uses a fixed 30-day month, deleting backups prematurely

pruneOldBackups calculates the monthly cutoff as monthlyMonths × 30 days. In a 31-day month, a backup from 2 calendar months ago is 61 to 62 days old, past the 60-day cutoff, and gets deleted even though it should be kept.

// monthlyMonths: 2 → cutoff = now - 60 days
// Today: March 31. Backup from Jan 28 is 62 days old → deleted.
// Correct: Jan 28 is within 2 calendar months → should be kept.
const monthlyCutoff = now - Math.max(1, retention.monthlyMonths) * 30 * 24 * 60 * 60 * 1000;
rtk-ai/rtk

Code complexity analysis · Mozilla

Rust ★ 26594

Two filter bugs corrupt comment stripping and function-body extraction

MinimalFilter: a single-line """...""" docstring leaves in_docstring=true, so a # comment between two single-line docstrings is incorrectly stripped. AggressiveFilter: lines starting with fn foo() { skip brace counting, causing let bindings after the first body line to leak out. 2 issues filed.

# MinimalFilter, comment suppressed between two single-line docstrings
"""doc A"""
# this comment is incorrectly stripped ← bug
"""doc B"""
expectedparrot/edsl

AI survey framework · open source

Python ★ 454

uniquify() produces duplicate IDs when suffixed names already exist in the list

When a ScenarioList contains a value like "item_1" and uniquify("id") is called on a list that also has duplicate "item" entries, the function generates "item_1" as a suffix, colliding with the pre-existing "item_1". The result has duplicate IDs, breaking the uniqueness contract.

sl = ScenarioList([Scenario({"id": "item"}),
Scenario({"id": "item_1"}), # pre-existing
Scenario({"id": "item"})])
ids = [s["id"] for s in sl.uniquify("id")]
# Expected: ['item', 'item_1', 'item_2']
# Actual: ['item', 'item_1', 'item_1'] ← duplicate
python-cmd2/cmd2

Interactive CLI library

Python ★ 687

Module-level REDIRECTION_TOKENS list grows without bound on every alias or macro command

Four functions in cmd2.py (_alias_create, _alias_list, _macro_create, _macro_list) assign constants.REDIRECTION_TOKENS by reference and call .extend() on it, permanently mutating the module-level list. Each invocation appends terminators; after 5 alias creates the list grows from 3 to 10 entries. Two Cmd() instances in the same process share the corrupted state, instance A's alias operations affect instance B's redirection parsing.

tokens_to_unquote = constants.REDIRECTION_TOKENS # reference, not copy
tokens_to_unquote.extend(self.statement_parser.terminators) # mutates module global
# After 5 alias creates: ['|', '>', '>>', ';', ';', ';', ';', ';', ';', ';', ';']
# Fix: list(constants.REDIRECTION_TOKENS)
View GitHub issue #1649 Fixed by maintainer
mattrobenolt/jinja2-cli

CLI for Jinja2 rendering

Python ★ 598

KeyError leaks from get_format() and has_format() when the format string is unknown

get_format(fmt) only catches ModuleNotFoundError; when fmt is not present in the formats dict (e.g. 'nonexistent'), formats[fmt] raises KeyError which propagates uncaught instead of being wrapped as InvalidDataFormat. has_format() inherits the same root cause: it only catches InvalidDataFormat, so the KeyError leaks through and has_format("unknown") raises instead of returning False. Found via V13 native adversarial mode (depth: adversarial) on 2026-04-25.

# jinja2cli/cli.py:74
def get_format(fmt):
try: return formats[fmt]() # KeyError on unknown fmt
except ModuleNotFoundError: raise InvalidDataFormat(fmt) # leaks KeyError
# Fix: except (KeyError, ModuleNotFoundError):
maldoinc/wireup

Type-driven dependency injection

Python ★ 388

Module discovery crashes on PEP 420 namespace packages and traverses hidden dirs like .git

_find_objects_in_module accesses module.__file__ unconditionally, but PEP 420 namespace packages have no __file__ and crash with AttributeError. Three more robustness issues in the same file: endswith('__init__.py') false-positives on not__init__.py; hidden directories like .git and .mypy_cache are traversed and importlib.import_module is called with invalid dot-prefixed names; one broken submodule kills the entire discovery scan because there is no try/except around the import.

# wireup/_discovery.py:62
module.__file__ # AttributeError on namespace packages
# Fix: getattr(module, "__file__", None)
# 3 more bugs in same file: __init__ false-positive, hidden dirs, broken submodule kills scan
omni-us/jsonargparse

CLIs from type hints

Python ★ 424

Forward-ref resolution crashes when run from __main__ context

resolve_forward_ref calls __builtins__.copy(). In regular Python modules, __builtins__ is a dict; in __main__ and many embedding contexts it is the builtins module, and modules don't have a copy method. Calling jsonargparse from a __main__ script crashes. Four more edge-case crashes in the same file: bare tuple/set types (no __origin__), and Dict[int, str] with non-numeric or empty-string keys (raw ValueError leak from int()).

# _typehints.py:777
__builtins__.copy() # AttributeError when __builtins__ is the module
# Fix: import builtins; vars(builtins).copy()
# 4 more crashes: bare tuple/set origin, Dict[int, str] non-numeric keys
luolingchun/flask-openapi

OpenAPI for Flask

Python ★ 265

Single-line docstring descriptions silently vanish from generated OpenAPI specs

get_operation has a backward condition: lines[0] if len(lines) == 0 else '<br/>'.join(lines[1:]). split() always returns at least one element, so len(lines) == 0 is always False, single-line docstrings always go through the join branch and produce an empty string. The description is silently lost. Two more bugs in parse_method: routes registered with HEAD or OPTIONS are silently dropped because the if/elif ladder only handles GET/POST/PUT/PATCH/DELETE.

# flask_openapi/utils.py:58
doc_description = lines[0] if len(lines) == 0 else "<br/>".join(lines[1:])
# len(lines) == 0 is always False after split() ← dead code
# Fix: len(lines) <= 1
itsDNNS/docsight

Self-hosted DOCSIS evidence system

Python ★ 228

api_restore proceeds with no config_manager and writes to a hardcoded /data path

When get_config_manager() returns None, api_restore does not bail early. It falls through to a fallback that uses '/data' as the data directory and proceeds to extract the user's uploaded archive into a hardcoded /data path on the host filesystem. The sibling api_backup_download endpoint correctly returns 500 in the same condition.

# app/modules/backup/routes.py
data_dir = _config_manager.data_dir if _config_manager else "/data" # falls through
# api_restore proceeds and unpacks to /data ← bug
# api_backup_download returns 500 in the same case (correct)
View GitHub issue #357 Fixed by maintainer
deep5050/radio-active

Terminal radio player

Python ★ 584

Newline in alias name corrupts the alias file with phantom radio entries

add_entry writes name and url directly to the alias file with no sanitization. A name containing a newline (TUI input glitch, clipboard paste, scripted alias creation) splits across two lines and creates a phantom alias on the next read. The search() method also has a state leak: self.found is set to True on a hit but never reset to False on a miss, so any miss following a previous hit reports a stale True.

# radioactive/alias.py:87
f.write(f"{left}=={right}\n") # no sanitization
# add_entry("evil\nstation", "http://url1") writes:
# evil==
# station==http://url1 ← phantom entry
majiidd/persiantools

Persian / Jalali date utilities

Python ★ 218

JalaliDateTime copy-construct silently drops timezone info

JalaliDateTime(other_jdt) returns a naive copy when the source is timezone-aware. The constructor's two input branches behave asymmetrically: the stdlib datetime branch preserves tzinfo, the JalaliDateTime branch (Pickle-support path) does not. Round-tripping a tz-aware value through the constructor silently makes it naive.

# persiantools/jdatetime.py:1082
tz = timezone(timedelta(hours=3, minutes=30))
a = JalaliDateTime(1404, 2, 8, 12, 0, 0, tzinfo=tz)
b = JalaliDateTime(a)
a.tzinfo # UTC+03:30
b.tzinfo # None ← silently dropped
jaraco/inflect

English plural / singular / number-to-words inflection

Python ★ 1k

number_to_words leaks IndexError instead of NumOutOfRangeError for huge inputs

engine().number_to_words(n) is documented to raise NumOutOfRangeError for out-of-range inputs (the exception is imported and advertised). For numbers requiring magnitude index >= 12 (roughly 10^36 and above), an uncaught IndexError leaks from internal mill[mindex] lookup in tenfn. Users wrapping calls in try/except NumOutOfRangeError will not catch IndexError, so their code crashes unexpectedly on large inputs.

# inflect/__init__.py:3699
import inflect
p = inflect.engine()
p.number_to_words(10**40)
# Expected: raises NumOutOfRangeError
# Actual: IndexError: list index out of range
mwilliamson/python-mammoth

.docx → HTML / Markdown converter

Python ★ 1.1k

Unmatched w:fldChar end crashes convert_to_html with IndexError

read_fld_char calls complex_field_stack.pop() unconditionally when it encounters a fldChar of type end or separate. Well-formed documents always pair these with a prior begin, but a hand-edited, tool-generated, or partially recovered .docx can carry an unmatched end. The result is IndexError: pop from empty list leaking from a public conversion call, callers wrapping mammoth in a try/except for known docx errors see an unexpected stdlib exception instead. Same shape as the maintainer-fixed #158 (w:ilvl crash on malformed numbering). Suggested fix: guard both pops with an empty-stack check, return _empty_result.

# mammoth/docx/body_xml.py:206
elif fld_char_type == "end":
complex_field = complex_field_stack.pop() # no empty-stack guard
# repro: one-page docx with a stray <w:fldChar w:fldCharType="end"/>
# mammoth.convert_to_html(buf) → IndexError: pop from empty list
gweis/isodate

ISO 8601 dates and durations · open source

Python ★ 175

Equal Durations hash differently, breaking sets and dicts

Duration.__eq__ treats Duration(years=1) and Duration(months=12) as equal (it normalizes years to months), but __hash__ hashes the raw year/month fields without that normalization. This violates Python's invariant that equal objects must hash equal, so equal Durations are not deduplicated in set/dict and membership tests silently fail.

a = Duration(years=1); b = Duration(months=12)
a == b # True
hash(a) == hash(b) # False ← invariant violated
len({a, b}) # 2 (expected 1)
python-humanize/humanize

Human-friendly numbers and dates · open source

Python ★ 737

naturaldelta(inf) crashes instead of returning the value unchanged

naturaldelta()'s docstring says a non-finite float is returned unchanged. nan is handled (its int() raises ValueError, which is caught), but float('inf') raises an uncaught OverflowError because the except clause omits OverflowError. That asymmetric crash contradicts the documented contract.

humanize.naturaldelta(float('nan')) # 'nan' handled
humanize.naturaldelta(float('inf')) # OverflowError ← uncaught
keleshev/schema

Schema validation · open source

Python ★ 2945

Optional mutable default ([]/{}) leaks across every validate() call

An Optional key with a mutable default returns the SAME object on every validate(). Mutating one validation's result corrupts the default for all later validations of the same Schema. That is the classic shared mutable default footgun, leaking state between unrelated calls.

s = Schema({Optional('items', default=[]): list})
a = s.validate({}); a['items'].append(1)
b = s.validate({})
b['items'] # [1] (expected []) ← leaked
erikrose/parsimonious

PEG parser · open source

Python ★ 1912

OneOrMore over a zero-width match fails at end-of-input (off-by-one)

A '+' quantifier over a member that can match empty (e.g. the regex ~"a*") fails when the cursor is already at end-of-input: the match loop guard 'while new_pos < size' refuses to try the sub-match at new_pos == size, even though it would match zero-width there and satisfy min=1. Parsing then wrongly raises ParseError.

Grammar('foo = ~"a*"+').parse('')
# ParseError, expected a successful empty match ← off-by-one at EOF
regebro/tzlocal

Local timezone detection · open source

Python ★ 219

Malformed system clock config crashes timezone detection

A /etc/sysconfig/clock line like ZONE="America/New_York with no closing quote makes the closing-quote regex return None; the code then calls .start() on it, raising an uncaught AttributeError. It isn't in the surrounding except (OSError, UnicodeDecodeError), so one malformed config line crashes detection instead of being skipped.

# etc/sysconfig/clock contains: ZONE="America/New_York no closing quote
unix._get_localzone_name(root)
# AttributeError: 'NoneType' object has no attribute 'start' ← uncaught
john-kurkowski/tldextract

Domain and TLD extraction · open source

Python ★ 2007

reverse_domain_name prepends a spurious dot for IPs and unknown TLDs

reverse_domain_name joins [suffix, domain, ...] without dropping empty components, so when suffix is '' (IP addresses, unknown TLDs) the result has a leading dot. The sibling fqdn property filters empties; reverse_domain_name does not.

extract('http://127.0.0.1/').reverse_domain_name
# '.127.0.0.1' (expected '127.0.0.1') ← leading dot
carpedm20/emoji

Emoji handling · open source

Python ★ 2031

emojize() validates the variant argument only for some inputs

emojize's docstring says it raises ValueError for an invalid variant. But the check runs lazily inside the per-match callback, only for an emoji that has a variant key, so the same invalid variant is silently accepted when the string has no emoji (or only emoji without a variant), and rejected otherwise.

emojize('hello world', variant='bogus') # 'hello world' no error
emojize(':red_heart:', variant='bogus') # ValueError ← inconsistent
matthewwithanm/python-markdownify

HTML to Markdown · open source

Python ★ 2203

Unicode 'numeric' characters in start/colspan crash int() conversion

convert_li and the table converter call int() on numeric-looking attribute values, but characters like '½' and superscript digits pass str.isnumeric() while int() rejects them, raising ValueError mid-conversion. tailtest surfaced both cold, with no guidance.

markdownify('<ol start="½"><li>a</li></ol>')
# ValueError: invalid literal for int() with base 10: '½' ← crash
Found cold; colspan variant duplicates closed upstream #123/#126/#137 (not re-filed). The ol-start variant is newly observed and held.
pytoolz/toolz

Functional utilities · open source

Python ★ 5150

tail(0, seq) returns the whole sequence instead of nothing

tail(n, seq) is seq[-n:] with a deque fallback. For n=0, seq[-0:] is seq[0:], the entire sequence, so tail(0, [10,20,30]) returns everything instead of the last zero elements. It is also inconsistent: sliceable inputs return the whole sequence, non-sliceable iterables return empty.

tail(0, [10, 20, 30]) # [10, 20, 30] ← expected empty
tuple(tail(0, iter([10,20,30]))) # () deque path: empty
gruns/furl

URL parsing and manipulation · open source

Python ★ 2807

Missing regex anchor lets invalid URL schemes through and corrupts the parse

is_valid_scheme matches the scheme regex but omits the trailing $ anchor (the module's other validators all use ^...$). Any prefix that looks like a scheme is accepted, so 'a b:c' is mis-parsed as scheme 'a b' plus path 'c' instead of no scheme and path 'a b:c'.

furl('a b:c').scheme # 'a b' ← expected None
str(furl('a b:c').path) # 'c' ← expected 'a b:c'
python-poetry/tomlkit

Style-preserving TOML · open source

Python ★ 832

item() reorders keys even with the default sort_keys=False

A misplaced parenthesis in item()'s sort key, (isinstance(i[1], dict), i[0] if _sort_keys else 1), leaves the dict-vs-scalar term always active, so dict-valued keys are forced after scalar keys even when sort_keys is False. The sibling top-level branch guards the whole tuple correctly.

item([{'a': {'x': 1}, 'b': 2}]).as_string()
# 'b = 2\n\n[a]\nx = 1\n' ← b emitted before [a]
mahmoud/glom

Nested data access · open source

Python ★ 2152

Path indexing one-past-the-end returns an empty Path instead of IndexError

Path.__getitem__ uses 'start > len(...)' instead of '>=' for its integer-index bounds check, so an index exactly one position past the end slips through and silently returns an empty Path() rather than raising IndexError.

Path('a', 'b')[2] # Path() ← expected IndexError
seatgeek/thefuzz

Fuzzy string matching · open source

Python ★ 3635

dedupe() crashes on an item that the default processor reduces to empty

dedupe() calls extractBests(score_cutoff=threshold) per item then max(matches). When an item reduces to the empty string under the default processor (e.g. '###'), all comparisons score 0, extractBests returns [], and max([]) raises ValueError. The code even warns about the empty-query case, then calls max() unconditionally.

dedupe(['###', 'apple', 'apple pie'])
# ValueError: max() iterable argument is empty ← crash
alecthomas/voluptuous

Data validation · open source

Python ★ 1847

Number validator leaks a raw TypeError on Infinity/NaN instead of raising Invalid

The Number validator converts input to Decimal and inspects precision/scale. For Decimal('Infinity')/Decimal('NaN'), that inspection raises a raw TypeError ('infinity and NaN have no precision') which escapes the validator instead of being surfaced as a voluptuous Invalid.

Number(precision=6, scale=2)('Infinity')
# TypeError: infinity and NaN have no precision ← expected Invalid
aio-libs/yarl

Async URL library · open source

Python ★ 1489

URL.join() decodes percent-encoded characters in the base path

When joining a relative reference onto a base whose path does not end in '/', the RFC 3986 merge is built from the already-decoded path segments (self.parts), so an encoded delimiter like %2F is turned into a real '/' and the path structure is corrupted. The encoded segment should be preserved.

URL('http://x/a%2Fb/c').join(URL('d'))
# http://x/a/b/d ← expected http://x/a%2Fb/d
prettytable/prettytable

ASCII table rendering · open source

Python ★ 1662

from_html() crashes on a ragged table row (off-by-one padding)

from_html() pads short rows up to the header width, but the padding loop iterates range(1, appends) instead of range(1, appends + 1), so a data row with fewer <td> cells than the header is padded one cell short and add_row rejects it with ValueError. Normalizing ragged HTML tables is exactly what from_html exists to do.

from_html('<table><tr><th>a</th><th>b</th></tr><tr><td>1</td></tr></table>')
# ValueError: Row has incorrect number of values, 1!=2 ← crash
astanin/python-tabulate

Table formatting · open source

Python ★ 2565

tabulate() raises TypeError when rowalign is a tuple

Every sequence-valued parameter (headers, colalign, floatfmt, maxcolwidths) accepts a tuple, but rowalign/maxheadercolwidths do not: the internal padding helper does 'original + [default] * n', which is tuple + list when a tuple is passed, raising TypeError (even when no padding is needed).

tabulate([[1,2],[3,4]], rowalign=('top','bottom'))
# TypeError: can only concatenate tuple (not 'list') to tuple ← list works
dgilland/pydash

Functional utilities · open source

Python ★ 1445

to_list() on a dict returns dict_values, not a list

A function named to_list returning a non-list breaks isinstance(result, list) and any code that indexes or concatenates the result. For a dict input, to_list yields obj.values() without materializing it into a list.

pydash.to_list({'a': 1, 'b': 2})
# dict_values([1, 2]) ← expected [1, 2]
tobgu/pyrsistent

Immutable data structures · open source

Python ★ 2189

CheckedPMap.create drops ignore_extra for nested checked types

CheckedPMap.create accepts ignore_extra but does not forward it to the nested key/value CheckedType.create calls, so extra fields in a nested checked value still raise. CheckedPVector and CheckedPSet thread ignore_extra correctly; CheckedPMap is the one collection that omits it.

M.create({'k': {'a': 1, 'extra': 2}}, ignore_extra=True)
# AttributeError: 'extra' is not among the specified fields ← ignore_extra ignored
Pylons/colander

Schema validation · open source

Python ★ 463

Any validator can pass when every subvalidator fails

Any (succeed if any subvalidator passes) decides success by comparing the number of collected messages to the number of validators. A failure raised as Invalid(node) with no message contributes zero messages, so when all subvalidators fail but one is message-less, the count comes up short and Any silently treats it as a pass, a false-accept in validation.

node = SchemaNode(Int(), validator=Any(fail_nomsg, fail_msg)) both raise Invalid
node.deserialize(5) # returns 5 ← expected Invalid
jsonpickle/jsonpickle

Object serialization · open source

Python ★ 1316

decode() crashes on a 6-element py/reduce payload

A 6-tuple is a valid __reduce_ex__ result (protocol 5 added a 6th state_setter element), but the unpickler only pads tuples shorter than 5 and then unpacks exactly five names, so a 6-element reduce raises an uncaught ValueError instead of being handled.

jsonpickle.decode('{"py/reduce": [null,null,null,null,null,null]}')
# ValueError: too many values to unpack (expected 5) ← uncaught

Full sweep

Every repo we've tested

38 bugs confirmed across 95 repos swept (2 fixed and merged by maintainers within 24 hours of filing, 20 reported upstream this cycle). The clean results are signal too, well-tested code passes.

Repo Result
mattrobenolt/jinja2-cli Bug filed #145
python-cmd2/cmd2 Bug filed #1649
maldoinc/wireup Bug filed #135
omni-us/jsonargparse Bug filed #904
luolingchun/flask-openapi Bug filed #262
itsDNNS/docsight Bug filed #357
deep5050/radio-active Bug filed #150
securo-finance/securo Bug filed #67
dongdongbh/Mindwtr Bug filed #380
theDakshJaitly/mex Bug filed #31
paperclipai/paperclip Bug filed #3713
rtk-ai/rtk Bug filed #1322
expectedparrot/edsl Bug filed #2446
majiidd/persiantools Bug filed #62
mwilliamson/python-mammoth Bug filed #168
hukkin/tomli No findings
frostming/marko No findings
pallets-eco/croniter No findings
akoumjian/datefinder No findings
jannikmi/timezonefinder No findings
JoshData/python-email-validator No findings
encode/httpcore No findings
un33k/python-slugify No findings
python-validators/validators No findings
Suor/funcy No findings
davidhalter/parso No findings
pyparsing/pyparsing No findings
marshmallow-code/marshmallow No findings
more-itertools/more-itertools No findings
getcompanion-ai/feynman No findings
basicmachines-co/basic-memory No findings
sgcarstrends/backend No findings
berrydev-ai/blockdoc-python No findings
stefanjudis/cchooks No findings
lamoom-ai/lamoom No findings
badlogic/claude-code-tools-python No findings
claudekit-dev/claudekit No findings
rulesync No findings
vibe-log-cli No findings
tdd-guard No findings
cc-flow No findings
claude-hub No findings
tsk No findings
claude-squad No findings
aws-mcp No findings
gweis/isodate Bug filed #104
python-humanize/humanize Bug filed #333
keleshev/schema Bug filed #352
erikrose/parsimonious Bug filed #257
regebro/tzlocal Bug filed #181
john-kurkowski/tldextract Bug filed #370
carpedm20/emoji Bug filed #330
pytoolz/toolz Bug filed #626
gruns/furl Bug filed #192
python-poetry/tomlkit Bug filed #546
mahmoud/glom Bug filed #299
seatgeek/thefuzz Bug filed #94
alecthomas/voluptuous Bug filed #541
xmltodict No findings
python-dotenv No findings
boltons No findings
python-decouple No findings
feedparser No findings
charset_normalizer No findings
pint No findings
aio-libs/yarl Bug filed #1774
prettytable/prettytable Bug filed #474
astanin/python-tabulate Bug filed #434
dgilland/pydash Bug filed #249
tobgu/pyrsistent Bug filed #326
Pylons/colander Bug filed #371
jsonpickle/jsonpickle Bug filed #608
arrow No findings
cerberus No findings
simplejson No findings
tenacity No findings
chardet No findings
configobj No findings
ccpm Skipped
coffee-analytics Skipped

Skipped = no testable source code (skills-only or SQL-only repos)

Get started

Run it on your own project.

Install in 60 seconds. No test files to write, no configuration, no commands.

Claude Code plugin
$ claude plugin marketplace add avansaber/tailtest
$ claude plugin install tailtest@avansaber-tailtest