ape-linux 0.3.4__tar.gz → 0.4.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.
@@ -20,10 +20,12 @@ jobs:
20
20
  run: curl -LsSf https://astral.sh/uv/install.sh | sh
21
21
  - name: Set up Python ${{ matrix.python-version }}
22
22
  run: uv python install ${{ matrix.python-version }}
23
+ - name: Set up just
24
+ uses: extractions/setup-just@v3
23
25
  - name: Run type check
24
- run: uv run pyright .
26
+ run: just type-check
25
27
  - name: Run tests
26
- run: uv run pytest
28
+ run: just test
27
29
 
28
30
  lint:
29
31
  name: Lint
@@ -35,5 +37,7 @@ jobs:
35
37
  run: curl -LsSf https://astral.sh/uv/install.sh | sh
36
38
  - name: Set up Python 3.13
37
39
  run: uv python install 3.13
40
+ - name: Set up just
41
+ uses: extractions/setup-just@v3
38
42
  - name: Ruff
39
- run: uv run ruff check .
43
+ run: just lint
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,103 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ > **Keep this file current.** Whenever you make a change that affects anything
6
+ > described here — behavior, commands, architecture, conventions, defaults, file
7
+ > layout — update the relevant section of CLAUDE.md (and `README.md` where it
8
+ > overlaps) in the same change, so the docs never drift from the code.
9
+
10
+ ## Overview
11
+
12
+ Ape (`ape-linux` on PyPI) is a CLI that turns a natural-language description of a
13
+ Linux task into a shell command using an LLM. The entire implementation lives in a
14
+ single module, `ape_linux.py`, exposing a Typer app as the `ape` console script.
15
+
16
+ **Single-file rule:** all of Ape's implementation must stay in `ape_linux.py` — do
17
+ not split it into additional modules/packages. New behavior is added as functions in
18
+ this one file.
19
+
20
+ ## Commands
21
+
22
+ This project uses [`uv`](https://docs.astral.sh/uv/) for everything, with
23
+ [`just`](https://github.com/casey/just) wrapping the CI-relevant tasks.
24
+
25
+ ```bash
26
+ just lint # lint (uv run ruff check .)
27
+ just type-check # type check with ty (uv run ty check)
28
+ just test # run all tests (uv run pytest)
29
+ ```
30
+
31
+ The `justfile` recipes are the single source of truth for lint, type-check, and test:
32
+ both local dev and CI (`.github/workflows/tests.yaml`) invoke them, so the two can't
33
+ drift. CI installs `just` via the `extractions/setup-just` action. Other useful
34
+ commands:
35
+
36
+ ```bash
37
+ uv sync # install deps + dev group into .venv
38
+ uv run pytest tests/test_app.py::test_app_for_version # run a single test
39
+ uv run ruff format . # format
40
+ uv run ape "list all files" # run the CLI locally
41
+ uv build # build the wheel/sdist
42
+ ```
43
+
44
+ ## Architecture
45
+
46
+ The flow in `ape_linux.py` is intentionally minimal:
47
+
48
+ 1. `main()` is the single Typer command. It takes the `query` argument plus
49
+ `--model/-m`, `--execute/-e`, `--system-info/-s`, and `--version/-v` options.
50
+ `--system-info` is an eager flag (like `--version`) whose callback prints
51
+ `detect_system_context()` and exits before the LLM is called, so it works without a
52
+ `query`.
53
+ 2. A hard-coded `system_prompt` (with few-shot examples) constrains the model to emit
54
+ **only** a runnable command — no Markdown fences — or `echo "Please try again."`
55
+ for anything off-topic. This prompt is the core product behavior; changes to it
56
+ directly change what the tool outputs. `main()` then appends a system-context block
57
+ (see below) so suggestions match the current machine.
58
+ 2a. `detect_system_context()` returns a best-effort, newline-separated `Key: value`
59
+ block describing the current machine (OS family + macOS/distro version, GNU-vs-BSD
60
+ userland, CPU arch, `$SHELL`, root-or-not, available package managers, and a probed
61
+ list of common tools). Two invariants: it **never raises** (every probe is guarded,
62
+ so an unavailable API or missing file just omits that field instead of crashing at
63
+ startup), and it **never includes identifying info** (no username, hostname, working
64
+ directory, or home path). Everything is stdlib (`platform`, `os`, `shutil.which`) and
65
+ stat-based — no subprocesses — to keep startup fast. Notable guards:
66
+ `platform.freedesktop_os_release()` raises `OSError` on macOS/minimal containers, and
67
+ `os.geteuid()` is absent on non-Unix platforms (`hasattr` check).
68
+ 3. `call_llm()` wraps `pydantic_ai.Agent`, which is the provider abstraction. Models
69
+ are passed through verbatim in `provider:name` form (e.g. `anthropic:claude-sonnet-4-5`),
70
+ so Ape supports any provider Pydantic AI supports without provider-specific code.
71
+ `--model` defaults to `None`; `main()` resolves the model as `--model` (if given)
72
+ → `APE_MODEL` env var → the `DEFAULT_MODEL` constant (`openai-chat:gpt-4.1`).
73
+ Credentials come from each provider's standard env var (e.g. `OPENAI_API_KEY`,
74
+ `ANTHROPIC_API_KEY`).
75
+ 4. Errors are flattened to one-line stderr messages with exit code 1 —
76
+ `ModelHTTPError` reports status/message; any other exception (bad credentials,
77
+ unknown provider) prints `str(error)`. Tracebacks are suppressed via
78
+ `pretty_exceptions_enable=False` on the Typer app.
79
+ 5. With `--execute`, the suggested command is run via `subprocess.check_call(..., shell=True)`.
80
+
81
+ ## Testing
82
+
83
+ `tests/test_app.py` uses `typer.testing.CliRunner` and monkeypatches
84
+ `ape_linux.call_llm` so no real network/LLM calls happen. The `mockenv` fixture sets a
85
+ dummy `OPENAI_API_KEY`. Note `test_app_for_suggestion_with_execute` mocks the LLM to
86
+ return `ls` and actually executes it (harmless, but be aware when adding execute-path
87
+ tests — avoid destructive mocked commands).
88
+
89
+ `detect_system_context()` is covered by tests that assert it returns a string without
90
+ crashing, reports the OS, and — importantly — excludes the current username, hostname,
91
+ working directory, and home path. These run against the real host (no mocking), so keep
92
+ them platform-agnostic; the username check skips the `root` collision with the privilege
93
+ line.
94
+
95
+ ## Conventions
96
+
97
+ - Ruff targets `py314`; lint rules are `F, E, W, I001` (pyflakes, pycodestyle, import
98
+ sorting). `ape_linux` is the known first-party package for import ordering.
99
+ - The published package requires Python >=3.10; CI matrixes 3.10–3.13, while local dev
100
+ uses 3.14 (`.python-version`).
101
+ - Version is read at runtime from package metadata (`importlib.metadata.version`), so
102
+ the single source of truth is `pyproject.toml`'s `version`. Publishing is tag-driven
103
+ (`.github/workflows/publish.yaml`).
@@ -1,4 +1,4 @@
1
- Copyright 2024 Seto Balian
1
+ Copyright 2026 Seto Balian
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
@@ -0,0 +1,175 @@
1
+ Metadata-Version: 2.4
2
+ Name: ape-linux
3
+ Version: 0.4.0
4
+ Summary: AI for Linux commands
5
+ Project-URL: Homepage, https://github.com/sbalian/ape
6
+ Project-URL: Repository, https://github.com/sbalian/ape
7
+ Author-email: Seto Balian <seto.balian@gmail.com>
8
+ Maintainer-email: Seto Balian <seto.balian@gmail.com>
9
+ License: MIT License
10
+ License-File: LICENSE
11
+ Keywords: ai,anthropic,linux,llm,openai,pydantic-ai
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Topic :: Software Development
16
+ Requires-Python: >=3.10
17
+ Requires-Dist: pydantic-ai-slim[anthropic,google,groq,mistral,openai]>=1.104.0
18
+ Requires-Dist: rich>=14.0.0
19
+ Requires-Dist: typer>=0.15.2
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Ape
23
+
24
+ Ape is an AI for Linux commands.
25
+
26
+ ```sh
27
+ ape "Find all the important PDF files in user/projects. An important PDF file has 'attention' in its name. Write the results to important_files.txt and then move it to Documents."
28
+ ```
29
+
30
+ Output:
31
+
32
+ ```text
33
+ find ~/user/projects -type f -name "*attention*.pdf" > important_files.txt && mv important_files.txt ~/Documents/
34
+ ```
35
+
36
+ Ape works with any provider supported by [Pydantic AI](https://ai.pydantic.dev/models/)
37
+ — OpenAI, Anthropic, Google, Groq, Mistral and more.
38
+
39
+ To install ([`uv`](https://docs.astral.sh/uv/getting-started/installation/) recommended):
40
+
41
+ ```bash
42
+ uv tool install ape-linux
43
+ ```
44
+
45
+ Next, set the API key for your provider using its standard environment variable.
46
+ For example:
47
+
48
+ ```bash
49
+ export OPENAI_API_KEY=key # for OpenAI models
50
+ export ANTHROPIC_API_KEY=key # for Anthropic models
51
+ ```
52
+
53
+ To run:
54
+
55
+ ```bash
56
+ ape "Create a symbolic link called win pointing to /mnt/c/Users/jdoe"
57
+ ```
58
+
59
+ Output:
60
+
61
+ ```text
62
+ ln -s /mnt/c/Users/jdoe win
63
+ ```
64
+
65
+ Another example:
66
+
67
+ ```bash
68
+ ape "Delete all the .venv directories under projects/"
69
+ ```
70
+
71
+ Output:
72
+
73
+ ```text
74
+ find projects/ -type d -name ".venv" -exec rm -rf {} +
75
+ ```
76
+
77
+ If you try to ask something unrelated to Linux commands:
78
+
79
+ ```bash
80
+ ape "Tell me about monkeys"
81
+ ```
82
+
83
+ you should get:
84
+
85
+ ```text
86
+ echo "Please try again."
87
+ ```
88
+
89
+ You can change the model using `--model` or `-m`. Models are specified in
90
+ `provider:name` form.
91
+ See [here](https://ai.pydantic.dev/models/) for the supported providers and models.
92
+ For example:
93
+
94
+ ```bash
95
+ ape "List the contents of the working directory with as much detail as possible" --model anthropic:claude-sonnet-4-5
96
+ ```
97
+
98
+ The model is resolved as follows:
99
+
100
+ 1. If `--model`/`-m` is given, that value is always used.
101
+ 2. Otherwise, if the `APE_MODEL` environment variable is set, its value is used.
102
+ 3. Otherwise, the default `openai-chat:gpt-4.1` is used.
103
+
104
+ So you can set a personal default without passing `--model` every time:
105
+
106
+ ```bash
107
+ export APE_MODEL=anthropic:claude-sonnet-4-5
108
+ ```
109
+
110
+ Output:
111
+
112
+ ```text
113
+ ls -lha
114
+ ```
115
+
116
+ ## System-aware suggestions
117
+
118
+ Ape automatically detects a few facts about your machine and adds them to the prompt so
119
+ the suggested command is correct for *your* environment — for example BSD (macOS) vs GNU
120
+ (Linux) flags, the right package manager (`brew`, `apt`, `dnf`, `pacman`, ...), and tools
121
+ that are actually installed. It looks at:
122
+
123
+ - operating system and version (macOS version or Linux distribution),
124
+ - whether the userland is BSD or GNU,
125
+ - CPU architecture (e.g. `arm64` vs `x86_64`),
126
+ - your shell (`$SHELL`),
127
+ - whether you are root,
128
+ - available package manager(s) and common tools (`rg`, `fd`, `jq`, `docker`, ...).
129
+
130
+ This is all gathered locally with the Python standard library and is best-effort: if
131
+ anything can't be determined it is simply left out. **No identifying information is
132
+ collected or sent** — never your username, hostname, working directory, or home path.
133
+
134
+ To see exactly what Ape detects and sends (without calling the model), use
135
+ `--system-info` or `-s`:
136
+
137
+ ```bash
138
+ ape --system-info
139
+ ```
140
+
141
+ Output (example):
142
+
143
+ ```text
144
+ Operating system: Darwin
145
+ macOS version: 26.5
146
+ Userland: BSD (macOS) — prefer BSD-compatible flags
147
+ Architecture: arm64
148
+ Shell: /bin/zsh
149
+ Privileges: non-root (use sudo for privileged actions)
150
+ Package manager(s): brew
151
+ Available tools: rg, fd, jq, git, curl, docker, tar, rsync, sed, awk
152
+ ```
153
+
154
+ ## Executing commands
155
+
156
+ If you pass `--execute` or `-e`, the tool will run the command for you after printing it! Be careful with this as LLMs often make mistakes:
157
+
158
+ ```bash
159
+ ape "Who am I logged in as?"
160
+ ```
161
+
162
+ Output:
163
+
164
+ ```text
165
+ whoami
166
+ jdoe
167
+ ```
168
+
169
+ For more help:
170
+
171
+ ```bash
172
+ ape --help
173
+ ```
174
+
175
+ See also: [Gorilla](https://github.com/gorilla-llm)
@@ -0,0 +1,154 @@
1
+ # Ape
2
+
3
+ Ape is an AI for Linux commands.
4
+
5
+ ```sh
6
+ ape "Find all the important PDF files in user/projects. An important PDF file has 'attention' in its name. Write the results to important_files.txt and then move it to Documents."
7
+ ```
8
+
9
+ Output:
10
+
11
+ ```text
12
+ find ~/user/projects -type f -name "*attention*.pdf" > important_files.txt && mv important_files.txt ~/Documents/
13
+ ```
14
+
15
+ Ape works with any provider supported by [Pydantic AI](https://ai.pydantic.dev/models/)
16
+ — OpenAI, Anthropic, Google, Groq, Mistral and more.
17
+
18
+ To install ([`uv`](https://docs.astral.sh/uv/getting-started/installation/) recommended):
19
+
20
+ ```bash
21
+ uv tool install ape-linux
22
+ ```
23
+
24
+ Next, set the API key for your provider using its standard environment variable.
25
+ For example:
26
+
27
+ ```bash
28
+ export OPENAI_API_KEY=key # for OpenAI models
29
+ export ANTHROPIC_API_KEY=key # for Anthropic models
30
+ ```
31
+
32
+ To run:
33
+
34
+ ```bash
35
+ ape "Create a symbolic link called win pointing to /mnt/c/Users/jdoe"
36
+ ```
37
+
38
+ Output:
39
+
40
+ ```text
41
+ ln -s /mnt/c/Users/jdoe win
42
+ ```
43
+
44
+ Another example:
45
+
46
+ ```bash
47
+ ape "Delete all the .venv directories under projects/"
48
+ ```
49
+
50
+ Output:
51
+
52
+ ```text
53
+ find projects/ -type d -name ".venv" -exec rm -rf {} +
54
+ ```
55
+
56
+ If you try to ask something unrelated to Linux commands:
57
+
58
+ ```bash
59
+ ape "Tell me about monkeys"
60
+ ```
61
+
62
+ you should get:
63
+
64
+ ```text
65
+ echo "Please try again."
66
+ ```
67
+
68
+ You can change the model using `--model` or `-m`. Models are specified in
69
+ `provider:name` form.
70
+ See [here](https://ai.pydantic.dev/models/) for the supported providers and models.
71
+ For example:
72
+
73
+ ```bash
74
+ ape "List the contents of the working directory with as much detail as possible" --model anthropic:claude-sonnet-4-5
75
+ ```
76
+
77
+ The model is resolved as follows:
78
+
79
+ 1. If `--model`/`-m` is given, that value is always used.
80
+ 2. Otherwise, if the `APE_MODEL` environment variable is set, its value is used.
81
+ 3. Otherwise, the default `openai-chat:gpt-4.1` is used.
82
+
83
+ So you can set a personal default without passing `--model` every time:
84
+
85
+ ```bash
86
+ export APE_MODEL=anthropic:claude-sonnet-4-5
87
+ ```
88
+
89
+ Output:
90
+
91
+ ```text
92
+ ls -lha
93
+ ```
94
+
95
+ ## System-aware suggestions
96
+
97
+ Ape automatically detects a few facts about your machine and adds them to the prompt so
98
+ the suggested command is correct for *your* environment — for example BSD (macOS) vs GNU
99
+ (Linux) flags, the right package manager (`brew`, `apt`, `dnf`, `pacman`, ...), and tools
100
+ that are actually installed. It looks at:
101
+
102
+ - operating system and version (macOS version or Linux distribution),
103
+ - whether the userland is BSD or GNU,
104
+ - CPU architecture (e.g. `arm64` vs `x86_64`),
105
+ - your shell (`$SHELL`),
106
+ - whether you are root,
107
+ - available package manager(s) and common tools (`rg`, `fd`, `jq`, `docker`, ...).
108
+
109
+ This is all gathered locally with the Python standard library and is best-effort: if
110
+ anything can't be determined it is simply left out. **No identifying information is
111
+ collected or sent** — never your username, hostname, working directory, or home path.
112
+
113
+ To see exactly what Ape detects and sends (without calling the model), use
114
+ `--system-info` or `-s`:
115
+
116
+ ```bash
117
+ ape --system-info
118
+ ```
119
+
120
+ Output (example):
121
+
122
+ ```text
123
+ Operating system: Darwin
124
+ macOS version: 26.5
125
+ Userland: BSD (macOS) — prefer BSD-compatible flags
126
+ Architecture: arm64
127
+ Shell: /bin/zsh
128
+ Privileges: non-root (use sudo for privileged actions)
129
+ Package manager(s): brew
130
+ Available tools: rg, fd, jq, git, curl, docker, tar, rsync, sed, awk
131
+ ```
132
+
133
+ ## Executing commands
134
+
135
+ If you pass `--execute` or `-e`, the tool will run the command for you after printing it! Be careful with this as LLMs often make mistakes:
136
+
137
+ ```bash
138
+ ape "Who am I logged in as?"
139
+ ```
140
+
141
+ Output:
142
+
143
+ ```text
144
+ whoami
145
+ jdoe
146
+ ```
147
+
148
+ For more help:
149
+
150
+ ```bash
151
+ ape --help
152
+ ```
153
+
154
+ See also: [Gorilla](https://github.com/gorilla-llm)