Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9d7dde6
chore(launcher): release v0.5.1
thestumonkey Jan 11, 2026
ccd165b
added tmux
thestumonkey Jan 13, 2026
b02b4a1
Tmux windows and add from branch
thestumonkey Jan 17, 2026
f33e12c
Merge branch 'main' into tmux
thestumonkey Jan 17, 2026
b9cabc0
Merge tmux branch: Add tmux integration and launcher improvements
thestumonkey Jan 17, 2026
6be7c7f
Perfect! Now let me show you what we've built with a visual summary:
thestumonkey Jan 18, 2026
d828a1a
★ Insight ─────────────────────────────────────
thestumonkey Jan 18, 2026
b38f3d3
★ Insight ─────────────────────────────────────
thestumonkey Jan 18, 2026
51fc1d5
Done! Now the structure is:
thestumonkey Jan 18, 2026
958191d
Now regenerate the lockfile:
thestumonkey Jan 18, 2026
67ba66c
All fixed! Here's the summary:
thestumonkey Jan 18, 2026
6c67512
All tasks are complete. Here's a summary of what was accomplished:
thestumonkey Jan 19, 2026
b412e9c
Done! Here's what was implemented:
thestumonkey Jan 19, 2026
9bcac1a
Fixed. I added `rich>=13.0.0` to `pyproject.toml` so it will be insta…
thestumonkey Jan 19, 2026
d9b73a7
You can install the dependencies a few ways:
thestumonkey Jan 19, 2026
f423df3
★ Insight ─────────────────────────────────────
thestumonkey Jan 20, 2026
36fb0eb
★ Insight ─────────────────────────────────────
thestumonkey Jan 20, 2026
dc3c7f5
★ Insight ─────────────────────────────────────
thestumonkey Jan 20, 2026
33ce4da
Done! Here's the summary:
thestumonkey Jan 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .workmux.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Workmux Configuration for Ushadow Project
# This config optimizes git worktree + tmux workflow for parallel environment development

# Main branch to merge into (auto-detected from git, but can override)
main_branch: "main"

# Where worktrees are created (relative to project root or absolute path)
# Using parent directory pattern for cleaner organization
worktree_dir: "../"

# Prefix for tmux window names (helps identify workmux windows)
window_prefix: "ushadow-"

# Default merge strategy: merge | rebase | squash
# Rebase recommended for cleaner history
merge_strategy: "rebase"

# How to name worktree directories: full (branch name) | basename (last component)
worktree_naming: "full"

# Commands to run after worktree creation (before tmux window opens)
post_create:
# Setup VSCode colors for environment identification
- "uv run --with pyyaml python3 -c \"from setup.vscode_utils.colors import setup_colors_for_directory; from pathlib import Path; setup_colors_for_directory(Path('.'), '$(basename $(pwd))')\" || true"
# Generate secrets if needed
- "bash scripts/generate-secrets.sh || true"

# Commands to run before merging (aborts merge if any fail)
pre_merge:
# Ensure tests pass before merging
# - "make test" # Uncomment when test suite is ready

# Commands to run before removing worktree
pre_remove:
# Stop any running containers for this environment
- "ENV_NAME=$(basename $(pwd)) bash scripts/stop-env.sh || true"

# File operations (applied after worktree creation)
files:
# Copy these files/patterns to each worktree (separate configs per env)
copy:
- ".env" # Each environment gets its own .env with unique ports
- ".vscode/settings.json" # VSCode colors set per environment

# Symlink these files/patterns (shared across worktrees)
symlink:
- "node_modules" # Share node_modules to save disk space
- ".venv" # Share Python virtual environment
- "ushadow/frontend/node_modules" # Share frontend deps

