Inline Intent: Embedding Specifications Directly in Your Source Files
By Ben Houston, 2025-05-07
Intent-based development has proven valuable for separating what a system should do from how it's implemented. Until now, Declary has focused on standalone .intent.yaml
files that live alongside your source code. But what if you could embed those specifications directly in your implementation files—just as React embeds components in JavaScript via JSX?
That's exactly what Inline Intent enables. This new capability lets you weave intent specifications directly into your source files, creating a fluid boundary between declarative intent and imperative code.
Why Embed Intent in Source?
While separate intent files provide clean separation, they create a context switch when working on closely related specifications and implementations. In many cases—particularly for complex algorithms, domain-specific logic, or performance-critical code—we need both:
- High-level natural language descriptions of purpose and constraints
- Precise, implementation-specific details that are difficult to capture in pure YAML
Inline Intent addresses this need by allowing you to define intent specifications exactly where the code should be generated, effectively turning pseudocode into actual implementation:
// src/utils/sorting.ts export function optimizedSort<T>( array: T[], compareFn?: (a: T, b: T) => number ): T[] { /** @intent * A stable, adaptive merge sort implementation optimized for * partially sorted arrays. Should maintain O(n log n) worst-case * performance but approach O(n) for nearly-sorted data. * * This optimizes for both runtime performance and memory efficiency * on modern JavaScript engines. */ }
When you run declary generate
, the comment block is interpreted as an intent specification, and the function implementation is regenerated.
The JSX Analogy
This approach is conceptually similar to how JSX works in React:
- JSX lets you embed UI components directly in JavaScript/TypeScript
- The transpiler converts this specialized syntax into standard function calls
- This provides a more intuitive mental model where component definitions live with their usage
Similarly, Inline Intent:
- Lets you embed intent specifications directly where the code should be generated
- The Declary processor converts these pseudocode-like instructions into real implementations
- The developer writes what amounts to structured comments that get automatically transformed into working code
Implementation Approaches
Declary supports multiple ways to define inline intent:
Comment-Based Intent
The simplest approach uses specially formatted comments:
/** @intent * builder: typescript/class * instructions: | * A cache implementation using LRU (least recently used) eviction. * Should support setting max item count and TTL (time to live). */ export class Cache<K, V> { // Implementation will be generated here }
This works in any language without requiring special tools—just Declary's processor.
Language Extension (TSI/JSI)
For TypeScript and JavaScript, we've introduced .tsi
and .jsi
extensions (TypeScript/JavaScript with Intent), providing first-class syntax support:
// user-service.tsi import { Database } from '../db'; export class UserService { constructor(private db: Database) {} intent { "User management service handling authentication, profiles, and permissions" concerns: ["logging", "error-handling", "input-validation"] } }
Similar to how TypeScript/JavaScript handle JSX, this syntax provides better tooling support, syntax highlighting, and validation.
Python Intent (PYI)
For Python codebases, we've created a .pyi
extension supporting a similar pattern:
# recommender.pyi import numpy as np def recommend(user_id, item_matrix, n_recommendations=5): """@intent A collaborative filtering recommendation algorithm using matrix factorization. Should handle sparse input matrices efficiently and support incremental updates. Must maintain sub-quadratic performance characteristics. """
This approach is syntactically compatible with standard Python, requiring minimal tooling changes.
When to Use Inline Intent
Inline Intent shines in several scenarios:
Complex Algorithmic Requirements
When algorithms have nuanced requirements difficult to express in pure YAML:
Algorithm as Pseudocode
Here's an example showing how you can write an entire algorithm in pseudocode form using intent comments:
// minimax.ts export function minimax( node: GameNode, depth: number, isMaximizingPlayer: boolean ): number { /** @intent * Base case: if we've reached a terminal node or maximum depth * return the evaluation score for this node */ /** @intent * If maximizing player: * Set maxEval to negative infinity * For each child of the node: * Recursively evaluate child with minimax(child, depth-1, false) * Update maxEval with maximum of current maxEval and the child evaluation * Return maxEval */ /** @intent * If minimizing player: * Set minEval to positive infinity * For each child of the node: * Recursively evaluate child with minimax(child, depth-1, true) * Update minEval with minimum of current minEval and the child evaluation * Return minEval */ }
When processed by Declary, these intent comments are transformed into a complete, working implementation:
// Generated output: export function minimax( node: GameNode, depth: number, isMaximizingPlayer: boolean ): number { // Base case: if we've reached a terminal node or maximum depth if (depth === 0 || node.isTerminal()) { return node.evaluate(); } // If maximizing player if (isMaximizingPlayer) { let maxEval = -Infinity; for (const child of node.children) { const eval = minimax(child, depth - 1, false); maxEval = Math.max(maxEval, eval); } return maxEval; } // If minimizing player else { let minEval = Infinity; for (const child of node.children) { const eval = minimax(child, depth - 1, true); minEval = Math.min(minEval, eval); } return minEval; } }
Gradual Migration
When incrementally adopting intent-based development in existing codebases:
Another Example: Multi-Step Algorithm Using Line-by-Line Intent
For algorithms that require step-by-step processing, you can use intent comments at each logical step:
# quick_sort.py def quick_sort(arr, low, high): """@intent Implementation of the quicksort algorithm with the following characteristics: - Uses the Hoare partition scheme - Selects pivot using median-of-three method to avoid worst-case on already sorted arrays - Falls back to insertion sort for small partitions (less than 10 elements) """ # @intent Check if the partition is small enough for insertion sort # @intent Select pivot using median-of-three # @intent Partition the array around the pivot # @intent Recursively sort the left partition # @intent Recursively sort the right partition
This approach provides complete freedom to structure your intent at the appropriate level of abstraction - whether that's describing an entire algorithm, outlining logical blocks, or detailing specific implementation steps.
Mixed Intent/Implementation
When some parts need intent-based generation while others require hand-crafting:
Enhanced Intent Directives: @builder and @concerns
To provide more precise control over code generation, inline intent supports specialized directives that can be included within the comment blocks:
/** @intent * @builder react/component * @concerns responsive theming accessibility * A dropdown menu component that displays a list of options when clicked. * Should support keyboard navigation, screen readers, and custom styling. */ function Dropdown({ options, defaultValue, onChange }) { // [CODEGEN] will be generated here }
Available Directives
- @builder - Specifies which code generator to use (e.g.,
react/component
,typescript/validator
,sql/query
) - @concerns - Lists cross-cutting concerns to apply (e.g.,
responsive
,authentication
,logging
)
These directives can be used with any of the intent styles we've discussed:
With Comment-Based Intent
function calculateTaxes(income: number, location: string): TaxResult { /** @intent * @builder finance/tax-calculator * @concerns logging validation * Calculate income taxes based on jurisdiction and income brackets. * For US locations, apply federal, state and local tax rates. * For international locations, apply country-specific tax treaties. */ }
With Tilde Syntax
export function generateReport(data: DataSet, format: ReportFormat): Report { ~@builder reporting/generator @concerns pagination caching Generate a financial report from the dataset with configurable sections. Include summary statistics, trend analysis, and visualizations. Format according to the specified output type (PDF, Excel, HTML).~ }
In Immediate Mode
// api-endpoints.ts export async function getUserProfile(userId: string): Promise<UserProfile> { /** @intent * @builder api/endpoint * @concerns authentication rate-limiting * Fetch user profile information from the database. * Include basic info, preferences, and activity history. * Ensure proper access control checks before returning data. */ // [CODEGEN:START] - Generated from @intent above const authResult = await checkAuthorization(userId); if (!authResult.isAuthorized) { throw new UnauthorizedError('Not authorized to view this profile'); } await rateLimiter.check('user-profile', userId); const user = await db.users.findOne({ id: userId }); if (!user) { throw new NotFoundError('User not found'); } const activities = await db.activities .find({ userId }) .sort({ date: -1 }) .limit(10); const preferences = await db.preferences.findOne({ userId }); return { id: user.id, name: user.name, email: user.email, profilePicture: user.profilePicture, joinDate: user.createdAt, preferences: preferences || {}, recentActivity: activities }; // [CODEGEN:END] }
Multiple Intents in a Single File
With these directives, you can now include multiple intents within a single file, each with its own builder and concerns:
// user-service.ts /** @intent * @builder typescript/service * @concerns logging error-handling * Service for managing user accounts and authentication. */ export class UserService { constructor(private db: Database) {} /** @intent * @builder typescript/method * @concerns validation security * Create a new user account with the provided details. * Hash password before storage, validate email format, * and ensure username uniqueness. */ async createUser( username: string, email: string, password: string ): Promise<User> { // [CODEGEN] will be generated here } /** @intent * @builder typescript/method * @concerns security audit-logging * Authenticate a user with email/password and return a session token. * Track login attempts and implement lockout after failed attempts. */ async login(email: string, password: string): Promise<AuthResult> { // [CODEGEN] will be generated here } /** @intent * @builder typescript/method * @concerns caching pagination * Retrieve a list of users matching the search criteria. * Support filtering, sorting, and pagination options. */ async findUsers( criteria: UserSearchCriteria ): Promise<PaginatedResult<User>> { // [CODEGEN] will be generated here } }
This enables a highly modular approach where each function, method, or component can have its own specialized intent, while still maintaining the overall cohesion of the file.
SQL Generation Example
Intent-based generation works particularly well for database queries:
function getUserAnalytics(userId: string, startDate: Date, endDate: Date) { const sql = /* @intent @builder sql/query @concerns performance security Generate a SQL query that retrieves user analytics data. Include total sessions, average session duration, pages viewed, and conversion events. Group by date for the specified date range. Ensure proper parameter sanitization and index usage. */ // [CODEGEN:START] ` SELECT DATE(session_start) as date, COUNT(DISTINCT session_id) as total_sessions, AVG(TIMESTAMPDIFF(SECOND, session_start, session_end)) as avg_duration, SUM(pages_viewed) as total_pages, SUM(CASE WHEN event_type = 'conversion' THEN 1 ELSE 0 END) as conversions FROM user_analytics WHERE user_id = ? AND session_start >= ? AND session_start <= ? GROUP BY DATE(session_start) ORDER BY DATE(session_start) ASC `; // [CODEGEN:END] return db.query(sql, [userId, startDate, endDate]); }
API Route Generation
Similarly, framework-specific route handlers can be generated:
// routes.ts /** @intent * @builder express/route * @concerns validation authentication * POST endpoint to create a new order. * Validate product availability and user payment details. * Return the created order with status and tracking information. */ app.post('/api/orders', async (req, res) => { // [CODEGEN] will be generated here });
By combining multiple specialized intents in a single file, each with its own builder and concerns, Declary can now support a much more flexible and granular approach to intent-based development.
Processing and Generation Flow
The workflow with Inline Intent is straightforward:
- Write or modify intent specifications directly in source files
- Run
declary generate
to process the codebase - Declary identifies inline intent blocks and passes them to appropriate builders
- Generated code replaces placeholder implementations or previous generations
- Version control tracks both the intent specifications and the resulting implementations
For .tsi
/.jsi
/.pyi
files, an additional transpilation step generates standard .ts
/.js
/.py
files, similar to how JSX processing works.
Benefits of Inline Intent
This approach offers several advantages:
Reduced Context Switching
Developers can define both what and how in a single file, reducing the cognitive load of switching between separate specification and implementation files.
Finer-Grained Control
You can apply intent-based generation selectively—just the parts that benefit from it—while keeping hand-crafted code where needed.
Easier Collaboration
Code reviews capture both intent changes and implementation changes in a single diff, making it easier to understand and validate modifications.
Familiar Mental Model
Developers already familiar with JSX/TSX will find the syntax patterns intuitive, flattening the learning curve.
Stronger Implementation/Intent Coupling
The physical proximity of intent to code encourages keeping them in sync, reducing the risk of drift over time.
Real-World Example: API Endpoint
Here's a practical example showing how Inline Intent works for an API endpoint:
// user-controller.tsi import { Request, Response } from 'express'; import { UserService } from '../services'; export class UserController { constructor(private userService: UserService) { /** @intent * Controller handling user account operations * concerns: ["auth", "rate-limiting", "validation"] */ } async createUser(req: Request, res: Response) { /** @intent * method: POST * route: "/users" * Creates a new user account * validation: { * email: "required|email", * password: "required|min:8", * name: "required|string" * } * responses: { * 201: "User created successfully", * 400: "Invalid input", * 409: "Email already exists" * } */ } // More endpoints... }
When processed, this generates fully implemented controller methods with appropriate validation, error handling, and service calls.
Conclusion: Intent Everywhere
Inline Intent represents an evolution in Declary's approach to intent-based development. Rather than forcing an all-or-nothing choice between separate intent files and traditional code, it enables a flexible spectrum where you can apply intent-based principles precisely where they add the most value.
By bringing intent specifications directly into your source files, Declary becomes even more adaptable to your existing workflows and codebases. The result is a development model that truly fits how real teams work: pragmatically, incrementally, and with an eye toward both immediate productivity and long-term maintainability.
Whether you're building new features or gradually refactoring legacy code, Inline Intent gives you a powerful new tool for expressing not just what your code does, but why it exists.