ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
A LangGraph agent that turns raw Wanderlearn captures into publishable lesson drafts through a research, write, and self-critique reflection loop.
EducationTypeScript · CSSGitHub @dapperAuteurOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
A LangGraph agent that turns a raw Wanderlearn capture (location transcript, GPS, photo metadata) into a publishable lesson. The agent researches the location, drafts an outline, writes a script with citations, then self-critiques against a rubric and revises until it passes — or hits a max revision count.
Loading the full README.
Read the full README ↗A LangGraph agent that turns a raw Wanderlearn capture (a location transcript, GPS, and photo references) into a publishable lesson draft. The agent researches the location, drafts an objectives-first outline, writes a cited lesson, then self-critiques against a rubric and revises until the draft passes or hits a revision cap.
Part of the WitUS ecosystem; a sibling of Wanderlearn.
Live: https://wanderlearn.field.reporter.witus.online
New here? The in-app /help page onboards three
readers (visitors browsing reports, people creating lessons, and operators
running the app) without needing this README. This README is the deeper
engineering reference.
research → outline → write → critique → ┬ pass → image prompts
▲ ├ fail → revise (loop)
└────────────────┘ give up → human review
critique scores the draft against the rubric in
src/agent/rubric.ts, the single source of truth for
lesson quality. A failing score loops back to write; after MAX_REVISIONS (3)
failed attempts the graph routes to human review instead of looping forever.
research gathers material from three tools: Tavily web search (capped at 5
calls per run by a node-level guard), Cloudinary photo metadata, and the
Wanderlearn course catalog. Then the LLM synthesizes the facts.
Each run picks its LLM provider (Claude Sonnet 4.6 or Gemini 2.5 Flash) so draft quality can be compared side by side.
/field-report lists every report. Submit a capture at /field-report/new,
then scrub a report's revision history in the side-by-side viewer at
/field-report/:id to see how each critique cycle changed the draft.
The read-only views (the report list and individual lessons) stay public so
visitors can browse the agent's work without signing in. The cost-incurring
paths (the capture form at /field-report/new and the POST /api/field-report/generate endpoint) are single-user: the one address in
ADMIN_EMAIL signs in through an emailed magic link, a jose-signed JWT
session, a single-use token, Mailgun delivery, no password. The gate lives in
src/proxy.ts; the auth module is
src/lib/auth/.
Non-admins who reach the sign-in screen can join a waitlist instead of being
turned away; signups are reviewed in the /admin dashboard and forwarded to
WitUS Inbox. A persistent global navigation header ties the console together.
When WITUS_OIDC_CLIENT_ID is set, /signin also offers Sign in with WitUS —
an OIDC authorization-code + PKCE flow against accounts.witus.online
(src/app/api/auth/witus/) that ends by minting the
same wlfr_session cookie the magic link does, behind the same ADMIN_EMAIL
gate. SSO widens nothing. Two behaviours ride on it, both dark without that env
var (see src/lib/witus-sso.ts):
/signin; you stay signed in to WitUS. When SSO is configured, Sign out of
WitUS everywhere sits beside it with the help text "Also signs you out of
WitUS. Other WitUS apps you are signed in to stay signed in until you sign out
of them." It destroys the local session first and hands off to the IdP
second, so an unreachable IdP still leaves you signed out here.Both depend on NEXT_PUBLIC_SITE_URL exactly matching the origin the WitUS IdP
has registered for this client; a mismatch fails closed. See
plans/user-tasks/14-confirm-site-origin-for-witus-sso.md.
Crash reporting goes to Better Stack, which ingests
the @sentry/nextjs SDK format (so the code, the config files, and the env var
names are the Sentry ones; only the DSN is Better Stack's). Wiring lives in
sentry.server.config.ts, sentry.edge.config.ts,
src/instrumentation.ts,
src/instrumentation-client.ts, and the root
boundary src/app/global-error.tsx.
It is inert until a DSN is set. With no SENTRY_DSN /
NEXT_PUBLIC_SENTRY_DSN, init() is never called: nothing is sent and nothing
changes for a visitor. Errors only, no tracing (LangSmith already owns run-level
observability here) and no session replay.
Every event passes through src/lib/sentry-scrub.ts
first, which matters more in an LLM app than a CRUD one:
This is the beginning of the README. Read the rest at the original. Read the full README ↗