| id | 002 | |
|---|---|---|
| title | Agent Mail Packaging | |
| status | in_progress | |
| blocked_by |
|
|
| blocks |
|
Package the audited Agent Mail CLI behavior from spec 001 as a Python distribution on PyPI, platform binaries on GitHub Releases, and a WinGet package for Windows users. npm distribution is intentionally separate and is covered by spec 003.
The PyPI distribution name is agent-mail-cli because PyPI rejected agent-mail as too similar to an existing project. The installed command remains agent-mail, preserving the product wedge and the npm npx -y @juanjofuchs/agent-mail describe path.
Completion rule: This spec is not complete until all acceptance criteria are verified through the testing approach below, including real installs from real publish channels:
pipx install agent-mail-clion a clean machine andwinget install JuanjoFuchs.agent-mail-clion a clean Windows machine after Microsoft approval. Build-only and CI-only verification are insufficient. The agent must iterate until verification passes.
- Make
agent-mailrunnable on a fresh machine through Python packaging (pip,pipx) and WinGet. - Preserve the complete spec 001 command behavior when invoked through installed packages and release binaries.
- Publish reproducible release artifacts from GitHub Actions, not from a developer machine.
- Establish the release artifacts that spec 003 consumes for npm and
npxdistribution.
- FR1:
pip install agent-mail-cli,pipx install agent-mail-cli, andpipx run --spec agent-mail-cli agent-mail describework on Linux, macOS, and Windows for Python 3.10+. - FR2: After install,
agent-mailis available on PATH even though the PyPI distribution name isagent-mail-cli. - FR3: Each tagged release attaches a wheel, an sdist, and four PyInstaller binaries to the GitHub Release.
- FR4:
winget install JuanjoFuchs.agent-mail-cliinstallsagent-mailon Windows after the WinGet manifest is approved. - FR5: Installed packages and release binaries preserve all behavior specified by spec 001.
- FR6: Packaged installs use
~/.agent-mail/mail.dbas the default database path, resolved from the user's home directory.AGENT_MAIL_DBremains the only override mechanism.
- NFR1: All release artifacts are built and uploaded by GitHub Actions.
- NFR2: After the first release, PyPI uploads use Trusted Publishing (OIDC). Long-lived PyPI API tokens are not used for steady-state publishing.
- NFR3: The release version is authored in exactly one place and tag-pushed releases fail before artifact creation when the tag disagrees with that version.
-
TC1: Source distribution requires Python 3.10+. PyInstaller binaries do not require Python on the user's machine.
-
TC2: PyPI distribution name is
agent-mail-cli; Python import name isagent_mail; console command isagent-mail. -
TC3: The console-script entry point exposes the same CLI as spec 001.
-
TC4: PyInstaller
--onefileis used for release binaries. -
TC5: Platform binary matrix:
Platform Architecture Runner Binary suffix Windows x64 windows-latestwindows-x64.exeLinux x64 ubuntu-22.04linux-x64macOS x64 macos-15-inteldarwin-x64macOS arm64 macos-latestdarwin-arm64 -
TC6: Default database path resolves to
~/.agent-mail/mail.dbvia the user's home directory. -
TC7:
AGENT_MAIL_DBoverride semantics from spec 001 are unchanged. -
TC8: WinGet package identifier is
JuanjoFuchs.agent-mail-cli.
| Requirement | Acceptance Criteria |
|---|---|
| FR1 | AC6, AC7, AC8 |
| FR2 | AC6, AC7, AC8, AC10 |
| FR3 | AC1, AC3 |
| FR4 | AC9, AC10, AC11 |
| FR5 | AC4, AC5 |
| FR6 | AC12, AC13 |
| NFR1 | AC3, AC9, AC15, AC16 |
| NFR2 | AC15, AC16 |
| NFR3 | AC14 |
| TC1 | AC6, AC7, AC8, AC10 |
| TC2 | AC1, AC6, AC7, AC8 |
| TC3 | AC4, AC5 |
| TC4 | AC3, AC5 |
| TC5 | AC3 |
| TC6 | AC12 |
| TC7 | AC13 |
| TC8 | AC9, AC10, AC11 |
These must be completed before the implementation can publish successfully. GitHub-side setup may be done from the agent session with JJ's approval and credentials. PyPI and token creation steps require the relevant web UI.
Known gotcha from ccburn: PyPI's pending-publisher flow may fail for a first upload. The reliable path used here was a one-time API token for the first release, then a normal Trusted Publisher on the existing PyPI project for steady-state OIDC publishing. A pending publisher does not activate after a token-created project already exists.
- PyPI account exists at https://pypi.org.
- Project name
agent-mail-clireserved on PyPI via Pending Trusted Publisher. - Pending Trusted Publisher configured for:
- Owner:
JuanjoFuchs - Repository:
agent-mail-cli - Workflow:
release.yml - Environment:
release
- Owner:
- PyPI API token generated and stored locally in
.envasPYPI_API_TOKEN. - Push
PYPI_API_TOKENto the repository secret for the first release only. - After the first release succeeds and
https://pypi.org/project/agent-mail-cli/is live:- Add a normal Trusted Publisher to the existing PyPI project.
- Remove the token fallback from the release workflow.
- Delete the
PYPI_API_TOKENrepository secret.
- Create the
releaseenvironment.
- Generate a GitHub Personal Access Token with
public_reposcope. - Add it as the
WINGET_TOKENrepository secret.
- After the first successful GitHub Release includes a Windows EXE, trigger the one-time WinGet submission workflow for version
0.1.1. - Verify the generated WinGet PR includes
UpgradeBehavior: uninstallPreviousbefore Microsoft review.
The implementation moves from a single script to an installable Python package while preserving the CLI behavior specified in spec 001. The package must support a console command and python -m agent_mail.
PyPI rejected agent-mail, so the PyPI distribution is agent-mail-cli. The command name, GitHub Release binary name, WinGet command alias, and spec 003 npm command remain agent-mail. This preserves the user-facing interface while satisfying PyPI's naming rules.
A Pending Trusted Publisher is configured before release, but the first upload uses PYPI_API_TOKEN because ccburn hit first-upload failures with pending publishers. Because the token upload creates the project, the pending publisher remains pending and cannot publish future releases. Steady-state publishing uses a normal Trusted Publisher configured under the existing agent-mail-cli PyPI project. Token-based publishing is removed from the workflow and the repository secret is deleted after an OIDC release succeeds.
The WinGet portable installer manifest must include UpgradeBehavior: uninstallPrevious. Without it, upgrades can leave duplicate installed versions. The submission workflow may inject the field, but AC9 verifies the submitted manifest rather than trusting the workflow implementation.
The original default database location was mail.db next to the script. Packaged installs cannot use that location because pipx environments and portable installer directories are not durable user state. Packaged installs default to ~/.agent-mail/mail.db; AGENT_MAIL_DB remains the only override.
The packaged CLI does not search for or import legacy mail.db files from other locations. Migration is documented as a manual copy operation.
The project version is authored once in package metadata. Release tags, file names, and release titles derive from or validate against that version.
ccburn (D:/jfuchs/dev/ccburn) is the working precedent for PyPI, GitHub Release binaries, and WinGet automation. The implementer reads ccburn's package metadata and workflows, then adapts names, package identifiers, binary names, and dependencies for Agent Mail. This spec defines the contracts; ccburn provides the proven implementation pattern.
- Convert the CLI into an installable
agent_mailpackage while preserving spec 001 behavior. - Expose
agent-mailas the console command. - Support
python -m agent_mail. - Change the packaged default database path to
~/.agent-mail/mail.db. - Keep
AGENT_MAIL_DBas the only database path override.
- Add package metadata for
agent-mail-cli, Python 3.10+, MIT license, repository URL, and theagent-mailscript entry. - Keep runtime dependencies empty unless implementation proves one is required.
- Verify the built wheel filename uses PyPI's normalized
agent_mail_cliprefix.
- Add automated coverage for every spec 001 acceptance criterion.
- Add parity coverage that runs each command through the importable Python package and the PyInstaller binary, comparing stdout JSON, stderr JSON where applicable, and exit codes.
- Isolate mailbox state per test with
AGENT_MAIL_DB.
- Add CI for lint, test, and build validation.
- Add a release workflow that validates the tag against package metadata before building artifacts.
- Publish wheel and sdist to PyPI from GitHub Actions.
- Build and attach the four platform binaries listed in TC5 to the GitHub Release.
- Add WinGet initial-submission and follow-up publish workflows using the
JuanjoFuchs.agent-mail-cliidentifier. - Ensure the WinGet submission manifest contains
UpgradeBehavior: uninstallPrevious.
- Update
README.mdinstall instructions forpipx install agent-mail-cli,pipx run --spec agent-mail-cli agent-mail describe, direct GitHub Release binaries, andwinget install JuanjoFuchs.agent-mail-cliafter Microsoft approval. - Document the manual legacy database migration copy.
- Update
AGENTS.mdandPROJECT_UNDERSTANDING.mdif the source layout changes.
- Set the first release version to
0.1.1afterv0.1.0published to PyPI but did not complete the GitHub Release. - Push tag
v0.1.1after JJ approves the implementation. - Verify GitHub Release artifacts, PyPI publication, and clean-machine
pipxinstall. - Complete the PyPI Trusted Publishing cleanup described in the prerequisites.
- Trigger the initial WinGet submission and verify the Microsoft PR opens.
- Monitor the Microsoft PR until approval or rejection.
- Local
ruff check src/ tests/passed. - Local
pytestpassed against the importable package. - Local parity tests passed against the PyInstaller binary.
- Local
python -m buildproduced wheel and sdist artifacts. - Local
twine check dist/*passed. - GitHub Release
v0.1.1exists with wheel, sdist, and four platform binaries. - PyPI
agent-mail-cli==0.1.1is live. - Clean Linux
pip install agent-mail-cli==0.1.1verification passed. - Clean Linux
pipx install agent-mail-cli==0.1.1verification passed. - Clean Linux
pipx run --spec agent-mail-cli==0.1.1 agent-mail describeverification passed. - Live
pipx runsmoke test covereddescribe,send,read,status, andackwith an isolatedAGENT_MAIL_DB. - Initial WinGet submission workflow succeeded for
0.1.1. - WinGet PR opened:
microsoft/winget-pkgs#371963. - Submitted WinGet installer manifest contains
UpgradeBehavior: uninstallPrevious. - Release workflow token fallback removed for OIDC-only PyPI publish attempt.
- OIDC-only
v0.1.2release attempt failed before upload with PyPIinvalid-pending-publisher: valid token, but project already exists. - Normal Trusted Publisher added under the existing
agent-mail-cliproject in the PyPI web UI. - OIDC-only
v0.1.2release rerun succeeded through PyPI Trusted Publishing. - PyPI
agent-mail-cli==0.1.2is live. - GitHub Release
v0.1.2exists with wheel, sdist, and four platform binaries. - Live
pipx run --spec agent-mail-cli==0.1.2 agent-mail describeverification passed. - Token-based PyPI fallback removed from release workflow.
-
PYPI_API_TOKENrepository secret deleted;gh secret listshows onlyWINGET_TOKEN. - WinGet publish workflow was triggered by
v0.1.2; it failed as expected because the initial WinGet PR is not approved yet. - Clean macOS
piporpipxinstall verified from PyPI. - Clean Windows
piporpipxinstall verified from PyPI. -
winget install JuanjoFuchs.agent-mail-cliverified after Microsoft approval. - Subsequent WinGet upgrade behavior verified after a later release.
- AC1:
python -m buildproducesdist/agent_mail_cli-X.Y.Z-py3-none-any.whlanddist/agent_mail_cli-X.Y.Z.tar.gzfor the package metadata version. - AC2:
twine check dist/*passes. - AC3: After a successful tag push, the GitHub Release for that tag has six artifacts:
.whl,.tar.gz, and four platform binaries.
- AC4: All spec 001 acceptance criteria (AC1-AC46) pass against the installed
agent-mailcommand. - AC5: Parity tests run each spec 001 command through both the importable package and the PyInstaller binary, asserting identical stdout JSON, stderr JSON where applicable, and exit codes.
- AC6:
pip install agent-mail-clion clean Python 3.10+ environments on Linux, macOS, and Windows makesagent-mailavailable on PATH. - AC7:
pipx install agent-mail-cli && agent-mail describereturns the documented schema on Linux, macOS, and Windows. - AC8:
pipx run --spec agent-mail-cli agent-mail describeworks without persistent install.
- AC9: The initial WinGet workflow opens a PR to
microsoft/winget-pkgs; the submitted installer manifest containsUpgradeBehavior: uninstallPrevious. - AC10: After Microsoft approval,
winget install JuanjoFuchs.agent-mail-cliinstalls the binary on a clean Windows x64 machine andagent-mail describeruns from any working directory. - AC11: After a subsequent release and WinGet publish run,
winget upgrade JuanjoFuchs.agent-mail-clidoes not leave duplicate entries;winget list agent-mail-clireturns exactly one row.
- AC12: First invocation of the packaged command creates
~/.agent-mail/mail.dbwith the schema documented in spec 001 TC9. - AC13:
AGENT_MAIL_DB=<path> agent-mail ...directs all reads and writes to<path>;~/.agent-mail/mail.dbis not created or modified.
- AC14: Pushing tag
vX.Y.Zwith a value that differs from the package metadata version fails the release workflow before artifact creation. - AC15: The first successful PyPI release publishes using
PYPI_API_TOKENandhttps://pypi.org/project/agent-mail-cli/is live. The pending publisher is not promoted because the project was created by token upload; steady-state publishing moves to a normal Trusted Publisher on the existing project. - AC16: After
PYPI_API_TOKENis removed and token-based workflow configuration is deleted, the next release publishes through OIDC without a password field in the PyPI publish step.
Run before pushing a release tag:
ruff check src/ tests/
pytest
python -m build
twine check dist/*
pipx install ./dist/agent_mail_cli-*.whl --force
agent-mail describeExpected result: lint, tests, build, package checks, local wheel install, and agent-mail describe all succeed.
Every PR and main push runs CI for lint, tests, and build validation. A failed CI run blocks release work until fixed.
After pushing vX.Y.Z:
gh run watch
gh release view vX.Y.Z
pip index versions agent-mail-cliExpected result: release workflow succeeds, six artifacts are attached to the GitHub Release, and the version is visible on PyPI.
- Linux or macOS clean environment:
pipx run --spec agent-mail-cli agent-mail describe. - Windows clean environment:
pipx install agent-mail-cli && agent-mail describe. - After WinGet approval:
winget install JuanjoFuchs.agent-mail-cli, thenagent-mail describe. - After the next release:
winget upgrade JuanjoFuchs.agent-mail-cli, then confirmwinget list agent-mail-clireturns one row.
- Agent: Finish implementation and pass local validation.
- Agent: Ask JJ before pushing the release tag.
- Human: Approves the release tag.
- Agent: Pushes the tag and monitors GitHub Actions.
- Agent: Reports PyPI and GitHub Release status.
- Human: Confirms PyPI Trusted Publisher status in the PyPI web UI if the agent cannot access it.
- Agent: Removes token-based publishing and deletes the repository secret after confirmation.
- Agent: Triggers WinGet submission.
- Human: Confirms clean Windows and Microsoft Store/WinGet validation steps when local agent access is unavailable.
pipx install agent-mail-cli
agent-mail describepipx run --spec agent-mail-cli agent-mail describewinget install JuanjoFuchs.agent-mail-cli
agent-mail describeManual legacy database migration:
mkdir -p ~/.agent-mail
cp /path/to/legacy/mail.db ~/.agent-mail/mail.db- npm distribution and
npxbehavior; covered by spec 003. - Linux arm64 binaries.
- Homebrew, conda, deb, rpm, or other package managers.
- TestPyPI and pre-release channels.
- Automatic legacy database migration.
- A
--migratecommand. - New Agent Mail CLI behavior beyond the packaged default database path.
- Telemetry, update checks, or network calls from the CLI itself.
- spec 001:
specs/001-agent-mail-cli.md— behavioral contract this packaging must preserve. - spec 003:
specs/003-npm-distribution.md— npm distribution that consumes these release binaries. - ccburn implementation reference:
D:/jfuchs/dev/ccburn— package metadata and GitHub workflows for CI, release, and WinGet. - PyPI Trusted Publishing: https://docs.pypi.org/trusted-publishers/.
- WinGet
wingetcreate: https://learn.microsoft.com/en-us/windows/package-manager/package/windows-package-manager-manifest-creator. - Project context: PROJECT_UNDERSTANDING.md.