Local-first job search workspace: sourcing, scoring, case tracking, applications and interview prep.
  • Python 98%
  • Shell 2%
Find a file
Kjell Tore Guttormsen 1d631b7c94 feat(m1): add pinned workspace root and ASCII slug helpers
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>
2026-09-04 17:29:52 +02:00
.claude-plugin feat: initial commit — plugin manifest and build brief 2026-09-03 20:27:23 +02:00
docs docs(m1): record Cowork probe results and degradation branch 2026-09-04 17:22:59 +02:00
scripts feat(m1): add pinned workspace root and ASCII slug helpers 2026-09-04 17:29:52 +02:00
tests feat(m1): add pinned workspace root and ASCII slug helpers 2026-09-04 17:29:52 +02:00
.gitignore chore: gitignore .claude/projects (local-only on public remote); brief validated 2026-09-03 21:17:47 +02:00
CHANGELOG.md feat: initial commit — plugin manifest and build brief 2026-09-03 20:27:23 +02:00
CLAUDE.md feat: initial commit — plugin manifest and build brief 2026-09-03 20:27:23 +02:00
LICENSE feat: initial commit — plugin manifest and build brief 2026-09-03 20:27:23 +02:00
pyproject.toml build(m1): pin toolchain and guard v1.3.0 in pyproject 2026-09-04 17:26:20 +02:00
README.md feat: initial commit — plugin manifest and build brief 2026-09-03 20:27:23 +02:00

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.

Version Platform License

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.