# Tmux pane layout (how the window is organized)
panes:
# Main pane - ready for commands or agent interaction
- command: "echo '🚀 Ushadow Environment: $(basename $(pwd))' && echo '' && echo 'Quick commands:' && echo ' ./dev.sh - Start in dev mode' && echo ' ./go.sh - Start in prod mode' && echo ' make test - Run tests' && echo ' code . - Open in VSCode' && echo '' && $SHELL"
focus: true
split: horizontal
size: 75%

# Agent status icons (shown in tmux status bar)
status_icons:
working: '🤖' # Agent actively processing
waiting: '💬' # Agent waiting for input
done: '✅' # Agent task completed
error: '❌' # Agent encountered error

# Auto-format tmux status line to show agent status
status_format: true

# LLM-based branch name generation (when using --auto-name flag)
auto_name:
# Use fast, cheap model for branch name generation
model: 'gemini-2.0-flash-lite'
system_prompt: |
Generate a short, descriptive git branch name (2-4 words, kebab-case).
Focus on the feature/fix being worked on.
Examples: "fix-auth-bug", "add-tailscale-wizard", "refactor-docker-setup"
285 changes: 285 additions & 0 deletions docs/CLI-TOOL-GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
# ushadow CLI Tool Guide

## Overview

The `ush` CLI tool provides command-line access to the ushadow API. It's built on an **auto-generated client** from the OpenAPI specification, ensuring it stays perfectly in sync with your backend.

## Quick Start

```bash
# Check backend health
./scripts/ush health

# List all services
./scripts/ush services list

# Start a service
./scripts/ush services start chronicle-backend

# Stop a service
./scripts/ush services stop chronicle-backend

# Get service status
./scripts/ush services status chronicle-backend

# Raw API access
./scripts/ush api GET /api/services/
```

## Architecture

```
┌─────────────────────────────────────────┐
│ FastAPI Backend (main.py) │
│ - Auto-generates /openapi.json │
└─────────────────┬───────────────────────┘
┌─────────────────────────────────────────┐
│ scripts/generate_openapi_spec.py │
│ - Downloads OpenAPI spec │
└─────────────────┬───────────────────────┘
┌─────────────────────────────────────────┐
│ openapi-python-client │
│ - Generates clients/python/ │
│ - Type-safe API methods │
└─────────────────┬───────────────────────┘
┌─────────────────────────────────────────┐
│ clients/python/ushadow_auth_client.py │
│ - Handles authentication │
│ - Wraps generated client │
└─────────────────┬───────────────────────┘
┌─────────────────────────────────────────┐
│ scripts/ush (typer + rich) │
│ - Beautiful CLI interface │
│ - Uses authenticated client │
└─────────────────────────────────────────┘
```

## Benefits Over Manual Client

### Old Approach (scripts/ushadow_client.py)
- ❌ Manually maintain endpoint URLs
- ❌ No type checking
- ❌ No IDE autocomplete
- ❌ Breaks when API changes
- ❌ Limited to endpoints you manually add

### New Approach (scripts/ush)
- ✅ Auto-generated from OpenAPI spec
- ✅ Full type safety with Pydantic models
- ✅ IDE autocomplete everywhere
- ✅ Regenerate when API changes
- ✅ 100% API coverage automatically

## Usage Examples

### Basic Commands

```bash
# Health check (no auth required)
./scripts/ush health

# List services (no auth required)
./scripts/ush services list
```

### Service Management (requires auth)

```bash
# Start a service
./scripts/ush services start chronicle-backend

# Stop a service
./scripts/ush services stop chronicle-backend

# Check service status
./scripts/ush services status chronicle-backend
```

### Verbose Mode

```bash
# See detailed output including login process
./scripts/ush -v services start chronicle-backend
```

### Raw API Access

```bash
# GET request
./scripts/ush api GET /api/services/

# POST request with JSON data
./scripts/ush api POST /api/services/test/start -d '{"detach": true}'

# Skip authentication
./scripts/ush api GET /health --no-auth
```

## Configuration

The CLI automatically loads credentials from:

