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.
@@ -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,16 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Reference materials (embedded repos)
13
+ reference/
14
+
15
+ # Internal design notes
16
+ PLAN.md
@@ -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.
@@ -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
@@ -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
+ ]