How to Use the Astryx JSON API Programmatically for AI Agent Integration
The Astryx JSON API provides a typed, machine-readable interface for every CLI command, enabling AI agents to parse responses, handle errors deterministically, and discover capabilities through a self-describing manifest.
The facebook/astryx repository ships a sophisticated JSON API that transforms the Astryx CLI into a programmable interface for automation tools and AI agents. By appending the --json flag to any command, the CLI emits structured envelopes instead of human-readable text, complete with TypeScript definitions that ensure type safety across the boundary between shell execution and application logic.
Understanding the JSON API Architecture
The Astryx JSON API is implemented as a thin serialization layer over the existing CLI infrastructure. Every command checks for the --json flag and, when present, outputs responses using typed helper functions rather than console formatting.
The Envelope Structure
Every JSON response follows a strict envelope pattern defined in packages/cli/src/types/base.d.ts. Successful responses return:
{ "type": "<discriminator>", "data": { … } }
Error responses use a complementary shape:
{ "error": "...", "code": "<ERR_…>", "suggestions": […] }
The type discriminators (such as component.detail, search, or manifest) function as tagged unions that allow TypeScript to narrow response types automatically.
Core Type Definitions
The type system lives in packages/cli/src/types/ and provides compile-time guarantees for AI agent integrations:
base.d.ts– Defines the genericCLIResult<T>,CLIError, and the unionCLIAnyResponse. It also exports helper functions includingjsonOut,jsonError,parseResponse,isError, andassertResponse.component.d.ts– Describes component-related responses such asComponentDetailResponse, specifying fields likename,props, andsource.manifest.d.ts– Exposes the self-describing capability manifest viaManifestResponse, which agents use to discover commands and their JSON support.
Consuming the API at Three Levels
Because the API is pure data, you can integrate it at three distinct abstraction levels depending on your runtime constraints.
Shell-Level Integration
Spawn a child process with the --json flag and parse the stdout stream. This approach works across any language or runtime that can execute shell commands, making it ideal for polyglot AI agent systems.
Node-Level Integration
Import the helper functions directly from @astryxdesign/cli/json to reuse the CLI's internal serialization logic in custom scripts or libraries. This eliminates string parsing and provides immediate access to the type definitions.
Agent-Level Discovery
Execute astryx manifest --json to retrieve a "mini-OpenAPI" description of every command, its arguments, flags, and JSON support status. AI agents can fetch this manifest once at startup and generate calling code dynamically without hard-coding response shapes.
Implementation Examples
Calling Astryx via Child Process
For generic AI agents running in isolated environments, spawn the CLI and parse the response using the built-in helpers:
import { execFile } from 'node:child_process';
import { parseResponse, isError } from '@astryxdesign/cli/json';
async function runAstryx(command: string[], cwd = process.cwd()) {
return new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
execFile('npx', ['astryx', ...command, '--json'], { cwd }, (err, stdout, stderr) => {
if (err) reject(err);
else resolve({ stdout, stderr });
});
});
}
// Example: fetch details for the Button component
const { stdout } = await runAstryx(['component', 'Button']);
const result = parseResponse(JSON.parse(stdout));
if (isError(result)) {
console.error('Astryx error:', result.code, result.error);
} else {
// `result` is now narrowed to ComponentDetailResponse
console.log('Component docs URL:', result.data.docUrl);
}
This pattern uses the parseResponse and isError helpers defined in packages/cli/src/types/base.d.ts to handle both success and error envelopes safely.
Direct Programmatic Usage
When running within a Node.js context where you can import the CLI library, emit responses using the same primitives the CLI uses internally:
import { jsonOut, jsonError } from '@astryxdesign/cli/json';
import type { ComponentDetailResponse } from '@astryxdesign/cli/json';
// Simulate a command implementation inside a custom script
function getButtonInfo(): ComponentDetailResponse {
return {
type: 'component.detail',
data: {
name: 'Button',
props: [],
source: 'packages/core/src/Button/Button.tsx',
},
};
}
// Emit a proper JSON envelope
jsonOut('component.detail', getButtonInfo().data);
The jsonOut function guarantees that the payload matches the declared shape according to the contracts in base.d.ts.
Discovering Capabilities via Manifest
AI agents can introspect the CLI's capabilities before executing commands:
import { execFileSync } from 'node:child_process';
import { parseResponse } from '@astryxdesign/cli/json';
const raw = execFileSync('npx', ['astryx', 'manifest', '--json'], { encoding: 'utf8' });
const manifest = parseResponse(JSON.parse(raw)); // type = ManifestResponse
if (!('commands' in manifest.data)) {
throw new Error('Unexpected manifest shape');
}
// Find all commands that support JSON output
const jsonCommands = manifest.data.commands.filter(c =>
c.flags.some(f => f.flag === '--json')
);
console.log('Commands with JSON support:', jsonCommands.map(c => c.name));
The manifest schema resides in packages/cli/src/types/manifest.d.ts and is exposed via the ManifestResponse type.
Asserting Specific Response Types
For type-safe narrowing when you expect a specific discriminator, use the assertion helper:
import { assertResponse } from '@astryxdesign/cli/json';
import type { SearchResponse } from '@astryxdesign/cli/json';
const raw = execFileSync('npx', ['astryx', 'search', 'button', '--json'], { encoding: 'utf8' });
const response = assertResponse(JSON.parse(raw), 'search'); // narrows to SearchResponse
console.log('Top result:', response.data.results[0].name);
The assertResponse function throws if the envelope does not match the expected discriminator, providing runtime validation that complements the static types in component.d.ts and related files.
Error Handling and Type Safety
Always use the type guard isError(result) to differentiate success from failure before accessing response data. This function checks for the presence of the error field and narrows the union type to CLIError, exposing the stable code field for programmatic error handling.
For stricter validation, the assertResponse helper validates that the type discriminator matches your expected string, throwing immediately if an unexpected response shape arrives. This prevents type confusion when integrating with third-party AI agents that may misparse outputs.
Summary
- Astryx JSON API responses follow a strict envelope pattern with
typediscriminators anddatapayloads, or error objects with stable codes. - Type definitions in
packages/cli/src/types/base.d.tsprovideCLIResult<T>,CLIError, and helper functions likeisErrorandassertResponse. - Three integration levels support shell-level parsing, direct Node.js imports from
@astryxdesign/cli/json, and agent-level discovery viaastryx manifest --json. - Error handling relies on the
isErrortype guard to safely narrow response unions before accessing data properties.
Frequently Asked Questions
What is the envelope format for Astryx JSON API responses?
Successful responses return a JSON object with type and data fields, where type acts as a discriminator (e.g., component.detail, search). Error responses return an object with error, code, and optional suggestions fields. This format is defined in packages/cli/src/types/base.d.ts as CLIResult<T> and CLIError.
How do I handle errors when calling Astryx commands programmatically?
Import the isError type guard from @astryxdesign/cli/json to narrow the response type. If isError(result) returns true, the response contains error and code fields that provide stable identifiers for programmatic error handling. Alternatively, use assertResponse to throw immediately if the response type does not match expectations.
Can AI agents discover available Astryx commands automatically?
Yes. By running astryx manifest --json, agents retrieve a ManifestResponse containing descriptions of every command, including available flags and JSON support status. Agents can parse this manifest to determine which commands support JSON output and what arguments they require, eliminating the need for hard-coded command lists.
What package should I import for TypeScript type definitions?
Install and import from @astryxdesign/cli/json to access helper functions (parseResponse, jsonOut, isError, assertResponse) and response types (ComponentDetailResponse, SearchResponse, ManifestResponse). These definitions mirror the source files in packages/cli/src/types/ and ensure your AI agent code remains synchronized with the CLI implementation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →