imap-agent-cli 0.2.0__tar.gz → 0.2.1__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 (37) hide show
  1. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/CHANGELOG.md +7 -0
  2. imap_agent_cli-0.2.1/PKG-INFO +417 -0
  3. imap_agent_cli-0.2.1/README.md +382 -0
  4. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/pyproject.toml +1 -1
  5. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/spec.md +3 -1
  6. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/__init__.py +1 -1
  7. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/cli.py +3 -3
  8. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/skill.py +11 -3
  9. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_cli.py +34 -0
  10. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_imap_client.py +8 -0
  11. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_skill.py +11 -0
  12. imap_agent_cli-0.2.0/PKG-INFO +0 -294
  13. imap_agent_cli-0.2.0/README.md +0 -259
  14. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/.github/workflows/publish.yml +0 -0
  15. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/.gitignore +0 -0
  16. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/AGENTS.md +0 -0
  17. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/LICENSE +0 -0
  18. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/imap_agent_cli.py +0 -0
  19. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/config.py +0 -0
  20. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/errors.py +0 -0
  21. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/imap_client.py +0 -0
  22. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/mime.py +0 -0
  23. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/models.py +0 -0
  24. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/render.py +0 -0
  25. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/runtime.py +0 -0
  26. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/src/imap_agent_cli/search.py +0 -0
  27. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/__init__.py +0 -0
  28. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/_bootstrap.py +0 -0
  29. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/pymap_server_runner.py +0 -0
  30. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_config.py +0 -0
  31. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_live_no_seen.py +0 -0
  32. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_mime.py +0 -0
  33. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_pymap_integration.py +0 -0
  34. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_runtime.py +0 -0
  35. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_search.py +0 -0
  36. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_skill_sync.py +0 -0
  37. {imap_agent_cli-0.2.0 → imap_agent_cli-0.2.1}/tests/test_wheel_smoke.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.1 - 2026-09-08
4
+
5
+ - Direct agents to search only `INBOX` when the user does not specify a folder or broader scope. Do not automatically expand empty or incomplete searches.
6
+ - Keep specific-folder, recursive, and all-folder searches available when requested, including through JSON input.
7
+ - Clarify search scope in CLI help and documentation. Preserve the existing configurable CLI folder default.
8
+ - Add regression coverage for search scope defaults, explicit overrides, and single-folder searches avoiding folder enumeration.
9
+
3
10
  ## 0.2.0 - 2026-09-03
4
11
 
5
12
  - Automatically synchronize existing managed `imap` skills in the standard directory to the running CLI's newer version. No package lookup, uv refresh, or CLI update is performed.
