applika-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- applika_cli-0.1.0/.gitignore +170 -0
- applika_cli-0.1.0/AGENTS.md +1 -0
- applika_cli-0.1.0/CLAUDE.md +123 -0
- applika_cli-0.1.0/Makefile +29 -0
- applika_cli-0.1.0/PKG-INFO +340 -0
- applika_cli-0.1.0/README.md +320 -0
- applika_cli-0.1.0/pyproject.toml +54 -0
- applika_cli-0.1.0/src/applika/__init__.py +0 -0
- applika_cli-0.1.0/src/applika/app.py +57 -0
- applika_cli-0.1.0/src/applika/commands/__init__.py +0 -0
- applika_cli-0.1.0/src/applika/commands/applications/__init__.py +25 -0
- applika_cli-0.1.0/src/applika/commands/applications/commands.py +405 -0
- applika_cli-0.1.0/src/applika/commands/applications/filter.py +73 -0
- applika_cli-0.1.0/src/applika/commands/applications/payloads.py +213 -0
- applika_cli-0.1.0/src/applika/commands/auth.py +93 -0
- applika_cli-0.1.0/src/applika/commands/skill.py +149 -0
- applika_cli-0.1.0/src/applika/config.py +27 -0
- applika_cli-0.1.0/src/applika/lib/__init__.py +0 -0
- applika_cli-0.1.0/src/applika/lib/api.py +168 -0
- applika_cli-0.1.0/src/applika/lib/loopback.py +85 -0
- applika_cli-0.1.0/src/applika/lib/session.py +59 -0
- applika_cli-0.1.0/src/applika/main.py +5 -0
- applika_cli-0.1.0/src/applika/schemas/__init__.py +0 -0
- applika_cli-0.1.0/src/applika/schemas/application.py +74 -0
- applika_cli-0.1.0/src/applika/schemas/enums.py +58 -0
- applika_cli-0.1.0/src/applika/skills/applika-cli/SKILL.md +243 -0
- applika_cli-0.1.0/src/applika/utils/__init__.py +0 -0
- applika_cli-0.1.0/src/applika/utils/dates.py +10 -0
- applika_cli-0.1.0/src/applika/utils/output.py +54 -0
- applika_cli-0.1.0/tests/conftest.py +89 -0
- applika_cli-0.1.0/tests/test_api.py +69 -0
- applika_cli-0.1.0/tests/test_commands.py +454 -0
- applika_cli-0.1.0/tests/test_session.py +28 -0
- applika_cli-0.1.0/uv.lock +385 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib64/
|
|
18
|
+
parts/
|
|
19
|
+
sdist/
|
|
20
|
+
var/
|
|
21
|
+
wheels/
|
|
22
|
+
share/python-wheels/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
MANIFEST
|
|
27
|
+
|
|
28
|
+
# PyInstaller
|
|
29
|
+
# Usually these files are written by a python script from a template
|
|
30
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
31
|
+
*.manifest
|
|
32
|
+
*.spec
|
|
33
|
+
|
|
34
|
+
# Installer logs
|
|
35
|
+
pip-log.txt
|
|
36
|
+
pip-delete-this-directory.txt
|
|
37
|
+
|
|
38
|
+
# Unit test / coverage reports
|
|
39
|
+
htmlcov/
|
|
40
|
+
.tox/
|
|
41
|
+
.nox/
|
|
42
|
+
.coverage
|
|
43
|
+
.coverage.*
|
|
44
|
+
.cache
|
|
45
|
+
nosetests.xml
|
|
46
|
+
coverage.xml
|
|
47
|
+
*.cover
|
|
48
|
+
*.py,cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
.pytest_cache/
|
|
51
|
+
cover/
|
|
52
|
+
|
|
53
|
+
# Translations
|
|
54
|
+
*.mo
|
|
55
|
+
*.pot
|
|
56
|
+
|
|
57
|
+
# Django stuff:
|
|
58
|
+
*.log
|
|
59
|
+
local_settings.py
|
|
60
|
+
db.sqlite3
|
|
61
|
+
db.sqlite3-journal
|
|
62
|
+
|
|
63
|
+
# Flask stuff:
|
|
64
|
+
instance/
|
|
65
|
+
.webassets-cache
|
|
66
|
+
|
|
67
|
+
# vscode
|
|
68
|
+
settings.json
|
|
69
|
+
.vscode/
|
|
70
|
+
|
|
71
|
+
# Scrapy stuff:
|
|
72
|
+
.scrapy
|
|
73
|
+
|
|
74
|
+
# Sphinx documentation
|
|
75
|
+
docs/_build/
|
|
76
|
+
|
|
77
|
+
# PyBuilder
|
|
78
|
+
.pybuilder/
|
|
79
|
+
target/
|
|
80
|
+
|
|
81
|
+
# Jupyter Notebook
|
|
82
|
+
.ipynb_checkpoints
|
|
83
|
+
|
|
84
|
+
# IPython
|
|
85
|
+
profile_default/
|
|
86
|
+
ipython_config.py
|
|
87
|
+
/documents
|
|
88
|
+
|
|
89
|
+
# pyenv
|
|
90
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
91
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
92
|
+
# .python-version
|
|
93
|
+
|
|
94
|
+
# pipenv
|
|
95
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
96
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
97
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
98
|
+
# install all needed dependencies.
|
|
99
|
+
#Pipfile.lock
|
|
100
|
+
|
|
101
|
+
# poetry
|
|
102
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
103
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
104
|
+
# commonly ignored for libraries.
|
|
105
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
106
|
+
#poetry.lock
|
|
107
|
+
|
|
108
|
+
# pdm
|
|
109
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
110
|
+
#pdm.lock
|
|
111
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
112
|
+
# in version control.
|
|
113
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
114
|
+
.pdm.toml
|
|
115
|
+
|
|
116
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
117
|
+
__pypackages__/
|
|
118
|
+
|
|
119
|
+
# Celery stuff
|
|
120
|
+
celerybeat-schedule
|
|
121
|
+
celerybeat.pid
|
|
122
|
+
|
|
123
|
+
# SageMath parsed files
|
|
124
|
+
*.sage.py
|
|
125
|
+
|
|
126
|
+
# Environments
|
|
127
|
+
.env
|
|
128
|
+
.venv
|
|
129
|
+
env/
|
|
130
|
+
venv/
|
|
131
|
+
ENV/
|
|
132
|
+
env.bak/
|
|
133
|
+
venv.bak/
|
|
134
|
+
.claude/settings.local.json
|
|
135
|
+
|
|
136
|
+
# Spyder project settings
|
|
137
|
+
.spyderproject
|
|
138
|
+
.spyproject
|
|
139
|
+
|
|
140
|
+
# Rope project settings
|
|
141
|
+
.ropeproject
|
|
142
|
+
|
|
143
|
+
# mkdocs documentation
|
|
144
|
+
/site
|
|
145
|
+
|
|
146
|
+
# mypy
|
|
147
|
+
.mypy_cache/
|
|
148
|
+
.dmypy.json
|
|
149
|
+
dmypy.json
|
|
150
|
+
|
|
151
|
+
# Pyre type checker
|
|
152
|
+
.pyre/
|
|
153
|
+
|
|
154
|
+
# pytype static type analyzer
|
|
155
|
+
.pytype/
|
|
156
|
+
|
|
157
|
+
# Cython debug symbols
|
|
158
|
+
cython_debug/
|
|
159
|
+
|
|
160
|
+
# PyCharm
|
|
161
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
162
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
163
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
164
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
165
|
+
#.idea/
|
|
166
|
+
*.db
|
|
167
|
+
|
|
168
|
+
fake_ledger_db.json
|
|
169
|
+
*.pem
|
|
170
|
+
logs/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CLAUDE.md
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this CLI.
|
|
4
|
+
|
|
5
|
+
## Keeping This File Up to Date
|
|
6
|
+
|
|
7
|
+
**CLAUDE.md is a living document. Update it when the CLI changes in ways that affect how you work here.**
|
|
8
|
+
|
|
9
|
+
Update when:
|
|
10
|
+
- A new command or sub-app is added
|
|
11
|
+
- The package structure changes
|
|
12
|
+
- A new development command is added or removed
|
|
13
|
+
- Packaging or install behavior changes
|
|
14
|
+
- A new required environment variable is introduced
|
|
15
|
+
- Validation, formatting, or test workflow changes
|
|
16
|
+
|
|
17
|
+
Do NOT add:
|
|
18
|
+
- Implementation details already visible in the code
|
|
19
|
+
- Ephemeral task notes or in-progress work
|
|
20
|
+
- Anything already obvious from the command help or tests
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Install the CLI globally from the local checkout
|
|
28
|
+
uv tool install --force .
|
|
29
|
+
|
|
30
|
+
# Install dev dependencies
|
|
31
|
+
uv sync
|
|
32
|
+
|
|
33
|
+
# Show CLI help
|
|
34
|
+
uv run python -m applika.main --help
|
|
35
|
+
|
|
36
|
+
# Run linter with auto-fix
|
|
37
|
+
make lint
|
|
38
|
+
|
|
39
|
+
# Run formatter
|
|
40
|
+
make format
|
|
41
|
+
|
|
42
|
+
# Run tests
|
|
43
|
+
make test
|
|
44
|
+
|
|
45
|
+
# Build wheel for PyPI
|
|
46
|
+
uv build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## End-of-Task Validation
|
|
52
|
+
|
|
53
|
+
**Always finish a CLI task by running formatting, linting, and tests.**
|
|
54
|
+
|
|
55
|
+
Run these at the end of any CLI code change:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
make format
|
|
59
|
+
make lint
|
|
60
|
+
make test
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Do not skip this unless the user explicitly asks you not to run validation or the environment prevents it.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Package Structure
|
|
68
|
+
|
|
69
|
+
All source code lives under `src/applika/` (importable as `applika`).
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
src/applika/
|
|
73
|
+
├── main.py # Entry point: def main() -> None
|
|
74
|
+
├── app.py # Root Typer app + --api-base-url callback → AppConfig
|
|
75
|
+
├── config.py # AppConfig dataclass + resolve_api_base_url
|
|
76
|
+
├── skills/
|
|
77
|
+
│ └── applika-cli/ # Bundled SKILL.md (included in wheel, symlinked/copied by skill install)
|
|
78
|
+
├── schemas/
|
|
79
|
+
│ ├── enums.py # StrEnum types: Currency, SalaryPeriod, ExperienceLevel,
|
|
80
|
+
│ │ # WorkMode, ApplicationMode, ModeFilter, StatusFilter, OutputFormat
|
|
81
|
+
│ └── application.py # Pydantic models: ApplicationCreate, ApplicationUpdate,
|
|
82
|
+
│ # ApplicationCompanyInput (vendored from backend DTOs)
|
|
83
|
+
├── lib/
|
|
84
|
+
│ ├── api.py # ApiClient (httpx + cookie auth), ApiError, AuthError,
|
|
85
|
+
│ │ # require_session, create_session_from_exchange
|
|
86
|
+
│ ├── session.py # SessionData, SessionStore (~/.config/applika/session.json)
|
|
87
|
+
│ └── loopback.py # LoopbackLoginServer for OAuth callback
|
|
88
|
+
├── utils/
|
|
89
|
+
│ ├── dates.py # parse_date, ensure_date_string
|
|
90
|
+
│ └── output.py # render_application_table, print_application_summary
|
|
91
|
+
└── commands/
|
|
92
|
+
├── auth.py # login + logout + whoami Typer commands
|
|
93
|
+
├── skill.py # skill install Typer sub-app
|
|
94
|
+
└── applications/
|
|
95
|
+
├── __init__.py # applications_app Typer sub-app with default-to-list callback
|
|
96
|
+
├── commands.py # list_applications, new_application, edit_application
|
|
97
|
+
├── filter.py # filter_applications, resolve_platform_id
|
|
98
|
+
└── payloads.py # ApplicationArgs dataclass + build_application_payload
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Key Patterns
|
|
102
|
+
|
|
103
|
+
- **Global state**: `AppConfig` (dataclass with `api_base_url` + `store`) lives on `ctx.obj`, set by the root `@app.callback()` in `app.py`.
|
|
104
|
+
- **Auth required**: Commands call `require_session(config.store)` → raises `AuthError` if no session.
|
|
105
|
+
- **Payload validation**: `ApplicationCreate`/`ApplicationUpdate` Pydantic models validate inputs before API calls in `new_application` and `edit_application`.
|
|
106
|
+
- **ApplicationArgs**: Thin dataclass passed to `build_application_payload()` — decouples Typer command signatures from payload construction logic.
|
|
107
|
+
- **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.
|
|
108
|
+
|
|
109
|
+
## CLI Commands
|
|
110
|
+
|
|
111
|
+
| Command | Description |
|
|
112
|
+
|---|---|
|
|
113
|
+
| `applika login` | GitHub OAuth login (opens browser) |
|
|
114
|
+
| `applika logout` | Log out and clear session |
|
|
115
|
+
| `applika whoami` | Show the currently authenticated user |
|
|
116
|
+
| `applika applications list` | List applications (filterable) |
|
|
117
|
+
| `applika applications new` | Create a new application |
|
|
118
|
+
| `applika applications edit <id>` | Edit an existing application |
|
|
119
|
+
| `applika skill install` | Install the AI skill (symlink/copy) for Claude, Gemini, or Codex |
|
|
120
|
+
|
|
121
|
+
## Environment Variables
|
|
122
|
+
|
|
123
|
+
- `APPLIKA_API_BASE_URL`: Override the default API URL (`https://applika.dev/api`)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
install:
|
|
2
|
+
uv tool install --force .
|
|
3
|
+
|
|
4
|
+
install-dev:
|
|
5
|
+
uv sync
|
|
6
|
+
|
|
7
|
+
install-linux:
|
|
8
|
+
$(MAKE) install
|
|
9
|
+
|
|
10
|
+
install-macos:
|
|
11
|
+
$(MAKE) install
|
|
12
|
+
|
|
13
|
+
install-windows:
|
|
14
|
+
$(MAKE) install
|
|
15
|
+
|
|
16
|
+
test:
|
|
17
|
+
uv run --no-sync pytest tests -q
|
|
18
|
+
|
|
19
|
+
lint:
|
|
20
|
+
uv run --no-sync ruff check . --fix
|
|
21
|
+
|
|
22
|
+
format:
|
|
23
|
+
uv run --no-sync ruff format .
|
|
24
|
+
|
|
25
|
+
help:
|
|
26
|
+
uv run --no-sync applika --help
|
|
27
|
+
|
|
28
|
+
uninstall:
|
|
29
|
+
uv tool uninstall applika-cli
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: applika-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Job application tracker CLI for Applika.dev
|
|
5
|
+
Project-URL: Homepage, https://applika.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/ApplikaDev/applika
|
|
7
|
+
Author-email: Luis Eduardo Soares <luisedu.soares@outlook.com.br>, David Alecrim <dsalecrim@outlook.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: applika,cli,job-tracker
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Requires-Dist: httpx>=0.28.1
|
|
17
|
+
Requires-Dist: pydantic>=2.0
|
|
18
|
+
Requires-Dist: typer>=0.15.0
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# applika-cli
|
|
22
|
+
|
|
23
|
+
Command-line interface for [Applika.dev](https://applika.dev) — a structured job application tracker designed for active job seekers who want full control over their data without relying on a browser.
|
|
24
|
+
|
|
25
|
+
Track every application you send, filter and review your pipeline from the terminal, and keep your AI coding assistant (Claude Code, Gemini, Codex) aware of the CLI through a bundled skill file.
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- Python 3.12+
|
|
30
|
+
- [uv](https://docs.astral.sh/uv/) (recommended) or pip
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv tool install applika-cli
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This installs the `applika` binary globally via uv's tool environment. Verify:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
applika --help
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
To install from a local source checkout (useful during development):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv tool install --force .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Authentication
|
|
53
|
+
|
|
54
|
+
The CLI authenticates via GitHub OAuth. On `applika login`, your browser opens to GitHub's authorization page. Once you authorize, the callback is captured locally on a loopback port and the session (access + refresh tokens) is saved to `~/.config/applika/session.json`. The session refreshes automatically on expiry — you only need to log in once per device.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Open browser and complete GitHub OAuth
|
|
58
|
+
applika login
|
|
59
|
+
|
|
60
|
+
# Verify the active session without making any other API call
|
|
61
|
+
applika whoami
|
|
62
|
+
# → Logged in as: username=luissoares name=Luis Soares email=luis@example.com
|
|
63
|
+
|
|
64
|
+
# Revoke the session server-side and clear local storage
|
|
65
|
+
applika logout
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
> `applika whoami` is the recommended pre-flight check. Run it before any other command, especially in scripts or AI-assisted workflows, to confirm a valid session exists before hitting the API.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
### `applika applications list`
|
|
75
|
+
|
|
76
|
+
Lists all job applications in the current cycle, sorted by date descending. Supports rich filtering and both human-readable table output and machine-readable JSON.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Default: all applications as a table
|
|
80
|
+
applika applications list
|
|
81
|
+
|
|
82
|
+
# Narrow down by any combination of filters
|
|
83
|
+
applika applications list \
|
|
84
|
+
--search "stripe" \
|
|
85
|
+
--mode active \
|
|
86
|
+
--status active \
|
|
87
|
+
--platform LinkedIn \
|
|
88
|
+
--from 2026-01-01 \
|
|
89
|
+
--to 2026-06-30
|
|
90
|
+
|
|
91
|
+
# JSON output — useful for piping into jq or scripts
|
|
92
|
+
applika applications list --output-format json
|
|
93
|
+
|
|
94
|
+
# Scope to a specific job-search cycle by UUID
|
|
95
|
+
applika applications list --cycle-id <uuid>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Filter reference:**
|
|
99
|
+
|
|
100
|
+
| Flag | Values | Default | Description |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| `--search TEXT` | any string | — | Case-insensitive substring match on company name or role title |
|
|
103
|
+
| `--mode` | `active` · `passive` · `all` | `all` | `active` = you applied; `passive` = recruiter reached out |
|
|
104
|
+
| `--status` | `active` · `finalized` · `all` | `all` | `finalized` applications have a recorded outcome |
|
|
105
|
+
| `--platform TEXT` | e.g. `LinkedIn` | — | Exact match on platform name |
|
|
106
|
+
| `--from YYYY-MM-DD` | date | — | Include applications from this date (inclusive) |
|
|
107
|
+
| `--to YYYY-MM-DD` | date | — | Include applications up to this date (inclusive) |
|
|
108
|
+
| `--output-format` | `table` · `json` | `table` | `json` returns the raw API response as a formatted array |
|
|
109
|
+
| `--cycle-id TEXT` | UUID | — | Filter to a specific job-search cycle |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### `applika applications new`
|
|
114
|
+
|
|
115
|
+
Records a new job application. The CLI validates the payload locally with Pydantic before calling the API, so you get clear field-level error messages without a round-trip.
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Minimal — required fields only
|
|
119
|
+
applika applications new \
|
|
120
|
+
--company "Stripe" \
|
|
121
|
+
--role "Backend Engineer" \
|
|
122
|
+
--platform "LinkedIn" \
|
|
123
|
+
--mode active \
|
|
124
|
+
--date 2026-05-10
|
|
125
|
+
|
|
126
|
+
# With salary info (currency and period are always required together with any salary field)
|
|
127
|
+
applika applications new \
|
|
128
|
+
--company "Cloudflare" \
|
|
129
|
+
--role "Systems Engineer" \
|
|
130
|
+
--platform "Email" \
|
|
131
|
+
--mode passive \
|
|
132
|
+
--date 2026-05-10 \
|
|
133
|
+
--observation "Recruiter cold-messaged. Interesting stack." \
|
|
134
|
+
--country "Brazil" \
|
|
135
|
+
--work-mode remote \
|
|
136
|
+
--salary-min 18000 \
|
|
137
|
+
--salary-max 24000 \
|
|
138
|
+
--currency BRL \
|
|
139
|
+
--salary-period monthly
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Required flags:**
|
|
143
|
+
|
|
144
|
+
| Flag | Description |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `--company TEXT` | Company name. Matched against known companies; a new record is created if not found. |
|
|
147
|
+
| `--role TEXT` | Job title or role description |
|
|
148
|
+
| `--platform TEXT` | Platform where you found or were contacted about the role (e.g. `LinkedIn`, `Indeed`, `Email`) |
|
|
149
|
+
| `--mode` | `active` — you applied proactively · `passive` — inbound from a recruiter |
|
|
150
|
+
| `--date YYYY-MM-DD` | Date the application was submitted or the first contact occurred |
|
|
151
|
+
|
|
152
|
+
**Optional flags:**
|
|
153
|
+
|
|
154
|
+
| Flag | Description |
|
|
155
|
+
|---|---|
|
|
156
|
+
| `--company-url URL` | Company website |
|
|
157
|
+
| `--job-url URL` | Direct link to the job posting |
|
|
158
|
+
| `--observation TEXT` | Free-form notes about the role, process, or company |
|
|
159
|
+
| `--country TEXT` | Country where the role is based |
|
|
160
|
+
| `--work-mode` | `remote` · `hybrid` · `on_site` |
|
|
161
|
+
| `--experience-level` | `intern` · `junior` · `mid_level` · `senior` · `staff` · `lead` · `principal` · `specialist` |
|
|
162
|
+
| `--expected-salary FLOAT` | The salary you expect or asked for |
|
|
163
|
+
| `--salary-min FLOAT` | Lower bound of a posted salary range |
|
|
164
|
+
| `--salary-max FLOAT` | Upper bound of a posted salary range |
|
|
165
|
+
| `--currency` | `USD` · `BRL` · `EUR` · `GBP` · `CAD` · `AUD` · `JPY` · `CHF` · `INR` |
|
|
166
|
+
| `--salary-period` | `hourly` · `monthly` · `annual` |
|
|
167
|
+
|
|
168
|
+
> **Salary rule:** if any salary amount is provided (`--expected-salary`, `--salary-min`, or `--salary-max`), both `--currency` and `--salary-period` become required. The CLI enforces this before making any API call.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### `applika applications edit <id>`
|
|
173
|
+
|
|
174
|
+
Updates an existing application. Only the flags you pass are changed — everything else keeps its current value. This makes partial updates safe: you can update just the role name or add salary info without touching anything else.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Update the role title
|
|
178
|
+
applika applications edit 42 --role "Staff Engineer"
|
|
179
|
+
|
|
180
|
+
# Add salary info that wasn't captured at application time
|
|
181
|
+
applika applications edit 42 \
|
|
182
|
+
--expected-salary 180000 \
|
|
183
|
+
--currency USD \
|
|
184
|
+
--salary-period annual
|
|
185
|
+
|
|
186
|
+
# Clear fields you no longer want to track
|
|
187
|
+
applika applications edit 42 \
|
|
188
|
+
--clear-job-url \
|
|
189
|
+
--clear-observation \
|
|
190
|
+
--clear-country \
|
|
191
|
+
--clear-salary
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Find the application `id` with:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
applika applications list --search "company name" --output-format json
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Clear flags** — set a field back to null without affecting others:
|
|
201
|
+
|
|
202
|
+
| Flag | Clears |
|
|
203
|
+
|---|---|
|
|
204
|
+
| `--clear-job-url` | Job posting URL |
|
|
205
|
+
| `--clear-observation` | Notes |
|
|
206
|
+
| `--clear-country` | Country |
|
|
207
|
+
| `--clear-salary` | All salary fields (`expected_salary`, `salary_min`, `salary_max`, `currency`, `salary_period`) |
|
|
208
|
+
|
|
209
|
+
> Finalized applications (those with a recorded outcome) are read-only and cannot be edited. The CLI checks this before sending the request.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### `applika skill`
|
|
214
|
+
|
|
215
|
+
Installs the bundled AI skill into your assistant's skills directory. The skill teaches Claude Code, Gemini, or Codex how to use this CLI — what commands exist, how authentication works, required vs optional flags, and common workflows.
|
|
216
|
+
|
|
217
|
+
The skill file is shipped inside the installed package (`applika/skills/applika-cli/SKILL.md`) so it stays in sync with the CLI version you have installed. By default the command creates a symlink so updates are reflected automatically; it falls back to a file copy if symlink creation fails (e.g. Windows without Developer Mode enabled).
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Interactive — choose which tool(s) to install for
|
|
221
|
+
applika skill
|
|
222
|
+
# → 1. Claude (~/.claude/skills/applika-cli)
|
|
223
|
+
# → 2. Gemini (~/.gemini/skills/applika-cli)
|
|
224
|
+
# → 3. Codex (~/.codex/skills/applika-cli)
|
|
225
|
+
# → 4. All of the above
|
|
226
|
+
|
|
227
|
+
# Install to the current project's .claude/skills/ (file copy, no prompt)
|
|
228
|
+
# Useful when you want the skill scoped to a single repo
|
|
229
|
+
applika skill --local
|
|
230
|
+
|
|
231
|
+
# Install to any arbitrary directory (file copy, no prompt)
|
|
232
|
+
applika skill --dir /path/to/skills
|
|
233
|
+
|
|
234
|
+
# Preview what would be installed without touching the filesystem
|
|
235
|
+
applika skill --dry-run
|
|
236
|
+
|
|
237
|
+
# Overwrite an existing installation
|
|
238
|
+
applika skill --force
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Once installed, the AI assistant automatically loads the skill context in every session and knows how to:
|
|
242
|
+
- check authentication with `applika whoami` before running commands
|
|
243
|
+
- construct valid `new` and `edit` payloads
|
|
244
|
+
- apply the correct filters on `list`
|
|
245
|
+
- recover from auth errors by prompting for `applika login`
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Global options
|
|
250
|
+
|
|
251
|
+
These flags apply to every command and are passed before the subcommand name:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
applika --api-base-url https://staging.applika.dev/api applications list
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
| Flag | Default | Env variable |
|
|
258
|
+
|---|---|---|
|
|
259
|
+
| `--api-base-url TEXT` | `https://applika.dev/api` | `APPLIKA_API_BASE_URL` |
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Package structure
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
cli/
|
|
267
|
+
├── pyproject.toml # Build config, dependencies, entry point
|
|
268
|
+
├── Makefile # Shortcuts: test, lint, format
|
|
269
|
+
├── README.md
|
|
270
|
+
├── CLAUDE.md # Guidance for AI assistants working in this repo
|
|
271
|
+
└── src/
|
|
272
|
+
└── applika/ # Importable package (entry: applika.main:main)
|
|
273
|
+
├── main.py # Entry point — calls app()
|
|
274
|
+
├── app.py # Root Typer app, --api-base-url callback, AppConfig wiring
|
|
275
|
+
├── config.py # AppConfig dataclass + resolve_api_base_url()
|
|
276
|
+
│
|
|
277
|
+
├── skills/
|
|
278
|
+
│ └── applika-cli/
|
|
279
|
+
│ └── SKILL.md # Bundled AI skill — installed via `applika skill`
|
|
280
|
+
│
|
|
281
|
+
├── schemas/ # Vendored Pydantic models (no backend import)
|
|
282
|
+
│ ├── enums.py # StrEnum types: Currency, SalaryPeriod, WorkMode, etc.
|
|
283
|
+
│ └── application.py # ApplicationCreate, ApplicationUpdate with validators
|
|
284
|
+
│
|
|
285
|
+
├── lib/ # Infrastructure — no Typer dependency
|
|
286
|
+
│ ├── api.py # ApiClient (httpx + cookie auth), ApiError, AuthError
|
|
287
|
+
│ ├── session.py # SessionData, SessionStore (~/.config/applika/session.json)
|
|
288
|
+
│ └── loopback.py # LoopbackLoginServer for OAuth browser callback
|
|
289
|
+
│
|
|
290
|
+
├── utils/ # Pure helpers — no httpx, no Typer
|
|
291
|
+
│ ├── dates.py # parse_date, ensure_date_string
|
|
292
|
+
│ └── output.py # render_application_table, print_application_summary
|
|
293
|
+
│
|
|
294
|
+
└── commands/
|
|
295
|
+
├── auth.py # login, logout, whoami commands
|
|
296
|
+
├── skill.py # skill command — installs the AI skill
|
|
297
|
+
└── applications/
|
|
298
|
+
├── __init__.py # applications_app Typer sub-app, default-to-list callback
|
|
299
|
+
├── commands.py # list_applications, new_application, edit_application
|
|
300
|
+
├── filter.py # filter_applications, resolve_platform_id
|
|
301
|
+
└── payloads.py # ApplicationArgs dataclass, build_application_payload()
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Layer rules:**
|
|
305
|
+
- `lib/` — HTTP and session logic only. No Typer, no output formatting.
|
|
306
|
+
- `utils/` — Pure functions. No side effects, no I/O beyond what the function signature implies.
|
|
307
|
+
- `schemas/` — Vendored copies of backend DTOs. Keep in sync manually with `backend/app/application/dto/application.py` and `backend/app/core/enums.py` when the backend changes.
|
|
308
|
+
- `commands/` — Typer command functions only. Delegates to `lib/` and `utils/`.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Development
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
# Install project + dev dependencies into a local virtualenv
|
|
316
|
+
uv sync
|
|
317
|
+
|
|
318
|
+
# Run the test suite
|
|
319
|
+
make test
|
|
320
|
+
|
|
321
|
+
# Auto-fix lint issues
|
|
322
|
+
make lint
|
|
323
|
+
|
|
324
|
+
# Apply code formatter
|
|
325
|
+
make format
|
|
326
|
+
|
|
327
|
+
# Build a wheel for distribution
|
|
328
|
+
uv build
|
|
329
|
+
|
|
330
|
+
# Install the locally built CLI globally for manual testing
|
|
331
|
+
uv tool install --force .
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Tests live in `tests/` and use `typer.testing.CliRunner` with fake `ApiClient` and `SessionStore` implementations defined in `tests/conftest.py`. No real network calls are made.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## License
|
|
339
|
+
|
|
340
|
+
MIT
|