@agenticprimitives/agent-naming 0.1.0-alpha.2

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.
Files changed (54) hide show
  1. package/AUDIT.md +86 -0
  2. package/CLAUDE.md +180 -0
  3. package/LICENSE +21 -0
  4. package/README.md +158 -0
  5. package/dist/abis.d.ts +1532 -0
  6. package/dist/abis.d.ts.map +1 -0
  7. package/dist/abis.js +417 -0
  8. package/dist/abis.js.map +1 -0
  9. package/dist/client.d.ts +102 -0
  10. package/dist/client.d.ts.map +1 -0
  11. package/dist/client.js +299 -0
  12. package/dist/client.js.map +1 -0
  13. package/dist/constants.d.ts +8 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +7 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/custody.d.ts +133 -0
  18. package/dist/custody.d.ts.map +1 -0
  19. package/dist/custody.js +214 -0
  20. package/dist/custody.js.map +1 -0
  21. package/dist/errors.d.ts +15 -0
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/errors.js +30 -0
  24. package/dist/errors.js.map +1 -0
  25. package/dist/index.d.ts +10 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +22 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/namehash.d.ts +31 -0
  30. package/dist/namehash.d.ts.map +1 -0
  31. package/dist/namehash.js +46 -0
  32. package/dist/namehash.js.map +1 -0
  33. package/dist/normalize.d.ts +28 -0
  34. package/dist/normalize.d.ts.map +1 -0
  35. package/dist/normalize.js +68 -0
  36. package/dist/normalize.js.map +1 -0
  37. package/dist/records.d.ts +88 -0
  38. package/dist/records.d.ts.map +1 -0
  39. package/dist/records.js +193 -0
  40. package/dist/records.js.map +1 -0
  41. package/dist/types.d.ts +117 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +2 -0
  44. package/dist/types.js.map +1 -0
  45. package/docs/api.md +110 -0
  46. package/docs/concepts.md +159 -0
  47. package/docs/migration.md +93 -0
  48. package/docs/security.md +127 -0
  49. package/docs/troubleshooting.md +116 -0
  50. package/examples/basic.ts +31 -0
  51. package/examples/custody-rotation.ts +44 -0
  52. package/examples/records.ts +41 -0
  53. package/package.json +71 -0
  54. package/spec.md +14 -0
