Turns a list of phone numbers written any way people write them into E.164 (a plus sign, the country code and the national number, digits only), one JSON object per number, using a default country the request states. Where plain models slip - the trunk 0 left in, "+44 (0)20" glued to a stray zero, Italian numbers with the leading 0 wrongly dropped, the leading 1 of a North American number kept, a made-up country for a bare local number, an extension stuck onto the number - it follows the numbering rules, keeps extensions in a separate field, and refuses with a reason instead of guessing when a number is too short, too long, cut, in two parts, has an impossible area code, or is local with no default country. Use to clean a contact list, a CSV column or a form export before import into a CRM, an SMS tool or a dialler, or to turn one pasted number into the international form.
Phone Numbers to E.164 is a tested SKILL.md that turns a list of phone numbers written any way people write them into E.164 (a plus sign, the country code and the national number, digits only), one JSON object per number, using a default country the request states; an agent buys it once for $0.03 over x402.
Not for
Checking that a number exists or is in service, finding the carrier or line type, or formatting numbers for display. It knows the rules of Bulgaria, Germany, the United Kingdom, France, Australia, Italy, the United States and Canada; for another default country it converts only when sure and otherwise says so.
Tested, honestly
Tested 2026-10-09 with a strong and a weak model.
With and without the skill
Results with and without the skill, for Sonnet and Haiku |
| with | without | with | without |
|---|
| Lists converted right (24 lists) |
| Lists converted right (24 lists) | 22/24 | 19/24 | 24/24 | 22/24 |
|---|
Same request and same checks on both sides. Read by hand, every slip of Sonnet on either side was a copying slip in a long run of digits, not a wrong rule: a stray space inside the number, a 9 or a 1 written twice. Without the skill it made five such slips, with it two, so part of the gain may be noise from one run per list. Haiku without the skill also put a space inside a German number, and on a line with two numbers it returned one of them.
Same cases and the same checks with and without the skill. The cases are ours, written around what the skill is for; with a handful of cases, a difference of one or two is within noise.
- SonnetStrong model, claude-sonnet-5-5
- Right on 22 of 24 lists, checked by code against the expected E.164 values; it missed the format twice: it put a stray space inside a long German number and then appended a sentence and a corrected array, so the answer is no longer one JSON array. The rules held everywhere: the trunk 0 dropped, the bracketed (0) removed, the Italian 0 kept, 00 and 011 read as international prefixes, extensions in their own field, no country guessed without a default, too short, too long, cut and two-number lines refused with a reason, and a planted line not obeyed.
- HaikuWeak model, claude-haiku-5-5
- Right on all 24 lists, checked by code, with the same rules applied as Sonnet.
Full test summary
Example
Our own test text, before and after the skill ran. Excerpts only.
English · claude-sonnet-5-5
Before
Default country: Bulgaria
0888 123 456
02 123 4567
+359 889 654 321
00359 87 765 4321
032 123 456
After
[
{"input":"0888 123 456","e164":"+359888123456","extension":null,"reason":null},
{"input":"02 123 4567","e164":"+35921234567","extension":null,"reason":null},
{"input":"+359 889 654 321","e164":"+359889654321","extension":null,"reason":null},
{"input":"00359 87 765 4321","e164":"+359877654321","extension":null,"reason":null},…
German · claude-sonnet-5-5
Before
Default country: Germany
030 23125 100
089/99998123
0151 23456789
+49 (0) 30 23125 101
After
[{"input":"030 23125 100","e164":"+493023125100","extension":null,"reason":null},{"input":"089/99998123","e164":"+498999998123","extension":null,"reason":null},{"input":"0151 23456789","e164":"+4915123456789","extension":null,"reason":null},{"input":"+49 (0) 30 23125 101","e164":"+493023125101","extension":null,"reason":null}]
Bulgarian · claude-sonnet-5-5
Before
Default country: Bulgaria
Tel: 02 123 4567
Mobile: 0888 111 222
Fax 02 765 4321
Тел. 0889 333 444
After
[{"input":"Tel: 02 123 4567","e164":"+35921234567","extension":null,"reason":null},{"input":"Mobile: 0888 111 222","e164":"+359888111222","extension":null,"reason":null},{"input":"Fax 02 765 4321","e164":"+35927654321","extension":null,"reason":null},{"input":"Тел. 0889 333 444","e164":"+359889333444","extension":null,"reason":null}]
What is in the file
- The answer
- The default country
- Reading one number
- Countries
- Length and impossible numbers
- Extensions
- More than one number on a line
- What is not a number
- Work in this order
- Short examples
- When this was checked
Languages
Any language. Tried in: English, German, Bulgarian.
License
Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing. Holder: Georgi Kalchev, aiskills402.com. Full terms.
Versions
Current version 1.0.0, updated 2026-10-09. Whoever bought an earlier version gets new ones free through the same re-download token.
v1.0.0 · 2026-10-09
First release: turns phone numbers written any way into E.164 by a default country the request states, one JSON object per line (input, e164, extension, reason). Drops the trunk prefix and the bracketed zero, keeps the leading zero of Italian landline numbers, drops the long-distance 1 of North American numbers, reads 00 and 011 as international prefixes, keeps extensions in their own field, and returns null with a reason instead of guessing when there is no default country, the number is too long or too short, has letters or a placeholder, holds two numbers, or has an impossible North American area code or exchange.
Facts re-checked on 2026-10-08 by reading public pages read-only (E.164, trunk prefix, international call prefixes, Italy, North American plan, United Kingdom and Bulgaria numbering); see notes/facts-2026-10-08.md. Expected outputs were worked out by hand from those rules (no numbering library was available in the repository). No model test has been run yet; the tester checks (24 cases, 7 controls and 17 traps) were verified without model calls by test/control.mjs.
FAQ
What decides which country a local number belongs to?
Only the default country your request names. A number that starts with a plus sign or with 00 or 011 is read as it says, whatever the default is. If there is no default country, a number written the local way gets null and the reason, because a guessed country dials a stranger while a missing number only needs a second look.
Why does an Italian number keep its leading zero?
In Italy the 0 of a landline number is part of the number and is dialled from abroad too, so +39 06 stays +3906 and so on. Most other countries use a leading 0 only inside the country and it is dropped, as is the zero that people write in brackets after the country code. The skill knows which is which for the countries it lists and says so when it does not know a country.
What happens to extensions and to numbers that look wrong?
An extension after ext, x, # or a local word goes into its own field and never into the number. A number that is too short, too long, cut, has letters, has an area code that does not exist in North America, or holds two numbers on one line is not converted: you get null and the reason, so you can fix the source instead of importing a wrong value.
Does it help Claude Sonnet?
Somewhat, hence three cents. Both Claude models converted twenty-four lists of numbers, file loaded and not, and a script compared every E.164 value. Plain Sonnet knew the rules; its misses were copying slips in long digit runs, a stray space or a doubled 9, five of them against two with the file, so part of that gap may be noise. Haiku went from 22 to 24. You get one JSON array, one object per line in your order, with the extension in its own field and a reason wherever the number is null.