@@ -0,0 +1,417 @@
1
+ Metadata-Version: 2.5
2
+ Name: imap-agent-cli
3
+ Version: 0.2.1
4
+ Summary: Agent-first IMAP CLI for safe email search, read, attachment download, and draft creation
5
+ Project-URL: Homepage, https://github.com/pseudosavant/imap-agent-cli
6
+ Project-URL: Repository, https://github.com/pseudosavant/imap-agent-cli
7
+ Project-URL: Issues, https://github.com/pseudosavant/imap-agent-cli/issues
8
+ Author: Paul
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,cli,drafts,email,imap
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Communications :: Email
22
+ Classifier: Topic :: Communications :: Email :: Post-Office :: IMAP
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: beautifulsoup4>=4.12.0
26
+ Requires-Dist: bleach>=6.2.0
27
+ Requires-Dist: imapclient>=3.0.0
28
+ Requires-Dist: markdownify>=0.14.0
29
+ Requires-Dist: packaging>=23.2
30
+ Requires-Dist: pyyaml>=6.0
31
+ Provides-Extra: test
32
+ Requires-Dist: pymap>=0.36.0; extra == 'test'
33
+ Requires-Dist: pytest>=8.0.0; extra == 'test'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # imap-agent-cli
37
+
38
+ `imap-agent-cli` gives coding agents a narrow, safe interface to generic IMAP mailboxes. It can search email, read messages without changing their unread state, inspect or download requested attachments, and save new or reply drafts.
39
+
40
+ It never sends email and cannot change existing messages or folders.
41
+
42
+ ## Prerequisite
43
+
44
+ `imap-agent-cli` is designed to be used with [`uv`](https://docs.astral.sh/uv/getting-started/installation/). Install `uv` before continuing. The documented workflows and managed agent skill use `uvx` to run the tool without requiring a global installation.
45
+
46
+ ## Quick start with an agent
47
+
48
+ Install the managed `imap` agent skill:
49
+
50
+ ```text
51
+ uvx imap-agent-cli skill install
52
+ ```
53
+
54
+ Configure a default IMAP account through environment variables:
55
+
56
+ ```text
57
+ IMAP_AGENT_CLI_HOST=imap.example.com
58
+ IMAP_AGENT_CLI_PORT=993
59
+ IMAP_AGENT_CLI_USERNAME=me@example.com
60
+ IMAP_AGENT_CLI_PASSWORD=your-password-or-app-password
61
+ IMAP_AGENT_CLI_TLS=true
62
+ IMAP_AGENT_CLI_SSL_MODE=required
63
+ ```
64
+
65
+ Check the connection without reading message bodies:
66
+
67
+ ```text
68
+ uvx imap-agent-cli config check
69
+ ```
70
+
71
+ Then use `$imap` in Codex, Claude Code, or another agentic tool that supports skills:
72
+
73
+ > Use $imap to find the five most recent emails about the Acme renewal. Summarize the latest thread and create a reply draft asking for the updated contract. Do not download attachments.
74
+
75
+ The skill teaches the agent to search before reading, keep operations bounded, download attachments only when requested, and create drafts without sending them.
76
+
77
+ ## What it can do
78
+
79
+ | The tool can | The tool cannot |
80
+ | --- | --- |
81
+ | List folders and their metadata | Send email |
82
+ | Search message metadata | Delete, move, or archive messages |
83
+ | Read messages without marking them read | Mark messages read or unread |
84
+ | Inspect bounded thread context | Change flags, stars, or labels |
85
+ | List and download requested attachments | Create, rename, or delete folders |
86
+ | Append new and reply drafts to Drafts | Modify existing messages |
87
+
88
+ Draft creation only appends a new MIME message to the configured or detected Drafts folder. It never submits or sends the message.
89
+
90
+ ## Use the CLI directly
91
+
92
+ Run the published CLI without installing it globally:
93
+
94
+ ```text
95
+ uvx imap-agent-cli --help
96
+ uvx imap-agent-cli folders
97
+ uvx imap-agent-cli search --subject invoice
98
+ ```
99
+
100
+ To install the command as a persistent tool instead:
101
+
102
+ ```text
103
+ uv tool install imap-agent-cli
104
+ uv tool update-shell
105
+ imap-agent-cli --help
106
+ ```
107
+
108
+ Restart your shell after `uv tool update-shell` if the command is not found.
109
+
110
+ You can also install it into a Python environment:
111
+
112
+ ```text
113
+ python -m pip install imap-agent-cli
114
+ imap-agent-cli --help
115
+ ```
116
+
117
+ The examples below continue to use `uvx imap-agent-cli` so they work without a global installation.
118
+
119
+ ## How safe access works
120
+
121
+ The tool follows five core rules:
122
+
123
+ 1. Folder access is read-only except for appending a new message to Drafts.
124
+ 2. Search fetches message metadata, not complete message bodies.
125
+ 3. Read and thread operations use peek behavior so they do not set the IMAP `\Seen` flag.
126
+ 4. Attachment content is written only after an explicit download command and output directory.
127
+ 5. Draft commands use IMAP `APPEND`. There is no SMTP client or send command.
128
+
129
+ The usual workflow is to search first, select a result by folder and UID, read only the needed context, then optionally create a draft.
130
+
131
+ ## Configure accounts
132
+
133
+ ### One account with environment variables
134
+
135
+ For a single account, environment variables are enough:
136
+
137
+ ```text
138
+ IMAP_AGENT_CLI_HOST=imap.example.com
139
+ IMAP_AGENT_CLI_PORT=993
140
+ IMAP_AGENT_CLI_USERNAME=me@example.com
141
+ IMAP_AGENT_CLI_PASSWORD=your-password-or-app-password
142
+ IMAP_AGENT_CLI_TLS=true
143
+ IMAP_AGENT_CLI_SSL_MODE=required
144
+ IMAP_AGENT_CLI_DRAFTS_FOLDER=Drafts
145
+ ```
146
+
147
+ `IMAP_AGENT_CLI_DRAFTS_FOLDER` is optional. When omitted, the CLI tries the server's IMAP special-use metadata and common Drafts folder names.
148
+
149
+ Validate the resolved configuration, login, folders, default folder, and Drafts detection without reading message bodies:
150
+
151
+ ```text
152
+ uvx imap-agent-cli config check
153
+ ```
154
+
155
+ ### Multiple account profiles
156
+
157
+ Create a config file when you need named accounts:
158
+
159
+ ```text
160
+ uvx imap-agent-cli config init
161
+ uvx imap-agent-cli config add-profile work --host imap.example.com --port 993 --username me@example.com --password-env IMAP_AGENT_CLI_WORK_PASSWORD
162
+ uvx imap-agent-cli config set-default-profile work
163
+ ```
164
+
165
+ The config file is stored at `~/.imap-agent-cli/config.toml`. Keep passwords in environment variables. Profiles store the name of the password environment variable, not the password itself.
166
+
167
+ The CLI uses standard IMAP username and password authentication. It does not provide OAuth setup. Providers that disable account-password login may require an app password.
168
+
169
+ Inspect resolved settings without exposing secrets, or list available profiles:
170
+
171
+ ```text
172
+ uvx imap-agent-cli config show
173
+ uvx imap-agent-cli profiles
174
+ uvx imap-agent-cli config check --profile work
175
+ ```
176
+
177
+ Pass `--profile NAME` to any mailbox command to select a non-default profile. Direct commands also accept connection flags and `--password-stdin` for one-off use.
178
+
179
+ ### Connection security
180
+
181
+ The recommended configuration is port `993`, `tls=true`, and `ssl_mode=required`.
182
+
183
+ | Setting | Behavior |
184
+ | --- | --- |
185
+ | `tls=true`, `ssl_mode=required` | Use implicit TLS and fail if a secure connection cannot be established |
186
+ | `tls=false`, `ssl_mode=required` | Require STARTTLS before login |
187
+ | `ssl_mode=preferred` | Allow implicit TLS to fall back to STARTTLS without falling back to plaintext login |
188
+ | `ssl_mode=disabled` | Allow plaintext IMAP login for deliberate local testing only |
189
+
190
+ Both `required` and `preferred` refuse to send credentials over plaintext.
191
+
192
+ ## Common workflows
193
+
194
+ ### Find messages
195
+
196
+ Search defaults to `INBOX` only, returns metadata only, and limits results to a bounded number. You can override the default folder with `defaults.default_folder` in config. Pass `--folder INBOX` to explicitly select the inbox:
197
+
198
+ ```text
199
+ uvx imap-agent-cli search --subject "invoice" --max-results 10
200
+ uvx imap-agent-cli search --from "person@example.com" --since 2026-01-01 --max-results 10
201
+ uvx imap-agent-cli search --to "me@example.com" --has-attachments --max-results 10 --max-scan 100
202
+ ```
203
+
204
+ When requested, search a specific folder, include its children, or search all selectable folders:
205
+
206
+ ```text
207
+ uvx imap-agent-cli search --folder "Archive/Support" --subject "contract" --max-results 25
208
+ uvx imap-agent-cli search --folder Projects --recursive --subject "contract" --max-results 25
209
+ uvx imap-agent-cli search --all-folders --subject "contract" --max-results 25
210
+ ```
211
+
212
+ All-folder searches exclude folders marked as Junk or Spam by default. All-folder and recursive searches can be expensive on large nested archives even with a small result limit. The installed skill directs agents to use the inbox unless the user requests another scope. Empty or incomplete results do not authorize automatically expanding the search.
213
+
214
+ ### Read a selected message
215
+
216
+ Search results identify messages by folder and UID. Read only metadata when confirming a result, or request a body format when content is needed:
217
+
218
+ ```text
219
+ uvx imap-agent-cli read --folder INBOX --uid 12345 --body-format metadata --include-attachments none
220
+ uvx imap-agent-cli read --folder INBOX --uid 12345 --body-format plain --max-body-chars 12000
221
+ uvx imap-agent-cli read --folder INBOX --uid 12345 --body-format markdown
222
+ uvx imap-agent-cli read --folder INBOX --uid 12345 --body-format html --include-attachments metadata
223
+ ```
224
+
225
+ | Body format | Intended use |
226
+ | --- | --- |
227
+ | `metadata` | Return headers without a message body |
228
+ | `plain` | Summaries and ordinary text processing |
229
+ | `markdown` | Agent-friendly conversion that preserves common structure |
230
+ | `html` | Sanitized HTML when layout, tables, or links matter |
231
+ | `raw-html` | Explicit access to untrusted, unsanitized source HTML |
232
+
233
+ HTML sanitization removes active content and unsafe resource references. Markdown conversion is intentionally lossy. Attachment content is never included in a read result.
234
+
235
+ ### Inspect thread context
236
+
237
+ Start with metadata-only context for a conversation:
238
+
239
+ ```text
240
+ uvx imap-agent-cli thread --folder INBOX --uid 12345 --max-messages 5
241
+ ```
242
+
243
+ Include only the latest body when preparing a summary or reply:
244
+
245
+ ```text
246
+ uvx imap-agent-cli thread --folder INBOX --uid 12345 --include-body latest --body-format plain --max-body-chars 6000
247
+ ```
248
+
249
+ ### Inspect and download attachments
250
+
251
+ List attachment names, types, sizes, and part IDs without downloading content:
252
+
253
+ ```text
254
+ uvx imap-agent-cli attachments --folder INBOX --uid 12345
255
+ ```
256
+
257
+ Download one attachment or all non-inline attachments to an explicit directory:
258
+
259
+ ```text
260
+ uvx imap-agent-cli attachments download --folder INBOX --uid 12345 --part-id 2 --output-dir ./email-attachments
261
+ uvx imap-agent-cli attachments download --folder INBOX --uid 12345 --all --output-dir ./email-attachments
262
+ ```
263
+
264
+ Downloads sanitize filenames and preflight every target before writing. Existing files are preserved unless `--overwrite` is provided. Inline attachments are excluded unless `--include-inline` is provided.
265
+
266
+ ### Create drafts
267
+
268
+ Create a new draft:
269
+
270
+ ```text
271
+ uvx imap-agent-cli draft create --to person@example.com --subject "Hello" --body "Draft only."
272
+ ```
273
+
274
+ Create a reply draft from an existing message:
275
+
276
+ ```text
277
+ uvx imap-agent-cli draft reply --folder INBOX --uid 12345 --body "Thanks. I will review this."
278
+ ```
279
+
280
+ For longer content, use `--body-file`. Add local files with repeated `--attachment` options. Draft bodies may be `plain`, `markdown`, or `html`.
281
+
282
+ Reply drafts choose the original sender or `Reply-To`, add a reply subject when needed, and preserve `In-Reply-To` and `References` headers. They do not quote the original message by default.
283
+
284
+ ## Manage the agent skill
285
+
286
+ The managed skill is installed at `~/.agents/skills/imap/SKILL.md`:
287
+
288
+ ```text
289
+ uvx imap-agent-cli skill install
290
+ ```
291
+
292
+ Inspect its path, ownership, version, integrity, and automatic synchronization eligibility without changing it:
293
+
294
+ ```text
295
+ uvx imap-agent-cli skill status
296
+ uvx imap-agent-cli skill status --format plain
297
+ ```
298
+
299
+ Normal invocations of an installed CLI update a pristine older managed skill to the running CLI version. Synchronization is local. It does not query PyPI, refresh uv's cache, or update the CLI. Missing skills are never installed automatically. Unmanaged, modified, equal-version, and newer skills are preserved.
300
+
301
+ Restore altered managed content explicitly:
302
+
303
+ ```text
304
+ uvx imap-agent-cli skill install --force
305
+ ```
306
+
307
+ Install-time `--force` still refuses unmanaged content and never downgrades a newer skill. Managed front matter records ownership, version, and a SHA-256 content hash. The hash detects edits. It is not a signature.
308
+
309
+ Remove the managed skill:
310
+
311
+ ```text
312
+ uvx imap-agent-cli skill remove
313
+ ```
314
+
315
+ Removal deletes only `SKILL.md` and removes its directory when empty. Unrelated files are kept. The original `install-skill` and `remove-skill` aliases remain supported.
316
+
317
+ All skill commands accept `--skills-dir PATH`. Custom locations require explicit updates and are not checked during normal invocations:
318
+
319
+ ```text
320
+ uvx imap-agent-cli skill install --skills-dir ./my-skills
321
+ uvx imap-agent-cli skill status --skills-dir ./my-skills
322
+ ```
323
+
324
+ Local checkouts, direct source installs, editable builds, and unidentifiable installation origins do not synchronize automatically. Explicit skill installation still works from development builds. Skill updates affect future agent sessions and may not replace instructions already loaded by a running session.
325
+
326
+ ## Structured output and automation
327
+
328
+ Operational commands write JSON payloads to stdout. Diagnostics, warnings, progress, and errors go to stderr. This keeps command output safe to parse in agent and automation workflows.
329
+
330
+ Search, read, and draft commands also accept structured input from a JSON file:
331
+
332
+ ```text
333
+ uvx imap-agent-cli search --json query.json
334
+ uvx imap-agent-cli read --json message.json
335
+ uvx imap-agent-cli draft create --json draft.json
336
+ uvx imap-agent-cli draft reply --json reply.json
337
+ ```
338
+
339
+ Use `--json -` to read the JSON request from stdin. Failures leave stdout empty and write a compact JSON error to stderr. Logs do not include passwords, message bodies, or attachment content.
340
+
341
+ Default guardrails keep work bounded:
342
+
343
+ | Limit | Default |
344
+ | --- | ---: |
345
+ | Search results | 25 |
346
+ | Messages scanned | 250 |
347
+ | Body characters | 12,000 |
348
+ | Thread messages | 5 |
349
+ | Connection timeout | 15 seconds |
350
+ | Read timeout | 30 seconds |
351
+
352
+ Commands expose targeted overrides such as `--max-results`, `--max-scan`, `--max-messages`, and `--max-body-chars`.
353
+
354
+ ## Reference
355
+
356
+ | Command | Purpose |
357
+ | --- | --- |
358
+ | `config` | Initialize, inspect, validate, and manage profile configuration |
359
+ | `profiles` | List configured profile names |
360
+ | `skill` | Install, inspect, or remove the managed agent skill |
361
+ | `folders` | List folders and folder metadata |
362
+ | `search` | Search message metadata with bounded results |
363
+ | `read` | Read one message by folder and UID without marking it read |
364
+ | `thread` | Inspect bounded conversation context |
365
+ | `attachments` | List or explicitly download attachments |
366
+ | `draft create` | Append a new message to Drafts |
367
+ | `draft reply` | Append a reply draft with conversation headers |
368
+
369
+ Use command help for the complete set of options:
370
+
371
+ ```text
372
+ uvx imap-agent-cli --help
373
+ uvx imap-agent-cli search --help
374
+ uvx imap-agent-cli read --help
375
+ uvx imap-agent-cli attachments download --help
376
+ uvx imap-agent-cli draft reply --help
377
+ uvx imap-agent-cli --about
378
+ uvx imap-agent-cli --version
379
+ ```
380
+
381
+ ## Development
382
+
383
+ Run the CLI from the repository:
384
+
385
+ ```text
386
+ uv run ./imap_agent_cli.py --help
387
+ uv run ./imap_agent_cli.py folders
388
+ uv run ./imap_agent_cli.py search --subject invoice
389
+ ```
390
+
391
+ Run the no-network test suite:
392
+
393
+ ```text
394
+ python -m unittest discover -v
395
+ ```
396
+
397
+ Run the opt-in local IMAP integration test after setting `IMAP_AGENT_CLI_TEST_PYMAP=1`:
398
+
399
+ ```text
400
+ uv run --extra test python -m unittest tests.test_pymap_integration -v
401
+ ```
402
+
403
+ The integration test starts `pymap dict --demo-data` locally and signs in with its demo credentials.
404
+
405
+ Run the opt-in live no-seen test only when intentionally validating a configured mailbox. Set `IMAP_AGENT_CLI_LIVE_TEST=1` first:
406
+
407
+ ```text
408
+ python -m unittest tests.test_live_no_seen -v
409
+ ```
410
+
411
+ Build the package:
412
+
413
+ ```text
414
+ uv build --no-sources
415
+ ```
416
+
417
+ This project is under active development. The behavior target is documented in [`spec.md`](./spec.md). It is distributed under the [MIT License](./LICENSE).