Intent-Driven Development
Describe what you want. Your agent writes the spec and the code. NTNT checks that the two match.
IDD is built into the language. When you ask an agent for a feature, it writes a .intent file alongside the implementation, and ntnt intent check runs every scenario against the real code. The agent gets a closed feedback loop; you get a spec you can actually read.
Keep requirements close to the checks.
You write code, then tests to cover it, while the requirements live in a ticket nobody rereads. Nothing connects what was asked for to what was built. IDD makes the requirement itself the executable check.
Requirements are the tests
Features and scenarios in plain language, backed by a glossary that resolves each phrase to a concrete check. One source of truth, reviewed by you.
Code points at the spec
@implements annotations tie functions to features, so coverage is a question the toolchain can answer: ntnt intent coverage.
Agents close their own loop
The agent runs the check, reads the failures, and iterates. Intent lint catches unresolved phrases and empty scenarios before execution; review the assertions and coverage, not just the exit code.
From prompt to verified code.
Pair the intent file with its implementation, then run lint and check. A passing scenario verifies its assertions, not every property of the application.
The agent writes the intent
From your prompt, the agent creates a .intent file: features, scenarios, and a glossary that maps natural phrases to executable checks. You review the spec before any code exists.
“A user visits the home page” resolves to GET /. “The page loads” resolves to status 200. Define a phrase once; reuse it everywhere.
## Glossary | Term | Means | |------------------------|------------------------| | a user visits {path} | GET {path} | | the home page | / | | the page loads | status 200 | | they see {text} | body contains {text} | --- Feature: Home Page id: feature.home Scenario: Shows welcome message When a user visits the home page → the page loads → they see "Welcome" Scenario: Shows navigation When a user visits the home page → they see "About" → they see "Contact"
Lint the spec before running it
ntnt intent lint checks the glossary statically: unresolved phrases, definition cycles, and orphaned terms, with did-you-mean suggestions. Typos in a spec fail fast instead of silently skipping.
$ ntnt intent lint home.intent ✗ [unresolved_term] Home Page › Shows navigation: "they spot "Contact"" term not found in glossary or standard vocabulary did you mean: 'they see {text}' 2 scenarios and 4 glossary terms checked: 1 error(s), 0 warning(s)
The agent implements
The agent writes the code and links it to the feature with an @implements annotation, so NTNT knows which code answers for which requirement.
import { html } from "std/http/server" // @implements: feature.home fn home(req) { return html("<h1>Welcome</h1><a href='/about'>About</a> <a href='/contact'>Contact</a>") } get("/", home) listen(8080)
NTNT verifies
ntnt intent check starts the app, runs every scenario, and gives a definitive pass or fail. Checks run in strict type mode by default. The agent iterates on failures; you see the green result.
$ ntnt intent check home.tnt -vv ✓ Feature: Home Page ✓ Shows welcome message → the page loads → they see "Welcome" ✓ status: 200 ✓ body contains "Welcome" ✓ Shows navigation → they see "About" → they see "Contact" ✓ status: 200 ✓ body contains "About" ✓ body contains "Contact" === Summary === Features: 1 total, 1 passed, 0 failed Scenarios: 2 passed, 0 failed, 0 skipped Assertions: 5 passed, 0 failed
More than HTTP tests.
The same workflow covers plain functions, cross-cutting rules, and runtime contracts. One methodology for the whole codebase.
# utils.intent — no server needed ## Glossary | Term | Means | |---------------------|-------------------------------------------| | slugifying {text} | call: to_slug({text}), source: slug.tnt | --- Feature: URL Slugs id: feature.slugs Scenario: Basic conversion When slugifying "Hello World" → result is "hello-world" → is deterministic Scenario: Trims whitespace When slugifying " NTNT " → result is "ntnt"
# security.intent Constraint: Security Headers description: "Every page sets basic security headers" applies_to: [feature.home, feature.api] → header "X-Frame-Options" exists → header "X-Content-Type-Options" equals "nosniff"
fn withdraw(balance: Int, amount: Int) -> Int requires amount > 0 requires amount <= balance ensures result >= 0 { return balance - amount } // A failed contract reports the runtime values that broke it. // In HTTP handlers: requires fails → 400, ensures fails → 500.
Functions
A glossary entry with call: and source: tests a function directly, with no server. Property checks like is deterministic call it repeatedly and compare.
Constraints
Rules that apply across features: define security headers or error policies once, and every listed feature is checked against them.
Contracts
requires and ensures document the function and enforce it at runtime. Agents read them as specs; people read them as docs.
A vocabulary that ships with the language.
These terms work in any intent file without a glossary entry. The full list lives in the IAL reference.
HTTP
status 200,status 4xxbody contains "text"body not contains "text"body matches "pattern"body has field "key"content-type is jsonheader "X" equals "Y"response time < 100ms
Functions
result is "value"starts with "prefix"does not contain "text"is at most 10length is at most 64is deterministicis idempotent
CLI
exits successfullyexit code is 2stdout contains "text"stderr is empty
Code quality
code passes lintno lint warningsno syntax errors
The IDD command set.
Five subcommands under ntnt intent. Lint and check both support --json for CI and agents.
ntnt intent check app.tnt | Run every scenario against the implementation; pass or fail for each |
ntnt intent lint app.intent | Statically validate the glossary and scenarios before running anything |
ntnt intent coverage app.tnt | Show which features have linked implementations |
ntnt intent init app.intent -o app.tnt | Generate code scaffolding from an intent file |
ntnt intent studio app.intent | Visual workspace with live test results as you edit |
Try it on your next feature.
Install NTNT, point your agent at it with ntnt learn, and describe what you want. The spec, the code, and the proof come back together.