@@ -0,0 +1,93 @@
1
+ # Agent Naming Migration Notes
2
+
3
+ ## Current Status
4
+
5
+ `@agenticprimitives/agent-naming` is experimental. Public helpers, record
6
+ schemas, ABIs, and call builders are present, but contract deployments and demo
7
+ wiring may still change before a stable release.
8
+
9
+ ## Versioning Policy
10
+
11
+ Before `1.0`, breaking changes may happen when:
12
+
13
+ - the contract ABI changes
14
+ - record predicates change
15
+ - normalization rules change
16
+ - the client write path changes
17
+ - package-boundary rules move logic to another package
18
+
19
+ Every breaking change should update:
20
+
21
+ 1. `README.md`
22
+ 2. `docs/api.md`
23
+ 3. `docs/security.md` when invariants change
24
+ 4. `capability.manifest.json`
25
+ 5. tests or examples that show the changed path
26
+
27
+ ## Canonical-Identifier-First Wiring
28
+
29
+ New integrations should follow [spec 220](../../../specs/220-agent-identity-bootstrap.md):
30
+
31
+ 1. Deploy or resolve the Smart Agent (`agent-account`) — canonical `Address`.
32
+ 2. Register a forced-unique `.agent` name pointing at that address (this package).
33
+ 3. Enroll custodians (`custody` + `identity-auth` ceremonies).
34
+ 4. Optionally publish a profile (`agent-identity`).
35
+
36
+ Display both in UI:
37
+
38
+ ```text
39
+ Canonical Agent ID: eip155:84532:0x…
40
+ Name: alice.agent (facet — may be alice2.agent if taken)
41
+ ```
42
+
43
+ ## From Ad Hoc Address Config To Names
44
+
45
+ Old app wiring often carries raw addresses and endpoint URLs in local config:
46
+
47
+ ```ts
48
+ const treasury = '0x...';
49
+ const mcpEndpoint = 'https://...';
50
+ ```
51
+
52
+ New wiring should resolve through names and records:
53
+
54
+ ```ts
55
+ const treasury = await naming.resolveName('treasury.acme.agent');
56
+ const records = await naming.getRecords('treasury.acme.agent');
57
+ ```
58
+
59
+ Keep raw addresses as fallback diagnostics, not primary UI.
60
+
61
+ ## From Metadata-Only Profiles To Typed Records
62
+
63
+ Use resolver records for small, frequently-read discovery fields:
64
+
65
+ - `addr`
66
+ - `displayName`
67
+ - `agentKind`
68
+ - `a2aEndpoint`
69
+ - `mcpEndpoint`
70
+ - `nativeId`
71
+
72
+ Use `metadataUri` plus `metadataHash` for larger profile documents.
73
+
74
+ ## From Direct Writes To Encoded Calls
75
+
76
+ When writes need custom submission, prefer call builders:
77
+
78
+ ```ts
79
+ const call = buildRotateNameResolverCall({ registry, node, newResolver });
80
+ ```
81
+
82
+ Then submit the call through the appropriate Smart Agent, relayer, or account
83
+ policy path.
84
+
85
+ ## Future Migration Hooks
86
+
87
+ Expected future migration areas:
88
+
89
+ - IDN/punycode support beyond ASCII labels.
90
+ - Generated API docs or manifest-doc synchronization.
91
+ - Example typecheck enforcement.
92
+ - Stable deployment address package.
93
+ - Optional compatibility layer for external ENS resolvers.
@@ -0,0 +1,127 @@
1
+ # Agent Naming Security
2
+
3
+ This package is a **facet registry**, not the identity anchor. Treat names as
4
+ user-facing labels; bind authority to Smart Agent addresses and contract checks
5
+ ([ADR-0010](../../../docs/architecture/decisions/0010-smart-agent-canonical-identifier.md)).
6
+
7
+ ## Read-Path Discipline (No Log Scans)
8
+
9
+ Binding: [ADR-0012](../../../docs/architecture/decisions/0012-no-eth-getlogs-in-product-read-paths.md).
10
+
11
+ Product reads must use `readContract` only:
12
+
13
+ - `resolveName` and `getRecords` — compliant.
14
+ - `reverseResolve` — on-chain round-trip uses `readContract`; returning the
15
+ dotted string currently uses **chunked `eth_getLogs`** in `_reconstructName`
16
+ (**transitional debt** — do not add more log walkers).
17
+
18
+ Approved exits: store plaintext `label` on chain, or a naming indexer, or app
19
+ cache after registration. Chunking log ranges does not make log scans an
20
+ acceptable long-term pattern.
21
+
22
+ ## Deterministic Normalization
23
+
24
+ Every name must normalize the same way on every runtime:
25
+
26
+ 1. NFC normalize.
27
+ 2. Trim whitespace.
28
+ 3. Lowercase.
29
+ 4. Validate labels.
30
+
31
+ Two strings that normalize identically must produce the same `namehash`.
32
+
33
+ Phase 1 uses ASCII-only labels to avoid Unicode spoofing and homoglyph attacks.
34
+ Do not loosen this until the package has a full IDN/punycode policy and golden
35
+ vectors.
36
+
37
+ ## Forward And Reverse Resolution
38
+
39
+ Forward resolution answers:
40
+
41
+ ```text
42
+ name -> address
43
+ ```
44
+
45
+ Reverse resolution answers:
46
+
47
+ ```text
48
+ address -> primary name
49
+ ```
50
+
51
+ Reverse resolution is only trustworthy when it round-trips:
52
+
53
+ ```text
54
+ reverseResolve(address) -> name
55
+ resolveName(name) -> same address
56
+ ```
57
+
58
+ This prevents a malicious account from claiming someone else's name as its
59
+ primary name.
60
+
61
+ ## Unknown Predicates
62
+
63
+ The record layer has asymmetric behavior:
64
+
65
+ - Encode side is strict. Unknown fields are not representable through
66
+ `AgentNameRecords` and known fields are validated before encoding.
67
+ - Decode side is forward-compatible. Unknown predicate ids are ignored.
68
+
69
+ This prevents clients from accidentally writing unsupported records while still
70
+ allowing older readers to survive newer resolver schemas.
71
+
72
+ ## Passkey Material
73
+
74
+ Never store raw passkey credential IDs in naming records.
75
+
76
+ The only passkey-related record is `passkeyCredentialDigest`, a `bytes32` hash
77
+ of the credential ID. Use it for UI correlation only, not as an auth secret.
78
+
79
+ ## CAIP-10 Native ID
80
+
81
+ `nativeId` must match CAIP-10 grammar on encode:
82
+
83
+ ```text
84
+ namespace:reference:account
85
+ ```
86
+
87
+ Phase 1 encode-side namespaces are allowlisted:
88
+
89
+ - `eip155`
90
+ - `hedera`
91
+ - `solana`
92
+
93
+ `eip155` account addresses are lowercased during encode. Decode remains more
94
+ permissive so clients do not fail on future namespaces.
95
+
96
+ ## Endpoint Records
97
+
98
+ `a2aEndpoint` and `mcpEndpoint` are discovery records. They tell clients where
99
+ an agent service claims to be reachable.
100
+
101
+ They do not prove endpoint control. If a product needs endpoint-control proof,
102
+ compose with `@agenticprimitives/agent-profile` verification methods.
103
+
104
+ ## Naming Is Not Account Safety Policy
105
+
106
+ This package can build calls that rotate name owners, resolvers, records, and
107
+ subregistries. It does not decide who is allowed to submit those calls.
108
+
109
+ Authorization lives in the owner Smart Agent and its account safety policy. The
110
+ call builders return encoded calldata only; transaction submission and approval
111
+ flows happen outside this package.
112
+
113
+ ## Subregistries
114
+
115
+ Subregistries can make child-name issuance easier, but they change the authority
116
+ model for a whole subtree.
117
+
118
+ Before setting a subregistry, decide:
119
+
120
+ - who can register children
121
+ - whether registration requires a credential, invite, fee, or stake
122
+ - whether names expire
123
+ - how disputes and reserved names are handled
124
+ - whether the subtree should ever become permissionless
125
+
126
+ For organization/service namespaces, prefer permissioned or credential-gated
127
+ subregistries unless anti-spam rules are already deployed.
@@ -0,0 +1,116 @@
1
+ # Agent Naming Troubleshooting
2
+
3
+ ## `InvalidNameError`
4
+
5
+ The name failed normalization.
6
+
7
+ Common causes:
8
+
9
+ - empty string
10
+ - leading or trailing dot
11
+ - consecutive dots
12
+ - label starts or ends with `-`
13
+ - non-ASCII character
14
+ - label longer than 63 characters
15
+
16
+ Use `isValidAgentName(name)` for UI validation and `normalizeAgentName(name)`
17
+ when you want the canonical value or a detailed thrown error.
18
+
19
+ ## `resolveName(name)` Returns `null`
20
+
21
+ Possible causes:
22
+
23
+ - the name is not registered
24
+ - the name has no resolver
25
+ - the resolver has no `addr` record
26
+ - the configured registry/universal resolver addresses point to the wrong chain
27
+
28
+ Check `chainId`, `registry`, `universalResolver`, and the normalized name.
29
+
30
+ ## `reverseResolve(address)` Returns `null`
31
+
32
+ Possible causes:
33
+
34
+ - the address has no primary name
35
+ - the primary name node cannot be reconstructed from registry events
36
+ - round-trip verification failed
37
+
38
+ Round-trip failure means the primary name points somewhere else or no longer
39
+ resolves to the given address.
40
+
41
+ ## Empty Records From `getRecords(name)`
42
+
43
+ An empty object means no known records were read. Common causes:
44
+
45
+ - no resolver is set
46
+ - records have not been written
47
+ - the resolver is on a different chain
48
+ - records exist only under newer predicates this SDK does not know yet
49
+
50
+ Unknown predicates are ignored on decode by design.
51
+
52
+ ## Unknown Predicate Dropped On Decode
53
+
54
+ This is expected. Decode is forward-compatible and silently ignores unknown
55
+ predicate ids.
56
+
57
+ If the record should be first-class, add it to:
58
+
59
+ 1. `src/types.ts`
60
+ 2. `src/records.ts`
61
+ 3. `test/records.test.ts`
62
+ 4. `docs/api.md`
63
+ 5. `capability.manifest.json`
64
+
65
+ ## Unknown Or Invalid Record Rejected On Encode
66
+
67
+ Encode is strict. Known fields validate their expected shape:
68
+
69
+ - addresses must be 20-byte hex strings
70
+ - `bytes32` values must be 32-byte hex strings
71
+ - `agentKind` must be `person`, `org`, or `service` (a treasury is a `service`
72
+ agent; the `treasury` distinction lives on the profile, not the agent kind)
73
+ - `nativeId` must match CAIP-10 grammar and use an allowed namespace
74
+
75
+ ## Native ID Validation Failed
76
+
77
+ Expected shape:
78
+
79
+ ```text
80
+ eip155:84532:0x0000000000000000000000000000000000000003
81
+ ```
82
+
83
+ `nativeId` must match the `addr` record for the same Smart Agent on EVM chains.
84
+ If you need a new CAIP-10 namespace, add it deliberately to
85
+ `CAIP10_NAMESPACE_ALLOWLIST` and include a test vector.
86
+
87
+ ## Resolver Unset
88
+
89
+ `setAgentRecords` requires the name to have a resolver. Install a resolver
90
+ through registry owner flow before writing records.
91
+
92
+ ## Subregistry Unset
93
+
94
+ If a parent has no subregistry, child registration falls back to parent-owner
95
+ authorization. If a product expects permissionless or credential-gated child
96
+ registration, confirm `setSubregistry` has been applied to the parent node.
97
+
98
+ ## Transaction Write Fails
99
+
100
+ The client write methods submit raw encoded calls through the supplied
101
+ `walletClient`. The caller must be authorized by the contracts.
102
+
103
+ If writes need to pass through a Smart Agent, relayer, or scheduled approval
104
+ flow, use the pure call builders in `@agenticprimitives/agent-naming/custody`
105
+ and submit them through that external flow.
106
+
107
+ ## Confused Name With Identity
108
+
109
+ Symptom: CREATE2 address changes when the user picks a different `.agent` label,
110
+ or APIs accept only a name string with no `Address`.
111
+
112
+ Fix:
113
+
114
+ - Deploy / resolve the Smart Agent first (`agent-account`).
115
+ - Register the name as a facet pointing at that address.
116
+ - Never derive CREATE2 salt from the chosen `.agent` name ([spec 220](../../../specs/220-agent-identity-bootstrap.md)).
@@ -0,0 +1,31 @@
1
+ import {
2
+ AgentNamingClient,
3
+ labelhash,
4
+ namehash,
5
+ normalizeAgentName,
6
+ } from '@agenticprimitives/agent-naming';
7
+
8
+ const normalized = normalizeAgentName(' Treasury.Acme.Agent ');
9
+ const labelNode = labelhash('treasury');
10
+ const nameNode = namehash(normalized);
11
+
12
+ console.log({ normalized, labelNode, nameNode });
13
+
14
+ const naming = new AgentNamingClient({
15
+ rpcUrl: 'https://base-sepolia.example/rpc',
16
+ chainId: 84532,
17
+ registry: '0x0000000000000000000000000000000000000001',
18
+ universalResolver: '0x0000000000000000000000000000000000000002',
19
+ });
20
+
21
+ async function main() {
22
+ const address = await naming.resolveName('treasury.acme.agent');
23
+ const records = await naming.getRecords('treasury.acme.agent');
24
+
25
+ if (address) {
26
+ const primaryName = await naming.reverseResolve(address);
27
+ console.log({ address, primaryName, records });
28
+ }
29
+ }
30
+
31
+ void main();
@@ -0,0 +1,44 @@
1
+ import { namehash } from '@agenticprimitives/agent-naming';
2
+ import {
3
+ buildRecordCalls,
4
+ buildRotateNameOwnerCall,
5
+ buildRotateNameResolverCall,
6
+ buildSetPrimaryNameCall,
7
+ } from '@agenticprimitives/agent-naming/custody';
8
+
9
+ const registry = '0x0000000000000000000000000000000000000001';
10
+ const resolver = '0x0000000000000000000000000000000000000002';
11
+ const newOwner = '0x0000000000000000000000000000000000000003';
12
+ const node = namehash('treasury.acme.agent');
13
+
14
+ // These are pure encoded calls. Submit them through your own transaction path:
15
+ // a Smart Agent execute call, a relayer, or an account-safety approval flow.
16
+ const rotateOwner = buildRotateNameOwnerCall({
17
+ registry,
18
+ node,
19
+ newOwner,
20
+ });
21
+
22
+ const rotateResolver = buildRotateNameResolverCall({
23
+ registry,
24
+ node,
25
+ newResolver: resolver,
26
+ });
27
+
28
+ const setPrimaryName = buildSetPrimaryNameCall({
29
+ registry,
30
+ node,
31
+ });
32
+
33
+ const recordCalls = buildRecordCalls({
34
+ resolver,
35
+ node,
36
+ records: {
37
+ addr: newOwner,
38
+ agentKind: 'service', // treasury is a service subtype (profile), not an agent kind
39
+ displayName: 'Acme Treasury',
40
+ nativeId: `eip155:84532:${newOwner}`,
41
+ },
42
+ });
43
+
44
+ console.log([rotateOwner, rotateResolver, setPrimaryName, ...recordCalls]);
@@ -0,0 +1,41 @@
1
+ import {
2
+ AGENT_KIND_ID,
3
+ PREDICATE_ID,
4
+ decodeRecords,
5
+ encodeRecords,
6
+ } from '@agenticprimitives/agent-naming/records';
7
+
8
+ const agentAddress = '0x0000000000000000000000000000000000000003';
9
+
10
+ const encoded = encodeRecords({
11
+ addr: agentAddress,
12
+ // A treasury is a SERVICE agent (agentKind='service'); 'treasury' is a profile
13
+ // subtype (ProfileType/serviceType), not an agent kind (specs 210/217/225 §6).
14
+ agentKind: 'service',
15
+ displayName: 'Acme Treasury',
16
+ a2aEndpoint: 'https://a2a.acme.example',
17
+ mcpEndpoint: 'https://mcp.acme.example',
18
+ metadataUri: 'https://metadata.acme.example/treasury.json',
19
+ metadataHash: '0x1111111111111111111111111111111111111111111111111111111111111111',
20
+ passkeyCredentialDigest: '0x2222222222222222222222222222222222222222222222222222222222222222',
21
+ custodyPolicy: '0x0000000000000000000000000000000000000004',
22
+ nativeId: `eip155:84532:${agentAddress}`,
23
+ });
24
+
25
+ console.log(encoded);
26
+
27
+ const decoded = decodeRecords({
28
+ strings: {
29
+ [PREDICATE_ID.displayName]: 'Acme Treasury',
30
+ [PREDICATE_ID.a2aEndpoint]: 'https://a2a.acme.example',
31
+ [PREDICATE_ID.nativeId]: `eip155:84532:${agentAddress}`,
32
+ },
33
+ addresses: {
34
+ [PREDICATE_ID.addr]: agentAddress,
35
+ },
36
+ bytes32s: {
37
+ [PREDICATE_ID.agentKind]: AGENT_KIND_ID.service,
38
+ },
39
+ });
40
+
41
+ console.log(decoded);
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@agenticprimitives/agent-naming",
3
+ "version": "0.1.0-alpha.2",
4
+ "description": "Agent Naming Service SDK: ENS-v2-style hierarchical naming for Smart Agents (.agent TLD). Owns name normalization, namehash/labelhash, records schemas, and the AgentNamingClient (resolve / reverse / registry). Speaks naming-domain vocabulary only \u2014 no delegation / caveat / custody concepts.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/agentictrustlabs/agenticprimitives.git",
9
+ "directory": "packages/agent-naming"
10
+ },
11
+ "homepage": "https://github.com/agentictrustlabs/agenticprimitives/tree/master/packages/agent-naming",
12
+ "bugs": {
13
+ "url": "https://github.com/agentictrustlabs/agenticprimitives/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js"
22
+ },
23
+ "./records": {
24
+ "types": "./dist/records.d.ts",
25
+ "import": "./dist/records.js"
26
+ },
27
+ "./custody": {
28
+ "types": "./dist/custody.d.ts",
29
+ "import": "./dist/custody.js"
30
+ }
31
+ },
32
+ "files": [
33
+ "LICENSE",
34
+ "dist",
35
+ "docs",
36
+ "examples",
37
+ "spec.md",
38
+ "README.md",
39
+ "AUDIT.md",
40
+ "CLAUDE.md"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.build.json",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit",
45
+ "test": "vitest run",
46
+ "test:unit": "vitest run test/normalize.test.ts test/namehash.test.ts test/records.test.ts",
47
+ "test:integration": "vitest run test/integration.test.ts",
48
+ "test:watch": "vitest",
49
+ "clean": "rm -rf dist"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "peerDependencies": {
55
+ "@agenticprimitives/agent-account": "workspace:*",
56
+ "@agenticprimitives/connect-auth": "workspace:*",
57
+ "@agenticprimitives/types": "workspace:*",
58
+ "viem": "^2.50.0"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^22.7.0",
62
+ "vitest": "^2.1.0"
63
+ },
64
+ "keywords": [
65
+ "agent",
66
+ "naming",
67
+ "ens",
68
+ "smart-agent",
69
+ "agentic"
70
+ ]
71
+ }
package/spec.md ADDED
@@ -0,0 +1,14 @@
1
+ # @agenticprimitives/agent-naming — spec
2
+
3
+ The full design lives in [`../../specs/215-agent-naming.md`](../../specs/215-agent-naming.md).
4
+
5
+ Architecture decisions:
6
+
7
+ - [ADR-0006](../../docs/architecture/decisions/0006-agent-naming-as-resolution-layer.md)
8
+ — naming as resolution layer via NameContext injection (no
9
+ back-edges from downstream packages).
10
+ - [ADR-0008](../../docs/architecture/decisions/0008-caip10-nativeid-record-predicate.md)
11
+ — `native-id` predicate carries CAIP-10 (HCS-14 interop) without
12
+ UAID derivation.
13
+
14
+ Do not edit a divergent copy here — edit the canonical spec.