Extensions and Helpers Agent Tools
An agent should not work out a weekday, a percentage change, an IBAN checksum or a time zone offset by reasoning, because it will sometimes be wrong. The service layer therefore offers 178 small, exact, pure functions as agent tools, in 22 groups of 7 to 10. Each group is meant to be handed to one agent. Statistical, numerical and machine-learning tools are not here; they are the separate Advanced Analytics tool layer.
Where the logic lives
Jube.Dictionary.Extensionsholds the logic as extension methods, which are also the rule language’s tokens (see Rule Compilation Algorithm). A rule and an agent tool therefore run the same code and cannot disagree.Jube.Service.Extensions.<Group>is a thin facade over those methods. Each tool adds an LLM-oriented description, input limits and plain-English errors, and sometimes combines several extension calls into one small result record, such asValidateIban.Jube.Service.Helpers.<Group>holds the few functions that are not extension methods: reading the clock, creating UUIDs, and set operations over lists of text.
Contract
- Tools are marked
[FunctionToolGroup(name, description)]on the class and[FunctionTool(name)]with[Description]on each method and parameter. Tests hold the decoration to a standard: descriptions of at least 30 characters (8 for parameters), globally unique tool names, a group size of 7 to 20, and a namespace that ends in the group name. Discovering the groups and binding them as agent functions is the agent host’s job, beside the existing service tool binder, and is not part of this layer. - Errors are for the model. Invalid input, and any result that would be undefined (division by zero, an unknown
currency, a skipped local time), throws
ArgumentExceptionwith the reason and, where useful, the valid options. The hosting middleware should return that message to the model as the tool result. Results never containNaNor infinity. - Bounded input. Text is limited to 100,000 characters (1,000 for names in fuzzy matching and 1,000,000 for JSON/XML documents), and lists to 10,000 items. Regular expressions time out after 250 ms, and XML with a DTD is refused.
- Pure. A unit test reads the compiled IL of every facade and rule-library type and fails on any reference to file,
network, process, environment, dynamic loading,
Activator,Reflection.Emit, native interop or Win32, or on any platform invoke. Extension facades are also barred from the clock and from random sources, so they always return the same answer for the same input; onlyHelpers.ClockAndIdentifiersreads the clock, through an injectableTimeProvider. - Host. Linux containers only. Time zones are IANA ids resolved from the image’s tzdata, and Unicode normalisation and international host names use ICU; the runtime image carries both.
- Every tool is named by at least one test through
[Trait("Covers", "<ToolName>")], and a catalogue test fails when one is not.
Extension groups
CalendarFacts
Jube.Service.Extensions.CalendarFacts — Calendar facts about a date: weekday, week number, quarter, fiscal period,
month length, leap years, business hours and the start and end of its day, week, month, quarter or year.
| Tool | What it does |
|---|---|
DescribeDate |
Calendar facts about one date in a single call: weekday name, day of year, ISO week number, calendar quarter, days in the month, whether it is a weekend, the last day of its month, and whether its year is a leap year. Use it instead of working out weekdays or week numbers by hand. |
PeriodBoundaries |
First and last instant of the day, week, month, quarter or year containing a date; the week can start on any weekday. End is the last tick of the period, so an instant is inside when Start <= instant <= End. |
FiscalPeriod |
Fiscal year and fiscal quarter of a date when the fiscal year starts in a given month. The fiscal year is named after the calendar year in which it ends; with an April start, 2026-08-17 is fiscal 2027 quarter 2. |
DaysInMonth |
Number of days in a given month of a given year, allowing for leap years; February 2028 has 29. |
IsLeapYear |
Whether a year is a Gregorian leap year: divisible by 4, except centuries not divisible by 400; 2000 and 2028 are, 1900 and 2026 are not. |
IsWithinBusinessHours |
Whether the clock time of a date-time falls in business hours, from startHour inclusive to endHour exclusive, optionally on weekdays only. Convert to the customer’s local time zone first when that matters. |
IsSameCalendarDay |
Whether two date-times fall on the same calendar date, ignoring the time of day. Convert both to the same time zone first. |
CurrencyAndCountry
Jube.Service.Extensions.CurrencyAndCountry — ISO 4217 currency and ISO 3166 country reference data with exact
minor-unit money conversion, from tables embedded in the product.
| Tool | What it does |
|---|---|
CurrencyMinorUnitDigits |
Number of decimal places an ISO 4217 currency uses: USD 2, JPY 0, KWD 3, CLF 4. Use it before storing, rounding or comparing money in minor units. |
IsValidCurrencyCode |
Whether a three-letter code is an active ISO 4217 currency, case-insensitive. Use it to check payment currency fields. |
ToMinorUnits |
Converts a money amount to whole minor units for a currency, exactly and rounding halves away from zero; 19.99 USD is 1999 cents and 1500 JPY is 1500. |
FromMinorUnits |
Converts whole minor units back to a money amount for a currency; 1999 USD cents is 19.99 and 1234 KWD fils is 1.234. |
RoundToCurrency |
Rounds a money amount to the precision of its currency, halves away from zero, using exact decimal arithmetic; 1234.5678 JPY is 1235 and in BHD is 1234.568. |
ConvertAtExchangeRate |
Multiplies an amount by a supplied exchange rate; 100 at 1.25 is 125. This tool knows no live rates, so the rate must come from the conversation or data. |
IsValidCountryCode |
Whether a two-letter code is an ISO 3166-1 alpha-2 country code, case-insensitive; GB is valid and UK is not. Use it to check country fields. |
DescribeCountry |
Looks up an ISO 3166-1 country by alpha-2 or alpha-3 code and returns both codes and the English short name; DEU gives DE, DEU, Germany. |
DateArithmetic
Jube.Service.Extensions.DateArithmetic — Adds time to dates and measures the time between them exactly, including
business days, whole months and years, ages as of a date, and interval overlap.
| Tool | What it does |
|---|---|
AddToDate |
Adds (or with a negative amount subtracts) a number of units to a date-time. Months and Years keep the day where possible and clamp to month end, so 2026-01-31 plus 1 month is 2026-02-28. |
AddBusinessDays |
Moves a date forward (or backward, if negative) by a number of Monday-to-Friday business days, skipping weekends; Friday plus 1 is Monday. Public holidays are not known and are not skipped. |
BusinessDaysBetween |
Number of Monday-to-Friday days after the start date up to and including the end date; negative when the end is earlier. Wednesday to the following Wednesday is 5. Public holidays are not known. |
TimeBetween |
Exact elapsed time from a start to an end date-time in several units at once: total days, hours, minutes and seconds (fractional), plus completed whole months and whole years. Values are negative when the end is earlier. |
AgeAsOf |
Age in completed years and in days of someone or something born on a date, measured at an as-of date; born 1990-06-15 is 35 on 2026-06-14 and 36 the next day. Use CurrentUtcTime for today’s date. |
IntervalsOverlap |
Whether two time intervals overlap. Intervals are half-open (start included, end excluded), so one ending exactly when the other starts does not overlap. |
IsDateBetween |
Whether a date-time lies within an inclusive range from a start to an end. Use it for effective dates, statement periods and lookback windows. |
EncodingAndHashing
Jube.Service.Extensions.EncodingAndHashing — Encodes and decodes text (Base64, Base64Url, hex, URL, HTML, XML,
JavaScript) and computes digests, HMACs and checksums over UTF-8 text.
| Tool | What it does |
|---|---|
EncodeText |
Encodes UTF-8 text in a scheme: Base64, Base64Url (URL-safe, no padding), Hex (lowercase), Url (form encoding, spaces as +), Html, XmlEscape or JavaScript (string-literal escaping). Use DecodeText to reverse. |
DecodeText |
Decodes text from a scheme back to UTF-8 text: Base64, Base64Url, Hex (an optional 0x prefix is allowed), Url or Html. Malformed input is refused with the reason. |
HashText |
Lowercase hex digest of the UTF-8 bytes of a text with Sha256 (default), Sha384, Sha512, Sha1 or Md5. Sha1 and Md5 are for matching legacy values only, never for security. Use it to compare or pseudonymise values without revealing them. |
HmacText |
Lowercase hex HMAC of the UTF-8 bytes of a text under a secret key, with Sha256 (default) or Sha512. Use it to verify a signed payload or to pseudonymise with a key. Never put a production secret into a conversation. |
Crc32Checksum |
CRC-32 (IEEE) checksum of the UTF-8 bytes of a text as eight lowercase hex digits; ‘123456789’ gives cbf43926. For detecting accidental change, not tampering. |
HashesMatch |
Whether a text hashes to a given hex digest with an algorithm, comparing case-insensitively. Use it to check a value against a stored fingerprint without ever handling the original. |
DescribeUuid |
Whether a text is a UUID (GUID) and, if so, its canonical lowercase form and version number; version 4 is random and version 7 is time-ordered. SWIFT UETRs are version 4 UUIDs. |
FinancialIdentifiers
Jube.Service.Extensions.FinancialIdentifiers — Validates and dissects payment and securities identifiers: IBAN,
BIC/SWIFT, card numbers and expiry, Luhn check digits, ABA routing numbers, ISIN, LEI, CUSIP and SEDOL.
| Tool | What it does |
|---|---|
ValidateIban |
Checks an IBAN’s structure and ISO 7064 mod-97 check digits (spaces allowed) and, when valid, returns its country, check digits, basic bank account number and print format in groups of four. A valid checksum does not prove the account exists. |
ValidateBic |
Checks the format of a BIC (SWIFT code, 8 or 11 characters) and, when valid, splits it into institution, country, location and branch codes; an 8-character BIC is the primary office, branch XXX. |
ValidateCardNumber |
Checks a payment card number with the Luhn algorithm (spaces and hyphens allowed) and reports the card network from its prefix, the 6 and 8 digit issuer identification numbers and a masked form showing only the last four digits. |
LuhnCheckDigit |
The Luhn check digit that would complete a digit string; 7992739871 needs 3. Use it to generate or explain card, IMEI and account check digits. |
IsCardExpiryValid |
Whether a card expiry written MM/YY or MM/YYYY is still valid at a given date; a card is valid through the last day of its expiry month. Use CurrentUtcTime for today. |
IsValidAbaRoutingNumber |
Whether a nine-digit US ABA routing transit number passes its 3-7-1 weighted checksum; 021000021 does. |
IsValidIsin |
Whether a 12-character ISIN (International Securities Identification Number) has a valid country prefix shape and Luhn check digit; US0378331005 does. |
IsValidLei |
Whether a 20-character LEI (Legal Entity Identifier) passes its ISO 17442 mod-97 check digits. A valid checksum does not prove the entity is registered. |
IsValidCusip |
Whether a nine-character CUSIP (North American security identifier) has a valid check digit; 037833100 does. |
IsValidSedol |
Whether a seven-character SEDOL (London Stock Exchange security identifier) has a valid weighted check digit and no vowels; 0263494 does. |
Geospatial
Jube.Service.Extensions.Geospatial — Great-circle geometry on latitude and longitude: distances, radius checks,
implied travel speed for impossible-travel analysis, bearings and geohashes.
| Tool | What it does |
|---|---|
DistanceBetweenPoints |
Great-circle (haversine) distance between two points given as latitude and longitude in decimal degrees, in both kilometres and miles. |
IsWithinRadius |
Whether a point lies within a radius in kilometres of a centre point, by great-circle distance. Use it for geofences around a home address or merchant. |
ImpliedTravelSpeed |
Speed in km/h someone would need to travel between two locations in the time between two events. Over about 900 km/h (a commercial flight) suggests impossible travel, such as the same card used in two countries an hour apart. |
InitialBearing |
Initial compass bearing in degrees (0 north, 90 east) for the great-circle route from a first point to a second. |
EncodeGeohash |
Encodes a latitude and longitude as a geohash of 1 to 12 characters; longer is more precise (6 is about 1.2 km, 9 about 5 m). Points sharing a prefix are near each other, which makes geohashes good grouping keys. |
DecodeGeohash |
The centre latitude and longitude of the cell a geohash names. |
IsValidCoordinate |
Whether a latitude and longitude pair is in range: latitude -90 to 90 and longitude -180 to 180. Swapped coordinates often fail this check. |
ListScreening
Jube.Service.Extensions.ListScreening — Screens a name or text against a list, such as a watch list or allow list,
with configurable fuzzy matching, and reports the best match, its score and how many entries matched.
| Tool | What it does |
|---|---|
ScreenAgainstList |
Screens one value against a list with a fuzzy rule and reports whether anything matched, how many entries matched, the best matching entry and its score from 0 to 1. The main tool for checking a name against a watch list or a counterparty against known entities. |
IsFuzzilyInList |
Whether a value fuzzily equals any entry of a list under a fuzzy rule. Use ScreenAgainstList when the matching entry or score is also wanted. |
ContainsFuzzilyAnyInList |
Whether any list entry fuzzily appears inside a longer text, such as a sanctioned name inside a payment narrative. The within modifier is applied automatically. |
IsExactlyInList |
Whether a value equals any list entry exactly, optionally ignoring case; no fuzziness. Use it for code lists such as country or merchant category codes. |
InitialsMatchInList |
Whether a name matches any list entry when initials are allowed to stand for whole words; ‘J R R Tolkien’ matches ‘John Ronald Reuel Tolkien’. |
SoundsLikeAnyInList |
Whether a name sounds like any list entry word by word under Soundex after case and accent folding. Phonetic only, so pair it with an edit-distance check. |
CheckFuzzyOptions |
Checks a fuzzy options string and returns an empty text when it is valid, or the reason it is not. Use it before saving a list-matching rule. |
NameSimilarity
Jube.Service.Extensions.NameSimilarity — Scores how alike two names or references are with edit-distance, phonetic and
token algorithms, and normalises names for matching; for pairwise comparison rather than screening a list.
| Tool | What it does |
|---|---|
CompareNames |
Scores two names with every similarity algorithm at once: Levenshtein and Damerau edit distances, normalised similarity, Jaro-Winkler, Dice bigrams, token-sort, token-set (0 to 1, higher is closer), and whether they sound alike by Soundex. Use it to explain why two parties may or may not be the same. |
LevenshteinDistance |
Minimum number of single-character insertions, deletions or substitutions turning one text into another, case-sensitive; ‘kitten’ to ‘sitting’ is 3. |
DamerauDistance |
Edit distance that also counts swapping two adjacent characters as one edit, so typing transpositions score 1; ‘abcd’ to ‘abdc’ is 1. |
JaroWinklerSimilarity |
Jaro-Winkler similarity from 0 to 1, rewarding a shared prefix; well suited to short personal names. Case-sensitive; 0.92 and above is a typical match threshold. |
SoundexCode |
The four-character American Soundex code of a word, grouping names that sound alike; Robert and Rupert are both R163. |
NamesSoundAlike |
Whether two names sound alike word by word under Soundex after case and accent folding; ‘Robert Smith’ and ‘Rupert Smyth’ do. |
InitialsOf |
The initials of a name, one uppercase letter per word; ‘john ronald reuel tolkien’ gives JRRT. |
NormaliseNameForMatching |
The canonical form used for name matching: lowercase, accents and punctuation removed, leading titles (Mr, Dr, Frau) and trailing company suffixes (Ltd, GmbH, LLC) dropped; ‘Dr. José Núñez’ gives ‘jose nunez’. |
NamesMatchWithOptions |
Whether two names match under a configurable fuzzy rule, the same rule language used by list screening, so a pair can be tested before a list rule is written. |
OnlineIdentifiers
Jube.Service.Extensions.OnlineIdentifiers — Validates and dissects digital identifiers: email addresses and
plus-aliases, phone numbers, domain names, URLs, IPv4 and IPv6 addresses and CIDR network ranges. Pure parsing; nothing
is looked up on the network.
| Tool | What it does |
|---|---|
ValidateEmailAddress |
Checks an email address’s syntax and splits it into local part, domain and top-level domain, plus the plus-alias-normalised address (ann+promo@x.com becomes ann@x.com), which exposes one person registering many aliases. Syntax only; no mailbox lookup. |
EmailAddressesMatchIgnoringAliases |
Whether two email addresses reach the same mailbox once case and plus-aliases are ignored; ann+1@x.com and ANN@x.com match. |
ValidatePhoneNumber |
Reduces a phone number to digits (keeping a leading + and turning a 00 prefix into +) and reports whether that is a valid E.164 international number (+ then up to 15 digits, not starting 0). Format only; no carrier lookup. |
DescribeUrl |
Parses an absolute URL and returns its lowercase scheme and host (internationalised hosts in punycode) and its top-level domain; file and network-share URLs are refused. Nothing is fetched. |
IsValidDomainName |
Whether a text is a syntactically valid internet domain name of at least two labels, each 1 to 63 letters, digits or hyphens, not starting or ending with a hyphen. No DNS lookup. |
DescribeIpAddress |
Parses an IPv4 or IPv6 address and classifies it: canonical form, family, private (RFC 1918, carrier-grade NAT, unique local), loopback, reserved (link-local, multicast, documentation and similar) or public, and the IPv4 address as a number. IPv4-mapped IPv6 addresses are treated as IPv4. |
IsIpAddressInRange |
Whether an IP address falls inside a CIDR network range such as 10.0.0.0/8 or 2001:db8::/32. Addresses and ranges of different families never match. |
DescribeIpRange |
The first and last address and the number of addresses in a CIDR network range; 192.168.1.77/24 spans 192.168.1.0 to 192.168.1.255, 256 addresses. |
NumberToIPv4Address |
Writes a number from 0 to 4294967295 as a dotted IPv4 address; 3232235777 is 192.168.1.1. The reverse is in DescribeIpAddress. |
PatternMatching
Jube.Service.Extensions.PatternMatching — Regular-expression and wildcard matching with a hard time limit per call:
test, find, capture, count, replace and escape.
| Tool | What it does |
|---|---|
RegexIsMatch |
.NET regular expression test: whether the pattern matches anywhere in the text. Matching is time-limited, so a pattern that would backtrack catastrophically is refused rather than hanging. |
RegexFindAll |
Every match of a .NET regular expression in a text, in order, as the matched texts (up to 10000). Matching is time-limited. |
RegexCapture |
The text captured by a numbered group of the first match of a .NET regular expression, or empty if there is no match; group 1 of ‘order-([0-9]+)’ in ‘order-12345-x’ is ‘12345’. Group 0 is the whole match. |
RegexCountMatches |
Number of non-overlapping matches of a .NET regular expression in a text. Matching is time-limited. |
RegexReplaceAll |
Replaces every match of a .NET regular expression; the replacement may use $1, $2 for groups. ‘a1b22’ with [0-9]+ replaced by # is ‘a#b#’. Matching is time-limited. |
EscapeForRegex |
Escapes a literal text so it can be placed inside a regular expression and match itself exactly; ‘1.5*2’ becomes ‘1.5*2’. |
WildcardIsMatch |
Whether a whole text matches a simple wildcard pattern: * is any run of characters, ? is one character, # is one digit and [abc] or [!abc] is a character set; ‘INV-2026-*’ matches ‘INV-2026-0042’. Case-sensitive. |
PercentagesAndChanges
Jube.Service.Extensions.PercentagesAndChanges — Percentages, ratios and growth between two figures, such as the change
from last month or the share of a total, computed exactly.
| Tool | What it does |
|---|---|
PercentOfTotal |
What percent a part is of a total; 25 of 200 is 12.5. Use it for shares such as declined spend as a percent of total spend. |
PercentageChange |
Percentage change from a previous value to a current value; 80 to 100 is +25 and 100 to 80 is -20. Use it for period-on-period movement. |
PercentDifference |
Symmetric percent difference between two values relative to their average; 90 and 110 differ by 20 percent. Use it when neither value is the baseline. |
RatioOfValues |
One value divided by another as a plain ratio; 30 over 120 is 0.25. Use it for velocity ratios, coverage and other quotients. |
LogRatio |
Natural log of numerator over denominator, a symmetric measure of relative size: doubling is +0.693 and halving is -0.693. Both values must be positive. |
CompoundGrowthRate |
Average compound growth rate per period between a starting and an ending value, as a fraction; 100 growing to 121 over 2 periods is 0.1 (10 percent per period). |
AddPercentage |
Increases an amount by a percentage; 100 plus 20 percent is 120. Use it for tax, fees, uplifts and mark-ups. |
SubtractPercentage |
Decreases an amount by a percentage; 100 less 20 percent is 80. Use it for discounts, haircuts and deductions. |
AmountBeforePercentageAdded |
Recovers the original amount before a percentage was added; 120 including 20 percent was 100 before it. Use it to back tax or fees out of a gross amount. |
IsWithinPercentOf |
Whether a value lies within a percentage tolerance of a target, inclusive; 104 is within 5 percent of 100. Use it for near-match checks on amounts. |
RoundingAndPowers
Jube.Service.Extensions.RoundingAndPowers — Exact rounding, clamping, powers, roots and logarithms of single numbers,
so an answer never depends on mental arithmetic.
| Tool | What it does |
|---|---|
RoundNumber |
Rounds a number to a number of decimal places using an explicit rule for halves. Use it whenever a figure must be presented or compared at a fixed precision; AwayFromZero is the everyday rule (2.5 becomes 3), ToEven is banker’s rounding (2.5 becomes 2). |
RoundToNearestIncrement |
Rounds a number to the nearest multiple of an increment, halves away from zero; for example 1234 to the nearest 50 is 1250, and 0.125 to the nearest 0.05 is 0.15. Use it for price points, reporting bands and cash denominations. |
RoundDownToWholeNumber |
Largest whole number less than or equal to the value (the floor); -2.5 becomes -3. Use it for completed units such as whole days or whole bands. |
RoundUpToWholeNumber |
Smallest whole number greater than or equal to the value (the ceiling); 2.1 becomes 3. Use it for counts of units needed to cover an amount. |
TruncateToWholeNumber |
Drops the fractional part of a number, moving towards zero; -2.7 becomes -2 and 2.7 becomes 2. Use it when the integer part is wanted regardless of sign. |
ClampNumber |
Limits a number to an inclusive range, returning the minimum when below it and the maximum when above it. Use it to cap scores, limits or percentages. |
RaiseToPower |
Raises a base to an exponent, including fractional and negative exponents; 2 to the 10 is 1024 and 9 to the 0.5 is 3. Use it for compounding and scale factors. |
NthRoot |
The real n-th root of a number; the cube root of 27 is 3 and the cube root of -8 is -2. An even root of a negative number has no real answer and is refused. |
Logarithm |
Logarithm of a positive number in any base; base 10 of 1000 is 3, base 2 of 8 is 3, and base e (2.718281828) gives the natural log. Use it to compare orders of magnitude. |
StructuredData
Jube.Service.Extensions.StructuredData — Reads values out of JSON and XML documents by path without loading them into
the conversation, and checks that documents are well formed. DTDs and external entities are refused.
| Tool | What it does |
|---|---|
IsValidJson |
Whether a text is well-formed JSON (up to 1,000,000 characters and 64 levels deep). |
JsonValueAtPath |
The value at a path in a JSON document as text: strings unquoted, anything else as compact JSON. Paths use dots and brackets with an optional $, such as $.customer.name, customer.tags[0], items[-1] (last) or $[‘odd key’]. Empty when the path is missing. |
JsonNumberAtPath |
The number at a path in a JSON document; refused when the path is missing or not a number. Uses the same paths as JsonValueAtPath. |
JsonArrayLengthAtPath |
Number of elements in the array at a path in a JSON document; -1 when the path is missing or not an array. |
JsonHasPath |
Whether a path exists and is not null in a JSON document; the same paths as JsonValueAtPath. |
MinifyJson |
Removes insignificant whitespace from a JSON document; refused when the text is not valid JSON. |
IsValidXml |
Whether a text is a well-formed XML document without a DTD (up to 1,000,000 characters). Documents declaring a DTD or entities are refused for safety. |
XmlValueAtXPath |
Text content of the first node selected by an XPath 1.0 expression, such as /Document/GrpHdr/MsgId or //Nm, in an XML document such as an ISO 20022 payment message; empty when nothing is selected. Namespaced documents need local-name(), for example //*[local-name()=’MsgId’]. |
TextCleaning
Jube.Service.Extensions.TextCleaning — Cleans and normalises text before comparison or storage: accents, whitespace,
control characters, Unicode forms, keeping or removing letters and digits, and URL slugs.
| Tool | What it does |
|---|---|
RemoveAccents |
Removes accents and other combining marks while keeping the base letters; ‘Crème Brûlée’ becomes ‘Creme Brulee’. Use it before comparing names from different systems. |
CollapseWhitespace |
Trims the text and replaces every run of spaces, tabs and line breaks with a single space. |
RemoveControlCharacters |
Removes invisible control characters such as NUL and BEL, keeping tabs and line breaks. Use it on data pasted from other systems before display or matching. |
NormaliseUnicode |
Applies a Unicode normalisation form: NFC composes accents (the usual storage form), NFD decomposes them, NFKC and NFKD also fold compatibility characters such as the ‘fi’ ligature and full-width letters to their plain forms, which defeats look-alike tricks. |
KeepOnlyDigits |
Keeps only the numeric characters of a text, dropping everything else; ‘+44 (0) 7911-123456’ gives ‘4407911123456’. |
KeepOnlyLetters |
Keeps only the letters of a text, in any alphabet, dropping digits, spaces and punctuation; ‘AB-12 cd’ gives ‘ABcd’. |
RemoveDigits |
Removes every numeric character from a text, keeping letters, spaces and punctuation. |
RemoveLetters |
Removes every letter from a text, keeping digits, spaces and punctuation. |
ToSlug |
Turns text into a lowercase ASCII slug of letters and digits joined by hyphens; ‘Crème Brûlée & Co.!’ becomes ‘creme-brulee-co’. Useful for stable keys and file-safe names. |
TextEditing
Jube.Service.Extensions.TextEditing — Edits text exactly: case, reversing, repeating, truncating, taking the left or
right characters, masking and replacing the first or last occurrence.
| Tool | What it does |
|---|---|
ToTitleCase |
Capitalises the first letter of each word and lowercases the rest, except words already all in capitals, which are kept as acronyms; ‘john SMITH-jones’ becomes ‘John SMITH-Jones’. |
ReverseText |
Reverses the order of the characters in a text; ‘abc’ becomes ‘cba’. |
RepeatText |
Repeats a text a number of times end to end; ‘ab’ three times is ‘ababab’. The result is limited to 100000 characters. |
TruncateText |
Shortens a text to at most a maximum length, ending with a suffix (default …) when it was cut; texts already short enough are returned unchanged. |
TakeFirstCharacters |
The first n characters of a text, or the whole text if it is shorter; the first 4 of ‘GB82WEST’ is ‘GB82’. |
TakeLastCharacters |
The last n characters of a text, or the whole text if it is shorter; the last 4 of ‘4111111111111111’ is ‘1111’. |
MaskAllButLast |
Replaces all but the last few characters with a mask character, for safe display of card numbers, accounts and phone numbers; ‘4111111111111111’ with 4 visible is ‘****1111’. |
ReplaceFirstOccurrence |
Replaces only the first case-sensitive occurrence of a substring; texts without it are returned unchanged. |
ReplaceLastOccurrence |
Replaces only the last case-sensitive occurrence of a substring; texts without it are returned unchanged. |
TextExtraction
Jube.Service.Extensions.TextExtraction — Pulls pieces out of text: the part before, after or between markers, the n-th
token, all tokens, and numbers written inside free text.
| Tool | What it does |
|---|---|
TextAfter |
The part of a text after the first occurrence of a marker, or empty if the marker is absent; after ‘@’ in ‘ann@example.com’ is ‘example.com’. |
TextBefore |
The part of a text before the first occurrence of a marker, or empty if the marker is absent; before ‘@’ in ‘ann@example.com’ is ‘ann’. |
TextBetween |
The text between the first occurrence of a start marker and the next end marker after it, or empty if either is missing; between ‘ref:’ and ‘;’ in ‘x ref:AB12; y’ is ‘AB12’. |
TokenAt |
The token at a zero-based position after splitting on a separator; a negative position counts from the end, so -1 is the last. Out-of-range positions give empty text. |
SplitText |
Splits a text on a separator into a list, optionally trimming each part and dropping empty parts. Returns at most 10000 parts. |
ExtractNumbers |
Every decimal number written in a free text, in order, reading ‘.’ as the decimal point and a leading ‘-‘ as negative; ‘paid 12.50 then -3 twice’ gives 12.5, -3. Thousands separators split numbers, so remove them first. |
ExtractWholeNumbers |
Every whole number written in a free text, in order, with a leading ‘-‘ read as negative; ‘invoices 1001 and 1002’ gives 1001, 1002. Digit runs too long for a 64-bit integer are refused. |
QueryStringValue |
The decoded value of a named parameter in a URL or query string, or empty if absent; name in ‘https://x.test/p?name=J%C3%BCbe+Ltd’ is ‘Jübe Ltd’. |
TextInspection
Jube.Service.Extensions.TextInspection — Counts and tests on text: words, lines, letters, digits, character variety,
entropy, repeated or sequential characters, palindromes, anagrams and containment.
| Tool | What it does |
|---|---|
DescribeText |
Measures a text in one call: characters, words, lines, letters, digits, distinct characters, longest run of one repeated character, Shannon entropy in bits per character, and whether it is all ASCII letters, all ASCII digits, or one repeated character. Low entropy or long runs suggest synthetic or keyboard-mashed identifiers. |
CountOccurrences |
Counts non-overlapping, case-sensitive occurrences of a substring in a text; ‘aba’ occurs twice in ‘abababa’. |
HasSequentialDigits |
Whether a text contains a run of consecutive ascending or descending digits of at least a given length, such as 1234 or 9876. Common in weak PINs, test card numbers and fabricated identifiers. |
IsPalindrome |
Whether a text reads the same backwards, ignoring case, spaces and punctuation; ‘A man, a plan, a canal: Panama’ is a palindrome. |
AreAnagrams |
Whether two texts use exactly the same characters the same number of times, case-sensitive and counting spaces; ‘listen’ and ‘silent’ are anagrams. Normalise case first if case should not matter. |
EqualsIgnoringCase |
Whether two texts are equal when upper and lower case are ignored (ordinal, culture-independent comparison). |
ContainsAllOf |
Whether a text contains every one of several substrings, optionally ignoring case. Use it for keyword checks in narratives and references. |
ContainsAnyOf |
Whether a text contains at least one of several substrings, optionally ignoring case. Use it for keyword or watch-word checks. |
ThresholdsAndLimits
Jube.Service.Extensions.ThresholdsAndLimits — Amount-against-limit arithmetic for structuring, smurfing and limit
monitoring: distance and headroom to a threshold, excess and shortfall, round amounts and position in a range.
| Tool | What it does |
|---|---|
DistanceToThreshold |
Absolute distance between an amount and a threshold, whichever side it is on; 9600 and 10400 are both 400 from 10000. Use it to see how close a payment came to a reporting limit. |
PercentBelowThreshold |
How far an amount is below a threshold as a percent of the threshold; 9500 against 10000 is 5. Use it to express near-threshold behaviour on a common scale. |
IsJustBelowThreshold |
Whether an amount sits under a threshold but within a margin of it, the classic structuring pattern; 9600 is just below 10000 with a 5 percent margin. |
HeadroomToLimit |
Remaining room under a limit (limit minus used), negative once the limit is breached; 700 used against 1000 leaves 300 and 1200 used leaves -200. Use it for available balance or remaining allowance. |
ExcessOverLimit |
How much an amount exceeds a limit, never negative; 1200 against a 1000 limit is 200 over. Use it to size a breach. |
ShortfallBelowMinimum |
How much an amount falls short of a required minimum, never negative; 80 against a minimum of 100 is 20 short. Use it for minimum balances and floors. |
IsRoundAmount |
Whether an amount is an exact multiple of a round unit such as 100 or 1000. Round amounts are a common money-laundering indicator when frequent. |
LeadingSignificantDigit |
The first non-zero digit of an amount (1 to 9), or 0 for zero; 4567 gives 4 and 0.0456 gives 4. Collect these across many amounts to compare with the first-digit law. |
PositionInRange |
Where a value sits inside a range as a percent from minimum (0) to maximum (100); 75 in 50 to 150 is 25. Values outside the range give below 0 or above 100. |
TimeZonesAndFormats
Jube.Service.Extensions.TimeZonesAndFormats — Converts date-times between UTC and IANA time zones, reports offsets and
daylight saving, and converts to and from Unix epoch and standard text formats.
| Tool | What it does |
|---|---|
ConvertUtcToTimeZone |
Converts a UTC date-time to the local wall-clock time in an IANA time zone such as Europe/London or Asia/Kolkata, allowing for daylight saving. The result has no zone marker. |
ConvertTimeZoneToUtc |
Converts a local wall-clock date-time in an IANA time zone to UTC, allowing for daylight saving. A local time skipped by a clock change is refused. |
ConvertBetweenTimeZones |
Converts a local wall-clock date-time in one IANA time zone to the wall-clock time in another; 09:00 in Europe/London in July is 04:00 in America/New_York. |
DescribeTimeZoneAt |
Offset from UTC in hours and whether daylight saving is in force for an IANA time zone at a given UTC instant; Europe/London is +1 with daylight saving in July. |
IsValidTimeZoneId |
Whether a text is a time zone id known to this system, such as Europe/Paris. Use it before converting times with a zone taken from data. |
ToUnixEpoch |
Converts a UTC date-time to Unix epoch time, returning both seconds and milliseconds since 1970-01-01T00:00:00Z. |
FromUnixEpoch |
Converts a Unix epoch value to a UTC date-time. Values above 100000000000 are usually milliseconds; say which unit the value is in. |
FormatDateTime |
Writes a date-time in a standard text format: Iso8601 (2026-09-23T12:00:00.0000000Z for UTC), Rfc1123 (Wed, 23 Sep 2026 12:00:00 GMT), Sortable (2026-09-23T12:00:00) or UniversalSortable (2026-09-23 12:00:00Z). |
ParseDateTimeWithFormat |
Reads a date-time from text using an exact .NET format pattern such as dd/MM/yyyy HH:mm, treating it as UTC. Use it for unambiguous parsing of data where day and month order matter. |
UnitsAndNumerals
Jube.Service.Extensions.UnitsAndNumerals — Converts measurements between units and whole numbers between Roman
numerals and other bases, plus simple whole-number facts.
| Tool | What it does |
|---|---|
ConvertUnits |
Converts a measurement between units of the same kind. Length: m km cm mm mi yd ft in nmi. Mass: kg g mg t lb oz st ozt. Area: m2 km2 ha acre ft2 mi2. Volume: l ml m3 gal ukgal qt pt floz. Speed: m/s km/h mph kn. Time: s ms min h d wk. Data: b kb mb gb tb kib mib gib tib. Temperature: c f k. |
IntegerToRomanNumerals |
Writes a whole number from 1 to 3999 as Roman numerals; 1994 is MCMXCIV. |
RomanNumeralsToInteger |
Reads canonical Roman numerals as a whole number, case-insensitive; MCMXCIV is 1994. Non-canonical forms such as IIII are refused. |
IntegerToBase |
Writes a whole number in another base from 2 to 36 using lowercase digits; 255 in base 16 is ff and -10 in base 2 is -1010. |
BaseToInteger |
Reads a whole number written in a base from 2 to 36, case-insensitive, with an optional leading minus; ff in base 16 is 255. |
IsPrimeNumber |
Whether a whole number is prime (divisible only by 1 and itself); 1 and negative numbers are not prime. |
DigitSum |
Sum of the decimal digits of a whole number, ignoring the sign; 9999 gives 36. Useful for check-digit reasoning and digit patterns. |
Helper groups
ClockAndIdentifiers
Jube.Service.Helpers.ClockAndIdentifiers — The current date and time in UTC or any time zone, the list of time zone
ids, and fresh random or time-ordered UUIDs; the only tools here that are not repeatable, because they read the clock or
a random source.
| Tool | What it does |
|---|---|
CurrentUtcTime |
The current date and time in UTC from the server clock, with today’s UTC date. Call it whenever a question depends on now or today; never assume the current date. |
CurrentTimeInZone |
The current local date and time, today’s local date and the UTC offset in an IANA time zone such as Europe/London. Use it for questions about local business hours or the local date. |
ListTimeZoneIds |
Time zone ids known to this system whose id contains a filter, case-insensitive, sorted; filter by city or region such as London, America or Kolkata. At most 100 are returned. |
NewRandomUuid |
One or more new random (version 4) UUIDs in canonical lowercase form, for correlation ids or test data. Up to 100 at once. |
NewTimeOrderedUuid |
One or more new time-ordered (version 7) UUIDs, which sort by creation time and suit database keys. Up to 100 at once. |
UuidVersion7Timestamp |
The UTC creation time embedded in a version 7 UUID, to the millisecond. Refused for other UUID versions, which carry no time. |
TimeSince |
Exact time elapsed from a past date-time until now, in total days, hours and minutes and as completed whole years; negative for a future date-time. Use it for questions such as how long ago an account was opened. |
TextLists
Jube.Service.Helpers.TextLists — Exact set operations on lists of text values: distinct values, union, intersection,
difference, symmetric difference, joining and comparing lists, optionally ignoring case. Numeric sorting and frequency
tables are analytics tools.
| Tool | What it does |
|---|---|
DistinctValues |
The list with duplicates removed, keeping the first occurrence of each value in its original order, optionally ignoring case and surrounding spaces. |
UnionOfLists |
Every distinct value that appears in either list, first list order then new values from the second. |
IntersectionOfLists |
The distinct values that appear in both lists, in first-list order. Use it to find shared devices, addresses or counterparties. |
DifferenceOfLists |
The distinct values in the first list that are not in the second, in first-list order; for example new counterparties this month compared with last month. |
CompareLists |
Compares two lists in one call: values only in the first, only in the second, in both, and whether they hold the same set of distinct values. |
CountDistinctValues |
How many different values a list holds, optionally ignoring case; the list a, A, b has 3 distinct values, or 2 ignoring case. |
JoinValues |
Joins a list into one text with a separator, such as a comma and a space, for display or for building a rule’s list literal. |
