EIP-2004 DRAFT · ERC Pull Request (ethereum/ERCs #1557)
Agent-readable smart contract documentation layer — bridging the semantic gap between onchain logic and autonomous reasoning.
Website · Demo Video · CLI on npm
- Overview
- Installation
- Quick Start
- Example
- Project Structure
- The Intent Schema
- Developer Workflow
- NatSpec Tags
- The Problem: The "Black Box" of ABIs
- The Solution
- Whitepaper: The Semantic Safety Frontier
- Impact & Use Cases
- License
Onchain activity is increasingly driven by autonomous agents. Smart contracts, however, remain optimized for human auditors. Agents today infer behavior from function names and ABIs alone, which is brittle and error-prone.
Intent Spec adds a standardized, machine-verifiable metadata layer so developers can declare a function’s intent, economic impact, and safety boundaries. By turning opaque bytecode into structured semantics, Intent Spec reduces systemic risk and supports a safer agentic economy.
Requirements: Node.js ≥ 18
Run without installing (recommended):
npx intentspec compile
npx intentspec extract-natspec --file path/to/Contract.solOr install globally:
npm install -g intentspecOr as a dev dependency:
npm install --save-dev intentspecFull CLI docs (options, build from source): cli/README.md.
-
Annotate your Solidity contract with
@custom:agent-*NatSpec tags (see NatSpec Tags). -
Generate specs from your project directory:
npx intentspec compile
This scans for
.solfiles (excludingnode_modulesand.git), extracts metadata, and writes one JSON file per contract tointentspec/<ContractName>.json. -
Inspect or publish the generated files (e.g. use in agents, docs, or upload to IPFS and point onchain metadata to the hash).
To extract from a single file and print JSON to stdout:
npx intentspec extract-natspec -f contracts/MyContract.solThe example/ folder contains a reference contract with full Intent Spec NatSpec annotations:
- example/UserProxy.sol — A user proxy contract (owner/user–guarded execution, token withdrawals, ETH handling) annotated with contract-level tags (
@custom:agent-version,agent-description,agent-invariant,agent-event) and function-level tags (@custom:agent-intent,agent-precondition,agent-effect,agent-risk,agent-guidance).
To generate the Intent Spec JSON from the example:
npx intentspec extract-natspec -f example/UserProxy.solOr from the repo root to compile all .sol files (including the example) into intentspec/:
npx intentspec compile -d .Use this contract as a reference when annotating your own Solidity code.
intent-spec/
├── cli/ # intentspec CLI — parses NatSpec and generates intentspec JSON
│ ├── src/ # TypeScript source (index.ts, natspec.ts, logger.ts)
│ └── dist/ # Compiled output (published to npm)
├── example/ # Example contract with full Intent Spec NatSpec
│ └── UserProxy.sol
├── landing/ # Intent Spec landing site (https://intentspec.collinsadi.xyz)
│ └── ... # React + Vite + Tailwind
├── schema/ # Intent Spec JSON Schema
│ └── intentspec.schema.json
├── solidity/ # Solidity interface for onchain metadata discovery
│ └── IIntentSpec.sol # getIntentSpecURI() — returns IPFS/URI of intentspec.json
├── README.md
└── LICENSE
The CLI is published as the intentspec npm package. The schema defines the structure of generated intentspec.json files so agents can parse them without ambiguity.
Generated files conform to schema/intentspec.schema.json. All text is brief and precise for AI consumption.
Example intentspec.json:
{
"contract": {
"name": "ExampleToken",
"version": "1.0",
"description": "ERC-20 with minting."
},
"functions": [
{
"name": "mint",
"intent": "Mints tokens to an address; increases total supply.",
"signature": "0x1234567890abcdef",
"preconditions": [
"Caller has MINTER_ROLE.",
"Amount > 0 and within supply cap."
],
"effects": [
"Irreversible: supply increases.",
"Economic: dilutes holders."
],
"risks": ["Inflation if abused.", "Reentrancy without guards."],
"agentGuidance": "Simulate first; check role revocation in recent blocks."
}
],
"events": [
{
"name": "Transfer",
"description": "Token moves; index for balances."
}
],
"invariants": ["Total supply never decreases.", "Paused blocks transfers."]
}contractandfunctionsare required;eventsandinvariantsare optional.signatureis the EVM function selector (first 4 bytes ofkeccak256(functionSignature)) in hex.
-
Annotate — Use custom NatSpec tags in your
.solfiles:/// @custom:agent-intent Withdraws collateral and closes position /// @custom:agent-risk High slippage during volatility function exitPosition(uint256 amount) external { ... }
-
Generate — Run the CLI to extract metadata:
npx intentspec compile
Or for a single file (stdout):
npx intentspec extract-natspec -f path/to/Contract.sol
-
Publish — Upload the generated
intentspec/*.jsonto IPFS (or another URI), then have your contract expose it onchain by implementingIIntentSpecfromsolidity/IIntentSpec.soland returning that URI fromgetIntentSpecURI(). Agents can then discover the spec by calling this function.
Place tags in block comments (/** ... */) directly above the contract or function.
| Level | Tag | Purpose |
|---|---|---|
| Contract | @custom:agent-version |
Contract version |
| Contract | @custom:agent-description |
Short description |
| Contract | @custom:agent-invariant |
Invariant (repeatable) |
| Contract | @custom:agent-event |
Event name + description |
| Function | @custom:agent-intent |
Required. One-line intent |
| Function | @custom:agent-precondition |
Precondition (repeatable) |
| Function | @custom:agent-effect |
Effect (repeatable) |
| Function | @custom:agent-risk |
Risk (repeatable) |
| Function | @custom:agent-guidance |
Guidance for agents |
Only functions with @custom:agent-intent are included in the generated spec. See cli/README.md for detailed examples and behavior.
Agents interact with contracts via the Application Binary Interface (ABI). The ABI defines how to call a function but not why or what the risks are.
- Ambiguity — Is
execute()a harmless state update or a high-risk treasury transfer? - Invisible preconditions — Does this function depend on oracle state not visible in the parameters?
- Irreversibility — Agents lack a clear “danger” signal for actions that cannot be undone.
Intent Spec gives you a metadata standard and tooling so a contract’s semantic intent lives in one place and is machine-readable.
- Declare once — Annotate your Solidity with
@custom:agent-*NatSpec; the CLI emits schema-strict JSON (intent, preconditions, effects, risks, guidance). - Publish & point — Host the generated spec at a stable URI (e.g. IPFS). Implement
IIntentSpecand return that URI fromgetIntentSpecURI()so agents can resolve it onchain. - Agent loop — Agents discover the spec (call
getIntentSpecURI()or use a registry), validate their goal against the declared intent and preconditions, and simulate locally to confirm state changes match the metadata before signing.
The EVM enforces syntactic correctness but not semantic intent. As LLM-driven agents begin to manage private keys, this “semantic gap” becomes critical. Intent Spec provides a ground-truth anchor for machine reasoning.
Agents today perform a translation:
Because the ABI is sparse, estimation variance is high, leading to agentic drift. Intent Spec introduces a structured verification loop: discover metadata, validate declared intent against the goal, and correlate simulation state changes with expected outcomes.
With structured metadata we move to constraint-based interaction. Let (P(f)) be the probability of a “failure of intent.” With a semantic anchor (A):
Preliminary benchmarks suggest this can reduce certain classes of catastrophic agent errors significantly.
- DeFi protocols — Make contracts interpretable by agents to attract “agentic liquidity.”
- Security auditors — Machine-readable spec to compare against bytecode and behavior.
- Users — Agents (e.g. ENS-integrated) can explain transaction risks in plain language.
- Systemic safety — Reduce AI-driven “flash crashes” from agents misinterpreting complex logic.
MIT © Collins Adi. See LICENSE.