Terminal adapter for apcore. Execute AI-Perceivable modules from the command line.
| Python SDK | github.com/aipartnerup/apcore-cli-python |
| Spec repo | github.com/aipartnerup/apcore-cli |
| apcore core | github.com/aipartnerup/apcore |
apcore-cli turns any apcore-based project into a fully featured CLI tool — with zero code changes to your existing modules.
┌──────────────────┐
│ django-apcore │ <- your existing apcore project (unchanged)
│ flask-apcore │
│ ... │
└────────┬─────────┘
│ extensions directory
v
┌──────────────────┐
│ apcore-cli │ <- just install & point to extensions dir
└───┬──────────┬───┘
│ │
v v
Terminal Unix
Commands Pipes
- Zero intrusion -- your apcore project needs no code changes, no imports, no dependencies on apcore-cli
- Zero configuration -- point to an extensions directory, everything is auto-discovered
- Pure adapter -- apcore-cli reads from the apcore Registry; it never modifies your modules
- Unix-native -- JSON output for pipes, rich tables for terminals, STDIN input, shell completions
pip install apcore-cliRequires Python 3.11+ and apcore >= 0.13.0.
The repo includes 8 example modules you can run immediately:
git clone https://github.com/aipartnerup/apcore-cli-python.git
cd apcore-cli-python
pip install -e ".[dev]"
# Run a module
apcore-cli --extensions-dir examples/extensions math.add --a 5 --b 10
# {"sum": 15}
# List all modules
apcore-cli --extensions-dir examples/extensions list --format json
# Run all examples
bash examples/run_examples.shSee Examples for the full list of example modules and usage patterns.
If you already have an apcore-based project with an extensions directory:
# Execute a module
apcore-cli --extensions-dir ./extensions math.add --a 42 --b 58
# Or set the env var once
export APCORE_EXTENSIONS_ROOT=./extensions
apcore-cli math.add --a 42 --b 58All modules are auto-discovered. CLI flags are auto-generated from each module's JSON Schema.
from apcore import Registry, Executor
from apcore_cli.__main__ import create_cli
# Build the CLI from your registry
cli = create_cli(extensions_dir="./extensions")
cli(standalone_mode=True)Or use the LazyModuleGroup directly with Click:
import click
from apcore import Registry, Executor
from apcore_cli.cli import LazyModuleGroup
registry = Registry(extensions_dir="./extensions")
registry.discover()
executor = Executor(registry)
@click.group(cls=LazyModuleGroup, registry=registry, executor=executor)
def cli():
pass
cli()your-project/
├── extensions/ <- modules live here
│ ├── math/
│ │ └── add.py
│ ├── text/
│ │ └── upper.py
│ └── ...
├── your_app.py <- your existing code (untouched)
└── ...
No changes to your project. Just install and run:
pip install apcore-cli
apcore-cli --extensions-dir ./extensions list
apcore-cli --extensions-dir ./extensions math.add --a 5 --b 10# 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}
# Chain with other tools
apcore-cli sysutil.info | jq '.os, .hostname'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 |
describe <module_id> |
Show full module metadata and schemas |
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 or table |
--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 |
extensions:
root: ./extensions
logging:
level: DEBUG
sandbox:
enabled: false
cli:
help_text_max_length: 1000- Auto-discovery -- all modules in the extensions directory are found and exposed as CLI commands
- Auto-generated flags -- JSON Schema
input_schemais converted to--flag valueCLI options with type 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 - Audit logging -- all executions logged to
~/.apcore-cli/audit.jsonlwith SHA-256 input hashing
| apcore | CLI |
|---|---|
module_id (math.add) |
Command name (apcore-cli math.add) |
description |
--help text |
input_schema.properties |
CLI flags (--a, --b) |
input_schema.required |
Validated post-collection via jsonschema.validate() (required fields shown as [required] in --help) |
annotations.requires_approval |
HITL approval prompt |
User / AI Agent (terminal)
|
v
apcore-cli (the adapter)
|
+-- ConfigResolver 4-tier config precedence
+-- LazyModuleGroup Dynamic Click command generation
+-- schema_parser JSON Schema -> Click options
+-- ref_resolver $ref / allOf / anyOf / oneOf
+-- approval TTY-aware HITL approval
+-- output TTY-adaptive JSON/table output
+-- AuditLogger JSON Lines execution logging
+-- Sandbox Subprocess isolation
|
v
apcore Registry + Executor (your modules, unchanged)
The examples/extensions/ directory contains 8 runnable modules:
| Module | Description | Usage |
|---|---|---|
math.add |
Add two integers | apcore-cli math.add --a 5 --b 10 |
math.multiply |
Multiply two integers | apcore-cli math.multiply --a 6 --b 7 |
text.upper |
Uppercase a string | apcore-cli text.upper --text hello |
text.reverse |
Reverse a string | apcore-cli text.reverse --text abcdef |
text.wordcount |
Count words/chars/lines | apcore-cli text.wordcount --text "hello world" |
sysutil.info |
OS, hostname, Python version | apcore-cli sysutil.info |
sysutil.env |
Read environment variables | apcore-cli sysutil.env --name HOME |
sysutil.disk |
Disk usage statistics | apcore-cli sysutil.disk --path / |
# Set extensions path (one time)
export APCORE_EXTENSIONS_ROOT=examples/extensions
# Execute modules
apcore-cli math.add --a 42 --b 58
apcore-cli text.upper --text "hello apcore"
apcore-cli sysutil.info
apcore-cli sysutil.disk --path /
# Discovery
apcore-cli list --format json
apcore-cli list --tag math --format json
apcore-cli describe math.add --format json
# STDIN piping
echo '{"a": 100, "b": 200}' | apcore-cli math.add --input -
# Shell completion
apcore-cli completion bash >> ~/.bashrc
apcore-cli completion zsh >> ~/.zshrc
apcore-cli completion fish > ~/.config/fish/completions/apcore-cli.fish
# Man pages
apcore-cli man list | man -l -
# Run all examples at once
bash examples/run_examples.shCreate a Python file in your extensions directory:
# 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']}!"}Then run it:
apcore-cli --extensions-dir ./extensions greet.hello --name World
# {"message": "Hello, World!"}
apcore-cli --extensions-dir ./extensions greet.hello --name Alice --greeting Hi
# {"message": "Hi, Alice!"}git clone https://github.com/aipartnerup/apcore-cli-python.git
cd apcore-cli-python
pip install -e ".[dev]"
pytest # 263 tests
pytest --cov # with coverage report
bash examples/run_examples.sh # run all examplesApache-2.0