Skip to content

Commit 91f739a

Browse files
tbitcsoz-agent
andcommitted
feat: pipx as recommended install method
- README.md: lead install section with pipx; show pipx inject for each provider extra and GUI; pip as secondary option; update instructions (pipx upgrade vs specsmith self-update) - updater.py: add is_pipx_install() detection (checks sys.executable path + PIPX_HOME / PIPX_LOCAL_VENVS env vars); run_self_update() now uses 'pipx upgrade specsmith' when running inside a pipx environment instead of 'pip install --upgrade' - agents.md.j2: add install/update block to Quick Command Reference showing pipx install + inject pattern alongside pip fallback Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent d642532 commit 91f739a

3 files changed

Lines changed: 70 additions & 11 deletions

File tree

README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,30 @@ Every governed project follows: **propose → check → execute → verify → r
7676

7777
## Install
7878

79+
**Recommended — global install via [pipx](https://pipx.pypa.io) (isolated, no dependency conflicts):**
80+
81+
```bash
82+
pipx install specsmith # core CLI + epistemic library
83+
pipx inject specsmith anthropic # + Claude support
84+
pipx inject specsmith openai # + GPT / O-series support
85+
pipx inject specsmith google-generativeai # + Gemini support
86+
pipx inject specsmith PySide6 # + GUI (specsmith gui)
87+
```
88+
89+
**Or with pip (into your active environment):**
90+
91+
```bash
92+
pip install specsmith # core
93+
pip install "specsmith[anthropic]" # + Claude
94+
pip install "specsmith[openai]" # + GPT/O-series
95+
pip install "specsmith[gui]" # + GUI
96+
```
97+
98+
**Update:**
99+
79100
```bash
80-
pip install specsmith # core + epistemic library
81-
pip install specsmith[anthropic] # + Claude support (specsmith run)
82-
pip install specsmith[openai] # + GPT/O-series support
101+
pipx upgrade specsmith # pipx install
102+
specsmith self-update # pip install
83103
```
84104

85105
## Quick Start

src/specsmith/templates/agents.md.j2

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,16 @@ Stop condition (H13): P1 requirement with confidence below MEDIUM = work stops.
215215
| `pr` | `specsmith pr` (create PR with governance) |
216216
| `update` | `specsmith update` (check + install + migrate) |
217217
| `session-end` | `specsmith session-end` (end checklist) |
218+
219+
**specsmith install / update:**
220+
221+
```bash
222+
# Recommended — global isolated install
223+
pipx install specsmith
224+
pipx inject specsmith anthropic openai # add LLM providers
225+
pipx upgrade specsmith # update
226+
227+
# Or with pip
228+
pip install specsmith
229+
specsmith self-update
230+
```

src/specsmith/updater.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,50 @@ def is_outdated() -> bool:
6060
return current != latest
6161

6262

63+
def is_pipx_install() -> bool:
64+
"""Return True if specsmith was installed via pipx.
65+
66+
Checks sys.executable path and PIPX_HOME / PIPX_LOCAL_VENVS env vars.
67+
"""
68+
import os
69+
import sys
70+
71+
exe = sys.executable.replace("\\", "/").lower()
72+
return (
73+
"pipx" in exe
74+
or bool(os.environ.get("PIPX_HOME"))
75+
or bool(os.environ.get("PIPX_LOCAL_VENVS"))
76+
)
77+
78+
6379
def run_self_update(
6480
*,
6581
channel: str = "",
6682
target_version: str = "",
6783
) -> tuple[bool, str]:
68-
"""Update specsmith via pip.
84+
"""Update specsmith.
85+
86+
Detects whether running under pipx and uses the appropriate command:
87+
- pipx: ``pipx upgrade specsmith`` (or ``pipx install specsmith==X.Y.Z``)
88+
- pip: ``pip install --upgrade specsmith``
6989
7090
If target_version is set, installs that exact version.
7191
Otherwise uses --pre flag for dev channel, plain upgrade for stable.
7292
"""
73-
if target_version:
74-
cmd = ["pip", "install", f"specsmith=={target_version}"]
93+
if is_pipx_install():
94+
if target_version:
95+
cmd = ["pipx", "install", f"specsmith=={target_version}", "--force"]
96+
else:
97+
cmd = ["pipx", "upgrade", "specsmith"]
7598
else:
76-
if not channel:
77-
channel = get_update_channel()
78-
cmd = ["pip", "install", "--upgrade", "specsmith"]
79-
if channel == "dev":
80-
cmd.insert(2, "--pre")
99+
if target_version:
100+
cmd = ["pip", "install", f"specsmith=={target_version}"]
101+
else:
102+
if not channel:
103+
channel = get_update_channel()
104+
cmd = ["pip", "install", "--upgrade", "specsmith"]
105+
if channel == "dev":
106+
cmd.insert(2, "--pre")
81107

82108
try:
83109
result = subprocess.run(

0 commit comments

Comments
 (0)