Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ Thumbs.db

# Superpowers specs and plans (local design docs, not shipped)
docs/superpowers/

# Local agent evidence and workflow state
.omo/
18 changes: 11 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Repository Guidelines

Potaco is a Go CLI for image generation and editing via multi-provider adapters (OpenAI, fal, Vercel AI Gateway, and custom OpenAI-compatible endpoints) with encrypted credential storage and interactive TUI flows.
Potaco is a Go CLI for image generation and editing via multi-provider adapters (OpenAI, fal, Replicate, and custom OpenAI-compatible endpoints) with encrypted credential storage and interactive TUI flows.

## Project Structure

Expand All @@ -10,16 +10,17 @@ models` or `potaco config set model <model>`. Generation is assumed available fo
the selected model. Edit capability is user-configured per model with
`potaco config set model.edit true` or
`potaco config set providers.<name>.models.<model>.edit true`; do not infer it
from provider discovery. The `custom` provider has no preset and requires a
user-supplied base URL.
from provider discovery. Generation/edit parameters are user-configured per model with `potaco config set model.parameters.<name> <value>` or `potaco config set providers.<name>.models.<model>.parameters.<name> <value>`.
Generation/edit may fall back across configured providers with the same or similar model ID only when provider/API key/base URL are not explicitly overridden by flags or environment.
The `custom` provider has no preset and requires a user-supplied base URL.

Layered monolith dependency graph:

```
cli --> adapter, auth, config, credential, tui, image
tui --> adapter, auth
auth --> config, credential
adapter/openai|fal|vercel|custom --> adapter (parent), config
adapter/openai|fal|replicate|custom --> adapter (parent), config
config, credential, image --> (no internal deps)
```

Expand Down Expand Up @@ -68,21 +69,23 @@ Config file lives at `~/.potaco/config.yaml`. Update check cache lives at `~/.po
POTACO_BASE_URL=https://api.openai.com POTACO_API_KEY=sk-test \
./potaco gen --prompt "a cat" --dry-run
```
`potaco config show` prints the raw `config.yaml` contents without formatting or migration.

Provider credentials are managed via `auth add`:
```
./potaco auth add openai --api-key sk-... # Connect a provider
./potaco auth list # List connected providers
./potaco use openai # Switch active provider
./potaco models # Discover available models (interactive)
./potaco models # Discover available models (interactive, includes Custom)
./potaco status # Show current provider/model status
./potaco stats --non-interactive # Show local command analytics
```

## Coding Style & Naming Conventions

- Go 1.26, pure Go only (no CGO).
- Standard `gofmt` formatting. Run `gofmt -l .` before committing; fix any flagged files.
- Key dependencies: `spf13/cobra` (CLI), `charmbracelet/huh` (TUI forms), `charm.land/lipgloss/v2` (styling), `golang.org/x/image` (WebP decode), `golang.org/x/term` (TTY detection), `gopkg.in/yaml.v3` (config).
- Key dependencies: `spf13/cobra` (CLI), `github.com/charmbracelet/bubbletea` (hand-crafted TUI programs), `charm.land/lipgloss/v2` (styling), `golang.org/x/image` (WebP decode), `golang.org/x/term` (TTY detection), `gopkg.in/yaml.v3` (config).
- Internal image package is imported as `img` in CLI files to avoid collision with stdlib `image`.
- No panics in library code. Use `fmt.Errorf` with `%w` for error wrapping.
- Keep files focused: one responsibility per file, one subcommand per file in `cli/`.
Expand All @@ -98,7 +101,7 @@ Provider credentials are managed via `auth add`:
- Adapter tests use `httptest.Server` mocks and override `Adapter.backoff` and `Adapter.sleep` (via `SetBackoff`/`SetSleep`) to 1ms for fast retry tests.
- Credential tests verify encrypt/decrypt roundtrips with test keys and temp directories.
- Image tests use `t.TempDir()` for temp files and `bytes.Buffer` for in-memory roundtrips.
- TUI tests are minimal (smoke tests) since interactive forms require a TTY.
- TUI tests are minimal (smoke tests) since interactive prompts require a TTY.

## Commit & Pull Request Guidelines

Expand Down Expand Up @@ -137,6 +140,7 @@ Subject line is lowercase, no period. Use `feat(scope):` for new features, `fix(
### Input Validation

- Normalize user-supplied URLs (trim trailing slashes) before joining with path segments to avoid double-slash endpoints.
- Validate provider base URLs before model discovery or verification. Unencrypted `http://` base URLs require an explicit interactive trust confirmation; non-interactive commands should reject them.
- Validate file size and dimensions before decoding user-supplied image files to prevent OOM. Use shared budget checks (`maxImageFileBytes`, `validateImageDimensionsFromBytes`) for every image input path.
- Do not write multiple binary blobs to stdout in sequence. Reject combinations of flags that would produce undecodable output early with a `UserError`.
- When an interactive picker returns a zero-value result on cancel, the caller must check for it and return early. Do not let a cancelled selection flow through to downstream operations.
Expand Down
12 changes: 8 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,20 @@ Provider credentials are managed via `auth add`:

```sh
./potaco auth add openai --api-key sk-... # Connect a provider
./potaco auth add replicate --api-key r8_... # Connect Replicate
./potaco auth add custom --api-key sk-... --base-url https://api.example.com/v1 # Connect custom endpoint
./potaco auth add openrouter --type openai-compatible --api-key sk-... --base-url https://openrouter.ai/api/v1 # Connect named custom endpoint
./potaco auth add openrouter --type openai --api-key sk-... --base-url https://openrouter.ai/api/v1 # Connect named OpenAI-style endpoint
./potaco auth list # List connected providers
./potaco use openai # Switch active provider
./potaco models # Pick a model interactively
./potaco models list # List available models without changing selection
./potaco models # Pick a model interactively, including Custom
./potaco models list # List available models by display name
./potaco status # Show current provider/model status
./potaco stats --non-interactive # Show local command analytics
./potaco config set model gpt-image-2 # Set active provider model
./potaco config set model.edit true # Mark active provider model edit capable
./potaco config set model.parameters.size 1536x1024 # Set active model size
./potaco config set auto_update false # Disable automatic update prompts
./potaco config show # Print raw config.yaml
```

## Coding Style
Expand Down Expand Up @@ -118,7 +122,7 @@ The following checks run on every PR:
- Adapter tests use `httptest.Server` mocks and override `Adapter.backoff` and `Adapter.sleep` (via `SetBackoff`/`SetSleep`) to 1ms for fast retry tests
- Credential tests verify encrypt/decrypt roundtrips with test keys and temp directories
- Image tests use `t.TempDir()` for temp files and `bytes.Buffer` for in-memory roundtrips
- TUI tests are minimal (smoke tests) since interactive forms require a TTY
- TUI tests are minimal (smoke tests) since interactive prompts require a TTY
- Use `--dry-run` for local testing without a real provider

## Releasing (Maintainers)
Expand Down
54 changes: 54 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Potaco Design System

## 1. Atmosphere & Identity

Potaco feels like a compact creative console: direct, precise, and image-native without becoming flashy. The signature is a quiet terminal surface with clear replacement prompts, muted helper explanations, and decisive success or failure messages.

## 2. Color

| Role | Token | Terminal | Usage |
|------|-------|----------|-------|
| Surface/primary | `potaco-surface` | terminal default | Terminal background |
| Text/primary | `potaco-text` | terminal default | Titles, body text, options, keystrokes, entered values |
| Text/secondary | `potaco-muted` | ANSI 240 | Helper action explanations, placeholders, and captions |
| Status/success | `potaco-success` | ANSI 42 | Completed action messages only |
| Status/error | `potaco-error` | ANSI 203 | Failed, empty, destructive, and cancelled states |

## 3. Typography

Terminal typography uses the user's monospace font. Prompt titles are bold, options and helper keystrokes are regular white/default text, and helper action explanations are muted. No negative tracking or decorative glyphs.

## 4. Spacing & Layout

TUI flows follow the compact redraw pattern used by Vercel's `skills` CLI: one active prompt surface, stable row replacement, explicit completion/cancel states, and no scrollback pile-up while a multi-step flow is running. All prompts use one leading blank line, single-line titles aligned to the option/input text column, one blank line before controls, and one blank line before help. Prompt steps render in the alternate screen so completing one step replaces it with the next instead of appending below it. Lists use a two-cell cursor gutter with a Nerd Font chevron so selected and unselected rows never shift. Layout decisions must use display-cell width, not byte count, because ANSI styling and Nerd Font glyphs should not move columns.

## 5. Components

### Prompt Select
- **Structure**: title, option list, help row.
- **Variants**: standard provider/model selection and destructive provider removal selection.
- **States**: default option, focused option, empty option list, cancelled.
- **Accessibility**: arrow keys and vim-style `ctrl+n`/`ctrl+p`; `esc` and `ctrl+c` cancel.
- **Motion**: none.

### Prompt Input
- **Structure**: title, input line, help row.
- **Variants**: plain text and password mask.
- **States**: empty, filled, submitted, cancelled.
- **Accessibility**: keyboard-only; typed CJK text is preserved as runes.
- **Motion**: none.

### Prompt Confirm
- **Structure**: inline title plus `[Y/n]` typed answer input, help row.
- **Variants**: neutral and destructive copy.
- **States**: empty default yes, typed yes, typed no, submitted, cancelled.
- **Accessibility**: `y`, `n`, backspace, enter, `esc`, and `ctrl+c`.
- **Motion**: none.

## 6. Motion & Interaction

Terminal prompts do not animate. State changes are immediate and visible through replacement, bold titles, cursor position, and status lines.

## 7. Depth & Surface

Depth strategy is tonal-shift only. The TUI uses text hierarchy and muted captions instead of boxes, shadows, accent-heavy styling, or decorative borders.
Loading
Loading