MAMATHA EPILI / ENGINEERING & AI
Selected work

AI platform2026Open source

SkillForge

Three agents grade code against rubrics you author yourself

Stack

Frontend
  • Next.js 14 App Router playground
  • Angular 18 standalone components with Signals
  • TypeScript across both apps
  • Tailwind CSS
  • Monaco Editor
  • Sandboxed live preview
  • GSAP score dial, Framer Motion feedback drawer
  • Reactive Forms rubric and challenge editors
Backend & Data
  • Go 1.22 with Gin
  • OpenAPI generated from handler annotations
  • Supabase PostgreSQL with pgvector
  • Cosine retrieval through a SQL function
  • 768-dimension embeddings, L2-normalised
  • Three-agent evaluation pipeline
  • JSONB audit trail per submission
  • Row-level security, service-role key held server-side only

How it works

Flowchart: Two paths meet in the database. An instructor saves a rubric and it is embedded into pgvector as it is written. A learner submits code; it is embedded the same way, the nearest rubrics are retrieved by cosine in SQL, and three agents grade in sequence — spec compliance, then logic, then a mentor that sees only their reports. If retrieval returns nothing, grading runs ungrounded and says so. Every run is stored as an audit trail before the feedback goes back.YesNoRubric authored86.5Angular 18 admin consoleEmbed rubric86.5768-d, L2-normalisedRubric vectors80.5Supabase Postgres ·pgvectorGrade without rubrics86.5flagged in the reportLearner submits code208.5Next.js playgroundEmbed submissionRetrieve nearestrubrics209.5cosine, SQL function,top-kRubrics found?Spec agent202.5rubric compliance ·weight 40Logic agent208.5correctness · weight 60Mentor agent324.5reads reports only, asksquestionsAudit trail324.5rubrics, reports,latency · JSONBFeedback to learner
Two paths meet in the database. An instructor saves a rubric and it is embedded into pgvector as it is written. A learner submits code; it is embedded the same way, the nearest rubrics are retrieved by cosine in SQL, and three agents grade in sequence — spec compliance, then logic, then a mentor that sees only their reports. If retrieval returns nothing, grading runs ungrounded and says so. Every run is stored as an audit trail before the feedback goes back.

Try it here

Recorded run — no key, no backend

The full pipeline needs a provider key and a database, so it cannot run on a static page. This is the project’s own demo: the real challenges and rubrics, and assessment reports in the exact shape the pipeline returns, replayed with no network calls and no key.

Open the demo in its own tab Served from mamta-epili.github.io, sandboxed.

Problem

Rubric-grounded grading is only as good as the rubrics, and the prototype had no way to write them — the corpus was committed to the repository, so changing a criterion meant a code change and a redeploy. Grading criteria are content, not code.

What I built

  • An admin console for authoring challenges and rubrics, where saving embeds and editing re-embeds, so a vector can never drift from the text it represents.
  • A Go assessment API with full CRUD, dashboard aggregates and a health probe, its OpenAPI spec generated from the handler annotations so the docs cannot fall behind the code.
  • The evaluation pipeline as a service: embed the submission, retrieve the closest rubrics by cosine, run spec compliance, then logic, then a mentor that only asks questions — weighted 40/60 towards functional correctness.
  • A learner playground with an editor, a sandboxed preview, an animated score dial and a feedback drawer that stages each agent’s findings.
  • A full audit trail: every submission stores the retrieved rubrics, all three agent reports, warnings, latency and the model names it ran against.

Technical decisions & trade-offs

  • Vectors moved from a committed file into the database once rubrics became editable — retrieval is a SQL function over an indexed column, so authoring and search share one source of truth.
  • Embeddings are truncated to 768 dimensions and re-normalised, because only the full-width vector arrives normalised and cosine assumes unit vectors. A width mismatch fails loudly rather than writing a corrupt row.
  • Submitted code is fenced and both code-facing agents treat it as untrusted data; the mentor sees only the structured reports, so nothing runs from a submission to the agent that speaks to the learner.
  • Every step degrades rather than fails: lost retrieval means the agents run ungrounded and say so, a dead scoring agent means the survivor carries the score, and a failed write still returns the feedback.
  • Model names, thresholds and top-k are configuration, not constants — providers retire models on a schedule, and that should be an environment change rather than a release.

Challenges solved

  • A vector index on a small table quietly returned nothing while exact matches existed — approximate search partitions the space before there is enough data to partition. The fix was dropping the index until the table earns it.
  • The dashboard pass rate and the API’s own verdict came from two places — a SQL aggregate and a configurable threshold — and could disagree. Documented as a constraint rather than papered over.
  • Grading without executing code is an honest limit, not a feature: the logic agent reasons about behaviour, and containerised test runs are written down as the next step rather than implied.

Outcome

Open source, and the version I would hand to someone else: the prototype proved the pipeline, this one makes the rubrics — the part that decides grading quality — something a subject expert can own without touching the codebase.

Permalink: https://www.mamathaepili.com/projects/skillforge