Work

Software products, research tools, and language-learning projects I have taken from idea to usable release.

  1. №01

    A live trilingual platform that helps Hong Kong researchers publish studies and recruit participants. I built the product, publishing-review process, and a guarded AI review layer that suggests updates only after evidence checks and human approval.

    problem HK research recruitment is scattered across chat groups, ad-hoc forms, aggregate pages, posters, and bilingual source pages; researchers struggle to fill studies, while participants and operators need reliable evidence before anything is published.

    impact Live trilingual platform · 115 merged PRs (latest #120) · solo-built and operated

    role Sole founder & builder — product design, front end, back end, launch, daily maintenance

    stack
    • Next.js
    • TypeScript
    • Tailwind CSS
    • +6
    project screenshots
    UniExp HK landing page with researcher and participant entry points
    Landing page for the trilingual study-recruitment platform.
    case details

    Case study

    solution

    I built the full platform around two simple flows: researchers publish and manage studies; participants browse, sign up, and rate them. An evidence-gated AI review layer sits behind admin review so automation can surface candidates without directly changing production truth.

    my contribution

    • Study posting + time-slot scheduling + enrolment review for researchers
    • Browse / filter / sign-up / rating for participants
    • Full trilingual i18n (EN / 繁中 / 简中)
    • External Study Ops Agent with a layered autonomy ladder: L1 shadow → L1.5 cross-check → L1.6 Codex replacement check → L2 proposal queue → L3 guarded write (≤1 pending item per queue per run)
    • Multi-queue agent: one external entry, internal supervisor + four workers (new_study_lead / published_change / source_candidate / seed_candidate), each bounded to a specific Admin pending table
    • Scheduled guarded review: a daily VPS cron (22:05 UTC) runs the L1 shadow, emits read-only evidence, and writes nothing to production — explicitly not autonomous production control
    • Production Explore truth source, quality workbench, section-level evidence, signup freshness, visual/OCR/QR review, and a feedback-audit ledger

    technical evidence

    • Agent safety model: every queue proposal passes a deterministic evaluateQueueProposalPolicy() gate that stamps writeEligible; L1 only writes local noProductionWrite=true reports; autonomy stops at Admin pending queues — experiments, source registry, and approve/reject stay human-reviewed
    • Truth discipline: production Explore (published experiments) is the only source of truth; the legacy pipeline, source/seed discovery, and agent shadow reports are candidate generators, never allowed to overwrite truth
    • Evaluation & readiness gates: daily-cron evidence distinguishes real_cron from manual runs; L3 readiness requires ≥10 reviewed proposals, ≥80% acceptance, zero stale/bad-source false positives, and no production-write incident over 30 days
    • Failure→gate discipline: a proposal that mistook an HKD 80 baseline for the total compensation became a permanent compensation-component policy check, downgrading that class to report-only
    • Reasoner reliability: the Gemini reasoner must return structured JSON; on bad output or failure it falls back to a deterministic reasoner and keeps running read-only — model participation never implies execution permission
    • Self-hosted Supabase (auth + Postgres + maintenance) + Cloudflare for edge acceleration and abuse protection; sustained solo through 115 merged PRs (latest #120, Cloudflare deploy Node patch)
  2. №02

    Role Fit turns pasted or uploaded JDs into source-backed fit briefs for recruiters; the same han-dong.link system also pairs a live Q&A assistant for source-backed answers with a Three.js cockpit for profile, work, research, and CV.

    problem A public portfolio has to serve recruiters, technical peers, and research collaborators without making them guess which evidence supports each claim. Static pages can list work, but they rarely answer role-specific questions or show how the site itself organizes evidence.

    impact Live on han-dong.link · homepage cockpit entry with live portfolio counts · answer cards cite source pages · visible answer trace · Role Fit turns JD text or files into strengths, adjacent evidence, gaps, and questions

    role Sole builder — interactive cockpit UI, Three.js navigation, Q&A and Role Fit agent loops, source-backed answer cards, file/JD guardrails, deployment

    stack
    • TypeScript
    • Astro
    • React
    • +7
    project screenshots
    han-dong.link cockpit with four planets, navigation, Q&A assistant, and Role Fit JD matching
    The spatial cockpit is the default portfolio entry.
    case details

    Case study

    solution

    I built a spatial cockpit plus canonical read-mode pages, then connected both to the same Astro content collections that power Q&A and Role Fit. The portfolio can be browsed visually, read linearly, or queried through evidence-backed cards.

    my contribution

    • Spatial portfolio cockpit: a Three.js experience around the assistant, with four planets for profile, work, research, and CV, plus read-mode pages for reduced-motion, mobile, and no-WebGL contexts
    • Five typed tools (getProjects / getPublications / getStack / getTimeline / getContact) the LLM chooses between per question, with a prose fallback
    • Role Fit agent: a dedicated `/role-fit` page accepts pasted JD text or PDF/PNG/JPEG/WebP uploads, then returns an advocacy brief with strong matches, adjacent evidence, honest gaps, and recruiter questions — no percentages or hire/no-hire recommendations
    • Source-linked generative UI: every tool result renders a React card (project cards, publication list, stack chips, timeline, contact) that links back to its canonical page
    • Visible answer trace: the assistant surfaces the source-backed path from retrieved content to answer cards, so a visitor can see why a response was produced
    • Content collections are the single source of truth — a new project flows into the agent with no retraining and no embeddings
    • Honest persuasion: leads with strengths, acknowledges gaps in one brief clause, and never fabricates facts, titles, or numbers

    technical evidence

    • Progressively enhanced Three.js shell: WebGL/reduced-motion/mobile checks, boot sequence, keyboard and wheel navigation, and a cockpit dashboard that shows live content counts from the same Astro content collections
    • Agent loop: validate input → build a grounded system prompt from collections → LLM tool decision → dedup tool calls → resolve typed tools → render cards + prose
    • Observable agent traces keep the loop inspectable: retrieved collection records, selected tool cards, and final prose remain visibly connected rather than disappearing into a chat-only response
    • Guardrails: input validation (length cap, prompt-injection regex, refuse off-topic and prompt-reveal attempts) plus per-IP rate limiting
    • Role Fit safeguards: JD-specific validation, third-party job-link refusal instead of crawling, PDF/image extraction, evidence allowlisting, numeric/credential claim guards, and site-evidence brief generation when full analysis is delayed
    • Provider-agnostic LLM integration with a deterministic mock fallback, so dev / no-key runs work fully offline
    • Server-rendered on Astro + Vercel; trilingual (EN / 繁中 / 简中); answers render through markdown
  3. №03

    A public, local-first developer tool that checks whether README files, docs, AGENTS.md, CLAUDE.md, examples, API notes, and source-bound documentation still match the repository that exists now. It gives humans, CI, and coding agents the same repo-local evidence before they trust or repair stale context.

    problem Agentic repositories accumulate stale instructions quickly: README commands drift from package scripts, AGENTS.md and CLAUDE.md keep obsolete paths, examples stop matching APIs, and coding agents may trust those claims before checking the source. Evidoc turns that trust problem into a local evidence workflow.

    impact Public v0.3.2 · published on npm as @evidoc/evidoc · CLI, MCP server, Local Web UI, GitHub Action, Local Git Gate · package artifacts for CLI, core, dashboard, local app, MCP server, reports, and review log

    role Sole builder — product framing, CLI, MCP server, local Command Center, GitHub Action, Local Git Gate, release workflow

    stack
    • TypeScript
    • Node.js
    • MCP
    • +5
    case details

    Case study View code

    solution

    I packaged the trust check as a local workflow available from the CLI, MCP server, local web UI, and GitHub Action. Each surface compares documentation claims against repository evidence before suggesting repairs or blocking a gate.

    my contribution

    • CLI workflow for checking drift, running doctor diagnostics, generating repo-local reports, and enforcing local gates from the command line
    • MCP server for coding agents, exposing drift status, scans, diagnosis, doc-fix suggestions, and explicit review logging as bounded tools
    • Bilingual Evidoc Command Center / Local Web UI for repository health, triage, repair prompts, and local-gate visibility
    • GitHub Action for CI-side drift checks, PR feedback, changed-file focus, and compatibility detection for old DriftGuard action references
    • v0.1.0 release that completed the DriftGuard -> Evidoc rename across CLI, npm packages, .evidoc state, MCP, GitHub Action, local app, and docs
    • npm scoped publication as @evidoc/evidoc in v0.3.x, after the Evidoc namespace migration, topological npm publication, and hardened 0.3.2 release flow

    technical evidence

    • Repo-local evidence model: compare commands, paths, symbols, package scripts, frontmatter source bindings, API surfaces, and changed files before trusting documentation claims
    • Agent-safe defaults: read-only checks by default, explicit write boundaries for review logs and repair proposals, and no reliance on remote project knowledge
    • Repair workflow separates evidence, diagnosis, and patch suggestions so generated fixes remain reviewable instead of silently rewriting repository truth
    • Release hardening covered doctor readiness, scoped package artifacts, GitHub Action behavior, and docs aligned with the current scoped npx and local GUI paths
  4. №04

    A local-first academic evidence workspace that audits claims and citations against source evidence with a deterministic NLI judge. It ships as an Electron desktop app plus MCP-capable core, with external scite/Consensus evidence search kept explicitly opt-in.

    problem Citation auditing and literature review are error-prone at scale: LLMs hallucinate support where none exists, and 'supports' from a lexical judge is meaningless if it can't detect contradiction. Every claim needs a grounded locator, not a model guess.

    impact 317 offline tests · 42-claim hand-labeled gold set · latest packaged release for macOS arm64 / x64 / universal

    role Sole builder — architecture, core pipeline, Electron app, MCP server, evaluation framework

    stack
    • TypeScript
    • Electron
    • MCP
    • +9
    project screenshots
    D-academic-agent citation audit workspace with evidence verdicts
    Citation checking against imported source evidence.
    case details

    Case study View code

    solution

    I built a local-first pipeline that ingests papers, retrieves evidence, judges claims with deterministic NLI, and exposes verdicts with snippets and locators. External evidence search stays opt-in, so private drafts and libraries are not sent out by default.

    my contribution

    • Draft Citation Audit — per-sentence: each citation is resolved to a source, judged (supports / weakly_supports / unsupported / contradicts / unclear) with a verbatim snippet, a structured char-span locator, a confidence, and a suggested rewrite; corpus counter-evidence surfaces when other sources push back
    • Thesis Review — decompose thesis → retrieve evidence → judge each piece → consensus verdict (supported / contested / refuted / insufficient) with ratio and decisiveness over a supporting-vs-contradicting evidence map
    • Hybrid retrieval — BM25 + dense vectors (local ONNX: all-MiniLM / bge-small / nomic, role-aware) fused with reciprocal-rank fusion; locator survival from page to char span
    • Offline-first judge — deterministic DeBERTa-NLI (zero external calls) as default; OpenAI-compatible and Ollama one-click preset for cloud/local LLM judges
    • Persistent library — PDF drag-drop ingest (GROBID section-aware + unpdf fallback); local SQLite (Source / Chunk / vectors); re-index on embedder switch
    • Iterative agent-loop checker — when top evidence is inconclusive, examines next-ranked candidates with traced steps; failure-mode is measured and exposed as a diagnostic
    • Three-axis evaluation: accuracy (macro-F1 + per-class + confusion matrix), faithfulness (answer_groundedness), and governance (policy_compliance: grounded-locator rate + snippet-only rate + outbound chars)
    • Provider ablation runner — compares hash+mock vs all-MiniLM+NLI vs agentic on all three axes; local-vs-cloud and single-shot-vs-agentic trade-offs, quantified
    • Writing Desk — paste a paragraph: it splits and classifies claims (causal / comparison / method …) and flags needs_citation / overclaimed / contradicted against your library, with safer-wording rewrites; per claim, find external evidence via an editable, disclosed query
    • External research & reference health (opt-in) — search scite / Consensus in-app for candidate external evidence; surface scite's citation analysis as a risk badge (no major concerns / some pushback / notable concerns / retracted or serious notice) with support / contradict / mention counts and retraction notices, in three places: on search results, on your imported library papers (catch a retracted work before you cite it), and on a paper's GROBID-parsed bibliography
    • Reusable MCP OAuth — an OAuth 2.1 PKCE + Dynamic Client Registration browser sign-in (built on the MCP SDK) for OAuth-gated MCP servers: a 127.0.0.1 loopback flow, tokens stored only in the keychain, the worker handed nothing but a bearer access token
    • Desktop release pipeline — packaged the latest public release for macOS arm64 / x64 / universal so reviewers can inspect the workspace as a real app instead of only a source checkout

    technical evidence

    • Shared core, two faces: pure-TS engine in src/ (ingest · retrieve · check · plan · eval · trace); MCP server and Electron app are thin adapters — src/ never imports Electron
    • Determinism from offline mocks (HashEmbedder / MockJudge / MockPlanner); model-loading tests are environment-gated so CI stays fully offline
    • Gold set: 42 hand-labeled claims with integrity-gated sources.lock.json; gold must be human-labeled, never self-graded by the model under test
    • Opt-in egress with a hard boundary — external calls fire only on an explicit action and send only the query or public DOIs, never the corpus or draft (the one exception, Writing-Desk evidence search, sends an editable, disclosed query); OAuth tokens stay in the keychain, reach the worker only as a bearer scalar, and are redacted at every boundary
    • Secrets in OS keychain (Electron safeStorage) — never in config, git, traces, or logs; 317 tests across retrieval, checking, eval, trace, and the external-research layer, all offline (live-network smokes are environment-gated)
    • Electron packaging covers macOS arm64 / x64 / universal artifacts in the latest packaged release, with source-run fallback kept available for non-macOS targets
  5. №05

    A Claude Code port of the official openai/codex-plugin-cc surface, adapted to drive the local OpenCode CLI. It lets Claude Code hand bounded review, adversarial-review, rescue, transfer, status, result, cancel, setup, and optional stop-time review work to OpenCode, which can front Anthropic, OpenAI, Google, open-weight, and free zen models.

    problem Claude Code needed a controlled way to use a second model without leaving its local workflow or losing ownership of context. The risk was handing too much scope to another tool.

    impact Public v0.1.1 · port of the official codex-plugin-cc surface · multi-provider second-model delegation · optional stop-time review gate

    role Sole adapter and maintainer of the Claude Code port — OpenCode CLI wiring, command surface, job ledger, privacy boundary, stop-time gate

    stack
    • JavaScript
    • Node.js
    • Claude Code Plugin
    • +2
    case details

    Case study View code

    solution

    I ported the official command surface to OpenCode CLI and kept job control, stop-time review, and privacy boundaries explicit. Claude Code remains responsible for files, git, verification, and final judgment.

    my contribution

    • Claude Code commands for review, adversarial-review, rescue, transfer, status, result, cancel, and setup
    • Bounded delegation to OpenCode across Anthropic, OpenAI, Google, open-weight, and free zen model choices
    • Background job ledger, status/result/cancel controls, and optional stop-time review gate
    • Companion surface for Dong-skills collaboration workflows without moving final ownership out of Claude Code
  6. №06

    A Claude Code port of the official openai/codex-plugin-cc surface, adapted to drive the local Grok CLI headless mode. It mirrors the same bounded review, adversarial-review, rescue, transfer, status, result, cancel, setup, and optional stop-time review flow while adding the grok:grok-rescue subagent.

    problem Claude Code needed a bounded path to ask Grok for review or rescue work without making Grok the owner of local files or git. Manual tool switching weakens scope and evidence tracking.

    impact Public v0.1.1 · port of the official codex-plugin-cc surface · Grok CLI headless delegation · optional stop-time review gate

    role Sole adapter and maintainer of the Claude Code port — Grok CLI headless orchestration, command surface, grok:grok-rescue, job ledger, boundaries

    stack
    • JavaScript
    • Node.js
    • Claude Code Plugin
    • +2
    case details

    Case study View code

    solution

    I ported the official command surface to Grok CLI headless mode, with job controls, a grok:grok-rescue subagent, stop-time review, and explicit boundaries. Claude Code keeps verification and shipping decisions.

    my contribution

    • Claude Code commands for review, adversarial-review, rescue, transfer, status, result, cancel, and setup
    • Native Grok CLI headless mode integration for bounded second-model review and rescue
    • grok:grok-rescue subagent plus status/result/cancel controls for inspectable jobs
    • Optional stop-time review gate that keeps Claude Code responsible for final verification
  7. №07

    A public Codex plugin that lets OpenCode support code review, troubleshooting, and handoff work from inside Codex. It keeps collaboration controllable with job status, cancellation, and a narrow privacy boundary.

    problem Codex and OpenCode are useful in different ways, but switching between them usually loses context and makes reviews harder to track. The goal was to make OpenCode a controlled collaborator inside Codex, with clear job control and a narrow privacy boundary.

    impact Public Codex plugin · tested MCP tools · OpenCode review support inside Codex

    role Sole builder — Codex plugin packaging, MCP tool surface, OpenCode CLI orchestration, transcript boundary, tests

    stack
    • TypeScript
    • Node.js
    • MCP
    • +3
    case details

    Case study View code

    solution

    I exposed OpenCode through Codex MCP tools with capability checks, background job status, cancellation, and transcript boundaries. OpenCode can review or troubleshoot, while Codex keeps final control over files, git, and verification.

    my contribution

    • Codex plugin exposing OpenCode MCP tools: check, run, continue, rescue, review, adversarial review, transfer, status, result, and cancel
    • Background OpenCode job orchestration, so long-running reviews can be polled, inspected, or cancelled from Codex
    • Transcript import with a deliberate privacy boundary: by default, opencode_transfer sends visible user/assistant conversation rather than hidden system, developer, or tool output
    • Review and adversarial-review helpers that make OpenCode useful as a second-pass engineering reviewer before a diff is shipped
    • Prompt-before-file message handling, a file attachment guard, and explicit blocking guidance for prompts that ask OpenCode to inspect Codex private runtime paths

    technical evidence

    • Bundled stdio MCP server written in TypeScript, packaged as a Codex plugin
    • OpenCode CLI discovery, version check, background process management, job ledger, timeout handling, and result retrieval
    • Narrow context transfer by design: the plugin keeps tool output and hidden instructions out of OpenCode unless a future explicit surface supports it
    • Safety hardening after public release: task text stays in prompt before file attachments, the file attachment guard rejects prompt text passed as files, and Codex private runtime paths stay outside OpenCode's read scope
    • Vitest coverage around the MCP tools and the transcript-transfer boundary
  8. №08

    A public Codex plugin that lets Codex ask the local Grok CLI for bounded repo work, code review, rescue analysis, adversarial checks, session inspection, and background jobs without handing over hidden Codex context.

    problem Grok can be useful as another engineering perspective, but switching tools manually makes scope, session history, and review ownership hard to control. The goal was to let Codex ask Grok for help while Codex still owns files, tests, git, and final judgment.

    impact Public Codex plugin · 0.2 with a typed MCP contract and explicit workspace roots · Grok review and rescue inside Codex · bounded second-agent workflow

    role Sole builder — Codex plugin packaging, MCP tool surface, Grok CLI orchestration, privacy boundary, background jobs, tests

    stack
    • TypeScript
    • Node.js
    • MCP
    • +3
    case details

    Case study View code

    solution

    I exposed Grok CLI through Codex MCP tools with capability checks, bounded run/review/rescue wrappers, session listing/export, background status/result/cancel controls, and explicit safeguards around hidden context and private runtime paths.

    my contribution

    • Codex plugin exposing Grok MCP tools: check, models, run, continue, rescue, review, adversarial review, sessions, export, status, result, and cancel
    • Bounded review and rescue helpers, so Grok can act as a second pair of eyes without becoming the owner of the change
    • Background Grok job management with status/result/cancel, so long-running reviews can be inspected before their output is trusted
    • The 0.2 typed MCP contract keeps session listing and export as explicit evidence surfaces, while deliberately still avoiding any claim of a Codex-to-Grok transfer path
    • 0.2 release changes: breaking typed MCP contract, explicit workspace roots, restart-safe background workers, atomic job lifecycle, private prompt staging over fd3, and stricter path, symlink, env, session, and cancel boundaries

    technical evidence

    • Bundled stdio MCP server written in TypeScript, packaged as a Codex plugin with a plugin manifest, skill, MCP config, privacy policy, terms, and security policy
    • Grok CLI discovery, version check, optional model probing, foreground JSON runs, streaming background runs, job ledger, and conservative result-completion detection
    • Privacy boundary by design: prompts do not receive Codex hidden context, tool output, secrets, or Grok auth tokens; private runtime path requests are rejected unless explicitly allowed
    • Verification scripts covering build, typecheck, unit tests, MCP smoke checks, documentation drift checks, and optional authenticated live Grok smoke
  9. №09

    A public personal skills repository that packages agent collaboration discipline for Claude Code, Codex, OpenCode, and Grok with bounded scope, review gates, and explicit verification. It keeps Claude-Codex mutual review, Codex-OpenCode, and Codex-Grok workflows as the named reusable operating rules.

    problem Multi-agent coding work fails when scope, privacy, review authority, and verification are implicit. A second agent is useful only if it receives a bounded packet and its claims are checked against the real repo.

    impact Public skills repository · collaboration workflows across Claude Code, Codex, OpenCode, and Grok · skills aligned with the plugin contract v2

    role Sole author — workflow design, safety boundaries, review protocol, documentation

    stack
    • Codex
    • OpenCode
    • Grok CLI
    • +4
    case details

    Case study View code

    solution

    I turned repeated collaboration practice into explicit skill workflows: define the work packet, constrain what the second agent can see or do, require review gates, and verify every claim against the repo before shipping.

    my contribution

    • Claude-Codex mutual-review workflow for asking one coding agent to review the other's diff without giving up final ownership
    • Codex-OpenCode workflow with capability checks, bounded delegation, review/adversarial-review entry points, and result verification
    • OpenCode collaboration guidance that keeps task text in prompts, treats files as attachments, avoids hidden runtime context, and makes Codex verify every finding
    • Codex-Grok collaboration workflow for using grok-plugin-codex: capability checks, bounded runs, review/rescue/adversarial review, session export, background jobs, and final Codex verification
    • OpenCode and Grok collaboration skills aligned with the plugin contract v2 in 2026-07 while keeping the three named workflows explicit

    technical evidence

    • Operational safety rules: no destructive commands, no commits or pushes by the second agent, no private runtime paths, and no acceptance of unverified agent claims
    • Reusable work-packet shape: goal, acceptance criteria, exact files in scope, constraints, verification commands, expected output, and risks
    • Review discipline: OpenCode and Grok can supply second-pass review or adversarial review, but Codex remains responsible for reading the diff, running tests, and deciding what ships
  10. №10

    A focused macOS menu-bar tool for people who run multiple AI coding accounts every day. It keeps account pools, remaining quota, and throttled states visible before a run stalls.

    problem AI-coding sessions can fail because quota or account-pool status is invisible until a provider throttles a run. The user needs a small early-warning surface, not another dashboard to keep open.

    impact Open-source MIT macOS menu-bar tool · built for daily AI-coding account monitoring

    role Sole author

    stack
    • Swift
    • macOS
    • Developer Tools
    project screenshots
    relaybar macOS menu-bar panel showing AI coding account usage and quota status
    Menu-bar quota and account-pool status for daily AI coding work.
    case details

    Case study View code

    solution

    I built a native macOS menu-bar app that polls quota and account status, then keeps the signal one click away so users can switch pools before a coding run stalls.

    my contribution

    • Live menu-bar readout of account pool + remaining quota across providers
    • Clear signal when a pool is exhausted or throttled, so you can switch before a run stalls
    • Low-distraction, always-on surface that lives in the macOS menu bar

    technical evidence

    • Native Swift menu-bar app; polls provider quota endpoints on an interval
    • Built from the seat of a daily Codex / Claude Code / Antigravity user — the real pain is account-pool rotation, quota exhaustion, and multi-provider context, not model quality
    • Open source under MIT; a small, focused macOS tool that turns daily account-limit problems into an early warning signal
  11. №11

    Open-source maintenance work on Memoh, a Go multi-agent platform for running coding agents in isolated environments. The merged PRs made failures easier to diagnose, Docker deployment docs clearer, and fork CI less surprising for contributors.

    problem Multi-agent developer platforms often fail at the edges: container setup, Docker instructions, fork CI, and vague diagnostics. Contributors need errors and setup paths that point to the next action.

    impact 3 merged upstream PRs · diagnostics, Docker docs, and fork-safe CI

    role Contributor (not maintainer)

    stack
    • Go
    • Docker
    • GitHub Actions
    • +1
    case details

    Case study View code

    solution

    I contributed small upstream fixes that made those edges easier to operate: diagnostics surface container failures, Docker docs match current deployment, and fork CI no longer tries to publish images.

    technical evidence

    • PR #592: surfaced container setup failures in diagnostics
    • PR #595: refreshed Docker deployment guide
    • PR #671: made CI avoid Docker publish in forks
    • Contribution focus: runtime diagnostics, deployment reliability, developer feedback, and fork-safe open-source CI
  12. №12

    A private desktop app for thesis viva preparation. It turns a student's own thesis into evidence-linked practice questions, scoring, and revision tasks while keeping the thesis file and practice history on the device.

    problem Existing viva prep tools are either generic flashcard apps or require hand-crafting every question. The real bottleneck is grounding: an AI examiner is only useful if its questions trace back to what the thesis actually says, and scoring is only trustworthy if it cites the evidence it used.

    impact Shipped local-first viva prep app · evidence-linked practice · privacy-first desktop use

    role Sole builder — product design, architecture, database layer, LLM integration, validation and tests

    stack
    • Next.js
    • TypeScript
    • AI SDK v6
    • +5
    project screenshots
    D-viva-assistant-agent practice workspace with examiner question, scoring, and evidence-linked revision
    Local-first thesis viva practice with scoring and review tasks.
    case details

    Case study View code

    solution

    I built a private desktop workflow where the thesis is ingested into evidence blocks, practice questions and scoring cite those blocks, and low-scoring answers feed a review queue. The app keeps files and history local unless the user opts into a provider.

    my contribution

    • Thesis ingest pipeline — PDF / MD / TXT → paragraph evidence blocks with a quality report; every downstream AI call is grounded to ingest output, not model priors
    • AI study pack generation — thesis summary, key numbers, method Q&A, high-pressure Q&A, and literature cards; each item cites the evidence block it came from and passes a pre-persist validator
    • Editable prep items, revalidation, review queue, and a training plan generator with a static fallback when no model key is configured
    • Real-time AI examiner — draws questions from evidence blocks, scores responses on five dimensions (accuracy / depth / language / methodology / poise) with diagnosis, English rewrite, and follow-up
    • STT practice loop — record answer → transcribe (browser Web Speech or Google Cloud STT) → score; low-scoring items feed the review repair board
    • Provider-agnostic LLM layer — AI SDK v6 generateObject + Zod for structured scoring; supports Gemini / Claude / OpenAI; graceful no-key degradation (practice + transcripts still work)
    • Electron + electron-builder macOS packaging, positioning the app as a private desktop tool rather than a hosted multi-user service

    technical evidence

    • Local-first data model: SQLite (better-sqlite3, WAL, FTS5) for theses, evidence blocks, study packs, and session history; DB lives entirely on device
    • Privacy-by-design: cloud AI is opt-in with explicit disclosure of what is sent to which provider; API keys in .env.local (gitignored), log-level redacted; recordings never synced
    • Next.js App Router with server-only DB access (runtime=nodejs boundary, globalThis singleton, serverExternalPackages for better-sqlite3); AI calls gated behind env parse
    • Tests use MockLlmClient by default; real model calls are gated by RUN_LIVE_AI=1 and only run against public sample theses
  13. №13

    A lightweight learning tool for comparing Cantonese and Mandarin readings side by side. It turns HKEdU correspondence data into a learner-facing lookup path with Jyutping, recorded audio, and a mobile-friendly interface.

    problem Cantonese learners often have to jump between dense correspondence tables, romanization notes, and audio sources to understand how a Mandarin reading maps to Cantonese.

    impact Open-source learner tool · Cantonese-Mandarin lookup · Jyutping and recorded audio

    role Sole builder and learning-tool designer

    stack
    • JavaScript
    • Jyutping
    • Language Education
    project screenshots
    Cantonese-Mandarin cross-reference tool usage instructions explaining lookup modes and features
    The usage guide explains bidirectional lookup, character search, audio playback, and script switching.
    case details

    Case study View code

    solution

    I turned the correspondence data into a fast learner-facing lookup path with character search, Mandarin-to-Cantonese mapping, Jyutping, recorded audio, simplified/traditional switching, and mobile support.

    technical evidence

    • Vanilla JavaScript web tool built on HKEdU's correspondence table, with my own Jyutping conversion, recorded audio, and a fast mobile-friendly lookup UI for learners
Do these projects fit your role? Paste or upload the JD for an evidence-backed brief — strengths and honest gaps included. Go to Role Fit →