@claudinho/cli 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +324 -267
- package/dist/index.js +779 -159
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,353 +1,410 @@
|
|
|
1
1
|
# @claudinho/cli ⚽
|
|
2
2
|
|
|
3
|
-
**Live football scores, fixtures and standings in your terminal
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
**Live football scores, fixtures and standings in your terminal, for the competition you follow: the World Cup, the Premier League, LALIGA, the Champions League and 12 more.**
|
|
4
|
+
The `claudinho` command also puts the live score in your Claude Code or Cursor CLI statusline. It
|
|
5
|
+
speaks English, Spanish, Portuguese and French, follows your timezone, and prints JSON for scripts.
|
|
6
|
+
No API key, no signup, no account.
|
|
6
7
|
|
|
7
8
|
## Install
|
|
8
9
|
|
|
10
|
+
It needs Node.js 20 or later.
|
|
11
|
+
|
|
9
12
|
```bash
|
|
10
|
-
npm i -g @claudinho/cli
|
|
11
|
-
claudinho follow
|
|
12
|
-
|
|
13
|
-
npx @claudinho/cli --competition world-cup today
|
|
13
|
+
npm i -g @claudinho/cli
|
|
14
|
+
claudinho follow champions-league # choose your competition once (every alias is in the table below)
|
|
15
|
+
claudinho today
|
|
14
16
|
```
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Or run it without installing:
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
offline: a provider double served the capture's three results on the bundled
|
|
23
|
-
fixtures' ids, at a frozen clock of 2026-06-30T12:00Z. A US zone, because the capture's
|
|
24
|
-
was west of UTC: in UTC the third tie (01:00Z on Jun 30) leaves this date. -->
|
|
25
|
-
```text
|
|
26
|
-
Matches · 2026-06-29
|
|
27
|
-
World Cup
|
|
20
|
+
```bash
|
|
21
|
+
npx @claudinho/cli follow champions-league
|
|
22
|
+
npx @claudinho/cli today --lang es --tz America/Mexico_City
|
|
23
|
+
```
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
<!-- DEMO: verbatim `claudinho --tz UTC today` with the Champions League followed, on Oct 14, 2026
|
|
26
|
+
after the day's games, colour off. Never hand-edit. -->
|
|
27
|
+
```text
|
|
28
|
+
Today's matches · 2026-10-14
|
|
29
|
+
Champions League
|
|
30
|
+
|
|
31
|
+
Feyenoord Rotterdam 3–2 Como FT the scoreboard has spoken!
|
|
32
|
+
LASK Linz 3–6 Liverpool FT You'll never walk alone!
|
|
33
|
+
AS Roma 3–4 Real Madrid FT Daje Roma!
|
|
34
|
+
Aston Villa 6–0 Fenerbahce FT UTV!
|
|
35
|
+
Bodo/Glimt 1–0 Borussia Dortmund FT Echte Liebe!
|
|
36
|
+
Manchester City 2–4 Paris Saint-Germain FT Blue Moon!
|
|
37
|
+
Real Betis 3–2 FC Porto FT ¡Viva er Betis manque pierda!
|
|
38
|
+
Shakhtar Donetsk 3–1 AEK Athens FT off to the tunnel!
|
|
39
|
+
Slovan Bratislava 0–3 VfB Stuttgart FT the referee calls time!
|
|
32
40
|
|
|
33
41
|
Live data: ESPN
|
|
34
42
|
Not affiliated with FIFA, any confederation, league or club, or Anthropic.
|
|
35
43
|
```
|
|
36
44
|
|
|
37
|
-
|
|
45
|
+
This is a capture from Oct 14, 2026. `claudinho --tz UTC today 2026-10-14` shows that day's results
|
|
46
|
+
again.
|
|
47
|
+
|
|
48
|
+
## Competitions
|
|
49
|
+
|
|
50
|
+
The 16 competitions Claudinho follows, by the alias `follow` and `--competition` take:
|
|
51
|
+
|
|
52
|
+
<!-- competitions:start -->
|
|
53
|
+
| Alias | Competition | Teams | Scores | Next | Standings | Bracket | Markets |
|
|
54
|
+
|---|---|---|---|---|---|---|---|
|
|
55
|
+
| `world-cup` | World Cup | nations | yes | yes | yes | yes | yes |
|
|
56
|
+
| `euro` | EURO | nations | yes | yes | yes | not yet | not yet |
|
|
57
|
+
| `copa-america` | Copa América | nations | yes | yes | yes | not yet | not yet |
|
|
58
|
+
| `nations-league` | UEFA Nations League | nations | yes | yes | yes | not yet | not yet |
|
|
59
|
+
| `concacaf-nations-league` | Concacaf Nations League | nations | yes | yes | yes | not yet | not yet |
|
|
60
|
+
| `gold-cup` | Gold Cup | nations | yes | yes | yes | not yet | not yet |
|
|
61
|
+
| `premier-league` | Premier League | clubs | yes | yes | yes | n/a | not yet |
|
|
62
|
+
| `laliga` | LALIGA | clubs | yes | yes | yes | n/a | not yet |
|
|
63
|
+
| `serie-a` | Serie A | clubs | yes | yes | yes | not yet | not yet |
|
|
64
|
+
| `bundesliga` | Bundesliga | clubs | yes | yes | yes | not yet | not yet |
|
|
65
|
+
| `liga-mx` | Liga MX | clubs | yes | yes | yes | not yet | not yet |
|
|
66
|
+
| `liga-auf` | Liga AUF Uruguaya | clubs | yes | yes | yes | not yet | not yet |
|
|
67
|
+
| `champions-league` | Champions League | clubs | yes | yes | yes | not yet | not yet |
|
|
68
|
+
| `libertadores` | Libertadores | clubs | yes | yes | yes | not yet | not yet |
|
|
69
|
+
| `concacaf-champions-cup` | Concacaf Champions Cup | clubs | yes | yes | n/a | not yet | not yet |
|
|
70
|
+
| `club-world-cup` | Club World Cup | clubs | yes | yes | yes | not yet | not yet |
|
|
71
|
+
|
|
72
|
+
`yes` offered · `not yet` not offered yet · `n/a` the competition has no such thing (a league season with no knockout tie has no bracket; a knockout-only cup has no table).
|
|
73
|
+
<!-- competitions:end -->
|
|
38
74
|
|
|
39
75
|
## Commands
|
|
40
76
|
|
|
41
77
|
```bash
|
|
42
|
-
claudinho follow [ALIAS] # choose the competition
|
|
78
|
+
claudinho follow [ALIAS] # choose the competition you follow (saved); --team <name> pins your team; --list; off
|
|
43
79
|
claudinho today [date] # a day's fixtures in your timezone (default: today), live scores inline
|
|
44
80
|
claudinho live # matches in play right now
|
|
45
|
-
claudinho next [TEAM] # a team's next
|
|
46
|
-
claudinho table [KEY] #
|
|
47
|
-
claudinho
|
|
48
|
-
claudinho
|
|
49
|
-
claudinho
|
|
50
|
-
claudinho markets [target] # prediction-market
|
|
51
|
-
|
|
52
|
-
claudinho
|
|
53
|
-
claudinho
|
|
54
|
-
claudinho init cursor #
|
|
55
|
-
claudinho init
|
|
56
|
-
claudinho init
|
|
57
|
-
claudinho init-
|
|
58
|
-
claudinho init-cursor-statusline #
|
|
59
|
-
claudinho hook # live-score
|
|
60
|
-
claudinho ambient --json # the statusline and the hook as one JSON object, for a program
|
|
61
|
-
claudinho
|
|
62
|
-
claudinho
|
|
63
|
-
claudinho star # how to support the project (star the repo ⭐)
|
|
81
|
+
claudinho next [TEAM] # a team's next match and a countdown; TEAM is a name or a code (Arsenal, ARS, Mexico, MEX); default: CLAUDINHO_TEAM, else your pin
|
|
82
|
+
claudinho table [KEY] # standings (default: every table); KEY is a group letter, or A1, A-B, LEAGUE
|
|
83
|
+
claudinho match <id> # one match, with its goals and cards
|
|
84
|
+
claudinho bracket [STAGE] # the knockout bracket, World Cup only (R32, R16, QF, SF, 3P, F); --tree for an ASCII tree
|
|
85
|
+
claudinho share [target] # a plain-text card to paste: today | live | <date> | <id> | next [TEAM] | table [KEY] | bracket [STAGE]
|
|
86
|
+
claudinho markets [target] # World Cup prediction-market odds: today | <date> | <id> | next [TEAM]
|
|
87
|
+
claudinho team <query> # a World Cup nation's name or code to its FIFA code, flag and group (team "DR Congo")
|
|
88
|
+
claudinho prompt # one compact status line (for a statusline, tmux or Starship)
|
|
89
|
+
claudinho init claude # Claude Code: statusline + score-aware hook, then the MCP line to run
|
|
90
|
+
claudinho init cursor # Cursor CLI: statusline, then the MCP config to paste (--print for the snippets)
|
|
91
|
+
claudinho init plugin # remove the Claudinho statusline and hook from Claude Code (for the Claude Code plugin)
|
|
92
|
+
claudinho init-statusline # just the Claude Code statusline
|
|
93
|
+
claudinho init-hook # just the Claude Code score-aware hook
|
|
94
|
+
claudinho init-cursor-statusline # just the Cursor CLI statusline
|
|
95
|
+
claudinho hook # the live-score block for a Claude Code hook (silent off-match)
|
|
96
|
+
claudinho ambient --json # the statusline and the hook as one JSON object, for a program
|
|
97
|
+
claudinho vibe # a matchday-coder one-liner
|
|
98
|
+
claudinho star # how to support the project
|
|
64
99
|
```
|
|
65
100
|
|
|
66
|
-
In a club competition, `next` resolves a club's name or code against the
|
|
67
|
-
competition's own table and answers its next match within 14 days (several teams
|
|
68
|
-
matching a name are listed, never guessed); `match <id>` looks from yesterday to
|
|
69
|
-
14 days ahead and names the days it searched when the match is not there;
|
|
70
|
-
`bracket` says when a league season has no bracket; and `today`, `live`, `next`
|
|
71
|
-
and `match` say "between editions" once a competition's edition has ended and
|
|
72
|
-
the next has not started. A club shows by its name (or its code on the
|
|
73
|
-
statusline: `ARS 2–1 CHE 50'`), with nothing where a nation's flag would be, and
|
|
74
|
-
`next`/`match` say the stage it is in ("League", "Play-offs", or the provider's
|
|
75
|
-
words for a phase Claudinho does not know).
|
|
76
|
-
|
|
77
|
-
`claudinho follow <alias>` saves the competition every surface follows;
|
|
78
|
-
`--team <name>` pins a team in it, resolved as `next <name>` resolves it. Pin a
|
|
79
|
-
team while its competition has fixtures ahead: between editions `next` answers
|
|
80
|
-
the verdict before it resolves a club, so there is nothing to pin (a `follow
|
|
81
|
-
<alias>` without `--team` still works there). A pin is scoped to its
|
|
82
|
-
competition, whatever chose it (`--competition`, `CLAUDINHO_COMPETITION`, or the
|
|
83
|
-
saved choice), and never applies to another. `follow --json` says the same facts as
|
|
84
|
-
its text: `competition` (`follow` alone: this command's; after a write or `off`: what
|
|
85
|
-
the next command follows), `override` (its source when it is not the saved choice),
|
|
86
|
-
`sources` (the flag, the environment and `CLAUDINHO_TEAM` this command ran under),
|
|
87
|
-
`refused` (each refused value under its source's name, `flag`, `env` or `team`; a
|
|
88
|
-
`CLAUDINHO_TEAM` with nothing readable is `"team": ""`, which the team-taking
|
|
89
|
-
commands refuse), `saved` (the file as read) and `path`.
|
|
90
|
-
|
|
91
101
|
### Examples
|
|
92
102
|
|
|
93
103
|
```bash
|
|
104
|
+
claudinho follow premier-league --team Arsenal # follow a league and pin a team
|
|
105
|
+
claudinho next # Arsenal's next match, with a countdown
|
|
94
106
|
claudinho today --tz America/Mexico_City --lang es
|
|
95
|
-
claudinho
|
|
96
|
-
claudinho table A
|
|
97
|
-
claudinho bracket R32 --tree
|
|
107
|
+
claudinho --competition liga-mx table # another competition, for one command
|
|
98
108
|
claudinho live --json | jq '.matches[].status'
|
|
99
|
-
claudinho
|
|
100
|
-
claudinho share next MEX --copy # a shareable card, copied to your clipboard
|
|
101
|
-
claudinho follow premier-league --team Arsenal # follow a competition, pin a team: `claudinho next` answers for it
|
|
102
|
-
claudinho --competition laliga today # another competition for one command, by its alias
|
|
103
|
-
CLAUDINHO_COMPETITION=laliga claudinho table # the environment works too (the statusline and hook follow it)
|
|
109
|
+
claudinho share next --copy # a card for the group chat, on your clipboard
|
|
104
110
|
```
|
|
105
111
|
|
|
106
|
-
|
|
112
|
+
### In a club competition
|
|
113
|
+
|
|
114
|
+
`next` finds a club by its name or code among the competition's clubs (its table, and its fixtures
|
|
115
|
+
from yesterday to 14 days ahead) and answers its next match within 14 days. When several clubs match a name it
|
|
116
|
+
lists them and does not guess. `match <id>` looks from yesterday to 14 days ahead. When the match is not there it names the days it
|
|
117
|
+
searched, or, when the provider's answer was not whole, says no match with that id was read; when
|
|
118
|
+
the provider cannot be reached, it says so. Between two seasons, `today`, `live`, `next` and
|
|
119
|
+
`match` say "Between editions". `bracket` says "This competition has no bracket." on the Premier
|
|
120
|
+
League and LALIGA, and "Not available for this competition yet." on every other competition but the
|
|
121
|
+
World Cup. A club shows by its name (by its code
|
|
122
|
+
on the statusline: `ARS 2–1 CHE 50'`), with no flag, and `next` and `match` say the stage:
|
|
123
|
+
"League", "Play-offs", or the provider's own words for a round Claudinho does not know.
|
|
124
|
+
|
|
125
|
+
### One match
|
|
126
|
+
|
|
127
|
+
`match <id>` lists the goals and cards the provider sent for a match in play or finished, one row
|
|
128
|
+
each: the minute (`90+3'` with added time), the kind (goal, own goal, penalty, yellow or red card),
|
|
129
|
+
the side and the player when named, a marker before the kind (`⚽` for a goal, an own goal or a penalty, `🟨` for a
|
|
130
|
+
yellow card, `🟥` for a red card): `22' ⚽ Goal LIV Ronald Araújo`. An own goal sits under the side it counted for.
|
|
131
|
+
The list is what could be read, not a promise that it holds every goal. The answer opens with the score in bold, your
|
|
132
|
+
pinned team's name in colour, and a status row (`FT · Kickoff Wed 16:45`). With `--json` it adds `lines` (the rows
|
|
133
|
+
the text prints), `rows` (the same rows as styled parts with their roles, for a program that draws them),
|
|
134
|
+
`attribution` and `disclaimer`.
|
|
135
|
+
|
|
136
|
+
### When the data is not whole
|
|
137
|
+
|
|
138
|
+
When the provider sends a record Claudinho cannot read, `today`, `live`, `next`, `match`, `bracket`,
|
|
139
|
+
`markets` and their share cards say their data may be incomplete. `today` and `live` say it after
|
|
140
|
+
their list; the others, and every share card, before what they show. With
|
|
141
|
+
`--json` they carry `partial` (with `omitted`, the count of records left out, when it is known). An
|
|
142
|
+
empty answer then means nothing was read, not that nothing exists: no next match does not mean a
|
|
143
|
+
team is out.
|
|
144
|
+
|
|
145
|
+
## Choosing a competition
|
|
146
|
+
|
|
147
|
+
Nothing is followed until you choose. Three sources can choose, and the first one present wins:
|
|
148
|
+
|
|
149
|
+
1. `--competition <alias>` (or `-c`), for one command;
|
|
150
|
+
2. `CLAUDINHO_COMPETITION`, while it is set (the statusline, the hook and `ambient --json` follow it too);
|
|
151
|
+
3. the choice `claudinho follow <alias>` saved.
|
|
152
|
+
|
|
153
|
+
Each takes an alias from the table, or an ESPN slug such as `eng.1`. Any other lower-case dotted
|
|
154
|
+
ESPN slug works too, labelled experimental. An unknown value is refused with the list. With none of
|
|
155
|
+
the three, a command that answers for a competition says so and exits 1 (`--json` prints
|
|
156
|
+
`{ "competition": null, "noCompetition": true }`), the statusline reads `⚽ claudinho follow`, and
|
|
157
|
+
the hook stays silent.
|
|
158
|
+
|
|
159
|
+
`today`, `live`, `next`, `match`, `table`, `bracket` and `markets` name their competition near the
|
|
160
|
+
top (`Premier League · from the command line`), and in `--json` as `competition`. A share card names
|
|
161
|
+
it in its title, and `share --json` carries `competition` too. `team` reads the World Cup's nations
|
|
162
|
+
and carries no `competition`; it is refused when `--competition` or `CLAUDINHO_COMPETITION` chooses
|
|
163
|
+
another competition.
|
|
164
|
+
|
|
165
|
+
**Your team.** `claudinho follow <alias> --team <name>` pins a team in that competition. When you
|
|
166
|
+
name no team and `CLAUDINHO_TEAM` is not set, it is the team `next`, `share next` and `markets next`
|
|
167
|
+
answer for, and its match comes first on the statusline and in the hook. A pin belongs to its
|
|
168
|
+
competition and never applies to another, whatever chose the competition. Between two seasons
|
|
169
|
+
("between editions") `follow --team` saves nothing: pin your team once the next season has started.
|
|
170
|
+
A club with no match in the next 14 days can still be pinned.
|
|
171
|
+
|
|
172
|
+
**`CLAUDINHO_TEAM`** replaces the pin while it is set. `next`, `share next` and `markets next` take it
|
|
173
|
+
as a name or a code. The statusline and the hook take a code (`ARS`); on the World Cup a nation's
|
|
174
|
+
name works too (`mexico`). Off the World Cup a club's name there puts no team first, and the pin is
|
|
175
|
+
not used either.
|
|
176
|
+
|
|
177
|
+
**`claudinho follow`** shows the choice and where it came from; `claudinho follow off` forgets it
|
|
178
|
+
(it deletes `config.json`). `follow --json` prints the same facts as its text:
|
|
179
|
+
|
|
180
|
+
- `competition`: with `follow` alone, what this command follows (`--competition`, else
|
|
181
|
+
`CLAUDINHO_COMPETITION`, else the saved choice). After a write or `off`, what the next command
|
|
182
|
+
follows: while `CLAUDINHO_COMPETITION` is set, that is the environment's choice, not the one just
|
|
183
|
+
saved. With nothing chosen it is `null`, beside `noCompetition: true`; when the value that decides
|
|
184
|
+
it is refused, it is `null`, beside `refused` (a refused value that does not decide it is only in
|
|
185
|
+
`refused`).
|
|
186
|
+
- `override`: `flag` or `env` when that competition does not come from the saved choice.
|
|
187
|
+
- `sources`: the `--competition`, `CLAUDINHO_COMPETITION` and `CLAUDINHO_TEAM` values this command
|
|
188
|
+
ran under, each competition as its resolved slug (`laliga` is `esp.1`).
|
|
189
|
+
- `refused`: each refused value under `flag`, `env` or `team` (a `CLAUDINHO_TEAM` with nothing
|
|
190
|
+
readable is `"team": ""`).
|
|
191
|
+
- `saved`: the file as read, or as written; `null` when there is none, with `reason` saying why.
|
|
192
|
+
- `path`: the file's path; after `off`, `removed` says whether there was a file.
|
|
193
|
+
|
|
194
|
+
### Where it is saved
|
|
195
|
+
|
|
196
|
+
Your choice is `config.json` in `$XDG_CONFIG_HOME/claudinho/` when `XDG_CONFIG_HOME` is an absolute
|
|
197
|
+
path, else in `%APPDATA%\claudinho\` on Windows, else in `~/.config/claudinho/`. The cache follows the
|
|
198
|
+
same rule: `$XDG_CACHE_HOME/claudinho/`, else `%LOCALAPPDATA%\claudinho\` on Windows, else
|
|
199
|
+
`~/.cache/claudinho/`. A relative `XDG_*` value is ignored. `claudinho follow off` deletes the
|
|
200
|
+
choice; delete the cache folder yourself after `npm rm -g @claudinho/cli`.
|
|
201
|
+
|
|
202
|
+
### Other settings
|
|
203
|
+
|
|
204
|
+
`CLAUDINHO_NO_STAR=1` turns off the occasional "star the repo" line under the interactive commands. `CLAUDINHO_DEBUG=1` prints the data provider's failures to stderr.
|
|
205
|
+
|
|
206
|
+
## Options
|
|
107
207
|
|
|
108
208
|
| Flag | Description |
|
|
109
209
|
|---|---|
|
|
110
|
-
| `--lang <code>` | `en`, `es`, `pt`, `fr` (also
|
|
111
|
-
| `--tz <zone>` | IANA timezone,
|
|
112
|
-
| `--json` | machine-readable output for
|
|
113
|
-
| `--no-color` |
|
|
114
|
-
| `-c, --competition <alias\|slug>` | the competition
|
|
115
|
-
| `--
|
|
116
|
-
| `--
|
|
117
|
-
| `--
|
|
118
|
-
|
|
119
|
-
Team codes: a nation's is FIFA
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
with a cry takes no line from the bank, so the others in the list stay
|
|
135
|
-
different; a postponed or cancelled match prints neither.
|
|
136
|
-
|
|
137
|
-
- `--flavor full` *(default)*: flair on fixtures, live play, goals, the break, the closing minutes, and full time
|
|
138
|
-
- `--flavor subtle`: only goals, full time and draws, and the rally cries
|
|
210
|
+
| `--lang <code>` | `en`, `es`, `pt`, `fr` (also `CLAUDINHO_LANG`; falls back to `$LANG`) |
|
|
211
|
+
| `--tz <zone>` | an IANA timezone, such as `America/Mexico_City` (also `CLAUDINHO_TZ`; default: your system's). Kickoff times **and** the day a match falls on use this zone. |
|
|
212
|
+
| `--json` | machine-readable output for scripts |
|
|
213
|
+
| `--no-color` | no ANSI color (also `NO_COLOR`; off automatically when piped) |
|
|
214
|
+
| `-c, --competition <alias\|slug>` | the competition for this command (see [Choosing a competition](#choosing-a-competition)) |
|
|
215
|
+
| `--flavor <level>` | commentary: `full` (default), `subtle` or `off` (also `CLAUDINHO_FLAVOR`) |
|
|
216
|
+
| `--no-markets` | hide World Cup market odds in `today`, `match` and share cards (also `CLAUDINHO_MARKETS=off`) |
|
|
217
|
+
| `--source <name>` | the live data provider (advanced) |
|
|
218
|
+
|
|
219
|
+
Team codes: a nation's is FIFA's 3 letters (`MEX`, `BRA`, `ENG`); a club's is the provider's
|
|
220
|
+
abbreviation (`ARS`, `LEE`). A club is also found by its name (`next Arsenal`).
|
|
221
|
+
|
|
222
|
+
### Commentary
|
|
223
|
+
|
|
224
|
+
By default a match line ends with a short line of commentary in your language: `¡GOOOOL!` on a
|
|
225
|
+
goal, `¡a cancha llena!` before kickoff, something for the break and the last ten minutes. The bank
|
|
226
|
+
holds a few hundred lines in four languages, and a day's list does not repeat one while the bank has
|
|
227
|
+
another. When a side has a rally cry of its own, the cry takes the slot (Mexico's `¿Y si sí?`, Pumas'
|
|
228
|
+
`¡Goya!`, Arsenal's `COYG!`; your pinned team's when both sides have one). A postponed or cancelled
|
|
229
|
+
match gets neither. The commentary reaches `--json` only in `match --json`'s `lines` and `rows`,
|
|
230
|
+
which are the text's own rows.
|
|
231
|
+
|
|
232
|
+
- `--flavor full` *(default)*: before kickoff, in play, goals, the break, the closing minutes and full time
|
|
233
|
+
- `--flavor subtle`: goals, full time, draws and the rally cries only
|
|
139
234
|
- `--flavor off`: just the facts
|
|
140
235
|
|
|
141
|
-
##
|
|
236
|
+
## Shareable cards
|
|
142
237
|
|
|
143
|
-
`claudinho
|
|
144
|
-
market-implied percentages) for a date, a match, or a team's next fixture:
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
claudinho markets # today's signals
|
|
148
|
-
claudinho markets 2026-06-11 # a specific date
|
|
149
|
-
claudinho markets 760415 # one match by id
|
|
150
|
-
claudinho markets next MEX # a team's current-or-next fixture (in-play preferred)
|
|
151
|
-
claudinho markets today --json # structured sidecar output
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
A short market line is also added under `claudinho today` and `claudinho match`
|
|
155
|
-
when a reliable market is available. It's **informational only, not betting
|
|
156
|
-
advice:** market-implied percentages with attribution, no trading, no links. Data
|
|
157
|
-
comes from Polymarket public market data and is shown
|
|
158
|
-
only when the market maps cleanly to the result and is fresh.
|
|
159
|
-
Structured output uses `complete` on `markets` and `marketComplete` on the
|
|
160
|
-
default-on `today`/`match` enrichment. `false` means the optional read did not
|
|
161
|
-
finish and is paired with an explicit warning, not a confident empty result.
|
|
162
|
-
|
|
163
|
-
Opt out with `--no-markets` (per command) or `CLAUDINHO_MARKETS=off` (global). The
|
|
164
|
-
statusline and hook **never** show market data: it stays off the hot path.
|
|
165
|
-
|
|
166
|
-
> **How matches are matched:** event slugs are derived automatically from each
|
|
167
|
-
> fixture (`fifwc-{home}-{away}-{date}`), so real signals appear for any match with a
|
|
168
|
-
> live Polymarket market, with no mapping needed (`mapping.2026.json` is for slug
|
|
169
|
-
> *overrides* only). Matching fails closed, so an unmatched fixture simply shows
|
|
170
|
-
> nothing, and finished matches never show one (market signals are pre-match
|
|
171
|
-
> and in-play reads). For an offline preview, set `CLAUDINHO_MARKETS_SOURCE=fake`
|
|
172
|
-
> to render clearly-labeled synthetic **"demo data"** signals.
|
|
173
|
-
|
|
174
|
-
## Shareable snippets
|
|
175
|
-
|
|
176
|
-
`claudinho share` prints a polished, **copy-pasteable** match card for chats,
|
|
177
|
-
social posts, READMEs, and issue comments: your terminal football, ready to post:
|
|
238
|
+
`claudinho share` prints a plain-text card you can paste into a chat, a post or an issue:
|
|
178
239
|
|
|
179
240
|
```bash
|
|
180
241
|
claudinho share # today's matches
|
|
181
|
-
claudinho share live # matches in play
|
|
182
|
-
claudinho share next
|
|
183
|
-
claudinho share table
|
|
184
|
-
claudinho share
|
|
185
|
-
claudinho share bracket R16 # one round
|
|
186
|
-
claudinho share
|
|
187
|
-
claudinho share next MEX --copy # …and copy it straight to the clipboard
|
|
242
|
+
claudinho share live # the matches in play
|
|
243
|
+
claudinho share next # your team's next match (or next <TEAM>)
|
|
244
|
+
claudinho share table # the standings (or table <KEY> for one table)
|
|
245
|
+
claudinho share 401915407 # one match by id
|
|
246
|
+
claudinho share bracket R16 # the World Cup bracket, or one round (R32, R16, QF, SF, 3P, F)
|
|
247
|
+
claudinho share next --copy # also copy it to the clipboard
|
|
188
248
|
```
|
|
189
249
|
|
|
190
|
-
<!-- DEMO CARD: verbatim
|
|
191
|
-
|
|
192
|
-
drifts. Never hand-edit. Re-rendered on 2026-10-05 (0.11) through the CLI's own
|
|
193
|
-
`share next MEX` command, offline: a provider double served the Round of 32 tie the
|
|
194
|
-
capture showed (Mexico vs Ecuador, on the bundled fixture's id, kickoff and venue),
|
|
195
|
-
at a frozen clock of 2026-06-28T12:00Z. -->
|
|
250
|
+
<!-- DEMO CARD: verbatim `claudinho --tz UTC share 401915407` (a Champions League match from Oct 14,
|
|
251
|
+
2026), with the Champions League followed. Never hand-edit. -->
|
|
196
252
|
```text
|
|
197
|
-
|
|
253
|
+
Match pulse · Champions League
|
|
198
254
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
Round of 32
|
|
255
|
+
Manchester City 2–4 Paris Saint-Germain · FT
|
|
256
|
+
Etihad Stadium, Manchester, England
|
|
257
|
+
League phase
|
|
203
258
|
|
|
204
259
|
Live data: ESPN
|
|
205
260
|
#VibingLaVidaLoca · Independent fan project · Not affiliated with FIFA, any confederation, league or club, or Anthropic.
|
|
206
|
-
Try it: npx @claudinho/cli --competition
|
|
261
|
+
Try it: npx @claudinho/cli --competition champions-league match 401915407
|
|
207
262
|
```
|
|
208
263
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
264
|
+
This card is a capture from Oct 14, 2026. Off the World Cup, `share <id>` finds a match from
|
|
265
|
+
yesterday to 14 days ahead, so run it with a current id (`claudinho today --json` lists each
|
|
266
|
+
match's `id`).
|
|
267
|
+
|
|
268
|
+
A card has no color codes, so it pastes cleanly anywhere, and always carries the non-affiliation
|
|
269
|
+
sentence. `--copy` uses `pbcopy` on macOS, `clip` on Windows, and elsewhere the first of `wl-copy`,
|
|
270
|
+
`xclip` and `xsel` that works. When none works, the card is still printed: copy it from the terminal.
|
|
213
271
|
|
|
214
272
|
| Flag | Description |
|
|
215
273
|
|---|---|
|
|
216
|
-
| `--style <social\|compact>` | `social` (default) is the full card; `compact` is one
|
|
217
|
-
| `--copy` | also copy the
|
|
218
|
-
| `--no-hashtag` |
|
|
219
|
-
| `--no-install-line` |
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
`
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
## Statusline
|
|
274
|
+
| `--style <social\|compact>` | `social` (default) is the full card; `compact` is one line per match |
|
|
275
|
+
| `--copy` | also copy the card to the clipboard |
|
|
276
|
+
| `--no-hashtag` | leave out the `#VibingLaVidaLoca` tag |
|
|
277
|
+
| `--no-install-line` | leave out the `Try it: …` line |
|
|
278
|
+
|
|
279
|
+
`share … --json` prints the card (`kind`, `snippet`) with its facts. A card for a day, live
|
|
280
|
+
matches, a match or a team's next match adds `matches`, `marketSignals` and `marketComplete`; a
|
|
281
|
+
table card adds `tables`, and a bracket card the bracket's `view`. When the market read did not
|
|
282
|
+
finish, the card says so and `--json` carries `marketComplete: false`: that is not "no market".
|
|
283
|
+
|
|
284
|
+
Want an image? A screenshot of the card works, or a tool such as
|
|
285
|
+
`freeze --execute "claudinho share next" -o card.png` (charmbracelet/freeze).
|
|
286
|
+
|
|
287
|
+
## Prediction-market odds (World Cup)
|
|
288
|
+
|
|
289
|
+
For World Cup matches, `claudinho markets` shows a "who's favored" line: the percentages Polymarket's
|
|
290
|
+
public market data implies, for a date, a match, or a team's current match (one whose kickoff time
|
|
291
|
+
passed less than about three and a half hours ago and that the feed has not marked finished) or,
|
|
292
|
+
with none, its next. A short version appears under `today`,
|
|
293
|
+
`match` and on the share cards for a date, a match or a team's next match, when a reliable market
|
|
294
|
+
exists. **Informational only, not betting
|
|
295
|
+
advice:** no trading, no links. A match with no clean market, and a finished match, shows nothing.
|
|
296
|
+
With `--json`, `markets` carries `complete`, and `today` and `match` carry `marketComplete`. `false`
|
|
297
|
+
means the optional market read did not finish, and the text says so: it is not "no market".
|
|
298
|
+
Turn the short version off with `--no-markets` or `CLAUDINHO_MARKETS=off`; `claudinho markets`
|
|
299
|
+
still answers. The statusline and the hook never show market data.
|
|
300
|
+
|
|
301
|
+
## Statusline: Claude Code
|
|
244
302
|
|
|
245
303
|
```bash
|
|
246
|
-
claudinho init-statusline #
|
|
304
|
+
claudinho init-statusline # edits ~/.claude/settings.json (backed up first)
|
|
247
305
|
claudinho init-statusline --print # just print the snippet
|
|
248
306
|
```
|
|
249
307
|
|
|
250
|
-
The statusline reads
|
|
251
|
-
|
|
252
|
-
`⚽
|
|
308
|
+
The statusline reads a local cache and never waits on the network. A background process refreshes
|
|
309
|
+
the cache. When several matches are live it shows up to eight side by side, and counts the rest
|
|
310
|
+
(`+N`): `⚽ ARS 2–1 CHE 67' · LIV 0–0 MNC 12'`. When your team is in play it shows that match
|
|
311
|
+
alone and counts the others.
|
|
312
|
+
With nothing in play it counts down to the next match: `⚽ ARS vs LEE in 2d4h`. From kickoff until the data provider
|
|
313
|
+
marks the match live, for up to 30 minutes, it reads `⚽ BET vs BAR now` instead of moving on to the next fixture.
|
|
314
|
+
The statusline is English in every language.
|
|
253
315
|
|
|
254
|
-
- `CLAUDINHO_TEAM=
|
|
255
|
-
- `CLAUDINHO_MAX=2`:
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
- `CLAUDINHO_COMPACT=0`: show 3-letter codes alongside flags
|
|
259
|
-
- `CLAUDINHO_FLAGS=off`: drop emoji flags for 3-letter codes (statusline) / plain names (`today`, `live`, `table`, `next`, hook); already automatic on terminals that can't render flag emoji, e.g. Warp
|
|
316
|
+
- `CLAUDINHO_TEAM=ARS`: that team's match first, the others counted (`+N`). Give a code; on the World Cup a nation's name works too. A pinned team does the same when this is not set.
|
|
317
|
+
- `CLAUDINHO_MAX=2`: show at most this many live matches when your team is not in play (default and maximum: 8); the rest are counted.
|
|
318
|
+
- `CLAUDINHO_COMPACT=0`: show 3-letter codes beside the flags.
|
|
319
|
+
- `CLAUDINHO_FLAGS=off`: no flag emoji: 3-letter codes on the statusline and in `bracket`, plain names in `today`, `live`, `next`, `match`, `table`, `team` and the hook (automatic in Warp, which cannot draw them). Share cards keep their flags. `CLAUDINHO_FLAGS=on` keeps the flags.
|
|
260
320
|
|
|
261
|
-
|
|
321
|
+
The same `claudinho prompt` works in tmux (`set -g status-right '#(claudinho prompt)'`) and as a
|
|
322
|
+
Starship custom command.
|
|
262
323
|
|
|
263
|
-
|
|
264
|
-
|
|
324
|
+
Running a local build (a checkout, no global `claudinho`)? `init-statusline`, `init-hook` and
|
|
325
|
+
`init-cursor-statusline` take `--command`. From the checkout's root, after a build:
|
|
326
|
+
`node packages/cli/dist/index.js init-cursor-statusline --command "node \"$PWD/packages/cli/dist/index.js\" prompt"`.
|
|
265
327
|
|
|
266
|
-
### Score-aware Claude
|
|
328
|
+
### Score-aware Claude: the hook
|
|
267
329
|
|
|
268
330
|
```bash
|
|
269
|
-
claudinho init-hook #
|
|
331
|
+
claudinho init-hook # edits ~/.claude/settings.json (backed up first)
|
|
270
332
|
```
|
|
271
333
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
334
|
+
The hook runs on every prompt you send in Claude Code. During a match it adds the live score to
|
|
335
|
+
what Claude reads, so Claude can mention it. Off-match it adds nothing. Restart Claude Code to
|
|
336
|
+
activate it.
|
|
275
337
|
|
|
276
|
-
**Moving to the Claude Code plugin?**
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
338
|
+
**Moving to the Claude Code plugin?** The plugin draws the score above the prompt and adds the
|
|
339
|
+
score to your prompts itself. Run `claudinho init plugin` first: it removes the statusline whose
|
|
340
|
+
command is `claudinho prompt` and the hook whose command is `claudinho hook` (the commands
|
|
341
|
+
`init claude`, `init-statusline` and `init-hook` write by default), and keeps every other setting.
|
|
342
|
+
Any other command stays (a wrapper, an `npx` form, a `--command` one); `init plugin` names it when
|
|
343
|
+
it mentions `claudinho`. Then see the
|
|
344
|
+
[plugin's README](https://github.com/arturogarrido/claudinho/tree/main/packages/plugin#readme).
|
|
282
345
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
`claudinho ambient --json [--columns N]` prints the statusline and the hook as one JSON object on
|
|
286
|
-
one line, for a program that draws them itself: `line` (what `claudinho prompt` prints, fitted to N
|
|
287
|
-
columns with the `+N` count kept; N a positive integer), `context` (the hook's block, or `null`),
|
|
288
|
-
`live` (the live matches, each marked `picked` and `pinned`), `current` (an empty list means nothing
|
|
289
|
-
is on only when this is true), `next`, `pick`, `competition`, `degraded`, `source`, `updatedAt`,
|
|
290
|
-
`staleAfter` and `disclaimer` (the non-affiliation sentence). Beside `line` the view says what the line is, `idle` (the edition-complete line, however narrow it was fitted) and `empty` (nothing known), read before the fit so a program never reads a pace or a visibility off the text; and each live record carries `line`, the hook's own line for it with its flags and roster names, which a program says and never composes. It reads only the local cache, never
|
|
291
|
-
the network; the command itself exits 0 whatever the cache holds, and any other `--columns` value is
|
|
292
|
-
refused by the option parser, as a wrong option is for every command.
|
|
346
|
+
## Statusline: Cursor CLI
|
|
293
347
|
|
|
294
|
-
|
|
348
|
+
Cursor CLI is Cursor's agent in the terminal.
|
|
295
349
|
|
|
296
350
|
```bash
|
|
297
|
-
claudinho init-cursor-statusline #
|
|
351
|
+
claudinho init-cursor-statusline # edits ~/.cursor/cli-config.json (backed up first)
|
|
298
352
|
claudinho init-cursor-statusline --print # just print the snippet
|
|
299
353
|
```
|
|
300
354
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
`timeoutMs: 1500`).
|
|
355
|
+
It runs the same `claudinho prompt`, so the settings above apply. `export CLAUDINHO_CURSOR_META=auto`
|
|
356
|
+
adds a second line with the model, the context in use, the worktree and the vim mode. Cursor's
|
|
357
|
+
prompt hook cannot pass the score to the model yet, so the score-aware hook is Claude Code only.
|
|
305
358
|
|
|
306
|
-
|
|
359
|
+
## For a program: `claudinho ambient --json`
|
|
307
360
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
361
|
+
`claudinho ambient --json [--columns N]` prints the statusline and the hook as one JSON object on
|
|
362
|
+
one line, for a program that draws them itself (the Claude Code plugin does). It reads the local
|
|
363
|
+
cache, never the network (it may start the background refresh, as the statusline does), and exits 0
|
|
364
|
+
whatever the cache holds.
|
|
311
365
|
|
|
312
|
-
|
|
366
|
+
| Field | What it holds |
|
|
367
|
+
|---|---|
|
|
368
|
+
| `line` | the line `claudinho prompt` prints, but in the CLI's language (`--lang`; `prompt` itself stays English), fitted to `--columns N` with its `+N` count kept. Its `+more`, the World Cup's sign-off and `⚽ —` stay English, and the countdown's units (`2d4h`, `17m`) are the same in every language |
|
|
369
|
+
| `lineParts` | the same line in parts, each shown score marked `strong`; their texts joined equal `line` |
|
|
370
|
+
| `idle` | `true` on the end-of-edition line, however narrow the fit |
|
|
371
|
+
| `empty` | `true` when nothing is known |
|
|
372
|
+
| `context` | the hook's block, or `null` |
|
|
373
|
+
| `live` | the live matches, each with `picked`, `pinned`, `pinnedSide` (`home`, `away` or `null`: your saved team's side, never `CLAUDINHO_TEAM`'s), `names` (the two names the hook's line uses), `lastGoal` (the last goal, only when the provider's goals add up to the score, none listed twice, the credited side having scored; else `null`) and `line` (the hook's own line for it) |
|
|
374
|
+
| `finished` | the matches the refresher saw in play and then read at full time, each for 10 minutes from that read, while the snapshot's last live read was whole; each with `pinnedSide`, `names` and a `line` ending `(FT)` |
|
|
375
|
+
| `current` | whether `live` is a current, whole read: an empty list means nothing is on only when this is `true` |
|
|
376
|
+
| `next` | the fixture the countdown names (a kickoff that passed less than 30 minutes ago, still listed as scheduled, included) |
|
|
377
|
+
| `pick`, `competition` | the team preferred and the competition followed |
|
|
378
|
+
| `lang`, `words` | the CLI's resolved language, and the words of the plugin's goal and full-time moments in it |
|
|
379
|
+
| `degraded`, `source`, `updatedAt`, `staleAfter` | where the data came from, when, and when its live scores stop being shown |
|
|
380
|
+
| `disclaimer`, `attribution` | the non-affiliation sentence, and the provider's (`Live data: ESPN`; `null` with no snapshot, on the end-of-edition line and when nothing is known) |
|
|
381
|
+
|
|
382
|
+
Read `idle` and `empty`, never the text of `line`, to decide what the line is. With nothing chosen
|
|
383
|
+
it prints `{ "competition": null, "noCompetition": true }` and the first-run line.
|
|
313
384
|
|
|
314
|
-
|
|
315
|
-
claudinho init-cursor-statusline --command "node ./packages/cli/dist/index.js prompt"
|
|
316
|
-
```
|
|
385
|
+
## How it works
|
|
317
386
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
387
|
+
The World Cup's schedule (104 matches, with venues and kickoffs) ships with the package, so it works
|
|
388
|
+
offline. Every other competition's schedule, and every live score, comes from ESPN's public
|
|
389
|
+
scoreboard (an answer from it says `Live data: ESPN`). World Cup market odds come from
|
|
390
|
+
Polymarket's public data. Rate limits are respected, and the CLI backs off when a provider asks it
|
|
391
|
+
to.
|
|
321
392
|
|
|
322
|
-
##
|
|
393
|
+
## Privacy
|
|
323
394
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
## Privacy Policy
|
|
332
|
-
|
|
333
|
-
No personal data collected: no accounts, no telemetry, no analytics, no tracking, and no
|
|
334
|
-
Claudinho server. To show live results, the CLI makes read-only requests to public services
|
|
335
|
-
(ESPN; Polymarket for informational-only market signals) with no account or personal data
|
|
336
|
-
attached, though those services still receive standard request metadata (such as your IP
|
|
337
|
-
address) like any HTTP call. It keeps a small cache of public match data in your local cache
|
|
338
|
-
directory (`~/.cache/claudinho`, or `$XDG_CACHE_HOME/claudinho`), and the optional `init`
|
|
339
|
-
commands update your Claude Code / Cursor settings file after saving a one-time
|
|
340
|
-
`.claudinho.bak` backup, all on your machine, never uploaded. Full policy:
|
|
395
|
+
No accounts, no telemetry, no analytics, no tracking, and no Claudinho server. The CLI asks ESPN
|
|
396
|
+
(and Polymarket, for World Cup odds) for public data with nothing about you attached; those services
|
|
397
|
+
still see standard request metadata, such as your IP address, like any web request. It keeps your
|
|
398
|
+
choice and a cache of public match data on your machine (see [Where it is saved](#where-it-is-saved)).
|
|
399
|
+
The `init` commands edit only the settings file they name, after a
|
|
400
|
+
one-time `.claudinho.bak` backup. Nothing is uploaded. Full policy:
|
|
341
401
|
[PRIVACY.md](https://github.com/arturogarrido/claudinho/blob/main/PRIVACY.md).
|
|
342
402
|
|
|
343
403
|
## License
|
|
344
404
|
|
|
345
|
-
MIT © 2026 Arturo Garrido · [source
|
|
346
|
-
|
|
347
|
-
> **Not affiliated with FIFA, any confederation, league or club, or Anthropic. Nor endorsed by or connected to any of them.** An independent,
|
|
348
|
-
> open-source fan project showing factual match data (scores, fixtures, standings) with emoji
|
|
349
|
-
> flags only: no logos, crests, kits, broadcast footage, or player likenesses.
|
|
405
|
+
MIT © 2026 Arturo Garrido · [source and issues](https://github.com/arturogarrido/claudinho) ·
|
|
406
|
+
like it? [star it on GitHub](https://github.com/arturogarrido/claudinho) (`claudinho star` shows how).
|
|
350
407
|
|
|
351
|
-
|
|
408
|
+
Independent fan project. Not affiliated with FIFA, any confederation, league or club, or Anthropic.
|
|
352
409
|
|
|
353
410
|
_Built while watching the games._ **#VibingLaVidaLoca** ⚽
|