# ENS Metadata > ENS-based identity and metadata protocol ## SDK Find documentation [on Github](https://github.com/0xLighthouse/ens-metadata/tree/main/packages/sdk). ## Agent An AI agent with ERC-8004 metadata. ### Attributes | Key | Type | Recommended | Description | Values | | --------------- | ------ | ----------- | ---------------------------------------------------------------------------------------------------------- | ------ | | class | string | Y | Class identifier for this node | - | | schema | string | Y | URI pointing to the agent schema | - | | agent-uri | string | Y | URI pointing to an ERC-8004 registration file | - | | alias | string | Y | Display name of the agent, equivalent to the `name` field in an ERC-8004 registration file | - | | description | string | Y | Natural-language description of the agent | - | | avatar | string | Y | URI pointing to the agent's avatar image, equivalent to the `image` field in an ERC-8004 registration file | - | | services | string | - | URI pointing to a payload containing the agent's services | - | | x402-support | string | - | Indicates whether or not the agent supports x402 payments | - | | active | string | - | Indicates whether or not the agent is currently active | - | | registrations | string | - | URI pointing to a payload containing the agent's cross-chain identity registrations | - | | supported-trust | string | - | Trust models supported by the agent | - | | agent-wallet | string | - | The address where the agent receives payments | - | ### Metadata * Schema ID: `agent` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmUATTZzuow7zUPz9KV4AbY2YgVtaRKHzbQ1Kh8w8dTeZs` * Checksum: `sha256:cc1dd0a2ebabd867492a0b6699f05d21eb4fa04153f6197eea0a3990a9349476` * Published at (UTC): `2026-04-14T10:22:05.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmUATTZzuow7zUPz9KV4AbY2YgVtaRKHzbQ1Kh8w8dTeZs` | [Open](https://ipfs.io/ipfs/QmUATTZzuow7zUPz9KV4AbY2YgVtaRKHzbQ1Kh8w8dTeZs) | `2026-04-14T10:22:05.000Z` | | `3.0.0` | `QmbteLU1FCjb2zaEkLD6F97KJvgRK372sQ7SxECbWxSAQs` | [Open](https://ipfs.io/ipfs/QmbteLU1FCjb2zaEkLD6F97KJvgRK372sQ7SxECbWxSAQs) | `2026-04-14T09:51:05.000Z` | | `2.0.0` | `QmUjh8DBC6YjAhdzzumWJEssHNfzJ52sug1GE25YZ6B1BF` | [Open](https://ipfs.io/ipfs/QmUjh8DBC6YjAhdzzumWJEssHNfzJ52sug1GE25YZ6B1BF) | `2026-03-24T20:20:12.000Z` | | `1.0.0` | `QmS1ZHmucPJCo8KGaBG2e27c6jqpjFrFWoZWoVPyBPqVyJ` | [Open](https://ipfs.io/ipfs/QmS1ZHmucPJCo8KGaBG2e27c6jqpjFrFWoZWoVPyBPqVyJ) | `2026-02-18T13:13:22.000Z` | ## Application A software application, service, or website. ### Attributes | Key | Type | Recommended | Description | Values | | ----------- | ------ | ----------- | ----------------------------------------------- | ----------------------------------------------------- | | class | string | Y | Class identifier for this node | e.g. `Application`, `Service`, `Website`, `API` | | schema | string | Y | URI pointing to the application schema | - | | alias | string | Y | Display name of the application | - | | description | string | Y | Description of the application | - | | avatar | string | - | URI pointing to the application's avatar | - | | url | string | Y | URL where the application is hosted or accessed | e.g. `https://example.com`, `https://app.example.com` | | repository | string | - | URL pointing to the source code repository | e.g. `https://github.com/example/example` | | version | string | - | Current version of the application | - | | status | string | - | The current status of the application | `Active`, `Development`, `Deprecated` | ### Metadata * Schema ID: `application` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmU9v5zCHehurk6DeeWLHSDCxMT5pv9AtBRckdZP5sVK3t` * Checksum: `sha256:9c4a408c988ba327a070f517dd4d53bd34a97085a7a9aa78bca7e734ecadf1d3` * Published at (UTC): `2026-04-14T10:22:12.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmU9v5zCHehurk6DeeWLHSDCxMT5pv9AtBRckdZP5sVK3t` | [Open](https://ipfs.io/ipfs/QmU9v5zCHehurk6DeeWLHSDCxMT5pv9AtBRckdZP5sVK3t) | `2026-04-14T10:22:12.000Z` | | `3.0.0` | `Qmedeq2mJCamgmk3WqzWg1mpS7JX5rC7dBzkKwQHmvThKU` | [Open](https://ipfs.io/ipfs/Qmedeq2mJCamgmk3WqzWg1mpS7JX5rC7dBzkKwQHmvThKU) | `2026-04-14T09:51:11.000Z` | | `2.0.0` | `QmXMMavDn5CGU4ZixXDpVcQV3Z1bvd4aLvRycfHetEyUzh` | [Open](https://ipfs.io/ipfs/QmXMMavDn5CGU4ZixXDpVcQV3Z1bvd4aLvRycfHetEyUzh) | `2026-03-24T20:20:38.000Z` | | `1.0.0` | `QmSsjRkk2xZSU6yXxjgPmyKpyfQVGmUw5qLGaPkYcdPW9A` | [Open](https://ipfs.io/ipfs/QmSsjRkk2xZSU6yXxjgPmyKpyfQVGmUw5qLGaPkYcdPW9A) | `2026-02-18T13:17:52.000Z` | ## Contract An on-chain smart contract found at this node's resolved address. ### Attributes | Key | Type | Recommended | Description | Values | | ------------ | ------ | ----------- | --------------------------------------------------- | ----------------------------------------------------------- | | class | string | Y | Class identifier for this node | - | | schema | string | Y | URI pointing to the contract schema | - | | alias | string | Y | Display name of the contract | - | | description | string | Y | Brief description of what the contract does | - | | avatar | string | - | URI pointing to the contract's or owner's avatar | - | | url | string | - | URL pointing to the project's website | - | | category | string | - | The category of the contract | e.g. `defi`, `gaming`, `dao`, `utility`, `proxy`, `factory` | | license | string | - | Software license for the source code in SPDX format | e.g. `MIT`, `GPL-3.0-only`, `Apache-2.0` | | docs | string | - | Primary documentation URL for developers and users | - | | audits | string | - | URI pointing to third-party audit reports | - | | com.github | string | - | GitHub repository | - | | com.twitter | string | - | X/Twitter handle | - | | org.telegram | string | - | Telegram handle | - | ### Metadata * Schema ID: `contract` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmbioLkr8t9A35aBaqWuChJhLyvjUoYVYB3ekw3nrGAL3P` * Checksum: `sha256:5c9eaa06da290d7208ef93c834db68cba7159a726e293ea4f35daf8dfc8c4492` * Published at (UTC): `2026-04-14T10:22:14.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmbioLkr8t9A35aBaqWuChJhLyvjUoYVYB3ekw3nrGAL3P` | [Open](https://ipfs.io/ipfs/QmbioLkr8t9A35aBaqWuChJhLyvjUoYVYB3ekw3nrGAL3P) | `2026-04-14T10:22:14.000Z` | | `3.0.0` | `QmSQ2fJREtNCf24k3CmkyQ5BsfXBjpCJMq8PXpJR3wtFrN` | [Open](https://ipfs.io/ipfs/QmSQ2fJREtNCf24k3CmkyQ5BsfXBjpCJMq8PXpJR3wtFrN) | `2026-04-14T09:51:16.000Z` | | `2.0.0` | `QmSobCLXmBwTFnNnG7gSVaZxfzgpoC6frbXaYEkTTHcr1R` | [Open](https://ipfs.io/ipfs/QmSobCLXmBwTFnNnG7gSVaZxfzgpoC6frbXaYEkTTHcr1R) | `2026-03-24T20:20:41.000Z` | | `1.1.1` | `QmPq5xpj5LoCnAswuLk8ofgvpFLFNsRhJDPjvPVssCyPw1` | [Open](https://ipfs.io/ipfs/QmPq5xpj5LoCnAswuLk8ofgvpFLFNsRhJDPjvPVssCyPw1) | `2026-02-18T13:17:58.000Z` | ## Delegate A voter who has been delegated voting power. ### Attributes | Key | Type | Recommended | Description | Values | | -------------------- | ------ | ----------- | --------------------------------------------------------------- | ----------------------------------------- | | class | string | Y | Class identifier for this node | - | | schema | string | Y | URI pointing to the delegate schema | - | | alias | string | Y | Display name of the delegate | e.g. `JDoe` | | description | string | - | Profile or introduction of the delegate | e.g. `John Doe is a delegate for the DAO` | | avatar | string | - | URI pointing to the delegate's avatar | - | | url | string | - | URL pointing to the delegate's profile or website | - | | legal-name | string | - | Legal name of the delegate | e.g. `John Doe` | | statement | string | Y | The delegate's general-purpose delegate statement | - | | conflict-of-interest | string | Y | The delegate's general-purpose conflict of interest declaration | - | | forum-handle | string | Y | The delegate's default forum handle | e.g. `johndoe` | ### Metadata * Schema ID: `delegate` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmaXLcD6imQYMibAfoXaVGdkJJo6dZf9YiBTqfBQ8joeUj` * Checksum: `sha256:fe73893e724b46b7aa0b249027e301ae202d1122757d95f7b60b871be0d747b3` * Published at (UTC): `2026-04-14T10:22:16.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmaXLcD6imQYMibAfoXaVGdkJJo6dZf9YiBTqfBQ8joeUj` | [Open](https://ipfs.io/ipfs/QmaXLcD6imQYMibAfoXaVGdkJJo6dZf9YiBTqfBQ8joeUj) | `2026-04-14T10:22:16.000Z` | | `3.0.0` | `QmWP9pn2voNgNXVb2u8e5P2nRVPUbgsoVqeXB9qSL6d1HJ` | [Open](https://ipfs.io/ipfs/QmWP9pn2voNgNXVb2u8e5P2nRVPUbgsoVqeXB9qSL6d1HJ) | `2026-04-14T09:51:21.000Z` | | `2.0.0` | `Qmer3XYrtsTawrVdgpk1RwkancBR6rBxnkBn4rM7f2ShRz` | [Open](https://ipfs.io/ipfs/Qmer3XYrtsTawrVdgpk1RwkancBR6rBxnkBn4rM7f2ShRz) | `2026-03-24T20:20:42.000Z` | | `1.0.1` | `QmcHmNS3NhcrMgXmCm72bv77EKUx7inoeaS2QeWDuQGU1q` | [Open](https://ipfs.io/ipfs/QmcHmNS3NhcrMgXmCm72bv77EKUx7inoeaS2QeWDuQGU1q) | `2026-02-18T16:50:06.000Z` | | `1.0.0` | `QmaDG9p9vJjsLBtbtCPTd6tmfJUh2wuXmYQfNwrpe2qQwe` | [Open](https://ipfs.io/ipfs/QmaDG9p9vJjsLBtbtCPTd6tmfJUh2wuXmYQfNwrpe2qQwe) | `2026-02-18T13:18:03.000Z` | ## Globals A collection of globally applicable ENS record schemas. ### ENSIP-5 A group of entities that have been empowered by a larger organization to undertake some activity. Source: [https://docs.ens.domains/ensip/5](https://docs.ens.domains/ensip/5) #### Attributes | Key | Type | Recommended | Description | Values | | ----------- | ------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | | avatar | string | - | A URL to an image used as an avatar or logo | - | | description | string | - | A description of the name | - | | display | string | - | A canonical display name for the ENS name; this MUST match the ENS name when its case is folded, and clients should ignore this value if it does not (e.g. "ricmoo.eth" could set this to "RicMoo.eth") | - | | email | string | - | An e-mail address | - | | keywords | string | - | A list of comma-separated keywords, ordered by most significant first; clients that interpresent this field may choose a threshold beyond which to ignore | - | | mail | string | - | A physical mailing address | - | | notice | string | - | A notice regarding this name | - | | location | string | - | A generic location (e.g. "Toronto, Canada") | - | | phone | string | - | A phone number as an E.164 string | - | | url | string | - | A website URL | - | ### Metadata * Schema ID: `globals` * Latest version: `1.0.0` * CID: `QmVPf3nP4KC12An7v94ziWLE3ptFHXwUxFcvKEaPNXGRYd` * Checksum: `sha256:128951c9c9c6e91ee0a07b36058180a2881dc0bf33e6216b9d89fb1288e7a27c` * Published at (UTC): `2026-02-18T13:33:27.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `1.0.0 (latest)` | `QmVPf3nP4KC12An7v94ziWLE3ptFHXwUxFcvKEaPNXGRYd` | [Open](https://ipfs.io/ipfs/QmVPf3nP4KC12An7v94ziWLE3ptFHXwUxFcvKEaPNXGRYd) | `2026-02-18T13:33:27.000Z` | ## Grant A grant issued by an organization. ### Attributes | Key | Type | Recommended | Description | Values | | ----------- | ------ | ----------- | ------------------------------------------------------ | ----------------------------------------------------------- | | class | string | Y | Class identifier for this node | e.g. `Grant`, `GrantProgram` | | schema | string | Y | URI pointing to the grant schema | - | | alias | string | Y | Display name of the grant | - | | description | string | Y | Description of the grant purpose and scope | - | | avatar | string | - | URI pointing to the grant's avatar | - | | url | string | Y | URL pointing to information about the grant program | e.g. `https://www.example.com/grants/example-grant` | | status | string | Y | The current status of the grant | `Active`, `Incomplete`, `Pending`, `Completed`, `Cancelled` | | budget | string | Y | Total amount of the grant in WEI | - | | token | string | Y | The address of the ERC-20 token used to fund the grant | - | ### Metadata * Schema ID: `grant` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmXHZB371UYkDXUnAJFHHRDPFT5MgAkyNQRbS7H5qsBcEb` * Checksum: `sha256:d230860d6e3a6ab493a8fed338ea98f5f131f4bea62a1fc14846e6f625124077` * Published at (UTC): `2026-04-14T10:22:18.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmXHZB371UYkDXUnAJFHHRDPFT5MgAkyNQRbS7H5qsBcEb` | [Open](https://ipfs.io/ipfs/QmXHZB371UYkDXUnAJFHHRDPFT5MgAkyNQRbS7H5qsBcEb) | `2026-04-14T10:22:18.000Z` | | `3.0.0` | `QmRMcmfV7xHhsUu9nyKUtbXEU962vmiKSex9w8jwHwsbxh` | [Open](https://ipfs.io/ipfs/QmRMcmfV7xHhsUu9nyKUtbXEU962vmiKSex9w8jwHwsbxh) | `2026-04-14T09:51:25.000Z` | | `2.0.0` | `QmbWE66HnZytqtumkiTVt4VAsjzFkvBKosbxFJULthG5bN` | [Open](https://ipfs.io/ipfs/QmbWE66HnZytqtumkiTVt4VAsjzFkvBKosbxFJULthG5bN) | `2026-03-24T20:20:44.000Z` | | `1.0.0` | `QmdktToaxwvN31DGDEtWQ7uVKNURssW5k8oCtgceTFHemS` | [Open](https://ipfs.io/ipfs/QmdktToaxwvN31DGDEtWQ7uVKNURssW5k8oCtgceTFHemS) | `2026-02-18T13:18:08.000Z` | ## Group A group of individuals or entities with a shared purpose or responsibility. ### Attributes | Key | Type | Recommended | Description | Values | | ------------- | ------ | ----------- | ----------------------------------------------------------- | ----------------------------------------------------------------------- | | class | string | Y | Class identifier for this node | e.g. `Group`, `Committee`, `Council`, `Workgroup`, `Team`, `Department` | | schema | string | Y | URI pointing to the group schema | - | | alias | string | Y | Display name of the group | - | | avatar | string | Y | URI pointing to the group's avatar | - | | description | string | Y | Short description of the group's purpose and responsibility | - | | url | string | Y | URL pointing to information about the group | e.g. `https://www.example.com/groups/example-group` | | lead | string | Y | ENS name or address of the group leader | - | | lead-title | string | - | Title or role of the group leader | e.g. `Lead Steward`, `Chair`, `Manager`, `Owner` | | members-title | string | - | Title or role of the group members | e.g. `Member`, `Steward`, `Contributor`, `Participant` | ### Metadata * Schema ID: `group` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmPy7ZXw7EDJmZ8pPG4BGFHvSfy5QQ17Ph2Z58uWa3PhBJ` * Checksum: `sha256:b64dc02974626beb73c7f0a04f22ac07645bfed2b38485315cd895645d208f41` * Published at (UTC): `2026-04-14T10:22:20.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmPy7ZXw7EDJmZ8pPG4BGFHvSfy5QQ17Ph2Z58uWa3PhBJ` | [Open](https://ipfs.io/ipfs/QmPy7ZXw7EDJmZ8pPG4BGFHvSfy5QQ17Ph2Z58uWa3PhBJ) | `2026-04-14T10:22:20.000Z` | | `3.0.0` | `QmU3UeqcMQiED7mydG55V6zFVNnWcTrcVBcxmajra6s3qF` | [Open](https://ipfs.io/ipfs/QmU3UeqcMQiED7mydG55V6zFVNnWcTrcVBcxmajra6s3qF) | `2026-04-14T09:51:52.000Z` | | `2.0.0` | `QmRMx99kKSPFttqZd8iHVBng4gtvNX7AAGfNjm9BTbxQ6j` | [Open](https://ipfs.io/ipfs/QmRMx99kKSPFttqZd8iHVBng4gtvNX7AAGfNjm9BTbxQ6j) | `2026-03-24T20:20:45.000Z` | | `0.1.4` | `QmYJieM3KXTeDhrwcFr3cMSi1LVWofxjCVkMzv1HTuoYSw` | [Open](https://ipfs.io/ipfs/QmYJieM3KXTeDhrwcFr3cMSi1LVWofxjCVkMzv1HTuoYSw) | `2026-02-18T13:18:14.000Z` | ## Organization A legal or organizational entity. ### Attributes | Key | Type | Recommended | Description | Values | | ----------- | ------ | ----------- | -------------------------------------------------- | --------------------------------------------------------------- | | class | string | Y | Class identifier for this node | e.g. `Organization`, `Foundation`, `OPCo`, `DAO`, `DUNA`, `LLC` | | schema | string | Y | URI pointing to the organization schema | - | | alias | string | Y | Display name of the organization | - | | avatar | string | - | URI pointing to the organization's avatar | - | | description | string | Y | Description of the organization | - | | url | string | Y | URL pointing to information about the organization | e.g. `https://www.example.com/` | ### Metadata * Schema ID: `org` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmaJ6HSdKy7fLsJy9Sk8xP6LW2CagLUwLgDm5KtKLPTwnp` * Checksum: `sha256:7d798099710c2d3eeb036613b1448df6a1fe3b0431da62e616525a6d5793f200` * Published at (UTC): `2026-04-14T10:22:22.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmaJ6HSdKy7fLsJy9Sk8xP6LW2CagLUwLgDm5KtKLPTwnp` | [Open](https://ipfs.io/ipfs/QmaJ6HSdKy7fLsJy9Sk8xP6LW2CagLUwLgDm5KtKLPTwnp) | `2026-04-14T10:22:22.000Z` | | `3.0.0` | `QmVuUd67YEGWQ3vCQFCRRKsUBvRBDHksHPo8vfvX3Y9eLX` | [Open](https://ipfs.io/ipfs/QmVuUd67YEGWQ3vCQFCRRKsUBvRBDHksHPo8vfvX3Y9eLX) | `2026-04-14T09:51:56.000Z` | | `2.0.0` | `QmVUKLNY5RiMUa7dYk2DvJBhBusTZWtNVnk1TRoJBHC3C2` | [Open](https://ipfs.io/ipfs/QmVUKLNY5RiMUa7dYk2DvJBhBusTZWtNVnk1TRoJBHC3C2) | `2026-03-24T20:20:46.000Z` | | `0.1.8` | `QmfPD2L38hREq356GxhMkyMJMECVwRAxm6dEJZh3bpPAdd` | [Open](https://ipfs.io/ipfs/QmfPD2L38hREq356GxhMkyMJMECVwRAxm6dEJZh3bpPAdd) | `2026-02-18T13:18:19.000Z` | ## Person A person. ### Attributes | Key | Type | Recommended | Description | Values | | ----------- | ------ | ----------- | ----------------------------------------------- | -------------------------------------------------------------------------------------- | | class | string | Y | Class identifier for this node | e.g. `Person`, `Human`, `Signer`, `Signatory`, `Officer`, `Employee`, `Secretary` | | schema | string | Y | URI pointing to the person schema | - | | alias | string | Y | Display name of the person | - | | description | string | - | Profile or introduction of the person | e.g. `John Doe is a software engineer at Example Inc.` | | avatar | string | - | URI pointing to the person's avatar | - | | legal-name | string | Y | Legal name of the person | e.g. `John Doe` | | title | string | Y | Title or role of the person | e.g. `CEO`, `CFO`, `Director`, `Company Secretary`, `Treasurer`, `Officer`, `Employee` | | email | string | - | Email address of the person | e.g. `john.doe@example.com` | | phone | string | - | Phone number of the person | e.g. `+1234567890` | | mail | string | - | Mailing address where the person can be reached | e.g. `123 Main St, Anytown, USA` | ### Metadata * Schema ID: `person` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmSHkLhbPF96jYwYq52TmmvQNSCFijhZWYziRqgimBQ9Na` * Checksum: `sha256:2f4b6ec6f6e2f868c1e5e0a350c2b40e495d9888ca25eaa5ed8d46f7c38d912f` * Published at (UTC): `2026-04-14T10:22:24.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmSHkLhbPF96jYwYq52TmmvQNSCFijhZWYziRqgimBQ9Na` | [Open](https://ipfs.io/ipfs/QmSHkLhbPF96jYwYq52TmmvQNSCFijhZWYziRqgimBQ9Na) | `2026-04-14T10:22:24.000Z` | | `3.0.0` | `QmZUAK5JkWchnbU6TMYRQhwDRFjSfqEAW2AiZpGEQ1weNy` | [Open](https://ipfs.io/ipfs/QmZUAK5JkWchnbU6TMYRQhwDRFjSfqEAW2AiZpGEQ1weNy) | `2026-04-14T09:52:01.000Z` | | `2.0.0` | `QmU5KqV4PAPgejjKWSg4LAbz1R56aVRMU6MQK21zaSChJZ` | [Open](https://ipfs.io/ipfs/QmU5KqV4PAPgejjKWSg4LAbz1R56aVRMU6MQK21zaSChJZ) | `2026-03-24T20:20:48.000Z` | | `1.0.0` | `QmYZNmUKP751Vfj2ZEVwXawvGto1zsmi4oiTsnunzx6dsp` | [Open](https://ipfs.io/ipfs/QmYZNmUKP751Vfj2ZEVwXawvGto1zsmi4oiTsnunzx6dsp) | `2026-02-18T13:18:24.000Z` | ## Treasury Funds and assets managed by a collective of individuals or entities. ### Attributes | Key | Type | Recommended | Description | Values | | ----------- | ------ | ----------- | ----------------------------------- | ------------------------ | | class | string | Y | Class identifier for this node | e.g. `Treasury`, `Vault` | | schema | string | Y | URI pointing to the treasury schema | - | | alias | string | Y | Display name of the treasury | - | | description | string | Y | Description of the treasury | - | ### Metadata * Schema ID: `treasury` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmceYfvRNjdZN3KD7sA3NfCHHBf3jVekDpLQCD39omdykt` * Checksum: `sha256:39dd6a379113b1126cec96b39c5021d3c4ac5e47e8c8f46016cefb88625fa969` * Published at (UTC): `2026-04-14T10:22:27.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmceYfvRNjdZN3KD7sA3NfCHHBf3jVekDpLQCD39omdykt` | [Open](https://ipfs.io/ipfs/QmceYfvRNjdZN3KD7sA3NfCHHBf3jVekDpLQCD39omdykt) | `2026-04-14T10:22:27.000Z` | | `3.0.0` | `QmdMnrVK98zghFj8y5W8y31MuLc2feo4AzNfRbAWDsRTG9` | [Open](https://ipfs.io/ipfs/QmdMnrVK98zghFj8y5W8y31MuLc2feo4AzNfRbAWDsRTG9) | `2026-04-14T09:52:06.000Z` | | `2.0.0` | `QmXrSdULaxgq1wtKZakamPyaUEpkpSsD7dfaWmfuwKsBrG` | [Open](https://ipfs.io/ipfs/QmXrSdULaxgq1wtKZakamPyaUEpkpSsD7dfaWmfuwKsBrG) | `2026-03-24T20:20:49.000Z` | | `1.0.0` | `QmcrTCuN3FmpTP66LzQqDtaxmK7j5wMNtHKQEjE2SCLUZr` | [Open](https://ipfs.io/ipfs/QmcrTCuN3FmpTP66LzQqDtaxmK7j5wMNtHKQEjE2SCLUZr) | `2026-02-18T13:18:28.000Z` | ## Wallet A wallet for holding or managing assets. ### Attributes | Key | Type | Recommended | Description | Values | | ----------- | ------ | ----------- | ----------------------------------- | ------------------------ | | class | string | Y | Class identifier for this node | e.g. `Wallet`, `Account` | | schema | string | Y | URI pointing to the wallet schema | - | | alias | string | Y | Display name of the wallet | - | | description | string | Y | Description of the wallet's purpose | - | ### Metadata * Schema ID: `wallet` * Latest version: `3.0.1` * Source: [https://github.com/0xLighthouse/ens-metadata](https://github.com/0xLighthouse/ens-metadata) * CID: `QmNhNg4LFsWyLNEXRzotmAmzyo9cWYaWzxGc4gLgrxHeEL` * Checksum: `sha256:9d3d6d06b5e3a1e93838e16debc5a0a427dd587fec2a2cfb7e21e2b59db8ea61` * Published at (UTC): `2026-04-14T10:22:29.000Z` ### Version history | Version | CID | IPFS | Published at (UTC) | | ---------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | -------------------------- | | `3.0.1 (latest)` | `QmNhNg4LFsWyLNEXRzotmAmzyo9cWYaWzxGc4gLgrxHeEL` | [Open](https://ipfs.io/ipfs/QmNhNg4LFsWyLNEXRzotmAmzyo9cWYaWzxGc4gLgrxHeEL) | `2026-04-14T10:22:29.000Z` | | `3.0.0` | `QmRupTL9ETkjCywt5KrZpNsVKaabaJMMXGumTCYwP96v3n` | [Open](https://ipfs.io/ipfs/QmRupTL9ETkjCywt5KrZpNsVKaabaJMMXGumTCYwP96v3n) | `2026-04-14T09:52:11.000Z` | | `2.0.0` | `QmWPw8Mj4GrMDdGPnsDkPsjgv6RTQXLooi9rNX4LwA2BAV` | [Open](https://ipfs.io/ipfs/QmWPw8Mj4GrMDdGPnsDkPsjgv6RTQXLooi9rNX4LwA2BAV) | `2026-03-24T20:20:51.000Z` | | `1.0.0` | `QmTdnHbDob1Cf7Uy1dYmrRezyETvf19QWcaNpFP3WSe2JD` | [Open](https://ipfs.io/ipfs/QmTdnHbDob1Cf7Uy1dYmrRezyETvf19QWcaNpFP3WSe2JD) | `2026-02-18T13:18:32.000Z` | ## Resources * View the [draft ENSIP](https://github.com/ensdomains/ensips/pull/64) to provide feedback * Read the working group [Wiki](https://stealth-respect-4e8.notion.site/Organizational-Metadata-on-ENS-2313a8375c77801dad2ce5b513ce9450?pvs=74) to join meetins and workshops. * Join our public [Telegram](https://t.me/+wh4CCm74pr04NGZk) * Explore the [metadata manager](https://ens-metadata-interface.vercel.app/) to start classifying your subnames. * See the [changelog](https://github.com/0xLighthouse/ens-metadata/blob/main/CHANGELOG.md) for what's shipped in each release. ## How schemas work ENS metadata is built on three layers: a class label, a schema definition, and the attributes themselves. Together they let any ENS node declare what it represents and carry structured, machine-readable metadata about it. ### Class: the label Any ENS node can set a `class` text record to declare what role the node plays. The value is pascal case and should be one of the recognised class identifiers (such as `Treasury`, `Contract`, `Person`, `Agent`, `Org`, or `Delegate`), though custom values are allowed for specialised use cases. ``` treasury.supercooldao.eth └── class = "Treasury" ``` This single record is enough for indexers and governance tools to recognise the node's purpose. It answers the question "what is this node?" ### Schema: the structure A node can also set a `schema` text record pointing to a JSON schema. The schema declares which additional metadata attributes the node is expected to carry, what each attribute means, and which ones are required. ``` treasury.supercooldao.eth ├── class = "Treasury" └── schema = "ipfs://QmXrSd..." ``` Schemas are published to IPFS so they are immutable and available for the long term. They follow the [JSON Schema 2020-12](https://json-schema.org/draft/2020-12/json-schema-core) specification, and describe a flat object where every property is of type `string`, matching the ENS text record model. A minimal schema looks like this: ```json { "$id": "https://github.com/0xLighthouse/ens-node-metadata/.../treasury/2.0.0", "title": "Treasury", "description": "Funds and assets managed by a collective of individuals or entities.", "type": "object", "properties": { "class": { "type": "string", "default": "Treasury", "description": "Class identifier for this node" }, "schema": { "type": "string", "format": "uri", "description": "URI pointing to the treasury schema" }, "name": { "type": "string", "description": "Display name of the treasury" }, "description": { "type": "string", "description": "Description of the treasury" } }, "required": ["class", "schema"] } ``` Interfaces like [ensmetadata.app](https://ensmetadata.app) read the schema to determine which fields to show, which are required, and what descriptions and examples to display when editing a node's records. ### Attributes: the data Once a schema is selected, the node can be populated with the attributes it defines. Each attribute is stored as an ordinary ENS text record on the node's resolver. ``` treasury.supercooldao.eth ├── class = "Treasury" ├── schema = "ipfs://QmXrSd..." ├── name = "Main DAO Treasury" └── description = "Primary treasury managed by the governor contract" ``` Clients reading the node can look up the schema to understand what each record means, validate the data, and present it in a structured way. Some attributes support parameterized key names, which allow a single attribute to hold multiple entries as either a dictionary (map) or an ordered list (array). For example, an agent might publish `services[web]`, `services[mcp]`, and `services[a2a]` as separate records under one parameterized key. See the [parameterized keys guide](/guides/parameterized-keys) for details. ### Custom schemas The standard schemas listed in the [schema reference](/schemas/agent) cover the most common node types. Anyone is free to create and publish additional schemas for use cases not covered by the standard set. Custom schemas follow the same JSON Schema format and can be published to IPFS for immutability or hosted over HTTPS if mutability is preferred. ### Where to go next The [schema reference](/schemas/agent) documents every attribute available for each node type. The [guides](/guides/agents) walk through applying schemas to real scenarios, from setting up a delegate profile to representing an entire organization's on-chain structure. ## Setting up metadata for your AI agent This guide explains how to publish your AI agent's identity and capabilities as ENS metadata, turning an ENS name into a permissionless, registry-free discovery point for your agent. It complements [ERC-8004](https://eips.ethereum.org/EIPS/eip-8004), and the on-chain records described here can stand alone or point at an existing ERC-8004 registration file via `agent-uri`. ### Step 1: Choose the right ENS node Agent records should live on the ENS name you want to be your agent's canonical identity. Indexers find agents by scanning ENS text records on-chain, so the name you choose here is the address consumers will resolve when they look your agent up. Two distinct addresses are involved in this step, and it's worth being clear about both before proceeding. 1. **The address the ENS name resolves to should be the address controlled by the agent.** This is the agent's on-chain identity: any transaction or signature coming from this address is understood to originate from the agent itself. The ETH address record on the node should be set to this address. 2. **The owner or manager of the ENS name controls who can update records and create subnames.** This can be set to either the agent's own address (giving the agent the ability to update its own records autonomously) or to a user's address (so the operator retains control and can update the agent's records on its behalf). With those two decisions made, you can proceed: 3. **Pick the ENS name (or subname) the agent will be known by.** This might be a top-level name like `myagent.eth`, or a dedicated subname like `agent.alice.eth`. Subnames are recommended when an operator runs multiple agents, since each subname gets its own independent set of records. ### Step 2: Add your agent information 1. Open [ensmetadata.app](https://ensmetadata.app), connect the wallet that controls the ENS name you want to use, and navigate to the node you chose in Step 1. 2. Under `Schema`, select `Agent`. This automatically sets the `class` and `schema` records and reveals the recommended fields. 3. Fill in your agent's information. The most common fields appear automatically; to add additional fields, choose "+ Add Optional Field" and select from the list. | Record key | What to put | | -------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `name` | The display name shown in agent directories and clients | | `description` | A short natural-language description of what the agent does | | `avatar` | URI pointing to the agent's avatar image | | `agent-uri` | *(Optional)* URI pointing to an ERC-8004 registration file, if the agent has one | | `agent-wallet` | The address where the agent receives payments (corresponds to the `agentWallet` reserved key in the ERC-8004 Identity Registry) | | `x402-support` | `"true"` if the agent accepts [x402](https://x402.org) payments | | `active` | `"true"` or `"false"` — whether the agent is currently operational | The agent schema follows a **layering principle**: stable, important metadata lives directly on the ENS name where it's always available and costs nothing to read; verbose or frequently-changing data lives in the registration file pointed to by `agent-uri`. As a rule of thumb, publish `name`, `description`, `avatar`, `agent-wallet`, and `x402-support` directly on the ENS name, and leave large service catalogues, evolving capability details, and frequently-flipped status flags to the registration file. A minimal agent record after this step looks like: ``` myagent.eth ├── class = "Agent" ├── schema = "" ├── name = "My Agent" ├── description = "A natural-language description of what this agent does" ├── avatar = "https://example.com/avatar.png" ├── agent-wallet = "0x..." └── x402-support = "true" ``` Consumers can now resolve all of these with a standard ENS text record lookup. ### Step 3: Advertise services Services are how clients discover what your agent actually does and where to call it. The agent schema supports two approaches that can coexist. **As a single index URI** using the `services` field, pointing to a JSON payload that enumerates all services. This mirrors the `services` array in an ERC-8004 registration file and is convenient when services change frequently or are too verbose to publish individually: ``` myagent.eth └── services = "https://example.com/services.json" ``` **As individual parametrised records** using `services[name]`, where each entry maps a service name to its endpoint. This keeps service data on-chain and directly readable without fetching an external file: ``` myagent.eth ├── services[web] = "https://web.agentxyz.com/" ├── services[mcp] = "https://mcp.agentxyz.com/" └── services[a2a] = "https://agent.example/.well-known/agent-card.json" ``` Each value can be a direct endpoint URI, or it can point to a JSON descriptor if the service requires more detail (authentication schemes, input/output formats, etc.). The `data:` and `cbor:` URI prefixes are also supported for embedding descriptors inline rather than hosting them externally. For now, adding parametrised entries is a manual process in [ensmetadata.app](https://ensmetadata.app): 1. With the node selected, click the "+ Record" button at the bottom of the metadata editing drawer. 2. Enter the parametrised key exactly as shown (for example, `services[mcp]`), with the service name in square brackets. 3. Paste the endpoint URI as the value, and save the changes. 4. Repeat for each service the agent exposes, then broadcast the transaction. Clients should treat the bare `services` record as a fallback value that gets queried when they can't find a direct `services[name]` entry on the ENS name. ### Step 4: Cross-registry references and trust models These two array fields are optional but recommended for agents that participate in on-chain registries or advertise verification mechanisms. Both are added through the same "+ Record" flow as parametrised services in Step 3. **Cross-registry references.** Agents registered with ERC-8004 or other on-chain registries can advertise those registrations using the `registrations[*]` array field. Each entry follows [CAIP-19 format](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-19.md), since ERC-8004 identities are modelled as ERC-721 tokens (`{namespace}:{chainId}/{tokenStandard}:{identityRegistry}/{agentId}`): ``` myagent.eth ├── registrations[0] = "eip155:1/erc721:0x742.../22" └── registrations[1] = "eip155:8453/erc721:0x.../7" ``` This makes the ENS name a single place to find every registration the agent holds, regardless of which chains or contracts they span. **Trust models.** The `supported-trust[*]` array advertises which trust verification mechanisms the agent supports — corresponding to the `supportedTrust` field in an ERC-8004 registration file: ``` myagent.eth ├── supported-trust[0] = "reputation" └── supported-trust[1] = "tee-attestation" ``` ### How agents are discovered Once your records are live, any consumer can find and read them without a central directory. The discovery flow looks like this: 1. **Index `TextChanged` events on the ENS Public Resolver**, filtering for records where the key is `class` and the value is `"Agent"`. Alternatively, index all nodes that set a `schema` record pointing to a recognised agent schema. 2. **Resolve the agent's records on each matching node.** Read the text records listed in the schema — or all text records if you want the full picture — including `name`, `description`, `agent-wallet`, parametrised `services[*]` entries, and `registrations[*]`. 3. **Fall back to the registration file only when needed.** If the data the consumer wants isn't published directly on the ENS name, fetch the JSON file at `agent-uri` and read it from there. This gives any consumer a live, permissionless view of every agent that has opted in to on-chain discoverability. ### Related * [Agent schema](/schemas/agent) * [ERC-8004 specification](https://eips.ethereum.org/EIPS/eip-8004) ## Attesting social attributes with ENS This guide explains how to attach a compact, verifiable attestation to an ENS name. Supported platforms today are: * X (`com.x`) * Telegram (`org.telegram`) The same scheme applies to any platform with a server-verifiable login, and extends to other private attributes (OAuth subject ids, email addresses, and so on). ### How it works An attestation is a signed record written to an ENS text record by the name's owner. Three pieces are involved: 1. **The attester** — a backend service that verifies that you own your wallet (via SIWE) and that you are able to log into your social media account (via OAuth / login widget), then signs the attestation with its key. 2. **The attestation** — a CBOR-encoded envelope with an EIP-191 signature over a reconstructable DAG-CBOR payload (platform, handle *or* private uid, ENS name, owner address, timestamp). The attester signs; the name owner publishes on-chain. 3. **The text record** — a parameterized key on the ENS name (for example `attestations[com.x][atst.lighthousegov.eth]`), holding the attestation envelope. ### What gets written on-chain The user's social media handle is written to their ENS name as a text record. The attestation is written as a separate text record, parameterized by the platform and the attester's ENS name. ```sh alice.eth ├── com.x = "alice" ├── attestations[com.x][attester.eth] = "0xda61747374..." ├── org.telegram = "alice" └── attestations[org.telegram][attester.eth] = "0xda61747374..." ``` ### Verifying the attestation #### SDK verification Read the text record, decode the attestation, and verify the attester signature and ownership using the SDK: ```ts import { createPublicClient, http } from 'viem' import { mainnet } from 'viem/chains' import { addEnsContracts } from '@ensdomains/ensjs' import { attestationVerifier } from '@ensmetadata/sdk' const client = createPublicClient({ chain: addEnsContracts(mainnet), transport: http(), }).extend(attestationVerifier({ maxAge: 90 * 24 * 60 * 60, // optional: reject attestations older than 90 days })) // Handle attestation — verifies the public handle on the `com.x` text record. const handleResult = await client.verifyHandleAttestation({ name: 'alice.eth', platform: 'com.x', attester: 'atst.lighthousegov.eth', // optional, defaults to this }) // UID attestation — verifies a private uid you already know (e.g. from OAuth). const uidResult = await client.verifyUidAttestation({ name: 'alice.eth', platform: 'com.x', uid: '12345', attester: 'atst.lighthousegov.eth', // optional, defaults to this }) ``` #### Manual verification To verify an attestation that has been published to an ENS name, first collect the following details: 1. The full ENS name (`name.eth`) or subname (`alice.name.eth`) under which the attestation was published. 2. The address of the manager of the ENS name (or if the address is a wrapped name, the address of the owner). 3. The ENS name of the attester, and the attestation record itself. 4. Look up which address the attester's ENS name resolves to. This is the signer's address. ##### Attestation format Attestations are encoded using CBOR format, identified by tag `1635021684` (`0x61747374`, the ASCII encoding of "`atst`"), using the following structure: ```sh Tag(1635021684) [ 2, // envelope version , // timestamp , // signature — EIP-191 over keccak256(payload) ] ``` ##### Payload The payload for the signature is encoded using [DAG-CBOR](https://www.npmjs.com/package/@ipld/dag-cbor). The payload can be recreated using the following key names, and the values from the steps listed above: | Field | Key | Description | | --------- | --- | ---------------------------------------------------------------------------------------- | | Name | `n` | The ENS name the attestation is bound to. | | Address | `a` | The wallet address that manages the ENS name. | | Platform | `p` | Reverse-DNS platform identifier, e.g. `com.x` or `org.telegram` | | Handle | `h` | The value of the text record matching the platform namespace. (e.g. `alice` for `com.x`) | | Issued at | `t` | The timestamp from the attestation. | Encode the above fields as canonical DAG-CBOR, then hash the bytes with keccak256 to get the digest the attester signed. Recover the signer from the digest plus the signature and compare to the address the attester's ENS name currently resolves to. ##### Private UID attestations A non-public user identifier (like the stable id exposed during an OAuth flow, or a Telegram numeric id) can also be attested and published to the user's ENS name without revealing the UID itself. Consumers who already know the user's UID can verify the attestation; those who don't cannot recover it from the record. UID attestations are published to the user's ENS name under the `uid` record, parameterized by the platform and the attester's ENS name. ```sh alice.eth ├── uid[com.x][attester.eth] = "0xda61747374..." └── uid[org.telegram][attester.eth] = "0xda61747374..." ``` These attestations follow the same format as the handle variant above; the payload differs in one field: | Field | Key | Description | | --------- | --- | --------------------------------------------------------------- | | Name | `n` | The ENS name the attestation is bound to. | | Address | `a` | The wallet address that manages the ENS name. | | Platform | `p` | Reverse-DNS platform identifier, e.g. `com.x` or `org.telegram` | | UID | `u` | The non-public user identifier. (e.g. `12345` for `com.x`) | | Issued at | `t` | The timestamp from the attestation. | Using the above details from the user's ENS name, plus the private UID received from an OAuth flow or another out-of-band method, you can regenerate the signed payload and verify the attestation. ### Related * [`@ensmetadata/sdk` reference](/sdk/documentation) * [Attestation CDDL schema](https://github.com/0xLighthouse/ens-metadata/blob/main/packages/sdk/schemas/attestation.cddl) * [Attester worker source](https://github.com/0xLighthouse/ens-metadata/tree/main/workers/attester) * [Parameterized keys guide](/guides/parameterized-keys) ## Filling out your delegate information This guide explains how to publish your delegate information as ENS metadata, turning your ENS name into a single source of truth for your online delegate identity. ### Step 1: Choose the right ENS node Delegate records should live on the ENS name that **resolves to the address holding your voting power**. Governance tools trace delegation on-chain from token balances to an address, then reverse-resolve that address to find your ENS name. If your metadata records are on a different name/subname, they may be hard to find. Here are step-by-step instructions on how to properly set up your delegate information, using [ensmetadata.app](https://ensmetadata.app) and [app.ens.domains](https://app.ens.domains) to directly query on-chain data. 1. **Identify the address that holds your voting power.** This is the address you use to vote on proposals. 2. **Check which ENS name resolves to that address.** If you already have an ENS name configured, open [app.ens.domains](https://app.ens.domains) and search for your name. The name whose forward record (the `ETH address` record) points to your voting address is the correct node to use. If you don't yet have an ENS name configured, you can make one now. 3. **Confirm the reverse record matches.** For governance tools to find you, the address should also have a primary ENS name set, and that primary name should be the same node you are editing. If the reverse record is missing or points somewhere else, set it in the ENS app under *My Names → Set as primary ENS*. 4. **Use a subname if you want to keep delegate data separate.** Many users prefer to isolate delegate metadata on a dedicated subname such as `delegate.alice.eth` and point its address record at their voting wallet. This keeps your main name's records uncluttered. Just make sure the subname's address record and reverse record both point at the voting address. ### Step 2: Add your delegate information 1. You are now ready to add your delegate information via ensmetadata.app. Connect your wallet, and navigate to the node you identified in step 2 above. 2. Under `Schema`, select `Delegate`. 3. The most common fields will appear automatically. To add additional fields, choose "+ Add Optional Field" and select from the list. | Record key | What to put | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | | `display-name` | The name or username you want shown in delegate lists | | `legal-name` | *(Optional)* Your real name, if you want to make it public and it differs from your display name | | `statement` | Your default delegate statement: your philosophy, priorities, and why token holders should delegate to you | | `conflict-of-interest` | Your default conflict-of-interest declaration | | `forum-handle` | Your default governance forum username | The `statement`, `conflict-of-interest`, and `forum-handle` fields act as fallbacks that any DAO can read when you haven't written something specific for them. ### Step 3: Add DAO-specific statements and conflict-of-interest If you delegate in multiple DAOs, you'll usually want a different statement and conflict-of-interest declaration for each one. The delegate schema supports this through parametrised keys, where the parameter is the DAO's own ENS name. Add one record per DAO you participate in: ``` delegate.alice.eth ├── statement[uniswap.eth] = "My Uniswap priorities are..." ├── statement[ens.eth] = "For ENS governance I focus on..." ├── conflict-of-interest[uniswap.eth] = "I hold positions in..." ├── conflict-of-interest[ens.eth] = "I am a contributor to..." ├── forum-handle[uniswap.eth] = "alice" └── forum-handle[ens.eth] = "alice576" ``` For now, adding these variants is a manual process: 1. With the node selected, click the "+ Record" button at the bottom of the metadata editing drawer. 2. Enter the parametrised key exactly as shown (for example, `statement[ens.eth]`) with the DAO's full ENS name in square brackets. 3. Paste your statement or declaration as the value for that record, and save the changes. 4. Repeat for each DAO you are active in, and then broadcast the transaction to update your records. ### Discovering delegates Once records are live, any governance tool can find and display them. Typical on-chain voting systems make it possible to discover a list of all addresses that currently hold voting power. Each of those addresses can then be reverse-resolved to its primary ENS name, connecting the on-chain voting power to the delegate records published under that name. ### Related * [Delegate schemas](/schemas/delegate) ## Representing your organization with ENS metadata This guide explains how to use a single ENS name as the canonical, on-chain index of everything an organization controls, including legal entities, officers, treasuries, smart contracts, and internal working groups. The end result is a tree of subnames under your organization's root ENS name, where each subname resolves to a real on-chain address and carries structured metadata describing its role. The finished structure looks something like this: ``` supercooldao.eth (Org) ├── treasury.supercooldao.eth (Treasury) ├── ops.supercooldao.eth (Wallet) ├── governor.supercooldao.eth (Contract) ├── token.supercooldao.eth (Contract) ├── duna.supercooldao.eth (Legal entity) │ ├── ceo.duna.supercooldao.eth (Person) │ ├── secretary.duna.supercooldao.eth (Person) │ ├── agent.duna.supercooldao.eth (Person) │ └── wallet.duna.supercooldao.eth (Wallet) └── grants.supercooldao.eth (Group) └── wallet.grants.supercooldao.eth (Wallet) ``` The root name is the trust anchor. Whoever controls it is the entity asserting that every subname below belongs to the organization. ### Step 1: Configure the organization's root ENS name Pick the ENS name you want to be the organization's public identity (`supercooldao.eth` in the examples below). This is the name that anchors the entire namespace you're about to build. Two distinct addresses are involved in this step, and it's worth being clear about both before proceeding. 1. **The owner or manager of the ENS name** is the address with the authority to update records and create subnames under the root. This address controls the namespace itself, so it should reflect how the organization actually makes decisions. A multisig, governor contract, or other governance-controlled address is appropriate here. The authority to issue subnames and edit records flows down from this address to everything underneath it. 2. **The address the root name resolves to** represents the organization's on-chain identity. Any signature or transaction originating from this address is understood to be an official, top-level action by the organization, so it should be an address that genuinely speaks for the organization. Both of these can be the same address, or they can be separate. For example, an organization might use a governance-controlled multisig to manage the namespace while pointing the address record at a different address that represents the organization's identity. What matters is that both choices are intentional: the first address controls the authority to update records, and the second represents the organization to the outside world. ### Step 2: Apply the Org schema to the root Setting the organization-level metadata on the root name lets indexers recognise the name as an organization and display it sensibly. 1. Open [ensmetadata.app](https://ensmetadata.app), connect the wallet that controls the root name, and navigate to it. 2. Under `Schema`, select `Organization`. This automatically sets `class = "Organization"` and the `schema` record. 3. Fill in the recommended fields and broadcast the transaction. | Record key | What to put | | ------------- | -------------------------------------------------------------------------- | | `class` | The organization's type, usually `DAO` | | `name` | Display name of the organization | | `description` | Short description of what the organization does | | `url` | Canonical URL for the organization (homepage, docs site, governance forum) | | `avatar` | URI to a logo or avatar image | After this step the root carries enough metadata for any consumer to identify it: ``` supercooldao.eth ├── class = "DAO" ├── schema = "" ├── name = "Super Cool DAO" ├── description = "A public-goods infrastructure DAO" └── url = "https://supercool.dao" ``` The root represents the DAO as a whole. It is the governance-controlled namespace from which everything else hangs. If the DAO has a legal wrapper whose authority sits beneath the DAO, it probably makes more sense for that entity to be represented as a subname beneath the root level. ### Step 3: Plan the subname structure Before creating any subnames, decide on a naming convention and stick to it. Subnames are how the rest of the world will refer to the constituent parts of the organization, so they should be human-readable and predictable. A few rules of thumb: * **One subname per real-world thing.** Don't conflate a treasury and a governor contract into a single node. Each gets its own subname so each can carry the right schema and the right address. * **Use short, descriptive labels.** `treasury.dao.eth`, `governor.dao.eth` , etc. * **Set each subname's address record to the address it represents.** A treasury subname points at the treasury multisig, a contract subname points at the deployed contract, an officer subname points at an address that individual controls. The metadata on the subname describes what's at that address; the address record itself is what makes the subname resolvable. * **Issue subnames from the wallet that controls the parent name.** This preserves the chain of authority. Every subname can be traced back to the organization's root, and consumers can trust that the parent has explicitly claimed each one. Subnames can be created and edited in [ensmetadata.app](https://ensmetadata.app) wherever supported, or in [app.ens.domains](https://app.ens.domains). Records on each subname are then edited in ensmetadata.app exactly like any other node. ### Step 4: Add treasury, wallet, and contract subnames These three node types cover most of an organization's on-chain footprint. The pattern for each is the same: create a subname, point its address record at the relevant on-chain address, then apply the right schema in ensmetadata.app and fill in the fields. If you have many contracts to claim, it might be worthwhile to group them under a single subname (perhaps `contracts.dao.eth`). #### Treasuries Use the `Treasury` schema for any address whose primary purpose is holding and disbursing assets under collective control, such as main treasuries, grant vaults, and escrow vaults. The address record should point at the multisig or vault contract that holds the funds. | Record key | What to put | | ------------- | --------------------------------------------- | | `class` | `Treasury` (or `Vault`) | | `name` | Display name (e.g. `Main Treasury`) | | `description` | What this treasury is for and who controls it | ``` treasury.supercooldao.eth ├── address record → 0x... (governance multisig) ├── class = "Treasury" ├── name = "Main DAO Treasury" └── description = "Primary treasury managed by the governor contract" ``` Use additional subnames (`grants-treasury.dao.eth`, `escrow.dao.eth`) when an organization wants to separate funds by purpose. #### Operational wallets Use the `Wallet` schema for hot wallets, operational EOAs, or smaller-purpose accounts that aren't full treasuries. The schema is intentionally simple, and just lets you label and describe the address. | Record key | What to put | | ------------- | ---------------------------- | | `class` | `Wallet` (or `Account`) | | `name` | Display name | | `description` | What this wallet is used for | ``` ops.supercooldao.eth ├── address record → 0x... (operations EOA) ├── class = "Wallet" ├── name = "Operations Hot Wallet" └── description = "Day-to-day operational expenses, topped up monthly from treasury" ``` #### Smart contracts Use the `Contract` schema for any deployed smart contract the organization wants to claim, such as governor contracts, token contracts, staking contracts, factories, and periphery contracts. The address record points at the deployed contract address. | Record key | What to put | | ------------------- | ------------------------------------------------------------------------- | | `class` | `Contract` | | `name` | Display name (e.g. `Governor`, `Token`) | | `description` | What the contract does | | `category` | *(Optional)* `defi`, `gaming`, `dao`, `utility`, `proxy`, `factory`, etc. | | `license` | *(Optional)* SPDX identifier for the source code license | | `docs` | *(Optional)* Primary documentation URL | | `compiled-metadata` | *(Optional)* URI to the compiler metadata file | | `audits` | *(Optional)* URI or inline data for third-party audit reports | ``` governor.supercooldao.eth ├── address record → 0x... (Governor contract) ├── class = "Contract" ├── name = "Super Cool Governor" ├── description = "OpenZeppelin Governor used for on-chain proposals and voting" ├── category = "dao" └── docs = "https://docs.supercool.dao/governance" ``` Once these subnames exist, the organization has a verifiable, on-chain answer to the question "is this address really yours?" When someone shares a contract address claiming it belongs to the organization, anyone can resolve the organization's ENS name and check whether the address appears under it. Omissions become visible too. If funds are flowing through an address that isn't published as a subname, that's a signal worth investigating. ### Step 5: Add the legal entity, its officers, and its wallet Many DAOs adopt a legal wrapper, such as a Wyoming DUNA, a Cayman foundation, or an LLC, to interact with the off-chain world. The wrapper has its own identity, its own officers, and usually its own dedicated funds, distinct from the DAO's broader treasury. Publishing all of that as children under a single subname keeps the legal entity neatly contained as one branch of the org's tree. #### The legal entity subname Create a subname like `duna.supercooldao.eth` (use whatever short label matches the wrapper, such as `foundation.dao.eth` or `llc.dao.eth`) and apply the `Org` schema to it. The class on this node should be the specific legal form, and the description and URL fields are where the registered office address and contact information live. | Record key | What to put | | ------------- | ------------------------------------------------------------------------------------ | | `class` | The legal form, such as `DUNA`, `Foundation`, or `LLC` | | `name` | The legal entity's registered name | | `description` | The registered office address and any other contact info you want published on-chain | | `url` | URL to the entity's filings, registered-agent page, or contact page | ``` duna.supercooldao.eth ├── class = "DUNA" ├── schema = "" ├── name = "Super Cool DAO LCA" ├── description = "Wyoming Decentralized Unincorporated Nonprofit Association. Registered office: 123 Main St, Cheyenne, WY 82001" └── url = "https://supercool.dao/legal" ``` #### Officers Use the `Person` schema to publish the individuals who hold named roles in the legal entity, such as the CEO, secretary, registered agent, or any other officer the wrapper requires. Each officer gets a child subname under `duna.supercooldao.eth`, and each subname's address record should point at an address that individual actually controls. | Record key | What to put | | ----------- | --------------------------------------------------------------------------------- | | `class` | `Officer` (or `Person`, `Signer`, `Signatory`, `Employee`) | | `full-name` | The person's full legal or preferred name | | `title` | Their role, such as `Chief Executive Officer`, `Secretary`, or `Registered Agent` | ``` ceo.duna.supercooldao.eth ├── address record → 0x... (Alice's wallet) ├── class = "Officer" ├── full-name = "Alice Johnson" └── title = "Chief Executive Officer" secretary.duna.supercooldao.eth ├── address record → 0x... (Bob's wallet) ├── class = "Officer" ├── full-name = "Bob Chen" └── title = "Secretary" agent.duna.supercooldao.eth ├── address record → 0x... (registered agent's wallet) ├── class = "Officer" ├── full-name = "Wyoming Registered Agents LLC" └── title = "Registered Agent" ``` #### The legal entity's wallet The legal wrapper usually controls funds that are its own, used for legal fees, government filings, registered-agent renewals, and other expenses incurred by the entity rather than by the broader DAO. Publish that wallet as a child subname of the legal entity, distinct from the main `treasury.supercooldao.eth` from Step 4. ``` wallet.duna.supercooldao.eth ├── address record → 0x... (legal entity multisig) ├── class = "Wallet" ├── name = "DUNA Operating Wallet" └── description = "Funds controlled by the legal entity for filings, legal fees, and registered-agent renewals" ``` Keeping this wallet under `duna.supercooldao.eth` makes the separation explicit: anyone walking the tree can see which funds belong to the legal wrapper and which belong to the DAO at large. #### Why this structure matters Nesting the officers and the entity's wallet under a single legal-entity subname has a powerful consequence: because each officer subname resolves to a real address, signatures from that address can be traced back through the legal entity, back through the org root, to the governance that authorised the wrapper in the first place. If `ceo.duna.supercooldao.eth` signs a message, anyone can verify that the signer is the person the legal entity has designated as its CEO, and that the legal entity itself is the one the DAO has adopted. The chain of attribution runs from signature → address → officer subname → legal entity subname → root → governance, entirely on-chain. This matters anywhere official authority matters: signing governance proposals, authorising treasury disbursements, issuing public statements, or executing legal agreements on-chain. The subname structure turns the organization's ENS name into something close to a corporate seal. ### Step 6: Add working groups and committees Use the `Group` schema for the organization's internal structure, including workgroups, committees, councils, and teams. A group subname represents the group itself; the group can then have its own child subnames for the wallets and contracts it controls, mirroring the pattern from Steps 4 and 5. Set the group subname's address record to the address that signs on behalf of the group, typically a multisig controlled by the group's members. That way, when the group authorises something, the signature comes from an address that resolves back through `grants.supercooldao.eth` to the organization's root. | Record key | What to put | | --------------- | ---------------------------------------------------------------- | | `class` | `Group` (or `Committee`, `Council`, `Workgroup`, `Team`) | | `name` | The group's name | | `description` | What the group is responsible for | | `url` | URL with more information about the group | | `lead` | ENS name or address of the group's lead | | `lead-title` | *(Optional)* The lead's title, such as `Lead Steward` or `Chair` | | `members-title` | *(Optional)* The title used for ordinary members | | `avatar` | *(Optional)* URI to a logo or avatar | A workgroup with its own operating budget might look like this: ``` grants.supercooldao.eth ├── address record → 0x... (workgroup multisig) ├── class = "Workgroup" ├── name = "Grants Workgroup" ├── description = "Reviews and funds public-goods grant proposals" ├── url = "https://supercool.dao/grants" ├── lead = "carol.supercooldao.eth" ├── lead-title = "Lead Steward" └── members-title = "Steward" wallet.grants.supercooldao.eth ├── address record → 0x... (grants operating wallet) ├── class = "Wallet" ├── name = "Grants Operating Wallet" └── description = "Operating budget for the Grants Workgroup, topped up quarterly" ``` The grants workgroup is now a discoverable branch of the organization in its own right: it has a name, a lead, an authorising multisig, and its own operational wallet, all anchored back to `supercooldao.eth`. The same pattern can be repeated for any committee, council, or team the organization wants to publish. ### How an organization's structure is discovered Once the tree is in place, any consumer can map an organization's full on-chain footprint without querying any external API or documentation site: 1. **Start from the organization's root ENS name** (`supercooldao.eth`). 2. **Enumerate its subnames** via the ENS Subgraph, or by scanning `NewOwner` events on the registry under the root's namehash. 3. **For each subname, read the `class` and `schema` records** to determine whether it's a treasury, contract, officer, group, or something else. 4. **Read the schema-specific records** (`name`, `description`, `full-name`, `title`, `lead`, etc.) and resolve the subname's address record to find the on-chain target. 5. **Recurse into group subnames** to discover their own child wallets and contracts. The result is a live, permissionless map of the organization's legal structure, treasuries, contracts, and internal groups, all anchored in the same name people already use to refer to the organization. ### Related * [Organization schema](/schemas/org) * [Treasury schema](/schemas/treasury) * [Wallet schema](/schemas/wallet) * [Contract schema](/schemas/contract) * [Person schema](/schemas/person) * [Group schema](/schemas/group) ## Using parameterized key names ENS text records are simple key-value pairs. Parameterized key names extend this model to support dictionaries and ordered lists, without requiring any changes to the underlying resolver. A parameter is appended to a key name in square brackets: ``` key-name[parameter] ``` This guide explains the two types of parameterized keys, how to populate them on a node, and how to define them in a schema. ### Maps A map is a set of key-value pairs where the parameter is a free-form label. Use maps when each entry represents a named variant of the same attribute. For example, a delegate might publish a different statement for each DAO they participate in, using the DAO's ENS name as the parameter: ``` delegate.alice.eth ├── statement = "My general governance philosophy..." ├── statement[ens.eth] = "For ENS governance I focus on..." ├── statement[uniswap.eth] = "My Uniswap priorities are..." └── statement[arbitrum.eth] = "For Arbitrum I care most about..." ``` An agent might publish a map of service endpoints, keyed by service name: ``` myagent.eth ├── services[web] = "https://web.agentxyz.com/" ├── services[mcp] = "https://mcp.agentxyz.com/" └── services[a2a] = "https://agent.example/.well-known/agent-card.json" ``` The base form of the key (`statement`, `services`) can coexist alongside parameterized entries. Clients should treat the base form as a default or fallback when no specific parameter is requested. #### Populating a map in ensmetadata.app If the schema has already been selected and the parameterized key appears in the schema, the common fields will appear automatically. To add additional entries: 1. Click "+ Record" at the bottom of the metadata editing drawer. 2. Enter the full key including the parameter in square brackets, for example `statement[ens.eth]`. 3. Enter the value and save. 4. Repeat for each entry, then broadcast the transaction. ### Arrays An array is an ordered, zero-indexed list. Use arrays when the entries form a sequence and their position matters more than a named label. For example, an agent might publish the on-chain registries it is registered with: ``` myagent.eth ├── registrations[0] = "eip155:1/erc721:0x742.../22" ├── registrations[1] = "eip155:8453/erc721:0x.../7" └── registrations[2] = "eip155:42161/erc721:0x.../3" ``` Array entries start at index `0` and must be sequential with no gaps. Clients read arrays by starting at `0` and incrementing until no value is found. If a gap exists in the sequence, clients will stop at the gap and will not retrieve entries beyond it. Like maps, arrays also support a base form of the key as a fallback. #### Populating an array in ensmetadata.app Adding array entries follows the same process as maps: 1. Click "+ Record" at the bottom of the metadata editing drawer. 2. Enter the key with the next index in square brackets, for example `registrations[0]`. 3. Enter the value and save. 4. Repeat for each entry in order, then broadcast the transaction. When removing entries, re-index the remaining items so there are no gaps in the sequence. ### Defining parameterized keys in a schema Parameterized keys are declared in the `patternProperties` section of a JSON schema. The property name is a regex pattern that matches both the base form and the parameterized form of the key. The following regex format accepts either form while rejecting empty brackets: ``` ^key-name(\[[^\]]+\])?$ ``` We recommend running your schema through a JSON Schema validator to ensure it is valid before publishing. #### Defining a map Add the property to `patternProperties` with `"parameterType": "map"`. If `parameterType` is omitted, the default is `"map"`. ```json { "patternProperties": { "^services(\\[[^\\]]+\\])?$": { "type": "string", "parameterType": "map", "format": "uri", "description": "A map of service names to their endpoints" } } } ``` This allows records like `services`, `services[web]`, `services[mcp]`, etc. #### Defining an array Add the property to `patternProperties` with `"parameterType": "array"`. ```json { "patternProperties": { "^registrations(\\[[^\\]]+\\])?$": { "type": "string", "parameterType": "array", "description": "An array of cross-chain identity registrations following CAIP-19 format" } } } ``` This allows records like `registrations[0]`, `registrations[1]`, `registrations[2]`, etc. #### Combining both types in one schema A schema can include any number of parameterized keys, mixing maps and arrays as needed. For example, the agent schema defines `services` as a map and `registrations` as an array: ```json { "properties": { "name": { "type": "string", "description": "Display name of the agent" } }, "patternProperties": { "^services(\\[[^\\]]+\\])?$": { "type": "string", "parameterType": "map", "format": "uri", "description": "A map of service names to their endpoints" }, "^registrations(\\[[^\\]]+\\])?$": { "type": "string", "parameterType": "array", "description": "An array of cross-chain identity registrations following CAIP-19 format" } } } ``` ### Related * [Agent schema](/schemas/agent) (uses both maps and arrays) * [Delegate schema](/schemas/delegate) (uses maps for DAO-specific statements) ## CLI Find documentation [on Github](https://github.com/0xLighthouse/ens-metadata/tree/main/packages/cli). This tool's SKILL.md can be seen [here](https://github.com/0xLighthouse/ens-metadata/blob/main/packages/cli/SKILL.md).