apcore-cli 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. apcore_cli-0.1.0/.github/CODEOWNERS +3 -0
  2. apcore_cli-0.1.0/.github/copilot-ignore +13 -0
  3. apcore_cli-0.1.0/.github/workflows/ci.yml +46 -0
  4. apcore_cli-0.1.0/.gitignore +18 -0
  5. apcore_cli-0.1.0/.gitmessage +60 -0
  6. apcore_cli-0.1.0/.pre-commit-config.yaml +27 -0
  7. apcore_cli-0.1.0/CHANGELOG.md +37 -0
  8. apcore_cli-0.1.0/PKG-INFO +459 -0
  9. apcore_cli-0.1.0/README.md +422 -0
  10. apcore_cli-0.1.0/examples/extensions/math/add.py +23 -0
  11. apcore_cli-0.1.0/examples/extensions/math/multiply.py +23 -0
  12. apcore_cli-0.1.0/examples/extensions/sysutil/disk.py +47 -0
  13. apcore_cli-0.1.0/examples/extensions/sysutil/env.py +30 -0
  14. apcore_cli-0.1.0/examples/extensions/sysutil/info.py +40 -0
  15. apcore_cli-0.1.0/examples/extensions/text/reverse.py +22 -0
  16. apcore_cli-0.1.0/examples/extensions/text/upper.py +22 -0
  17. apcore_cli-0.1.0/examples/extensions/text/wordcount.py +29 -0
  18. apcore_cli-0.1.0/examples/run_examples.sh +111 -0
  19. apcore_cli-0.1.0/planning/approval-gate.md +95 -0
  20. apcore_cli-0.1.0/planning/config-resolver.md +90 -0
  21. apcore_cli-0.1.0/planning/core-dispatcher.md +148 -0
  22. apcore_cli-0.1.0/planning/discovery.md +81 -0
  23. apcore_cli-0.1.0/planning/output-formatter.md +100 -0
  24. apcore_cli-0.1.0/planning/overview.md +85 -0
  25. apcore_cli-0.1.0/planning/schema-parser.md +164 -0
  26. apcore_cli-0.1.0/planning/security-manager.md +126 -0
  27. apcore_cli-0.1.0/planning/shell-integration.md +92 -0
  28. apcore_cli-0.1.0/planning/state.json +65 -0
  29. apcore_cli-0.1.0/pyproject.toml +85 -0
  30. apcore_cli-0.1.0/src/apcore_cli/__init__.py +3 -0
  31. apcore_cli-0.1.0/src/apcore_cli/__main__.py +142 -0
  32. apcore_cli-0.1.0/src/apcore_cli/_sandbox_runner.py +25 -0
  33. apcore_cli-0.1.0/src/apcore_cli/approval.py +167 -0
  34. apcore_cli-0.1.0/src/apcore_cli/cli.py +315 -0
  35. apcore_cli-0.1.0/src/apcore_cli/config.py +94 -0
  36. apcore_cli-0.1.0/src/apcore_cli/discovery.py +75 -0
  37. apcore_cli-0.1.0/src/apcore_cli/output.py +190 -0
  38. apcore_cli-0.1.0/src/apcore_cli/ref_resolver.py +113 -0
  39. apcore_cli-0.1.0/src/apcore_cli/schema_parser.py +168 -0
  40. apcore_cli-0.1.0/src/apcore_cli/security/__init__.py +8 -0
  41. apcore_cli-0.1.0/src/apcore_cli/security/audit.py +53 -0
  42. apcore_cli-0.1.0/src/apcore_cli/security/auth.py +37 -0
  43. apcore_cli-0.1.0/src/apcore_cli/security/config_encryptor.py +94 -0
  44. apcore_cli-0.1.0/src/apcore_cli/security/sandbox.py +60 -0
  45. apcore_cli-0.1.0/src/apcore_cli/shell.py +185 -0
  46. apcore_cli-0.1.0/tests/__init__.py +0 -0
  47. apcore_cli-0.1.0/tests/conftest.py +28 -0
  48. apcore_cli-0.1.0/tests/test_approval.py +173 -0
  49. apcore_cli-0.1.0/tests/test_bugfixes.py +150 -0
  50. apcore_cli-0.1.0/tests/test_cli.py +370 -0
  51. apcore_cli-0.1.0/tests/test_config.py +141 -0
  52. apcore_cli-0.1.0/tests/test_discovery.py +148 -0
  53. apcore_cli-0.1.0/tests/test_e2e.py +468 -0
  54. apcore_cli-0.1.0/tests/test_integration.py +287 -0
  55. apcore_cli-0.1.0/tests/test_output.py +195 -0
  56. apcore_cli-0.1.0/tests/test_ref_resolver.py +191 -0
  57. apcore_cli-0.1.0/tests/test_schema_parser.py +224 -0
  58. apcore_cli-0.1.0/tests/test_security/__init__.py +0 -0
  59. apcore_cli-0.1.0/tests/test_security/test_audit.py +78 -0
  60. apcore_cli-0.1.0/tests/test_security/test_auth.py +62 -0
  61. apcore_cli-0.1.0/tests/test_security/test_config_encryptor.py +56 -0
  62. apcore_cli-0.1.0/tests/test_security/test_sandbox.py +50 -0
  63. apcore_cli-0.1.0/tests/test_shell.py +126 -0
