demarkus-library — Roadmap & Resume
Pick-up-where-we-left-off doc. Authoritative plan is /plans/universe-library.md; this tracks status, the Phase 1b breakdown, and which tasks to run on Claude Fable 5 vs Opus 4.8.
Where we are (2026-06-10, end of session)
- Phase 0 — foundation spike: DONE, merged to
main. - Phase 1a — reading room (features-first): DONE, merged to
main(PR #2). Built over the current direct-QUIC world adapter. Working today:/default doc ·/d/<path>document or stacks listing (path ending/) ·/search?q=card catalog (LOOKUP, debounced htmx, click-through, and a real<form>so it works without JS) ·/versions/<path>editions ·/health.- Link rewriting maps internal doc/dir/version links → in-app
/d/<path>. - htmx fragment-vs-page: targeted swaps return the
contentpartial; boosted nav + no-JS return the fullpage. One render path, degrades without JS. - x/net on v0.56.0 (CVE-patched),
govulncheckclean.
How to resume (runs today, direct-QUIC, no auth)
cd ~/latebit/demarkus-library
go test ./... && go build -o /tmp/demarkus-library ./cmd/demarkus-library
PORT=8080 DEMARKUS_INSECURE=true DEMARKUS_HOST=soul.demarkus.io \
DEMARKUS_DEFAULT_DOC=/index.md \
DEMARKUS_AUTH=<token from .mcp.json> /tmp/demarkus-library
# open http://localhost:8080
.mcp.json (gitignored) holds the soul read token. The repo depends on the local
demarkus checkout via replace → ../demarkus (client + protocol modules).
File map (hexagonal — see ADR 0002)
internal/core/domain— entities + sentinel errors (no external deps)internal/core/port/port.go—ReadingService(in);WorldGateway,Renderer(out)internal/core/service/reading.go— Read/Browse/History/Searchinternal/adapter/inbound/web— Echo handlers/routes,view.go,links.go, templatesinternal/adapter/outbound/world— direct-QUIC gateway (Fetch/List/Versions/Lookup)internal/adapter/outbound/markdown— goldmark + bluemondaycmd/demarkus-library— composition root + envAppConfig
Phase 1b — the library card (NEXT)
Add org-scoped auth + a broker transport, then gate the reading room behind login. The hexagonal split means this is a new outbound adapter + session, swapped at the composition root; the core and web reading-room logic do not change.
Broker (source: ~/latebit/demarkus/tools/demarkus-broker/internal/broker/):
standard OAuth surface — /.well-known/oauth-authorization-server,
/.well-known/oauth-protected-resource, /authorize, /token, /register
(RFC 7591 DCR), /auth/callback — plus the /mcp gateway (14 tools:
mark_fetch/list/versions/lookup/...). This is the same path Claude Code's MCP SDK
authenticates through (plan: "MCP session model = same as the broker").
Tasks — and who runs them
Run on Claude Fable 5 (the escalation valve — transport + auth-session design, one-shot correctness, refresh/concurrency; per the plan's build-model strategy):
- Broker MCP client (Go). Speak MCP over HTTPS to the broker
/mcpwith a bearer token; call the read tools. Replaces the direct-QUIC fetch client as the transport. Decide the client lib (mcp-go, already a demarkus dep) vs hand-rolled. Hardest, load-bearing — design it on Fable. - Org OAuth login (auth-code + PKCE + DCR).
/registerfor a client, build the authorize redirect with PKCE S256, handle/auth/callback, exchange code→tokens. Correctness-critical and one-shot — Fable. - Token refresh + session lifecycle.
grant_type=refresh_token, expiry/renew, revoke on logout. Refresh races are bug-prone — Fable.
Run on Opus 4.8 (mechanical once the above exist):
- Broker
WorldGatewayadapter. Implementport.WorldGatewayover the MCP client + the request's session token. Newinternal/adapter/outbound/broker/. - Cookie session store. Server-side session holding tokens (never to the browser — the XSS boundary); Echo session middleware; login/logout routes.
- Login turnstile + UI. htmx-hard login page; middleware redirecting unauthenticated users; logout. Keep ADR 0003 (degrade without JS — real form).
- Composition-root swap. Env flag selects direct-QUIC vs broker adapter so the Phase-0/1a demo path still works.
- Resolve the open question (below) — investigation, Opus.
Open question to resolve in 1b
Does the broker expose any anonymous-readable surface? Decides whether login is
a hard gate or reads can be unauthenticated. Check mcp_auth.go / mcp_gateway.go
in the broker source (is /mcp always auth-gated?). Not blocking 1a.
Deferred backlog (not 1b core)
- Backlinks / "cited by" — no server verb; needs a graph crawl (client
graphpackage doesCrawl()). Plan defers the force-directed viz. - Multi-world directory / floor — enumerate worlds from the
roothub; cross-worldmark://<world>/...link rewriting (link rewriting is single-world today). - Phase 2 restricted collections; Phase 3 cataloging desk (writes, CodeMirror island); Phase 4 AI librarian (SSE); Phase 5 public face.
Git / process notes
mainhas Phase 0 + 1a. Work Phase 1b on afeature/phase-1b-*branch.- Never auto-commit — Fritz always commits (global rule). Prepare changes,
he commits + opens the PR; CodeRabbit reviews via
.coderabbit.yaml. - PR titles use conventional-commit scopes: domain, port, service, web, world,
markdown, cmd, view, deps, ci (+ add
broker,authfor 1b).