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
75 changes: 75 additions & 0 deletions .github/workflows/cli-cd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: CLI CD

on:
workflow_dispatch:
push:
branches:
- actions/*
- main
paths:
- "cli/**"

permissions:
contents: read

jobs:
linter:
runs-on: ubuntu-latest
defaults:
run:
working-directory: cli

steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python 3.10
run: uv python install 3.10
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Lint with ruff
run: uv run ruff check ./src

pytest:
runs-on: ubuntu-latest
defaults:
run:
working-directory: cli

steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python 3.10
run: uv python install 3.10
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Test with pytest
run: uv run pytest

build-and-publish:
needs: [linter, pytest]
runs-on: ubuntu-latest
defaults:
run:
working-directory: cli
environment: pypi

steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python 3.10
run: uv python install 3.10
- name: Build distribution
run: uv build
- name: Publish to PyPI
run: uv publish
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
81 changes: 81 additions & 0 deletions .github/workflows/cli-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: CLI CI

on:
workflow_dispatch:
push:
branches:
- actions/*
- develop
paths:
- "cli/**"
pull_request:
branches:
- develop
- main
paths:
- "cli/**"

permissions:
contents: read

jobs:
linter:
runs-on: ubuntu-latest
defaults:
run:
working-directory: cli

steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python 3.10
run: uv python install 3.10
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Lint with ruff
run: uv run ruff check ./src

pytest:
runs-on: ubuntu-latest
defaults:
run:
working-directory: cli

steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python 3.10
run: uv python install 3.10
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Test with pytest
run: uv run pytest

build:
needs: [linter, pytest]
runs-on: ubuntu-latest
defaults:
run:
working-directory: cli

steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
- name: Set up Python 3.10
run: uv python install 3.10
- name: Build distribution
run: uv build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: cli/dist/
70 changes: 60 additions & 10 deletions cli/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
**CLAUDE.md is a living document. Update it when the CLI changes in ways that affect how you work here.**

Update when:
- A new command group or handler structure is introduced
- A new command or sub-app is added
- The package structure changes
- A new development command is added or removed
- Packaging or install behavior changes
- A new required environment variable is introduced
Expand All @@ -30,7 +31,7 @@ uv tool install --force .
uv sync

# Show CLI help
make help
uv run python -m applika.main --help

# Run linter with auto-fix
make lint
Expand All @@ -40,6 +41,9 @@ make format

# Run tests
make test

# Build wheel for PyPI
uv build
```

---
Expand All @@ -60,13 +64,59 @@ Do not skip this unless the user explicitly asks you not to run validation or th

---

## Structure
## Package Structure

All source code lives under `src/applika/` (importable as `applika`).

```
src/applika/
├── main.py # Entry point: def main() -> None
├── app.py # Root Typer app + --api-base-url callback → AppConfig
├── config.py # AppConfig dataclass + resolve_api_base_url
├── skills/
│ └── applika-cli/ # Bundled SKILL.md (included in wheel, symlinked/copied by skill install)
├── schemas/
│ ├── enums.py # Enum types: Currency, SalaryPeriod, ExperienceLevel,
│ │ # WorkMode, ApplicationMode, ModeFilter, StatusFilter, OutputFormat, ClearField
│ ├── application.py # Pydantic models: ApplicationCreate, ApplicationUpdate,
│ │ # ApplicationCompany (vendored from backend DTOs)
│ └── supports.py # SupportSchema — platforms and companies from /supports
├── lib/
│ ├── api.py # ApiClient (httpx + cookie auth), ApiError, AuthError,
│ │ # require_session, create_session_from_exchange
│ ├── session.py # SessionData, SessionStore (~/.config/applika/session.json)
│ └── loopback.py # LoopbackLoginServer for OAuth callback
├── utils/
│ └── output.py # render_application_table, print_application_summary
└── commands/
├── auth.py # login + logout + whoami Typer commands
├── skill.py # skill install Typer sub-app
└── applications/
├── __init__.py # applications_app Typer sub-app with default-to-list callback
├── commands.py # list_applications, new_application, edit_application
├── filter.py # filter_applications
└── api_resolve.py # resolve_platform_id, resolve_company_input
```

## Key Patterns

- **Global state**: `AppConfig` (dataclass with `api_base_url` + `store`) lives on `ctx.obj`, set by the root `@app.callback()` in `app.py`.
- **Auth required**: Commands call `require_session(config.store)` → raises `AuthError` if no session.
- **Payload validation**: `ApplicationCreate`/`ApplicationUpdate` Pydantic models validate inputs before API calls in `new_application` and `edit_application`.
- **Schemas are vendored**: `schemas/enums.py` and `schemas/application.py` are standalone copies (no backend import). Keep in sync with `backend/app/core/enums.py` and `backend/app/application/dto/application.py` when the backend changes.

## CLI Commands

| Command | Description |
|---|---|
| `applika login` | GitHub OAuth login (opens browser) |
| `applika logout` | Log out and clear session |
| `applika whoami` | Show the currently authenticated user |
| `applika applications list` | List applications (filterable) |
| `applika applications new` | Create a new application |
| `applika applications edit <id>` | Edit an existing application |
| `applika skill install` | Install the AI skill (symlink/copy) for Claude, Gemini, or Codex |

- `src/main.py` keeps the entrypoint small
- `src/cli_parser.py` owns argparse setup
- `src/auth_commands.py` owns login/logout flows
- `src/applications/` owns application-specific command logic
- `src/session.py` owns local session persistence
- `src/api.py` owns HTTP client behavior
## Environment Variables

Keep new feature-specific logic grouped by feature instead of expanding `main.py`.
- `APPLIKA_API_BASE_URL`: Override the default API URL (`https://applika.dev/api`)
21 changes: 0 additions & 21 deletions cli/Makefile
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
install:
uv tool install --force .

install-dev:
uv sync

install-linux:
$(MAKE) install

install-macos:
$(MAKE) install

install-windows:
$(MAKE) install

test:
uv run --no-sync pytest tests -q

Expand All @@ -21,9 +6,3 @@ lint:

format:
uv run --no-sync ruff format .

help:
uv run --no-sync applika --help

uninstall:
uv tool uninstall applika-cli
Loading
Loading