@@ -0,0 +1,3 @@
1
+ # all workflow and CODEOWNERS itself modification must be approved by repository owner or core maintainer
2
+ .github/workflows/ @tercel
3
+ .github/CODEOWNERS @tercel
@@ -0,0 +1,13 @@
1
+ # Environment variables (sensitive data)
2
+ .env
3
+ .data
4
+
5
+ # Secrets
6
+ secrets/
7
+ *.pem
8
+ *.key
9
+
10
+ .claude/
11
+ CLAUDE.md
12
+ .cursor/
13
+
@@ -0,0 +1,46 @@
1
+ name: CI
2
+
3
+ permissions:
4
+ contents: read
5
+
6
+ on:
7
+ push:
8
+ branches: [ "main" ]
9
+ pull_request:
10
+ branches: [ "main" ]
11
+
12
+ jobs:
13
+ test:
14
+ name: Test on Python ${{ matrix.python-version }}
15
+ runs-on: ubuntu-latest
16
+ # container:
17
+ # image: python:${{ matrix.python-version }}
18
+ strategy:
19
+ fail-fast: false
20
+ matrix:
21
+ # Pin CI to a single, consistent Python version to reduce version-related
22
+ # test flakiness. Use 3.12 for CI stability; expand matrix later if desired.
23
+ python-version: ["3.12"]
24
+
25
+ steps:
26
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
27
+
28
+ - name: Set up Python
29
+ uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+
33
+ - name: Install uv
34
+ uses: astral-sh/setup-uv@v5
35
+
36
+ - name: Install dependencies
37
+ run: |
38
+ uv sync --extra dev
39
+
40
+ - name: Lint with Ruff
41
+ run: |
42
+ uv run ruff check src/ tests/
43
+
44
+ - name: Run tests
45
+ run: |
46
+ uv run pytest
@@ -0,0 +1,18 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .eggs/
7
+ .claude/
8
+ .idea/
9
+ .vscode/
10
+ .DS_Store
11
+ .ruff_cache/
12
+ .pytest_cache/
13
+ .coverage
14
+ .venv/
15
+ venv/
16
+ env/
17
+ .env
18
+ .forge
@@ -0,0 +1,60 @@
1
+ # <type>(<scope>): <subject>
2
+ #
3
+ # <body>
4
+ #
5
+ # <footer>
6
+
7
+ # Type must be one of the following:
8
+ # feat: A new feature
9
+ # fix: A bug fix
10
+ # docs: Documentation only changes
11
+ # style: Changes that do not affect the meaning of the code
12
+ # refactor: A code change that neither fixes a bug nor adds a feature
13
+ # perf: A code change that improves performance
14
+ # test: Adding missing tests or correcting existing tests
15
+ # chore: Changes to the build process or auxiliary tools
16
+ # ci: Changes to CI configuration files and scripts
17
+
18
+ # Scope is optional and can be anything specifying the place of the commit change.
19
+ # Examples: api, core, storage, cli, stdio, etc.
20
+
21
+ # Subject should be:
22
+ # - Use imperative, present tense: "change" not "changed" nor "changes"
23
+ # - Don't capitalize first letter
24
+ # - No dot (.) at the end
25
+ # - Maximum 72 characters
26
+
27
+ # Body should include:
28
+ # - Motivation for the change and contrast with previous behavior
29
+ # - What changed and why
30
+ # - Any breaking changes
31
+
32
+ # Footer should contain:
33
+ # - Breaking changes (start with BREAKING CHANGE:)
34
+ # - Issue references (Closes #123, Fixes #456)
35
+
36
+ # Examples:
37
+ # feat(stdio): add stdio executor for process execution
38
+ #
39
+ # Implement a new stdio executor that allows executing system commands
40
+ # and processes via stdin/stdout communication, similar to MCP stdio
41
+ # transport mode. This enables flexible task execution through shell
42
+ # commands and Python scripts.
43
+ #
44
+ # - Add StdioExecutor class with command execution support
45
+ # - Add system resource monitoring (CPU, memory, disk)
46
+ # - Support async process communication
47
+ # - Add comprehensive error handling and logging
48
+ #
49
+ # Closes #123
50
+
51
+ # refactor(core): extract shared types to core.types module
52
+ #
53
+ # Move common type definitions from various modules to a centralized
54
+ # core.types module to avoid circular dependencies and improve code
55
+ # organization.
56
+ #
57
+ # - Add TaskPreHook and TaskPostHook type aliases
58
+ # - Move TaskStatus enum to core.types
59
+ # - Update imports across affected modules
60
+
@@ -0,0 +1,27 @@
1
+ repos:
2
+
3
+ # apdev hooks
4
+ - repo: local
5
+ hooks:
6
+ - id: check-chars
7
+ name: apdev check-chars
8
+ entry: apdev check-chars
9
+ language: system
10
+ types_or: [text, python]
11
+
12
+ - id: check-imports
13
+ name: apdev check-imports
14
+ entry: apdev check-imports
15
+ language: system
16
+ pass_filenames: false
17
+ always_run: true
18
+
19
+ # Ruff linter and formatter
20
+ - repo: https://github.com/astral-sh/ruff-pre-commit
21
+ rev: v0.8.4
22
+ hooks:
23
+ - id: ruff
24
+ args: [--fix]
25
+ files: ^(src|tests)/
26
+ - id: ruff-format
27
+ files: ^(src|tests)/
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ All notable changes to apcore-cli (Python SDK) will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-03-15
9
+
10
+ ### Added
11
+ - `--sandbox` flag for subprocess-isolated module execution (FE-05)
12
+ - `ModuleExecutionError` exception class for sandbox failures
13
+ - Windows approval timeout support via `threading.Timer` + `ctypes` (FE-03)
14
+ - Approval timeout clamping to 1..3600 seconds range (FE-03)
15
+ - Tag format validation (`^[a-z][a-z0-9_-]*$`) in `list --tag` (FE-04)
16
+ - `cli.auto_approve` config key with `False` default (FE-07)
17
+ - Extensions directory readability check with exit code 47 (FE-01)
18
+ - Missing required property warning in schema parser (FE-02)
19
+ - DEBUG log `"Loading extensions from {path}"` before registry discovery (FE-01)
20
+ - `TYPE_CHECKING` imports for proper type annotations (`Registry`, `Executor`, `ModuleDescriptor`, `ConfigResolver`, `AuditLogger`)
21
+ - `_get_module_id()` helper for `canonical_id`/`module_id` resolution
22
+ - `APCORE_AUTH_API_KEY` and `APCORE_CLI_SANDBOX` to README environment variables table
23
+ - `--sandbox` to README module execution options table
24
+ - CHANGELOG.md
25
+ - Core Dispatcher (FE-01): `LazyModuleGroup`, `build_module_command`, `collect_input`, `validate_module_id`
26
+ - Schema Parser (FE-02): `schema_to_click_options`, `_map_type`, `_extract_help`, `reconvert_enum_values`
27
+ - Ref Resolver (FE-02): `resolve_refs`, `_resolve_node` with `$ref`, `allOf`, `anyOf`, `oneOf` support
28
+ - Config Resolver (FE-07): `ConfigResolver` with 4-tier precedence (CLI > Env > File > Default)
29
+ - Approval Gate (FE-03): `check_approval`, `_prompt_with_timeout` with TTY detection and Unix SIGALRM
30
+ - Discovery (FE-04): `list` and `describe` commands with tag filtering and TTY-adaptive output
31
+ - Output Formatter (FE-08): `format_module_list`, `format_module_detail`, `format_exec_result` with Rich rendering
32
+ - Security Manager (FE-05): `AuthProvider`, `ConfigEncryptor` (keyring + AES-256-GCM), `AuditLogger` (JSON Lines), `Sandbox` (subprocess isolation)
33
+ - Shell Integration (FE-06): bash/zsh/fish completion generators, roff man page generator
34
+ - 8 example modules: `math.add`, `math.multiply`, `text.upper`, `text.reverse`, `text.wordcount`, `sysutil.info`, `sysutil.env`, `sysutil.disk`
35
+ - 244 tests (unit, integration, end-to-end)
36
+ - CI workflow with pytest and coverage
37
+ - Pre-commit hooks configuration
@@ -0,0 +1,459 @@
1
+ Metadata-Version: 2.4
2
+ Name: apcore-cli
3
+ Version: 0.1.0
4
+ Summary: Terminal adapter for apcore — execute AI-Perceivable modules from the command line
5
+ Project-URL: Homepage, https://aipartnerup.com
6
+ Project-URL: Repository, https://github.com/aipartnerup/apcore-cli-python
7
+ Project-URL: Documentation, https://github.com/aipartnerup/apcore-cli-python#readme
8
+ Project-URL: Issues, https://github.com/aipartnerup/apcore-cli-python/issues
9
+ Author-email: aipartnerup <team@aipartnerup.com>
10
+ License-Expression: Apache-2.0
11
+ Keywords: agent,ai,apcore,automation,cli,command-line,llm,shell,terminal,unix
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: apcore>=0.13.0
24
+ Requires-Dist: click>=8.1
25
+ Requires-Dist: cryptography>=41.0
26
+ Requires-Dist: jsonschema>=4.20
27
+ Requires-Dist: keyring>=24.0
28
+ Requires-Dist: pyyaml>=6.0
29
+ Requires-Dist: rich>=13.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: apdev[dev]>=0.2.3; extra == 'dev'
32
+ Requires-Dist: mypy>=1.0; extra == 'dev'
33
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
34
+ Requires-Dist: pytest>=7.0; extra == 'dev'
35
+ Requires-Dist: ruff>=0.1; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ <div align="center">
39
+ <img src="https://raw.githubusercontent.com/aipartnerup/apcore-cli/main/apcore-cli-logo.svg" alt="apcore-cli logo" width="200"/>
40
+ </div>
41
+
42
+ # apcore-cli
43
+
44
+ Terminal adapter for apcore. Execute AI-Perceivable modules from the command line.
45
+
46
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
47
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://python.org)
48
+ [![Tests](https://img.shields.io/badge/tests-244%20passed-brightgreen.svg)]()
49
+
50
+ | | |
51
+ |---|---|
52
+ | **Python SDK** | [github.com/aipartnerup/apcore-cli-python](https://github.com/aipartnerup/apcore-cli-python) |
53
+ | **Spec repo** | [github.com/aipartnerup/apcore-cli](https://github.com/aipartnerup/apcore-cli) |
54
+ | **apcore core** | [github.com/aipartnerup/apcore](https://github.com/aipartnerup/apcore) |
55
+
56
+ **apcore-cli** turns any [apcore](https://github.com/aipartnerup/apcore)-based project into a fully featured CLI tool — with **zero code changes** to your existing modules.
57
+
58
+ ```
59
+ ┌──────────────────┐
60
+ │ django-apcore │ <- your existing apcore project (unchanged)
61
+ │ flask-apcore │
62
+ │ ... │
63
+ └────────┬─────────┘
64
+ │ extensions directory
65
+ v
66
+ ┌──────────────────┐
67
+ │ apcore-cli │ <- just install & point to extensions dir
68
+ └───┬──────────┬───┘
69
+ │ │
70
+ v v
71
+ Terminal Unix
72
+ Commands Pipes
73
+ ```
74
+
75
+ ## Design Philosophy
76
+
77
+ - **Zero intrusion** -- your apcore project needs no code changes, no imports, no dependencies on apcore-cli
78
+ - **Zero configuration** -- point to an extensions directory, everything is auto-discovered
79
+ - **Pure adapter** -- apcore-cli reads from the apcore Registry; it never modifies your modules
80
+ - **Unix-native** -- JSON output for pipes, rich tables for terminals, STDIN input, shell completions
81
+
82
+ ## Installation
83
+
84
+ ```bash
85
+ pip install apcore-cli
86
+ ```
87
+
88
+ Requires Python 3.11+ and `apcore >= 0.13.0`.
89
+
90
+ ## Quick Start
91
+
92
+ ### Try it now
93
+
94
+ The repo includes 8 example modules you can run immediately:
95
+
96
+ ```bash
97
+ git clone https://github.com/aipartnerup/apcore-cli-python.git
98
+ cd apcore-cli-python
99
+ pip install -e ".[dev]"
100
+
101
+ # Run a module
102
+ apcore-cli --extensions-dir examples/extensions math.add --a 5 --b 10
103
+ # {"sum": 15}
104
+
105
+ # List all modules
106
+ apcore-cli --extensions-dir examples/extensions list --format json
107
+
108
+ # Run all examples
109
+ bash examples/run_examples.sh
110
+ ```
111
+
112
+ See [Examples](#examples) for the full list of example modules and usage patterns.
113
+
114
+ ### Zero-code approach
115
+
116
+ If you already have an apcore-based project with an extensions directory:
117
+
118
+ ```bash
119
+ # Execute a module
120
+ apcore-cli --extensions-dir ./extensions math.add --a 42 --b 58
121
+
122
+ # Or set the env var once
123
+ export APCORE_EXTENSIONS_ROOT=./extensions
124
+ apcore-cli math.add --a 42 --b 58
125
+ ```
126
+
127
+ All modules are auto-discovered. CLI flags are auto-generated from each module's JSON Schema.
128
+
129
+ ### Programmatic approach (Python API)
130
+
131
+ ```python
132
+ from apcore import Registry, Executor
133
+ from apcore_cli.__main__ import create_cli
134
+
135
+ # Build the CLI from your registry
136
+ cli = create_cli(extensions_dir="./extensions")
137
+ cli(standalone_mode=True)
138
+ ```
139
+
140
+ Or use the `LazyModuleGroup` directly with Click:
141
+
142
+ ```python
143
+ import click
144
+ from apcore import Registry, Executor
145
+ from apcore_cli.cli import LazyModuleGroup
146
+
147
+ registry = Registry(extensions_dir="./extensions")
148
+ registry.discover()
149
+ executor = Executor(registry)
150
+
151
+ @click.group(cls=LazyModuleGroup, registry=registry, executor=executor)
152
+ def cli():
153
+ pass
154
+
155
+ cli()
156
+ ```
157
+
158
+ ## Integration with Existing Projects
159
+
160
+ ### Typical apcore project structure
161
+
162
+ ```
163
+ your-project/
164
+ ├── extensions/ <- modules live here
165
+ │ ├── math/
166
+ │ │ └── add.py
167
+ │ ├── text/
168
+ │ │ └── upper.py
169
+ │ └── ...
170
+ ├── your_app.py <- your existing code (untouched)
171
+ └── ...
172
+ ```
173
+
174
+ ### Adding CLI support
175
+
176
+ No changes to your project. Just install and run:
177
+
178
+ ```bash
179
+ pip install apcore-cli
180
+ apcore-cli --extensions-dir ./extensions list
181
+ apcore-cli --extensions-dir ./extensions math.add --a 5 --b 10
182
+ ```
183
+
184
+ ### STDIN piping (Unix pipes)
185
+
186
+ ```bash
187
+ # Pipe JSON input
188
+ echo '{"a": 100, "b": 200}' | apcore-cli math.add --input -
189
+ # {"sum": 300}
190
+
191
+ # CLI flags override STDIN values
192
+ echo '{"a": 1, "b": 2}' | apcore-cli math.add --input - --a 999
193
+ # {"sum": 1001}
194
+
195
+ # Chain with other tools
196
+ apcore-cli sysutil.info | jq '.os, .hostname'
197
+ ```
198
+
199
+ ## CLI Reference
200
+
201
+ ```
202
+ apcore-cli [OPTIONS] COMMAND [ARGS]
203
+ ```
204
+
205
+ ### Global Options
206
+
207
+ | Option | Default | Description |
208
+ |--------|---------|-------------|
209
+ | `--extensions-dir` | `./extensions` | Path to apcore extensions directory |
210
+ | `--log-level` | `INFO` | Logging: `DEBUG`, `INFO`, `WARN`, `ERROR` |
211
+ | `--version` | | Show version and exit |
212
+ | `--help` | | Show help and exit |
213
+
214
+ ### Built-in Commands
215
+
216
+ | Command | Description |
217
+ |---------|-------------|
218
+ | `list` | List available modules with optional tag filtering |
219
+ | `describe <module_id>` | Show full module metadata and schemas |
220
+ | `completion <shell>` | Generate shell completion script (bash/zsh/fish) |
221
+ | `man <command>` | Generate man page in roff format |
222
+
223
+ ### Module Execution Options
224
+
225
+ When executing a module (e.g. `apcore-cli math.add`), these built-in options are always available:
226
+
227
+ | Option | Description |
228
+ |--------|-------------|
229
+ | `--input -` | Read JSON input from STDIN |
230
+ | `--yes` / `-y` | Bypass approval prompts |
231
+ | `--large-input` | Allow STDIN input larger than 10MB |
232
+ | `--format` | Output format: `json` or `table` |
233
+ | `--sandbox` | Run module in subprocess sandbox |
234
+
235
+ Schema-generated flags (e.g. `--a`, `--b`) are added automatically from the module's `input_schema`.
236
+
237
+ ### Exit Codes
238
+
239
+ | Code | Meaning |
240
+ |------|---------|
241
+ | `0` | Success |
242
+ | `1` | Module execution error |
243
+ | `2` | Invalid CLI input |
244
+ | `44` | Module not found / disabled / load error |
245
+ | `45` | Schema validation error |
246
+ | `46` | Approval denied or timed out |
247
+ | `47` | Configuration error |
248
+ | `48` | Schema circular reference |
249
+ | `77` | ACL denied |
250
+ | `130` | Execution cancelled (Ctrl+C) |
251
+
252
+ ## Configuration
253
+
254
+ apcore-cli uses a 4-tier configuration precedence:
255
+
256
+ 1. **CLI flag** (highest): `--extensions-dir ./custom`
257
+ 2. **Environment variable**: `APCORE_EXTENSIONS_ROOT=./custom`
258
+ 3. **Config file**: `apcore.yaml`
259
+ 4. **Default** (lowest): `./extensions`
260
+
261
+ ### Environment Variables
262
+
263
+ | Variable | Description | Default |
264
+ |----------|-------------|---------|
265
+ | `APCORE_EXTENSIONS_ROOT` | Path to extensions directory | `./extensions` |
266
+ | `APCORE_CLI_AUTO_APPROVE` | Set to `1` to bypass all approval prompts | *(unset)* |
267
+ | `APCORE_LOGGING_LEVEL` | Log level | `INFO` |
268
+ | `APCORE_AUTH_API_KEY` | API key for remote registry authentication | *(unset)* |
269
+ | `APCORE_CLI_SANDBOX` | Set to `1` to enable subprocess sandboxing | *(unset)* |
270
+
271
+ ### Config File (`apcore.yaml`)
272
+
273
+ ```yaml
274
+ extensions:
275
+ root: ./extensions
276
+ logging:
277
+ level: DEBUG
278
+ sandbox:
279
+ enabled: false
280
+ ```
281
+
282
+ ## Features
283
+
284
+ - **Auto-discovery** -- all modules in the extensions directory are found and exposed as CLI commands
285
+ - **Auto-generated flags** -- JSON Schema `input_schema` is converted to `--flag value` CLI options with type validation
286
+ - **Boolean flag pairs** -- `--verbose` / `--no-verbose` from `"type": "boolean"` schema properties
287
+ - **Enum choices** -- `"enum": ["json", "csv"]` becomes `--format json` with Click validation
288
+ - **STDIN piping** -- `--input -` reads JSON from STDIN, CLI flags override for duplicate keys
289
+ - **TTY-adaptive output** -- rich tables for terminals, JSON for pipes (configurable via `--format`)
290
+ - **Approval gate** -- TTY-aware HITL prompts for modules with `requires_approval: true`, with `--yes` bypass and 60s timeout
291
+ - **Schema validation** -- inputs validated against JSON Schema before execution, with `$ref`/`allOf`/`anyOf`/`oneOf` resolution
292
+ - **Security** -- API key auth (keyring + AES-256-GCM), append-only audit logging, subprocess sandboxing
293
+ - **Shell completions** -- `apcore-cli completion bash|zsh|fish` generates completion scripts with dynamic module ID completion
294
+ - **Man pages** -- `apcore-cli man <command>` generates roff-formatted man pages
295
+ - **Audit logging** -- all executions logged to `~/.apcore-cli/audit.jsonl` with SHA-256 input hashing
296
+
297
+ ## How It Works
298
+
299
+ ### Mapping: apcore to CLI
300
+
301
+ | apcore | CLI |
302
+ |--------|-----|
303
+ | `module_id` (`math.add`) | Command name (`apcore-cli math.add`) |
304
+ | `description` | `--help` text |
305
+ | `input_schema.properties` | CLI flags (`--a`, `--b`) |
306
+ | `input_schema.required` | Required flag enforcement |
307
+ | `annotations.requires_approval` | HITL approval prompt |
308
+
309
+ ### Architecture
310
+
311
+ ```
312
+ User / AI Agent (terminal)
313
+ |
314
+ v
315
+ apcore-cli (the adapter)
316
+ |
317
+ +-- ConfigResolver 4-tier config precedence
318
+ +-- LazyModuleGroup Dynamic Click command generation
319
+ +-- SchemaParser JSON Schema -> Click options
320
+ +-- RefResolver $ref / allOf / anyOf / oneOf
321
+ +-- ApprovalGate TTY-aware HITL approval
322
+ +-- OutputFormatter TTY-adaptive JSON/table output
323
+ +-- AuditLogger JSON Lines execution logging
324
+ +-- Sandbox Subprocess isolation
325
+ |
326
+ v
327
+ apcore Registry + Executor (your modules, unchanged)
328
+ ```
329
+
330
+ ## Examples
331
+
332
+ The `examples/extensions/` directory contains 8 runnable modules:
333
+
334
+ | Module | Description | Usage |
335
+ |--------|-------------|-------|
336
+ | `math.add` | Add two integers | `apcore-cli math.add --a 5 --b 10` |
337
+ | `math.multiply` | Multiply two integers | `apcore-cli math.multiply --a 6 --b 7` |
338
+ | `text.upper` | Uppercase a string | `apcore-cli text.upper --text hello` |
339
+ | `text.reverse` | Reverse a string | `apcore-cli text.reverse --text abcdef` |
340
+ | `text.wordcount` | Count words/chars/lines | `apcore-cli text.wordcount --text "hello world"` |
341
+ | `sysutil.info` | OS, hostname, Python version | `apcore-cli sysutil.info` |
342
+ | `sysutil.env` | Read environment variables | `apcore-cli sysutil.env --name HOME` |
343
+ | `sysutil.disk` | Disk usage statistics | `apcore-cli sysutil.disk --path /` |
344
+
345
+ ### Running examples
346
+
347
+ ```bash
348
+ # Set extensions path (one time)
349
+ export APCORE_EXTENSIONS_ROOT=examples/extensions
350
+
351
+ # Execute modules
352
+ apcore-cli math.add --a 42 --b 58
353
+ apcore-cli text.upper --text "hello apcore"
354
+ apcore-cli sysutil.info
355
+ apcore-cli sysutil.disk --path /
356
+
357
+ # Discovery
358
+ apcore-cli list --format json
359
+ apcore-cli list --tag math --format json
360
+ apcore-cli describe math.add --format json
361
+
362
+ # STDIN piping
363
+ echo '{"a": 100, "b": 200}' | apcore-cli math.add --input -
364
+
365
+ # Shell completion
366
+ apcore-cli completion bash >> ~/.bashrc
367
+ apcore-cli completion zsh >> ~/.zshrc
368
+ apcore-cli completion fish > ~/.config/fish/completions/apcore-cli.fish
369
+
370
+ # Man pages
371
+ apcore-cli man list | man -l -
372
+
373
+ # Run all examples at once
374
+ bash examples/run_examples.sh
375
+ ```
376
+
377
+ ### Writing your own module
378
+
379
+ Create a Python file in your extensions directory:
380
+
381
+ ```python
382
+ # extensions/greet/hello.py
383
+ from pydantic import BaseModel
384
+
385
+ class Input(BaseModel):
386
+ name: str
387
+ greeting: str = "Hello"
388
+
389
+ class Output(BaseModel):
390
+ message: str
391
+
392
+ class GreetHello:
393
+ input_schema = Input
394
+ output_schema = Output
395
+ description = "Greet someone by name"
396
+
397
+ def execute(self, inputs, context=None):
398
+ return {"message": f"{inputs['greeting']}, {inputs['name']}!"}
399
+ ```
400
+
401
+ Then run it:
402
+
403
+ ```bash
404
+ apcore-cli --extensions-dir ./extensions greet.hello --name World
405
+ # {"message": "Hello, World!"}
406
+
407
+ apcore-cli --extensions-dir ./extensions greet.hello --name Alice --greeting Hi
408
+ # {"message": "Hi, Alice!"}
409
+ ```
410
+
411
+ ## Development
412
+
413
+ ```bash
414
+ git clone https://github.com/aipartnerup/apcore-cli-python.git
415
+ cd apcore-cli-python
416
+ pip install -e ".[dev]"
417
+ pytest # 244 tests
418
+ pytest --cov # with coverage report
419
+ bash examples/run_examples.sh # run all examples
420
+ ```
421
+
422
+ ### Project Structure
423
+
424
+ ```
425
+ src/apcore_cli/
426
+ ├── __init__.py # Package version
427
+ ├── __main__.py # CLI entry point, wiring
428
+ ├── cli.py # LazyModuleGroup, build_module_command, collect_input
429
+ ├── config.py # ConfigResolver (4-tier precedence)
430
+ ├── schema_parser.py # JSON Schema -> Click options
431
+ ├── ref_resolver.py # $ref / allOf / anyOf / oneOf resolution
432
+ ├── output.py # TTY-adaptive output formatting (rich)
433
+ ├── discovery.py # list / describe commands
434
+ ├── approval.py # HITL approval gate with timeout
435
+ ├── shell.py # bash/zsh/fish completion + man pages
436
+ ├── _sandbox_runner.py # Subprocess entry point for sandboxed execution
437
+ └── security/
438
+ ├── __init__.py # Exports
439
+ ├── auth.py # API key authentication
440
+ ├── config_encryptor.py # Keyring + AES-256-GCM encrypted config
441
+ ├── audit.py # JSON Lines audit logging
442
+ └── sandbox.py # Subprocess-based execution isolation
443
+
444
+ examples/
445
+ ├── run_examples.sh # Run all examples end-to-end
446
+ └── extensions/
447
+ ├── math/ # math.add, math.multiply
448
+ ├── text/ # text.upper, text.reverse, text.wordcount
449
+ └── sysutil/ # sysutil.info, sysutil.env, sysutil.disk
450
+
451
+ planning/ # Implementation plans (TDD task breakdowns)
452
+ ├── overview.md
453
+ ├── state.json
454
+ └── *.md # Per-feature plans
455
+ ```
456
+
457
+ ## License
458
+
459
+ Apache-2.0