Terminal adapter for apcore — execute AI-Perceivable modules from the command line
Project description
apcore-cli
Terminal adapter for apcore. Execute AI-Perceivable modules from the command line.
| Python SDK | github.com/aiperceivable/apcore-cli-python |
| Spec repo | github.com/aiperceivable/apcore-cli |
| apcore core | github.com/aiperceivable/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
Design Philosophy
- 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
Installation
pip install apcore-cli
Requires Python 3.11+ and apcore >= 0.17.1.
Quick Start
Try it now
The repo includes 8 example modules you can run immediately:
git clone https://github.com/aiperceivable/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 apcli list --format json
# Run all examples
bash examples/run_examples.sh
See Examples for the full list of example modules and usage patterns.
Zero-code approach
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 58
All modules are auto-discovered. CLI flags are auto-generated from each module's JSON Schema.
Programmatic approach (Python API)
from apcore_cli import create_cli
# Build the CLI from an extensions directory (auto-discovers modules)
cli = create_cli(extensions_dir="./extensions")
cli(standalone_mode=True)
Pre-populated registry
Frameworks that register modules at runtime (e.g. apflow's bridge) can pass a pre-populated Registry directly, skipping filesystem discovery entirely:
from apcore_cli import create_cli
# registry is already populated by your framework
cli = create_cli(registry=registry, prog_name="myapp")
cli(standalone_mode=True)
# Executor is auto-built from the registry if omitted.
# You can also provide your own:
cli = create_cli(registry=registry, executor=executor, prog_name="myapp")
Python API
The apcore_cli package exposes three public symbols:
| Export | Description |
|---|---|
__version__ |
Package version string |
create_cli(...) |
Factory that builds a ready-to-invoke click.Group. See the create_cli reference in the docs site for the full 8-parameter signature (extensions_dir, prog_name, commands_dir, binding_path, registry, executor, extra_commands, expose). |
ExposureFilter |
Declarative filter controlling which modules are exposed by the CLI (FE-12). |
Exposure filtering — restrict which modules are visible at the CLI layer without touching the underlying registry:
from apcore_cli import create_cli, ExposureFilter
# Only expose admin.* modules
cli = create_cli(
registry=registry,
executor=executor,
expose=ExposureFilter(mode="include", include=["admin.*"]),
)
# Or pass a config dict (equivalent)
cli = create_cli(
registry=registry,
executor=executor,
expose={"mode": "exclude", "exclude": ["debug.*", "test.*"]},
)
ExposureFilter supports mode="all" (default), "include", and "exclude", plus ExposureFilter.from_config(config) for dict-based construction, .is_exposed(module_id), and .filter_modules(module_ids).
Injecting custom commands — pass extra_commands=[...] to attach arbitrary Click commands alongside the auto-generated module commands (FE-11 extension point):
cli = create_cli(registry=registry, executor=executor, extra_commands=[my_custom_click_cmd])
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()
Adding Custom Commands
Fastest way (30 seconds)
apcore-cli apcli init module ops.deploy -d "Deploy to environment"
# Edit the generated file, add your logic
Zero-import way (convention discovery)
Drop a plain Python function into commands/:
# commands/deploy.py
def deploy(env: str, tag: str = "latest") -> dict:
"""Deploy the app to the given environment."""
return {"status": "deployed", "env": env}
Then run with --commands-dir commands/:
apcore-cli --commands-dir commands/ deploy deploy --env prod
The init module command supports three styles via --style:
- convention (default) — generates a plain Python function in the commands directory
- decorator — generates a
@module-decorated function in the extensions directory - binding — generates a
.binding.yamlfile
Integration with Existing Projects
Typical apcore project structure
your-project/
├── extensions/ <- modules live here
│ ├── math/
│ │ └── add.py
│ ├── text/
│ │ └── upper.py
│ └── ...
├── your_app.py <- your existing code (untouched)
└── ...
Adding CLI support
No changes to your project. Just install and run:
pip install apcore-cli
apcore-cli --extensions-dir ./extensions apcli list
apcore-cli --extensions-dir ./extensions math add --a 5 --b 10
STDIN piping (Unix pipes)
# 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'
CLI Reference
apcore-cli [OPTIONS] COMMAND [ARGS]
Global Options
| 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 | |
--verbose |
Show hidden built-in options in --help output |
|
--man |
Print man page to stdout (use with --help) |
Built-in Commands
apcore-cli ships with 14 built-in commands, all accessible under the apcli subgroup (e.g. apcore-cli apcli list). Root-level shims are kept for back-compat and will be removed in v0.8.
Module invocation
| Command | Description |
|---|---|
apcli exec <module_id> |
Execute a module (delegates to Executor.call()) |
apcli list |
List registered modules (supports --tag/--search/--status/--annotation/--sort/--reverse/--deprecated/--deps filters) |
apcli describe <module_id> |
Show full module metadata and schema |
System management (FE-11, v0.6.0)
| Command | Description |
|---|---|
apcli config get/set <key> |
Read or update runtime config values |
apcli health [<module_id>] |
Show module health status |
apcli usage [<module_id>] |
Show module usage statistics |
apcli enable <module_id> |
Enable a disabled module |
apcli disable <module_id> |
Disable a module at runtime |
apcli reload <module_id> |
Hot-reload a module from disk |
Workflow
| Command | Description |
|---|---|
apcli validate <module_id> |
Preflight-check a module without executing it (--dry-run) |
apcli describe-pipeline |
Show execution pipeline steps for a strategy (FE-11) |
apcli init module <module_id> |
Scaffold a new module (--style decorator|convention|binding) |
Shell integration
| Command | Description |
|---|---|
apcli completion <shell> |
Generate shell completion script (bash/zsh/fish) |
apcli man <command> |
Generate roff man page for a command |
Module Execution Options
When executing a module (e.g. apcore-cli math add), these built-in options are available (hidden by default; pass --help --verbose to display them):
| 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} |
--sandbox |
Run module in subprocess sandbox (not yet implemented) |
--dry-run |
Run preflight checks without executing (FE-11, v0.6.0) |
--trace |
Emit execution pipeline trace (v0.6.0) |
--stream |
Stream results line-by-line for stream-capable modules (v0.6.0) |
--strategy <name> |
Override execution strategy: standard/internal/testing/performance/minimal (v0.6.0) |
--fields <csv> |
Select specific output fields using dot-path notation (v0.6.0) |
--approval-timeout <seconds> |
Override approval timeout (default 60) (v0.6.0) |
--approval-token <token> |
Provide a pre-obtained approval token (v0.6.0) |
Schema-generated flags (e.g. --a, --b) are added automatically from the module's input_schema.
The list command gained several discovery filters in v0.6.0: --search, --status, --annotation, --sort, --reverse, --deprecated, and --deps.
Exit Codes
| 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) |
Configuration
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
Environment Variables
| 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-gate timeout in seconds (v0.6.0) | 60 |
APCORE_CLI_STRATEGY |
Default execution strategy (v0.6.0) | standard |
APCORE_CLI_GROUP_DEPTH |
Depth of automatic command grouping by . segments (v0.6.0) |
1 |
Config File (apcore.yaml)
extensions:
root: ./extensions
logging:
level: DEBUG
sandbox:
enabled: false
cli:
help_text_max_length: 1000
approval_timeout: 60 # v0.6.0
strategy: standard # v0.6.0
group_depth: 1 # v0.6.0
Features
- Auto-discovery -- all modules in the extensions directory are found and exposed as CLI commands
- Display overlay --
metadata["display"]["cli"]controls CLI command names, descriptions, and guidance per module (§5.13); set viabinding_pathincreate_cli()/fastapi-apcore - 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 - 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 apcli completion bash|zsh|fishgenerates completion scripts with dynamic module ID completion - Man pages --
apcore-cli apcli man <command>generates per-command man pages;--help --manprints a full-program man page viaconfigure_man_help() - Documentation URL --
set_docs_url()sets a base URL; per-command help showsDocs: {url}/commands/{name}, man page SEE ALSO links to the full docs site - Audit logging -- all executions logged to
~/.apcore-cli/audit.jsonlwith SHA-256 input hashing
How It Works
Mapping: apcore to CLI
| apcore | CLI |
|---|---|
metadata["display"]["cli"]["alias"] or module_id |
Command name — auto-grouped by first . segment (apcore-cli product get) |
metadata["display"]["cli"]["description"] or 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 |
Architecture
User / AI Agent (terminal)
|
v
apcore-cli (the adapter)
|
+-- ConfigResolver 4-tier config precedence
+-- GroupedModuleGroup (default) Multi-level command grouping (wraps LazyModuleGroup)
+-- LazyModuleGroup Lazy per-module Click command construction (base class)
+-- ExposureFilter Declarative module exposure filtering (FE-12)
+-- CliApprovalHandler Async approval handler protocol implementation (FE-11)
+-- system_cmd Runtime system-management (health/usage/enable/disable/reload/config)
+-- strategy Execution strategy dispatch (--strategy flag and describe-pipeline)
+-- init_cmd Module scaffolding (init subcommand)
+-- set_verbose_help Toggle built-in option visibility
+-- set_docs_url Set base URL for online docs
+-- build_program_man_page Full-program roff man page
+-- configure_man_help Add --help --man support to any CLI
+-- 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)
Examples
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 / |
Running examples
# 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 apcli list --format json
apcore-cli apcli list --tag math --format json
apcore-cli apcli describe math.add --format json
# STDIN piping
echo '{"a": 100, "b": 200}' | apcore-cli math add --input -
# Shell completion
apcore-cli apcli completion bash >> ~/.bashrc
apcore-cli apcli completion zsh >> ~/.zshrc
apcore-cli apcli completion fish > ~/.config/fish/completions/apcore-cli.fish
# Man pages
apcore-cli apcli man list | man -l -
# Run all examples at once
bash examples/run_examples.sh
Writing your own module
Create 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!"}
Development
The conformance suite under tests/conformance/ reads shared fixtures
from the spec repo (aiperceivable/apcore-cli). Clone it as a sibling
of this repo, or point APCORE_CLI_SPEC_REPO at an existing checkout:
# One-time: clone both repos side by side
git clone https://github.com/aiperceivable/apcore-cli.git
git clone https://github.com/aiperceivable/apcore-cli-python.git
cd apcore-cli-python
pip install -e ".[dev]"
pytest # reads fixtures from ../apcore-cli/conformance/
pytest --cov # with coverage report
bash examples/run_examples.sh # run all examples
Alternative layout (spec repo checked out elsewhere):
export APCORE_CLI_SPEC_REPO=/path/to/apcore-cli
pytest
Without the spec repo the conformance tests are skipped (pytest reports
them as skipped, not failed). CI clones the spec repo automatically —
see .github/workflows/ci.yml.
License
Apache-2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file apcore_cli-0.7.0.tar.gz.
File metadata
- Download URL: apcore_cli-0.7.0.tar.gz
- Upload date:
- Size: 359.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bda1f230f0f7ff9f4e258c04e8fd7c9b78c04204e4d104ae404fc3a9e75358e6
|
|
| MD5 |
883f1c52c8d3dda419f5064b94e510c6
|
|
| BLAKE2b-256 |
76f9f7f00a650b9c339e58c64511b510a60e88feefa816adb50cefe8f73f9020
|
File details
Details for the file apcore_cli-0.7.0-py3-none-any.whl.
File metadata
- Download URL: apcore_cli-0.7.0-py3-none-any.whl
- Upload date:
- Size: 83.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96a5ba0c9fc5be122bc5f5cd70f334b1f5252131352053702442ff5f71f7b925
|
|
| MD5 |
a559af95d7b56d638474d8c7ffdd1fb7
|
|
| BLAKE2b-256 |
d3cc40bcfc994288a40cb36ad8881fc76101ac955cd23299fc3fe4315cfd5020
|