- Python 98%
- Shell 2%
Plan Step 3. Verify green: `.venv/bin/python -m pytest tests/test_paths.py` ->
8 passed, exit 0. Full suite: 11 passed.
Test first, and RED was observed before a line of paths.py existed
(ModuleNotFoundError on collection).
Two measured risks drive the design, not one.
Risk C6 -- the host-side server runs unsandboxed with caller-supplied paths.
safe_join resolves BOTH operands with os.path.realpath before comparing, so
lexical traversal and symlink escape fall to the same check; a lexical check on
the joined string would have called the symlink case safe. The comparison is
component-aware, so a sibling whose name merely prefixes the root is outside.
Escape raises; it never clamps to an adjacent path.
Risk H8 -- macOS hands back NFD. slug normalises to NFC first, so a decomposed
name and its composed twin produce one slug rather than two directories. The
test asserts that equality on a real NFC/NFD pair, not on a lookalike.
No implicit default workspace: --workspace, else JOBBSOK_WORKSPACE, else a
`workspace:` line in ${CLAUDE_PLUGIN_DATA}/jobbsok.conf, else WorkspaceUnresolved.
Guessing at the operator's home directory is the one behaviour this module must
not have. This tightens build-brief section 5's `~/jobbsok-workspace` default
into an explicit order; the deviation is recorded in the plan's Assumptions.
scaffold is idempotent by only creating what is absent -- an existing
beslutninger.jsonl is never truncated. It is append-only, and a scaffold that
emptied it would destroy the decision log. The test proves this by populating
the workspace and asserting a byte-identical snapshot across a second run.
Collision rule is documented and tested: -2, then -3, counting up.
sak_id carries no `taken` parameter. An earlier draft had one; no step and no
test requires it, so it was unproven code and was removed rather than kept.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|---|---|---|
| .claude-plugin | ||
| docs | ||
| scripts | ||
| tests | ||
| .gitignore | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
jobbsok
Local-first job search workspace: sourcing, scoring, case tracking, applications and interview prep.
A read-only job search operating system for one person searching for their own job. It reads listings the operator is already looking at, scores them against a maintained candidate profile, records every accept/reject decision with a reason, keeps each case's full correspondence in one folder, drafts applications as files, and flags threads that have gone silent. It never submits, never sends, never stores a credential.
Solo-maintained, fork-and-own. This plugin is a starting point, not a vendor product. Issues are welcome as signals; pull requests are not accepted.
AI-generated: all code produced by Claude Code through dialog-driven development.
Status: pre-release. Nothing is built yet beyond the manifest; the build
brief in docs/build-brief.md is the contract, and milestones ship in order
(M1–M6).
Install
Not installable yet. When released, the plugin is pinned by tag in the
ktg-plugin-marketplace catalog:
claude plugin marketplace add https://git.fromaitochitta.com/open/ktg-plugin-marketplace.git
claude plugin install jobbsok@ktg-plugin-marketplace
Non-goals
Submitting applications. Sending email. Any write to Finn.no or LinkedIn. Credential storage. Background jobs. Multi-user support. Recruiter-side features. Bulk listing harvest.
Changelog
See CHANGELOG.md.
License
MIT — see LICENSE.