Skip to main content

Agentic Unit (AU) Specification

Version: 1.0 Status: Canonical Contract Specification Last Updated: 2025-11-17

This document defines the contract for Agentic Units (AUs) in the AGEniX ecosystem. AUs are specialized tools that AGX can orchestrate and AGW can execute.


Table of Contents​

  1. Overview
  2. Core Principles
  3. AU Contract
  4. Command-Line Interface
  5. Input/Output Protocol
  6. Model Card (--describe)
  7. Error Handling
  8. Security Requirements
  9. Examples
  10. Validation Checklist

1. Overview​

What is an Agentic Unit?​

An Agentic Unit (AU) is a command-line tool that:

  • Performs a specialized task (OCR, PDF parsing, data transformation, etc.)
  • Follows a strict stdin/stdout contract for AGEniX orchestration
  • Provides machine-readable metadata via --describe
  • Runs in zero-trust worker environments

AU vs Regular CLI Tool​

AspectRegular CLI ToolAgentic Unit
InputFiles, arguments, promptsBinary stdin + arguments
OutputFiles, stdout (text)Structured JSON to stdout
ErrorsMixed stdout/stderrErrors only to stderr
DiscoveryManual documentation--describe JSON schema
EnvironmentAssumes network, filesystemZero-trust, sandboxed
Model LoadingAuto-download, defaultsExplicit path, no auto-download

2. Core Principles​

2.1 Single Responsibility​

Each AU does one thing well:

  • ✅ agx-ocr: Extract text from images
  • ✅ agx-pdf: Parse PDF to structured data
  • ❌ agx-swiss-army-knife: OCR + PDF + translation + ...

2.2 Stateless Execution​

AUs are pure functions:

  • No persistent state between invocations
  • No databases, caches, or session files
  • Idempotent: Same input → same output

2.3 Data Flow Contract​

┌─────────────────────────────────────────┐
│ AGW Worker (Untrusted Environment) │
│ │
│ ┌───────────────────────────────────┐ │
│ │ Agentic Unit Process │ │
│ │ │ │
│ │ stdin ──────▶ [AU Logic] ──────▶ stdout (JSON)
│ │ │ │ │
│ │ └──────────▶ stderr (Errors)
│ │ │ │
│ └───────────────────────────────────┘ │
│ │
└─────────────────────────────────────────┘

2.4 Zero-Trust Execution​

AUs must assume:

  • No network access (blocked by worker)
  • Limited filesystem access (only specified paths)
  • No auto-downloading of models or dependencies
  • Timeouts enforced externally (by AGW)
  • Sandboxed execution (cgroups, namespaces)

3. AU Contract​

3.1 Required Behaviors​

Every AU MUST:

  1. Accept binary input via stdin

    • Read data as byte stream (not text)
    • Handle arbitrary binary formats (images, PDFs, etc.)
  2. Produce structured JSON output via stdout

    • Must be valid JSON
    • Must match declared output schema
    • Pretty-printed recommended (for debugging)
  3. Send errors to stderr only

    • Never mix errors with stdout JSON
    • Use structured logging if needed (stderr)
  4. Implement --describe flag

    • Output JSON matching describe.schema.json
    • Includes name, version, capabilities, inputs, outputs, config
  5. Accept configuration via CLI args or environment variables

    • --model-path or $MODEL_PATH for models
    • Other config via flags (e.g., --prompt, --format)
  6. Exit with appropriate codes

    • 0 = Success
    • 1 = General error
    • 2 = Invalid input/arguments
    • 3+ = Domain-specific errors (optional)

3.2 Forbidden Behaviors​

AUs MUST NOT:

  1. Auto-download models or dependencies

    • Models must be provided via explicit path
    • Fail fast if model not found
  2. Write to filesystem without explicit permission

    • No temp files unless in specified temp dir
    • No logging to files (use stderr)
  3. Make network requests

    • No API calls to external services
    • No telemetry or analytics
  4. Read configuration from global files

    • No ~/.config, no /etc/ files
    • Config via CLI args or env vars only
  5. Rely on specific working directory

    • All paths must be absolute or relative to explicit base

4. Command-Line Interface​

4.1 Required Flags​

AU_NAME [OPTIONS] [PROMPT]

--describe (required)

  • Prints AU model card as JSON
  • Exits after printing (does not process stdin)
  • Example: agx-ocr --describe

4.2 Common Optional Flags​

--model-path <PATH> or $MODEL_PATH (common for ML-based AUs)

  • Filesystem path to model file (GGUF, ONNX, etc.)
  • No default value (fail if not provided)
  • Example: agx-ocr --model-path /models/deepseek-ocr.gguf

--prompt <TEXT> (optional, for vision/language models)

  • Custom user prompt
  • Example: agx-ocr --prompt "Extract table data"

