pypi-doppler

LOCAL-ONLY PyPI publishing with Doppler credentials. TRIGGERS - publish to PyPI, pypi upload, local publish. NEVER use in CI/CD.

29 stars

Best use case

pypi-doppler is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

LOCAL-ONLY PyPI publishing with Doppler credentials. TRIGGERS - publish to PyPI, pypi upload, local publish. NEVER use in CI/CD.

Teams using pypi-doppler should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/pypi-doppler/SKILL.md --create-dirs "https://raw.githubusercontent.com/terrylica/cc-skills/main/plugins/itp/skills/pypi-doppler/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/pypi-doppler/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How pypi-doppler Compares

Feature / Agentpypi-dopplerStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

LOCAL-ONLY PyPI publishing with Doppler credentials. TRIGGERS - publish to PyPI, pypi upload, local publish. NEVER use in CI/CD.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# PyPI Publishing with Doppler (Local-Only)

> **Self-Evolving Skill**: This skill improves through use. If instructions are wrong, parameters drifted, or a workaround was needed — fix this file immediately, don't defer. Only update for real, reproducible issues.

## When to Use This Skill

Use this skill when:

- Publishing Python packages to PyPI from local machine
- Setting up Doppler for PyPI token management
- Creating local publish scripts with CI detection guards
- Validating repository ownership before release

## WORKSPACE-WIDE POLICY: LOCAL-ONLY PUBLISHING

**This skill supports LOCAL machine publishing ONLY.**

### FORBIDDEN

- Publishing from GitHub Actions
- Publishing from any CI/CD pipeline (GitHub Actions, GitLab CI, Jenkins, CircleCI)
- `publishCmd` in semantic-release configuration
- Building packages in CI (`uv build` in prepareCmd)
- Storing PyPI tokens in GitHub secrets

### REQUIRED

- Use `scripts/publish-to-pypi.sh` on local machine
- CI detection guards in publish script
- Manual approval before each release
- Doppler credential management (no plaintext tokens)
- Repository verification (prevents fork abuse)

### Rationale

- **Security**: No long-lived PyPI tokens in GitHub secrets
- **Speed**: 30 seconds locally vs 3-5 minutes in CI
- **Control**: Manual approval step before production release
- **Flexibility**: Centralized credential management via Doppler

**See**: ADR-0027, `docs/development/PUBLISHING.md`

---

## Overview

This skill provides **local-only PyPI publishing** using Doppler for secure credential management. It integrates with the workspace-wide release workflow where:

1. **GitHub Actions**: Automated versioning ONLY (tags, releases, CHANGELOG)
2. **Local Machine**: Manual PyPI publishing with Doppler credentials

## Bundled Scripts

| Script                                                       | Purpose                                        |
| ------------------------------------------------------------ | ---------------------------------------------- |
| [`scripts/publish-to-pypi.sh`](./scripts/publish-to-pypi.sh) | Local PyPI publishing with CI detection guards |

**Usage**: Copy to your project's `scripts/` directory:

```bash
/usr/bin/env bash << 'DOPPLER_EOF'
# Environment-agnostic path
PLUGIN_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/marketplaces/cc-skills/plugins/itp}"
cp "$PLUGIN_DIR/skills/pypi-doppler/scripts/publish-to-pypi.sh" scripts/
chmod +x scripts/publish-to-pypi.sh
DOPPLER_EOF
```

---

## Prerequisites

### One-Time Setup

1. **Install Doppler CLI**:

   ```bash
   brew install dopplerhq/cli/doppler
   ```

2. **Authenticate with Doppler**:

   ```bash
   doppler login
   ```

3. **Verify access to `claude-config` project**:

   ```bash
   doppler whoami
   doppler projects
   ```

### PyPI Token Setup

1. **Create PyPI API token**:
   - Visit: <https://pypi.org/manage/account/token/>
   - Enable 2FA if not already enabled (required since 2024)
   - Create token with scope: "Entire account" or specific project
   - Copy token (starts with `pypi-AgEIcHlwaS5vcmc...`, ~180 characters)

