humancli 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.
- humancli-0.1.0/.agents/AGENTS.md +4 -0
- humancli-0.1.0/.agents/skills/release/SKILL.md +48 -0
- humancli-0.1.0/.github/workflows/ci.yml +53 -0
- humancli-0.1.0/.github/workflows/release.yml +112 -0
- humancli-0.1.0/.gitignore +16 -0
- humancli-0.1.0/.python-version +1 -0
- humancli-0.1.0/LICENSE +21 -0
- humancli-0.1.0/PKG-INFO +178 -0
- humancli-0.1.0/README.md +141 -0
- humancli-0.1.0/pyproject.toml +50 -0
- humancli-0.1.0/src/agentcli/__init__.py +20 -0
- humancli-0.1.0/src/agentcli/_agents.py +93 -0
- humancli-0.1.0/src/agentcli/_app.py +432 -0
- humancli-0.1.0/src/agentcli/_context.py +39 -0
- humancli-0.1.0/src/agentcli/_errors.py +140 -0
- humancli-0.1.0/src/agentcli/_help.py +65 -0
- humancli-0.1.0/src/agentcli/_output.py +282 -0
- humancli-0.1.0/src/agentcli/_parser.py +417 -0
- humancli-0.1.0/src/agentcli/_schema.py +142 -0
- humancli-0.1.0/src/agentcli/_types.py +142 -0
- humancli-0.1.0/src/agentcli/_wizard.py +83 -0
- humancli-0.1.0/src/agentcli/prompt.py +71 -0
- humancli-0.1.0/src/agentcli/py.typed +0 -0
- humancli-0.1.0/src/agentcli/testing.py +55 -0
- humancli-0.1.0/tests/test_agentcli.py +180 -0
- humancli-0.1.0/uv.lock +847 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
after you finish work, commit with a conventional message. only commit the files you edited.
|
|
2
|
+
always run tests before code commits.
|
|
3
|
+
when using gh to edit or create PR descriptions, prefer `--body-file` to preserve newlines.
|
|
4
|
+
always include a "Manual testing" checklist section in PRs.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release
|
|
3
|
+
description: Prepare and ship an agentcli release. Use when asked to cut a release, bump release versions, tag v<major.minor.patch>, or trigger the GitHub release workflow.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Release
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Prepare a tagged release that matches the GitHub Actions release workflow. The workflow requires the tag version to match both `pyproject.toml` and `src/agentcli/__init__.py`.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
|
|
14
|
+
### 1) Choose version + date
|
|
15
|
+
|
|
16
|
+
Pick the release version (major.minor.patch) and the release date (YYYY-MM-DD).
|
|
17
|
+
If the current version has a `.dev` suffix, assume the target release version is the same version without the suffix, as long as that tag does not already exist.
|
|
18
|
+
|
|
19
|
+
### 2) Bump versions
|
|
20
|
+
|
|
21
|
+
Update version strings to match the release tag:
|
|
22
|
+
|
|
23
|
+
- `pyproject.toml`: `project.version = "<major.minor.patch>"`
|
|
24
|
+
- `src/agentcli/__init__.py`: `__version__ = "<major.minor.patch>"`
|
|
25
|
+
- `uv.lock`: refresh so the root package version matches (run `uv lock` or `uv sync`).
|
|
26
|
+
|
|
27
|
+
### 3) Run checks
|
|
28
|
+
|
|
29
|
+
Run tests before committing:
|
|
30
|
+
|
|
31
|
+
- `uv run python -m unittest tests/test_agentcli.py`
|
|
32
|
+
|
|
33
|
+
### 4) Commit + tag
|
|
34
|
+
|
|
35
|
+
Commit the release using conventional commits:
|
|
36
|
+
|
|
37
|
+
- Commit message: `chore(release): v<major.minor.patch>`
|
|
38
|
+
- Tag: `git tag v<major.minor.patch>`
|
|
39
|
+
|
|
40
|
+
Push the tag to trigger `.github/workflows/release.yml` (build, PyPI publish, GitHub release).
|
|
41
|
+
|
|
42
|
+
### 5) Optional post-release bump
|
|
43
|
+
|
|
44
|
+
If you keep a dev version between releases, bump the minor version (reset patch to 0) and commit (`chore: bump version to ...`).
|
|
45
|
+
|
|
46
|
+
## Notes
|
|
47
|
+
|
|
48
|
+
- The release workflow checks that the tag matches `pyproject.toml` and `src/agentcli/__init__.py`.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- "master"
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
checks:
|
|
15
|
+
name: ${{ matrix.task }}
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
include:
|
|
21
|
+
- task: format
|
|
22
|
+
do_sync: true
|
|
23
|
+
command: uv run --no-sync ruff format --check --diff src tests
|
|
24
|
+
sync_args: --no-install-project --group dev
|
|
25
|
+
- task: ruff
|
|
26
|
+
do_sync: true
|
|
27
|
+
command: uv run --no-sync ruff check src tests --output-format=github
|
|
28
|
+
sync_args: --no-install-project --group dev
|
|
29
|
+
- task: pytest
|
|
30
|
+
do_sync: true
|
|
31
|
+
command: uv run --no-sync python -m unittest discover tests -v
|
|
32
|
+
sync_args: ""
|
|
33
|
+
- task: build
|
|
34
|
+
do_sync: false
|
|
35
|
+
command: uv build
|
|
36
|
+
sync_args: ""
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- name: Checkout
|
|
40
|
+
uses: actions/checkout@v5
|
|
41
|
+
|
|
42
|
+
- name: Install uv
|
|
43
|
+
uses: astral-sh/setup-uv@v7
|
|
44
|
+
with:
|
|
45
|
+
python-version: "3.14"
|
|
46
|
+
enable-cache: true
|
|
47
|
+
|
|
48
|
+
- name: Install dependencies
|
|
49
|
+
if: matrix.do_sync
|
|
50
|
+
run: uv sync --frozen ${{ matrix.sync_args }}
|
|
51
|
+
|
|
52
|
+
- name: Run check
|
|
53
|
+
run: ${{ matrix.command }}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Build distributions
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v5
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
uses: astral-sh/setup-uv@v7
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.14"
|
|
22
|
+
enable-cache: true
|
|
23
|
+
|
|
24
|
+
- name: Check tag matches project version
|
|
25
|
+
run: |
|
|
26
|
+
uv run --no-project python - <<'PY'
|
|
27
|
+
import os
|
|
28
|
+
import re
|
|
29
|
+
import tomllib
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
tag = os.environ.get('GITHUB_REF_NAME', '')
|
|
33
|
+
tag_version = tag[1:] if tag.startswith('v') else tag
|
|
34
|
+
|
|
35
|
+
pyproject = tomllib.loads(Path('pyproject.toml').read_text(encoding='utf-8'))
|
|
36
|
+
project_version = pyproject['project']['version']
|
|
37
|
+
|
|
38
|
+
init_version = None
|
|
39
|
+
init_path = Path('src') / 'agentcli' / '__init__.py'
|
|
40
|
+
if init_path.is_file():
|
|
41
|
+
m = re.search(r'__version__\s*=\s*"([^"]+)"', init_path.read_text(encoding='utf-8'))
|
|
42
|
+
if m:
|
|
43
|
+
init_version = m.group(1)
|
|
44
|
+
|
|
45
|
+
if project_version != tag_version:
|
|
46
|
+
raise SystemExit(f"Tag {tag!r} does not match pyproject version {project_version!r}")
|
|
47
|
+
if init_version and init_version != project_version:
|
|
48
|
+
raise SystemExit(
|
|
49
|
+
f"src/agentcli/__init__.py __version__ {init_version!r} does not match pyproject version {project_version!r}"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
print(f"OK: tag {tag!r} matches version {project_version!r}")
|
|
53
|
+
PY
|
|
54
|
+
|
|
55
|
+
- name: Run tests
|
|
56
|
+
run: uv run python -m unittest discover tests -v
|
|
57
|
+
|
|
58
|
+
- name: Build (wheel + sdist)
|
|
59
|
+
run: uv build
|
|
60
|
+
|
|
61
|
+
- name: Upload dist artifacts
|
|
62
|
+
uses: actions/upload-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
name: dist
|
|
65
|
+
path: dist/
|
|
66
|
+
if-no-files-found: error
|
|
67
|
+
|
|
68
|
+
publish:
|
|
69
|
+
name: Publish to PyPI (trusted publishing)
|
|
70
|
+
needs: build
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
environment:
|
|
73
|
+
name: pypi
|
|
74
|
+
url: https://pypi.org/project/humancli/
|
|
75
|
+
permissions:
|
|
76
|
+
contents: read
|
|
77
|
+
id-token: write
|
|
78
|
+
steps:
|
|
79
|
+
- name: Download dist artifacts
|
|
80
|
+
uses: actions/download-artifact@v4
|
|
81
|
+
with:
|
|
82
|
+
name: dist
|
|
83
|
+
path: dist/
|
|
84
|
+
|
|
85
|
+
- name: Publish package distributions to PyPI
|
|
86
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
87
|
+
with:
|
|
88
|
+
packages-dir: dist/
|
|
89
|
+
skip-existing: true
|
|
90
|
+
|
|
91
|
+
github-release:
|
|
92
|
+
name: Create GitHub Release
|
|
93
|
+
needs: publish
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
permissions:
|
|
96
|
+
contents: write
|
|
97
|
+
steps:
|
|
98
|
+
- name: Checkout
|
|
99
|
+
uses: actions/checkout@v5
|
|
100
|
+
|
|
101
|
+
- name: Download dist artifacts
|
|
102
|
+
uses: actions/download-artifact@v4
|
|
103
|
+
with:
|
|
104
|
+
name: dist
|
|
105
|
+
path: dist/
|
|
106
|
+
|
|
107
|
+
- name: Create GitHub release and upload artifacts
|
|
108
|
+
uses: softprops/action-gh-release@v2
|
|
109
|
+
with:
|
|
110
|
+
generate_release_notes: true
|
|
111
|
+
files: |
|
|
112
|
+
dist/*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
humancli-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yaser Martinez Palenzuela
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
humancli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: humancli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python CLIs for agents and humans
|
|
5
|
+
Project-URL: Repository, https://github.com/elyase/agentcli
|
|
6
|
+
Project-URL: Issues, https://github.com/elyase/agentcli/issues
|
|
7
|
+
Author-email: Yaser Martinez Palenzuela <yaser.martinez@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent,ai,cli,command-line,llm
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: docstring-parser>=0.16
|
|
23
|
+
Provides-Extra: all
|
|
24
|
+
Requires-Dist: mcp>=1.0; extra == 'all'
|
|
25
|
+
Requires-Dist: pydantic>=2.0; extra == 'all'
|
|
26
|
+
Requires-Dist: pyyaml>=6.0; extra == 'all'
|
|
27
|
+
Requires-Dist: rich>=13.0; extra == 'all'
|
|
28
|
+
Provides-Extra: mcp
|
|
29
|
+
Requires-Dist: mcp>=1.0; extra == 'mcp'
|
|
30
|
+
Provides-Extra: pydantic
|
|
31
|
+
Requires-Dist: pydantic>=2.0; extra == 'pydantic'
|
|
32
|
+
Provides-Extra: rich
|
|
33
|
+
Requires-Dist: rich>=13.0; extra == 'rich'
|
|
34
|
+
Provides-Extra: yaml
|
|
35
|
+
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# agentcli
|
|
39
|
+
|
|
40
|
+
Python CLIs for agents and humans.
|
|
41
|
+
|
|
42
|
+
agentcli builds command-line interfaces that produce structured, parseable output for AI agents while remaining human-friendly. Type hints are the schema — a function signature IS the CLI specification.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
pip install humancli
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The package installs as `humancli` on PyPI but you import it as `agentcli`:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from agentcli import App
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
### Single function
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from agentcli import run
|
|
62
|
+
|
|
63
|
+
def greet(name: str):
|
|
64
|
+
"""Greet someone."""
|
|
65
|
+
return {"message": f"hello {name}"}
|
|
66
|
+
|
|
67
|
+
run(greet)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
$ greet world
|
|
72
|
+
message: hello world
|
|
73
|
+
|
|
74
|
+
$ greet world --json
|
|
75
|
+
{"ok": true, "data": {"message": "hello world"}}
|
|
76
|
+
|
|
77
|
+
$ greet --llms
|
|
78
|
+
# greet
|
|
79
|
+
| Command | Description |
|
|
80
|
+
|---------|-------------|
|
|
81
|
+
| `greet <name>` | Greet someone |
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Multi-command app
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from agentcli import App
|
|
88
|
+
|
|
89
|
+
app = App("my-cli", version="1.0.0")
|
|
90
|
+
|
|
91
|
+
@app.command
|
|
92
|
+
def status():
|
|
93
|
+
"""Show status."""
|
|
94
|
+
return {"clean": True, "branch": "main"}
|
|
95
|
+
|
|
96
|
+
@app.command
|
|
97
|
+
def install(package: str, *, save_dev: bool = False):
|
|
98
|
+
"""Install a package."""
|
|
99
|
+
return {"added": 1, "packages": 451}
|
|
100
|
+
|
|
101
|
+
app()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Parameters before `*` are positional arguments. Parameters after `*` are named options/flags. This is just Python's own syntax.
|
|
105
|
+
|
|
106
|
+
### Parameter metadata
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from typing import Annotated, Literal
|
|
110
|
+
from agentcli import App, Param
|
|
111
|
+
|
|
112
|
+
app = App("deploy-cli")
|
|
113
|
+
|
|
114
|
+
@app.command
|
|
115
|
+
def deploy(
|
|
116
|
+
env: Annotated[Literal["staging", "prod"], Param(help="Target environment")],
|
|
117
|
+
*,
|
|
118
|
+
token: Annotated[str, Param(env="DEPLOY_TOKEN", secret=True)] = "",
|
|
119
|
+
):
|
|
120
|
+
"""Deploy to an environment."""
|
|
121
|
+
return {"url": f"https://{env}.example.com"}
|
|
122
|
+
|
|
123
|
+
app()
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Sub-apps
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
app = App("gh")
|
|
130
|
+
pr = App("pr")
|
|
131
|
+
|
|
132
|
+
@pr.command
|
|
133
|
+
def list_(*, state: Literal["open", "closed"] = "open"):
|
|
134
|
+
"""List pull requests."""
|
|
135
|
+
return {"prs": [], "state": state}
|
|
136
|
+
|
|
137
|
+
app.mount(pr)
|
|
138
|
+
app()
|
|
139
|
+
|
|
140
|
+
# $ gh pr list --state closed
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Default commands
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
app = App("fetch")
|
|
147
|
+
|
|
148
|
+
@app.default
|
|
149
|
+
def fetch_cases(*, limit: int = 20):
|
|
150
|
+
"""Fetch cases."""
|
|
151
|
+
return {"fetched": limit}
|
|
152
|
+
|
|
153
|
+
# Runs when no sub-command is given:
|
|
154
|
+
# $ fetch --limit 5
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Agent discovery
|
|
158
|
+
|
|
159
|
+
Every agentcli app gets built-in flags for agent consumption:
|
|
160
|
+
|
|
161
|
+
- `--llms` — markdown command index
|
|
162
|
+
- `--llms-full` — full JSON schema of all commands
|
|
163
|
+
- `--json` / `--yaml` / `--jsonl` — structured output formats
|
|
164
|
+
- `--mcp` — start as an MCP server (requires `agentcli[mcp]`)
|
|
165
|
+
|
|
166
|
+
## Optional extras
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
pip install humancli[rich] # rich terminal formatting
|
|
170
|
+
pip install humancli[pydantic] # pydantic model support
|
|
171
|
+
pip install humancli[yaml] # yaml output format
|
|
172
|
+
pip install humancli[mcp] # MCP server mode
|
|
173
|
+
pip install humancli[all] # everything
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT
|
humancli-0.1.0/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# agentcli
|
|
2
|
+
|
|
3
|
+
Python CLIs for agents and humans.
|
|
4
|
+
|
|
5
|
+
agentcli builds command-line interfaces that produce structured, parseable output for AI agents while remaining human-friendly. Type hints are the schema — a function signature IS the CLI specification.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pip install humancli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The package installs as `humancli` on PyPI but you import it as `agentcli`:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from agentcli import App
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
### Single function
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from agentcli import run
|
|
25
|
+
|
|
26
|
+
def greet(name: str):
|
|
27
|
+
"""Greet someone."""
|
|
28
|
+
return {"message": f"hello {name}"}
|
|
29
|
+
|
|
30
|
+
run(greet)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
$ greet world
|
|
35
|
+
message: hello world
|
|
36
|
+
|
|
37
|
+
$ greet world --json
|
|
38
|
+
{"ok": true, "data": {"message": "hello world"}}
|
|
39
|
+
|
|
40
|
+
$ greet --llms
|
|
41
|
+
# greet
|
|
42
|
+
| Command | Description |
|
|
43
|
+
|---------|-------------|
|
|
44
|
+
| `greet <name>` | Greet someone |
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Multi-command app
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from agentcli import App
|
|
51
|
+
|
|
52
|
+
app = App("my-cli", version="1.0.0")
|
|
53
|
+
|
|
54
|
+
@app.command
|
|
55
|
+
def status():
|
|
56
|
+
"""Show status."""
|
|
57
|
+
return {"clean": True, "branch": "main"}
|
|
58
|
+
|
|
59
|
+
@app.command
|
|
60
|
+
def install(package: str, *, save_dev: bool = False):
|
|
61
|
+
"""Install a package."""
|
|
62
|
+
return {"added": 1, "packages": 451}
|
|
63
|
+
|
|
64
|
+
app()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Parameters before `*` are positional arguments. Parameters after `*` are named options/flags. This is just Python's own syntax.
|
|
68
|
+
|
|
69
|
+
### Parameter metadata
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from typing import Annotated, Literal
|
|
73
|
+
from agentcli import App, Param
|
|
74
|
+
|
|
75
|
+
app = App("deploy-cli")
|
|
76
|
+
|
|
77
|
+
@app.command
|
|
78
|
+
def deploy(
|
|
79
|
+
env: Annotated[Literal["staging", "prod"], Param(help="Target environment")],
|
|
80
|
+
*,
|
|
81
|
+
token: Annotated[str, Param(env="DEPLOY_TOKEN", secret=True)] = "",
|
|
82
|
+
):
|
|
83
|
+
"""Deploy to an environment."""
|
|
84
|
+
return {"url": f"https://{env}.example.com"}
|
|
85
|
+
|
|
86
|
+
app()
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Sub-apps
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
app = App("gh")
|
|
93
|
+
pr = App("pr")
|
|
94
|
+
|
|
95
|
+
@pr.command
|
|
96
|
+
def list_(*, state: Literal["open", "closed"] = "open"):
|
|
97
|
+
"""List pull requests."""
|
|
98
|
+
return {"prs": [], "state": state}
|
|
99
|
+
|
|
100
|
+
app.mount(pr)
|
|
101
|
+
app()
|
|
102
|
+
|
|
103
|
+
# $ gh pr list --state closed
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Default commands
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
app = App("fetch")
|
|
110
|
+
|
|
111
|
+
@app.default
|
|
112
|
+
def fetch_cases(*, limit: int = 20):
|
|
113
|
+
"""Fetch cases."""
|
|
114
|
+
return {"fetched": limit}
|
|
115
|
+
|
|
116
|
+
# Runs when no sub-command is given:
|
|
117
|
+
# $ fetch --limit 5
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Agent discovery
|
|
121
|
+
|
|
122
|
+
Every agentcli app gets built-in flags for agent consumption:
|
|
123
|
+
|
|
124
|
+
- `--llms` — markdown command index
|
|
125
|
+
- `--llms-full` — full JSON schema of all commands
|
|
126
|
+
- `--json` / `--yaml` / `--jsonl` — structured output formats
|
|
127
|
+
- `--mcp` — start as an MCP server (requires `agentcli[mcp]`)
|
|
128
|
+
|
|
129
|
+
## Optional extras
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
pip install humancli[rich] # rich terminal formatting
|
|
133
|
+
pip install humancli[pydantic] # pydantic model support
|
|
134
|
+
pip install humancli[yaml] # yaml output format
|
|
135
|
+
pip install humancli[mcp] # MCP server mode
|
|
136
|
+
pip install humancli[all] # everything
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "humancli"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Python CLIs for agents and humans"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Yaser Martinez Palenzuela", email = "yaser.martinez@gmail.com" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
keywords = ["cli", "agent", "llm", "ai", "command-line"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Programming Language :: Python :: 3.14",
|
|
21
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"docstring-parser>=0.16",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
rich = ["rich>=13.0"]
|
|
30
|
+
pydantic = ["pydantic>=2.0"]
|
|
31
|
+
yaml = ["pyyaml>=6.0"]
|
|
32
|
+
mcp = ["mcp>=1.0"]
|
|
33
|
+
all = ["humancli[rich,pydantic,yaml,mcp]"]
|
|
34
|
+
|
|
35
|
+
[dependency-groups]
|
|
36
|
+
dev = ["ruff>=0.11"]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Repository = "https://github.com/elyase/agentcli"
|
|
40
|
+
Issues = "https://github.com/elyase/agentcli/issues"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["hatchling"]
|
|
44
|
+
build-backend = "hatchling.build"
|
|
45
|
+
|
|
46
|
+
[tool.hatch.build.targets.wheel]
|
|
47
|
+
packages = ["src/agentcli"]
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""agentcli: Python CLIs for agents and humans."""
|
|
2
|
+
|
|
3
|
+
from ._app import App, run
|
|
4
|
+
from ._context import Context
|
|
5
|
+
from ._errors import AgentCliError, ConfigError, ParseError, ValidationError
|
|
6
|
+
from ._types import Param, Result
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"AgentCliError",
|
|
12
|
+
"App",
|
|
13
|
+
"ConfigError",
|
|
14
|
+
"Context",
|
|
15
|
+
"Param",
|
|
16
|
+
"ParseError",
|
|
17
|
+
"Result",
|
|
18
|
+
"ValidationError",
|
|
19
|
+
"run",
|
|
20
|
+
]
|