PROMPT (positional argument, alternative to --prompt)

  • Example: agx-ocr "Extract chart values" < chart.png

4.3 Example Invocations​

# Get model card
agx-ocr --describe

# Run OCR with model
cat image.png | agx-ocr --model-path /models/ocr.gguf > result.json

# Run with custom prompt
echo "image.png" | agx-ocr --model-path /models/ocr.gguf --prompt "Extract invoice data"

# Positional prompt
agx-ocr "Describe this chart" --model-path /models/ocr.gguf < chart.png

5. Input/Output Protocol​

5.1 Input: Binary stdin​

Format:

  • Raw binary bytes (PNG, JPEG, PDF, etc.)
  • No assumptions about encoding
  • Read entire stream until EOF

Example (Rust):

use std::io::{self, Read};

fn main() -> Result<()> {
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf)?;

// Process buf as binary data
let result = process_image(&buf)?;

println!("{}", serde_json::to_string_pretty(&result)?);
Ok(())
}

5.2 Output: JSON stdout​

Format:

  • Valid JSON (parseable by any JSON parser)
  • Pretty-printed recommended (readability)
  • No extra text before/after JSON
  • Schema matches declared output in --describe

Example Output (agx-ocr):

{
"text": "Hello World",
"regions": [
{
"text": "Hello",
"confidence": 0.98,
"bbox": [10.0, 20.0, 100.0, 50.0]
},
{
"text": "World",
"confidence": 0.95,
"bbox": [110.0, 20.0, 200.0, 50.0]
}
],
"model": "deepseek-ocr-v1"
}

5.3 Errors: stderr​

Format:

  • Human-readable error messages
  • Optional: Structured logging (JSON lines)
  • Never printed to stdout

Example (stderr):

Error: Failed to decode image
Caused by: Invalid PNG header

Example (structured logging to stderr):

{"level":"error","msg":"Failed to decode image","error":"Invalid PNG header"}

6. Model Card (--describe)​

6.1 Schema​

Model card must conform to specs/describe.schema.json:

{
"name": "string", // AU name (e.g., "agx-ocr")
"version": "string", // Semver version
"description": "string", // Human-readable summary
"capabilities": ["string"], // Tags: ["ocr", "image-to-text"]
"inputs": [
{
"media_type": "string", // MIME type (e.g., "image/*")
"description": "string" // Human-readable
}
],
"outputs": [
{
"media_type": "string", // MIME type (e.g., "application/json")
"description": "string"
}
],
"config": {
"param-name": {
"type": "string", // Type: string, integer, boolean
"description": "string",
"default": null // Default value (or null if required)
}
}
}

6.2 Example (agx-ocr)​

{
"name": "agx-ocr",
"version": "0.1.0",
"description": "Agentic Unit for OCR using DeepSeek GGUF models. Reads image bytes from stdin and outputs structured JSON.",
"capabilities": ["ocr", "image-to-text"],
"inputs": [
{
"media_type": "image/*",
"description": "Binary image data (PNG, JPEG) via stdin"
}
],
"outputs": [
{
"media_type": "application/json",
"description": "OCR result as structured JSON (text, regions, confidences)"
}
],
"config": {
"model-path": {
"type": "string",
"description": "Filesystem path to DeepSeek GGUF model file.",
"default": null
}
}
}

6.3 Capabilities Taxonomy​

Common capability tags:

CapabilityDescription
ocrOptical character recognition
image-to-textImage understanding/description
pdfPDF parsing/extraction
table-extractionExtract tables from documents
nlpNatural language processing
translationLanguage translation
summarizationText summarization
classificationClassify documents/images
entity-extractionNamed entity recognition

7. Error Handling​

7.1 Error Categories​

Input Errors (exit code 2):

  • Invalid image format
  • Corrupt binary data
  • Missing required arguments
  • Model file not found

Processing Errors (exit code 1):

  • Model inference failed
  • Out of memory
  • Unsupported feature

Example:

use anyhow::{bail, Context, Result};

fn main() -> Result<()> {
let model_path = std::env::var("MODEL_PATH")
.context("MODEL_PATH not set")?;

if !std::path::Path::new(&model_path).exists() {
bail!("Model file not found: {}", model_path);
}

// ... process
Ok(())
}

7.2 Error Messages​

Good error messages:

  • ✅ Error: Model file not found: /models/ocr.gguf
  • ✅ Error: Invalid image format. Expected PNG or JPEG, got PDF
  • ✅ Error: Image too large (50MB). Maximum supported: 20MB

Bad error messages:

  • ❌ Error: Something went wrong
  • ❌ Segmentation fault
  • ❌ panic: index out of bounds

7.3 Graceful Degradation​

When possible, return partial results:

{
"text": "Partial OCR result",
"regions": [...],
"warnings": [
"Low confidence region skipped",
"Unrecognized character: \u00ff"
]
}