2. **Store token in Doppler**:

   ```bash
   doppler secrets set PYPI_TOKEN='pypi-AgEIcHlwaS5vcmc...' \
     --project claude-config \
     --config prd
   ```

3. **Verify token stored**:

   ```bash
   doppler secrets get PYPI_TOKEN \
     --project claude-config \
     --config prd \
     --plain
   ```

---

## Publishing Workflow

### MANDATORY: Verify Version Increment Before Publishing

**Pre-publish validation**: Before publishing to PyPI, verify that the version has incremented from the previous release. Publishing without a version increment is invalid and wastes resources.

**Autonomous check sequence**:

1. Compare local `pyproject.toml` version against latest PyPI version
2. If versions match -- **STOP** - do not proceed with publishing
3. Inform user: "Version not incremented. Run semantic-release first or verify commits include `feat:` or `fix:` types."

### Complete Release Workflow

**Step 1: Development & Commit** (Conventional Commits):

```bash
git add .
git commit -m "feat: add new feature"  # MINOR bump
git push origin main
```

**Step 2: Automated Versioning** (GitHub Actions - 40-60s):

GitHub Actions automatically: analyzes commits, determines next version, updates `pyproject.toml`/`package.json`, generates CHANGELOG, creates git tag, creates GitHub release.

**PyPI publishing does NOT happen here** (by design - see ADR-0027).

**Step 3: Local PyPI Publishing** (30 seconds):

```bash
git pull origin main
./scripts/publish-to-pypi.sh
```

### Using Bundled Script (Recommended)

```bash
/usr/bin/env bash << 'GIT_EOF'
# First time: copy script from skill to your project (environment-agnostic)
PLUGIN_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/marketplaces/cc-skills/plugins/itp}"
cp "$PLUGIN_DIR/skills/pypi-doppler/scripts/publish-to-pypi.sh" scripts/
chmod +x scripts/publish-to-pypi.sh

# After semantic-release creates GitHub release
git pull origin main

# Publish using local copy of bundled script
./scripts/publish-to-pypi.sh
GIT_EOF
```

**Bundled script features**: CI detection guards, repository verification, Doppler integration, build + publish + verify workflow, clear error messages.

### Manual Publishing (Advanced)

For manual publishing without the canonical script:

```bash
/usr/bin/env bash << 'CONFIG_EOF'
# Retrieve token from Doppler
PYPI_TOKEN=$(doppler secrets get PYPI_TOKEN \
  --project claude-config \
  --config prd \
  --plain)

# Build package
uv build

# Publish to PyPI
UV_PUBLISH_TOKEN="${PYPI_TOKEN}" uv publish
CONFIG_EOF
```

**WARNING**: Manual publishing bypasses CI detection guards and repository verification. Use canonical script unless you have a specific reason not to.

---

## Reference Documentation

| Topic                 | Reference                                                           |
| --------------------- | ------------------------------------------------------------------- |
| CI Detection          | [CI Detection Enforcement](./references/ci-detection.md)            |
| Credential Management | [Doppler & Token Management](./references/credential-management.md) |
| Troubleshooting       | [Troubleshooting Guide](./references/troubleshooting.md)            |
| TestPyPI Testing      | [TestPyPI Testing](./references/testpypi-testing.md)                |
| mise Task Integration | [mise Task Integration](./references/mise-task-integration.md)      |

---

## Related Documentation

- **ADR-0027**: `docs/architecture/decisions/0027-local-only-pypi-publishing.md` - Architectural decision for local-only publishing
- **ADR-0028**: `docs/architecture/decisions/0028-skills-documentation-alignment.md` - Skills alignment with ADR-0027
- **PUBLISHING.md**: `docs/development/PUBLISHING.md` - Complete release workflow guide
- **mise-tasks Skill**: [`mise-tasks`](../mise-tasks/SKILL.md) - Task orchestration with dependency management
- **Release Workflow Patterns**: [`release-workflow-patterns.md`](../mise-tasks/references/release-workflow-patterns.md) - DAG patterns and anti-patterns
- **Bundled Script**: [`scripts/publish-to-pypi.sh`](./scripts/publish-to-pypi.sh) - Reference implementation with CI guards