1. `config/SECRETS/secrets.yaml` (preferred)
```yaml
admin:
email: admin@example.com
password: your-password
```

2. `.env` file (fallback)
```bash
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your-password
BACKEND_PORT=8000
```

3. Environment variables
```bash
export USHADOW_TOKEN=your-jwt-token # Pre-authenticated
export ADMIN_EMAIL=admin@example.com
export ADMIN_PASSWORD=your-password
```

## Regenerating the Client

When your FastAPI backend changes:

```bash
# 1. Ensure backend is running
cd ushadow && make up

# 2. Generate fresh OpenAPI spec
python scripts/generate_openapi_spec.py

# 3. Regenerate Python client
openapi-python-client generate \
--path openapi.json \
--output-path clients/python \
--overwrite

# 4. Test the CLI
./scripts/ush services list
```

**Recommended:** Add this to your CI/CD pipeline to keep the client in sync.

## Using in Python Scripts

The generated client can be used directly in your Python scripts:

```python
from clients.python.ushadow_auth_client import UshadowAuthClient

# Auto-login with env credentials
client = UshadowAuthClient.from_env()

# List services
services = client.list_services()
for svc in services:
print(f"{svc.service_name}: {svc.status}")

# Start a service
result = client.start_service("chronicle-backend")
if result["success"]:
print("Service started!")
```

## For LLM/AI Testing

The typed client is perfect for LLM-driven testing:

```python
# Full type hints help LLMs understand the API
from ushadow_api_client.models import Service

def test_service_health(client: UshadowAuthClient) -> None:
"""LLM can see Service schema and write correct tests"""
services: list[Service] = client.list_services()

for svc in services:
assert svc.status in ["running", "stopped", "exited"]
if svc.status == "running":
assert svc.health in ["healthy", "unhealthy"]
```

## Comparison Table

| Feature | Manual Client | Auto-Generated Client |
|---------|--------------|----------------------|
| **Endpoint Coverage** | Partial (what you wrote) | 100% automatic |
| **Type Safety** | None | Full Pydantic models |
| **IDE Autocomplete** | No | Yes |
| **Maintenance** | Manual updates | Regenerate command |
| **API Sync** | Can drift | Always in sync |
| **Testing** | Manual mocking | Type-safe mocking |
| **Documentation** | In code | From OpenAPI |
| **LLM-Friendly** | Medium | Excellent |

## Menu System (Future)

For interactive mode, we can add `questionary`:

```python
import questionary

choice = questionary.select(
"What would you like to do?",
choices=[
"List Services",
"Start Service",
"Stop Service",
"View Logs",
"Exit"
]
).ask()
```

This would provide a menu-driven interface for users who prefer interactive mode.

## Troubleshooting

### Authentication Errors
```bash
# Enable verbose mode to see login details
./scripts/ush -v services list

# Check credentials are configured
cat config/SECRETS/secrets.yaml
cat .env | grep ADMIN
```

### Client Out of Sync
```bash
# Regenerate from running server
python scripts/generate_openapi_spec.py
openapi-python-client generate --path openapi.json --output-path clients/python --overwrite
```

### Import Errors
```bash
# Ensure dependencies are installed
pip install httpx attrs typer rich
```

## Next Steps

1. **Add more commands** - The CLI is easily extensible with new typer commands
2. **Interactive menu** - Add `questionary` for menu-driven interface
3. **CI/CD integration** - Auto-regenerate client on API changes
4. **Shell completion** - Add bash/zsh completion support
5. **Config file** - Support `~/.ushrc` for user preferences

## References

- [OpenAPI Python Client](https://github.com/openapi-generators/openapi-python-client)
- [Typer CLI Framework](https://typer.tiangolo.com/)
- [Rich Terminal Formatting](https://rich.readthedocs.io/)
- [FastAPI OpenAPI](https://fastapi.tiangolo.com/advanced/extending-openapi/)
1 change: 1 addition & 0 deletions openapi.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading