Client Platform / Discovery

No model call is triggered by an anonymous or client action, so a public intake form cannot run up an API bill or be used as a prompt-injection vector.
Each one records whether it came from the intake, from research, or from the operator, and which outcome it serves. Gaps show up as UI rather than as a report.
A prospect submits a build brief in about six minutes and receives a discovery set back: research, outcomes, requirements, a brand direction, wireframes, architecture, and a roadmap. Every requirement records where it came from and which outcome it serves, so coverage gaps are a surface in the product rather than something you find out about later.
The unusual part is the generation seam. No model call is ever triggered by an anonymous or client action. Generation is operator-initiated from Claude Code, which posts validated artifacts to a bearer-authenticated internal API. The client-facing app reads and reviews; it never infers.
A public intake form wired to a model is two problems at once: anyone can run up an inference bill, and anyone can aim a prompt at your own infrastructure. The usual answers are rate limits and input sanitising, both of which are mitigations rather than solutions. The portal needed AI-generated deliverables without ever putting a model behind a public trigger.
Outcome, then requirement, then artifact node. Every requirement records its source (intake response, research finding, or operator) and the outcomes it serves. Coverage gaps at either level are first-class UI, not a report someone has to run.
Skills run from Claude Code and POST validated artifacts to a bearer-authenticated internal API. Nothing a client does reaches a model, which is what keeps marginal cost at zero and leaves no prompt-injection surface to defend.
Clients review and approve from an emailed deep link, on a phone, with no account to create. Approval is per artifact version and snapshots the requirements it covered, so what was agreed stays legible after the document moves on.
The obvious way to build an AI product is to let the user press the button. I did the opposite. Nothing a client does reaches a model here; generation is operator-initiated. That sounds like a limitation until you notice it takes marginal cost to zero and removes the entire prompt-injection surface in the same move.
An AI feature any visitor can trigger is an AI feature any visitor can run up a bill on, and a prompt-injection surface aimed at your own infrastructure.
I made generation operator-initiated only. Skills run from my machine and post validated artifacts to a bearer-authenticated internal API, so no client action reaches a model.
Who is allowed to trigger inference is an architecture decision, not a settings toggle. Deciding it early took marginal cost to zero and removed the injection surface at the same time, where rate limits and sanitising would only have reduced both.
A deliverable that can be regenerated loses every comment attached to it, because comments anchor to positions and positions move on the second draft.
Anchors are stable node ids assigned by an ingest reconciler that diffs structurally, so a node keeps its identity across versions even when it moves within the document.
If a document can be regenerated, its identities have to survive regeneration. Positional anchors are a bug that has not happened yet.
A design system described in a client document and implemented in the client's code will drift apart the moment either one is edited.
I built the brand deliverable as a generator instead of a document. One token file renders both the PDF the client reads and the globals.css their developers drop in.
When two artifacts have to agree, do not maintain two artifacts. Generate both from one source and the agreement becomes structural rather than something a person has to keep remembering.