Skip to content

Add /lorekit-self-host skill and make install.md self-host-correct - #694

Merged
mthines merged 19 commits into
mainfrom
feat/lorekit-self-host-skill
Oct 17, 2026
Merged

mthines merged 19 commits into
mainfrom
feat/lorekit-self-host-skill

Conversation

@mthines

@mthines mthines commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Today's install.md points a self-hoster at the hosted project
(pqokxlhvnosogizsjztg) in nine places, a token minted on lorekit.io
can't authenticate their own deployment, and the documented deploy step
only ships mcp + health — leaving memories (hooks, remote CLI
commands, the dashboard's REST API) undeployed.

This adds a guided /lorekit-self-host skill (a gated runbook — do the
step, verify it, stop and diagnose on failure), a public /docs/self-host
page comparing Hosted / Full self-host / Self-host + BYOD, and fixes
install.md throughout to use <your-project-ref> with an all-functions
deploy step and a token-minting flow that actually targets your own
project.

The skill links to install.md/byod.md rather than duplicating their
commands, and is deliberately not added to the CLI's SKILLS list
(D2 in the plan) — adding it there would turn every existing install's
lorekit doctor red until a re-install, for a runbook most users only
need once. It still ships via the Claude plugin and the npm tarball.

Added test coverage in install.test.mjs (extending the file that
already owns --endpoint coverage, not a new harness): a self-hosted
--endpoint is written verbatim and mcpToRestBase() derives the
matching REST base, omitting --endpoint still falls back to the hosted
URL, and the new skill is never scaffolded by a fresh install.

The docs now state the real precedence rules, checked against config.mjs:

  • install reads only --endpoint, then LOREKIT_MCP_URL, then LOREKIT_ENDPOINT. Almost every install rewrites the MCP entry: a new project, global, --force, --hooks, --mcp-json, --completions <shell>, or a re-run after an upgrade adds a skill. Without --endpoint it writes the hosted URL. Only a plain re-run on a fully installed project leaves .mcp.json alone.
  • The self-host page's next steps say token scoping and CI work unchanged against a self-hosted endpoint, but the GitHub App needs its own registration and GITHUB_APP_ENABLED=true.
  • Health returns "db":"ok" (503 "db":"error" on failure). The skill's Step 8 gate also checks the /mcp suffix, because doctor probes over REST and can't see it.
  • Hooks and remote CLI commands check the project .mcp.json, then ~/.claude.json, then mcp.endpoint in .lorekit.json. A leftover hosted global install therefore wins over a committed mcp.endpoint, and the docs tell the reader to re-run it with --endpoint.
  • A local dashboard (pnpm nx serve web) runs on port 4200, and the auth callback URLs use it.

CLAUDE.md and docs/decisions.md now allow <your-project-ref> in self-host instructions (install.md, byod.md, the skill, the self-host page). The concrete hosted URL is still mandatory wherever the hosted endpoint is meant.

Verified end to end with /local-verify on a fresh local Supabase stack, following the docs literally. Two legs passed:

The run's doc fixes are folded in. The {"db":false} row in install.md's Troubleshooting table is left for #690, because that row sits inside #690's hunk of the file. Report: the local-verify comment on this PR.

Follow-up, out of scope here: supabase/project.json's fn:deploy
target still only deploys mcp + health — this PR documents the
all-functions supabase functions deploy command as the self-host path,
but doesn't change the NX target itself.

Separate from #690 (BYOD schema rewrite). Both PRs edit docs/install.md, so expect a merge conflict in whichever lands second. This PR doesn't touch docs/byod.md.

🧪 UI verification spec — run against the preview deployment

Target: preview
Format: intent

Spec 1: A visitor reads the new self-hosting comparison page

Changed: the new /docs/self-host page and its "Self-hosting" entry in the docs nav
Start: /docs/remote
Steps:

  1. Open the docs nav rail (or the ⌘K docs command group).
  2. [must-follow] Navigate to the "Self-hosting" entry, directly after "Remote storage".
    Expected:
  • The page renders at /docs/self-host with the title "Self-hosting".
  • A comparison table is visible naming "Hosted", "Full self-host", and "Self-host + BYOD".
  • The page links out to docs/install.md and docs/byod.md on GitHub, and mentions /lorekit-self-host.
    Hints:
  • The nav rail renders every DOCS_SECTIONS entry as a /docs/<id> link (see SectionNav).
    Out of scope:
  • The actual deployment steps the page links to (covered by the /lorekit-self-host skill, not browser-testable).

…s page, and self-host-correct install.md

Today's install.md points a self-hoster at the hosted project in nine
places, a lorekit.io-minted token can't authenticate their own project, and
the default deploy only ships mcp + health (missing memories, which hooks,
remote CLI commands, and the dashboard REST API depend on). Adds a guided
/lorekit-self-host runbook, a public /docs/self-host comparison page, and
fixes install.md to use <your-project-ref> throughout with an all-functions
deploy step.
…default

Extends install.test.mjs — the file that already owns --endpoint/.mcp.json
coverage — rather than inventing a new harness: a self-hosted --endpoint is
written verbatim and its REST base derives correctly via mcpToRestBase,
omitting --endpoint still falls back to the hosted URL, and the new
lorekit-self-host skill is never scaffolded by a fresh install (D2).
@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

The dashboard preview for this PR — redeployed on each push that changes the web app.

Project Deployment Actions Updated
lorekit Ready Ready Preview Oct 17, 2026 10:49am UTC

Preview always points at this PR's latest commit; Deployment is the immutable build of 22f1140. · Comment /web-preview to force a redeploy. · Workflow logs

@mthines

mthines commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner Author

✅ No issues found

The delta fixes the last open finding: the self-host page now says the GitHub App needs its own registration and GITHUB_APP_ENABLED. Every review thread is resolved and nothing new turned up.

Checked: 1 of 1 changed file read · 0 of 4 dependent files traced · no possible issues found

Progress: open review threads 0 → 1 → 2 → 1 → 0 across the last 5 reviews

What this change reaches — 1 changed export · 4 dependent files · 0 checked · 4 not checked
flowchart LR
  subgraph pr["Changed in this PR"]
    s1["DOCS_SECTIONS<br/>body changed"]:::changed
  end
  s1c1["packages/web/src/app/docs/page.tsx<br/>? not checked"]:::unknown
  s1c2["packages/web/src/components/command/NavigationCommands.tsx<br/>? not checked"]:::unknown
  s1c3["packages/web/src/components/docs/DocsCommands.tsx<br/>? not checked"]:::unknown
  s1c4["packages/web/src/lib/docs/sections.spec.ts<br/>? not checked"]:::unknown
  s1 -.-> s1c1
  s1 -.-> s1c2
  s1 -.-> s1c3
  s1 -.-> s1c4
  classDef changed fill:#eef2ff,stroke:#6366f1,color:#1e1b4b
  classDef ok fill:#e7f6ec,stroke:#16a34a,color:#14532d
  classDef partial fill:#fef9c3,stroke:#ca8a04,color:#713f12
  classDef unknown fill:#f3f4f6,stroke:#9ca3af,stroke-dasharray:4 3,color:#374151
  classDef bad fill:#fde8e8,stroke:#dc2626,color:#7f1d1d
  classDef warn fill:#fff4e5,stroke:#d97706,color:#78350f
  classDef imports fill:#f8fafc,stroke:#64748b,stroke-dasharray:4 3,color:#1e293b
Loading
  • DOCS_SECTIONS (packages/web/src/lib/docs/sections.ts) — body change · 4 consumer files · 4 not traced
Review details
Gate Status Details
Description vs. code ✅ Description matches the diff: skill, /docs/self-host page, install.md self-host fixes, tests.
Prior review feedback ✅ Earlier review comments are resolved.
Documentation ✅ The new self-host page names what the GitHub App needs and links the guide.
Self-review signals ✅ No debug logs, leftover TODOs, or unreviewed stubs.
Code review ✅ The multi-lens review found no blocking issues.

Found

Quality — produced 0 → posted inline 0 · cleared 0 · carried forward 0 · deferred 0 · below-bar 0
Standards — ran — delta checked against 3 governing docs, no findings

Run

incremental · 6 lines in delta · tier standard · depth checkout
Integrations — not activated — no manifest or lockfile in the delta
CI — still pending: Typecheck, Test & Lint (affected), Web — Storybook interaction + visual tests (changed), Web — Vercel preview (changed) / Deploy Vercel preview · 12 passed
Memories — no relevance rules or lessons consulted

Nothing to report — optimality (skipped), measurability (skipped), severity, 0 files skipped.

pr-reviewer · commit 22f1140 · incremental review, delta since 0c3ebe8 · how these findings are produced · updated Oct 17, 2026 10:48am UTC

Comment thread docs/install.md Outdated
Comment thread packages/cli/skill/lorekit-self-host/SKILL.md Outdated
Comment thread packages/web/src/content/docs/self-host.mdx Outdated
Comment thread packages/web/src/content/docs/self-host.mdx Outdated
Comment thread CLAUDE.md
Comment thread packages/web/src/content/docs/self-host.mdx Outdated
…failure

The health function answers 200 {"status":"ok","db":"ok",...} and
503 {"status":"degraded","db":"error",...}. install.md's Step 6 and
smoke-test blocks, the self-host page, and the skill all promised
"db":true / "db":false, so a self-hoster comparing output literally
would read a healthy deploy as wrong. Found by local-verify.

The Troubleshooting row is left for after #690 lands: that table sits
inside #690's install.md hunk.
…a phone

At 390px the inline 57-character URL in the opening callout could not
wrap, so the whole page scrolled sideways. A fenced block scrolls on
its own, as the other docs pages already do for this URL. Found by
local-verify.
A plain re-run on an already-installed project returns early and leaves
.mcp.json alone. The hosted fallback applies when install WRITES the
entry without --endpoint: a --force reinstall, a new project, a global
install, or a missing entry. The advice (always pass --endpoint or
export LOREKIT_MCP_URL) is unchanged. Found by local-verify.
…k it

lorekit doctor checks connectivity and auth over REST, and the REST base
drops the /mcp suffix, so --endpoint .../functions/v1 passes every
doctor check while mcp-remote gets a 404. Step 8's gate now also checks
the suffix and points at Step 9 as the real MCP check. Found by
local-verify.
Step 9 said to write, read, then delete the test lesson but showed no
delete call. Add memory.delete and note that it archives, so a later
read returns null. Found by local-verify.
@mthines

mthines commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner Author

Local verify — ⚠️ verified with open items

✅ Self-hosting works end to end, following the docs literally. Leg 1 is a full self-host on a fresh project: migrations, all functions, a dashboard sign-up and token, install --endpoint, MCP, REST, hooks, and the dashboard. Leg 2 adds BYOD on a local merge of #690 + #694, with rows landing only in the storage project. The hosted default is unchanged. Following the docs exposed 5 doc errors, fixed in 5 commits; one Troubleshooting row is left for #690 and two pre-existing web issues are reported as follow-ups.

PR #694 · no ticket
Commit verified 1ae4259c (branch feat/lorekit-self-host-skill)
Stack Leg 1: supabase (fresh) + functions + web :4200 · Leg 2: + storage stack :55321, functions from a #690+#694 merge · daemon bound to this checkout
Telemetry default via dash0-dev · 2 loop(s)
Run 2026-10-17T09:49:05Z → 2026-10-17T10:11:12Z

Acceptance criteria

ID Criterion Result Evidence
AC-1 Step 3: a fresh project gets every migration, none pending pass migration list --local
AC-2 Step 6: health 200 + db ok; unauthenticated /memories → 401 pass HTTP 200 / 401
AC-3 Step 7: dashboard on :4200 against the own project → sign up, mint lk_rw_ under Connect your agent pass S-4 · S-5 · S-6 · S-1
AC-4 Step 9: install --endpoint <own>/functions/v1/mcp writes it; doctor passes connectivity + auth pass doctor output
AC-5 Skill Step 9: memory.write / memory.read round-trip over MCP pass JSON-RPC 200
AC-6 Remote CLI list / search over REST see the lesson pass CLI output
AC-7 SessionStart hook injects the lesson from the own endpoint pass hook JSON
AC-8 Full self-host: the dashboard shows the MCP-written lesson pass S-7
AC-9 /docs/self-host renders, nav after Remote storage, comparison table pass S-8 · S-2
AC-10 Hosted default: install with no --endpoint writes the hosted URL pass .mcp.json
AC-11 Leftover global ~/.claude.json beats mcp.endpoint; global re-install with --endpoint fixes it pass CLI output
AC-12 ᴮ BYOD 6.4: lorekit bootstrap with inline storage vars reports the schema state pass CLI output
AC-13 ᴮ BYOD: MCP write lands in the storage project, not the function project pass psql row counts
AC-14 ᴮ BYOD: inline-env doctor prints a passing byod storage line pass doctor output
AC-15 ᴮ BYOD caveat: REST / remote CLI / dashboard do not see the BYOD row pass S-3

ᴮ = Leg 2, self-host + BYOD, on a local merge of #690 + #694 (the BYOD bootstrap changes exist only in #690).

Edge cases

ID Probe Result Evidence
EC-1 --endpoint missing /mcp fixed → pass (F-4) missing /mcp passes doctor, MCP 404; skill gate now checks the suffix
EC-2 token not minted on this project pass foreign token → -32001 'Invalid or unknown API token…'
EC-3 unknown function path pass unknown function → 404, matching the doc's diagnostic
EC-4 lk_ro_ token writes pass lk_ro_ write → -32003 with an actionable message; read still works
EC-5 doctor with no LOREKIT_STORAGE_* pass doctor without LOREKIT_STORAGE_* prints no byod storage line
EC-6 re-run install without --endpoint fixed → pass (F-3) plain re-run keeps the self-host entry; --force / new project → hosted
Not applicable (3)
  • Viewport / a11y beyond the new page: the PR changes no UI component; the MDX page was checked at 390 px (F-2).
  • Concurrency: docs-only PR, no new request paths.
  • A real cloud supabase link / functions deploy: no throwaway cloud project; a fresh local stack stood in, with each cloud step mapped to its local equivalent (db push → fresh supabase start / db push --local; secrets set + functions deploy → functions serve --env-file). CI's deploy.yml runs the same functions deploy command.

Findings

ID Severity Kind What happened Status
F-1 medium functional health returns 200 {"status":"ok","version":"1.0.0","db":"ok","ts":…}; docs/skill/page promised {"status":"ok","db":true} and {"db":false} on failure fixed 39727ba4
F-4 medium functional --endpoint …/functions/v1 (no /mcp) passes every doctor check (REST base is the same) while MCP initialize at that URL returns 404 fixed fe861611
F-6 medium telemetry-error pre-existing: web logged ERROR lorekit.api_token.generate.failed: "revalidatePath /lore during render is unsupported" (tokens.ts via buildOnboardingSteps); a "My first token" row is created but the auto-generated t open (follow-up)
F-2 low ux at 390px the inline hosted URL in the opening callout cannot wrap; page scrollWidth 462 > 390 fixed c417dd3d
F-3 low functional a plain lorekit install re-run on an installed project returns early and keeps the self-hosted .mcp.json entry; only --force, a new project, a global install or a missing entry fall back to the host fixed f2c36428
F-5 low functional Step 9 says write, read back, then delete — but shows no delete call fixed 1ae4259c
F-7 low functional pre-existing: resolveMcpUrls() only handles https://.supabase.co; any other NEXT_PUBLIC_SUPABASE_URL (local stack, Supabase custom domain) yields a mangled snippet URL (https://http://127.0.0.1:54321.supabase. open (follow-up)
F-8 low functional the {"db":false} troubleshooting row has the same wrong shape as F-1 escalated

Fixes

Commit Finding Change Re-verified by
39727ba4 F-1 docs quote the real response shape /docs/self-host renders "db":"ok"; git grep finds no "db":true outside the install.md Troubleshooting row (left for afte
fe861611 F-4 the skill's Step 8 gate catches a missing /mcp suffix Step 8 verify now requires the /functions/v1/mcp suffix and names Step 9 as the real MCP check
c417dd3d F-2 no page-level horizontal scroll at phone width unclipped-overflow probe empty at 390px; sections + mdx-render specs 9/9
f2c36428 F-3 the warning describes when the hosted fallback actually happens wording matches all four probed cases
1ae4259c F-5 the runbook shows every call it asks for memory.delete archives; follow-up read returns null

Screenshots — 8

Screenshots uploaded. Keep the lv:shot markers so a re-run keeps them.

S-1 · F-6 (medium) — web logged ERROR lorekit.api_token.generate.failed: "revalidatePath /lore during render is unsupported" (tokens.ts via buildOnboardingSteps); a "My first token" row is created but the auto-generated token is never shown

S-1-ac-3

S-2 · F-2 (low) — at 390px the inline hosted URL in the opening callout cannot wrap; page scrollWidth 462 > 390

S-2-ac-9

S-3 · AC-15 (pass)

S-3-ac-15-explorer-byod-lesson

S-4 · AC-3 (pass)

S-4-ac-3

S-5 · AC-3 (pass)

S-5-ac-3

S-6 · AC-3 (pass)

S-6-ac-3

S-7 · AC-8 (pass)

S-7-ac-8-explorer-selfhost-lesson

S-8 · AC-9 (pass)

S-8-ac-9

Under the hood

  • Leg 1, full self-host (Add /lorekit-self-host skill and make install.md self-host-correct #694 head): fresh stack, 108 migrations → functions serve (all 8, VERCEL_ENV=production) → dashboard nx serve web :4200 → sign up → mint lk_rw_ → lorekit install --endpoint → MCP write/read → REST (list/search) → SessionStart hook → Explorer. All 15 CLI spans in Dash0 (service.name=cli, deployment.environment.name=local) are OK; 0 ERROR spans.
  • Leg 2, self-host + BYOD (local merge of fix(byod): generate the bootstrap from migrations and fix BYOD's limits #690 + Add /lorekit-self-host skill and make install.md self-host-correct #694, clean, no conflicts): second empty stack → lorekit bootstrap (inline env) → db push + storage-overlay.sql → functions re-served with the Step 6.3 storage secrets → same dashboard token writes over MCP → row in storage project only.
  • Local edge functions ran without OTel export (no OTEL_* secrets, which the docs mark optional), so their side was read from the function logs: 0 error lines in either leg. The dashboard dev server logged one ERROR (F-6, pre-existing).

Open and escalated

Lessons

  • local-verify-lessons::byod-two-stack-topology-on-colima (updated: Colima /private/tmp entrypoint failure, db push --local instead of --db-url)
  • local-verify-lessons::dashboard-accordion-click-before-hydration (new)

Generated by /local-verify · full artifacts in .agent/feat/lorekit-self-host-skill/local-verify/

Comment thread docs/install.md Outdated
…the endpoint

The early return in install only fires for a plain re-run on a fully
installed project; --hooks, --mcp-json, --completions, --force, or a
missing skill all rewrite the MCP entry with the hosted URL when no
--endpoint is given. Say that instead of listing a subset.
Comment thread packages/cli/skill/lorekit-self-host/SKILL.md Outdated
Comment thread packages/web/src/content/docs/self-host.mdx
…ite .mcp.json

Also align self-host.mdx with install.md (--mcp-json, the plain re-run
exception) and make the skill description admit Step 9's throwaway
write/read/delete round-trip.
Comment thread packages/web/src/content/docs/self-host.mdx Outdated
@mthines
mthines marked this pull request as ready for review October 17, 2026 11:27
@mthines
mthines merged commit c2a4196 into main Oct 17, 2026
18 checks passed
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