Skip to content

[codex] Update landing with hosted DocWriter deployment - #51

Draft
shreyashankar wants to merge 13 commits into
landingfrom
codex/landing-hosted-split
Draft

[codex] Update landing with hosted DocWriter deployment#51
shreyashankar wants to merge 13 commits into
landingfrom
codex/landing-hosted-split

Conversation

@shreyashankar

Copy link
Copy Markdown
Collaborator

Summary

This PR updates the landing branch with the hosted DocWriter deployment work after the shared runtime PR landed in main.

It brings landing up to the merged runtime work from main, then adds the hosted layer: Clerk auth, sign-in and welcome pages, hosted account UI, Fly and Vercel config, the hosted Bash runner, per-user workspace isolation, and hosted model and API-key restrictions.

It also keeps the current landing sync workflow and helper script so future main-to-landing syncs can resolve the recurring package.json conflict automatically.

Validation

I ran these checks in /Users/shreyashankar/Documents/projects/docwriter-landing-hosted-split.

  1. git merge-tree --write-tree origin/landing HEAD
  2. npm ci
  3. npm run check
  4. npm run build
  5. npm run build:landing

All passed. The build still reports the known Svelte warnings in TabBar and the welcome page. The Vercel build also reports optional Cursor SDK dependency warnings.

@shreyashankar
shreyashankar force-pushed the codex/landing-hosted-split branch from db5b1c5 to a92c27e Compare July 1, 2026 16:36
shreyashankar and others added 9 commits July 1, 2026 11:29
Correctness:
- tabFile: separator-aware containment (a bare prefix match admitted
  sibling workspaces) plus an isValidTabId assert
- render: only coerce models on hosted deployments; self-hosted again
  falls back to the provider default instead of forcing a Claude model
- getDb: throw in multi-tenant mode when no user context is active
  instead of silently using the shared singleton
- hosted-runner: bundle byte cap is now global across the whole bundle,
  not per subtree
- runner: refuses to start without RUNNER_SHARED_TOKEN (fail-open branch
  removed); single token env name on both sides
- workflow: runner path filter regex never matched runner/ changes

Centralization:
- deploy-mode.ts owns isMultiTenant(); the five server-side variants and
  the PUBLIC-var-only drift hazard are gone
- src/lib/hosted.ts owns the client IS_HOSTED flag (was 6 copies)
- request-context.ts gains getActiveUserId/requireActiveUserId/
  bindUserContext; the ~8 hand-copied userId binders are deleted
- doc-name.ts owns the <userId>:<tabId> encoding (was 3 implementations,
  including a separate dirty-key scheme in ydoc-persistence)
- claude-models.ts owns the model policy (isClaudeModelBlocked,
  hostedClaudeDefault, resolveHostedClaudeModel); render, /api/models,
  and stores.ts reuse it, /api/models now filters server-side
- provider stores bind their DB handle at construction, deleting the
  withContext re-wrapping in three files
- ws-server: dead resolveDocContext path removed; Clerk WS auth moved to
  clerk-auth.ts; explicit handleWsUpgrade replaces server.js reaching
  into Hocuspocus internals

Client:
- root +page.server.ts delivers the Clerk userId via load data; yjs-doc
  no longer reconstructs identity from an async fetch or window.Clerk
- authFetch() wrapper replaces five copy-pasted auth-recovery blocks
- HostedAccountButton slimmed (single identity source, lazy Clerk load,
  no impossible signed-out branch); sign-in redirect helpers collapsed
  and redirect_url honored behind the origin check; shared
  clerk-params.ts for handshake params
- /api/auth/status caches the user summary (one Clerk call per user)

Deploy/infra:
- DEPLOY-PLAN.md (stale) replaced by an accurate DEPLOY.md
- workflow reuses scripts/deploy-fly.sh; sync-landing runs npm run check
  before pushing (that push deploys production)
- flyctl action and claude-code install pinned; /api/health route plus a
  fly.toml health check; .dockerignore covers docs/e2e/.github/*.md
- six unused DOCWRITER_RUNNER_MAX_* env knobs removed; per-request
  workspace migration probes memoized; assorted dead code deleted

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
Resolves the sync-landing.yml conflict by keeping both sides: the bot
runs main's copy of the merge script (from landing) and the merged tree
is type checked before the push that triggers the production deploy
(from this branch).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
The subset of the codebase audit that depends on the hosted overlay
(auth-recovery, request-context, doc-name) and so stays on this branch;
the hosted-independent fixes went to the codebase-refactor branch off main.

Auth-aware fetch (hosted 401/403 recovery only works in hosted mode):
- Add apiJson() to auth-recovery; adopt authFetch/apiJson across the root
  page (27 sites) and the settings panels (Hooks, References, ApiKeys,
  Rules, Skills, FileTree writes, CommentGutter reply). Previously an
  expired session mid-edit just console.error'd forever.
- Extract shared rules-actions (save/add/remove/apply) so RulesPanel and
  RulesPillBar stop duplicating the logic and the agent prompt strings.

Multi-tenant server correctness:
- activeFeedbackThreadId was a module global shared across concurrent
  renders (two hosted users, or user+warmup, stomped each other's edit-
  thread target). Move it into an AsyncLocalStorage cell scoped per render.
- api/comments bypassed docNameForTab, so in multi-tenant mode user
  comments could target the wrong document. Route through the shared
  live-doc helper.
- Consolidate the live-or-replay Hocuspocus reader (repeated in render,
  mcp-doc-tools, and comments) into src/lib/server/live-doc.ts, keyed by
  docNameForTab.
- Align tool-handlers' edit_doc/comment_doc to mcp-doc-tools (restore the
  feedback-thread default instead of discarding it; add the missing
  mutator-aborted branch; consistent occurrence validation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qn9Y2sWV7xtkWDbvbmsmVf
@shreyashankar
shreyashankar force-pushed the codex/landing-hosted-split branch from fbbd827 to 763554d Compare July 6, 2026 17:20
shreyashankar added a commit that referenced this pull request Jul 9, 2026
…page

Remove the Clerk auth layer (clerk-client, clerk-auth, /sign-in route, the
auth handle hook, App.Locals.auth type, and @clerk/* deps) and the Cloudflare
DNS tooling (deploy/cloudflare, cf: scripts, wrangler). The full hosted
deployment lives in PR #51 (codex/landing-hosted-split).

landing now = main + the static /welcome page, deployed to Vercel via
adapter-vercel (LANDING_DEPLOY=1). The IS_HOSTED_LANDING guards in
hooks.server.ts stay so the editor/WebSocket server doesn't boot during the
static build. Validated with npm run check (0 errors) and npm run build:landing
(prerenders /welcome, exit 0).
Resolves the conflicts that made PR #51 unmergeable after landing was rebuilt
(main merged in + hosted stack stripped from the base landing branch).

Resolutions:
- Core files where PR #51 carried only stale pre-refactor text (CLAUDE.md,
  mcp-doc-tools.ts, api/render prompt wording): took main's current version.
- Provider/model UI: main relocated it into ModelPicker.svelte, which reads the
  hosted-aware AVAILABLE_PROVIDERS from stores.ts, so PR #51's obsolete context
  -menu provider/model block was dropped (the hosted claude-lock still applies
  via AVAILABLE_PROVIDERS/PROVIDER_LOCKED_TO_CLAUDE). Removed the now-unused
  ALL_PROVIDERS / HOSTED_CLAUDE_MODEL_NOTE imports in +page.svelte.
- hooks.server.ts: unioned imports (main's loadRepoEnv + hosted clerk/
  isMultiTenant) and restored the Clerk handle export the auto-merge dropped.
- Restored hosted files/deps the auto-merge silently dropped because landing had
  deleted them: clerk-client.ts, sign-in/+page.ts, deploy/cloudflare/*,
  @clerk/* deps, wrangler, cf: scripts, and App.Locals.auth in app.d.ts.
- api/render: rebuilt on main's refactored endpoint and re-applied PR #51's
  isMultiTenant-gated hosted behavior (run_bash gating, provider-lock coercion,
  resolveHostedClaudeModel, hosted shell/scratch instructions, hostedAllowedTools).

npm run check passes (0 errors).

KNOWN GAP (needs follow-up): PR #51's deeper multi-tenant render rearchitecture
was NOT re-applied on top of main's refactor — per-user effective roots
(getEffectiveRoot/getEffectiveScratchDir), the withLiveTabDoc live-doc helper,
and per-render session ownership (setSessionOwner/getSessionProvider/
getSessionModel). The render path currently uses main's single-tenant
AGENT_SCRATCH_DIR + session handling. The helpers exist in the tree; wiring them
through the handler is required before the hosted multi-tenant deploy is correct.
The prior merge based api/render + mcp-doc-tools on main's single-tenant
versions and re-applied only the isMultiTenant gating, dropping PR #51's
multi-tenant rearchitecture. Since main's delta to these files since the fork
point was tiny (render: 37 lines, all the comment_doc feature) while PR #51's
was large (306 lines of multi-tenant), the correct base is PR #51's version
with main's comment_doc delta merged in — done here via a 3-way merge
(base 4e5d845, ours=PR #51, theirs=main), resolving all conflicts toward
PR #51 to keep the render internally consistent (its per-turn prompt emits
'Autonomy:', matching its own system-prompt guidance).

Restores:
- Per-user workspace isolation: getEffectiveRoot / getEffectiveScratchDir
  (resolve per-user via the runWithUser context clerk-auth establishes), so
  concurrent hosted users read/write only their own workspace + scratch.
- Live-doc reads via withLiveTabDoc (in-memory Hocuspocus doc, SQLite replay
  fallback) instead of main's direct replayUpdatesInto.
- Per-render session ownership: setSessionOwner / getSessionProvider /
  getSessionModel, so concurrent renders don't clobber each other's provider
  /model.
- Concurrency-safe feedback-thread context: mcp-doc-tools now uses the
  request-context AsyncLocalStorage (getActiveFeedbackThreadId) instead of a
  module-global, matching the render's runWithFeedbackThread wrapping — so two
  concurrent renders can't stomp each other's default comment thread.

main's comment_doc tool + the isMultiTenant-gated hosted behavior (run_bash,
provider lock, resolveHostedClaudeModel) are preserved.

Validated: npm run check (0 errors) and npm run build (exit 0).
Match the published shreyashankar/plain-writing-skill: four rule groups (word
choice, sentences and paragraphs, punctuation and formatting, patterns to
avoid), a before and after under each of the 22 rules, new rules for paragraph
structure and vague demonstratives, and the fixed example pairs.
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.

2 participants