Skip to content

Employers and resume visibility as CRUD, so both flows are commands - #48

Merged
ralyodio merged 1 commit into
masterfrom
employer-crud
Sep 9, 2026
Merged

Employers and resume visibility as CRUD, so both flows are commands#48
ralyodio merged 1 commit into
masterfrom
employer-crud

Conversation

@ralyodio

@ralyodio ralyodio commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #45. Documenting the two flows turned up the reason they had never been documented: the CLI could not do them. There was no way to create an employer without a browser, and resume save sent no visibility, so a resume saved from a terminal was private with no command to list it. The docs page had to tell you to copy a bearer token out of config.json and curl the API — on a board whose whole pitch is that a client can drive it.

Both flows are now two commands.

agenticjobs employer create "Example Works" --website https://example.com
agenticjobs post job.md --org example-works
agenticjobs publish <slug>
agenticjobs resume save resume.md
agenticjobs resume publish <slug>

Employers get the rest of their CRUD

  • PATCH /api/v1/orgs/{slug} changes only the fields it carries. An absent field is left alone and an explicit null clears it, so a caller that knows about a name cannot blank a website it never read.
  • A rename never moves the slug. That slug is the URL every listing, link and directory row already points at; a company becoming "Example Works Inc" has not become a different employer. The CLI says so on every rename, because otherwise you go looking for a URL that never changed.
  • DELETE /api/v1/orgs/{slug} refuses with 409 once anything has gone live. jobs.org_id cascades and applications.job_id cascades behind it, so the honest delete is one that will not quietly take published listings and the applications people sent to them. Drafts do not count — nobody has seen one, and an employer whose listings are all drafts is almost always one typed in wrong five minutes ago.

Resumes get the visibility half they were missing

--visibility on save and import, plus resume publish, unpublish, visibility <slug> <value> and delete <slug> --yes. A typo'd value is now refused rather than silently dropped, which is what the old isVisibility filter did.

"Saved." became the address instead. The only question a candidate has after saving is whether anybody can read it yet:

$ agenticjobs resume publish backend-engineer
Saved and listed: https://agenticjobs.work/candidates/ada-lovelace

Verified end to end, not only in tests

Against a real board on a real Postgres: created an employer, renamed it and watched the slug hold, posted the exact front matter the docs page shows, published it, had the employer delete refused with its reason, then saved a resume, published it, and read the listed candidate back — skills comma-split as documented and the swarm capacity priced (10 agents, $100/agent, $1000/hr total).

Tests

210 pass against Postgres. Four new ones cover the rename, the partial patch, a stranger's 403/401, and the delete guard. The existing OpenAPI coverage test caught both new routes missing from the published document, which is exactly what it is there for.

Docs also pick up the swarm capacity keys from #46, which shipped without reaching the page.

🤖 Generated with Claude Code

https://claude.ai/code/session_01D8ai32QMBsKEs1nigijSiJ

Documenting the two flows turned up the reason they had never been
documented: the CLI could not do them. There was no way to create an
employer without a browser, and `resume save` sent no visibility, so a
resume saved from a terminal was private with no command to list it. The
page had to tell you to copy a bearer token out of config.json and curl
the API, on a board whose whole pitch is that a client can drive it.

Employers get the rest of their CRUD:

- PATCH /api/v1/orgs/{slug} changes only the fields it carries. An absent
  field is left alone and an explicit null clears it, so a caller that
  knows about a name cannot blank a website it never read.
- A rename never moves the slug. That slug is the URL every listing, link
  and directory row already points at, and a company becoming "Example
  Works Inc" has not become a different employer.
- DELETE /api/v1/orgs/{slug} refuses with 409 once anything has gone live.
  jobs.org_id cascades and applications.job_id cascades behind it, so the
  honest delete is one that will not quietly take published listings and
  the applications people sent to them. Drafts do not count: nobody has
  seen one, and an employer whose listings are all drafts is almost always
  one typed in wrong five minutes ago.

Resumes get the visibility half they were missing: `--visibility` on save
and import, `resume publish`, `unpublish`, `visibility <slug> <value>` and
`delete <slug> --yes`. A typo'd value is refused rather than dropped,
which is what the old silent isVisibility filter did.

"Saved." is now the address instead: the only question a candidate has
after saving is whether anyone can read it yet, and the URL is the answer.

Both flows are two commands on /docs now, with the REST calls kept as the
equivalent rather than the instruction. Also documents the swarm capacity
keys from #46, which shipped without reaching the page.

Verified end to end against a real board, not only in tests: created an
employer, renamed it and watched the slug hold, posted the exact front
matter the docs page shows, published it, had the delete refused, then
saved a resume, published it, and read the listed candidate back with its
skills split and its capacity priced.

Tests: 210 pass against Postgres. The four new ones cover the rename, the
partial patch, a stranger's 403 and the delete guard. The OpenAPI
coverage test caught both new routes missing from the published document,
which is what it is for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8ai32QMBsKEs1nigijSiJ
@ralyodio
ralyodio merged commit cf6eb32 into master Sep 9, 2026
4 checks passed
@ralyodio
ralyodio deleted the employer-crud branch September 9, 2026 16:52
ralyodio added a commit that referenced this pull request Sep 10, 2026
Minor rather than patch because commands and endpoints were added, and
because the reason to cut this at all is that /docs is currently ahead of
the published client: it tells people to run `agenticjobs employer create`
and `agenticjobs resume publish`, and npm still ships 0.10.0, where
neither exists.

Since 0.10.1:

- Employers and resume visibility as CRUD (#48). employer
  list/show/create/update/delete, resume publish/unpublish/visibility/
  delete and --visibility on save and import, with PATCH and DELETE
  /api/v1/orgs/{slug} behind them. A rename keeps the slug; an employer
  that has published cannot be deleted.
- Getting listed and hiring are documented at all (#45), and swarm
  capacity on a candidate profile (#46).
- An address is withheld wherever it is written, and never from cache
  (#47).
- Boolean CLI flags no longer swallow the command after them (#49).
- Salary bounds read correctly in summaries and compare correctly across
  periods in search (#50, #51).
- A JSON parse failure on a 200 is reported rather than swallowed (#52).
- Job and DOCX imports keep titles, structure, tabs and line breaks
  (#53, #54).

Both version files move together: package.json and VERSION in
src/config.ts.


Claude-Session: https://claude.ai/code/session_01D8ai32QMBsKEs1nigijSiJ

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant