Product: oll.in — dossier engine + Career Radar + get-found presence
Thesis: ~80% already exists as frozen spines
Method: parallel POCs → verify → chunk the build-out
The product surface what oll.in actually is
oll.in is not one feature — it's a career service with three distinct surfaces, and they carry very different build risk. Naming them precisely is the whole point of an architecture: it lets us reuse aggressively where the risk is already retired, and spike hard only where it isn't.
Surface 1 · the dossier engine
Pay-once, no subscription
- 📸 Bewerbungsfoto — a studio-grade application photo from phone snaps.
- 📄 Lebenslauf — a Swiss-format CV (A4, photo, permit/nationality fields, DD.MM.YYYY).
- ✉️ Motivationsschreiben — a cover letter for that one job, from the applicant's real work.
- 🎯 Vorstellungsgespräch — interview prep tailored to the role.
Surfaces 2 & 3 · the always-on engines
Subscription — Career Radar & get-found
- Career Radar — daily scouting of legitimate Swiss/DACH listings, scored against the applicant's profile, with alerts + salary benchmark.
- Get-found presence — drafts LinkedIn posts in the applicant's voice, scheduled via official LinkedIn OAuth (Postiz).
- The agent prepares; the human reviews & sends. Never auto-apply, never scrape, never a bot on the send button.
The critical read: Surface 1 is almost entirely reuse of what oll.am already runs. Surfaces 2 & 3 carry the genuinely-new backend and the real feasibility risk — which is exactly why they go behind POCs, not into a build-now list.
The thesis lead with this
oll.am is already three frozen spines and a set of product services. oll.in is mostly a matter of pointing them at a new problem shape — a job-seeker instead of a writer, a job description instead of a manuscript. The genuinely-new code is small and well-bounded; the rest is assembly and one thin frontend.
oll.in is ~80% assembly of frozen capabilities. The 20% that's new is where the risk lives — so we prove that 20% in parallel POCs before we commit a single sprint to build-out.
The method Sam set — verify feasibility, chunk to parallel sections
Ship-vs-build honesty. This is Phase-2 work. The nearer franc still lives on already-built assets (CiteBible, ollwrite, humaniz). oll.in earns its place only because its MVP reuses the same oll-write + memory + foto engines and is Sam's own itch (he dogfoods it on his real applications) — so it de-risks the platform rather than starting a net-new build. The POC-first framing keeps it honest: no build-out spend until a POC proves the value.
The reuse map every surface → platform capability
Each oll.in surface maps onto an existing capability, an additive extension of one, or a genuinely-new service. This table is the heart of the architecture — read the right-hand column as the actual scope of work.
| oll.in surface | Backed by | Status today | Work |
| Bewerbungsfoto | foto-service → Replicate | Scaffolded (services/foto, 12 tests); Replicate model stubbed | Unstub |
| Swiss CV | oll-write verb + BFF-grounded (memory) | oll-write LIVE but stateless; the BFF retrieves & passes cited context in; no CV verb yet | New verb |
| Cover letter | oll-write verb + BFF-grounded (memory) | Same — one new JD-aware prompt | New verb |
| Interview prep | oll-write verb + BFF-grounded (memory) | Same — one new JD-aware prompt | New verb |
| Applicant profile / grounding | oll-memory (memory.oll.am) | LIVE — per-user corpus, cited retrieval, honest abstain | Reuse |
| Sign-in / identity | Core (core.oll.am) | LIVE — magic-link, 72h identity JWT | Reuse |
| Pay-once dossier pack | Core billing (guest checkout) | One-time payment mode works; guest pair proposed (PR #21) | Guest pair |
| Email delivery | Core email → Resend | LIVE (guest-email allow-list needed) | Allow-list |
| Any-model generation | oll-model (model.oll.am) | LIVE — Groq default, provider-switchable | Reuse |
| Agent runtime / MCP drive | oll-mcp + OpenCLAW | Thin seam built + proven (feat/oll-mcp-thin); OpenCLAW live on VPS | Add verbs |
| Career Radar (scouting) | oll-scout (NEW) | Does not exist | New service |
| Radar subscription billing | Core billing (subscription mode) | Subscription mode already the DEFAULT (grounding-verified); needs a Radar price + an event-id dedupe table | Price + dedupe |
| Get-found presence | Postiz + LinkedIn OAuth + oll-write | Postiz not deployed; draft-post verb absent | Deploy + verb |
| oll.in web app | thin frontend (Next.js/BFF) | Landing exists; app does not | New client |
Count the reds. The genuinely-new backend is:
3 oll-write prompt verbs,
one oll-scout service,
a small event-id dedupe table on Core, and
a Postiz deploy. Everything else is reuse or a small additive extension already on a branch. That is a remarkably small new surface for a product this ambitious — the whole reason to build oll.in
on oll.am.
Grounding verified this against the live code — see the
plan → execution spec for the two corrections it forced (oll-write is stateless; Core already does subscriptions).
The solution architecture one picture
Same visual language as the platform diagrams: solid-black boxes are frozen spines / live services, dashed-red are genuinely-new for oll.in, dashed-blue is an external runtime. The seam is MCP. Nothing about the frozen layer changes — oll.in is a client of it.
oll.in web app + OpenCLAW
Next.js BFF · agentic runtime · cron
Applicant uploads CV, picks a job, reviews & sends. OpenCLAW runs the always-on loop.
HTTPS · Core JWT (BFF) · MCP/stdio+HTTP (agent)▼
the seam · MCPoll-mcp
FastMCP adapter · zero new logic · holds one Core JWT
clarify · rewrite · draft · tailor_cv · cover_letter · interview_prep · headshot_order · scout_status
HTTP · Bearer JWT · internal service token▼
frozenCore LIVE
core.oll.am
auth · billing · email
+ event-id dedupe (new)
frozenoll-model LIVE
model.oll.am
any-model gateway · Groq default
frozenoll-memory LIVE
memory.oll.am
per-user CV corpus · cited retrieval · abstain
▲product services call the spines over HTTP
liveoll-write LIVE
write.oll.am
+ 3 JD-aware verbs (prompts only)
foto-service
services/foto
guest-checkout headshot · unstub Replicate
newoll-scout
own Neon oll_scout
pull legit listings · score vs profile · daily digest
newPostiz
self-host OSS
LinkedIn OAuth · scheduled drafts
frozen spine / live service
genuinely-new for oll.in
external runtime
LIVE in production
The platform extensions needed the "in more detail" ask
Each extension is additive, respects the frozen-Core principle (never weaken an existing route), and follows the house pattern for its kind. Ordered by how much oll.in leans on it.
1 · oll-write — three JD-aware verbs new prompts, not architecture
Add tailor_cv(profile, job_description), cover_letter(profile, job_description), interview_prep(profile, job_description). Each reuses the existing _authorize_and_gate → _run_model pattern — new prompt constants only, no new architecture (per the agent-seam plan). Grounding: the applicant's CV/work history is ingested into oll-memory; retrieval supplies cited passages so output is "from real work, not buzzwords," and abstains rather than inventing when the corpus is thin. Prompts follow llm-call-contract (named constants, JSON-schema-in-prompt, fence-strip parse, input caps).
2 · foto-service — unstub Replicate extend
The scaffold, tests, guest-checkout wiring and Core-shaped error envelope already exist. The remaining work is replacing the stubbed Replicate model + photo-upload path with a real headshot model tuned for the Swiss Bewerbungsfoto (neutral background, head-and-shoulders). Feasibility of the output quality is a POC (below), not an assumption.
3 · Core — guest-checkout pair + email allow-list additive, branch exists
Both billing routes are @require_auth and email send is recipient-scoped to the authed user — so a no-login dossier sale needs the additive guest-checkout-session + guest-verify-session pair plus a guest-email allow-list (per guest-checkout-grant; PR #21). One-time payment mode already works. Never weaken the existing authed routes.
4 · Core — Radar price + event-id dedupe smaller than first drawn
Grounding correction: Core already runs Stripe subscription mode as its default (mode = "payment" if plan=="one_time" else "subscription"), and the webhook already handles invoice.payment_succeeded + customer.subscription.deleted. So Career Radar billing is mostly reuse — add a Radar price/plan and turn it on. The one real gap the grounding found: there is no event-id dedupe table (idempotency relies on naturally-idempotent upserts today). Add a ProcessedEvent table before a recurring paid plan rides the webhook (idempotent-paid-fulfillment). Entitlement stays identity-in-JWT, plan-from-/me (token-identity-not-entitlement).
5 · oll-scout — the one new service new · own Neon DB
A small service (per ADR-008 database-per-service: own Neon oll_scout) that on a cron: pulls fresh roles from legitimate job-board APIs / feeds only, stores them, scores each against the applicant's oll-memory profile via oll-model, and emits a daily digest through Core email. Stateless-to-the-user, thin, disposable. Its single hard unknown is data-source feasibility — which listing sources are ToS-compatible, well-structured, and cover Swiss/DACH with usable volume. That is POC-C, and it gates whether Radar is buildable at all.
6 · Postiz + LinkedIn OAuth new · deferred
The get-found engine self-hosts Postiz (OSS, already identified in the constellation audit as a zero-code deploy) and connects LinkedIn via official OAuth. oll-write drafts posts in the applicant's voice; Postiz schedules them after human approval. This is the highest ToS-sensitivity surface and the lowest near-term revenue — deferred to last, behind its own compliance POC.
7 · oll.in frontend new thin client
A thin product frontend that reuses ollwrite's memory-BFF pattern verbatim: the browser never names a collection or holds a service token; the BFF derives collection: mem:user:{id} from the Core JWT. Flow: upload CV → ingest to memory → paste/select a job → generate dossier (the 3 verbs) → order photo (foto guest-checkout) → pay → deliver. Reuses drag-to-cite + honest-abstain from the proactive-memory-sidecar pattern.
Identity, corpus & billing model how a job-seeker maps onto the spines
Identity & corpus
The applicant is a memory tenant
- Sign-in = Core magic-link → 72h identity JWT (
sub=user id).
- The uploaded CV + work history = the user's private corpus
mem:user:{id}, ACL-scoped by the BFF from the JWT.
- The job description is ephemeral context passed to the verb — not stored in the corpus.
- Guest (photo-only) buyers need no account — the foto guest-checkout pattern delivers by email.
Billing
Own the tool, subscribe to the work
- Photo-only — CHF ~29, guest one-time, no login.
- Active Search Pass — CHF ~99–149, one-time, the full dossier engine (account, so the corpus persists across applications).
- Career Radar — CHF ~19/mo, Stripe subscription mode (the new Core capability).
- Entitlement always live from
/me, never trusted from the browser.
The honest pricing line the landing already commits to: a tool you own is pay-once; a service that works for you daily is a subscription. The architecture mirrors it exactly — the dossier engine is stateless-per-purchase; Career Radar is the only thing that needs a recurring relationship, and it's the only thing that carries subscription billing.
POC-first plan parallel feasibility lanes
Sam's method: prove feasibility in multiple POC integrations before building out, chunked so the lanes run in parallel. Each POC below states a hypothesis, the smallest integration that tests it, and a binary pass signal. They share nothing at runtime, so they can be worked concurrently — and each one independently green-lights (or kills) a chunk of build-out.
critical value
POC-A
Grounded dossier quality
- Hypothesis
- oll-write + oll-memory can produce a send-worthy, cited Swiss dossier (CV + cover letter + interview prep) from a real CV and a real job posting.
- Smallest test
- Ingest one real CV to memory; add the 3 verbs as prompts on dev oll-write; run against 3 real Swiss postings.
- Pass signal
- Sam judges ≥1 output good enough to send under his own name — the founder-note test. Citations resolve; no invented facts.
Lane: oll-write prompts · owner-dogfood
critical feasibility
POC-C
Job-scout data source
- Hypothesis
- A legitimate, ToS-compatible job-listing API/feed exists covering Swiss/DACH roles with usable volume and structured fields (title, description, company, deadline).
- Smallest test
- A throwaway fetch script against 1–2 candidate sources; inspect fields, volume, terms.
- Pass signal
- ≥1 source returns enough well-structured roles under compliant terms to feed a daily digest. If none pass, Career Radar is re-scoped or killed.
- Result (verified)
- GREEN — with a flag. Jooble API is the only self-serve API with real CH coverage (+DE/AT) and redisplay-with-link-back terms; supplement with Arbeitnow (open, no-key). All government sources (Job-Room/SECO, EURES, German BA) and LinkedIn/Indeed are RED. Concentration risk: Jooble is effectively the single load-bearing source — confirm CH field depth with live calls before designing the digest around it.
Lane: research spike · done — see execution spec
quality
POC-B
Bewerbungsfoto output
- Hypothesis
- A Replicate headshot model yields a Swiss-acceptable application photo (neutral background, head-and-shoulders) from a few phone snaps.
- Smallest test
- Unstub the Replicate call in
services/foto; generate from Sam's own snaps.
- Pass signal
- Output passes an eyeball test against real Swiss Bewerbungsfoto standards; consistent across ≥3 subjects.
Lane: foto-service · independent
billing
POC-D
Radar billing + event dedupe
- Hypothesis
- Reframed by grounding: subscription mode already exists on Core. So: a Radar price + a new
ProcessedEvent dedupe table flip the plan exactly once, additively, without disturbing the frozen paths.
- Smallest test
- Feat branch on dev Core: test-mode subscription checkout →
invoice.payment_succeeded → /me reports plan; replay the same event.id and assert a no-op.
- Pass signal
- Plan flips once, replay is inert, existing billing tests stay green (adversarial-reviewer pass).
Lane: Core billing · gated by merge-gate
mostly proven
POC-E
Agent loop, end-to-end
- Hypothesis
- OpenCLAW can drive the dossier verbs over MCP for one real application, human-on-send.
- Smallest test
- Apply
services/oll-mcp/docs/openclaw-wiring.md; add the 3 verbs to the thin seam; run one full loop.
- Pass signal
- OpenCLAW produces a review-ready dossier via
--http seam. (Seam already proven both transports — this extends it.)
Lane: oll-mcp · builds on proven seam
compliance
POC-F
Presence via official OAuth
- Hypothesis
- Postiz can post to LinkedIn through sanctioned OAuth — draft, approve, schedule — with zero scraping or automation.
- Smallest test
- Deploy Postiz; connect one LinkedIn account via OAuth; schedule one human-approved post.
- Pass signal
- A drafted post publishes through the official API within LinkedIn's terms. Deferred — lowest near-term revenue, highest ToS care.
Lane: Postiz · deferred to last
Convergence gate. POCs are independent, but build-out is not started until the value POCs are green. POC-A (dossier quality) is the master gate for the MVP; POC-C (scout data source) is the master gate for Career Radar. A red on either doesn't stall the others — it re-scopes exactly one chunk.
Build-out chunked, each gated on its POC
Only after a POC passes does its chunk get built out. The chunks map 1:1 to POC lanes, so the same parallelism carries through. Sequence reflects revenue proximity and risk, not a rigid waterfall.
Chunk 1 · Assisted Dossier Pack — the MVPgated on POC-A + POC-B
Ship the pay-once dossier: 3 oll-write verbs + memory grounding + foto photo + Core guest-checkout + email delivery, behind a thin oll.in frontend. No autonomy, no scraping, no subscription. Genuinely-new code = 3 prompts + 1 frontend + foto unstub. Everything else frozen. This is the build-in-public MVP and Sam's own itch.
Chunk 2 · Career Radargated on POC-C + POC-D · after first franc
Build oll-scout (own Neon DB, cron, score-vs-profile, digest email) + Stripe subscription mode on Core. Recurring CHF ~19/mo. Only worth building if POC-C found a compliant data source and a stranger has paid for the dossier pack first.
Chunk 3 · Agent runtimegated on POC-E · parallel-able with Chunk 2
Wire OpenCLAW to the seam for the always-on prepare loop (human-on-send). Reuses the proven thin MCP seam; extension is the 3 verbs + openclaw-wiring. Low risk — can proceed alongside Radar.
Chunk 4 · Get-found presencegated on POC-F · deferred
Deploy Postiz + LinkedIn OAuth + an oll-write draft-post verb. Highest ToS care, lowest near-term revenue — last, and only if the compliance POC is clean.
Compliance & the honesty line non-negotiable
What oll.in does
Prepare, ground, hand over
- Prepares a review-ready dossier from the applicant's real work.
- Scouts only legitimate listings / APIs that permit it.
- Posts only via official LinkedIn OAuth (Postiz), on human approval.
- Cites its sources; abstains rather than inventing.
What it never does
The bright lines
- Never auto-applies, mass-applies, or submits on anyone's behalf — the human hits send.
- Never scrapes sites that disallow it or auto-connects on LinkedIn.
- Never claims "Swiss-hosted" or data-residency — "Swiss format" means the Bewerbungsdossier layout only.
- Never stores another user's corpus — ACL derived server-side from the JWT.
"100 tailored applications an hour" is a contradiction we refuse to sell. Ten sharp, cited, genuinely-tailored applications beat a hundred generic ones — and that's the only promise the architecture can honestly keep. The agent makes ten effortless; the human stays on every send.
Decision points for Sam batched, with recommendations
- Kick off which POCs now? A (dossier quality), B (photo), C (scout source) are independent and parallel-able today. Rec: start A + C first — they're the two master gates.
- oll.in frontend stack — reuse ollwrite's Next.js + memory-BFF verbatim, or the house Angular/Ionic? Rec: Next.js — reuse the ollwrite BFF, drag-to-cite, honest-abstain wholesale.
- Dossier billing — guest pay-once (no login, foto pattern) or account-based for the pack? Rec: guest for photo-only; account for the full pack so the corpus persists.
- Approve the additive Core subscription mode? Needed for Career Radar; additive, behind POC-D + the merge-gate. Rec: yes, but only build after POC-C proves a data source and after the first franc.
- Career Radar data source — this is the real unknown; POC-C is a research spike. Rec: run POC-C as a pure feasibility spike before committing any Radar build.
- Presence / Postiz — deploy now or defer to Chunk 4? Rec: defer — lowest revenue, highest ToS care.
What I'll do on a green light: stand up the two master-gate POCs in parallel — POC-A (add the 3 verbs as prompts on dev oll-write, ingest a real CV, run against real postings) and POC-C (a throwaway fetch spike against candidate Swiss/DACH listing APIs) — each on its own feat branch, each reporting a binary pass/fail, nothing deployed. No build-out until they report.