id-agent 1.1.3__tar.gz

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.
id_agent-1.1.3/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 id-agent contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,527 @@
1
+ Metadata-Version: 2.4
2
+ Name: id-agent
3
+ Version: 1.1.3
4
+ Summary: Human-readable, token-efficient IDs for AI agent systems
5
+ Project-URL: Homepage, https://github.com/vostride/id-agent#readme
6
+ Project-URL: Repository, https://github.com/vostride/id-agent
7
+ Project-URL: Issues, https://github.com/vostride/id-agent/issues
8
+ Author: Vostride
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,ai,collision-resistant,human-readable,id,identifier,llm,token-efficient,uuid-alternative
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Provides-Extra: dev
24
+ Requires-Dist: build>=1.3; extra == 'dev'
25
+ Requires-Dist: pytest>=9.0; extra == 'dev'
26
+ Requires-Dist: ruff>=0.15; extra == 'dev'
27
+ Description-Content-Type: text/markdown
28
+
29
+ <div align="center">
30
+ <img src="https://raw.githubusercontent.com/vostride/id-agent/main/docs/id-agent.png" alt="id-agent - Token efficient IDs for AI agents" />
31
+
32
+ [![Featured on Hacker News](https://img.shields.io/badge/Hacker%20News-featured-ff6600?style=flat&logo=ycombinator&logoColor=white&colorA=13110f)](https://news.ycombinator.com/item?id=48191852)
33
+ [![npm](https://img.shields.io/npm/dm/id-agent?style=flat&colorA=13110f&colorB=196872)](https://npm.chart.dev/id-agent?primary=neutral&gray=neutral&theme=dark)
34
+ [![npm version](https://img.shields.io/npm/v/id-agent.svg?style=flat&colorA=13110f&colorB=196872)](https://www.npmjs.com/package/id-agent)
35
+ [![GitHub stars](https://img.shields.io/github/stars/vostride/id-agent?style=flat&colorA=13110f&colorB=196872)](https://github.com/vostride/id-agent/stargazers)
36
+
37
+ <p>
38
+ <a href="#the-math">The Math</a>
39
+ ·
40
+ <a href="#javascript--typescript">JavaScript</a>
41
+ ·
42
+ <a href="#python">Python</a>
43
+ ·
44
+ <a href="https://www.npmjs.com/package/id-agent">npm</a>
45
+ ·
46
+ <a href="https://vostride.com">Vostride AI</a>
47
+ </p>
48
+ </div>
49
+
50
+ # id-agent
51
+
52
+ > Token efficient IDs for AI agents.
53
+
54
+ AI agents pass IDs through prompts, tool calls, logs, traces, and memory. UUIDs are great for databases, but they are expensive in context windows and hard for humans or LLMs to copy reliably. id-agent gives you word-based IDs that are compact in modern tokenizers, readable in logs, and configurable by collision budget.
55
+
56
+ Where UUIDs cost about 23 tokens and get hallucinated by LLMs, id-agent produces memorable word-based IDs at about 14 tokens with strong collision resistance. It is built for the context window, not just the database.
57
+
58
+ - **Human-readable** -- word-based IDs that humans and LLMs can remember.
59
+ - **Token-efficient** -- every word in the wordlist is exactly 1 BPE token on o200k_base.
60
+ - **Collision-safe** -- configurable entropy from about 12 to 192 bits.
61
+ - **Validated inputs** -- descriptive validation on all public APIs.
62
+
63
+ ## The Math
64
+
65
+ ### Token Cost Comparison
66
+
67
+ | Format | Example | Tokens (o200k_base) | Collision Resistance |
68
+ |--------|---------|---------------------|----------------------|
69
+ | UUID v4 | `89b842d9-6df9-4cf4-8db0-9dc3aed3cfd7` | about 23 | 122 bits |
70
+ | id-agent (default, 8 words) | `urd-antes-sorry-pac-dire-total-expire-going` | about 14 | about 96 bits |
71
+ | id-agent (5 words) | `frame-beer-bell-tog-hoot` | about 8 | about 60 bits |
72
+
73
+ <table align="center">
74
+ <tr>
75
+ <td align="center"><img src="docs/id-agent-tokenizer.png" alt="id-agent: 12 tokens for 8 words" width="100%" /><br/><strong>id-agent</strong> - 8 words, 43 chars, <strong>12 tokens</strong></td>
76
+ <td align="center"><img src="docs/uuid-tokenizer.png" alt="UUID v4: 26 tokens" width="100%" /><br/><strong>UUID v4</strong> - 36 chars, <strong>26 tokens</strong></td>
77
+ </tr>
78
+ </table>
79
+
80
+ ### Entropy
81
+
82
+ Each word is drawn uniformly from a curated **4096-word list** (2^12). Every position in the ID is an independent random selection:
83
+
84
+ ```text
85
+ Entropy per word = log2(4096) = 12 bits
86
+ Total entropy = words * 12 bits
87
+ ID space = 4096^words = 2^(words * 12)
88
+ ```
89
+
90
+ This holds regardless of individual word length. A 3-character word and a 6-character word both contribute exactly 12 bits because the attacker must guess from the same 4096-word pool.
91
+
92
+ ### Collision Probability
93
+
94
+ The probability of at least one collision among `n` randomly generated IDs:
95
+
96
+ ```text
97
+ P(collision) ~= n^2 / (2 * 2^b)
98
+
99
+ where b = total bits of entropy
100
+ ```
101
+
102
+ This is the birthday paradox approximation, valid when P is small (P < 0.01).
103
+
104
+ | Words | Bits | ID Space | P @ 1K | P @ 10K | P @ 100K | P @ 1M | P @ 1B | 50% collision at |
105
+ |-------|------|----------|--------|---------|----------|--------|--------|------------------|
106
+ | 3 | 36 | 6.9 * 10^10 | 7.3 * 10^-6 | 7.3 * 10^-4 | 7.3 * 10^-2 | about 1 | about 1 | about 309K items |
107
+ | 4 | 48 | 2.8 * 10^14 | 1.8 * 10^-9 | 1.8 * 10^-7 | 1.8 * 10^-5 | 1.8 * 10^-3 | about 1 | about 20M items |
108
+ | 5 | 60 | 1.2 * 10^18 | 4.3 * 10^-13 | 4.3 * 10^-11 | 4.3 * 10^-9 | 4.3 * 10^-7 | 0.43 | about 1.3B items |
109
+ | **8** | **96** | **7.9 * 10^28** | **6.3 * 10^-24** | **6.3 * 10^-22** | **6.3 * 10^-20** | **6.3 * 10^-18** | **6.3 * 10^-12** | **about 331T items** |
110
+ | 10 | 120 | 1.3 * 10^36 | 3.8 * 10^-31 | 3.8 * 10^-29 | 3.8 * 10^-27 | 3.8 * 10^-25 | 3.8 * 10^-19 | about 1.4 * 10^18 items |
111
+ | *UUID v4* | *122* | *5.3 * 10^36* | *9.4 * 10^-32* | *9.4 * 10^-30* | *9.4 * 10^-28* | *9.4 * 10^-26* | *9.4 * 10^-20* | *about 2.7 * 10^18 items* |
112
+
113
+ The default 8-word ID is safe for more than 300 trillion items before reaching a 50% collision chance. Most applications will never generate more than a few million IDs.
114
+
115
+ ### Worked Example
116
+
117
+ For the default 8-word ID at 1 million items:
118
+
119
+ ```text
120
+ b = 8 * 12 = 96 bits
121
+ n = 1,000,000
122
+
123
+ P ~= (10^6)^2 / (2 * 2^96)
124
+ = 10^12 / (2 * 7.92 * 10^28)
125
+ = 10^12 / (1.58 * 10^29)
126
+ = 6.3 * 10^-18
127
+ ```
128
+
129
+ That is roughly **1 in 158 quadrillion**.
130
+
131
+ ### Token Cost
132
+
133
+ All measurements use **o200k_base** (GPT-4o, GPT-4.1, o1, o3) through tiktoken. Token counts vary slightly per ID because of BPE merge behavior with hyphens. Values below are averages over 100 samples:
134
+
135
+ | Format | Avg Tokens | Entropy | Tokens Saved vs UUID | Savings |
136
+ |--------|------------|---------|----------------------|---------|
137
+ | UUID v4 | **about 23** | 122 bits | -- | -- |
138
+ | id-agent (3 words) | **about 5** | 36 bits | about 18 | **78%** |
139
+ | id-agent (5 words) | **about 8** | 60 bits | about 15 | **65%** |
140
+ | **id-agent (8 words, default)** | **about 14** | **96 bits** | **about 9** | **39%** |
141
+ | id-agent (10 words) | **about 17** | 120 bits | about 6 | **26%** |
142
+
143
+ ### Choosing Word Count
144
+
145
+ The right word count depends on your scale. The default of 8 is deliberately conservative and globally safe.
146
+
147
+ | Scale | Recommended | Entropy | Why |
148
+ |-------|-------------|---------|-----|
149
+ | Dev/testing | `words: 3` | 36 bits | Fast, memorable, about 5 tokens. Collides at about 300K items. |
150
+ | Team tools | `words: 4` | 48 bits | Safe to about 20M items. Good for internal APIs. |
151
+ | Production SaaS | `words: 5` | 60 bits | Safe to about 1B items. 65% token savings vs UUID. |
152
+ | High-volume / distributed | `words: 8` (default) | 96 bits | Safe to about 300T items. The safe default. |
153
+ | UUID-equivalent | `words: 10` | 120 bits | Matches UUID v4 collision math. |
154
+
155
+ ### Why Words Beat Hex
156
+
157
+ BPE tokenizers used by modern LLMs were trained on natural language. Short English words are single tokens by design. UUIDs are hex strings that split unpredictably:
158
+
159
+ ```text
160
+ "storm-delta-stone" => 4 tokens (3 words + separators)
161
+ "dc193952-186a-4645" => 11 tokens (same 18 characters)
162
+ ```
163
+
164
+ id-agent's wordlist is curated so every word is exactly **1 BPE token** on o200k_base. The hyphens add about 1 token per 6 words due to BPE merge behavior. This is why word-based IDs are fundamentally more token-efficient than random hex or alphanumeric strings.
165
+
166
+ ## Implementations
167
+
168
+ id-agent is implemented as first-class packages for:
169
+
170
+ - [JavaScript / TypeScript](#javascript--typescript)
171
+ - [Python](#python)
172
+
173
+ Both implementations use the same 4096-word list, separator rules, entropy model, prefix validation, and public behavior.
174
+
175
+ ## How It Works
176
+
177
+ id-agent uses a curated wordlist of 4096 English words, each verified as a single BPE token on the o200k_base tokenizer used by GPT-4o and GPT-4.1. Words are 3-6 characters and filtered for offensive terms and homophones.
178
+
179
+ Random IDs use cryptographically secure randomness. Deterministic IDs use HMAC-SHA256, mapping hash bytes to wordlist indices.
180
+
181
+ ## JavaScript / TypeScript
182
+
183
+ ### Install
184
+
185
+ ```bash
186
+ npm install id-agent
187
+ ```
188
+
189
+ ```bash
190
+ pnpm add id-agent
191
+ ```
192
+
193
+ ### Quick Start
194
+
195
+ ```typescript
196
+ import { idAgent } from 'id-agent'
197
+
198
+ const id = idAgent()
199
+ // => "urd-antes-sorry-pac-dire-total-expire-going"
200
+
201
+ const taskId = idAgent({ prefix: 'task' })
202
+ // => "task_slide-exact-cede-bury-linge-ease-bean-impact"
203
+
204
+ const short = idAgent({ words: 3 })
205
+ // => "front-reject-tho"
206
+ ```
207
+
208
+ ### Random IDs
209
+
210
+ Generate a random, human-readable ID.
211
+
212
+ ```typescript
213
+ import { idAgent } from 'id-agent'
214
+
215
+ idAgent() // 8 words, about 96 bits
216
+ idAgent({ words: 5 }) // 5 words, about 60 bits
217
+ idAgent({ prefix: 'user' }) // "user_cloud-train-scope-frame-match-level-paint-field"
218
+ ```
219
+
220
+ **Options:**
221
+
222
+ | Option | Type | Default | Description |
223
+ |--------|------|---------|-------------|
224
+ | `prefix` | `string` | `undefined` | Type prefix, lowercase alphanumeric only |
225
+ | `words` | `number` | `8` | Number of words, 1-16. Controls entropy: words * 12 bits |
226
+
227
+ ### Deterministic IDs
228
+
229
+ Generate a deterministic ID from a string input using HMAC-SHA256. The same input always produces the same ID.
230
+
231
+ ```typescript
232
+ import { idAgent } from 'id-agent'
233
+
234
+ const id = await idAgent.from('user@example.com')
235
+
236
+ const namespaced = await idAgent.from('user@example.com', {
237
+ namespace: 'my-app',
238
+ prefix: 'user',
239
+ words: 5,
240
+ })
241
+ ```
242
+
243
+ **Options:**
244
+
245
+ | Option | Type | Default | Description |
246
+ |--------|------|---------|-------------|
247
+ | `prefix` | `string` | `undefined` | Type prefix, lowercase alphanumeric only |
248
+ | `words` | `number` | `8` | Number of words, 1-16 |
249
+ | `namespace` | `string` | `'id-agent'` | HMAC key for domain separation |
250
+
251
+ ### Parse
252
+
253
+ Parse any id-agent ID into its components. Supports hyphen-separated and underscore-separated words. Returns `null` for unrecognized formats.
254
+
255
+ ```typescript
256
+ import { parse } from 'id-agent'
257
+
258
+ parse('task_storm-delta-stone')
259
+ // => { prefix: 'task', words: ['storm', 'delta', 'stone'], wordCount: 3, bits: 36, raw: 'task_storm-delta-stone', format: 'readable' }
260
+
261
+ parse('task_storm_delta_stone')
262
+ // => { prefix: 'task', words: ['storm', 'delta', 'stone'], wordCount: 3, bits: 36, raw: 'task_storm_delta_stone', format: 'readable' }
263
+ ```
264
+
265
+ ### Validate
266
+
267
+ Check if a string is a valid id-agent ID. Validation confirms that all words exist in the `WORDLIST`.
268
+
269
+ ```typescript
270
+ import { validate } from 'id-agent'
271
+
272
+ validate('storm-delta-stone')
273
+ // => { valid: true, prefix: undefined, wordCount: 3 }
274
+
275
+ validate('task_jump-notaword')
276
+ // => { valid: false, reason: 'unknown words: notaword' }
277
+
278
+ validate('INVALID')
279
+ // => { valid: false, reason: 'contains uppercase characters' }
280
+ ```
281
+
282
+ ### Alias Maps
283
+
284
+ Create a bidirectional alias map for token reduction in LLM contexts. Maps long IDs to short word-based aliases with replace and restore support.
285
+
286
+ ```typescript
287
+ import { createAliasMap } from 'id-agent'
288
+
289
+ const aliases = createAliasMap({ words: 3 })
290
+ aliases.set('8cdda07b-85d2-459c-8a2a-83c8f9245dbe')
291
+ // => "storm-delta-stone"
292
+
293
+ aliases.get('storm-delta-stone')
294
+ // => "8cdda07b-85d2-459c-8a2a-83c8f9245dbe"
295
+
296
+ const text = 'Process 8cdda07b-85d2-459c-8a2a-83c8f9245dbe then 6ba7b810-9dad-11d1-80b4-00c04fd430c8'
297
+ const shortened = aliases.replace(text, {
298
+ pattern: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi,
299
+ })
300
+ // => "Process storm-delta-stone then cloud-train-scope"
301
+
302
+ const restored = aliases.restore(shortened)
303
+ // => original text
304
+
305
+ aliases.entries()
306
+ // => [["8cdda07b-85d2-459c-8a2a-83c8f9245dbe", "storm-delta-stone"], ...]
307
+ ```
308
+
309
+ **Options:**
310
+
311
+ | Option | Type | Required | Description |
312
+ |--------|------|----------|-------------|
313
+ | `words` | `number` | Yes | Number of words per alias, 1-16 |
314
+
315
+ ### Duplicate Detection
316
+
317
+ Scan text for duplicate IDs using a regex pattern. This is a pure function with no filesystem access.
318
+
319
+ ```typescript
320
+ import { detectDuplicates } from 'id-agent'
321
+
322
+ const dupes = detectDuplicates({
323
+ pattern: /[a-z]+(?:-[a-z]+)+/,
324
+ text: 'Found storm-delta-stone in file A and storm-delta-stone in file B',
325
+ })
326
+ // => [{ id: 'storm-delta-stone', count: 2 }]
327
+
328
+ const dupes2 = detectDuplicates({
329
+ pattern: /task_[a-z]+(?:-[a-z]+)+/,
330
+ text: ['const x = "task_red-fox-run"', 'const y = "task_red-fox-run"'],
331
+ })
332
+ ```
333
+
334
+ **Options:**
335
+
336
+ | Option | Type | Description |
337
+ |--------|------|-------------|
338
+ | `pattern` | `RegExp` | Regex to match IDs in text |
339
+ | `text` | `string \| string[]` | Text to scan for duplicates |
340
+
341
+ ### WORDLIST
342
+
343
+ Direct access to the curated 4096-word list. Every word is exactly 1 BPE token on o200k_base. The JavaScript export is a frozen array.
344
+
345
+ ```typescript
346
+ import { WORDLIST } from 'id-agent'
347
+
348
+ WORDLIST.length // => 4096
349
+ Object.isFrozen(WORDLIST) // => true
350
+ ```
351
+
352
+ ## Python
353
+
354
+ ### Install
355
+
356
+ ```bash
357
+ pip install id-agent
358
+ ```
359
+
360
+ ```bash
361
+ uv add id-agent
362
+ ```
363
+
364
+ ### Quick Start
365
+
366
+ ```python
367
+ from id_agent import generate
368
+
369
+ id = generate()
370
+ # => "urd-antes-sorry-pac-dire-total-expire-going"
371
+
372
+ task_id = generate(prefix="task")
373
+ # => "task_slide-exact-cede-bury-linge-ease-bean-impact"
374
+
375
+ short = generate(words=3)
376
+ # => "front-reject-tho"
377
+ ```
378
+
379
+ ### Random IDs
380
+
381
+ Generate a random, human-readable ID.
382
+
383
+ ```python
384
+ from id_agent import generate
385
+
386
+ generate() # 8 words, about 96 bits
387
+ generate(words=5) # 5 words, about 60 bits
388
+ generate(prefix="user") # "user_cloud-train-scope-frame-match-level-paint-field"
389
+ ```
390
+
391
+ **Options:**
392
+
393
+ | Option | Type | Default | Description |
394
+ |--------|------|---------|-------------|
395
+ | `prefix` | `str \| None` | `None` | Type prefix, lowercase alphanumeric only |
396
+ | `words` | `int` | `8` | Number of words, 1-16. Controls entropy: words * 12 bits |
397
+
398
+ ### Deterministic IDs
399
+
400
+ Generate a deterministic ID from a string input using HMAC-SHA256. The same input always produces the same ID.
401
+
402
+ ```python
403
+ from id_agent import generate_deterministic
404
+
405
+ id = generate_deterministic("user@example.com")
406
+
407
+ namespaced = generate_deterministic(
408
+ "user@example.com",
409
+ namespace="my-app",
410
+ prefix="user",
411
+ words=5,
412
+ )
413
+ ```
414
+
415
+ **Options:**
416
+
417
+ | Option | Type | Default | Description |
418
+ |--------|------|---------|-------------|
419
+ | `prefix` | `str \| None` | `None` | Type prefix, lowercase alphanumeric only |
420
+ | `words` | `int` | `8` | Number of words, 1-16 |
421
+ | `namespace` | `str` | `"id-agent"` | HMAC key for domain separation |
422
+
423
+ ### Parse
424
+
425
+ Parse any id-agent ID into its components. Supports hyphen-separated and underscore-separated words. Returns `None` for unrecognized formats.
426
+
427
+ ```python
428
+ from id_agent import parse
429
+
430
+ parse("task_storm-delta-stone")
431
+ # => ParsedId(prefix="task", words=("storm", "delta", "stone"), word_count=3, bits=36.0, raw="task_storm-delta-stone", format="readable")
432
+
433
+ parse("task_storm_delta_stone")
434
+ # => ParsedId(prefix="task", words=("storm", "delta", "stone"), word_count=3, bits=36.0, raw="task_storm_delta_stone", format="readable")
435
+ ```
436
+
437
+ ### Validate
438
+
439
+ Check if a string is a valid id-agent ID. Validation confirms that all words exist in the `WORDLIST`.
440
+
441
+ ```python
442
+ from id_agent import validate
443
+
444
+ validate("storm-delta-stone")
445
+ # => ValidationResult(valid=True, prefix=None, word_count=3, words=("storm", "delta", "stone"))
446
+
447
+ validate("task_jump-notaword")
448
+ # => ValidationResult(valid=False, reason="unknown words: notaword", unknown_words=("notaword",))
449
+
450
+ validate("INVALID")
451
+ # => ValidationResult(valid=False, reason="contains uppercase characters")
452
+ ```
453
+
454
+ ### Alias Maps
455
+
456
+ Create a bidirectional alias map for token reduction in LLM contexts. Maps long IDs to short word-based aliases with replace and restore support.
457
+
458
+ ```python
459
+ from id_agent import AliasMap
460
+
461
+ aliases = AliasMap(words=3)
462
+ aliases.set("8cdda07b-85d2-459c-8a2a-83c8f9245dbe")
463
+ # => "storm-delta-stone"
464
+
465
+ aliases.get("storm-delta-stone")
466
+ # => "8cdda07b-85d2-459c-8a2a-83c8f9245dbe"
467
+
468
+ text = "Process 8cdda07b-85d2-459c-8a2a-83c8f9245dbe then 6ba7b810-9dad-11d1-80b4-00c04fd430c8"
469
+ shortened = aliases.replace(
470
+ text,
471
+ pattern=r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
472
+ )
473
+ # => "Process storm-delta-stone then cloud-train-scope"
474
+
475
+ restored = aliases.restore(shortened)
476
+ # => original text
477
+
478
+ aliases.entries()
479
+ # => (("8cdda07b-85d2-459c-8a2a-83c8f9245dbe", "storm-delta-stone"), ...)
480
+ ```
481
+
482
+ **Options:**
483
+
484
+ | Option | Type | Required | Description |
485
+ |--------|------|----------|-------------|
486
+ | `words` | `int` | Yes | Number of words per alias, 1-16 |
487
+
488
+ ### Duplicate Detection
489
+
490
+ Scan text for duplicate IDs using a regex pattern. This is a pure function with no filesystem access.
491
+
492
+ ```python
493
+ from id_agent import detect_duplicates
494
+
495
+ dupes = detect_duplicates(
496
+ pattern=r"[a-z]+(?:-[a-z]+)+",
497
+ text="Found storm-delta-stone in file A and storm-delta-stone in file B",
498
+ )
499
+ # => [DuplicateResult(id="storm-delta-stone", count=2)]
500
+
501
+ dupes2 = detect_duplicates(
502
+ pattern=r"task_[a-z]+(?:-[a-z]+)+",
503
+ text=['const x = "task_red-fox-run"', 'const y = "task_red-fox-run"'],
504
+ )
505
+ ```
506
+
507
+ **Options:**
508
+
509
+ | Option | Type | Description |
510
+ |--------|------|-------------|
511
+ | `pattern` | `str \| re.Pattern[str]` | Regex to match IDs in text |
512
+ | `text` | `str \| Iterable[str]` | Text to scan for duplicates |
513
+
514
+ ### WORDLIST
515
+
516
+ Direct access to the curated 4096-word list. Every word is exactly 1 BPE token on o200k_base. The Python export is an immutable tuple.
517
+
518
+ ```python
519
+ from id_agent import WORDLIST
520
+
521
+ len(WORDLIST) # => 4096
522
+ isinstance(WORDLIST, tuple) # => True
523
+ ```
524
+
525
+ ## License
526
+
527
+ MIT