The CLI Adapter for apcore — Expose modules as high-performance, AI-perceivable command-line tools.
Build once, invoke by Code, AI, or Terminal.
| Spec repo | github.com/aiperceivable/apcore-cli |
| Python SDK | github.com/aiperceivable/apcore-cli-python |
| TypeScript SDK | github.com/aiperceivable/apcore-cli-typescript |
| Rust SDK | github.com/aiperceivable/apcore-cli-rust |
| apcore core | github.com/aiperceivable/apcore |
apcore-cli is the "inside-out" adapter for the apcore ecosystem. It takes your apcore modules and automatically exposes them as CLI subcommands — with zero code changes.
It serves as the terminal-native counterpart to apcore-mcp (Model Context Protocol) and apcore-a2a (Agent-to-Agent).
apcore Module Registry apcore-cli Adapter (grouped)
━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
math.add(a, b) ──┐
math.sub(a, b) ──┤──→ apcore-cli math add --a 1 --b 2
system.health.summary() ──┤──→ apcore-cli system health.summary
git.commit(msg) ──┤──→ apcore-cli list --tag math
db.query(sql) ──┘──→ apcore-cli describe math.add
=== "Python"
```bash
pip install apcore-cli
```
**Requirements:** Python 3.11+, pip or poetry
=== "TypeScript"
```bash
npm install apcore-cli
# or
pnpm add apcore-cli
```
**Requirements:** Node.js 18+, npm or pnpm
=== "Rust"
```toml
# Cargo.toml
[dependencies]
apcore-cli = "0.6"
```
```bash
cargo add apcore-cli
```
**Requirements:** Rust 2021 edition, cargo
=== "Python"
```bash
git clone https://github.com/aiperceivable/apcore-cli-python.git
cd apcore-cli-python
pip install -e ".[dev]"
export APCORE_EXTENSIONS_ROOT=examples/extensions
apcore-cli math.add --a 5 --b 10
# {"sum": 15}
```
=== "TypeScript"
```bash
git clone https://github.com/aiperceivable/apcore-cli-typescript.git
cd apcore-cli-typescript
pnpm install
export APCORE_EXTENSIONS_ROOT=examples/extensions
npx apcore-cli math.add --a 5 --b 10
# {"sum": 15}
```
=== "Rust"
```bash
git clone https://github.com/aiperceivable/apcore-cli-rust.git
cd apcore-cli-rust
cargo build --release
export APCORE_EXTENSIONS_ROOT=examples/extensions
./target/release/apcore-cli math.add --a 5 --b 10
# {"sum": 15}
```
# List all discovered modules
apcore-cli list
# Search by keyword
apcore-cli list --search email
# Filter by tag
apcore-cli list --tag math
# Filter by annotation
apcore-cli list --annotation destructive --annotation requires-approval
# See full details for a module
apcore-cli describe math.add
# Validate without executing
apcore-cli validate math.add --a 5 --b hello# Pipe JSON input
echo '{"a": 100, "b": 200}' | apcore-cli math.add --input -
# {"sum": 300}
# CLI flags override STDIN values
echo '{"a": 1, "b": 2}' | apcore-cli math.add --input - --a 999
# {"sum": 1001}
# Output as CSV
apcore-cli math.add --a 5 --b 10 --format csv
# Select specific fields
apcore-cli sysutil.info --fields os,hostname
# Chain with other tools
apcore-cli sysutil.info --format json | jq '.os, .hostname'# One-time setup
export APCORE_EXTENSIONS_ROOT=./extensions
# Or pass it directly
apcore-cli --extensions-dir ./extensions math.add --a 42 --b 58=== "Python"
```python
# extensions/greet/hello.py
from pydantic import BaseModel
class Input(BaseModel):
name: str
greeting: str = "Hello"
class Output(BaseModel):
message: str
class GreetHello:
input_schema = Input
output_schema = Output
description = "Greet someone by name"
def execute(self, inputs, context=None):
return {"message": f"{inputs['greeting']}, {inputs['name']}!"}
```
=== "TypeScript"
```typescript
// extensions/greet/hello.ts
import { module } from "apcore-js";
export const greetHello = module({
id: "greet.hello",
description: "Greet someone by name",
inputSchema: {
properties: {
name: { type: "string" },
greeting: { type: "string", default: "Hello" },
},
required: ["name"],
},
execute: async (inputs) => {
return { message: `${inputs.greeting}, ${inputs.name}!` };
},
});
```
=== "Rust"
```rust
// extensions/greet/hello.rs
use apcore::module;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Deserialize)]
struct Input {
name: String,
#[serde(default = "default_greeting")]
greeting: String,
}
fn default_greeting() -> String { "Hello".into() }
#[derive(Serialize)]
struct Output { message: String }
pub fn execute(inputs: Value, _ctx: Option<Value>) -> Value {
let input: Input = serde_json::from_value(inputs).unwrap();
serde_json::to_value(Output {
message: format!("{}, {}!", input.greeting, input.name),
}).unwrap()
}
```
Run it:
apcore-cli greet.hello --name World
# {"message": "Hello, World!"}=== "Python"
```python
from apcore_cli import create_cli
# Standalone mode
cli = create_cli(extensions_dir="./extensions", prog_name="myapp")
cli(standalone_mode=True)
# Embedded mode (pre-populated registry)
from apcore import Registry, Executor
registry = Registry("./extensions")
registry.discover()
executor = Executor(registry)
cli = create_cli(registry=registry, executor=executor, prog_name="myapp")
# With custom commands
import click
@click.command()
@click.argument("env")
def deploy(env):
"""Deploy to target environment."""
click.echo(f"Deploying to {env}...")
cli = create_cli(
extensions_dir="./extensions",
prog_name="myapp",
extra_commands=[deploy],
)
```
=== "TypeScript"
```typescript
import { createCli } from "apcore-cli";
// Standalone mode
const cli = createCli({ extensionsDir: "./extensions", progName: "myapp" });
// Embedded mode (pre-populated registry)
const cli = createCli({
registry: myRegistry,
executor: myExecutor,
progName: "myapp",
});
// With custom commands
import { Command } from "commander";
const deployCmd = new Command("deploy")
.argument("<env>")
.action((env) => console.log(`Deploying to ${env}...`));
const cli = createCli({
extensionsDir: "./extensions",
progName: "myapp",
extraCommands: [deployCmd],
});
```
=== "Rust"
```rust
use apcore_cli::CliConfig;
use clap::Command;
// Standalone mode
let config = CliConfig {
extensions_dir: Some("./extensions".into()),
prog_name: Some("myapp".into()),
..Default::default()
};
// Embedded mode (pre-populated registry)
let config = CliConfig {
registry: Some(Arc::new(my_registry)),
executor: Some(Arc::new(my_executor)),
prog_name: Some("myapp".into()),
..Default::default()
};
// With custom commands
let deploy = Command::new("deploy")
.arg(clap::Arg::new("env").required(true));
let config = CliConfig {
extra_commands: vec![deploy],
..Default::default()
};
```
# Check if a call would succeed without executing
apcore-cli math.add --a 5 --b hello --dry-run
# ✓ module_id OK
# ✓ module_lookup OK
# ✓ call_chain OK
# ✓ acl OK
# ✗ schema {"field": "b", "expected": "integer"}
#
# Result: FAIL (1 error(s), 0 warning(s))# See which pipeline steps ran and their timing
apcore-cli math.add --a 5 --b 10 --trace
# {"sum": 15}
#
# Pipeline Trace (strategy: standard, 11 steps, 23.4ms)
# ✓ context_creation 0.1ms
# ✓ call_chain_guard 0.0ms
# ✓ module_lookup 1.2ms
# ...# Health overview
apcore-cli health
# Usage statistics
apcore-cli usage --period 7d
# Disable a module
apcore-cli disable db.dangerous --reason "release freeze" --yes
# View pipeline strategy
apcore-cli describe-pipeline --strategy minimal# Stream large results as JSONL
apcore-cli data.export --query "SELECT *" --stream
# Each line is one JSON object, flushed immediately
# {"row": 1, "data": {...}}
# {"row": 2, "data": {...}}- Grouped Commands -- Modules with dots in their names are auto-grouped into nested subcommands (
apcore-cli product listinstead ofapcore-cli product.list);display.cli.groupin binding.yaml overrides the auto-detected group - Display Overlay --
metadata["display"]["cli"]controls CLI command names, descriptions, and guidance per module (§5.13); set viabinding_pathincreate_cli()/fastapi-apcore - Zero-Config Routing -- Automatically maps module IDs (e.g.,
math.add) to CLI commands - Schema-Driven Args -- Uses
input_schemato generate CLI arguments, types, and validation - Boolean Flag Pairs --
--verbose/--no-verbosefrom"type": "boolean"schema properties - Enum Choices --
"enum": ["json", "csv"]becomes--format jsonwith Click validation - STDIN Piping --
--input -reads JSON from STDIN, CLI flags override for duplicate keys - TTY-Adaptive Output -- Rich tables for terminals, JSON for pipes (configurable via
--format) - Approval Gate -- TTY-aware HITL prompts for modules with
requires_approval: true, with--yesbypass and 60s timeout - Schema Validation -- Inputs validated against JSON Schema before execution, with
$ref/allOf/anyOf/oneOfresolution - Security -- API key auth (keyring + AES-256-GCM), append-only audit logging, subprocess sandboxing
- Shell Completions --
apcore-cli completion bash|zsh|fishgenerates completion scripts with dynamic module ID completion - Man Pages --
apcore-cli man <command>generates roff-formatted man pages;--help --mangenerates a full program man page covering all commands - Verbose Help -- Built-in apcore options are hidden by default; pass
--help --verboseto show the full option list - Documentation Links --
set_docs_url()/setDocsUrl()adds online documentation URLs to help footers and man pages - Audit Logging -- All executions logged to
~/.apcore-cli/audit.jsonlwith SHA-256 input hashing
apcore-cli [OPTIONS] COMMAND [ARGS]
| Option | Default | Description |
|---|---|---|
--extensions-dir |
./extensions |
Path to apcore extensions directory |
--log-level |
WARNING |
Logging: DEBUG, INFO, WARNING, ERROR |
--version |
Show version and exit | |
--help |
Show help and exit |
| Command | Description |
|---|---|
list |
List available modules with optional tag filtering, search, and annotation filters |
describe <module_id> |
Show full module metadata and schemas |
validate <module_id> |
Run preflight checks without executing (dry-run) |
exec <module_id> |
Internal routing alias for module execution (modules are also available as direct top-level subcommands) |
health [<module_id>] |
Show module health status (requires system modules) |
usage [<module_id>] |
Show module usage statistics (requires system modules) |
enable <module_id> |
Enable a disabled module at runtime |
disable <module_id> |
Disable a module at runtime |
reload <module_id> |
Hot-reload a module from disk |
config get <key> |
Read a runtime configuration value |
config set <key> <value> |
Update a runtime configuration value (requires approval) |
describe-pipeline |
Show execution pipeline steps for a strategy |
completion <shell> |
Generate shell completion script (bash/zsh/fish) |
man <command> |
Generate man page in roff format |
When executing a module (e.g. apcore-cli math.add), these built-in options are always available:
| Option | Description |
|---|---|
--input - |
Read JSON input from STDIN |
--yes / -y |
Bypass approval prompts |
--large-input |
Allow STDIN input larger than 10MB |
--format |
Output format: json, table, csv, yaml, jsonl |
--fields |
Comma-separated dot-paths to select from the result |
--dry-run |
Run preflight checks without executing |
--trace |
Show execution pipeline trace with per-step timing |
--stream |
Stream output as JSONL (one JSON object per line) |
--strategy |
Execution pipeline: standard, internal, testing, performance, minimal |
--approval-timeout |
Override approval prompt timeout in seconds (default: 60) |
--approval-token |
Resume a pending approval with the given token |
--sandbox |
Run module in subprocess sandbox |
Schema-generated flags (e.g. --a, --b) are added automatically from the module's input_schema.
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Module execution error |
2 |
Invalid CLI input |
44 |
Module not found / disabled / load error |
45 |
Schema validation error |
46 |
Approval denied or timed out |
47 |
Configuration error |
48 |
Schema circular reference |
77 |
ACL denied |
130 |
Execution cancelled (Ctrl+C) |
apcore-cli uses a 4-tier configuration precedence:
- CLI flag (highest):
--extensions-dir ./custom - Environment variable:
APCORE_EXTENSIONS_ROOT=./custom - Config file:
apcore.yaml - Default (lowest):
./extensions
| Variable | Description | Default |
|---|---|---|
APCORE_EXTENSIONS_ROOT |
Path to extensions directory | ./extensions |
APCORE_CLI_AUTO_APPROVE |
Set to 1 to bypass all approval prompts |
(unset) |
APCORE_CLI_LOGGING_LEVEL |
CLI-specific log level (takes priority over APCORE_LOGGING_LEVEL) |
WARNING |
APCORE_LOGGING_LEVEL |
Global apcore log level (fallback when APCORE_CLI_LOGGING_LEVEL is unset) |
WARNING |
APCORE_AUTH_API_KEY |
API key for remote registry authentication | (unset) |
APCORE_CLI_SANDBOX |
Set to 1 to enable subprocess sandboxing |
(unset) |
APCORE_CLI_HELP_TEXT_MAX_LENGTH |
Maximum characters for CLI option help text before truncation | 1000 |
APCORE_CLI_APPROVAL_TIMEOUT |
Approval prompt timeout in seconds | 60 |
APCORE_CLI_STRATEGY |
Default execution pipeline strategy | standard |
APCORE_CLI_GROUP_DEPTH |
Multi-level grouping depth for nested subcommands | 1 |
extensions:
root: ./extensions
logging:
level: DEBUG
sandbox:
enabled: false
cli:
help_text_max_length: 1000
approval_timeout: 60
strategy: standard
group_depth: 1| apcore | CLI |
|---|---|
metadata["display"]["cli"]["alias"] or module_id |
Command name — auto-grouped by first . segment (apcore-cli math add) |
metadata["display"]["cli"]["description"] or description |
--help text |
input_schema.properties |
CLI flags (--a, --b) |
input_schema.required |
Required flag enforcement |
annotations.requires_approval |
HITL approval prompt |
User / AI Agent (terminal)
|
v
apcore-cli (the adapter)
|
+-- ConfigResolver 4-tier config precedence
+-- GroupedModuleGroup Auto-grouped nested Click commands (extends LazyModuleGroup)
+-- SchemaParser JSON Schema -> Click options
+-- RefResolver $ref / allOf / anyOf / oneOf
+-- ApprovalGate TTY-aware HITL approval
+-- OutputFormatter TTY-adaptive JSON/table output
+-- AuditLogger JSON Lines execution logging
+-- Sandbox Subprocess isolation
|
v
apcore Registry + Executor (your modules, unchanged)
| Language | Repository | Status |
|---|---|---|
| Python | apcore-cli-python | v0.6.0 -- 11 features, 348 tests |
| TypeScript | apcore-cli-typescript | v0.6.0 -- 11 features, 247 tests |
| Rust | apcore-cli-rust | v0.6.0 -- 11 features, 553 tests |
This repository contains the specification and design documents:
apcore-cli/
├── docs/
│ ├── project-apcore-cli.md Project manifest (11 features)
│ ├── tech-design.md Tech Design v2.0
│ ├── srs.md Software Requirements Specification
│ └── features/
│ ├── overview.md Feature index
│ ├── core-dispatcher.md FE-01: CLI entry point
│ ├── schema-parser.md FE-02: JSON Schema → flags
│ ├── approval-gate.md FE-03: HITL approval
│ ├── discovery.md FE-04: list / describe
│ ├── config-resolver.md FE-07: 4-tier config
│ ├── output-formatter.md FE-08: TTY-adaptive output
│ ├── security.md FE-05: Auth, encryption
│ ├── shell-integration.md FE-06: Completions, man pages
│ ├── grouped-commands.md FE-09: Nested subcommands
│ ├── init-command.md FE-10: Module scaffolding
│ └── usability-enhancements.md FE-11: v0.6.0 enhancements
├── conformance/ Cross-language test fixtures
├── CHANGELOG.md
└── README.md
For the implementation, see the SDKs:
=== "Python"
```
apcore-cli-python/src/apcore_cli/
├── __main__.py Entry point, create_cli()
├── cli.py Dispatcher, GroupedModuleGroup
├── approval.py HITL approval + CliApprovalHandler
├── output.py TTY-adaptive formatting
├── discovery.py list, describe, validate commands
├── system_cmd.py health, usage, enable, disable, reload, config
├── strategy.py describe-pipeline command
├── config.py 4-tier ConfigResolver
├── schema_parser.py JSON Schema → Click options
├── shell.py Completion + man pages
└── security/ Audit, auth, encryption, sandbox
```
=== "TypeScript"
```
apcore-cli-typescript/src/
├── main.ts Entry point, createCli()
├── cli.ts LazyModuleGroup, GroupedModuleGroup
├── approval.ts HITL approval + CliApprovalHandler
├── output.ts TTY-adaptive formatting
├── discovery.ts list, describe, validate commands
├── system-cmd.ts health, usage, enable, disable, reload, config
├── strategy.ts describe-pipeline command
├── config.ts 4-tier ConfigResolver
├── schema-parser.ts JSON Schema → Commander options
├── shell.ts Completion + man pages
└── security/ Audit, auth, encryption, sandbox
```
=== "Rust"
```
apcore-cli-rust/src/
├── main.rs Entry point, dispatch routing
├── cli.rs Dispatcher, module execution
├── lib.rs CliConfig, exit codes
├── approval.rs HITL approval + CliApprovalHandler
├── output.rs TTY-adaptive formatting
├── discovery.rs list, describe commands
├── validate.rs validate command
├── system_cmd.rs health, usage, enable, disable, reload, config
├── strategy.rs describe-pipeline command
├── config.rs 4-tier ConfigResolver
├── schema_parser.rs JSON Schema → clap args
├── shell.rs Completion + man pages
└── security/ Audit, auth, encryption, sandbox
```
| Project | Description |
|---|---|
| apcore | Core protocol and framework for AI-Perceivable modules |
| apcore-mcp | Model Context Protocol adapter |
| apcore-a2a | Agent-to-Agent adapter |
| django-apcore | Django integration |
| flask-apcore | Flask integration |
Apache-2.0