---

## Validation History

- **2025-12-03**: Refactored to discovery-first, environment-agnostic approach
  - `discover_uv()` checks PATH, direct installs, version managers (priority order)
  - Supports: curl install, Homebrew, cargo, mise, asdf - doesn't force any method
- **2025-11-22**: Created with ADR-0027 alignment (workspace-wide local-only policy)
- **Validation**: CI detection guards tested, Doppler integration verified

---

**Last Updated**: 2025-12-03
**Policy**: Workspace-wide local-only PyPI publishing (ADR-0027)
**Supersedes**: None (created with ADR-0027 compliance from start)

## Post-Execution Reflection

After this skill completes, check before closing:

1. **Did the command succeed?** — If not, fix the instruction or error table that caused the failure.
2. **Did parameters or output change?** — If the underlying tool's interface drifted, update Usage examples and Parameters table to match.
3. **Was a workaround needed?** — If you had to improvise (different flags, extra steps), update this SKILL.md so the next invocation doesn't need the same workaround.

Only update if the issue is real and reproducible — not speculative.

Related Skills

doppler-workflows

29
from terrylica/cc-skills

Manage credentials and secrets through Doppler for publishing and deployment workflows. Use whenever the user needs to publish Python packages to PyPI, rotate AWS credentials, manage Doppler secrets, or configure credential pipelines for CI/CD. Do NOT use for 1Password vault operations or for secrets that are not managed through Doppler.

doppler-secret-validation

29
from terrylica/cc-skills

Validate and test Doppler secrets. TRIGGERS - add to Doppler, store secret, validate token, test credentials.

voice-quality-audition

29
from terrylica/cc-skills

Audition Kokoro TTS voices to compare quality and grade. TRIGGERS - audition voices, kokoro voices, voice comparison, tts voice, voice quality, compare voices.

settings-and-tuning

29
from terrylica/cc-skills

Configure TTS voices, speed, timeouts, queue depth, and bot settings. TRIGGERS - configure tts, change voice, tts speed, queue depth, tts timeout, bot config, tune settings, adjust parameters.

full-stack-bootstrap

29
from terrylica/cc-skills

One-time bootstrap for Kokoro TTS engine, Telegram bot, and BotFather setup. TRIGGERS - setup tts, install kokoro, botfather, bootstrap tts-tg-sync, configure telegram bot, full stack setup.

diagnostic-issue-resolver

29
from terrylica/cc-skills

Diagnose and resolve TTS and Telegram bot issues. TRIGGERS - tts not working, bot not responding, kokoro error, audio not playing, lock stuck, telegram bot troubleshoot, diagnose issue.

component-version-upgrade

29
from terrylica/cc-skills

Upgrade Kokoro model, bot dependencies, or TTS components. TRIGGERS - upgrade kokoro, update model, upgrade bot, update dependencies, version bump, component update.

clean-component-removal

29
from terrylica/cc-skills

Remove TTS and Telegram sync components cleanly. TRIGGERS - uninstall tts, remove telegram bot, uninstall kokoro, clean tts, teardown, component removal.

send-message

29
from terrylica/cc-skills

Use when user wants to send a text message on Telegram as their personal account via MTProto, text someone, or message a contact by username, phone, or chat ID.

send-media

29
from terrylica/cc-skills

Use when user wants to send or upload a file, photo, video, voice note, or document on Telegram via their personal account.

search-messages

29
from terrylica/cc-skills

Use when user wants to search for messages across all Telegram chats or within a specific chat, find old messages by text, or look up Telegram message history filtered by sender.

pin-message

29
from terrylica/cc-skills

Use when user wants to pin or unpin a message in a Telegram chat, group, or channel, or manage pinned messages.