8. Security Requirements​

8.1 Input Validation​

Always validate:

  • File format magic bytes
  • Size limits (prevent DoS)
  • Image dimensions (prevent OOM)
  • String lengths (prevent buffer overflows)

Example:

const MAX_INPUT_SIZE: usize = 50 * 1024 * 1024; // 50MB

fn validate_input(buf: &[u8]) -> Result<()> {
if buf.len() > MAX_INPUT_SIZE {
bail!("Input too large: {}MB (max 50MB)", buf.len() / 1024 / 1024);
}

// Check magic bytes for PNG
if buf.len() >= 8 && &buf[0..8] != b"\x89PNG\r\n\x1a\n" {
bail!("Invalid PNG header");
}

Ok(())
}

8.2 Path Validation​

Never trust user-provided paths:

use std::path::{Path, PathBuf};

fn validate_model_path(path: &str) -> Result<PathBuf> {
let p = PathBuf::from(path).canonicalize()?;

// Prevent path traversal
if path.contains("..") {
bail!("Path traversal detected");
}

// Ensure file exists
if !p.exists() {
bail!("Model file not found: {}", path);
}

Ok(p)
}

8.3 Resource Limits​

AUs should be defensive about resource usage:

  • Limit memory allocation
  • Set timeouts on inference
  • Bound output size
use std::time::Duration;

const MAX_INFERENCE_TIME: Duration = Duration::from_secs(300); // 5 min
const MAX_OUTPUT_SIZE: usize = 10 * 1024 * 1024; // 10MB

8.4 No Secrets in Logs​

Never log sensitive data to stderr:

  • ❌ API keys
  • ❌ Model weights (binary)
  • ❌ User input verbatim (may contain PII)

9. Examples​

9.1 Minimal AU (Echo)​

use std::io::{self, Read};
use anyhow::Result;
use serde::Serialize;

#[derive(Serialize)]
struct EchoResult {
input_size: usize,
sha256: String,
}

fn main() -> Result<()> {
// Read stdin
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf)?;

// Process
let hash = sha256::digest(&buf);
let result = EchoResult {
input_size: buf.len(),
sha256: hash,
};

// Output JSON
println!("{}", serde_json::to_string_pretty(&result)?);
Ok(())
}

9.2 AU with --describe​

use clap::Parser;

#[derive(Parser)]
struct Cli {
#[arg(long)]
describe: bool,
}

fn main() -> Result<()> {
let cli = Cli::parse();

if cli.describe {
print_model_card()?;
return Ok(());
}

// ... normal processing
Ok(())
}

fn print_model_card() -> Result<()> {
let card = serde_json::json!({
"name": "agx-echo",
"version": "1.0.0",
"description": "Echo AU that returns input hash",
"capabilities": ["hash", "checksum"],
"inputs": [{"media_type": "*/*", "description": "Any binary data"}],
"outputs": [{"media_type": "application/json", "description": "SHA256 hash"}]
});
println!("{}", serde_json::to_string_pretty(&card)?);
Ok(())
}

9.3 AU with Model Loading​

use std::path::PathBuf;
use clap::Parser;

#[derive(Parser)]
struct Cli {
#[arg(long, env = "MODEL_PATH")]
model_path: Option<PathBuf>,
}

fn main() -> Result<()> {
let cli = Cli::parse();

let model_path = cli.model_path
.ok_or_else(|| anyhow::anyhow!("MODEL_PATH required"))?;

if !model_path.exists() {
bail!("Model not found: {:?}", model_path);
}

let model = load_model(&model_path)?;

// ... process with model
Ok(())
}

10. Validation Checklist​

Before publishing an AU, verify:

Core Contract​

  • --describe flag implemented
  • Outputs valid JSON matching describe.schema.json
  • Reads binary data from stdin
  • Writes structured JSON to stdout
  • Errors go to stderr only
  • Exit codes: 0 (success), 1 (error), 2 (invalid input)

Security​

  • No auto-download of models
  • Path validation prevents traversal
  • Input size limits enforced
  • No secrets logged to stderr
  • No network requests

Error Handling​

  • Descriptive error messages
  • Graceful handling of corrupt input
  • Model file not found → clear error
  • Out of memory → graceful exit

Documentation​

  • README.md with usage examples
  • Model card includes all capabilities
  • Config parameters documented
  • License files present (MIT/Apache-2.0)

Testing​

  • Unit tests for core logic
  • Integration tests with sample inputs
  • --describe output validates against schema
  • Handles malformed input gracefully

Performance​

  • Processes typical inputs within reasonable time
  • Memory usage bounded
  • No leaks or resource exhaustion


Maintained by: AGX Core Team Review cycle: Per major version release Questions? Open an issue in the relevant AU repository or agenix/agenix